~ubuntu-branches/ubuntu/precise/v4l-utils/precise-updates

« back to all changes in this revision

Viewing changes to utils/v4l2-compliance/v4l2-test-controls.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Gregor Jasny
  • Date: 2011-01-26 22:35:38 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20110126223538-v4qdqz7ihlrbc9up
Tags: 0.8.2-1
* Imported Upstream version 0.8.2
* Removed patches that got applied upstream
* Keytable maps file got renamed upstream. Adjusted sed command line.
* Updated copyright file
* Use upstream manpage for ir-keytable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 */
 
20
 
 
21
#include <unistd.h>
 
22
#include <stdlib.h>
 
23
#include <stdio.h>
 
24
#include <string.h>
 
25
#include <inttypes.h>
 
26
#include <sys/types.h>
 
27
#include <sys/stat.h>
 
28
#include <fcntl.h>
 
29
#include <ctype.h>
 
30
#include <errno.h>
 
31
#include <sys/ioctl.h>
 
32
#include <vector>
 
33
#include "v4l2-compliance.h"
 
34
 
 
35
static int checkQCtrl(struct node *node, struct test_queryctrl &qctrl)
 
36
{
 
37
        struct v4l2_querymenu qmenu;
 
38
        __u32 fl = qctrl.flags;
 
39
        __u32 rw_mask = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
 
40
        int ret;
 
41
        int i;
 
42
 
 
43
        qctrl.menu_mask = 0;
 
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");
 
57
        }
 
58
        switch (qctrl.type) {
 
59
        case V4L2_CTRL_TYPE_BOOLEAN:
 
60
                if (qctrl.maximum > 1)
 
61
                        return fail("invalid boolean max value\n");
 
62
                /* fall through */
 
63
        case V4L2_CTRL_TYPE_MENU:
 
64
                if (qctrl.step != 1)
 
65
                        return fail("invalid step value %d\n", qctrl.step);
 
66
                if (qctrl.minimum < 0)
 
67
                        return fail("min < 0\n");
 
68
                /* fall through */
 
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");
 
73
                /* fall through */
 
74
        case V4L2_CTRL_TYPE_STRING:
 
75
                if (qctrl.minimum > qctrl.maximum)
 
76
                        return fail("min > max\n");
 
77
                if (qctrl.step == 0)
 
78
                        return fail("step == 0\n");
 
79
                if (qctrl.step < 0)
 
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
 
86
                        // for now.
 
87
                        warn("%s: (max - min) %% step != 0\n", qctrl.name);
 
88
                }
 
89
                break;
 
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");
 
95
                break;
 
96
        default:
 
97
                return fail("unknown control type\n");
 
98
        }
 
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");
 
105
                /* fall through */
 
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");
 
111
                /* fall through */
 
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");
 
116
                break;
 
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");
 
120
                break;
 
121
        }
 
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));
 
128
                qmenu.id = qctrl.id;
 
129
                qmenu.index = qctrl.minimum;
 
130
                ret = doioctl(node, VIDIOC_QUERYMENU, &qmenu);
 
131
                if (ret != EINVAL)
 
132
                        return fail("can do querymenu on a non-menu control\n");
 
133
                return 0;
 
134
        }
 
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));
 
139
                qmenu.id = qctrl.id;
 
140
                qmenu.index = i;
 
141
                ret = doioctl(node, VIDIOC_QUERYMENU, &qmenu);
 
142
                if (ret && ret != EINVAL)
 
143
                        return fail("invalid QUERYMENU return code\n");
 
144
                if (ret)
 
145
                        continue;
 
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");
 
152
                if (qmenu.reserved)
 
153
                        return fail("reserved is non-zero\n");
 
154
                qctrl.menu_mask |= 1 << i;
 
155
        }
 
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");
 
160
        return 0;
 
161
}
 
162
 
 
163
int testQueryControls(struct node *node)
 
