2
V4L2 API compliance control ioctl tests.
4
Copyright (C) 2011 Hans Verkuil <hverkuil@xs4all.nl>
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
#include <sys/types.h>
31
#include <sys/ioctl.h>
33
#include "v4l2-compliance.h"
35
static int checkQCtrl(struct node *node, struct test_queryctrl &qctrl)
37
struct v4l2_querymenu qmenu;
38
__u32 fl = qctrl.flags;
39
__u32 rw_mask = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
44
if (check_ustring(qctrl.name, sizeof(qctrl.name)))
45
return fail("invalid name\n");
46
info("checking v4l2_queryctrl of control '%s' (0x%08x)\n", qctrl.name, qctrl.id);
47
if (qctrl.id & V4L2_CTRL_FLAG_NEXT_CTRL)
48
return fail("V4L2_CTRL_FLAG_NEXT_CTRL not cleared\n");
49
if (check_0(qctrl.reserved, sizeof(qctrl.reserved)))
50
return fail("non-zero reserved fields\n");
51
if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
52
if ((qctrl.id & 0xffff) != 1)
53
return fail("invalid control ID for a control class\n");
54
} else if (qctrl.id < V4L2_CID_PRIVATE_BASE) {
55
if ((qctrl.id & 0xffff) < 0x900)
56
return fail("invalid control ID\n");
59
case V4L2_CTRL_TYPE_BOOLEAN:
60
if (qctrl.maximum > 1)
61
return fail("invalid boolean max value\n");
63
case V4L2_CTRL_TYPE_MENU:
65
return fail("invalid step value %d\n", qctrl.step);
66
if (qctrl.minimum < 0)
67
return fail("min < 0\n");
69
case V4L2_CTRL_TYPE_INTEGER:
70
if (qctrl.default_value < qctrl.minimum ||
71
qctrl.default_value > qctrl.maximum)
72
return fail("def < min || def > max\n");
74
case V4L2_CTRL_TYPE_STRING:
75
if (qctrl.minimum > qctrl.maximum)
76
return fail("min > max\n");
78
return fail("step == 0\n");
80
return fail("step < 0\n");
81
if ((unsigned)qctrl.step > (unsigned)(qctrl.maximum - qctrl.minimum))
82
return fail("step > max - min\n");
83
if ((qctrl.maximum - qctrl.minimum) % qctrl.step) {
84
// This really should be a fail, but there are so few
85
// drivers that do this right that I made it a warning
87
warn("%s: (max - min) %% step != 0\n", qctrl.name);
90
case V4L2_CTRL_TYPE_CTRL_CLASS:
91
case V4L2_CTRL_TYPE_INTEGER64:
92
case V4L2_CTRL_TYPE_BUTTON:
93
if (qctrl.minimum || qctrl.maximum || qctrl.step || qctrl.default_value)
94
return fail("non-zero min/max/step/def\n");
97
return fail("unknown control type\n");
99
if (qctrl.type == V4L2_CTRL_TYPE_STRING && qctrl.default_value)
100
return fail("non-zero default value for string\n");
101
switch (qctrl.type) {
102
case V4L2_CTRL_TYPE_BUTTON:
103
if ((fl & rw_mask) != V4L2_CTRL_FLAG_WRITE_ONLY)
104
return fail("button control not write only\n");
106
case V4L2_CTRL_TYPE_BOOLEAN:
107
case V4L2_CTRL_TYPE_MENU:
108
case V4L2_CTRL_TYPE_STRING:
109
if (fl & V4L2_CTRL_FLAG_SLIDER)
110
return fail("slider makes only sense for integer controls\n");
112
case V4L2_CTRL_TYPE_INTEGER64:
113
case V4L2_CTRL_TYPE_INTEGER:
114
if ((fl & rw_mask) == rw_mask)
115
return fail("can't read nor write this control\n");
117
case V4L2_CTRL_TYPE_CTRL_CLASS:
118
if (fl != (V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY))
119
return fail("invalid flags for control class\n");
122
if (fl & V4L2_CTRL_FLAG_GRABBED)
123
return fail("GRABBED flag set\n");
124
if (fl & V4L2_CTRL_FLAG_DISABLED)
125
return fail("DISABLED flag set\n");
126
if (qctrl.type != V4L2_CTRL_TYPE_MENU) {
127
memset(&qmenu, 0xff, sizeof(qmenu));
129
qmenu.index = qctrl.minimum;
130
ret = doioctl(node, VIDIOC_QUERYMENU, &qmenu);
132
return fail("can do querymenu on a non-menu control\n");
135
if (qctrl.maximum >= 32)
136
return fail("currently more than 32 menu items are not supported\n");
137
for (i = 0; i <= qctrl.maximum + 1; i++) {
138
memset(&qmenu, 0xff, sizeof(qmenu));
141
ret = doioctl(node, VIDIOC_QUERYMENU, &qmenu);
142
if (ret && ret != EINVAL)
143
return fail("invalid QUERYMENU return code\n");
146
if (i < qctrl.minimum || i > qctrl.maximum)
147
return fail("can get menu for out-of-range index\n");
148
if (qmenu.index != (__u32)i || qmenu.id != qctrl.id)
149
return fail("id or index changed\n");
150
if (check_ustring(qmenu.name, sizeof(qmenu.name)))
151
return fail("invalid menu name\n");
153
return fail("reserved is non-zero\n");
154
qctrl.menu_mask |= 1 << i;
156
if (qctrl.menu_mask == 0)
157
return fail("no menu items found\n");
158
if (!(qctrl.menu_mask & (1 << qctrl.default_value)))
159
return fail("the default_value is an invalid menu item\n");
163
int testQueryControls(struct node *node)
165
struct test_queryctrl qctrl;
168
__u32 ctrl_class = 0;
169
bool found_ctrl_class = false;
170
unsigned user_controls = 0;
171
unsigned priv_user_controls = 0;
172
unsigned user_controls_check = 0;
173
unsigned priv_user_controls_check = 0;
174
unsigned class_count = 0;
177
memset(&qctrl, 0xff, sizeof(qctrl));
178
qctrl.id = id | V4L2_CTRL_FLAG_NEXT_CTRL;
179
ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl);
180
if (ret && ret != EINVAL)
181
return fail("invalid queryctrl return code\n");
183
return fail("does not support V4L2_CTRL_FLAG_NEXT_CTRL\n");
186
if (checkQCtrl(node, qctrl))
187
return fail("invalid control %08x\n", qctrl.id);
189
return fail("id did not increase!\n");
191
if (id >= V4L2_CID_PRIVATE_BASE)
192
return fail("no V4L2_CID_PRIVATE_BASE allowed\n");
193
if (V4L2_CTRL_ID2CLASS(id) != ctrl_class) {
194
if (ctrl_class && !found_ctrl_class)
195
return fail("missing control class for class %08x\n", ctrl_class);
196
if (ctrl_class && !class_count)
197
return fail("no controls in class %08x\n", ctrl_class);
198
ctrl_class = V4L2_CTRL_ID2CLASS(id);
199
found_ctrl_class = false;
202
if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
203
found_ctrl_class = true;
208
if (ctrl_class == V4L2_CTRL_CLASS_USER &&
209
qctrl.type != V4L2_CTRL_TYPE_INTEGER64 &&
210
qctrl.type != V4L2_CTRL_TYPE_STRING &&
211
qctrl.type != V4L2_CTRL_TYPE_CTRL_CLASS) {
212
if (V4L2_CTRL_DRIVER_PRIV(id))
213
priv_user_controls_check++;
214
else if (id < V4L2_CID_LASTP1)
215
user_controls_check++;
217
if (V4L2_CTRL_DRIVER_PRIV(id))
218
node->priv_controls++;
220
node->std_controls++;
221
node->controls.push_back(qctrl);
223
if (ctrl_class && !found_ctrl_class)
224
return fail("missing control class for class %08x\n", ctrl_class);
225
if (ctrl_class && !class_count)
226
return fail("no controls in class %08x\n", ctrl_class);
228
for (id = V4L2_CID_BASE; id < V4L2_CID_LASTP1; id++) {
229
memset(&qctrl, 0xff, sizeof(qctrl));
231
ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl);
232
if (ret && ret != EINVAL)
233
return fail("invalid queryctrl return code\n");
237
return fail("qctrl.id (%08x) != id (%08x)\n",
239
if (checkQCtrl(node, qctrl))
240
return fail("invalid control %08x\n", qctrl.id);
244
for (id = V4L2_CID_PRIVATE_BASE; ; id++) {
245
memset(&qctrl, 0xff, sizeof(qctrl));
247
ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl);
248
if (ret && ret != EINVAL)
249
return fail("invalid queryctrl return code\n");
253
return fail("qctrl.id (%08x) != id (%08x)\n",
255
if (checkQCtrl(node, qctrl))
256
return fail("invalid control %08x\n", qctrl.id);
257
priv_user_controls++;
260
if (user_controls != user_controls_check)
261
return fail("expected %d user controls, got %d\n",
262
user_controls_check, user_controls);
263
if (priv_user_controls != priv_user_controls_check)
264
return fail("expected %d private controls, got %d\n",
265
priv_user_controls_check, priv_user_controls);
269
static int checkSimpleCtrl(struct v4l2_control &ctrl, struct test_queryctrl &qctrl)
271
if (ctrl.id != qctrl.id)
272
return fail("control id mismatch\n");
273
switch (qctrl.type) {
274
case V4L2_CTRL_TYPE_INTEGER:
275
case V4L2_CTRL_TYPE_BOOLEAN:
276
case V4L2_CTRL_TYPE_MENU:
277
if (ctrl.value < qctrl.minimum || ctrl.value > qctrl.maximum)
278
return fail("returned control value out of range\n");
279
if ((ctrl.value - qctrl.minimum) % qctrl.step) {
280
// This really should be a fail, but there are so few
281
// drivers that do this right that I made it a warning
283
warn("%s: returned control value %d not a multiple of step\n",
284
qctrl.name, ctrl.value);
287
case V4L2_CTRL_TYPE_BUTTON:
290
return fail("this type should not allow g_ctrl\n");
295
int testSimpleControls(struct node *node)
297
qctrl_list::iterator iter;
298
struct v4l2_control ctrl;
302
for (iter = node->controls.begin(); iter != node->controls.end(); ++iter) {
303
info("checking control '%s' (0x%08x)\n", iter->name, iter->id);
305
if (iter->type == V4L2_CTRL_TYPE_INTEGER64 ||
306
iter->type == V4L2_CTRL_TYPE_STRING ||
307
iter->type == V4L2_CTRL_TYPE_CTRL_CLASS) {
308
ret = doioctl(node, VIDIOC_G_CTRL, &ctrl);
310
!((iter->flags & V4L2_CTRL_FLAG_WRITE_ONLY) && ret == EACCES))
311
return fail("g_ctrl allowed for unsupported type\n");
314
// This call will crash on kernels <= 2.6.37 for control classes due to
315
// a bug in v4l2-ctrls.c. So skip this on those kernels.
316
if (kernel_version < 38 && iter->type == V4L2_CTRL_TYPE_CTRL_CLASS)
319
ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
321
!((iter->flags & V4L2_CTRL_FLAG_READ_ONLY) && ret == EACCES))
322
return fail("s_ctrl allowed for unsupported type\n");
326
// Get the current value
327
ret = doioctl(node, VIDIOC_G_CTRL, &ctrl);
328
if ((iter->flags & V4L2_CTRL_FLAG_WRITE_ONLY)) {
330
return fail("g_ctrl did not check the write-only flag\n");
332
ctrl.value = iter->default_value;
334
return fail("g_ctrl returned an error\n");
335
else if (checkSimpleCtrl(ctrl, *iter))
336
return fail("invalid control %08x\n", iter->id);
338
// Try to set the current value (or the default value for write only controls)
339
ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
340
if ((iter->flags & V4L2_CTRL_FLAG_READ_ONLY) && ret != EACCES)
341
return fail("s_ctrl did not check the read-only flag\n");
343
return fail("s_ctrl returned an error\n");
346
if (checkSimpleCtrl(ctrl, *iter))
347
return fail("s_ctrl returned invalid control contents (%08x)\n", iter->id);
349
// Try to set value 'minimum - 1'
350
if ((unsigned)iter->minimum != 0x80000000) {
352
ctrl.value = iter->minimum - 1;
353
ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
354
if (ret && ret != ERANGE)
355
return fail("invalid minimum range check\n");
356
if (!ret && checkSimpleCtrl(ctrl, *iter))
357
return fail("invalid control %08x\n", iter->id);
359
// Try to set value 'maximum + 1'
360
if ((unsigned)iter->maximum != 0x7fffffff) {
362
ctrl.value = iter->maximum + 1;
363
ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
364
if (ret && ret != ERANGE)
365
return fail("invalid maximum range check\n");
366
if (!ret && checkSimpleCtrl(ctrl, *iter))
367
return fail("invalid control %08x\n", iter->id);
369
// Try to set non-step value
370
if (iter->step > 1 && iter->maximum > iter->minimum) {
372
ctrl.value = iter->minimum + 1;
373
ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
375
warn("%s: returns ERANGE for in-range, but non-step-multiple value\n",
378
return fail("returns error for in-range, but non-step-multiple value\n");
381
if (iter->type == V4L2_CTRL_TYPE_MENU) {
383
for (i = iter->minimum; i <= iter->maximum; i++) {
384
unsigned valid = iter->menu_mask & (1 << i);
388
ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
390
return fail("could not set valid menu item %d\n", i);
392
return fail("could set invalid menu item %d\n", i);
393
if (ret && ret != EINVAL)
394
return fail("setting invalid menu item returned wrong error\n");
397
// at least min, max and default values should work
399
ctrl.value = iter->minimum;
400
ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
402
return fail("could not set minimum value\n");
403
ctrl.value = iter->maximum;
404
ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
406
return fail("could not set maximum value\n");
407
ctrl.value = iter->default_value;
408
ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
410
return fail("could not set default value\n");
414
ret = doioctl(node, VIDIOC_G_CTRL, &ctrl);
416
return fail("g_ctrl accepted invalid control ID\n");
419
ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
421
return fail("s_ctrl accepted invalid control ID\n");
425
static int checkExtendedCtrl(struct v4l2_ext_control &ctrl, struct test_queryctrl &qctrl)
429
if (ctrl.id != qctrl.id)
430
return fail("control id mismatch\n");
431
switch (qctrl.type) {
432
case V4L2_CTRL_TYPE_INTEGER:
433
case V4L2_CTRL_TYPE_BOOLEAN:
434
case V4L2_CTRL_TYPE_MENU:
435
if (ctrl.value < qctrl.minimum || ctrl.value > qctrl.maximum)
436
return fail("returned control value out of range\n");
437
if ((ctrl.value - qctrl.minimum) % qctrl.step) {
438
// This really should be a fail, but there are so few
439
// drivers that do this right that I made it a warning
441
warn("%s: returned control value %d not a multiple of step\n",
442
qctrl.name, ctrl.value);
445
case V4L2_CTRL_TYPE_BUTTON:
447
case V4L2_CTRL_TYPE_STRING:
448
len = strnlen(ctrl.string, qctrl.maximum + 1);
449
if (len == qctrl.maximum + 1)
450
return fail("string too long\n");
451
if (len < qctrl.minimum)
452
return fail("string too short\n");
453
if ((len - qctrl.minimum) % qctrl.step)
454
return fail("string not a multiple of step\n");
462
int testExtendedControls(struct node *node)
464
qctrl_list::iterator iter;
465
struct v4l2_ext_controls ctrls;
466
std::vector<struct v4l2_ext_control> total_vec;
467
std::vector<struct v4l2_ext_control> class_vec;
468
struct v4l2_ext_control ctrl;
469
__u32 ctrl_class = 0;
470
bool multiple_classes = false;
473
memset(&ctrls, 0, sizeof(ctrls));
474
ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
475
if (ret && !node->controls.empty())
476
return fail("g_ext_ctrls does not support count == 0\n");
477
if (ret && ret != EINVAL)
478
return fail("g_ext_ctrls with count == 0 did not return EINVAL\n");
481
if (node->controls.empty())
482
return fail("g_ext_ctrls worked even when no controls are present\n");
483
if (ctrls.ctrl_class)
484
return fail("field ctrl_class changed\n");
486
return fail("field count changed\n");
487
if (check_0(ctrls.reserved, sizeof(ctrls.reserved)))
488
return fail("reserved not zeroed\n");
490
for (iter = node->controls.begin(); iter != node->controls.end(); ++iter) {
491
info("checking extended control '%s' (0x%08x)\n", iter->name, iter->id);
494
ctrl.reserved2[0] = 0;
497
// Either should work, so try both semi-randomly
498
ctrls.ctrl_class = (ctrl.id & 1) ? 0 : V4L2_CTRL_ID2CLASS(ctrl.id);
499
ctrls.controls = &ctrl;
501
// Get the current value
502
ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
503
if ((iter->flags & V4L2_CTRL_FLAG_WRITE_ONLY)) {
505
return fail("g_ext_ctrls did not check the write-only flag\n");
506
if (ctrls.error_idx != ctrls.count)
507
return fail("invalid error index write only control\n");
509
ctrl.value = iter->default_value;
511
if (ret != ENOSPC && iter->type == V4L2_CTRL_TYPE_STRING)
512
return fail("did not check against size\n");
513
if (ret == ENOSPC && iter->type == V4L2_CTRL_TYPE_STRING) {
514
if (ctrls.error_idx != 0)
515
return fail("invalid error index string control\n");
516
ctrl.string = new char[iter->maximum + 1];
517
ctrl.size = iter->maximum + 1;
518
ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
521
return fail("g_ext_ctrls returned an error\n");
522
if (checkExtendedCtrl(ctrl, *iter))
523
return fail("invalid control %08x\n", iter->id);
526
// Try the current value (or the default value for write only controls)
527
ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
528
if (iter->flags & V4L2_CTRL_FLAG_READ_ONLY) {
530
return fail("try_ext_ctrls did not check the read-only flag\n");
531
if (ctrls.error_idx != 0)
532
return fail("invalid error index read only control\n");
534
return fail("try_ext_ctrls returned an error\n");
537
// Try to set the current value (or the default value for write only controls)
538
ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
539
if (iter->flags & V4L2_CTRL_FLAG_READ_ONLY) {
541
return fail("s_ext_ctrls did not check the read-only flag\n");
542
if (ctrls.error_idx != ctrls.count)
543
return fail("invalid error index\n");
546
return fail("s_ext_ctrls returned an error\n");
548
if (checkExtendedCtrl(ctrl, *iter))
549
return fail("s_ext_ctrls returned invalid control contents (%08x)\n", iter->id);
551
if (iter->type == V4L2_CTRL_TYPE_STRING)
552
delete [] ctrl.string;
556
ctrls.ctrl_class = 0;
559
ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
561
return fail("g_ext_ctrls accepted invalid control ID\n");
562
if (ctrls.error_idx != ctrls.count)
563
return fail("g_ext_ctrls(0) invalid error_idx\n");
567
ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
569
return fail("try_ext_ctrls accepted invalid control ID\n");
570
if (ctrls.error_idx != 0)
571
return fail("try_ext_ctrls(0) invalid error_idx\n");
572
ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
574
return fail("s_ext_ctrls accepted invalid control ID\n");
575
if (ctrls.error_idx != ctrls.count)
576
return fail("s_ext_ctrls(0) invalid error_idx\n");
578
for (iter = node->controls.begin(); iter != node->controls.end(); ++iter) {
579
struct v4l2_ext_control ctrl;
581
if (iter->flags & (V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY))
585
if (iter->type == V4L2_CTRL_TYPE_STRING) {
586
ctrl.size = iter->maximum + 1;
587
ctrl.string = new char[ctrl.size];
589
ctrl.reserved2[0] = 0;
591
ctrl_class = V4L2_CTRL_ID2CLASS(ctrl.id);
592
else if (ctrl_class != V4L2_CTRL_ID2CLASS(ctrl.id))
593
multiple_classes = true;
594
total_vec.push_back(ctrl);
597
ctrls.count = total_vec.size();
598
ctrls.controls = &total_vec[0];
599
ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
601
return fail("could not get all controls\n");
602
ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
604
return fail("could not try all controls\n");
605
ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
607
return fail("could not set all controls\n");
609
ctrls.ctrl_class = ctrl_class;
610
ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
611
if (ret && !multiple_classes)
612
return fail("could not get all controls of a specific class\n");
613
if (ret != EINVAL && multiple_classes)
614
return fail("should get EINVAL when getting mixed-class controls\n");
615
if (multiple_classes && ctrls.error_idx != ctrls.count)
616
return fail("error_idx should be equal to count\n");
617
ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
618
if (ret && !multiple_classes)
619
return fail("could not try all controls of a specific class\n");
620
if (ret != EINVAL && multiple_classes)
621
return fail("should get EINVAL when trying mixed-class controls\n");
622
if (multiple_classes && ctrls.error_idx >= ctrls.count)
623
return fail("error_idx should be < count\n");
624
ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
625
if (ret && !multiple_classes)
626
return fail("could not set all controls of a specific class\n");
627
if (ret != EINVAL && multiple_classes)
628
return fail("should get EINVAL when setting mixed-class controls\n");
629
if (multiple_classes && ctrls.error_idx != ctrls.count)
630
return fail("error_idx should be equal to count\n");