Home | History | Annotate | Download | only in user_space
      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 Mrton Nmeth <nm127 (at) 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 
     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 
    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 
    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 
    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);
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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