164
{
 
165
        struct test_queryctrl qctrl;
 
166
        __u32 id = 0;
 
167
        int ret;
 
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;
 
175
 
 
176
        for (;;) {
 
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");
 
182
                if (ret && id == 0)
 
183
                        return fail("does not support V4L2_CTRL_FLAG_NEXT_CTRL\n");
 
184
                if (ret)
 
185
                        break;
 
186
                if (checkQCtrl(node, qctrl))
 
187
                        return fail("invalid control %08x\n", qctrl.id);
 
188
                if (qctrl.id <= id)
 
189
                        return fail("id did not increase!\n");
 
190
                id = qctrl.id;
 
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;
 
200
                        class_count = 0;
 
201
                }
 
202
                if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
 
203
                        found_ctrl_class = true;
 
204
                } else {
 
205
                        class_count++;
 
206
                }
 
207
 
 
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++;
 
216
                }
 
217
                if (V4L2_CTRL_DRIVER_PRIV(id))
 
218
                        node->priv_controls++;
 
219
                else
 
220
                        node->std_controls++;
 
221
                node->controls.push_back(qctrl);
 
222
        }
 
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);
 
227
 
 
228
        for (id = V4L2_CID_BASE; id < V4L2_CID_LASTP1; id++) {
 
229
                memset(&qctrl, 0xff, sizeof(qctrl));
 
230
                qctrl.id = id;
 
231
                ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl);
 
232
                if (ret && ret != EINVAL)
 
233
                        return fail("invalid queryctrl return code\n");
 
234
                if (ret)
 
235
                        continue;
 
236
                if (qctrl.id != id)
 
237
                        return fail("qctrl.id (%08x) != id (%08x)\n",
 
238
                                        qctrl.id, id);
 
239
                if (checkQCtrl(node, qctrl))
 
240
                        return fail("invalid control %08x\n", qctrl.id);
 
241
                user_controls++;
 
242
        }
 
243
 
 
244
        for (id = V4L2_CID_PRIVATE_BASE; ; id++) {
 
245
                memset(&qctrl, 0xff, sizeof(qctrl));
 
246
                qctrl.id = id;
 
247
                ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl);
 
248
                if (ret && ret != EINVAL)
 
249
                        return fail("invalid queryctrl return code\n");
 
250
                if (ret)
 
251
                        break;
 
252
                if (qctrl.id != id)
 
253
                        return fail("qctrl.id (%08x) != id (%08x)\n",
 
254
                                        qctrl.id, id);
 
255
                if (checkQCtrl(node, qctrl))
 
256
                        return fail("invalid control %08x\n", qctrl.id);
 
257
                priv_user_controls++;
 
258
        }
 
259
 
 
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);
 
266
        return 0;
 
267
}
 
268
 
 
269
static int checkSimpleCtrl(struct v4l2_control &ctrl, struct test_queryctrl &qctrl)
 
270
{
 
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
 
282
                        // for now.
 
283
                        warn("%s: returned control value %d not a multiple of step\n",
 
284
                                        qctrl.name, ctrl.value);
 
285
                }
 
286
                break;
 
287
        case V4L2_CTRL_TYPE_BUTTON:
 
288
                break;
 
289
        default:
 
290
                return fail("this type should not allow g_ctrl\n");
 
291
        }
 
292
        return 0;
 
293
}
 
294
 
 
295
int testSimpleControls(struct node *node)
 
296
{
 
297
        qctrl_list::iterator iter;
 
298
        struct v4l2_control ctrl;
 
299
        int ret;
 
300
        int i;
 
301
 
 
302
        for (iter = node->controls.begin(); iter != node->controls.end(); ++iter) {
 
303
                info("checking control '%s' (0x%08x)\n", iter->name, iter->id);
 
304
                ctrl.id = 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);
 
309
                        if (ret != EINVAL &&
 
310
                            !((iter->flags & V4L2_CTRL_FLAG_WRITE_ONLY) && ret == EACCES))
 
311
                                return fail("g_ctrl allowed for unsupported type\n");
 
312
                        ctrl.id = iter->id;
 
313
                        ctrl.value = 0;
 
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)
 
317
                                ret = EACCES;
 
318
                        else
 
319
                                ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
 
320
                        if (ret != EINVAL &&
 
321
                            !((iter->flags & V4L2_CTRL_FLAG_READ_ONLY) && ret == EACCES))
 
322
                                return fail("s_ctrl allowed for unsupported type\n");
 
323
                        continue;
 
324
                }
 
