1 /*
2  * v4l-test: Test environment for Video For Linux Two API
3  *
4  * 25 Mar 2009  0.5  Cleaned up ret and errno variable names
5  * 14 Mar 2009  0.4  Added test steps for S16_MIN, S16_MAX, U16_MIN and U16_MAX
6  *  6 Mar 2009  0.3  Check whether the newly set value is converted to the
7  *                   closest valid value when setting out of bounds value
8  * 22 Feb 2009  0.2  Added test cases for VIDIOC_S_CTRL
9  * 19 Feb 2009  0.1  First release
10  *
11  * Written by M�rton N�meth <nm127@freemail.hu>
12  * Released under GPL
13  */
14 
15 /*
16  * Note: V4L2_CID_LASTP1 != V4L2_CID_BASE_LASTP1
17  */
18 
19 #include <sys/ioctl.h>
20 #include <errno.h>
21 #include <string.h>
22 
23 #include <linux/videodev2.h>
24 #include <linux/errno.h>
25 
26 #include <CUnit/CUnit.h>
27 
28 #include "v4l2_test.h"
29 #include "dev_video.h"
30 #include "video_limits.h"
31 
32 #include "test_VIDIOC_CTRL.h"
33 
do_get_control(__u32 id)34 static int do_get_control(__u32 id)
35 {
36 	int ret_query, errno_query;
37 	int ret_get, errno_get;
38 	struct v4l2_queryctrl queryctrl;
39 	struct v4l2_control control;
40 
41 	/* The expected return value of VIDIOC_G_CTRL depens on the value
42 	 * reported by VIDIOC_QUERYCTRL
43 	 */
44 
45 	memset(&queryctrl, 0, sizeof(queryctrl));
46 	queryctrl.id = id;
47 	ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl);
48 	errno_query = errno;
49 
50 	dprintf
51 	    ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n",
52 	     __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_query,
53 	     errno_query);
54 	if (ret_query == 0) {
55 		dprintf("\t%s:%u: queryctrl = {.id=%u, .type=%i, .name=\"%s\", "
56 			".minimum=%i, .maximum=%i, .step=%i, "
57 			".default_value=%i, "
58 			".flags=0x%X, "
59 			".reserved[]={ 0x%X, 0x%X } }\n",
60 			__FILE__, __LINE__,
61 			queryctrl.id,
62 			queryctrl.type,
63 			queryctrl.name,
64 			queryctrl.minimum,
65 			queryctrl.maximum,
66 			queryctrl.step,
67 			queryctrl.default_value,
68 			queryctrl.flags,
69 			queryctrl.reserved[0], queryctrl.reserved[1]
70 		    );
71 	}
72 
73 	memset(&control, 0xff, sizeof(control));
74 	control.id = id;
75 	ret_get = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control);
76 	errno_get = errno;
77 
78 	dprintf
79 	    ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i\n",
80 	     __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get, errno_get);
81 
82 	if (ret_query == 0) {
83 		CU_ASSERT_EQUAL(ret_query, 0);
84 
85 		switch (queryctrl.type) {
86 		case V4L2_CTRL_TYPE_INTEGER:
87 		case V4L2_CTRL_TYPE_BOOLEAN:
88 		case V4L2_CTRL_TYPE_MENU:
89 			CU_ASSERT_EQUAL(ret_get, 0);
90 			if (ret_get == 0) {
91 				CU_ASSERT(queryctrl.minimum <= control.value);
92 				CU_ASSERT(control.value <= queryctrl.maximum);
93 			}
94 			break;
95 
96 		case V4L2_CTRL_TYPE_BUTTON:
97 			/* This control only performs an action, does not have
98 			 * any value
99 			 */
100 			CU_ASSERT_EQUAL(ret_get, -1);
101 			CU_ASSERT_EQUAL(errno_get, EINVAL);
102 			break;
103 
104 		case V4L2_CTRL_TYPE_INTEGER64:	/* TODO: what about this case? */
105 		case V4L2_CTRL_TYPE_CTRL_CLASS:
106 		default:
107 			CU_ASSERT_EQUAL(ret_get, -1);
108 			CU_ASSERT_EQUAL(errno_get, EINVAL);
109 		}
110 	} else {
111 		CU_ASSERT_EQUAL(ret_query, -1);
112 		CU_ASSERT_EQUAL(errno_query, EINVAL);
113 
114 		CU_ASSERT_EQUAL(ret_get, -1);
115 		CU_ASSERT_EQUAL(errno_get, EINVAL);
116 
117 	}
118 
119 	return ret_query;
120 }
121 
test_VIDIOC_G_CTRL()122 void test_VIDIOC_G_CTRL()
123 {
124 	int ret1;
125 	__u32 i;
126 
127 	for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) {
128 		ret1 = do_get_control(i);
129 	}
130 
131 	ret1 = do_get_control(V4L2_CID_BASE - 1);
132 	ret1 = do_get_control(V4L2_CID_LASTP1);
133 	ret1 = do_get_control(V4L2_CID_PRIVATE_BASE - 1);
134 
135 	i = V4L2_CID_PRIVATE_BASE;
136 	do {
137 		ret1 = do_get_control(i);
138 		i++;
139 	} while (ret1 == 0);
140 
141 	ret1 = do_get_control(i);
142 }
143 
test_VIDIOC_G_CTRL_NULL()144 void test_VIDIOC_G_CTRL_NULL()
145 {
146 	int ret_get, errno_get;
147 	int ret_null, errno_null;
148 	struct v4l2_control control;
149 	__u32 id;
150 
151 	id = V4L2_CID_BASE;
152 	ret_get = -1;
153 	while (ret_get == -1 && id < V4L2_CID_LASTP1) {
154 		memset(&control, 0xff, sizeof(control));
155 		control.id = id;
156 		ret_get = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control);
157 		errno_get = errno;
158 		dprintf
159 		    ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i\n",
160 		     __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get,
161 		     errno_get);
162 	}
163 
164 	ret_null = ioctl(get_video_fd(), VIDIOC_G_CTRL, NULL);
165 	errno_null = errno;
166 
167 	dprintf("\t%s:%u: VIDIOC_G_CTRL, ret_null=%i, errno_null=%i\n",
168 		__FILE__, __LINE__, ret_null, errno_null);
169 
170 	if (ret_get == 0) {
171 		CU_ASSERT_EQUAL(ret_get, 0);
172 		CU_ASSERT_EQUAL(ret_null, -1);
173 		CU_ASSERT_EQUAL(errno_null, EFAULT);
174 	} else {
175 		CU_ASSERT_EQUAL(ret_get, -1);
176 		CU_ASSERT_EQUAL(errno_get, EINVAL);
177 		CU_ASSERT_EQUAL(ret_null, -1);
178 		CU_ASSERT_EQUAL(errno_null, EINVAL);
179 	}
180 
181 }
182 
do_set_control(__u32 id)183 int do_set_control(__u32 id)
184 {
185 	int ret_query, errno_query;
186 	int ret_set, errno_set;
187 	int ret_get, errno_get;
188 	int ret_orig, errno_orig;
189 	struct v4l2_queryctrl queryctrl;
190 	struct v4l2_control control_orig;
191 	struct v4l2_control control;
192 	struct v4l2_control control_new;
193 	__s32 value;
194 
195 	/* The expected return value of VIDIOC_S_CTRL depens on the value
196 	 * reported by VIDIOC_QUERYCTRL. The allowed limits are also
197 	 * reported by VIDIOC_QUERYCTRL.
198 	 */
199 
200 	memset(&queryctrl, 0, sizeof(queryctrl));
201 	queryctrl.id = id;
202 	ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl);
203 	errno_query = errno;
204 
205 	dprintf
206 	    ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n",
207 	     __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_query,
208 	     errno_query);
209 	if (ret_query == 0) {
210 		dprintf("\t%s:%u: queryctrl = {.id=%u, .type=%i, .name=\"%s\", "
211 			".minimum=%i, .maximum=%i, .step=%i, "
212 			".default_value=%i, "
213 			".flags=0x%X, "
214 			".reserved[]={ 0x%X, 0x%X } }\n",
215 			__FILE__, __LINE__,
216 			queryctrl.id,
217 			queryctrl.type,
218 			queryctrl.name,
219 			queryctrl.minimum,
220 			queryctrl.maximum,
221 			queryctrl.step,
222 			queryctrl.default_value,
223 			queryctrl.flags,
224 			queryctrl.reserved[0], queryctrl.reserved[1]
225 		    );
226 	}
227 
228 	memset(&control_orig, 0, sizeof(control_orig));
229 	control_orig.id = id;
230 	ret_orig = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control_orig);
231 	errno_orig = errno;
232 
233 	dprintf
234 	    ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_orig=%i, errno_orig=%i, control_orig.value=%i\n",
235 	     __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_orig, errno_orig,
236 	     control_orig.value);
237 
238 	if (ret_query == 0) {
239 		CU_ASSERT_EQUAL(ret_query, 0);
240 
241 		switch (queryctrl.type) {
242 		case V4L2_CTRL_TYPE_INTEGER:
243 		case V4L2_CTRL_TYPE_BOOLEAN:
244 		case V4L2_CTRL_TYPE_MENU:
245 
246 			/* TODO: this is an infinite loop if queryctrl.maximum == S32_MAX */
247 			for (value = queryctrl.minimum;
248 			     value <= queryctrl.maximum; value++) {
249 				memset(&control, 0xff, sizeof(control));
250 				control.id = id;
251 				control.value = value;
252 				ret_set =
253 				    ioctl(get_video_fd(), VIDIOC_S_CTRL,
254 					  &control);
255 				errno_set = errno;
256 
257 				dprintf
258 				    ("\t%s:%u: VIDIOC_S_CTRL, id=%u (V4L2_CID_BASE+%i), value=%i, ret_set=%i, errno_set=%i\n",
259 				     __FILE__, __LINE__, id, id - V4L2_CID_BASE,
260 				     value, ret_set, errno_set);
261 
262 				if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED ||
263 				    queryctrl.
264 				    flags & V4L2_CTRL_FLAG_READ_ONLY) {
265 					CU_ASSERT_EQUAL(ret_set, -1);
266 					CU_ASSERT_EQUAL(errno_set, EINVAL);
267 				} else if (queryctrl.
268 					   flags & V4L2_CTRL_FLAG_GRABBED) {
269 					CU_ASSERT_EQUAL(ret_set, -1);
270 					CU_ASSERT_EQUAL(errno_set, EBUSY);
271 				} else {
272 					CU_ASSERT_EQUAL(ret_set, 0);
273 				}
274 
275 				memset(&control_new, 0, sizeof(control_new));
276 				control_new.id = id;
277 				ret_get =
278 				    ioctl(get_video_fd(), VIDIOC_G_CTRL,
279 					  &control_new);
280 				errno_get = errno;
281 
282 				dprintf
283 				    ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i, control_new.value=%i\n",
284 				     __FILE__, __LINE__, id, id - V4L2_CID_BASE,
285 				     ret_get, errno_get, control_new.value);
286 
287 				CU_ASSERT_EQUAL(ret_get, 0);
288 				if (ret_get == 0) {
289 					CU_ASSERT(queryctrl.minimum <=
290 						  control_new.value);
291 					CU_ASSERT(control_new.value <=
292 						  queryctrl.maximum);
293 
294 					if (ret_set == 0) {
295 						/* TODO: the following checks works correctly only if
296 						 * S32_MIN <= queryctrl.minimum-queryctrl.step and
297 						 * queryctrl.maximum+queryctrl.step <= S32_MAX
298 						 */
299 
300 /*
301  * If we try to set the new control value to "value" then the possible results can be
302  * "x" and "x-step". These two values can be expressed with the range
303  * (value-step, value+step) where the ranges are not included.
304  *
305  *           value-step        value         value+step
306  *              |                |                |
307  *              |                v                |
308  *              +----------------+----------------+
309  *               *********************************
310  * ... -+----------------+----------------+----------------+----------------+- ...
311  *      |                |                |                |                |
312  *   x-2*step          x-step             x              x+step          x+2*step
313  *
314  * The following figure shows the case when we try to set value to "x" which is
315  * a possible set value. In this case the only valid result is the "x".
316  *
317  *                    value-step        value         value+step
318  *                       |                |                |
319  *                       |                v                |
320  *                       +----------------+----------------+
321  *                        *********************************
322  * ... -+----------------+----------------+----------------+----------------+- ...
323  *      |                |                |                |                |
324  *   x-2*step          x-step             x              x+step          x+2*step
325  *
326  *
327  *                                    value-step        value         value+step
328  *                                       |                |                |
329  *                                       |                v                |
330  *                                       +----------------+----------------+
331  *                                        *********************************
332  * ... -+----------------+----------------+----------------+----------------+- ...
333  *      |                |                |                |                |
334  *   x-2*step          x-step             x              x+step          x+2*step
335  *
336  *
337  */
338 						CU_ASSERT(value -
339 							  queryctrl.step <
340 							  control_new.value);
341 						CU_ASSERT(control_new.value <
342 							  value +
343 							  queryctrl.step);
344 					}
345 				}
346 
347 			}
348 
349 			break;
350 
351 		case V4L2_CTRL_TYPE_BUTTON:
352 			/* This control only performs an action, does not have
353 			 * any value
354 			 */
355 			CU_ASSERT_EQUAL(ret_orig, -1);
356 			CU_ASSERT_EQUAL(errno_orig, EINVAL);
357 
358 			/* The set value shall be ignored by button controls */
359 
360 			memset(&control, 0xff, sizeof(control));
361 			control.id = id;
362 			control.value = S32_MIN;
363 			ret_set =
364 			    ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
365 			errno_set = errno;
366 
367 			if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED ||
368 			    queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
369 				CU_ASSERT_EQUAL(ret_set, -1);
370 				CU_ASSERT_EQUAL(errno_set, EINVAL);
371 			} else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) {
372 				CU_ASSERT_EQUAL(ret_set, -1);
373 				CU_ASSERT_EQUAL(errno_set, EBUSY);
374 			} else {
375 				CU_ASSERT_EQUAL(ret_set, 0);
376 			}
377 
378 			memset(&control, 0xff, sizeof(control));
379 			control.id = id;
380 			control.value = -1;
381 			ret_set =
382 			    ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
383 			errno_set = errno;
384 
385 			if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED ||
386 			    queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
387 				CU_ASSERT_EQUAL(ret_set, -1);
388 				CU_ASSERT_EQUAL(errno_set, EINVAL);
389 			} else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) {
390 				CU_ASSERT_EQUAL(ret_set, -1);
391 				CU_ASSERT_EQUAL(errno_set, EBUSY);
392 			} else {
393 				CU_ASSERT_EQUAL(ret_set, 0);
394 			}
395 
396 			memset(&control, 0xff, sizeof(control));
397 			control.id = id;
398 			control.value = 0;
399 			ret_set =
400 			    ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
401 			errno_set = errno;
402 
403 			if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED ||
404 			    queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
405 				CU_ASSERT_EQUAL(ret_set, -1);
406 				CU_ASSERT_EQUAL(errno_set, EINVAL);
407 			} else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) {
408 				CU_ASSERT_EQUAL(ret_set, -1);
409 				CU_ASSERT_EQUAL(errno_set, EBUSY);
410 			} else {
411 				CU_ASSERT_EQUAL(ret_set, 0);
412 			}
413 
414 			memset(&control, 0xff, sizeof(control));
415 			control.id = id;
416 			control.value = 1;
417 			ret_set =
418 			    ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
419 			errno_set = errno;
420 
421 			if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED ||
422 			    queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
423 				CU_ASSERT_EQUAL(ret_set, -1);
424 				CU_ASSERT_EQUAL(errno_set, EINVAL);
425 			} else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) {
426 				CU_ASSERT_EQUAL(ret_set, -1);
427 				CU_ASSERT_EQUAL(errno_set, EBUSY);
428 			} else {
429 				CU_ASSERT_EQUAL(ret_set, 0);
430 			}
431 
432 			memset(&control, 0xff, sizeof(control));
433 			control.id = id;
434 			control.value = S32_MAX;
435 			ret_set =
436 			    ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
437 			errno_set = errno;
438 
439 			if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED ||
440 			    queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
441 				CU_ASSERT_EQUAL(ret_set, -1);
442 				CU_ASSERT_EQUAL(errno_set, EINVAL);
443 			} else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) {
444 				CU_ASSERT_EQUAL(ret_set, -1);
445 				CU_ASSERT_EQUAL(errno_set, EBUSY);
446 			} else {
447 				CU_ASSERT_EQUAL(ret_set, 0);
448 			}
449 
450 			break;
451 
452 		case V4L2_CTRL_TYPE_INTEGER64:	/* TODO: what about this case? */
453 		case V4L2_CTRL_TYPE_CTRL_CLASS:
454 		default:
455 			CU_ASSERT_EQUAL(ret_orig, -1);
456 			CU_ASSERT_EQUAL(errno_orig, -1);
457 		}
458 	} else {
459 		CU_ASSERT_EQUAL(ret_query, -1);
460 		CU_ASSERT_EQUAL(errno_query, EINVAL);
461 
462 		CU_ASSERT_EQUAL(ret_orig, -1);
463 		CU_ASSERT_EQUAL(errno_orig, EINVAL);
464 
465 	}
466 
467 	if (ret_orig == 0) {
468 		CU_ASSERT_EQUAL(ret_orig, 0);
469 
470 		/* restore the original control value */
471 		value = control_orig.value;
472 		memset(&control, 0xff, sizeof(control));
473 		control.id = id;
474 		control.value = value;
475 		ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
476 		errno_set = errno;
477 
478 		dprintf
479 		    ("\t%s:%u: VIDIOC_S_CTRL, id=%u (V4L2_CID_BASE+%i), value=%i, ret_set=%i, errno_set=%i\n",
480 		     __FILE__, __LINE__, id, id - V4L2_CID_BASE, value, ret_set,
481 		     errno_set);
482 
483 		/* it shall be possible to set to the original value if the control
484 		 * is not disabled, read only or grabbed by other application
485 		 */
486 		if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED ||
487 		    queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
488 			CU_ASSERT_EQUAL(ret_set, -1);
489 			CU_ASSERT_EQUAL(errno_set, EINVAL);
490 		} else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) {
491 			CU_ASSERT_EQUAL(ret_set, -1);
492 			CU_ASSERT_EQUAL(errno_set, EBUSY);
493 		} else {
494 			CU_ASSERT_EQUAL(ret_set, 0);
495 		}
496 
497 		memset(&control_new, 0, sizeof(control_new));
498 		control_new.id = id;
499 		ret_get = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control_new);
500 		errno_get = errno;
501 
502 		dprintf
503 		    ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i, control_new.value=%i\n",
504 		     __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get,
505 		     errno_get, control_new.value);
506 
507 		CU_ASSERT_EQUAL(ret_get, 0);
508 		if (ret_get == 0) {
509 			CU_ASSERT(queryctrl.minimum <= control_new.value);
510 			CU_ASSERT(control_new.value <= queryctrl.maximum);
511 			CU_ASSERT_EQUAL(control_new.value, control_orig.value);
512 		}
513 
514 	}
515 
516 	return ret_query;
517 }
518 
519 static void do_set_control_value(__u32 id, __s32 value,
520 				 struct v4l2_queryctrl *queryctrl);
do_set_control_value(__u32 id,__s32 value,struct v4l2_queryctrl * queryctrl)521 static void do_set_control_value(__u32 id, __s32 value,
522 				 struct v4l2_queryctrl *queryctrl)
523 {
524 	int ret_set, errno_set;
525 	int ret_get, errno_get;
526 	struct v4l2_control control;
527 	struct v4l2_control control_new;
528 
529 	memset(&control, 0xff, sizeof(control));
530 	control.id = id;
531 	control.value = value;
532 	ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
533 	errno_set = errno;
534 
535 	dprintf
536 	    ("\t%s:%u: VIDIOC_S_CTRL, id=%u (V4L2_CID_BASE+%i), value=%i, ret_set=%i, errno_set=%i\n",
537 	     __FILE__, __LINE__, id, id - V4L2_CID_BASE, value, ret_set,
538 	     errno_set);
539 
540 	/* The driver can decide if it returns ERANGE or
541 	 * accepts the value and converts it to
542 	 * the nearest limit
543 	 */
544 	if (ret_set == -1) {
545 		CU_ASSERT_EQUAL(ret_set, -1);
546 		if (!(queryctrl->flags & V4L2_CTRL_FLAG_DISABLED) &&
547 		    !(queryctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)) {
548 			CU_ASSERT_EQUAL(errno_set, ERANGE);
549 		} else {
550 			CU_ASSERT_EQUAL(errno_set, EINVAL);
551 		}
552 
553 		/* check whether the new value is not out of bounds */
554 		memset(&control_new, 0, sizeof(control_new));
555 		control_new.id = id;
556 		ret_get = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control_new);
557 		errno_get = errno;
558 
559 		dprintf
560 		    ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i, control_new.value=%i\n",
561 		     __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get,
562 		     errno_get, control_new.value);
563 
564 		CU_ASSERT_EQUAL(ret_get, 0);
565 		if (ret_get == 0) {
566 			CU_ASSERT(queryctrl->minimum <= control_new.value);
567 			CU_ASSERT(control_new.value <= queryctrl->maximum);
568 		}
569 
570 	} else {
571 		CU_ASSERT_EQUAL(ret_set, 0);
572 
573 		/* check whether the new value is not out of bounds */
574 		memset(&control_new, 0, sizeof(control_new));
575 		control_new.id = id;
576 		ret_get = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control_new);
577 		errno_get = errno;
578 
579 		dprintf
580 		    ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i, control_new.value=%i\n",
581 		     __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get,
582 		     errno_get, control_new.value);
583 
584 		CU_ASSERT_EQUAL(ret_get, 0);
585 		if (ret_get == 0) {
586 			CU_ASSERT(queryctrl->minimum <= control_new.value);
587 			CU_ASSERT(control_new.value <= queryctrl->maximum);
588 			CU_ASSERT_EQUAL(control_new.value, queryctrl->minimum);
589 		}
590 	}
591 }
592 
do_set_control_invalid(__u32 id)593 int do_set_control_invalid(__u32 id)
594 {
595 	int ret_query, errno_query;
596 	int ret_set, errno_set;
597 	int ret_get, errno_get;
598 	int ret_orig, errno_orig;
599 	struct v4l2_queryctrl queryctrl;
600 	struct v4l2_control control_orig;
601 	struct v4l2_control control;
602 	struct v4l2_control control_new;
603 	__s32 value;
604 
605 	/* The expected return value of VIDIOC_S_CTRL depens on the value
606 	 * reported by VIDIOC_QUERYCTRL. The allowed limits are also
607 	 * reported by VIDIOC_QUERYCTRL.
608 	 */
609 
610 	memset(&queryctrl, 0, sizeof(queryctrl));
611 	queryctrl.id = id;
612 	ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl);
613 	errno_query = errno;
614 
615 	dprintf
616 	    ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n",
617 	     __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_query,
618 	     errno_query);
619 	if (ret_query == 0) {
620 		dprintf("\t%s:%u: queryctrl = {.id=%u, .type=%i, .name=\"%s\", "
621 			".minimum=%i, .maximum=%i, .step=%i, "
622 			".default_value=%i, "
623 			".flags=0x%X, "
624 			".reserved[]={ 0x%X, 0x%X } }\n",
625 			__FILE__, __LINE__,
626 			queryctrl.id,
627 			queryctrl.type,
628 			queryctrl.name,
629 			queryctrl.minimum,
630 			queryctrl.maximum,
631 			queryctrl.step,
632 			queryctrl.default_value,
633 			queryctrl.flags,
634 			queryctrl.reserved[0], queryctrl.reserved[1]
635 		    );
636 	}
637 
638 	memset(&control_orig, 0, sizeof(control_orig));
639 	control_orig.id = id;
640 	ret_orig = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control_orig);
641 	errno_orig = errno;
642 
643 	dprintf
644 	    ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_orig=%i, errno_orig=%i, control_orig.value=%i\n",
645 	     __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_orig, errno_orig,
646 	     control_orig.value);
647 
648 	if (ret_query == 0) {
649 		CU_ASSERT_EQUAL(ret_query, 0);
650 
651 		switch (queryctrl.type) {
652 		case V4L2_CTRL_TYPE_INTEGER:
653 		case V4L2_CTRL_TYPE_BOOLEAN:
654 		case V4L2_CTRL_TYPE_MENU:
655 			if (S32_MIN < queryctrl.minimum) {
656 				do_set_control_value(id, S32_MIN, &queryctrl);
657 			}
658 
659 			if (S32_MIN < queryctrl.minimum) {
660 				do_set_control_value(id, queryctrl.minimum - 1,
661 						     &queryctrl);
662 			}
663 
664 			if (S16_MIN < queryctrl.minimum) {
665 				do_set_control_value(id, S16_MIN, &queryctrl);
666 			}
667 
668 			if (U16_MIN < queryctrl.minimum) {
669 				do_set_control_value(id, U16_MIN, &queryctrl);
670 			}
671 
672 			if (queryctrl.maximum < S16_MAX) {
673 				do_set_control_value(id, S16_MAX, &queryctrl);
674 			}
675 
676 			if (queryctrl.maximum < (__s32) U16_MAX) {
677 				do_set_control_value(id, (__s32) U16_MAX,
678 						     &queryctrl);
679 			}
680 
681 			if (queryctrl.maximum < S32_MAX) {
682 				do_set_control_value(id, queryctrl.maximum + 1,
683 						     &queryctrl);
684 			}
685 
686 			if (queryctrl.maximum < S32_MAX) {
687 				do_set_control_value(id, S32_MAX, &queryctrl);
688 			}
689 
690 			break;
691 
692 		case V4L2_CTRL_TYPE_BUTTON:
693 			/* This control only performs an action, does not have
694 			 * any value
695 			 */
696 			CU_ASSERT_EQUAL(ret_orig, -1);
697 			CU_ASSERT_EQUAL(errno_orig, EINVAL);
698 
699 			/* there is no invalid value for button control */
700 
701 			break;
702 
703 		case V4L2_CTRL_TYPE_INTEGER64:	/* TODO: what about this case? */
704 		case V4L2_CTRL_TYPE_CTRL_CLASS:
705 		default:
706 			CU_ASSERT_EQUAL(ret_orig, -1);
707 			CU_ASSERT_EQUAL(errno_orig, -1);
708 		}
709 	} else {
710 		CU_ASSERT_EQUAL(ret_query, -1);
711 		CU_ASSERT_EQUAL(errno_query, EINVAL);
712 
713 		CU_ASSERT_EQUAL(ret_orig, -1);
714 		CU_ASSERT_EQUAL(errno_orig, EINVAL);
715 
716 		memset(&control, 0xff, sizeof(control));
717 		control.id = id;
718 		control.value = S32_MIN;
719 		ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
720 		errno_set = errno;
721 
722 		CU_ASSERT_EQUAL(ret_set, -1);
723 		CU_ASSERT_EQUAL(errno_set, EINVAL);
724 
725 		memset(&control, 0xff, sizeof(control));
726 		control.id = id;
727 		control.value = -1;
728 		ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
729 		errno_set = errno;
730 
731 		CU_ASSERT_EQUAL(ret_set, -1);
732 		CU_ASSERT_EQUAL(errno_set, EINVAL);
733 
734 		memset(&control, 0xff, sizeof(control));
735 		control.id = id;
736 		control.value = 0;
737 		ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
738 		errno_set = errno;
739 
740 		CU_ASSERT_EQUAL(ret_set, -1);
741 		CU_ASSERT_EQUAL(errno_set, EINVAL);
742 
743 		memset(&control, 0xff, sizeof(control));
744 		control.id = id;
745 		control.value = 1;
746 		ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
747 		errno_set = errno;
748 
749 		CU_ASSERT_EQUAL(ret_set, -1);
750 		CU_ASSERT_EQUAL(errno_set, EINVAL);
751 
752 		memset(&control, 0xff, sizeof(control));
753 		control.id = id;
754 		control.value = S32_MAX;
755 		ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
756 		errno_set = errno;
757 
758 		CU_ASSERT_EQUAL(ret_set, -1);
759 		CU_ASSERT_EQUAL(errno_set, EINVAL);
760 
761 	}
762 
763 	if (ret_orig == 0) {
764 		CU_ASSERT_EQUAL(ret_orig, 0);
765 
766 		/* restore the original control value */
767 		value = control_orig.value;
768 		memset(&control, 0xff, sizeof(control));
769 		control.id = id;
770 		control.value = value;
771 		ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control);
772 		errno_set = errno;
773 
774 		dprintf
775 		    ("\t%s:%u: VIDIOC_S_CTRL, id=%u (V4L2_CID_BASE+%i), value=%i, ret_set=%i, errno_set=%i\n",
776 		     __FILE__, __LINE__, id, id - V4L2_CID_BASE, value, ret_set,
777 		     errno_set);
778 
779 		/* it shall be possible to set to the original value if the control
780 		 * is not disabled, read only or grabbed by other application
781 		 */
782 		if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED ||
783 		    queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
784 			CU_ASSERT_EQUAL(ret_set, -1);
785 			CU_ASSERT_EQUAL(errno_set, EINVAL);
786 		} else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) {
787 			CU_ASSERT_EQUAL(ret_set, -1);
788 			CU_ASSERT_EQUAL(errno_set, EBUSY);
789 		} else {
790 			CU_ASSERT_EQUAL(ret_set, 0);
791 		}
792 
793 		memset(&control_new, 0, sizeof(control_new));
794 		control_new.id = id;
795 		ret_get = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control_new);
796 		errno_get = errno;
797 
798 		dprintf
799 		    ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i, control_new.value=%i\n",
800 		     __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get,
801 		     errno_get, control_new.value);
802 
803 		CU_ASSERT_EQUAL(ret_get, 0);
804 		if (ret_get == 0) {
805 			CU_ASSERT(queryctrl.minimum <= control_new.value);
806 			CU_ASSERT(control_new.value <= queryctrl.maximum);
807 			CU_ASSERT_EQUAL(control_new.value, control_orig.value);
808 		}
809 
810 	}
811 
812 	return ret_query;
813 }
814 
test_VIDIOC_S_CTRL()815 void test_VIDIOC_S_CTRL()
816 {
817 	int ret1;
818 	__u32 i;
819 
820 	for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) {
821 		if (i != V4L2_CID_AUTO_WHITE_BALANCE &&
822 		    i != V4L2_CID_DO_WHITE_BALANCE &&
823 		    i != V4L2_CID_RED_BALANCE &&
824 		    i != V4L2_CID_BLUE_BALANCE &&
825 		    i != V4L2_CID_AUTOGAIN && i != V4L2_CID_GAIN)
826 			ret1 = do_set_control(i);
827 	}
828 
829 	ret1 = do_set_control(V4L2_CID_BASE - 1);
830 	ret1 = do_set_control(V4L2_CID_LASTP1);
831 	ret1 = do_set_control(V4L2_CID_PRIVATE_BASE - 1);
832 
833 	i = V4L2_CID_PRIVATE_BASE;
834 	do {
835 		ret1 = do_set_control(i);
836 		i++;
837 	} while (ret1 == 0);
838 
839 	ret1 = do_set_control(i);
840 }
841 
test_VIDIOC_S_CTRL_invalid()842 void test_VIDIOC_S_CTRL_invalid()
843 {
844 	int ret1;
845 	__u32 i;
846 
847 	for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) {
848 		if (i != V4L2_CID_AUTO_WHITE_BALANCE &&
849 		    i != V4L2_CID_DO_WHITE_BALANCE &&
850 		    i != V4L2_CID_RED_BALANCE &&
851 		    i != V4L2_CID_BLUE_BALANCE &&
852 		    i != V4L2_CID_AUTOGAIN && i != V4L2_CID_GAIN)
853 			ret1 = do_set_control_invalid(i);
854 	}
855 
856 	ret1 = do_set_control_invalid(V4L2_CID_BASE - 1);
857 	ret1 = do_set_control_invalid(V4L2_CID_LASTP1);
858 	ret1 = do_set_control_invalid(V4L2_CID_PRIVATE_BASE - 1);
859 
860 	i = V4L2_CID_PRIVATE_BASE;
861 	do {
862 		ret1 = do_set_control_invalid(i);
863 		i++;
864 	} while (ret1 == 0);
865 
866 	ret1 = do_set_control_invalid(i);
867 }
868 
test_VIDIOC_S_CTRL_white_balance()869 void test_VIDIOC_S_CTRL_white_balance()
870 {
871 	int ret1;
872 
873 	/* TODO: handle V4L2_CID_AUTO_WHITE_BALANCE activated and deactivated separately */
874 	ret1 = do_set_control(V4L2_CID_AUTO_WHITE_BALANCE);
875 	ret1 = do_set_control(V4L2_CID_DO_WHITE_BALANCE);
876 	ret1 = do_set_control(V4L2_CID_RED_BALANCE);
877 	ret1 = do_set_control(V4L2_CID_BLUE_BALANCE);
878 }
879 
test_VIDIOC_S_CTRL_white_balance_invalid()880 void test_VIDIOC_S_CTRL_white_balance_invalid()
881 {
882 	int ret1;
883 
884 	/* TODO: handle V4L2_CID_AUTO_WHITE_BALANCE activated and deactivated separately */
885 	ret1 = do_set_control_invalid(V4L2_CID_AUTO_WHITE_BALANCE);
886 	ret1 = do_set_control_invalid(V4L2_CID_DO_WHITE_BALANCE);
887 	ret1 = do_set_control_invalid(V4L2_CID_RED_BALANCE);
888 	ret1 = do_set_control_invalid(V4L2_CID_BLUE_BALANCE);
889 }
890 
test_VIDIOC_S_CTRL_gain()891 void test_VIDIOC_S_CTRL_gain()
892 {
893 	int ret1;
894 
895 	/* TODO: handle V4L2_CID_AUTOGAIN activated and deactivated separately */
896 	ret1 = do_set_control(V4L2_CID_AUTOGAIN);
897 	ret1 = do_set_control(V4L2_CID_GAIN);
898 }
899 
test_VIDIOC_S_CTRL_gain_invalid()900 void test_VIDIOC_S_CTRL_gain_invalid()
901 {
902 	int ret1;
903 
904 	/* TODO: handle V4L2_CID_AUTOGAIN activated and deactivated separately */
905 	ret1 = do_set_control_invalid(V4L2_CID_AUTOGAIN);
906 	ret1 = do_set_control_invalid(V4L2_CID_GAIN);
907 }
908 
test_VIDIOC_S_CTRL_NULL()909 void test_VIDIOC_S_CTRL_NULL()
910 {
911 	int ret_null, errno_null;
912 
913 	/* TODO: check whether VIDIOC_S_CTRL is supported or not */
914 
915 	ret_null = ioctl(get_video_fd(), VIDIOC_S_CTRL, NULL);
916 	errno_null = errno;
917 
918 	dprintf("\t%s:%u: VIDIOC_S_CTRL, ret_null=%i, errno_null=%i\n",
919 		__FILE__, __LINE__, ret_null, errno_null);
920 
921 	CU_ASSERT_EQUAL(ret_null, -1);
922 	CU_ASSERT_EQUAL(errno_null, EFAULT);
923 
924 }
925