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
34static 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
122void 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
144void 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
183int 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
519static void do_set_control_value(__u32 id, __s32 value,
520				 struct v4l2_queryctrl *queryctrl);
521static 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
593int 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
815void 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
842void 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
869void 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
880void 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
891void 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
900void 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
909void 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