325
 
 
326
                // Get the current value
 
327
                ret = doioctl(node, VIDIOC_G_CTRL, &ctrl);
 
328
                if ((iter->flags & V4L2_CTRL_FLAG_WRITE_ONLY)) {
 
329
                        if (ret != EACCES)
 
330
                                return fail("g_ctrl did not check the write-only flag\n");
 
331
                        ctrl.id = iter->id;
 
332
                        ctrl.value = iter->default_value;
 
333
                } else if (ret)
 
334
                        return fail("g_ctrl returned an error\n");
 
335
                else if (checkSimpleCtrl(ctrl, *iter))
 
336
                        return fail("invalid control %08x\n", iter->id);
 
337
                
 
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");
 
342
                else if (ret)
 
343
                        return fail("s_ctrl returned an error\n");
 
344
                if (ret)
 
345
                        continue;
 
346
                if (checkSimpleCtrl(ctrl, *iter))
 
347
                        return fail("s_ctrl returned invalid control contents (%08x)\n", iter->id);
 
348
 
 
349
                // Try to set value 'minimum - 1'
 
350
                if ((unsigned)iter->minimum != 0x80000000) {
 
351
                        ctrl.id = iter->id;
 
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);
 
358
                }
 
359
                // Try to set value 'maximum + 1'
 
360
                if ((unsigned)iter->maximum != 0x7fffffff) {
 
361
                        ctrl.id = iter->id;
 
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);
 
368
                }
 
369
                // Try to set non-step value
 
370
                if (iter->step > 1 && iter->maximum > iter->minimum) {
 
371
                        ctrl.id = iter->id;
 
372
                        ctrl.value = iter->minimum + 1;
 
373
                        ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
 
374
                        if (ret == ERANGE)
 
375
                                warn("%s: returns ERANGE for in-range, but non-step-multiple value\n",
 
376
                                                iter->name);
 
377
                        else if (ret)
 
378
                                return fail("returns error for in-range, but non-step-multiple value\n");
 
379
                }
 
380
 
 
381
                if (iter->type == V4L2_CTRL_TYPE_MENU) {
 
382
                        // check menu items
 
383
                        for (i = iter->minimum; i <= iter->maximum; i++) {
 
384
                                unsigned valid = iter->menu_mask & (1 << i);
 
385
 
 
386
                                ctrl.id = iter->id; 
 
387
                                ctrl.value = i;
 
388
                                ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
 
389
                                if (valid && ret)
 
390
                                        return fail("could not set valid menu item %d\n", i);
 
391
                                if (!valid && !ret)
 
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");
 
395
                        }
 
396
                } else {
 
397
                        // at least min, max and default values should work
 
398
                        ctrl.id = iter->id; 
 
399
                        ctrl.value = iter->minimum;
 
400
                        ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
 
401
                        if (ret)
 
402
                                return fail("could not set minimum value\n");
 
403
                        ctrl.value = iter->maximum;
 
404
                        ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
 
405
                        if (ret)
 
406
                                return fail("could not set maximum value\n");
 
407
                        ctrl.value = iter->default_value;
 
408
                        ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
 
409
                        if (ret)
 
410
                                return fail("could not set default value\n");
 
411
                }
 
412
        }
 
413
        ctrl.id = 0;
 
414
        ret = doioctl(node, VIDIOC_G_CTRL, &ctrl);
 
415
        if (ret != EINVAL)
 
416
                return fail("g_ctrl accepted invalid control ID\n");
 
417
        ctrl.id = 0;
 
418
        ctrl.value = 0;
 
419
        ret = doioctl(node, VIDIOC_S_CTRL, &ctrl);
 
420
        if (ret != EINVAL)
 
421
                return fail("s_ctrl accepted invalid control ID\n");
 
422
        return 0;
 
423
}
 
424
 
 
425
static int checkExtendedCtrl(struct v4l2_ext_control &ctrl, struct test_queryctrl &qctrl)
 
426
{
 
427
        int len;
 
428
 
 
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
 
440
                        // for now.
 
441
                        warn("%s: returned control value %d not a multiple of step\n",
 
442
                                        qctrl.name, ctrl.value);
 
443
                }
 
444
                break;
 
