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