• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     V4L2 API compliance control ioctl tests.
3 
4     Copyright (C) 2011  Hans Verkuil <hverkuil@xs4all.nl>
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
19  */
20 
21 #include <map>
22 #include <set>
23 #include <vector>
24 
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <sys/epoll.h>
28 
29 #include "compiler.h"
30 #include "v4l2-compliance.h"
31 
checkQCtrl(struct node * node,struct test_query_ext_ctrl & qctrl)32 static int checkQCtrl(struct node *node, struct test_query_ext_ctrl &qctrl)
33 {
34 	struct v4l2_querymenu qmenu;
35 	__u32 fl = qctrl.flags;
36 	__u32 rw_mask = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
37 	int ret;
38 	int i;
39 
40 	qctrl.menu_mask = 0;
41 	if (check_string(qctrl.name, sizeof(qctrl.name)))
42 		return fail("invalid name\n");
43 	info("checking v4l2_query_ext_ctrl of control '%s' (0x%08x)\n", qctrl.name, qctrl.id);
44 	if (qctrl.id & V4L2_CTRL_FLAG_NEXT_CTRL)
45 		return fail("V4L2_CTRL_FLAG_NEXT_CTRL not cleared\n");
46 	if (check_0(qctrl.reserved, sizeof(qctrl.reserved)))
47 		return fail("non-zero reserved fields\n");
48 	if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
49 		if ((qctrl.id & 0xffff) != 1)
50 			return fail("invalid control ID for a control class\n");
51 	} else if (qctrl.id < V4L2_CID_PRIVATE_BASE) {
52 		if ((qctrl.id & 0xffff) < 0x900)
53 			return fail("invalid control ID\n");
54 	}
55 	switch (qctrl.type) {
56 	case V4L2_CTRL_TYPE_BOOLEAN:
57 		if (qctrl.maximum > 1)
58 			return fail("invalid boolean max value\n");
59 		fallthrough;
60 	case V4L2_CTRL_TYPE_MENU:
61 	case V4L2_CTRL_TYPE_INTEGER_MENU:
62 		if (qctrl.step != 1)
63 			return fail("invalid step value %lld\n", qctrl.step);
64 		if (qctrl.minimum < 0)
65 			return fail("min < 0\n");
66 		fallthrough;
67 	case V4L2_CTRL_TYPE_INTEGER:
68 	case V4L2_CTRL_TYPE_INTEGER64:
69 		if (qctrl.default_value < qctrl.minimum ||
70 		    qctrl.default_value > qctrl.maximum)
71 			return fail("def < min || def > max\n");
72 		fallthrough;
73 	case V4L2_CTRL_TYPE_STRING:
74 		if (qctrl.minimum > qctrl.maximum)
75 			return fail("min > max\n");
76 		if (qctrl.step == 0)
77 			return fail("step == 0\n");
78 		if (static_cast<unsigned>(qctrl.step) > static_cast<unsigned>(qctrl.maximum - qctrl.minimum) &&
79 		    qctrl.maximum != qctrl.minimum)
80 			return fail("step > max - min\n");
81 		if ((qctrl.maximum - qctrl.minimum) % qctrl.step) {
82 			// This really should be a fail, but there are so few
83 			// drivers that do this right that I made it a warning
84 			// for now.
85 			warn("%s: (max - min) %% step != 0\n", qctrl.name);
86 		}
87 		break;
88 	case V4L2_CTRL_TYPE_BITMASK:
89 		if (qctrl.minimum)
90 			return fail("minimum must be 0 for a bitmask control\n");
91 		if (qctrl.step)
92 			return fail("step must be 0 for a bitmask control\n");
93 		if (!qctrl.maximum)
94 			return fail("maximum must be non-zero for a bitmask control\n");
95 		if (qctrl.default_value & ~qctrl.maximum)
96 			return fail("default_value is out of range for a bitmask control\n");
97 		break;
98 	case V4L2_CTRL_TYPE_CTRL_CLASS:
99 	case V4L2_CTRL_TYPE_BUTTON:
100 		if (qctrl.minimum || qctrl.maximum || qctrl.step || qctrl.default_value)
101 			return fail("non-zero min/max/step/def\n");
102 		break;
103 	default:
104 		if (qctrl.type >= V4L2_CTRL_COMPOUND_TYPES)
105 			break;
106 		return fail("unknown control type\n");
107 	}
108 	if (qctrl.type == V4L2_CTRL_TYPE_STRING && qctrl.default_value)
109 		return fail("non-zero default value for string\n");
110 	switch (qctrl.type) {
111 	case V4L2_CTRL_TYPE_BUTTON:
112 		if ((fl & rw_mask) != V4L2_CTRL_FLAG_WRITE_ONLY)
113 			return fail("button control not write only\n");
114 		fallthrough;
115 	case V4L2_CTRL_TYPE_BOOLEAN:
116 	case V4L2_CTRL_TYPE_MENU:
117 	case V4L2_CTRL_TYPE_INTEGER_MENU:
118 	case V4L2_CTRL_TYPE_STRING:
119 	case V4L2_CTRL_TYPE_BITMASK:
120 		if (fl & V4L2_CTRL_FLAG_SLIDER)
121 			return fail("slider makes only sense for integer controls\n");
122 		fallthrough;
123 	case V4L2_CTRL_TYPE_INTEGER64:
124 	case V4L2_CTRL_TYPE_INTEGER:
125 		if ((fl & rw_mask) == rw_mask)
126 			return fail("can't read nor write this control\n");
127 		break;
128 	case V4L2_CTRL_TYPE_CTRL_CLASS:
129 		if (fl != (V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY))
130 			return fail("invalid flags for control class\n");
131 		break;
132 	}
133 	if (fl & V4L2_CTRL_FLAG_GRABBED)
134 		return fail("GRABBED flag set\n");
135 	if (fl & V4L2_CTRL_FLAG_DISABLED)
136 		return fail("DISABLED flag set\n");
137 	if (qctrl.type != V4L2_CTRL_TYPE_MENU && qctrl.type != V4L2_CTRL_TYPE_INTEGER_MENU) {
138 		memset(&qmenu, 0xff, sizeof(qmenu));
139 		qmenu.id = qctrl.id;
140 		qmenu.index = qctrl.minimum;
141 		ret = doioctl(node, VIDIOC_QUERYMENU, &qmenu);
142 		if (ret != EINVAL && ret != ENOTTY)
143 			return fail("can do querymenu on a non-menu control\n");
144 		return 0;
145 	}
146 	bool have_default_value = false;
147 	for (i = 0; i <= qctrl.maximum + 1; i++) {
148 		memset(&qmenu, 0xff, sizeof(qmenu));
149 		qmenu.id = qctrl.id;
150 		qmenu.index = i;
151 		ret = doioctl(node, VIDIOC_QUERYMENU, &qmenu);
152 		if (ret && ret != EINVAL)
153 			return fail("invalid QUERYMENU return code (%d)\n", ret);
154 		if (ret)
155 			continue;
156 		if (i < qctrl.minimum || i > qctrl.maximum)
157 			return fail("can get menu for out-of-range index\n");
158 		if (qmenu.index != static_cast<__u32>(i) || qmenu.id != qctrl.id)
159 			return fail("id or index changed\n");
160 		if (qctrl.type == V4L2_CTRL_TYPE_MENU &&
161 		    check_ustring(qmenu.name, sizeof(qmenu.name)))
162 			return fail("invalid menu name\n");
163 		if (qmenu.reserved)
164 			return fail("reserved is non-zero\n");
165 		if (i == qctrl.default_value)
166 			have_default_value = true;
167 		if (i < 64)
168 			qctrl.menu_mask |= 1ULL << i;
169 	}
170 	if (qctrl.menu_mask == 0)
171 		return fail("no menu items found\n");
172 	fail_on_test(!have_default_value);
173 	return 0;
174 }
175 
testQueryExtControls(struct node * node)176 int testQueryExtControls(struct node *node)
177 {
178 	struct test_query_ext_ctrl qctrl;
179 	__u32 id = 0;
180 	int result = 0;
181 	int ret;
182 	__u32 which = 0;
183 	bool found_ctrl_class = false;
184 	unsigned user_controls = 0;
185 	unsigned priv_user_controls = 0;
186 	unsigned user_controls_check = 0;
187 	unsigned priv_user_controls_check = 0;
188 	unsigned class_count = 0;
189 
190 	for (;;) {
191 		memset(&qctrl, 0xff, sizeof(qctrl));
192 		qctrl.id = id | V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
193 		ret = doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qctrl);
194 		if (ret == ENOTTY)
195 			return ret;
196 		if (ret && ret != EINVAL)
197 			return fail("invalid query_ext_ctrl return code (%d)\n", ret);
198 		if (ret)
199 			break;
200 		if (checkQCtrl(node, qctrl))
201 			return fail("invalid control %08x\n", qctrl.id);
202 		if (qctrl.id <= id)
203 			return fail("id did not increase!\n");
204 		id = qctrl.id;
205 		if (id >= V4L2_CID_PRIVATE_BASE)
206 			return fail("no V4L2_CID_PRIVATE_BASE allowed\n");
207 		if (V4L2_CTRL_ID2WHICH(id) != which) {
208 			if (which && !found_ctrl_class)
209 				result = fail("missing control class for class %08x\n", which);
210 			if (which && !class_count)
211 				return fail("no controls in class %08x\n", which);
212 			which = V4L2_CTRL_ID2WHICH(id);
213 			found_ctrl_class = false;
214 			class_count = 0;
215 		}
216 		if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
217 			found_ctrl_class = true;
218 		} else {
219 			class_count++;
220 		}
221 
222 		if (which == V4L2_CTRL_CLASS_USER &&
223 		    qctrl.type < V4L2_CTRL_COMPOUND_TYPES &&
224 		    !qctrl.nr_of_dims &&
225 		    qctrl.type != V4L2_CTRL_TYPE_INTEGER64 &&
226 		    qctrl.type != V4L2_CTRL_TYPE_STRING &&
227 		    qctrl.type != V4L2_CTRL_TYPE_CTRL_CLASS) {
228 			if (V4L2_CTRL_DRIVER_PRIV(id))
229 				priv_user_controls_check++;
230 			else if (id < V4L2_CID_LASTP1)
231 				user_controls_check++;
232 		}
233 		if (V4L2_CTRL_DRIVER_PRIV(id)) {
234 			node->priv_controls++;
235 			if (qctrl.type >= V4L2_CTRL_COMPOUND_TYPES || qctrl.nr_of_dims)
236 				node->priv_compound_controls++;
237 		} else {
238 			node->std_controls++;
239 			if (qctrl.type >= V4L2_CTRL_COMPOUND_TYPES || qctrl.nr_of_dims)
240 				node->std_compound_controls++;
241 		}
242 		node->controls[qctrl.id] = qctrl;
243 	}
244 	if (which && !found_ctrl_class &&
245 	    (priv_user_controls_check > node->priv_compound_controls ||
246 	     user_controls_check > node->std_compound_controls))
247 		result = fail("missing control class for class %08x\n", which);
248 	if (which && !class_count)
249 		return fail("no controls in class %08x\n", which);
250 
251 	id = 0;
252 	unsigned regular_ctrls = 0;
253 	for (;;) {
254 		memset(&qctrl, 0xff, sizeof(qctrl));
255 		qctrl.id = id | V4L2_CTRL_FLAG_NEXT_CTRL;
256 		ret = doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qctrl);
257 		if (ret)
258 			break;
259 		id = qctrl.id;
260 		if (qctrl.type >= V4L2_CTRL_COMPOUND_TYPES || qctrl.nr_of_dims)
261 			return fail("V4L2_CTRL_FLAG_NEXT_CTRL enumerates compound controls!\n");
262 		regular_ctrls++;
263 	}
264 	unsigned num_compound_ctrls = node->std_compound_controls + node->priv_compound_controls;
265 	unsigned num_regular_ctrls = node->std_controls + node->priv_controls - num_compound_ctrls;
266 	if (regular_ctrls != num_regular_ctrls)
267 		return fail("expected to find %d standard controls, got %d instead\n",
268 			    num_regular_ctrls, regular_ctrls);
269 
270 	id = 0;
271 	unsigned compound_ctrls = 0;
272 	for (;;) {
273 		memset(&qctrl, 0xff, sizeof(qctrl));
274 		qctrl.id = id | V4L2_CTRL_FLAG_NEXT_COMPOUND;
275 		ret = doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qctrl);
276 		if (ret)
277 			break;
278 		id = qctrl.id;
279 		if (qctrl.type < V4L2_CTRL_COMPOUND_TYPES && !qctrl.nr_of_dims)
280 			return fail("V4L2_CTRL_FLAG_NEXT_COMPOUND enumerates regular controls!\n");
281 		compound_ctrls++;
282 	}
283 	if (compound_ctrls != num_compound_ctrls)
284 		return fail("expected to find %d compound controls, got %d instead\n",
285 			    num_compound_ctrls, compound_ctrls);
286 
287 	for (id = V4L2_CID_BASE; id < V4L2_CID_LASTP1; id++) {
288 		memset(&qctrl, 0xff, sizeof(qctrl));
289 		qctrl.id = id;
290 		ret = doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qctrl);
291 		if (ret && ret != EINVAL)
292 			return fail("invalid query_ext_ctrl return code (%d)\n", ret);
293 		if (ret)
294 			continue;
295 		if (qctrl.id != id)
296 			return fail("qctrl.id (%08x) != id (%08x)\n",
297 					qctrl.id, id);
298 		if (checkQCtrl(node, qctrl))
299 			return fail("invalid control %08x\n", qctrl.id);
300 		user_controls++;
301 	}
302 
303 	for (id = V4L2_CID_PRIVATE_BASE; ; id++) {
304 		memset(&qctrl, 0xff, sizeof(qctrl));
305 		qctrl.id = id;
306 		ret = doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qctrl);
307 		if (ret && ret != EINVAL)
308 			return fail("invalid query_ext_ctrl return code (%d)\n", ret);
309 		if (ret)
310 			break;
311 		if (qctrl.id != id)
312 			return fail("qctrl.id (%08x) != id (%08x)\n",
313 					qctrl.id, id);
314 		if (checkQCtrl(node, qctrl))
315 			return fail("invalid control %08x\n", qctrl.id);
316 		priv_user_controls++;
317 	}
318 
319 	if (priv_user_controls + user_controls && node->controls.empty())
320 		return fail("does not support V4L2_CTRL_FLAG_NEXT_CTRL\n");
321 	if (user_controls != user_controls_check)
322 		return fail("expected %d user controls, got %d\n",
323 			user_controls_check, user_controls);
324 	if (priv_user_controls != priv_user_controls_check)
325 		return fail("expected %d private controls, got %d\n",
326 			priv_user_controls_check, priv_user_controls);
327 	return result;
328 }
329 
testQueryControls(struct node * node)330 int testQueryControls(struct node *node)
331 {
332 	struct v4l2_queryctrl qctrl;
333 	unsigned controls = 0;
334 	unsigned compound_controls = 0;
335 	__u32 id = 0;
336 	int ret;
337 
338 	unsigned num_compound_ctrls = node->std_compound_controls + node->priv_compound_controls;
339 	unsigned num_regular_ctrls = node->std_controls + node->priv_controls - num_compound_ctrls;
340 
341 	for (;;) {
342 		memset(&qctrl, 0xff, sizeof(qctrl));
343 		qctrl.id = id | V4L2_CTRL_FLAG_NEXT_CTRL;
344 		ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl);
345 		if (ret == ENOTTY)
346 			return ret;
347 		if (ret && ret != EINVAL)
348 			return fail("invalid queryctrl return code (%d)\n", ret);
349 		if (ret)
350 			break;
351 		id = qctrl.id;
352 		fail_on_test(node->controls.find(qctrl.id) == node->controls.end());
353 		fail_on_test(qctrl.step < 0);
354 		controls++;
355 	}
356 	fail_on_test(controls != num_regular_ctrls);
357 
358 	id = 0;
359 	for (;;) {
360 		memset(&qctrl, 0xff, sizeof(qctrl));
361 		qctrl.id = id | V4L2_CTRL_FLAG_NEXT_COMPOUND;
362 		ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl);
363 		if (ret)
364 			break;
365 		id = qctrl.id;
366 		fail_on_test(node->controls.find(qctrl.id) == node->controls.end());
367 		if (qctrl.type >= V4L2_CTRL_COMPOUND_TYPES)
368 			fail_on_test(qctrl.step || qctrl.minimum || qctrl.maximum || qctrl.default_value);
369 		compound_controls++;
370 	}
371 	fail_on_test(compound_controls != num_compound_ctrls);
372 
373 	for (id = V4L2_CID_BASE; id < V4L2_CID_LASTP1; id++) {
374 		memset(&qctrl, 0xff, sizeof(qctrl));
375 		qctrl.id = id;
376 		ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl);
377 		if (ret && ret != EINVAL)
378 			return fail("invalid queryctrl return code (%d)\n", ret);
379 		if (ret)
380 			continue;
381 		if (qctrl.id != id)
382 			return fail("qctrl.id (%08x) != id (%08x)\n",
383 					qctrl.id, id);
384 		fail_on_test(qctrl.step < 0);
385 	}
386 
387 	for (id = V4L2_CID_PRIVATE_BASE; ; id++) {
388 		memset(&qctrl, 0xff, sizeof(qctrl));
389 		qctrl.id = id;
390 		ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl);
391 		if (ret && ret != EINVAL)
392 			return fail("invalid queryctrl return code (%d)\n", ret);
393 		if (ret)
394 			break;
395 		if (qctrl.id != id)
396 			return fail("qctrl.id (%08x) != id (%08x)\n",
397 					qctrl.id, id);
398 		fail_on_test(qctrl.step < 0);
399 	}
400 	return 0;
401 }
402 
checkSimpleCtrl(const struct v4l2_control & ctrl,const struct test_query_ext_ctrl & qctrl)403 static int checkSimpleCtrl(const struct v4l2_control &ctrl, const struct test_query_ext_ctrl &qctrl)
404 {
405 	if (ctrl.id != qctrl.id)
406 		return fail("control id mismatch\n");
407 	switch (qctrl.type) {
408 	case V4L2_CTRL_TYPE_INTEGER:
409 	case V4L2_CTRL_TYPE_BOOLEAN:
410 	case V4L2_CTRL_TYPE_MENU:
411 	case V4L2_CTRL_TYPE_INTEGER_MENU:
412 		if (ctrl.value < qctrl.minimum || ctrl.value > qctrl.maximum)
413 			return fail("returned control value out of range\n");
414 		if ((ctrl.value - qctrl.minimum) % qctrl.step) {
415 			// This really should be a fail, but there are so few
416 			// drivers that do this right that I made it a warning
417 			// for now.
418 			warn("%s: returned control value %d not a multiple of step\n",
419 					qctrl.name, ctrl.value);
420 		}
421 		break;
422 	case V4L2_CTRL_TYPE_BITMASK:
423 		if (static_cast<__u32>(ctrl.value) & ~qctrl.maximum)
424 			return fail("returned control value out of range\n");
425 		break;
426 	case V4L2_CTRL_TYPE_BUTTON:
427 		break;
428 	default:
429 		return fail("this type should not allow g_ctrl\n");
430 	}
431 	return 0;
432 }
433 
testSimpleControls(struct node * node)434 int testSimpleControls(struct node *node)
435 {
436 	struct v4l2_control ctrl;
437 	int ret;
438 	int i;
439 
440 	for (auto &control : node->controls) {
441 		test_query_ext_ctrl &qctrl = control.second;
442 
443 		if (qctrl.type >= V4L2_CTRL_COMPOUND_TYPES || qctrl.nr_of_dims)
444 			continue;
445 		if (is_vivid && V4L2_CTRL_ID2WHICH(qctrl.id) == V4L2_CTRL_CLASS_VIVID)
446 			continue;
447 
448 		info("checking control '%s' (0x%08x)\n", qctrl.name, qctrl.id);
449 		ctrl.id = qctrl.id;
450 		if (qctrl.type == V4L2_CTRL_TYPE_INTEGER64 ||
451 		    qctrl.type == V4L2_CTRL_TYPE_STRING ||
452 		    qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
453 			ret = doioctl(node, VIDIOC_G_CTRL, &ctrl);
454 			if (ret != EINVAL &&
455 			    !((qctrl.flags & V4L2_CTRL_FLAG_WRITE_ONLY) && ret == EACCES))
456 				return fail("g_ctrl allowed for unsupported type\n");
457 			ctrl.id = qctrl.id;
458 			ctrl.value = 0;
459 			ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
460 			if (ret != EINVAL &&
461 			    !((qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) && ret == EACCES))
462 				return fail("s_ctrl allowed for unsupported type\n");
463 			continue;
464 		}
465 
466 		// Get the current value
467 		ret = doioctl(node, VIDIOC_G_CTRL, &ctrl);
468 		if ((qctrl.flags & V4L2_CTRL_FLAG_WRITE_ONLY)) {
469 			if (ret != EACCES)
470 				return fail("g_ctrl did not check the write-only flag\n");
471 			ctrl.id = qctrl.id;
472 			ctrl.value = qctrl.default_value;
473 		} else if (ret)
474 			return fail("g_ctrl returned an error (%d)\n", ret);
475 		else if (checkSimpleCtrl(ctrl, qctrl))
476 			return fail("invalid control %08x\n", qctrl.id);
477 
478 		// Try to set the current value (or the default value for write only controls)
479 		ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
480 		if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
481 			if (ret != EACCES)
482 				return fail("s_ctrl did not check the read-only flag\n");
483 		} else if (ret == EIO) {
484 			warn("s_ctrl returned EIO\n");
485 			ret = 0;
486 		} else if (ret == EILSEQ) {
487 			warn("s_ctrl returned EILSEQ\n");
488 			ret = 0;
489 		} else if (ret == EACCES && is_uvcvideo) {
490 			ret = 0;
491 		} else if (ret) {
492 			return fail("s_ctrl returned an error (%d)\n", ret);
493 		}
494 		if (ret)
495 			continue;
496 		if (checkSimpleCtrl(ctrl, qctrl))
497 			return fail("s_ctrl returned invalid control contents (%08x)\n", qctrl.id);
498 
499 		// Try to set value 'minimum - 1'
500 		if (qctrl.minimum > -0x80000000LL && qctrl.minimum <= 0x7fffffffLL) {
501 			ctrl.id = qctrl.id;
502 			ctrl.value = qctrl.minimum - 1;
503 			ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
504 			if (ret && ret != EIO && ret != EILSEQ && ret != ERANGE &&
505 			    !(ret == EACCES && is_uvcvideo))
506 				return fail("invalid minimum range check\n");
507 			if (!ret && checkSimpleCtrl(ctrl, qctrl))
508 				return fail("invalid control %08x\n", qctrl.id);
509 		}
510 		// Try to set value 'maximum + 1'
511 		if (qctrl.maximum >= -0x80000000LL && qctrl.maximum < 0x7fffffffLL) {
512 			ctrl.id = qctrl.id;
513 			ctrl.value = qctrl.maximum + 1;
514 			ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
515 			if (ret && ret != EIO && ret != EILSEQ && ret != ERANGE &&
516 			    !(ret == EACCES && is_uvcvideo))
517 				return fail("invalid maximum range check\n");
518 			if (!ret && checkSimpleCtrl(ctrl, qctrl))
519 				return fail("invalid control %08x\n", qctrl.id);
520 		}
521 		// Try to set non-step value
522 		if (qctrl.step > 1 && qctrl.maximum > qctrl.minimum) {
523 			ctrl.id = qctrl.id;
524 			ctrl.value = qctrl.minimum + 1;
525 			ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
526 			if (ret == ERANGE)
527 				warn("%s: returns ERANGE for in-range, but non-step-multiple value\n",
528 						qctrl.name);
529 			else if (ret && ret != EIO && ret != EILSEQ &&
530 				 !(ret == EACCES && is_uvcvideo))
531 				return fail("returns error for in-range, but non-step-multiple value\n");
532 		}
533 
534 		if (qctrl.type == V4L2_CTRL_TYPE_MENU || qctrl.type == V4L2_CTRL_TYPE_INTEGER_MENU) {
535 			int max = qctrl.maximum;
536 
537 			/* Currently menu_mask is a 64-bit value, so we can't reliably
538 			 * test for menu item > 63. */
539 			if (max > 63)
540 				max = 63;
541 			// check menu items
542 			for (i = qctrl.minimum; i <= max; i++) {
543 				bool valid = qctrl.menu_mask & (1ULL << i);
544 
545 				ctrl.id = qctrl.id;
546 				ctrl.value = i;
547 				ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
548 				if (valid && ret == EACCES && is_uvcvideo)
549 					continue;
550 				if (valid && ret)
551 					return fail("could not set valid menu item %d\n", i);
552 				if (!valid && !ret)
553 					return fail("could set invalid menu item %d\n", i);
554 				if (ret && ret != EINVAL)
555 					return fail("setting invalid menu item returned wrong error (%d)\n", ret);
556 			}
557 		} else {
558 			// at least min, max and default values should work
559 			ctrl.id = qctrl.id;
560 			ctrl.value = qctrl.minimum;
561 			ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
562 			if (ret && ret != EIO && ret != EILSEQ &&
563 			    !(ret == EACCES && is_uvcvideo))
564 				return fail("could not set minimum value\n");
565 			ctrl.value = qctrl.maximum;
566 			ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
567 			if (ret && ret != EIO && ret != EILSEQ &&
568 			    !(ret == EACCES && is_uvcvideo))
569 				return fail("could not set maximum value\n");
570 			ctrl.value = qctrl.default_value;
571 			ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
572 			if (ret && ret != EIO && ret != EILSEQ &&
573 			    !(ret == EACCES && is_uvcvideo))
574 				return fail("could not set default value\n");
575 		}
576 	}
577 	ctrl.id = 0;
578 	ret = doioctl(node, VIDIOC_G_CTRL, &ctrl);
579 	if (ret != EINVAL && ret != ENOTTY)
580 		return fail("g_ctrl accepted invalid control ID\n");
581 	ctrl.id = 0;
582 	ctrl.value = 0;
583 	ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
584 	if (ret != EINVAL && ret != ENOTTY)
585 		return fail("s_ctrl accepted invalid control ID\n");
586 	if (ret == ENOTTY && node->controls.empty())
587 		return ENOTTY;
588 	return 0;
589 }
590 
checkExtendedCtrl(const struct v4l2_ext_control & ctrl,const struct test_query_ext_ctrl & qctrl)591 static int checkExtendedCtrl(const struct v4l2_ext_control &ctrl, const struct test_query_ext_ctrl &qctrl)
592 {
593 	int len;
594 
595 	if (ctrl.id != qctrl.id)
596 		return fail("control id mismatch\n");
597 
598 	if (qctrl.flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) {
599 		fail_on_test(qctrl.nr_of_dims != 1);
600 		unsigned tot_elems = qctrl.dims[0];
601 		fail_on_test(qctrl.elems > tot_elems);
602 		fail_on_test(!qctrl.elems);
603 	}
604 	if (qctrl.nr_of_dims)
605 		return 0;
606 
607 	switch (qctrl.type) {
608 	case V4L2_CTRL_TYPE_INTEGER:
609 	case V4L2_CTRL_TYPE_INTEGER64:
610 	case V4L2_CTRL_TYPE_BOOLEAN:
611 	case V4L2_CTRL_TYPE_MENU:
612 	case V4L2_CTRL_TYPE_INTEGER_MENU:
613 		if (ctrl.value < qctrl.minimum || ctrl.value > qctrl.maximum)
614 			return fail("returned control value out of range\n");
615 		if ((ctrl.value - qctrl.minimum) % qctrl.step) {
616 			// This really should be a fail, but there are so few
617 			// drivers that do this right that I made it a warning
618 			// for now.
619 			warn("%s: returned control value %d not a multiple of step\n",
620 					qctrl.name, ctrl.value);
621 		}
622 		break;
623 	case V4L2_CTRL_TYPE_BITMASK:
624 		if (static_cast<__u32>(ctrl.value) & ~qctrl.maximum)
625 			return fail("returned control value out of range\n");
626 		break;
627 	case V4L2_CTRL_TYPE_BUTTON:
628 		break;
629 	case V4L2_CTRL_TYPE_STRING:
630 		len = strnlen(ctrl.string, qctrl.maximum + 1);
631 		if (len == qctrl.maximum + 1)
632 			return fail("string too long\n");
633 		if (len < qctrl.minimum)
634 			return fail("string too short\n");
635 		if ((len - qctrl.minimum) % qctrl.step)
636 			return fail("string not a multiple of step\n");
637 		break;
638 	default:
639 		break;
640 	}
641 	return 0;
642 }
643 
checkVividDynArray(struct node * node,struct v4l2_ext_control & ctrl,const struct test_query_ext_ctrl & qctrl)644 static int checkVividDynArray(struct node *node,
645 			      struct v4l2_ext_control &ctrl,
646 			      const struct test_query_ext_ctrl &qctrl)
647 {
648 	struct v4l2_query_ext_ctrl qextctrl = {};
649 	unsigned max_elems = qctrl.dims[0];
650 	unsigned max_size = qctrl.elem_size * max_elems;
651 
652 	delete [] ctrl.string;
653 	// Allocate a buffer that's one element more than the max
654 	ctrl.string = new char[max_size + qctrl.elem_size];
655 	ctrl.size = qctrl.elem_size;
656 	ctrl.p_u32[0] = (qctrl.minimum + qctrl.maximum) / 2;
657 	// Set the last element + 1, must never be overwritten
658 	ctrl.p_u32[max_elems] = 0xdeadbeef;
659 
660 	struct v4l2_ext_controls ctrls = {};
661 	ctrls.count = 1;
662 	ctrls.controls = &ctrl;
663 	// Set the array to a single element
664 	fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
665 
666 	qextctrl.id = ctrl.id;
667 	// Check that only one element is reported
668 	fail_on_test(doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qextctrl));
669 	fail_on_test(qextctrl.elems != 1);
670 
671 	// If the size is less than elem_size, the ioctl must return -EFAULT
672 	ctrl.size = 0;
673 	fail_on_test(doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls) != EFAULT);
674 	ctrl.size = qctrl.elem_size - 1;
675 	fail_on_test(doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls) != EFAULT);
676 	ctrl.size = max_size + qctrl.elem_size;
677 	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
678 	// Check that ctrl.size is reset to the current size of the array (1 element)
679 	fail_on_test(ctrl.size != qctrl.elem_size);
680 	ctrl.size = max_size + qctrl.elem_size;
681 	// Attempting to set more than max_elems must result in -ENOSPC
682 	fail_on_test(doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls) != ENOSPC);
683 	fail_on_test(ctrl.size != max_size);
684 	ctrl.size = max_size + qctrl.elem_size;
685 	fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls) != ENOSPC);
686 	fail_on_test(ctrl.size != max_size);
687 	fail_on_test(doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qextctrl));
688 	// Verify that the number of elements is still 1
689 	fail_on_test(qextctrl.elems != 1);
690 
691 	ctrl.size = max_size;
692 	for (unsigned i = 0; i < max_elems; i++)
693 		ctrl.p_u32[i] = i;
694 	// Try the max number of elements
695 	fail_on_test(doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls));
696 	// Check that the values are clamped
697 	for (unsigned i = 0; i < max_elems; i++) {
698 		unsigned j = i;
699 		if (j < qctrl.minimum)
700 			j = qctrl.minimum;
701 		else if (j > qctrl.maximum)
702 			j = qctrl.maximum;
703 		fail_on_test(ctrl.p_u32[i] != j);
704 	}
705 	fail_on_test(ctrl.size != max_size);
706 	fail_on_test(doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qextctrl));
707 	// Verify that the number of elements is still 1
708 	fail_on_test(qextctrl.elems != 1);
709 	memset(ctrl.string, 0xff, max_size);
710 	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
711 	// Check that there is still just one element returned.
712 	fail_on_test(ctrl.size != qctrl.elem_size);
713 	fail_on_test(ctrl.p_u32[0] != (qctrl.minimum + qctrl.maximum) / 2);
714 
715 	ctrl.size = max_size;
716 	for (unsigned i = 0; i < max_elems; i++)
717 		ctrl.p_u32[i] = i;
718 	// Set the max number of elements
719 	fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
720 	for (unsigned i = 0; i < max_elems; i++) {
721 		unsigned j = i;
722 		if (j < qctrl.minimum)
723 			j = qctrl.minimum;
724 		else if (j > qctrl.maximum)
725 			j = qctrl.maximum;
726 		fail_on_test(ctrl.p_u32[i] != j);
727 	}
728 	fail_on_test(doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qextctrl));
729 	// Check that it is updated
730 	fail_on_test(qextctrl.elems != max_elems);
731 	memset(ctrl.string, 0xff, max_size);
732 	ctrl.size = qctrl.elem_size;
733 	// Check that ENOSPC is returned if the size is too small
734 	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != ENOSPC);
735 	// And updated to the actual required size
736 	fail_on_test(ctrl.size != max_size);
737 	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
738 	for (unsigned i = 0; i < max_elems; i++) {
739 		unsigned j = i;
740 		if (j < qctrl.minimum)
741 			j = qctrl.minimum;
742 		else if (j > qctrl.maximum)
743 			j = qctrl.maximum;
744 		fail_on_test(ctrl.p_u32[i] != j);
745 	}
746 	// Check that the end of the buffer isn't overwritten
747 	fail_on_test(ctrl.p_u32[max_elems] != 0xdeadbeef);
748 
749 	ctrl.size = qctrl.elem_size;
750 	ctrls.which = V4L2_CTRL_WHICH_DEF_VAL;
751 	// Check that ENOSPC is returned if the size is too small
752 	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != ENOSPC);
753 	// And updated to the actual required size
754 	fail_on_test(ctrl.size != max_size);
755 	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
756 	for (unsigned i = 0; i < max_elems; i++)
757 		fail_on_test(ctrl.p_u32[i] != 50);
758 	// Check that the end of the buffer isn't overwritten
759 	fail_on_test(ctrl.p_u32[max_elems] != 0xdeadbeef);
760 
761 	ctrls.which = 0;
762 	ctrl.size = qctrl.elem_size;
763 	ctrl.p_u32[0] = (qctrl.minimum + qctrl.maximum) / 2;
764 	// Back to just one element
765 	fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
766 	fail_on_test(doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qextctrl));
767 	// Check this.
768 	fail_on_test(qextctrl.elems != 1);
769 
770 	ctrl.size = max_size;
771 	ctrls.which = V4L2_CTRL_WHICH_DEF_VAL;
772 	memset(ctrl.string, 0xff, max_size);
773 	// And updated to the actual required size
774 	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
775 	fail_on_test(ctrl.size != qctrl.elem_size);
776 	fail_on_test(ctrl.p_u32[0] != 50);
777 	fail_on_test(ctrl.p_u32[1] != 0xffffffff);
778 
779 	return 0;
780 }
781 
checkVividControls(struct node * node,struct v4l2_ext_control & ctrl,struct v4l2_ext_controls & ctrls,const struct test_query_ext_ctrl & qctrl)782 static int checkVividControls(struct node *node,
783 			      struct v4l2_ext_control &ctrl,
784 			      struct v4l2_ext_controls &ctrls,
785 			      const struct test_query_ext_ctrl &qctrl)
786 {
787 	int ret;
788 
789 	switch (ctrl.id) {
790 	case VIVID_CID_INTEGER64:
791 		ctrl.value64 = qctrl.minimum;
792 		ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
793 		if (ret)
794 			return fail("could not set minimum value\n");
795 		ctrl.value64 = qctrl.maximum;
796 		ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
797 		if (ret)
798 			return fail("could not set maximum value\n");
799 		ctrl.value64 = qctrl.default_value;
800 		ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
801 		if (ret)
802 			return fail("could not set default value\n");
803 		return 0;
804 
805 	case VIVID_CID_STRING:
806 		delete [] ctrl.string;
807 		ctrl.string = new char[qctrl.maximum + 1];
808 		memset(ctrl.string, 'A', qctrl.minimum);
809 		ctrl.string[qctrl.minimum] = '\0';
810 		ctrl.size = 3;
811 		ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
812 		if (ret)
813 			return fail("could not set minimum string value\n");
814 		memset(ctrl.string, 'Z', qctrl.maximum);
815 		ctrl.string[qctrl.maximum] = '\0';
816 		ctrl.size = 5;
817 		ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
818 		if (ret)
819 			return fail("could not set maximum string value\n");
820 		memset(ctrl.string, ' ', qctrl.minimum);
821 		ctrl.string[qctrl.minimum] = '\0';
822 		ctrl.size = 3;
823 		ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
824 		if (ret)
825 			return fail("could not set default string value\n");
826 		return 0;
827 
828 	case VIVID_CID_AREA:
829 		ctrl.p_area->width = 200;
830 		ctrl.p_area->height = 100;
831 		ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
832 		if (ret)
833 			return fail("could not set area value\n");
834 		ctrl.p_area->width = 1000;
835 		ctrl.p_area->height = 2000;
836 		ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
837 		if (ret)
838 			return fail("could not set area value\n");
839 		return 0;
840 
841 	default:
842 		return fail("should not happen\n");
843 	}
844 }
845 
testExtendedControls(struct node * node)846 int testExtendedControls(struct node *node)
847 {
848 	struct v4l2_ext_controls ctrls;
849 	std::vector<struct v4l2_ext_control> total_vec;
850 	std::vector<struct v4l2_ext_control> class_vec;
851 	struct v4l2_ext_control ctrl;
852 	__u32 which = 0;
853 	bool multiple_classes = false;
854 	int ret;
855 
856 	memset(&ctrls, 0, sizeof(ctrls));
857 	ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
858 	if (ret == ENOTTY && node->controls.empty())
859 		return ret;
860 	if (ret)
861 		return fail("g_ext_ctrls does not support count == 0\n");
862 	if (ctrls.which)
863 		return fail("field which changed\n");
864 	if (ctrls.count)
865 		return fail("field count changed\n");
866 	if (check_0(ctrls.reserved, sizeof(ctrls.reserved)))
867 		return fail("reserved not zeroed\n");
868 
869 	memset(&ctrls, 0, sizeof(ctrls));
870 	ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
871 	if (ret == ENOTTY && node->controls.empty())
872 		return ret;
873 	if (ret)
874 		return fail("try_ext_ctrls does not support count == 0\n");
875 	if (ctrls.which)
876 		return fail("field which changed\n");
877 	if (ctrls.count)
878 		return fail("field count changed\n");
879 	if (check_0(ctrls.reserved, sizeof(ctrls.reserved)))
880 		return fail("reserved not zeroed\n");
881 
882 	for (auto &control : node->controls) {
883 		test_query_ext_ctrl &qctrl = control.second;
884 
885 		if (is_vivid && V4L2_CTRL_ID2WHICH(qctrl.id) == V4L2_CTRL_CLASS_VIVID)
886 			continue;
887 
888 		info("checking extended control '%s' (0x%08x)\n", qctrl.name, qctrl.id);
889 		ctrl.id = qctrl.id;
890 		ctrl.size = 0;
891 		ctrl.ptr = nullptr;
892 		ctrl.reserved2[0] = 0;
893 		ctrls.count = 1;
894 
895 		// Either should work, so try both semi-randomly
896 		ctrls.which = (ctrl.id & 1) ? 0 : V4L2_CTRL_ID2WHICH(ctrl.id);
897 		ctrls.controls = &ctrl;
898 
899 		// Get the current value
900 		ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
901 		if ((qctrl.flags & V4L2_CTRL_FLAG_WRITE_ONLY)) {
902 			if (ret != EACCES)
903 				return fail("g_ext_ctrls did not check the write-only flag\n");
904 			if (ctrls.error_idx != ctrls.count)
905 				return fail("invalid error index write only control\n");
906 			ctrl.id = qctrl.id;
907 			ctrl.value = qctrl.default_value;
908 		} else {
909 			if (ret != ENOSPC && (qctrl.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD))
910 				return fail("did not check against size\n");
911 			if (ret == ENOSPC && (qctrl.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD)) {
912 				if (qctrl.type == V4L2_CTRL_TYPE_STRING && ctrls.error_idx != 0)
913 					return fail("invalid error index string control\n");
914 				fail_on_test(ctrl.size != qctrl.elem_size * qctrl.elems);
915 				ctrl.string = new char[ctrl.size];
916 				ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
917 			}
918 			if (ret == EIO) {
919 				warn("g_ext_ctrls returned EIO\n");
920 				ret = 0;
921 			} else if (ret == EILSEQ) {
922 				warn("g_ext_ctrls returned EILSEQ\n");
923 				ret = 0;
924 			}
925 			if (ret)
926 				return fail("g_ext_ctrls returned an error (%d)\n", ret);
927 			if (checkExtendedCtrl(ctrl, qctrl))
928 				return fail("invalid control %08x\n", qctrl.id);
929 		}
930 
931 		// Try the current value (or the default value for write only controls)
932 		ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
933 		if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
934 			if (ret != EACCES)
935 				return fail("try_ext_ctrls did not check the read-only flag\n");
936 			if (ctrls.error_idx != 0)
937 				return fail("invalid error index read only control\n");
938 		} else if (ret) {
939 			return fail("try_ext_ctrls returned an error (%d)\n", ret);
940 		}
941 
942 		// Try to set the current value (or the default value for write only controls)
943 		ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
944 		if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
945 			if (ret != EACCES)
946 				return fail("s_ext_ctrls did not check the read-only flag\n");
947 			if (ctrls.error_idx != ctrls.count)
948 				return fail("invalid error index\n");
949 		} else {
950 			if (ret == EIO) {
951 				warn("s_ext_ctrls returned EIO\n");
952 				ret = 0;
953 			} else if (ret == EILSEQ) {
954 				warn("s_ext_ctrls returned EILSEQ\n");
955 				ret = 0;
956 			} else if (ret == EACCES && is_uvcvideo) {
957 				ret = 0;
958 			}
959 			if (ret)
960 				return fail("s_ext_ctrls returned an error (%d)\n", ret);
961 
962 			if (checkExtendedCtrl(ctrl, qctrl))
963 				return fail("s_ext_ctrls returned invalid control contents (%08x)\n", qctrl.id);
964 		}
965 
966 		if (is_vivid && (ctrl.id == VIVID_CID_INTEGER64 ||
967 				 ctrl.id == VIVID_CID_STRING ||
968 				 ctrl.id == VIVID_CID_AREA) &&
969 		    checkVividControls(node, ctrl, ctrls, qctrl))
970 			return fail("vivid control tests failed\n");
971 		if (is_vivid && ctrl.id == VIVID_CID_U32_DYN_ARRAY &&
972 		    checkVividDynArray(node, ctrl, qctrl))
973 			return fail("dynamic array tests failed\n");
974 		if (qctrl.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD)
975 			delete [] ctrl.string;
976 		ctrl.string = nullptr;
977 	}
978 
979 	ctrls.which = 0;
980 	ctrls.count = 1;
981 	ctrls.controls = &ctrl;
982 	ctrl.id = 0;
983 	ctrl.size = 0;
984 	ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
985 	if (ret != EINVAL)
986 		return fail("g_ext_ctrls accepted invalid control ID\n");
987 	fail_on_test(ctrls.error_idx > ctrls.count);
988 	if (ctrls.error_idx != ctrls.count)
989 		warn("g_ext_ctrls(0) invalid error_idx %u\n", ctrls.error_idx);
990 	ctrl.id = 0;
991 	ctrl.size = 0;
992 	ctrl.value = 0;
993 	ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
994 	if (ret != EINVAL)
995 		return fail("try_ext_ctrls accepted invalid control ID\n");
996 	if (ctrls.error_idx != 0)
997 		return fail("try_ext_ctrls(0) invalid error_idx %u\n", ctrls.error_idx);
998 	ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
999 	if (ret != EINVAL)
1000 		return fail("s_ext_ctrls accepted invalid control ID\n");
1001 	if (ctrls.error_idx != ctrls.count)
1002 		return fail("s_ext_ctrls(0) invalid error_idx %u\n", ctrls.error_idx);
1003 
1004 	for (auto &control : node->controls) {
1005 		test_query_ext_ctrl &qctrl = control.second;
1006 		struct v4l2_ext_control ctrl;
1007 
1008 		if (qctrl.flags & (V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY))
1009 			continue;
1010 
1011 		ctrl.id = qctrl.id;
1012 		ctrl.size = 0;
1013 		if (qctrl.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD) {
1014 			ctrl.size = qctrl.elems * qctrl.elem_size;
1015 			ctrl.string = new char[ctrl.size];
1016 		}
1017 		ctrl.reserved2[0] = 0;
1018 		if (!which)
1019 			which = V4L2_CTRL_ID2WHICH(ctrl.id);
1020 		else if (which != V4L2_CTRL_ID2WHICH(ctrl.id))
1021 			multiple_classes = true;
1022 		total_vec.push_back(ctrl);
1023 	}
1024 	if (total_vec.empty())
1025 		return 0;
1026 
1027 	ctrls.count = total_vec.size();
1028 	ctrls.controls = &total_vec[0];
1029 	ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
1030 	if (ret)
1031 		return fail("could not get all controls\n");
1032 	ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
1033 	if (ret)
1034 		return fail("could not try all controls\n");
1035 	ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
1036 	if (ret == EIO) {
1037 		warn("s_ext_ctrls returned EIO\n");
1038 		ret = 0;
1039 	} else if (ret == EILSEQ) {
1040 		warn("s_ext_ctrls returned EILSEQ\n");
1041 		ret = 0;
1042 	} else if (ret == EACCES && is_uvcvideo) {
1043 		ret = 0;
1044 	}
1045 	if (ret)
1046 		return fail("could not set all controls\n");
1047 
1048 	if (!which)
1049 		return 0;
1050 
1051 	ctrls.which = which;
1052 	ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
1053 	if (ret && !multiple_classes)
1054 		return fail("could not get all controls of a specific class\n");
1055 	if (ret != EINVAL && multiple_classes)
1056 		return fail("should get EINVAL when getting mixed-class controls\n");
1057 	if (multiple_classes && ctrls.error_idx != ctrls.count)
1058 		warn("error_idx should be equal to count\n");
1059 	ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
1060 	if (ret && !multiple_classes)
1061 		return fail("could not try all controls of a specific class\n");
1062 	if (ret != EINVAL && multiple_classes)
1063 		return fail("should get EINVAL when trying mixed-class controls\n");
1064 	if (multiple_classes && ctrls.error_idx >= ctrls.count)
1065 		return fail("error_idx should be < count\n");
1066 	ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
1067 	if (ret == EIO) {
1068 		warn("s_ext_ctrls returned EIO\n");
1069 		ret = 0;
1070 	} else if (ret == EILSEQ) {
1071 		warn("s_ext_ctrls returned EILSEQ\n");
1072 		ret = 0;
1073 	}
1074 	if (ret && !(ret == EACCES && is_uvcvideo) && !multiple_classes)
1075 		return fail("could not set all controls of a specific class\n");
1076 	if (ret != EINVAL && multiple_classes)
1077 		return fail("should get EINVAL when setting mixed-class controls\n");
1078 	if (multiple_classes && ctrls.error_idx != ctrls.count)
1079 		warn("error_idx should be equal to count\n");
1080 
1081 	ctrls.which = V4L2_CTRL_WHICH_DEF_VAL;
1082 	fail_on_test(!doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
1083 	fail_on_test(!doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls));
1084 	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
1085 	return 0;
1086 }
1087 
testEvents(struct node * node)1088 int testEvents(struct node *node)
1089 {
1090 	for (auto &control : node->controls) {
1091 		test_query_ext_ctrl &qctrl = control.second;
1092 		struct v4l2_event_subscription sub = { 0 };
1093 		struct v4l2_event ev;
1094 		struct timeval timeout = { 0, 100 };
1095 		fd_set set;
1096 		int ret;
1097 
1098 		info("checking control event '%s' (0x%08x)\n", qctrl.name, qctrl.id);
1099 		sub.type = V4L2_EVENT_CTRL;
1100 		sub.id = qctrl.id;
1101 		sub.flags = V4L2_EVENT_SUB_FL_SEND_INITIAL;
1102 		ret = doioctl(node, VIDIOC_SUBSCRIBE_EVENT, &sub);
1103 		if (ret)
1104 			return fail("subscribe event for control '%s' failed\n", qctrl.name);
1105 		//if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS)
1106 		FD_ZERO(&set);
1107 		FD_SET(node->g_fd(), &set);
1108 		ret = select(node->g_fd() + 1, nullptr, nullptr, &set, &timeout);
1109 		if (ret == 0) {
1110 			if (qctrl.type != V4L2_CTRL_TYPE_CTRL_CLASS)
1111 				return fail("failed to find event for control '%s'\n", qctrl.name);
1112 		} else if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
1113 			return fail("found event for control class '%s'\n", qctrl.name);
1114 		}
1115 		if (ret) {
1116 			ret = doioctl(node, VIDIOC_DQEVENT, &ev);
1117 			if (ret)
1118 				return fail("couldn't get event for control '%s'\n", qctrl.name);
1119 			if (ev.type != V4L2_EVENT_CTRL || ev.id != qctrl.id)
1120 				return fail("dequeued wrong event\n");
1121 			fail_on_test(check_0(ev.reserved, sizeof(ev.reserved)));
1122 		}
1123 		ret = doioctl(node, VIDIOC_UNSUBSCRIBE_EVENT, &sub);
1124 		if (ret)
1125 			return fail("unsubscribe event for control '%s' failed\n", qctrl.name);
1126 	}
1127 	if (node->cur_io_caps & V4L2_IN_CAP_DV_TIMINGS) {
1128 		struct v4l2_event_subscription sub = { };
1129 		int id;
1130 
1131 		if (node->can_capture) {
1132 			fail_on_test(doioctl(node, VIDIOC_G_INPUT, &id));
1133 			if (node->is_video &&
1134 			    node->controls.find(V4L2_CID_DV_RX_POWER_PRESENT) == node->controls.end())
1135 				warn("V4L2_CID_DV_RX_POWER_PRESENT not found for input %d\n", id);
1136 		} else {
1137 			fail_on_test(doioctl(node, VIDIOC_G_OUTPUT, &id));
1138 			if (node->is_video &&
1139 			    node->controls.find(V4L2_CID_DV_TX_HOTPLUG) == node->controls.end())
1140 				warn("V4L2_CID_DV_TX_HOTPLUG not found for output %d\n", id);
1141 			if (node->is_video &&
1142 			    node->controls.find(V4L2_CID_DV_TX_EDID_PRESENT) == node->controls.end())
1143 				warn("V4L2_CID_DV_TX_EDID_PRESENT not found for output %d\n", id);
1144 		}
1145 		if (node->can_capture) {
1146 			sub.type = V4L2_EVENT_SOURCE_CHANGE;
1147 			sub.id = id;
1148 			fail_on_test(doioctl(node, VIDIOC_SUBSCRIBE_EVENT, &sub));
1149 			fail_on_test(doioctl(node, VIDIOC_UNSUBSCRIBE_EVENT, &sub));
1150 		}
1151 	}
1152 
1153 	if (node->codec_mask & STATEFUL_ENCODER)
1154 		fail_on_test(node->controls.find(V4L2_CID_MIN_BUFFERS_FOR_OUTPUT) == node->controls.end());
1155 
1156 	struct v4l2_event_subscription sub = { 0 };
1157 
1158 	sub.type = V4L2_EVENT_EOS;
1159 	bool have_eos = !doioctl(node, VIDIOC_SUBSCRIBE_EVENT, &sub);
1160 	if (have_eos)
1161 		fail_on_test(doioctl(node, VIDIOC_UNSUBSCRIBE_EVENT, &sub));
1162 	else
1163 		fail_on_test(node->codec_mask & STATEFUL_ENCODER);
1164 	sub.type = V4L2_EVENT_SOURCE_CHANGE;
1165 	bool have_source_change = !doioctl(node, VIDIOC_SUBSCRIBE_EVENT, &sub);
1166 	if (have_source_change)
1167 		fail_on_test(doioctl(node, VIDIOC_UNSUBSCRIBE_EVENT, &sub));
1168 
1169 	switch (node->codec_mask) {
1170 	case STATEFUL_ENCODER:
1171 		fail_on_test(have_source_change || !have_eos);
1172 		break;
1173 	case STATEFUL_DECODER:
1174 		fail_on_test(!have_source_change || !have_eos);
1175 		break;
1176 	case STATELESS_ENCODER:
1177 	case STATELESS_DECODER:
1178 		fail_on_test(have_source_change || have_eos);
1179 		break;
1180 	default:
1181 		break;
1182 	}
1183 	if (node->can_output && !node->is_m2m)
1184 		fail_on_test(have_source_change);
1185 
1186 	if (node->controls.empty())
1187 		return ENOTTY;
1188 	return 0;
1189 }
1190 
testVividDisconnect(struct node * node)1191 int testVividDisconnect(struct node *node)
1192 {
1193 	// Test that disconnecting a device will wake up any processes
1194 	// that are using select or poll.
1195 	//
1196 	// This can only be tested with the vivid driver that enabled
1197 	// the DISCONNECT control.
1198 
1199 	pid_t pid = fork();
1200 	if (pid == 0) {
1201 		struct timeval tv = { 5, 0 };
1202 		fd_set fds;
1203 
1204 		FD_ZERO(&fds);
1205 		FD_SET(node->g_fd(), &fds);
1206 		int res = select(node->g_fd() + 1, nullptr, nullptr, &fds, &tv);
1207 		// No POLLPRI seen
1208 		if (res != 1)
1209 			exit(1);
1210 		// POLLPRI seen, but didn't wake up
1211 		if (!tv.tv_sec)
1212 			exit(2);
1213 		v4l2_event ev = {};
1214 		// Woke up on POLLPRI, but VIDIOC_DQEVENT didn't return
1215 		// the ENODEV error.
1216 		if (doioctl(node, VIDIOC_DQEVENT, &ev) != ENODEV)
1217 			exit(3);
1218 		exit(0);
1219 	}
1220 	v4l2_control ctrl = { VIVID_CID_DISCONNECT, 0 };
1221 	sleep(1);
1222 	fail_on_test(doioctl(node, VIDIOC_S_CTRL, &ctrl));
1223 	int wstatus;
1224 	fail_on_test(waitpid(pid, &wstatus, 0) != pid);
1225 	fail_on_test(!WIFEXITED(wstatus));
1226 	if (WEXITSTATUS(wstatus))
1227 		return fail("select child exited with status %d\n", WEXITSTATUS(wstatus));
1228 
1229 	node->reopen();
1230 
1231 	pid = fork();
1232 	if (pid == 0) {
1233 		struct epoll_event ep_ev;
1234 		int epollfd = epoll_create1(0);
1235 
1236 		if (epollfd < 0)
1237 			exit(1);
1238 
1239 		ep_ev.events = 0;
1240 		if (epoll_ctl(epollfd, EPOLL_CTL_ADD, node->g_fd(), &ep_ev))
1241 			exit(2);
1242 
1243 		ep_ev.events = EPOLLPRI;
1244 		ep_ev.data.fd = node->g_fd();
1245 		if (epoll_ctl(epollfd, EPOLL_CTL_MOD, node->g_fd(), &ep_ev))
1246 			exit(3);
1247 		int ret = epoll_wait(epollfd, &ep_ev, 1, 5000);
1248 		if (ret == 0)
1249 			exit(4);
1250 		if (ret < 0)
1251 			exit(5);
1252 		if (ret != 1)
1253 			exit(6);
1254 		if (!(ep_ev.events & EPOLLPRI))
1255 			exit(7);
1256 		if (!(ep_ev.events & EPOLLERR))
1257 			exit(8);
1258 		v4l2_event ev = {};
1259 		// Woke up on POLLPRI, but VIDIOC_DQEVENT didn't return
1260 		// the ENODEV error.
1261 		if (doioctl(node, VIDIOC_DQEVENT, &ev) != ENODEV)
1262 			exit(9);
1263 		exit(0);
1264 	}
1265 	sleep(1);
1266 	fail_on_test(doioctl(node, VIDIOC_S_CTRL, &ctrl));
1267 	fail_on_test(waitpid(pid, &wstatus, 0) != pid);
1268 	fail_on_test(!WIFEXITED(wstatus));
1269 	if (WEXITSTATUS(wstatus))
1270 		return fail("epoll child exited with status %d\n", WEXITSTATUS(wstatus));
1271 	return 0;
1272 }
1273 
testJpegComp(struct node * node)1274 int testJpegComp(struct node *node)
1275 {
1276 	struct v4l2_jpegcompression jc;
1277 	bool have_jpegcomp = false;
1278 	const unsigned all_markers =
1279 		V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT |
1280 		V4L2_JPEG_MARKER_DRI | V4L2_JPEG_MARKER_COM |
1281 		V4L2_JPEG_MARKER_APP;
1282 	int ret;
1283 
1284 	memset(&jc, 0, sizeof(jc));
1285 	ret = doioctl(node, VIDIOC_G_JPEGCOMP, &jc);
1286 	if (ret != ENOTTY) {
1287 		warn("The VIDIOC_G_JPEGCOMP ioctl is deprecated!\n");
1288 		if (ret)
1289 			return fail("VIDIOC_G_JPEGCOMP gave an error\n");
1290 		have_jpegcomp = true;
1291 		if (jc.COM_len < 0 || jc.COM_len > static_cast<int>(sizeof(jc.COM_data)))
1292 			return fail("invalid COM_len value\n");
1293 		if (jc.APP_len < 0 || jc.APP_len > static_cast<int>(sizeof(jc.APP_data)))
1294 			return fail("invalid APP_len value\n");
1295 		if (jc.quality < 0 || jc.quality > 100)
1296 			warn("weird quality value: %d\n", jc.quality);
1297 		if (jc.APPn < 0 || jc.APPn > 15)
1298 			return fail("invalid APPn value (%d)\n", jc.APPn);
1299 		if (jc.jpeg_markers & ~all_markers)
1300 			return fail("invalid markers (%x)\n", jc.jpeg_markers);
1301 	}
1302 	ret = doioctl(node, VIDIOC_S_JPEGCOMP, &jc);
1303 	if (ret != ENOTTY) {
1304 		warn("The VIDIOC_S_JPEGCOMP ioctl is deprecated!\n");
1305 		if (ret && ret != EINVAL)
1306 			return fail("VIDIOC_S_JPEGCOMP gave an error\n");
1307 		have_jpegcomp = true;
1308 	}
1309 
1310 	return have_jpegcomp ? ret : ENOTTY;
1311 }
1312