445
        case V4L2_CTRL_TYPE_BUTTON:
 
446
                break;
 
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");
 
455
                break;
 
456
        default:
 
457
                break;
 
458
        }
 
459
        return 0;
 
460
}
 
461
 
 
462
int testExtendedControls(struct node *node)
 
463
{
 
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;
 
471
        int ret;
 
472
 
 
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");
 
479
        if (ret)
 
480
                return -ENOSYS;
 
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");
 
485
        if (ctrls.count)
 
486
                return fail("field count changed\n");
 
487
        if (check_0(ctrls.reserved, sizeof(ctrls.reserved)))
 
488
                return fail("reserved not zeroed\n");
 
489
 
 
490
        for (iter = node->controls.begin(); iter != node->controls.end(); ++iter) {
 
491
                info("checking extended control '%s' (0x%08x)\n", iter->name, iter->id);
 
492
                ctrl.id = iter->id;
 
493
                ctrl.size = 0;
 
494
                ctrl.reserved2[0] = 0;
 
495
                ctrls.count = 1;
 
496
 
 
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;
 
500
 
 
501
                // Get the current value
 
502
                ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
 
503
                if ((iter->flags & V4L2_CTRL_FLAG_WRITE_ONLY)) {
 
504
                        if (ret != EACCES)
 
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");
 
508
                        ctrl.id = iter->id;
 
509
                        ctrl.value = iter->default_value;
 
510
                } else {
 
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);
 
519
                        }
 
520
                        if (ret)
 
521
                                return fail("g_ext_ctrls returned an error\n");
 
522
                        if (checkExtendedCtrl(ctrl, *iter))
 
523
                                return fail("invalid control %08x\n", iter->id);
 
524
                }
 
525
                
 
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) {
 
529
                        if (ret != EACCES)
 
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");
 
533
                } else if (ret) {
 
534
                        return fail("try_ext_ctrls returned an error\n");
 
535
                }
 
536
                
 
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) {
 
540
                        if (ret != EACCES)
 
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");
 
544
                } else {
 
545
                        if (ret)
 
546
                                return fail("s_ext_ctrls returned an error\n");
 
547
                
 
548
                        if (checkExtendedCtrl(ctrl, *iter))
 
549
                                return fail("s_ext_ctrls returned invalid control contents (%08x)\n", iter->id);
 
550
                }
 
551
                if (iter->type == V4L2_CTRL_TYPE_STRING)
 
552
                        delete [] ctrl.string;
 
553
                ctrl.string = NULL;
 
554
        }
 
555
 
 
556
        ctrls.ctrl_class = 0;
 
557
        ctrl.id = 0;
 
558
        ctrl.size = 0;
 
559
        ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
 
560
        if (ret != EINVAL)
 
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");
 
564
        ctrl.id = 0;
 
565
        ctrl.size = 0;
 
566
        ctrl.value = 0;
 
567
        ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
 
568
        if (ret != EINVAL)
 
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);
 
573
        if (ret != EINVAL)
 
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");
 
577
 
 
578
        for (iter = node->controls.begin(); iter != node->controls.end(); ++iter) {
 
579
                struct v4l2_ext_control ctrl;
 
580
 
 
581
                if (iter->flags & (V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY))
 
582
                        continue;
 
583
                ctrl.id = iter->id;
 
584
                ctrl.size = 0;
 
585
                if (iter->type == V4L2_CTRL_TYPE_STRING) {
 
586
                        ctrl.size = iter->maximum + 1;
 
587
                        ctrl.string = new char[ctrl.size];
 
588
                }
 
589
                ctrl.reserved2[0] = 0;
 
590
                if (!ctrl_class)
 
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);
 
595
        }
 
596
 
 
597
        ctrls.count = total_vec.size();
 
598
        ctrls.controls = &total_vec[0];
 
599
        ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
 
600
        if (ret)
 
601
                return fail("could not get all controls\n");
 
602
        ret = doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls);
 
603
        if (ret)
 
604
                return fail("could not try all controls\n");
 
605
        ret = doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls);
 
606
        if (ret)
 
607
                return fail("could not set all controls\n");
 
608
 
 
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");
 
631
        return 0;
 
632
}