static int checkPresets(struct node *node, bool has_presets)
{
	struct v4l2_dv_enum_preset enumpreset;
	struct v4l2_dv_preset preset;
	unsigned i;
	int ret;

	memset(&preset, 0xff, sizeof(preset));
	ret = doioctl(node, VIDIOC_G_DV_PRESET, &preset);
	if (!ret && check_0(preset.reserved, sizeof(preset.reserved)))
		return fail("reserved not zeroed\n");
	if (ret && has_presets)
		return fail("PRESET cap set, but could not get current preset\n");
	if (!ret && !has_presets)
		return fail("PRESET cap not set, but could still get a preset\n");
	if (preset.preset != V4L2_DV_INVALID) {
		ret = doioctl(node, VIDIOC_S_DV_PRESET, &preset);
		if (ret && has_presets)
			return fail("PRESET cap set, but could not set preset\n");
		if (!ret && !has_presets)
			return fail("PRESET cap not set, but could still set a preset\n");
	}
	preset.preset = V4L2_DV_INVALID;
	ret = doioctl(node, VIDIOC_S_DV_PRESET, &preset);
	if (ret != EINVAL && ret != ENOTTY)
		return fail("could set preset V4L2_DV_INVALID\n");

	for (i = 0; ; i++) {
		memset(&enumpreset, 0xff, sizeof(enumpreset));

		enumpreset.index = i;
		ret = doioctl(node, VIDIOC_ENUM_DV_PRESETS, &enumpreset);
		if (ret)
			break;
		if (check_ustring(enumpreset.name, sizeof(enumpreset.name)))
			return fail("invalid preset name\n");
		if (check_0(enumpreset.reserved, sizeof(enumpreset.reserved)))
			return fail("reserved not zeroed\n");
		if (enumpreset.index != i)
			return fail("index changed!\n");
		if (enumpreset.preset == V4L2_DV_INVALID)
			return fail("invalid preset!\n");
		if (enumpreset.width == 0 || enumpreset.height == 0)
			return fail("width or height not set\n");
	}
	if (i == 0 && has_presets)
		return fail("PRESET cap set, but no presets can be enumerated\n");
	if (i && !has_presets)
		return fail("PRESET cap was not set, but presets can be enumerated\n");
	ret = doioctl(node, VIDIOC_QUERY_DV_PRESET, &preset);
	if (!ret && !has_presets)
		return fail("PRESET cap was not set, but could still query preset\n");
	return 0;
}
static int checkOutput(struct node *node, const struct v4l2_output &descr, unsigned o)
{
	__u32 mask = (1 << node->audio_outputs) - 1;

	if (descr.index != o)
		return fail("invalid index\n");
	if (check_ustring(descr.name, sizeof(descr.name)))
		return fail("invalid name\n");
	if (descr.type != V4L2_OUTPUT_TYPE_MODULATOR && descr.type != V4L2_OUTPUT_TYPE_ANALOG)
		return fail("invalid type\n");
	if (descr.type == V4L2_OUTPUT_TYPE_ANALOG && descr.modulator)
		return fail("invalid modulator\n");
	if (!(descr.capabilities & V4L2_OUT_CAP_STD) && descr.std)
		return fail("invalid std\n");
	if ((descr.capabilities & V4L2_OUT_CAP_STD) && !descr.std)
		return fail("std == 0\n");
	if (descr.capabilities & ~0x7)
		return fail("invalid capabilities\n");
	if (check_0(descr.reserved, sizeof(descr.reserved)))
		return fail("non-zero reserved fields\n");
	if (descr.audioset & ~mask)
		return fail("invalid audioset\n");
	if (descr.modulator && descr.modulator >= node->modulators)
		return fail("invalid modulator\n");
	return 0;
}
static int checkTimings(struct node *node, bool has_timings)
{
	struct v4l2_enum_dv_timings enumtimings;
	struct v4l2_dv_timings timings;
	int ret;
	unsigned i;

	memset(&timings, 0xff, sizeof(timings));
	ret = doioctl(node, VIDIOC_G_DV_TIMINGS, &timings);
	if (ret && has_timings)
		return fail("TIMINGS cap set, but could not get current timings\n");
	if (!ret && !has_timings)
		return fail("TIMINGS cap not set, but could still get timings\n");

	for (i = 0; ; i++) {
		memset(&enumtimings, 0xff, sizeof(enumtimings));

		enumtimings.index = i;
		ret = doioctl(node, VIDIOC_ENUM_DV_TIMINGS, &enumtimings);
		if (ret)
			break;
		if (check_0(enumtimings.reserved, sizeof(enumtimings.reserved)))
			return fail("reserved not zeroed\n");
		if (enumtimings.index != i)
			return fail("index changed!\n");
	}
	if (i == 0 && has_timings)
		return fail("TIMINGS cap set, but no timings can be enumerated\n");
	if (i && !has_timings)
		return fail("TIMINGS cap was not set, but timings can be enumerated\n");
	ret = doioctl(node, VIDIOC_QUERY_DV_TIMINGS, &timings);
	if (!ret && !has_timings)
		return fail("TIMINGS cap was not set, but could still query timings\n");
	return 0;
}
static int testSlicedVBICapType(struct node *node, enum v4l2_buf_type type)
{
	struct v4l2_sliced_vbi_cap cap;
	bool sliced_type = (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ||
			    type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT);
	__u32 service_set = 0;
	int ret;

	memset(&cap, 0xff, sizeof(cap));
	memset(&cap.reserved, 0, sizeof(cap.reserved));
	cap.type = type;
	ret = doioctl(node, VIDIOC_G_SLICED_VBI_CAP, &cap);
	fail_on_test(check_0(cap.reserved, sizeof(cap.reserved)));
	fail_on_test(cap.type != type);
	fail_on_test(ret && ret != EINVAL && sliced_type);
	if (ret == EINVAL) {
		fail_on_test(sliced_type && (node->caps & buftype2cap[type]));
		if (node->caps & (V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT))
			return 0;
		return -ENOSYS;
	}
	if (ret)
		return fail("expected EINVAL, but got %d when getting sliced VBI caps buftype %d\n", ret, type);
	fail_on_test(!(node->caps & buftype2cap[type]));

	for (int f = 0; f < 2; f++)
		for (int i = 0; i < 24; i++)
			service_set |= cap.service_lines[f][i];
	fail_on_test(cap.service_set != service_set);
	fail_on_test(cap.service_lines[0][0] || cap.service_lines[1][0]);
	return 0;
}
static int checkInput(struct node *node, const struct v4l2_input &descr, unsigned i)
{
	__u32 mask = (1 << node->audio_inputs) - 1;

	if (descr.index != i)
		return fail("invalid index\n");
	if (check_ustring(descr.name, sizeof(descr.name)))
		return fail("invalid name\n");
	if (descr.type != V4L2_INPUT_TYPE_TUNER && descr.type != V4L2_INPUT_TYPE_CAMERA)
		return fail("invalid type\n");
	if (descr.type == V4L2_INPUT_TYPE_CAMERA && descr.tuner)
		return fail("invalid tuner\n");
	if (!(descr.capabilities & V4L2_IN_CAP_STD) && descr.std)
		return fail("invalid std\n");
	if ((descr.capabilities & V4L2_IN_CAP_STD) && !descr.std)
		return fail("std == 0\n");
	if (descr.capabilities & ~0x7)
		return fail("invalid capabilities\n");
	if (check_0(descr.reserved, sizeof(descr.reserved)))
		return fail("non-zero reserved fields\n");
	if (descr.status & ~0x07070337)
		return fail("invalid status\n");
	if (descr.status & 0x02070000)
		return fail("use of deprecated digital video status\n");
	if (descr.audioset & ~mask)
		return fail("invalid audioset\n");
	if (descr.tuner && descr.tuner >= node->tuners)
		return fail("invalid tuner\n");
	return 0;
}
Пример #6
0
static int testSlicedVBICapType(struct node *node, unsigned type)
{
	struct v4l2_sliced_vbi_cap cap;
	bool sliced_type = (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ||
			    type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT);
	__u32 service_set = 0;
	int ret;

	memset(&cap, 0xff, sizeof(cap));
	memset(&cap.reserved, 0, sizeof(cap.reserved));
	cap.type = type;
	ret = doioctl(node, VIDIOC_G_SLICED_VBI_CAP, &cap);
	if (ret == ENOTTY) {
		fail_on_test(sliced_type && (node->caps & buftype2cap[type]));
		return ret;
	}
	fail_on_test(check_0(cap.reserved, sizeof(cap.reserved)));
	fail_on_test(cap.type != type);
	fail_on_test(ret && ret != EINVAL);
	fail_on_test(ret && sliced_type && (node->caps & buftype2cap[type]));
	fail_on_test(!ret && (!sliced_type || !(node->caps & buftype2cap[type])));
	if (ret)
		return 0;

	for (int f = 0; f < 2; f++)
		for (int i = 0; i < 24; i++)
			service_set |= cap.service_lines[f][i];
	fail_on_test(cap.service_set != service_set);
	fail_on_test(cap.service_lines[0][0] || cap.service_lines[1][0]);
	return 0;
}
static int checkEnumFreqBands(struct node *node, __u32 tuner, __u32 type, __u32 caps)
{
	unsigned i;
	__u32 caps_union = 0;

	for (i = 0; ; i++) {
		struct v4l2_frequency_band band;
		int ret;

		memset(band.reserved, 0, sizeof(band.reserved));
		band.tuner = tuner;
		band.type = type;
		band.index = i;
		ret = doioctl(node, VIDIOC_ENUM_FREQ_BANDS, &band);
		if (ret == EINVAL && i)
			return 0;
		if (ret)
			return fail("couldn't get freq band\n");
		caps_union |= band.capability;
		if ((caps & V4L2_TUNER_CAP_LOW) != (band.capability & V4L2_TUNER_CAP_LOW))
			return fail("Inconsistent CAP_LOW usage\n");
		fail_on_test(band.rangehigh < band.rangelow);
		fail_on_test(band.index != i);
		fail_on_test(band.type != type);
		fail_on_test(band.tuner != tuner);
		fail_on_test((band.capability & V4L2_TUNER_CAP_FREQ_BANDS) == 0);
		check_0(band.reserved, sizeof(band.reserved));
	}
	fail_on_test(caps_union != caps);
	return 0;
}
static int checkModulator(struct node *node, const struct v4l2_modulator &mod, unsigned m)
{
	bool tv = !node->is_radio;

	if (mod.index != m)
		return fail("invalid index\n");
	if (check_ustring(mod.name, sizeof(mod.name)))
		return fail("invalid name\n");
	if (check_0(mod.reserved, sizeof(mod.reserved)))
		return fail("non-zero reserved fields\n");
	if (tv)
		return fail("currently only radio modulators are supported\n");
	if (!(mod.capability & V4L2_TUNER_CAP_LOW))
		return fail("V4L2_TUNER_CAP_LOW was not set for a radio modulator\n");
	if (mod.capability & (V4L2_TUNER_CAP_NORM |
					V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2))
		return fail("TV capabilities for radio modulator?\n");
	if (mod.rangelow >= mod.rangehigh)
		return fail("rangelow >= rangehigh\n");
	if (mod.rangelow == 0 || mod.rangehigh == 0xffffffff)
		return fail("invalid rangelow or rangehigh\n");
	if (!(mod.capability & V4L2_TUNER_CAP_STEREO) &&
			(mod.txsubchans & V4L2_TUNER_SUB_STEREO))
		return fail("stereo subchan, but no stereo caps?\n");
	if (!(mod.capability & V4L2_TUNER_CAP_LANG1) &&
			(mod.txsubchans & V4L2_TUNER_SUB_LANG1))
		return fail("lang1 subchan, but no lang1 caps?\n");
	if (!(mod.capability & V4L2_TUNER_CAP_LANG2) &&
			(mod.txsubchans & V4L2_TUNER_SUB_LANG2))
		return fail("lang2 subchan, but no lang2 caps?\n");
	if (!(mod.capability & V4L2_TUNER_CAP_RDS) &&
			(mod.txsubchans & V4L2_TUNER_SUB_RDS))
		return fail("RDS subchan, but no RDS caps?\n");
	return 0;
}
Пример #9
0
static int testParmStruct(struct node *node, struct v4l2_streamparm &parm)
{
	struct v4l2_captureparm *cap = &parm.parm.capture;
	struct v4l2_outputparm *out = &parm.parm.output;
	int ret;

	switch (parm.type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
		ret = check_0(cap->reserved, sizeof(cap->reserved));
		if (ret)
			return fail("reserved not zeroed\n");
		fail_on_test(cap->readbuffers > VIDEO_MAX_FRAME);
		if (!(node->caps & V4L2_CAP_READWRITE))
			fail_on_test(cap->readbuffers);
		else if (node->caps & V4L2_CAP_STREAMING)
			fail_on_test(!cap->readbuffers);
		fail_on_test(cap->capability & ~V4L2_CAP_TIMEPERFRAME);
		fail_on_test(cap->capturemode & ~V4L2_MODE_HIGHQUALITY);
		if (cap->capturemode & V4L2_MODE_HIGHQUALITY)
			warn("V4L2_MODE_HIGHQUALITY is poorly defined\n");
		fail_on_test(cap->extendedmode);
		if (cap->capability & V4L2_CAP_TIMEPERFRAME)
			fail_on_test(cap->timeperframe.numerator == 0 || cap->timeperframe.denominator == 0);
		break;
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
		ret = check_0(out->reserved, sizeof(out->reserved));
		if (ret)
			return fail("reserved not zeroed\n");
		fail_on_test(out->writebuffers > VIDEO_MAX_FRAME);
		if (!(node->caps & V4L2_CAP_READWRITE))
			fail_on_test(out->writebuffers);
		else if (node->caps & V4L2_CAP_STREAMING)
			fail_on_test(!out->writebuffers);
		fail_on_test(out->capability & ~V4L2_CAP_TIMEPERFRAME);
		fail_on_test(out->outputmode);
		fail_on_test(out->extendedmode);
		if (out->capability & V4L2_CAP_TIMEPERFRAME)
			fail_on_test(out->timeperframe.numerator == 0 || out->timeperframe.denominator == 0);
		break;
	default:
		break;
	}
	return 0;
}
Пример #10
0
static int testEnumFormatsType(struct node *node, unsigned type)
{
	pixfmt_set &set = node->buftype_pixfmts[type];
	struct v4l2_fmtdesc fmtdesc;
	unsigned f = 0;
	int ret;

	for (;;) {
		memset(&fmtdesc, 0xff, sizeof(fmtdesc));
		fmtdesc.type = type;
		fmtdesc.index = f;

		ret = doioctl(node, VIDIOC_ENUM_FMT, &fmtdesc);
		if (ret == ENOTTY)
			return ret;
		if (f == 0 && ret == EINVAL)
			return ENOTTY;
		if (ret == EINVAL)
			break;
		if (ret)
			return fail("expected EINVAL, but got %d when enumerating buftype %d\n", ret, type);
		ret = check_0(fmtdesc.reserved, sizeof(fmtdesc.reserved));
		if (ret)
			return fail("fmtdesc.reserved not zeroed\n");
		if (fmtdesc.index != f)
			return fail("fmtdesc.index was modified\n");
		if (fmtdesc.type != type)
			return fail("fmtdesc.type was modified\n");
		ret = check_ustring(fmtdesc.description, sizeof(fmtdesc.description));
		if (ret)
			return fail("fmtdesc.description not set\n");
		if (!fmtdesc.pixelformat)
			return fail("fmtdesc.pixelformat not set\n");
		if (!wrapper && (fmtdesc.flags & V4L2_FMT_FLAG_EMULATED))
			return fail("drivers must never set the emulated flag\n");
		if (fmtdesc.flags & ~(V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_EMULATED))
			return fail("unknown flag %08x returned\n", fmtdesc.flags);
		ret = testEnumFrameSizes(node, fmtdesc.pixelformat);
		if (ret && ret != ENOTTY)
			return ret;
		if (ret == 0 && !(node->caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)))
			return fail("found framesizes when no video capture is supported\n");
		f++;
		if (type == V4L2_BUF_TYPE_PRIVATE)
			continue;
		// Update array in v4l2-compliance.h if new buffer types are added
		assert(type <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
		if (set.find(fmtdesc.pixelformat) != set.end())
			return fail("duplicate format %08x\n", fmtdesc.pixelformat);
		set.insert(fmtdesc.pixelformat);
	}
	info("found %d formats for buftype %d\n", f, type);
	return 0;
}
int testTunerHwSeek(struct node *node)
{
	struct v4l2_hw_freq_seek seek;
	unsigned t;
	int ret;

	for (t = 0; t < node->tuners; t++) {
		struct v4l2_tuner tuner;
		
		tuner.index = t;
		ret = doioctl(node, VIDIOC_G_TUNER, &tuner);
		if (ret)
			return fail("could not get tuner %d\n", t);

		memset(&seek, 0, sizeof(seek));
		seek.tuner = t;
		seek.type = V4L2_TUNER_RADIO;
		ret = doioctl(node, VIDIOC_S_HW_FREQ_SEEK, &seek);
		if (!(node->caps & V4L2_CAP_HW_FREQ_SEEK) && ret != ENOTTY)
			return fail("hw seek supported but capability not set\n");
		if (!node->is_radio && ret != ENOTTY)
			return fail("hw seek supported on a non-radio node?!\n");
		if (!node->is_radio || !(node->caps & V4L2_CAP_HW_FREQ_SEEK))
			return ENOTTY;
		seek.type = V4L2_TUNER_ANALOG_TV;
		ret = doioctl(node, VIDIOC_S_HW_FREQ_SEEK, &seek);
		if (ret != EINVAL)
			return fail("hw seek accepted TV tuner\n");
		seek.type = V4L2_TUNER_RADIO;
		seek.seek_upward = 1;
		ret = doioctl(node, VIDIOC_S_HW_FREQ_SEEK, &seek);
		if (ret == EINVAL && (tuner.capability & V4L2_TUNER_CAP_HWSEEK_BOUNDED))
			return fail("hw bounded seek failed\n");
		if (ret && ret != EINVAL && ret != ENODATA)
			return fail("hw bounded seek failed with error %d\n", ret);
		seek.wrap_around = 1;
		ret = doioctl(node, VIDIOC_S_HW_FREQ_SEEK, &seek);
		if (ret == EINVAL && (tuner.capability & V4L2_TUNER_CAP_HWSEEK_WRAP))
			return fail("hw wrapped seek failed\n");
		if (ret && ret != EINVAL && ret != ENODATA)
			return fail("hw wrapped seek failed with error %d\n", ret);
		if (check_0(seek.reserved, sizeof(seek.reserved)))
			return fail("non-zero reserved fields\n");
	}
	memset(&seek, 0, sizeof(seek));
	seek.tuner = node->tuners;
	seek.type = V4L2_TUNER_RADIO;
	ret = doioctl(node, VIDIOC_S_HW_FREQ_SEEK, &seek);
	if (ret != EINVAL && ret != ENOTTY)
		return fail("hw seek for invalid tuner didn't return EINVAL or ENOTTY\n");
	return ret == ENOTTY ? ret : 0;
}
static int checkOutputAudio(const struct v4l2_audioout &descr, unsigned o)
{
	if (descr.index != o)
		return fail("invalid index\n");
	if (check_ustring(descr.name, sizeof(descr.name)))
		return fail("invalid name\n");
	if (descr.capability)
		return fail("invalid capabilities\n");
	if (descr.mode)
		return fail("invalid mode\n");
	if (check_0(descr.reserved, sizeof(descr.reserved)))
		return fail("non-zero reserved fields\n");
	return 0;
}
Пример #13
0
static int checkTimingsCap(struct node *node, bool has_timings)
{
	struct v4l2_dv_timings_cap timingscap;
	int ret;

	memset(&timingscap, 0xff, sizeof(timingscap));
	ret = doioctl(node, VIDIOC_DV_TIMINGS_CAP, &timingscap);
	if (ret && has_timings)
		return fail("TIMINGS cap set, but could not get timings caps\n");
	if (!ret && !has_timings)
		return fail("TIMINGS cap not set, but could still get timings caps\n");
	if (ret && !has_timings)
		return 0;
	if (check_0(timingscap.reserved, sizeof(timingscap.reserved)))
		return fail("reserved not zeroed\n");
	fail_on_test(timingscap.type != V4L2_DV_BT_656_1120);
	if (check_0(timingscap.bt.reserved, sizeof(timingscap.bt.reserved)))
		return fail("reserved not zeroed\n");
	fail_on_test(timingscap.bt.min_width > timingscap.bt.max_width);
	fail_on_test(timingscap.bt.min_height > timingscap.bt.max_height);
	fail_on_test(timingscap.bt.min_pixelclock > timingscap.bt.max_pixelclock);
	return 0;
}
Пример #14
0
int testEncIndex(struct node *node)
{
	struct v4l2_enc_idx idx;
	int ret;

	memset(&idx, 0xff, sizeof(idx));
	ret = doioctl(node, VIDIOC_G_ENC_INDEX, &idx);
	if (ret == ENOTTY)
		return ret;
	if (check_0(idx.reserved, sizeof(idx.reserved)))
		return fail("idx.reserved not zeroed\n");
	fail_on_test(ret);
	fail_on_test(idx.entries != 0);
	fail_on_test(idx.entries_cap == 0);
	return 0;
}
static int checkInputAudio(const struct v4l2_audio &descr, unsigned i)
{
	if (descr.index != i)
		return fail("invalid index\n");
	if (check_ustring(descr.name, sizeof(descr.name)))
		return fail("invalid name\n");
	if (descr.capability & ~0x3)
		return fail("invalid capabilities\n");
	if (descr.mode != 0 && descr.mode != V4L2_AUDMODE_AVL)
		return fail("invalid mode\n");
	if (!(descr.capability & V4L2_AUDCAP_AVL) && descr.mode)
		return fail("mode != 0\n");
	if (check_0(descr.reserved, sizeof(descr.reserved)))
		return fail("non-zero reserved fields\n");
	return 0;
}
static int checkModulator(struct node *node, const struct v4l2_modulator &mod, unsigned m)
{
	bool tv = !node->is_radio;

	if (mod.index != m)
		return fail("invalid index\n");
	if (check_ustring(mod.name, sizeof(mod.name)))
		return fail("invalid name\n");
	if (check_0(mod.reserved, sizeof(mod.reserved)))
		return fail("non-zero reserved fields\n");
	if (tv)
		return fail("currently only radio modulators are supported\n");
	if (!(mod.capability & V4L2_TUNER_CAP_LOW))
		return fail("V4L2_TUNER_CAP_LOW was not set for a radio modulator\n");
	if (mod.capability & (V4L2_TUNER_CAP_NORM |
					V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2))
		return fail("TV capabilities for radio modulator?\n");
	fail_on_test(!(mod.capability & V4L2_TUNER_CAP_FREQ_BANDS));
	if (mod.rangelow >= mod.rangehigh)
		return fail("rangelow >= rangehigh\n");
	if (mod.rangelow == 0 || mod.rangehigh == 0xffffffff)
		return fail("invalid rangelow or rangehigh\n");
	if (!(mod.capability & V4L2_TUNER_CAP_STEREO) &&
			(mod.txsubchans & V4L2_TUNER_SUB_STEREO))
		return fail("stereo subchan, but no stereo caps?\n");
	if (!(mod.capability & V4L2_TUNER_CAP_LANG1) &&
			(mod.txsubchans & V4L2_TUNER_SUB_LANG1))
		return fail("lang1 subchan, but no lang1 caps?\n");
	if (!(mod.capability & V4L2_TUNER_CAP_LANG2) &&
			(mod.txsubchans & V4L2_TUNER_SUB_LANG2))
		return fail("lang2 subchan, but no lang2 caps?\n");
	if (!(mod.capability & V4L2_TUNER_CAP_RDS) &&
			(mod.txsubchans & V4L2_TUNER_SUB_RDS))
		return fail("RDS subchan, but no RDS caps?\n");
	bool have_rds = mod.capability & V4L2_TUNER_CAP_RDS;
	bool have_rds_method = mod.capability &
                        (V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_RDS_CONTROLS);
	if (have_rds ^ have_rds_method)
		return fail("V4L2_TUNER_CAP_RDS is set, but not V4L2_TUNER_CAP_RDS_* or vice versa\n");
	if ((mod.capability & V4L2_TUNER_CAP_RDS_BLOCK_IO) &&
			!(node->caps & V4L2_CAP_READWRITE))
		return fail("V4L2_TUNER_CAP_RDS_BLOCK_IO is set, but not V4L2_CAP_READWRITE\n");
	if (!(mod.capability & V4L2_TUNER_CAP_RDS_BLOCK_IO) &&
			(node->caps & V4L2_CAP_READWRITE))
		return fail("V4L2_TUNER_CAP_RDS_BLOCK_IO is not set, but V4L2_CAP_READWRITE is\n");
	return checkEnumFreqBands(node, mod.index, V4L2_TUNER_RADIO, mod.capability);
}
Пример #17
0
int testExtendedControls(struct node *node)
{
	qctrl_list::iterator iter;
	struct v4l2_ext_controls ctrls;
	std::vector<struct v4l2_ext_control> total_vec;
	std::vector<struct v4l2_ext_control> class_vec;
	struct v4l2_ext_control ctrl;
	__u32 ctrl_class = 0;
	bool multiple_classes = false;
	int ret;

	memset(&ctrls, 0, sizeof(ctrls));
	ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
	if (ret == ENOTTY && node->controls.empty())
		return ret;
	if (ret)
		return fail("g_ext_ctrls does not support count == 0\n");
	if (node->controls.empty())
		return fail("g_ext_ctrls worked even when no controls are present\n");
	if (ctrls.ctrl_class)
		return fail("field ctrl_class changed\n");
	if (ctrls.count)
		return fail("field count changed\n");
	if (check_0(ctrls.reserved, sizeof(ctrls.reserved)))
		return fail("reserved not zeroed\n");

	memset(&ctrls, 0, sizeof(ctrls));
	ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
	if (ret == ENOTTY && node->controls.empty())
		return ret;
	if (ret)
		return fail("try_ext_ctrls does not support count == 0\n");
	if (node->controls.empty())
		return fail("try_ext_ctrls worked even when no controls are present\n");
	if (ctrls.ctrl_class)
		return fail("field ctrl_class changed\n");
	if (ctrls.count)
		return fail("field count changed\n");
	if (check_0(ctrls.reserved, sizeof(ctrls.reserved)))
		return fail("reserved not zeroed\n");

	for (iter = node->controls.begin(); iter != node->controls.end(); ++iter) {
		info("checking extended control '%s' (0x%08x)\n", iter->name, iter->id);
		ctrl.id = iter->id;
		ctrl.size = 0;
		ctrl.reserved2[0] = 0;
		ctrls.count = 1;

		// Either should work, so try both semi-randomly
		ctrls.ctrl_class = (ctrl.id & 1) ? 0 : V4L2_CTRL_ID2CLASS(ctrl.id);
		ctrls.controls = &ctrl;

		// Get the current value
		ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
		if ((iter->flags & V4L2_CTRL_FLAG_WRITE_ONLY)) {
			if (ret != EACCES)
				return fail("g_ext_ctrls did not check the write-only flag\n");
			if (ctrls.error_idx != ctrls.count)
				return fail("invalid error index write only control\n");
			ctrl.id = iter->id;
			ctrl.value = iter->default_value;
		} else {
			if (ret != ENOSPC && iter->type == V4L2_CTRL_TYPE_STRING)
				return fail("did not check against size\n");
			if (ret == ENOSPC && iter->type == V4L2_CTRL_TYPE_STRING) {
				if (ctrls.error_idx != 0)
					return fail("invalid error index string control\n");
				ctrl.string = new char[iter->maximum + 1];
				ctrl.size = iter->maximum + 1;
				ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
			}
			if (ret == EIO) {
				warn("g_ext_ctrls returned EIO\n");
				ret = 0;
			}
			if (ret)
				return fail("g_ext_ctrls returned an error (%d)\n", ret);
			if (checkExtendedCtrl(ctrl, *iter))
				return fail("invalid control %08x\n", iter->id);
		}
		
		// Try the current value (or the default value for write only controls)
		ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
		if (iter->flags & V4L2_CTRL_FLAG_READ_ONLY) {
			if (ret != EACCES)
				return fail("try_ext_ctrls did not check the read-only flag\n");
			if (ctrls.error_idx != 0)
				return fail("invalid error index read only control\n");
		} else if (ret) {
			return fail("try_ext_ctrls returned an error\n");
		}
		
		// Try to set the current value (or the default value for write only controls)
		ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
		if (iter->flags & V4L2_CTRL_FLAG_READ_ONLY) {
			if (ret != EACCES)
				return fail("s_ext_ctrls did not check the read-only flag\n");
			if (ctrls.error_idx != ctrls.count)
				return fail("invalid error index\n");
		} else {
			if (ret == EIO) {
				warn("s_ext_ctrls returned EIO\n");
				ret = 0;
			}
			if (ret)
				return fail("s_ext_ctrls returned an error\n");
		
			if (checkExtendedCtrl(ctrl, *iter))
				return fail("s_ext_ctrls returned invalid control contents (%08x)\n", iter->id);
		}
		if (iter->type == V4L2_CTRL_TYPE_STRING)
			delete [] ctrl.string;
		ctrl.string = NULL;
	}

	ctrls.ctrl_class = 0;
	ctrl.id = 0;
	ctrl.size = 0;
	ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
	if (ret != EINVAL)
		return fail("g_ext_ctrls accepted invalid control ID\n");
	if (ctrls.error_idx != ctrls.count)
		return fail("g_ext_ctrls(0) invalid error_idx\n");
	ctrl.id = 0;
	ctrl.size = 0;
	ctrl.value = 0;
	ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
	if (ret != EINVAL)
		return fail("try_ext_ctrls accepted invalid control ID\n");
	if (ctrls.error_idx != 0)
		return fail("try_ext_ctrls(0) invalid error_idx\n");
	ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
	if (ret != EINVAL)
		return fail("s_ext_ctrls accepted invalid control ID\n");
	if (ctrls.error_idx != ctrls.count)
		return fail("s_ext_ctrls(0) invalid error_idx\n");

	for (iter = node->controls.begin(); iter != node->controls.end(); ++iter) {
		struct v4l2_ext_control ctrl;

		if (iter->flags & (V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY))
			continue;
		ctrl.id = iter->id;
		ctrl.size = 0;
		if (iter->type == V4L2_CTRL_TYPE_STRING) {
			ctrl.size = iter->maximum + 1;
			ctrl.string = new char[ctrl.size];
		}
		ctrl.reserved2[0] = 0;
		if (!ctrl_class)
			ctrl_class = V4L2_CTRL_ID2CLASS(ctrl.id);
		else if (ctrl_class != V4L2_CTRL_ID2CLASS(ctrl.id))
			multiple_classes = true;
		total_vec.push_back(ctrl);
	}

	ctrls.count = total_vec.size();
	ctrls.controls = &total_vec[0];
	ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
	if (ret)
		return fail("could not get all controls\n");
	ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
	if (ret)
		return fail("could not try all controls\n");
	ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
	if (ret == EIO) {
		warn("s_ext_ctrls returned EIO\n");
		ret = 0;
	}
	if (ret)
		return fail("could not set all controls\n");

	ctrls.ctrl_class = ctrl_class;
	ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
	if (ret && !multiple_classes)
		return fail("could not get all controls of a specific class\n");
	if (ret != EINVAL && multiple_classes)
		return fail("should get EINVAL when getting mixed-class controls\n");
	if (multiple_classes && ctrls.error_idx != ctrls.count)
		return fail("error_idx should be equal to count\n");
	ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
	if (ret && !multiple_classes)
		return fail("could not try all controls of a specific class\n");
	if (ret != EINVAL && multiple_classes)
		return fail("should get EINVAL when trying mixed-class controls\n");
	if (multiple_classes && ctrls.error_idx >= ctrls.count)
		return fail("error_idx should be < count\n");
	ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
	if (ret == EIO) {
		warn("s_ext_ctrls returned EIO\n");
		ret = 0;
	}
	if (ret && !multiple_classes)
		return fail("could not set all controls of a specific class\n");
	if (ret != EINVAL && multiple_classes)
		return fail("should get EINVAL when setting mixed-class controls\n");
	if (multiple_classes && ctrls.error_idx != ctrls.count)
		return fail("error_idx should be equal to count\n");
	return 0;
}
Пример #18
0
static int checkQCtrl(struct node *node, struct test_queryctrl &qctrl)
{
	struct v4l2_querymenu qmenu;
	__u32 fl = qctrl.flags;
	__u32 rw_mask = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
	int ret;
	int i;

	qctrl.menu_mask = 0;
	if (check_ustring(qctrl.name, sizeof(qctrl.name)))
		return fail("invalid name\n");
	info("checking v4l2_queryctrl of control '%s' (0x%08x)\n", qctrl.name, qctrl.id);
	if (qctrl.id & V4L2_CTRL_FLAG_NEXT_CTRL)
		return fail("V4L2_CTRL_FLAG_NEXT_CTRL not cleared\n");
	if (check_0(qctrl.reserved, sizeof(qctrl.reserved)))
		return fail("non-zero reserved fields\n");
	if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
		if ((qctrl.id & 0xffff) != 1)
			return fail("invalid control ID for a control class\n");
	} else if (qctrl.id < V4L2_CID_PRIVATE_BASE) {
		if ((qctrl.id & 0xffff) < 0x900)
			return fail("invalid control ID\n");
	}
	switch (qctrl.type) {
	case V4L2_CTRL_TYPE_BOOLEAN:
		if (qctrl.maximum > 1)
			return fail("invalid boolean max value\n");
		/* fall through */
	case V4L2_CTRL_TYPE_MENU:
	case V4L2_CTRL_TYPE_INTEGER_MENU:
		if (qctrl.step != 1)
			return fail("invalid step value %d\n", qctrl.step);
		if (qctrl.minimum < 0)
			return fail("min < 0\n");
		/* fall through */
	case V4L2_CTRL_TYPE_INTEGER:
		if (qctrl.default_value < qctrl.minimum ||
		    qctrl.default_value > qctrl.maximum)
			return fail("def < min || def > max\n");
		/* fall through */
	case V4L2_CTRL_TYPE_STRING:
		if (qctrl.minimum > qctrl.maximum)
			return fail("min > max\n");
		if (qctrl.step == 0)
			return fail("step == 0\n");
		if (qctrl.step < 0)
			return fail("step < 0\n");
		if ((unsigned)qctrl.step > (unsigned)(qctrl.maximum - qctrl.minimum))
			return fail("step > max - min\n");
		if ((qctrl.maximum - qctrl.minimum) % qctrl.step) {
			// This really should be a fail, but there are so few
			// drivers that do this right that I made it a warning
			// for now.
			warn("%s: (max - min) %% step != 0\n", qctrl.name);
		}
		break;
	case V4L2_CTRL_TYPE_BITMASK:
		if (qctrl.minimum)
			return fail("minimum must be 0 for a bitmask control\n");
		if (qctrl.step)
			return fail("step must be 0 for a bitmask control\n");
		if (!qctrl.maximum)
			return fail("maximum must be non-zero for a bitmask control\n");
		if (qctrl.default_value & ~qctrl.maximum)
			return fail("default_value is out of range for a bitmask control\n");
		break;
	case V4L2_CTRL_TYPE_CTRL_CLASS:
	case V4L2_CTRL_TYPE_INTEGER64:
	case V4L2_CTRL_TYPE_BUTTON:
		if (qctrl.minimum || qctrl.maximum || qctrl.step || qctrl.default_value)
			return fail("non-zero min/max/step/def\n");
		break;
	default:
		return fail("unknown control type\n");
	}
	if (qctrl.type == V4L2_CTRL_TYPE_STRING && qctrl.default_value)
		return fail("non-zero default value for string\n");
	switch (qctrl.type) {
	case V4L2_CTRL_TYPE_BUTTON:
		if ((fl & rw_mask) != V4L2_CTRL_FLAG_WRITE_ONLY)
			return fail("button control not write only\n");
		/* fall through */
	case V4L2_CTRL_TYPE_BOOLEAN:
	case V4L2_CTRL_TYPE_MENU:
	case V4L2_CTRL_TYPE_INTEGER_MENU:
	case V4L2_CTRL_TYPE_STRING:
	case V4L2_CTRL_TYPE_BITMASK:
		if (fl & V4L2_CTRL_FLAG_SLIDER)
			return fail("slider makes only sense for integer controls\n");
		/* fall through */
	case V4L2_CTRL_TYPE_INTEGER64:
	case V4L2_CTRL_TYPE_INTEGER:
		if ((fl & rw_mask) == rw_mask)
			return fail("can't read nor write this control\n");
		break;
	case V4L2_CTRL_TYPE_CTRL_CLASS:
		if (fl != (V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY))
			return fail("invalid flags for control class\n");
		break;
	}
	if (fl & V4L2_CTRL_FLAG_GRABBED)
		return fail("GRABBED flag set\n");
	if (fl & V4L2_CTRL_FLAG_DISABLED)
		return fail("DISABLED flag set\n");
	if (qctrl.type != V4L2_CTRL_TYPE_MENU && qctrl.type != V4L2_CTRL_TYPE_INTEGER_MENU) {
		memset(&qmenu, 0xff, sizeof(qmenu));
		qmenu.id = qctrl.id;
		qmenu.index = qctrl.minimum;
		ret = doioctl(node, VIDIOC_QUERYMENU, &qmenu);
		if (ret != EINVAL)
			return fail("can do querymenu on a non-menu control\n");
		return 0;
	}
	if (qctrl.maximum >= 32)
		return fail("currently more than 32 menu items are not supported\n");
	for (i = 0; i <= qctrl.maximum + 1; i++) {
		memset(&qmenu, 0xff, sizeof(qmenu));
		qmenu.id = qctrl.id;
		qmenu.index = i;
		ret = doioctl(node, VIDIOC_QUERYMENU, &qmenu);
		if (ret && ret != EINVAL)
			return fail("invalid QUERYMENU return code\n");
		if (ret)
			continue;
		if (i < qctrl.minimum || i > qctrl.maximum)
			return fail("can get menu for out-of-range index\n");
		if (qmenu.index != (__u32)i || qmenu.id != qctrl.id)
			return fail("id or index changed\n");
		if (qctrl.type == V4L2_CTRL_TYPE_MENU &&
		    check_ustring(qmenu.name, sizeof(qmenu.name)))
			return fail("invalid menu name\n");
		if (qmenu.reserved)
			return fail("reserved is non-zero\n");
		qctrl.menu_mask |= 1 << i;
	}
	if (qctrl.menu_mask == 0)
		return fail("no menu items found\n");
	if (!(qctrl.menu_mask & (1 << qctrl.default_value)))
		return fail("the default_value is an invalid menu item\n");
	return 0;
}
int testModulatorFreq(struct node *node)
{
	struct v4l2_frequency freq;
	unsigned m;
	int ret;

	for (m = 0; m < node->modulators; m++) {
		struct v4l2_modulator modulator;
		
		modulator.index = m;
		ret = doioctl(node, VIDIOC_G_MODULATOR, &modulator);
		if (ret)
			return fail("could not get modulator %d\n", m);
		memset(&freq, 0, sizeof(freq));
		freq.tuner = m;
		ret = doioctl(node, VIDIOC_G_FREQUENCY, &freq);
		if (ret)
			return fail("could not get frequency for modulator %d\n", m);
		if (check_0(freq.reserved, sizeof(freq.reserved)))
			return fail("reserved was not zeroed\n");
		if (freq.tuner != m)
			return fail("frequency modulator field changed!\n");
		if (freq.frequency == 0)
			return fail("frequency not set\n");
		if (freq.frequency < modulator.rangelow || freq.frequency > modulator.rangehigh)
			warn("returned modulator %d frequency out of range (%d not in [%d...%d])\n",
					m, freq.frequency, modulator.rangelow, modulator.rangehigh);

		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set current frequency\n");
		freq.frequency = modulator.rangelow;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set rangelow frequency\n");
		freq.frequency = modulator.rangehigh;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set rangehigh frequency\n");
		freq.frequency = modulator.rangelow - 1;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set rangelow-1 frequency\n");
		ret = doioctl(node, VIDIOC_G_FREQUENCY, &freq);
		if (ret || freq.frequency != modulator.rangelow)
			return fail("frequency rangelow-1 wasn't mapped to rangelow\n");
		freq.frequency = modulator.rangehigh + 1;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set rangehigh+1 frequency\n");
		ret = doioctl(node, VIDIOC_G_FREQUENCY, &freq);
		if (ret || freq.frequency != modulator.rangehigh)
			return fail("frequency rangehigh+1 wasn't mapped to rangehigh\n");
	}

	/* If this is a tuner device, then skip the remaining tests */
	if (node->caps & V4L2_CAP_TUNER)
		return 0;

	freq.tuner = m;
	ret = doioctl(node, VIDIOC_G_FREQUENCY, &freq);
	if (ret != EINVAL && ret != ENOTTY)
		return fail("could get frequency for invalid modulator %d\n", m);
	freq.tuner = m;
	// Radio: 100 MHz
	freq.frequency = 1600000;
	ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
	if (ret != EINVAL && ret != ENOTTY)
		return fail("could set frequency for invalid modulator %d\n", m);
	return node->modulators ? 0 : ENOTTY;
}
Пример #20
0
static int testEnumFrameIntervals(struct node *node, __u32 pixfmt, __u32 w, __u32 h, bool valid)
{
	struct v4l2_frmivalenum frmival;
	struct v4l2_frmival_stepwise *sw = &frmival.stepwise;
	bool found_stepwise = false;
	unsigned f = 0;
	int ret;

	for (;;) {
		memset(&frmival, 0xff, sizeof(frmival));
		frmival.index = f;
		frmival.pixel_format = pixfmt;
		frmival.width = w;
		frmival.height = h;

		ret = doioctl(node, VIDIOC_ENUM_FRAMEINTERVALS, &frmival);
		if (ret == ENOTTY)
			return ret;
		if (f == 0 && ret == EINVAL) {
			if (valid)
				warn("found framesize %dx%d, but no frame intervals\n", w, h);
			return ENOTTY;
		}
		if (ret == EINVAL)
			break;
		if (ret)
			return fail("expected EINVAL, but got %d when enumerating frameinterval %d\n", ret, f);
		ret = check_0(frmival.reserved, sizeof(frmival.reserved));
		if (ret)
			return fail("frmival.reserved not zeroed\n");
		if (frmival.pixel_format != pixfmt || frmival.index != f ||
				frmival.width != w || frmival.height != h)
			return fail("frmival.pixel_format, index, width or height changed\n");
		switch (frmival.type) {
		case V4L2_FRMIVAL_TYPE_DISCRETE:
			ret = check_fract(&frmival.discrete);
			if (found_stepwise)
				return fail("mixing discrete and stepwise is not allowed\n");
			break;
		case V4L2_FRMIVAL_TYPE_CONTINUOUS:
			if (sw->step.numerator != 1 || sw->step.denominator != 1)
				return fail("invalid step for continuous frameinterval\n");
			/* fallthrough */
		case V4L2_FRMIVAL_TYPE_STEPWISE:
			if (frmival.index)
				return fail("index must be 0 for stepwise/continuous frameintervals\n");
			found_stepwise = true;
			ret = check_fract(&sw->min);
			if (ret == 0)
				ret = check_fract(&sw->max);
			if (ret == 0)
				ret = check_fract(&sw->step);
			if (ret)
				return fail("invalid min, max or step for frameinterval %d\n", f);
			if (fract2f(&sw->min) > fract2f(&sw->max))
				return fail("min > max\n");
			if (fract2f(&sw->step) > fract2f(&sw->max) - fract2f(&sw->min))
				return fail("step > (max - min)\n");
			break;
		default:
			return fail("frmival.type is invalid\n");
		}

		f++;
	}
	if (!valid)
		return fail("found frame intervals for invalid size %dx%d\n", w, h);
	info("found %d frameintervals for pixel format %08x and size %dx%d\n", f, pixfmt, w, h);
	return 0;
}
Пример #21
0
static int testFormatsType(struct node *node, int ret,  unsigned type, struct v4l2_format &fmt)
{
	pixfmt_set &set = node->buftype_pixfmts[type];
	pixfmt_set *set_splane;
	struct v4l2_pix_format &pix = fmt.fmt.pix;
	struct v4l2_pix_format_mplane &pix_mp = fmt.fmt.pix_mp;
	struct v4l2_window &win = fmt.fmt.win;
	struct v4l2_vbi_format &vbi = fmt.fmt.vbi;
	struct v4l2_sliced_vbi_format &sliced = fmt.fmt.sliced;
	unsigned min_data_samples;
	unsigned min_sampling_rate;
	v4l2_std_id std;
	__u32 service_set = 0;
	unsigned cnt = 0;

	if (ret == ENOTTY)
		return ret;
	if (ret == EINVAL)
		return ENOTTY;
	if (ret)
		return fail("expected EINVAL, but got %d when getting format for buftype %d\n", ret, type);
	fail_on_test(fmt.type != type);

	switch (type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
		fail_on_test(!pix.width || !pix.height);
		if (set.find(pix.pixelformat) == set.end())
			return fail("unknown pixelformat %08x for buftype %d\n",
					pix.pixelformat, type);
		fail_on_test(pix.bytesperline && pix.bytesperline < pix.width);
		fail_on_test(!pix.sizeimage);
		fail_on_test(!pix.colorspace);
		fail_on_test(pix.field == V4L2_FIELD_ANY);
		if (pix.priv)
			warn("priv is non-zero!\n");
		break;
	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
		fail_on_test(!pix_mp.width || !pix_mp.height);
		set_splane = &node->buftype_pixfmts[type - 8];
		if (set.find(pix_mp.pixelformat) == set.end() &&
		    set_splane->find(pix_mp.pixelformat) == set_splane->end())
			return fail("unknown pixelformat %08x for buftype %d\n",
					pix_mp.pixelformat, type);
		fail_on_test(!pix_mp.colorspace);
		fail_on_test(pix.field == V4L2_FIELD_ANY);
		ret = check_0(pix_mp.reserved, sizeof(pix_mp.reserved));
		if (ret)
			return fail("pix_mp.reserved not zeroed\n");
		fail_on_test(pix_mp.num_planes == 0 || pix_mp.num_planes >= VIDEO_MAX_PLANES);
		for (int i = 0; i < pix_mp.num_planes; i++) {
			struct v4l2_plane_pix_format &pfmt = pix_mp.plane_fmt[i];

			ret = check_0(pfmt.reserved, sizeof(pfmt.reserved));
			if (ret)
				return fail("pix_mp.plane_fmt[%d].reserved not zeroed\n", i);
			fail_on_test(!pfmt.sizeimage);
			fail_on_test(pfmt.bytesperline && pfmt.bytesperline < pix_mp.width);
		}
		break;
	case V4L2_BUF_TYPE_VBI_CAPTURE:
	case V4L2_BUF_TYPE_VBI_OUTPUT:
		// Currently VBI assumes that you have G_STD as well.
		fail_on_test(doioctl(node, VIDIOC_G_STD, &std));
		if (std & V4L2_STD_625_50) {
			min_sampling_rate = 6937500;
			// the number of databits for PAL teletext is 18 (clock run in) +
			// 6 (framing code) + 42 * 8 (data).
			min_data_samples = (vbi.sampling_rate * (18 + 6 + 42 * 8)) / min_sampling_rate;
		} else {
			min_sampling_rate = 5727272;
			// the number of databits for NTSC teletext is 18 (clock run in) +
			// 6 (framing code) + 34 * 8 (data).
			min_data_samples = (vbi.sampling_rate * (18 + 6 + 34 * 8)) / min_sampling_rate;
		}
		fail_on_test(vbi.sampling_rate < min_sampling_rate);
		fail_on_test(!vbi.samples_per_line);
		fail_on_test(vbi.sample_format != V4L2_PIX_FMT_GREY);
		fail_on_test(vbi.offset > vbi.samples_per_line);
		ret = check_0(vbi.reserved, sizeof(vbi.reserved));
		if (ret)
			return fail("vbi.reserved not zeroed\n");
		// Check that offset leaves enough room for the maximum required
		// amount of data.
		fail_on_test(min_data_samples > vbi.samples_per_line - vbi.offset);
		fail_on_test(!vbi.count[0] || !vbi.count[1]);
		fail_on_test(vbi.flags & ~(V4L2_VBI_UNSYNC | V4L2_VBI_INTERLACED));
		if (vbi.flags & V4L2_VBI_INTERLACED)
			fail_on_test(vbi.count[0] != vbi.count[1]);
		break;
	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
		ret = check_0(sliced.reserved, sizeof(sliced.reserved));
		if (ret)
			return fail("sliced.reserved not zeroed\n");
		fail_on_test(sliced.service_lines[0][0] || sliced.service_lines[1][0]);
		for (int f = 0; f < 2; f++) {
			for (int i = 0; i < 24; i++) {
				if (sliced.service_lines[f][i])
					cnt++;
				service_set |= sliced.service_lines[f][i];
			}
		}
		fail_on_test(sliced.io_size < sizeof(struct v4l2_sliced_vbi_data) * cnt);
		fail_on_test(sliced.service_set != service_set);
		break;
	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
		fail_on_test(win.field == V4L2_FIELD_ANY);
		fail_on_test(win.clipcount && !(node->fbuf_caps & V4L2_FBUF_CAP_LIST_CLIPPING));
		for (struct v4l2_clip *clip = win.clips; clip; win.clipcount--) {
			fail_on_test(clip == NULL);
			clip = clip->next;
		}
		fail_on_test(win.clipcount);
		fail_on_test(win.chromakey && !(node->fbuf_caps & (V4L2_FBUF_CAP_CHROMAKEY | V4L2_FBUF_CAP_SRC_CHROMAKEY)));
		if (!(node->fbuf_caps & V4L2_FBUF_CAP_BITMAP_CLIPPING))
			fail_on_test(win.bitmap);
		fail_on_test(win.global_alpha && !(node->fbuf_caps & V4L2_FBUF_CAP_GLOBAL_ALPHA));
		break;
	case V4L2_BUF_TYPE_PRIVATE:
		break;
	}
	return 0;
}
int testModulatorFreq(struct node *node)
{
	struct v4l2_frequency freq;
	unsigned m;
	int ret;

	for (m = 0; m < node->modulators; m++) {
		struct v4l2_modulator modulator;
		
		modulator.index = m;
		ret = doioctl(node, VIDIOC_G_MODULATOR, &modulator);
		if (ret)
			return fail("could not get modulator %d\n", m);
		memset(&freq, 0, sizeof(freq));
		freq.tuner = m;
		ret = doioctl(node, VIDIOC_G_FREQUENCY, &freq);
		if (ret)
			return fail("could not get frequency for modulator %d\n", m);
		if (check_0(freq.reserved, sizeof(freq.reserved)))
			return fail("reserved was not zeroed\n");
		if (freq.tuner != m)
			return fail("frequency modulator field changed!\n");
		if (freq.frequency == 0)
			return fail("frequency not set\n");
		if (freq.frequency < modulator.rangelow || freq.frequency > modulator.rangehigh)
			warn("returned modulator %d frequency out of range (%d not in [%d...%d])\n",
					m, freq.frequency, modulator.rangelow, modulator.rangehigh);

		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set current frequency\n");
		freq.frequency = modulator.rangelow;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set rangelow frequency\n");
		freq.frequency = modulator.rangehigh;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set rangehigh frequency\n");
		freq.frequency = modulator.rangelow - 1;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret != EINVAL)
			return fail("set rangelow-1 frequency did not return EINVAL\n");
		freq.frequency = modulator.rangehigh + 1;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret != EINVAL)
			return fail("set rangehigh+1 frequency did not return EINVAL\n");
	}

	/* There is an ambiguity in the API and G/S_FREQUENCY: you cannot specify
	   correctly whether to the ioctl is for a tuner or a modulator. This should
	   be corrected, but until then the tests below have to be skipped if there
	   is a tuner of index m. */
	if (node->tuners > m)
		return 0;

	freq.tuner = m;
	ret = doioctl(node, VIDIOC_G_FREQUENCY, &freq);
	if (ret != EINVAL)
		return fail("could get frequency for invalid modulator %d\n", m);
	freq.tuner = m;
	// Radio: 100 MHz
	freq.frequency = 1600000;
	ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
	if (ret != EINVAL)
		return fail("could set frequency for invalid modulator %d\n", m);
	return node->modulators ? 0 : -ENOSYS;
}
Пример #23
0
static int testEnumFrameSizes(struct node *node, __u32 pixfmt)
{
	struct v4l2_frmsizeenum frmsize;
	struct v4l2_frmsize_stepwise *sw = &frmsize.stepwise;
	bool found_stepwise = false;
	unsigned f = 0;
	int ret;

	for (;;) {
		memset(&frmsize, 0xff, sizeof(frmsize));
		frmsize.index = f;
		frmsize.pixel_format = pixfmt;

		ret = doioctl(node, VIDIOC_ENUM_FRAMESIZES, &frmsize);
		if (ret == ENOTTY)
			return ret;
		if (f == 0 && ret == EINVAL)
			return ENOTTY;
		if (ret == EINVAL)
			break;
		if (ret)
			return fail("expected EINVAL, but got %d when enumerating framesize %d\n", ret, f);
		ret = check_0(frmsize.reserved, sizeof(frmsize.reserved));
		if (ret)
			return fail("frmsize.reserved not zeroed\n");
		if (frmsize.pixel_format != pixfmt || frmsize.index != f)
			return fail("frmsize.pixel_format or index changed\n");
		switch (frmsize.type) {
		case V4L2_FRMSIZE_TYPE_DISCRETE:
			if (frmsize.discrete.width == 0 || frmsize.discrete.height == 0)
				return fail("invalid width/height for discrete framesize\n");
			if (found_stepwise)
				return fail("mixing discrete and stepwise is not allowed\n");
			ret = testEnumFrameIntervals(node, pixfmt,
					frmsize.discrete.width, frmsize.discrete.height, true);
			if (ret && ret != ENOTTY)
				return ret;
			ret = testEnumFrameIntervals(node, pixfmt,
					frmsize.discrete.width + 1, frmsize.discrete.height, false);
			if (ret && ret != ENOTTY)
				return ret;
			break;
		case V4L2_FRMSIZE_TYPE_CONTINUOUS:
			if (frmsize.stepwise.step_width != 1 || frmsize.stepwise.step_height != 1)
				return fail("invalid step_width/height for continuous framesize\n");
			/* fallthrough */
		case V4L2_FRMSIZE_TYPE_STEPWISE:
			if (frmsize.index)
				return fail("index must be 0 for stepwise/continuous framesizes\n");
			found_stepwise = true;
			if (!sw->min_width || !sw->min_height || !sw->step_width || !sw->step_height)
				return fail("0 for min_width/height or step_width/height\n");
			if (sw->min_width > sw->max_width || sw->min_height > sw->max_height)
				return fail("min_width/height > max_width/height\n");
			if (sw->step_width > sw->max_width - sw->min_width ||
			    sw->step_height > sw->max_height - sw->min_height)
				return fail("step > max - min for width or height\n");
			ret = testEnumFrameIntervals(node, pixfmt,
					sw->min_width, sw->min_height, true);
			if (ret && ret != ENOTTY)
				return ret;
			ret = testEnumFrameIntervals(node, pixfmt,
					sw->max_width, sw->max_height, true);
			if (ret && ret != ENOTTY)
				return ret;
			ret = testEnumFrameIntervals(node, pixfmt,
					sw->min_width - 1, sw->min_height, false);
			if (ret && ret != ENOTTY)
				return ret;
			ret = testEnumFrameIntervals(node, pixfmt,
					sw->max_width, sw->max_height + 1, false);
			if (ret && ret != ENOTTY)
				return ret;
			break;
		default:
			return fail("frmsize.type is invalid\n");
		}

		f++;
	}
	info("found %d framesizes for pixel format %08x\n", f, pixfmt);
	return 0;
}
int testTunerFreq(struct node *node)
{
	struct v4l2_frequency freq;
	enum v4l2_tuner_type last_type = V4L2_TUNER_ANALOG_TV;
	unsigned t;
	int ret;

	for (t = 0; t < node->tuners; t++) {
		struct v4l2_tuner tuner;
		
		tuner.index = t;
		ret = doioctl(node, VIDIOC_G_TUNER, &tuner);
		if (ret)
			return fail("could not get tuner %d\n", t);
		last_type = tuner.type;
		memset(&freq, 0, sizeof(freq));
		freq.tuner = t;
		ret = doioctl(node, VIDIOC_G_FREQUENCY, &freq);
		if (ret)
			return fail("could not get frequency for tuner %d\n", t);
		if (check_0(freq.reserved, sizeof(freq.reserved)))
			return fail("reserved was not zeroed\n");
		if (freq.type != V4L2_TUNER_RADIO && freq.type != V4L2_TUNER_ANALOG_TV)
			return fail("returned invalid tuner type %d\n", freq.type);
		if (freq.type == V4L2_TUNER_RADIO && !(node->caps & V4L2_CAP_RADIO))
			return fail("radio tuner found but no radio capability set\n");
		if (freq.type != tuner.type)
			return fail("frequency tuner type and tuner type mismatch\n");
		if (freq.tuner != t)
			return fail("frequency tuner field changed!\n");
		if (freq.frequency == 0)
			return fail("frequency not set\n");
		if (freq.frequency < tuner.rangelow || freq.frequency > tuner.rangehigh)
			warn("returned tuner %d frequency out of range (%d not in [%d...%d])\n",
					t, freq.frequency, tuner.rangelow, tuner.rangehigh);

		freq.type = (enum v4l2_tuner_type)0;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret != EINVAL)
			return fail("did not return EINVAL when passed tuner type 0\n");
		freq.type = tuner.type;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set current frequency\n");
		freq.frequency = tuner.rangelow;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set rangelow frequency\n");
		freq.frequency = tuner.rangehigh;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set rangehigh frequency\n");
		freq.frequency = tuner.rangelow - 1;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret != EINVAL)
			return fail("set rangelow-1 frequency did not return EINVAL\n");
		freq.frequency = tuner.rangehigh + 1;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret != EINVAL)
			return fail("set rangehigh+1 frequency did not return EINVAL\n");
	}

	/* There is an ambiguity in the API and G/S_FREQUENCY: you cannot specify
	   correctly whether to the ioctl is for a tuner or a modulator. This should
	   be corrected, but until then the tests below have to be skipped if there
	   is a modulator of index t. */
	if (node->modulators > t)
		return 0;

	freq.tuner = t;
	ret = doioctl(node, VIDIOC_G_FREQUENCY, &freq);
	if (ret != EINVAL)
		return fail("could get frequency for invalid tuner %d\n", t);
	freq.tuner = t;
	freq.type = last_type;
	// TV: 400 Mhz Radio: 100 MHz
	freq.frequency = last_type == V4L2_TUNER_ANALOG_TV ? 6400 : 1600000;
	ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
	if (ret != EINVAL)
		return fail("could set frequency for invalid tuner %d\n", t);
	return node->tuners ? 0 : -ENOSYS;
}
static int testFormatsType(struct node *node, enum v4l2_buf_type type)
{
	pixfmt_set &set = node->buftype_pixfmts[type];
	pixfmt_set *set_splane;
	struct v4l2_format fmt;
	struct v4l2_pix_format &pix = fmt.fmt.pix;
	struct v4l2_pix_format_mplane &pix_mp = fmt.fmt.pix_mp;
	struct v4l2_window &win = fmt.fmt.win;
	struct v4l2_vbi_format &vbi = fmt.fmt.vbi;
	struct v4l2_sliced_vbi_format &sliced = fmt.fmt.sliced;
	__u32 service_set = 0;
	unsigned cnt = 0;
	int ret;
	
	memset(&fmt, 0xff, sizeof(fmt));
	fmt.type = type;
	ret = doioctl(node, VIDIOC_G_FMT, &fmt);
	if (ret == EINVAL)
		return -ENOSYS;
	if (ret)
		return fail("expected EINVAL, but got %d when getting format for buftype %d\n", ret, type);
	fail_on_test(fmt.type != type);
	
	switch (type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
		fail_on_test(!pix.width || !pix.height);
		if (set.find(pix.pixelformat) == set.end())
			return fail("unknown pixelformat %08x for buftype %d\n",
					pix.pixelformat, type);
		fail_on_test(pix.bytesperline && pix.bytesperline < pix.width);
		fail_on_test(!pix.sizeimage);
		fail_on_test(!pix.colorspace);
		if (pix.priv)
			warn("priv is non-zero!\n");
		break;
	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
		fail_on_test(!pix_mp.width || !pix_mp.height);
		set_splane = &node->buftype_pixfmts[type - 8];
		if (set.find(pix_mp.pixelformat) == set.end() &&
		    set_splane->find(pix_mp.pixelformat) == set_splane->end())
			return fail("unknown pixelformat %08x for buftype %d\n",
					pix_mp.pixelformat, type);
		fail_on_test(!pix_mp.colorspace);
		ret = check_0(pix_mp.reserved, sizeof(pix_mp.reserved));
		if (ret)
			return fail("pix_mp.reserved not zeroed\n");
		fail_on_test(pix_mp.num_planes == 0 || pix_mp.num_planes >= VIDEO_MAX_PLANES);
		for (int i = 0; i < pix_mp.num_planes; i++) {
			struct v4l2_plane_pix_format &pfmt = pix_mp.plane_fmt[i];

			ret = check_0(pfmt.reserved, sizeof(pfmt.reserved));
			if (ret)
				return fail("pix_mp.plane_fmt[%d].reserved not zeroed\n", i);
			fail_on_test(!pfmt.sizeimage);
			fail_on_test(pfmt.bytesperline && pfmt.bytesperline < pix_mp.width);
		}
		break;
	case V4L2_BUF_TYPE_VBI_CAPTURE:
	case V4L2_BUF_TYPE_VBI_OUTPUT:
		fail_on_test(!vbi.sampling_rate);
		fail_on_test(!vbi.samples_per_line);
		fail_on_test(vbi.sample_format != V4L2_PIX_FMT_GREY);
		fail_on_test(vbi.offset > vbi.samples_per_line);
		ret = check_0(vbi.reserved, sizeof(vbi.reserved));
		if (ret)
			return fail("vbi.reserved not zeroed\n");
		fail_on_test(!vbi.count[0] || !vbi.count[1]);
		fail_on_test(vbi.flags & ~(V4L2_VBI_UNSYNC | V4L2_VBI_INTERLACED));
		if (vbi.flags & V4L2_VBI_INTERLACED)
			fail_on_test(vbi.count[0] != vbi.count[1]);
		break;
	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
		ret = check_0(sliced.reserved, sizeof(sliced.reserved));
		if (ret)
			return fail("sliced.reserved not zeroed\n");
		fail_on_test(sliced.service_lines[0][0] || sliced.service_lines[1][0]);
		for (int f = 0; f < 2; f++) {
			for (int i = 0; i < 24; i++) {
				if (sliced.service_lines[f][i])
					cnt++;
				service_set |= sliced.service_lines[f][i];
			}
		}
		fail_on_test(sliced.io_size < sizeof(struct v4l2_sliced_vbi_data) * cnt);
		fail_on_test(sliced.service_set != service_set);
		break;
	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
		fail_on_test(win.field != V4L2_FIELD_ANY &&
			     win.field != V4L2_FIELD_TOP &&
			     win.field != V4L2_FIELD_BOTTOM &&
			     win.field != V4L2_FIELD_INTERLACED);
		fail_on_test(win.clipcount && !(node->fbuf_caps & V4L2_FBUF_CAP_LIST_CLIPPING));
		for (struct v4l2_clip *clip = win.clips; clip; win.clipcount--) {
			fail_on_test(clip == NULL);
			clip = clip->next;
		}
		fail_on_test(win.clipcount);
		fail_on_test(win.chromakey && !(node->fbuf_caps & (V4L2_FBUF_CAP_CHROMAKEY | V4L2_FBUF_CAP_SRC_CHROMAKEY)));
		if (!(node->fbuf_caps & V4L2_FBUF_CAP_BITMAP_CLIPPING))
			fail_on_test(win.bitmap);
		fail_on_test(win.global_alpha && !(node->fbuf_caps & V4L2_FBUF_CAP_GLOBAL_ALPHA));
		break;
	case V4L2_BUF_TYPE_PRIVATE:
		break;
	}
	return 0;
}
int testTunerFreq(struct node *node)
{
	struct v4l2_frequency freq;
	enum v4l2_tuner_type last_type = V4L2_TUNER_ANALOG_TV;
	unsigned t;
	int ret;

	for (t = 0; t < node->tuners; t++) {
		struct v4l2_tuner tuner;
		
		tuner.index = t;
		ret = doioctl(node, VIDIOC_G_TUNER, &tuner);
		if (ret)
			return fail("could not get tuner %d\n", t);
		last_type = (enum v4l2_tuner_type)tuner.type;
		memset(&freq, 0, sizeof(freq));
		freq.tuner = t;
		ret = doioctl(node, VIDIOC_G_FREQUENCY, &freq);
		if (ret)
			return fail("could not get frequency for tuner %d\n", t);
		if (check_0(freq.reserved, sizeof(freq.reserved)))
			return fail("reserved was not zeroed\n");
		if (freq.type != V4L2_TUNER_RADIO && freq.type != V4L2_TUNER_ANALOG_TV &&
		    freq.type != V4L2_TUNER_ADC && freq.type != V4L2_TUNER_RF)
			return fail("returned invalid tuner type %d\n", freq.type);
		if (freq.type == V4L2_TUNER_RADIO && !(node->caps & V4L2_CAP_RADIO))
			return fail("radio tuner found but no radio capability set\n");
		if ((freq.type == V4L2_TUNER_ADC || freq.type == V4L2_TUNER_RF) &&
		    !(node->caps & V4L2_CAP_SDR_CAPTURE))
			return fail("sdr tuner found but no sdr capture capability set\n");
		if (freq.type != tuner.type)
			return fail("frequency tuner type and tuner type mismatch\n");
		if (freq.tuner != t)
			return fail("frequency tuner field changed!\n");
		if (freq.frequency == 0)
			return fail("frequency not set\n");
		if (freq.frequency < tuner.rangelow || freq.frequency > tuner.rangehigh)
			warn("returned tuner %d frequency out of range (%d not in [%d...%d])\n",
					t, freq.frequency, tuner.rangelow, tuner.rangehigh);

		freq.type = (enum v4l2_tuner_type)0;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret != EINVAL)
			return fail("did not return EINVAL when passed tuner type 0\n");
		freq.type = tuner.type;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set current frequency\n");
		freq.frequency = tuner.rangelow;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set rangelow frequency\n");
		freq.frequency = tuner.rangehigh;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set rangehigh frequency\n");
		freq.frequency = tuner.rangelow - 1;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set rangelow-1 frequency\n");
		ret = doioctl(node, VIDIOC_G_FREQUENCY, &freq);
		if (ret || freq.frequency != tuner.rangelow)
			return fail("frequency rangelow-1 wasn't mapped to rangelow\n");
		freq.frequency = tuner.rangehigh + 1;
		ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
		if (ret)
			return fail("could not set rangehigh+1 frequency\n");
		ret = doioctl(node, VIDIOC_G_FREQUENCY, &freq);
		if (ret || freq.frequency != tuner.rangehigh)
			return fail("frequency rangehigh+1 wasn't mapped to rangehigh\n");
	}

	/* If this is a modulator device, then skip the remaining tests */
	if (node->caps & V4L2_CAP_MODULATOR)
		return 0;

	freq.tuner = t;
	ret = doioctl(node, VIDIOC_G_FREQUENCY, &freq);
	if (ret != EINVAL && ret != ENOTTY)
		return fail("could get frequency for invalid tuner %d\n", t);
	freq.tuner = t;
	freq.type = last_type;
	// TV: 400 Mhz Radio: 100 MHz
	freq.frequency = last_type == V4L2_TUNER_ANALOG_TV ? 6400 : 1600000;
	ret = doioctl(node, VIDIOC_S_FREQUENCY, &freq);
	if (ret != EINVAL && ret != ENOTTY)
		return fail("could set frequency for invalid tuner %d\n", t);
	return node->tuners ? 0 : ENOTTY;
}
Пример #27
0
static int checkStd(struct node *node, bool has_std, v4l2_std_id mask, bool is_input)
{
	v4l2_std_id std_mask = 0;
	v4l2_std_id std;
	struct v4l2_standard enumstd;
	unsigned i;
	int ret;

	ret = doioctl(node, VIDIOC_G_STD, &std);
	if (ret && has_std)
		return fail("STD cap set, but could not get standard\n");
	if (!ret && !has_std)
		return fail("STD cap not set, but could still get a standard\n");
	if (ret != ENOTTY && ret != ENODATA && !has_std)
		return fail("STD cap not set, but got wrong error code (%d)\n", ret);
	if (!ret && has_std) {
		if (std & ~mask)
			warn("current standard is invalid according to the standard mask\n");
		if (std == 0)
			return fail("Standard == 0?!\n");
		if (std & V4L2_STD_ATSC)
			return fail("Current standard contains ATSC standards. This is no longer supported\n");
	}
	ret = doioctl(node, VIDIOC_S_STD, &std);
	if (ret && has_std)
		return fail("STD cap set, but could not set standard\n");
	if (!ret && !has_std)
		return fail("STD cap not set, but could still set a standard\n");
	std = V4L2_STD_ATSC;
	ret = doioctl(node, VIDIOC_S_STD, &std);
	if (ret != EINVAL && ret != ENOTTY)
		return fail("could set standard to ATSC, which is not supported anymore\n");
	for (i = 0; ; i++) {
		memset(&enumstd, 0xff, sizeof(enumstd));

		enumstd.index = i;
		ret = doioctl(node, VIDIOC_ENUMSTD, &enumstd);
		if (ret)
			break;
		std_mask |= enumstd.id;
		if (check_ustring(enumstd.name, sizeof(enumstd.name)))
			return fail("invalid standard name\n");
		if (check_0(enumstd.reserved, sizeof(enumstd.reserved)))
			return fail("reserved not zeroed\n");
		if (enumstd.framelines == 0)
			return fail("framelines not filled\n");
		if (enumstd.framelines != 625 && enumstd.framelines != 525)
			warn("strange framelines value %d for standard %08llx\n",
					enumstd.framelines, enumstd.id);
		if (enumstd.frameperiod.numerator == 0 || enumstd.frameperiod.denominator == 0)
			return fail("frameperiod is not filled\n");
		if (enumstd.index != i)
			return fail("index changed!\n");
		if (enumstd.id == 0)
			return fail("empty standard returned\n");
	}
	if (i == 0 && has_std)
		return fail("STD cap set, but no standards can be enumerated\n");
	if (i && !has_std)
		return fail("STD cap was not set, but standards can be enumerated\n");
	if (ret != ENOTTY && ret != ENODATA && !has_std)
		return fail("STD cap not set, but got wrong error code for enumeration (%d)\n", ret);
	if (std_mask & V4L2_STD_ATSC)
		return fail("STD mask contains ATSC standards. This is no longer supported\n");
	if (has_std && std_mask != mask)
		return fail("the union of ENUMSTD does not match the standard mask (%llx != %llx)\n",
				std_mask, mask);
	ret = doioctl(node, VIDIOC_QUERYSTD, &std);
	if (!ret && !has_std)
		return fail("STD cap was not set, but could still query standard\n");
	if (ret != ENOTTY && ret != ENODATA && !has_std)
		return fail("STD cap not set, but got wrong error code for query (%d)\n", ret);
	if (ret != ENOTTY && !is_input)
		return fail("this is an output, but could still query standard\n");
	if (!ret && is_input && (std & ~std_mask))
		return fail("QUERYSTD gives back an unsupported standard\n");
	return 0;
}
static int checkTuner(struct node *node, const struct v4l2_tuner &tuner,
		unsigned t, v4l2_std_id std)
{
	bool valid_modes[5] = { true, false, false, false, false };
	bool tv = node->is_video || node->is_vbi;
	bool hwseek_caps = tuner.capability & (V4L2_TUNER_CAP_HWSEEK_BOUNDED |
			V4L2_TUNER_CAP_HWSEEK_WRAP | V4L2_TUNER_CAP_HWSEEK_PROG_LIM);
	unsigned type = tv ? V4L2_TUNER_ANALOG_TV : V4L2_TUNER_RADIO;
	__u32 audmode;

	if (tuner.index != t)
		return fail("invalid index\n");
	if (check_ustring(tuner.name, sizeof(tuner.name)))
		return fail("invalid name\n");
	if (check_0(tuner.reserved, sizeof(tuner.reserved)))
		return fail("non-zero reserved fields\n");
	if (node->is_sdr) {
		fail_on_test(tuner.type != V4L2_TUNER_ADC && tuner.type != V4L2_TUNER_RF);
	} else if (tuner.type != type) {
		return fail("invalid tuner type %d\n", tuner.type);
	}
	if (tv && (tuner.capability & V4L2_TUNER_CAP_RDS))
		return fail("RDS for TV tuner?\n");
	if (!tv && (tuner.capability & (V4L2_TUNER_CAP_NORM |
					V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2)))
		return fail("TV capabilities for radio tuner?\n");
	if (tv && (tuner.capability & (V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_1HZ)))
		return fail("did not expect to see V4L2_TUNER_CAP_LOW/1HZ set for a tv tuner\n");
	if (node->is_radio && !(tuner.capability & V4L2_TUNER_CAP_LOW))
		return fail("V4L2_TUNER_CAP_LOW was not set for a radio tuner\n");
	fail_on_test((tuner.capability & V4L2_TUNER_CAP_LOW) &&
		     (tuner.capability & V4L2_TUNER_CAP_1HZ));
	if (node->is_sdr)
		fail_on_test(!(V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_1HZ));
	fail_on_test(!(tuner.capability & V4L2_TUNER_CAP_FREQ_BANDS));
	fail_on_test(!(node->caps & V4L2_CAP_HW_FREQ_SEEK) && hwseek_caps);
	fail_on_test((node->caps & V4L2_CAP_HW_FREQ_SEEK) &&
		!(tuner.capability & (V4L2_TUNER_CAP_HWSEEK_BOUNDED | V4L2_TUNER_CAP_HWSEEK_WRAP)));
	if (tuner.rangelow >= tuner.rangehigh)
		return fail("rangelow >= rangehigh\n");
	if (tuner.rangelow == 0 || tuner.rangehigh == 0xffffffff)
		return fail("invalid rangelow or rangehigh\n");
	if (!(tuner.capability & V4L2_TUNER_CAP_STEREO) &&
			(tuner.rxsubchans & V4L2_TUNER_SUB_STEREO))
		return fail("stereo subchan, but no stereo caps?\n");
	if (!(tuner.capability & V4L2_TUNER_CAP_LANG1) &&
			(tuner.rxsubchans & V4L2_TUNER_SUB_LANG1))
		return fail("lang1 subchan, but no lang1 caps?\n");
	if (!(tuner.capability & V4L2_TUNER_CAP_LANG2) &&
			(tuner.rxsubchans & V4L2_TUNER_SUB_LANG2))
		return fail("lang2 subchan, but no lang2 caps?\n");
	if (!(tuner.capability & V4L2_TUNER_CAP_RDS) &&
			(tuner.rxsubchans & V4L2_TUNER_SUB_RDS))
		return fail("RDS subchan, but no RDS caps?\n");
	bool have_rds = tuner.capability & V4L2_TUNER_CAP_RDS;
	bool have_rds_method = tuner.capability &
                        (V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_RDS_CONTROLS);
	if (have_rds ^ have_rds_method)
		return fail("V4L2_TUNER_CAP_RDS is set, but not V4L2_TUNER_CAP_RDS_* or vice versa\n");
	fail_on_test(node->is_sdr && have_rds);
	if ((tuner.capability & V4L2_TUNER_CAP_RDS_BLOCK_IO) &&
			!(node->caps & V4L2_CAP_READWRITE))
		return fail("V4L2_TUNER_CAP_RDS_BLOCK_IO is set, but not V4L2_CAP_READWRITE\n");
	if (node->is_radio && !(tuner.capability & V4L2_TUNER_CAP_RDS_BLOCK_IO) &&
			(node->caps & V4L2_CAP_READWRITE))
		return fail("V4L2_TUNER_CAP_RDS_BLOCK_IO is not set, but V4L2_CAP_READWRITE is\n");
	if (std == V4L2_STD_NTSC_M && (tuner.rxsubchans & V4L2_TUNER_SUB_LANG1))
		return fail("LANG1 subchan, but NTSC-M standard\n");
	if (tuner.audmode > V4L2_TUNER_MODE_LANG1_LANG2)
		return fail("invalid audio mode\n");
	if (!tv && tuner.audmode > V4L2_TUNER_MODE_STEREO)
		return fail("invalid audio mode for radio device\n");
	if (tuner.signal > 65535)
		return fail("signal too large\n");
	if (tuner.capability & V4L2_TUNER_CAP_STEREO)
		valid_modes[V4L2_TUNER_MODE_STEREO] = true;
	if (tuner.capability & V4L2_TUNER_CAP_LANG1)
		valid_modes[V4L2_TUNER_MODE_LANG1] = true;
	if (tuner.capability & V4L2_TUNER_CAP_LANG2) {
		valid_modes[V4L2_TUNER_MODE_LANG2] = true;
		valid_modes[V4L2_TUNER_MODE_LANG1_LANG2] = true;
	}
	for (audmode = 0; audmode < 5; audmode++) {
		struct v4l2_tuner tun = { 0 };

		tun.index = tuner.index;
		tun.audmode = audmode;
		if (doioctl(node, VIDIOC_S_TUNER, &tun))
			return fail("cannot set audmode %d\n", audmode);
		if (doioctl(node, VIDIOC_G_TUNER, &tun))
			fail("failure to get new tuner audmode\n");
		if (tun.audmode > V4L2_TUNER_MODE_LANG1_LANG2)
			return fail("invalid new audmode\n");
		if (!valid_modes[tun.audmode])
			return fail("accepted invalid audmode %d\n", audmode);
	}
	return checkEnumFreqBands(node, tuner.index, tuner.type, tuner.capability);
}
Пример #29
0
static int testCap(struct node *node)
{
	struct v4l2_capability vcap;
	__u32 caps, dcaps;
	const __u32 video_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
			V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE |
			V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE |
			V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
	const __u32 vbi_caps = V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE |
			V4L2_CAP_VBI_OUTPUT | V4L2_CAP_SLICED_VBI_OUTPUT;
	const __u32 radio_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR;
	const __u32 input_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
			V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE |
			V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_HW_FREQ_SEEK |
			V4L2_CAP_TUNER;
	const __u32 output_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE |
			V4L2_CAP_VIDEO_OUTPUT_OVERLAY | V4L2_CAP_VBI_OUTPUT |
			V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_MODULATOR;
	const __u32 overlay_caps = V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
	const __u32 m2m_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE;
	const __u32 io_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
	const __u32 mplane_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE |
		V4L2_CAP_VIDEO_M2M_MPLANE;
	const __u32 splane_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
		V4L2_CAP_VIDEO_M2M;

	memset(&vcap, 0xff, sizeof(vcap));
	// Must always be there
	fail_on_test(doioctl(node, VIDIOC_QUERYCAP, &vcap));
	fail_on_test(check_ustring(vcap.driver, sizeof(vcap.driver)));
	fail_on_test(check_ustring(vcap.card, sizeof(vcap.card)));
	fail_on_test(check_ustring(vcap.bus_info, sizeof(vcap.bus_info)));
	// Check for valid prefixes
	if (memcmp(vcap.bus_info, "usb-", 4) &&
	    memcmp(vcap.bus_info, "PCI:", 4) &&
	    memcmp(vcap.bus_info, "PCIe:", 5) &&
	    memcmp(vcap.bus_info, "ISA:", 4) &&
	    memcmp(vcap.bus_info, "I2C:", 4) &&
	    memcmp(vcap.bus_info, "parport", 7) &&
	    memcmp(vcap.bus_info, "platform:", 9))
		return fail("missing bus_info prefix ('%s')\n", vcap.bus_info);
	fail_on_test((vcap.version >> 16) < 3);
	fail_on_test(check_0(vcap.reserved, sizeof(vcap.reserved)));
	caps = vcap.capabilities;
	dcaps = vcap.device_caps;
	node->is_m2m = dcaps & m2m_caps;
	fail_on_test(caps == 0);
	fail_on_test(caps & V4L2_CAP_ASYNCIO);
	fail_on_test(!(caps & V4L2_CAP_DEVICE_CAPS));
	fail_on_test(dcaps & V4L2_CAP_DEVICE_CAPS);
	fail_on_test(dcaps & ~caps);
	fail_on_test(!(dcaps & caps));
	fail_on_test(node->is_video && !(dcaps & video_caps));
	fail_on_test(node->is_radio && !(dcaps & radio_caps));
	// V4L2_CAP_AUDIO is invalid for radio
	fail_on_test(node->is_radio && (dcaps & V4L2_CAP_AUDIO));
	fail_on_test(node->is_vbi && !(dcaps & vbi_caps));
	// You can't have both set due to missing buffer type in VIDIOC_G/S_FBUF
	fail_on_test((dcaps & overlay_caps) == overlay_caps);
	// Overlay support makes no sense for m2m devices
	fail_on_test((dcaps & m2m_caps) && (dcaps & overlay_caps));
	fail_on_test(node->is_video && (dcaps & (vbi_caps | radio_caps)));
	fail_on_test(node->is_radio && (dcaps & (vbi_caps | video_caps)));
	fail_on_test(node->is_vbi && (dcaps & (video_caps | radio_caps)));
	if (node->is_m2m) {
		// This will become an error as this combination of caps
		// is on the feature removal list.
		if ((dcaps & input_caps) && (dcaps & output_caps))
			warn("VIDIOC_QUERYCAP: m2m with video input and output caps\n");
	} else {
		if (dcaps & input_caps)
			fail_on_test(dcaps & output_caps);
		if (dcaps & output_caps)
			fail_on_test(dcaps & input_caps);
	}
	if (node->can_capture || node->can_output) {
		// whether io_caps need to be set for RDS capture/output is
		// checked elsewhere as that depends on the tuner/modulator
		// capabilities.
		if (!(dcaps & (V4L2_CAP_RDS_CAPTURE | V4L2_CAP_RDS_OUTPUT)))
			fail_on_test(!(dcaps & io_caps));
	} else {
		fail_on_test(dcaps & io_caps);
	}
	// having both mplane and splane caps is not allowed (at least for now)
	fail_on_test((dcaps & mplane_caps) && (dcaps & splane_caps));

	return 0;
}
static int checkTuner(struct node *node, const struct v4l2_tuner &tuner,
		unsigned t, v4l2_std_id std)
{
	bool valid_modes[5] = { true, false, false, true, false };
	bool tv = !node->is_radio;
	enum v4l2_tuner_type type = tv ? V4L2_TUNER_ANALOG_TV : V4L2_TUNER_RADIO;
	__u32 audmode;

	if (tuner.index != t)
		return fail("invalid index\n");
	if (check_ustring(tuner.name, sizeof(tuner.name)))
		return fail("invalid name\n");
	if (check_0(tuner.reserved, sizeof(tuner.reserved)))
		return fail("non-zero reserved fields\n");
	if (tuner.type != type)
		return fail("invalid tuner type %d\n", tuner.type);
	if (tv && (tuner.capability & V4L2_TUNER_CAP_RDS))
		return fail("RDS for TV tuner?\n");
	if (!tv && (tuner.capability & (V4L2_TUNER_CAP_NORM |
					V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2)))
		return fail("TV capabilities for radio tuner?\n");
	if (tv && (tuner.capability & V4L2_TUNER_CAP_LOW))
		return fail("did not expect to see V4L2_TUNER_CAP_LOW set for a tv tuner\n");
	if (!tv && !(tuner.capability & V4L2_TUNER_CAP_LOW))
		return fail("V4L2_TUNER_CAP_LOW was not set for a radio tuner\n");
	if (tuner.rangelow >= tuner.rangehigh)
		return fail("rangelow >= rangehigh\n");
	if (tuner.rangelow == 0 || tuner.rangehigh == 0xffffffff)
		return fail("invalid rangelow or rangehigh\n");
	if (!(tuner.capability & V4L2_TUNER_CAP_STEREO) &&
			(tuner.rxsubchans & V4L2_TUNER_SUB_STEREO))
		return fail("stereo subchan, but no stereo caps?\n");
	if (!(tuner.capability & V4L2_TUNER_CAP_LANG1) &&
			(tuner.rxsubchans & V4L2_TUNER_SUB_LANG1))
		return fail("lang1 subchan, but no lang1 caps?\n");
	if (!(tuner.capability & V4L2_TUNER_CAP_LANG2) &&
			(tuner.rxsubchans & V4L2_TUNER_SUB_LANG2))
		return fail("lang2 subchan, but no lang2 caps?\n");
	if (!(tuner.capability & V4L2_TUNER_CAP_RDS) &&
			(tuner.rxsubchans & V4L2_TUNER_SUB_RDS))
		return fail("RDS subchan, but no RDS caps?\n");
	if (std == V4L2_STD_NTSC_M && (tuner.rxsubchans & V4L2_TUNER_SUB_LANG1))
		return fail("LANG1 subchan, but NTSC-M standard\n");
	if (tuner.audmode > V4L2_TUNER_MODE_LANG1_LANG2)
		return fail("invalid audio mode\n");
	// Ambiguous whether this is allowed or not
	//		if (!tv && tuner.audmode > V4L2_TUNER_MODE_STEREO)
	//			return -16;
	if (tuner.signal > 65535)
		return fail("signal too large\n");
	if (tuner.capability & V4L2_TUNER_CAP_STEREO)
		valid_modes[V4L2_TUNER_MODE_STEREO] = true;
	if (tuner.capability & V4L2_TUNER_CAP_LANG2) {
		valid_modes[V4L2_TUNER_MODE_LANG2] = true;
		valid_modes[V4L2_TUNER_MODE_LANG1_LANG2] = true;
	}
	for (audmode = 0; audmode < 5; audmode++) {
		struct v4l2_tuner tun = { 0 };

		tun.index = tuner.index;
		tun.audmode = audmode;
		if (doioctl(node, VIDIOC_S_TUNER, &tun))
			return fail("cannot set audmode %d\n", audmode);
		if (doioctl(node, VIDIOC_G_TUNER, &tun))
			fail("failure to get new tuner audmode\n");
		if (tun.audmode > V4L2_TUNER_MODE_LANG1_LANG2)
			return fail("invalid new audmode\n");
		// Ambiguous whether this is allowed or not
		//	if (!tv && tun.audmode > V4L2_TUNER_MODE_STEREO)
		//		return -21;
		//	if (!valid_modes[tun.audmode])
		//		return fail("accepted invalid audmode %d\n", audmode);
	}
	return 0;
}