1 /*
2  * v4l-test: Test environment for Video For Linux Two API
3  *
4  *  5 Jul 2009  0.9  Iterate through all possible inputs
5  * 18 Apr 2009  0.8  Typo corrected
6  * 27 Mar 2009  0.7  Cleanup ret and errno variable names and dprintf() outputs;
7  *                   Make VIDIOC_S_STD tests independent from VIDIOC_G_STD
8  *  9 Feb 2009  0.6  Modify test cases to support drivers without any inputs;
9  *                   cleanup debug printouts
10  * 30 Jan 2009  0.5  valid_v4l2_std_id() moved to v4l2_validator.c
11  * 18 Jan 2009  0.4  Typo corrected
12  * 23 Dec 2008  0.3  Debug messages added
13  * 22 Dec 2008  0.2  Test case with NULL parameter added
14  * 18 Dec 2008  0.1  First release
15  *
16  * Written by M�rton N�meth <nm127@freemail.hu>
17  * Released under GPL
18  */
19 
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <sys/ioctl.h>
26 #include <errno.h>
27 #include <string.h>
28 
29 #include <linux/videodev2.h>
30 #include <linux/errno.h>
31 
32 #include <CUnit/CUnit.h>
33 
34 #include "v4l2_test.h"
35 #include "dev_video.h"
36 #include "video_limits.h"
37 #include "v4l2_validator.h"
38 #include "v4l2_foreach.h"
39 
40 #include "test_VIDIOC_STD.h"
41 
do_test_VIDIOC_G_STD(int ret_input_enum,int errno_input_enum,struct v4l2_input * input)42 static void do_test_VIDIOC_G_STD(int ret_input_enum, int errno_input_enum,
43 				 struct v4l2_input *input)
44 {
45 	v4l2_std_id std_id;
46 	int ret_std_get, errno_std_get;
47 	int f;
48 
49 	/* Iterate trough all inputs with VIDIOC_ENUMINPUT.
50 	 * Also ensure tahat VIDIC_G_STD is called at least
51 	 * once even if VIDIOC_ENUMINPUT always return EINVAL.
52 	 *
53 	 * V4L2 API specification rev. 0.24, Chapter 1.7.
54 	 * "Video Standards" specifies if the std field
55 	 * of v4l2_input or v4l2_output is zero when
56 	 * executing VIDIOC_ENUMINPUT or VIDIOC_ENUMOUTPUT,
57 	 * respectively, then VIDIOC_G_STD shall always
58 	 * return EINVAL.
59 	 */
60 
61 	/* TODO: Iterate trough all outputs VIDIOC_ENUMOUTPUT.
62 	 * Also ensure tahat VIDIC_G_STD is called at least
63 	 * once even if VIDIOC_ENUMOUTPUT always return EINVAL.
64 	 *
65 	 * TODO: What shall happen when changing output? The
66 	 * VIDIOC_G_STD only deals with current input.
67 	 */
68 
69 	f = get_video_fd();
70 
71 	memset(&std_id, 0xff, sizeof(std_id));
72 	ret_std_get = ioctl(f, VIDIOC_G_STD, &std_id);
73 	errno_std_get = errno;
74 
75 	dprintf
76 	    ("\t%s:%u: VIDIOC_G_STD, ret_std_get=%i, errno_std_get=%i, std_id=0x%llX\n",
77 	     __FILE__, __LINE__, ret_std_get, errno_std_get, std_id);
78 
79 	if (ret_input_enum == 0) {
80 		CU_ASSERT_EQUAL(ret_input_enum, 0);
81 		if (input->std == 0) {
82 			CU_ASSERT_EQUAL(ret_std_get, -1);
83 			CU_ASSERT_EQUAL(errno_std_get, EINVAL);
84 		} else {
85 			if (ret_std_get == 0) {
86 				CU_ASSERT_EQUAL(ret_std_get, 0);
87 				CU_ASSERT(valid_v4l2_std_id(std_id));
88 			} else {
89 				CU_ASSERT_EQUAL(ret_std_get, -1);
90 				CU_ASSERT_EQUAL(errno_std_get, EINVAL);
91 			}
92 		}
93 	} else {
94 		CU_ASSERT_EQUAL(ret_input_enum, -1);
95 		CU_ASSERT_EQUAL(errno_input_enum, EINVAL);
96 		if (ret_std_get == 0) {
97 			CU_ASSERT_EQUAL(ret_std_get, 0);
98 			CU_ASSERT(valid_v4l2_std_id(std_id));
99 		} else {
100 			CU_ASSERT_EQUAL(ret_std_get, -1);
101 			CU_ASSERT_EQUAL(errno_std_get, EINVAL);
102 		}
103 	}
104 }
105 
test_VIDIOC_G_STD()106 void test_VIDIOC_G_STD()
107 {
108 
109 	/* Iterate trough all inputs with VIDIOC_ENUMINPUT.
110 	 * Also ensure tahat VIDIC_G_STD is called at least
111 	 * once even if VIDIOC_ENUMINPUT always return EINVAL.
112 	 *
113 	 * V4L2 API specification rev. 0.24, Chapter 1.7.
114 	 * "Video Standards" specifies if the std field
115 	 * of v4l2_input or v4l2_output is zero when
116 	 * executing VIDIOC_ENUMINPUT or VIDIOC_ENUMOUTPUT,
117 	 * respectively, then VIDIOC_G_STD shall always
118 	 * return EINVAL.
119 	 */
120 
121 	foreach_input(do_test_VIDIOC_G_STD);
122 
123 	/* TODO: Iterate trough all outputs VIDIOC_ENUMOUTPUT.
124 	 * Also ensure tahat VIDIC_G_STD is called at least
125 	 * once even if VIDIOC_ENUMOUTPUT always return EINVAL.
126 	 *
127 	 * TODO: What shall happen when changing output? The
128 	 * VIDIOC_G_STD only deals with current input.
129 	 */
130 
131 }
132 
do_set_video_standard(int f,v4l2_std_id id,int ret_input_enum,int errno_input_enum,struct v4l2_input * input)133 static int do_set_video_standard(int f, v4l2_std_id id,
134 				 int ret_input_enum, int errno_input_enum,
135 				 struct v4l2_input *input)
136 {
137 	int ret_std_set, errno_std_set;
138 	int ret_std_get, errno_std_get;
139 	v4l2_std_id std_id;
140 
141 	std_id = id;
142 	ret_std_set = ioctl(f, VIDIOC_S_STD, &std_id);
143 	errno_std_set = errno;
144 
145 	dprintf
146 	    ("\t%s:%u: VIDIOC_S_STD: ret_std_set=%i, errno_std_set=%i, std_id=0x%llX, id=0x%llX\n",
147 	     __FILE__, __LINE__, ret_std_set, errno_std_set, std_id, id);
148 
149 	memset(&std_id, 0xff, sizeof(std_id));
150 	ret_std_get = ioctl(f, VIDIOC_G_STD, &std_id);
151 	errno_std_get = errno;
152 
153 	dprintf
154 	    ("\t%s:%u: VIDIOC_G_STD: ret_std_get=%i, errno_std_get=%i, std_id=0x%llX\n",
155 	     __FILE__, __LINE__, ret_std_get, errno_std_get, std_id);
156 
157 	if (ret_input_enum == 0) {
158 		CU_ASSERT_EQUAL(ret_input_enum, 0);
159 		if (input->std == 0) {
160 			CU_ASSERT_EQUAL(ret_std_get, -1);
161 			CU_ASSERT_EQUAL(errno_std_get, EINVAL);
162 			CU_ASSERT_EQUAL(ret_std_set, -1);
163 			CU_ASSERT_EQUAL(errno_std_set, EINVAL);
164 		} else {
165 			if (ret_std_set == 0) {
166 				CU_ASSERT_EQUAL(ret_std_set, 0);
167 				CU_ASSERT_EQUAL(ret_std_get, 0);
168 				CU_ASSERT(valid_v4l2_std_id(std_id));
169 			} else {
170 				CU_ASSERT_EQUAL(ret_std_set, -1);
171 				CU_ASSERT_EQUAL(errno_std_set, EINVAL);
172 			}
173 		}
174 	} else {
175 		CU_ASSERT_EQUAL(ret_input_enum, -1);
176 		CU_ASSERT_EQUAL(errno_input_enum, EINVAL);
177 		if (ret_std_set == 0) {
178 			CU_ASSERT_EQUAL(ret_std_set, 0);
179 			CU_ASSERT_EQUAL(ret_std_get, 0);
180 			CU_ASSERT(valid_v4l2_std_id(std_id));
181 		} else {
182 			CU_ASSERT_EQUAL(ret_std_set, -1);
183 			CU_ASSERT_EQUAL(errno_std_set, EINVAL);
184 		}
185 	}
186 
187 	return ret_std_set;
188 }
189 
do_test_VIDIOC_S_STD(int ret_input_enum,int errno_input_enum,struct v4l2_input * input)190 static void do_test_VIDIOC_S_STD(int ret_input_enum, int errno_input_enum,
191 				 struct v4l2_input *input)
192 {
193 	int ret_get, errno_get;
194 	int ret_set, errno_set;
195 	v4l2_std_id std_id_orig;
196 	int f;
197 
198 	f = get_video_fd();
199 
200 	memset(&std_id_orig, 0xff, sizeof(std_id_orig));
201 	ret_get = ioctl(f, VIDIOC_G_STD, &std_id_orig);
202 	errno_get = errno;
203 
204 	dprintf
205 	    ("\t%s:%u: VIDIOC_G_STD: ret_get=%i, errno_get=%i, std_id_orig=0x%llX\n",
206 	     __FILE__, __LINE__, ret_get, errno_get, std_id_orig);
207 
208 	ret_set =
209 	    do_set_video_standard(f, V4L2_STD_PAL_B, ret_input_enum,
210 				  errno_input_enum, input);
211 	ret_set =
212 	    do_set_video_standard(f, V4L2_STD_PAL_B1, ret_input_enum,
213 				  errno_input_enum, input);
214 	ret_set =
215 	    do_set_video_standard(f, V4L2_STD_PAL_G, ret_input_enum,
216 				  errno_input_enum, input);
217 	ret_set =
218 	    do_set_video_standard(f, V4L2_STD_PAL_H, ret_input_enum,
219 				  errno_input_enum, input);
220 	ret_set =
221 	    do_set_video_standard(f, V4L2_STD_PAL_I, ret_input_enum,
222 				  errno_input_enum, input);
223 	ret_set =
224 	    do_set_video_standard(f, V4L2_STD_PAL_D, ret_input_enum,
225 				  errno_input_enum, input);
226 	ret_set =
227 	    do_set_video_standard(f, V4L2_STD_PAL_D1, ret_input_enum,
228 				  errno_input_enum, input);
229 	ret_set =
230 	    do_set_video_standard(f, V4L2_STD_PAL_K, ret_input_enum,
231 				  errno_input_enum, input);
232 	ret_set =
233 	    do_set_video_standard(f, V4L2_STD_PAL_M, ret_input_enum,
234 				  errno_input_enum, input);
235 	ret_set =
236 	    do_set_video_standard(f, V4L2_STD_PAL_N, ret_input_enum,
237 				  errno_input_enum, input);
238 	ret_set =
239 	    do_set_video_standard(f, V4L2_STD_PAL_Nc, ret_input_enum,
240 				  errno_input_enum, input);
241 	ret_set =
242 	    do_set_video_standard(f, V4L2_STD_PAL_60, ret_input_enum,
243 				  errno_input_enum, input);
244 	ret_set =
245 	    do_set_video_standard(f, V4L2_STD_NTSC_M, ret_input_enum,
246 				  errno_input_enum, input);
247 	ret_set =
248 	    do_set_video_standard(f, V4L2_STD_NTSC_M_JP, ret_input_enum,
249 				  errno_input_enum, input);
250 	ret_set =
251 	    do_set_video_standard(f, V4L2_STD_NTSC_443, ret_input_enum,
252 				  errno_input_enum, input);
253 	ret_set =
254 	    do_set_video_standard(f, V4L2_STD_NTSC_M_KR, ret_input_enum,
255 				  errno_input_enum, input);
256 	ret_set =
257 	    do_set_video_standard(f, V4L2_STD_SECAM_B, ret_input_enum,
258 				  errno_input_enum, input);
259 	ret_set =
260 	    do_set_video_standard(f, V4L2_STD_SECAM_D, ret_input_enum,
261 				  errno_input_enum, input);
262 	ret_set =
263 	    do_set_video_standard(f, V4L2_STD_SECAM_G, ret_input_enum,
264 				  errno_input_enum, input);
265 	ret_set =
266 	    do_set_video_standard(f, V4L2_STD_SECAM_H, ret_input_enum,
267 				  errno_input_enum, input);
268 	ret_set =
269 	    do_set_video_standard(f, V4L2_STD_SECAM_K, ret_input_enum,
270 				  errno_input_enum, input);
271 	ret_set =
272 	    do_set_video_standard(f, V4L2_STD_SECAM_K1, ret_input_enum,
273 				  errno_input_enum, input);
274 	ret_set =
275 	    do_set_video_standard(f, V4L2_STD_SECAM_L, ret_input_enum,
276 				  errno_input_enum, input);
277 	ret_set =
278 	    do_set_video_standard(f, V4L2_STD_SECAM_LC, ret_input_enum,
279 				  errno_input_enum, input);
280 	ret_set =
281 	    do_set_video_standard(f, V4L2_STD_ATSC_8_VSB, ret_input_enum,
282 				  errno_input_enum, input);
283 	ret_set =
284 	    do_set_video_standard(f, V4L2_STD_ATSC_16_VSB, ret_input_enum,
285 				  errno_input_enum, input);
286 
287 	if (ret_get == 0) {
288 		CU_ASSERT_EQUAL(ret_get, 0);
289 		/* Setting the original std_id should not fail */
290 		ret_set =
291 		    do_set_video_standard(f, std_id_orig, ret_input_enum,
292 					  errno_input_enum, input);
293 		errno_set = errno;
294 
295 		CU_ASSERT_EQUAL(ret_set, 0);
296 	} else {
297 		CU_ASSERT_EQUAL(ret_get, -1);
298 		CU_ASSERT_EQUAL(errno_get, EINVAL);
299 	}
300 
301 }
302 
test_VIDIOC_S_STD()303 void test_VIDIOC_S_STD()
304 {
305 	foreach_input(do_test_VIDIOC_S_STD);
306 }
307 
do_test_VIDIOC_S_STD_from_enum(int ret_input_enum,int errno_input_enum,struct v4l2_input * input)308 static void do_test_VIDIOC_S_STD_from_enum(int ret_input_enum,
309 					   int errno_input_enum,
310 					   struct v4l2_input *input)
311 {
312 	int ret_get, errno_get;
313 	int ret_enum, errno_enum;
314 	int ret_set, errno_set;
315 	v4l2_std_id std_id_orig;
316 	struct v4l2_standard std;
317 	__u32 i;
318 	int f;
319 
320 	f = get_video_fd();
321 
322 	memset(&std_id_orig, 0xff, sizeof(std_id_orig));
323 	ret_get = ioctl(f, VIDIOC_G_STD, &std_id_orig);
324 	errno_get = errno;
325 
326 	dprintf
327 	    ("\t%s:%u: VIDIOC_G_STD: ret_get=%i, errno_get=%i, std_id_orig=0x%llX\n",
328 	     __FILE__, __LINE__, ret_get, errno_get, std_id_orig);
329 
330 	/* Try to continue even if VIDIOC_G_STD returned error */
331 	i = 0;
332 	do {
333 		memset(&std, 0xff, sizeof(std));
334 		std.index = i;
335 		ret_enum = ioctl(f, VIDIOC_ENUMSTD, &std);
336 		errno_enum = errno;
337 
338 		dprintf
339 		    ("\t%s:%u: VIDIOC_ENUMSTD: i=%u, ret_enum=%i, errno_enum=%i, std.id=0x%llX\n",
340 		     __FILE__, __LINE__, i, ret_enum, errno_enum, std.id);
341 
342 		if (ret_enum == 0) {
343 			ret_set =
344 			    do_set_video_standard(f, std.id, ret_input_enum,
345 						  errno_input_enum, input);
346 			CU_ASSERT_EQUAL(ret_set, 0);
347 		}
348 		i++;
349 	} while (ret_enum == 0 && i != 0);
350 
351 	if (ret_get == 0) {
352 		CU_ASSERT_EQUAL(ret_get, 0);
353 
354 		/* Setting the original std_id should not fail */
355 		ret_set =
356 		    do_set_video_standard(f, std_id_orig, ret_input_enum,
357 					  errno_input_enum, input);
358 		errno_set = errno;
359 		dprintf
360 		    ("\t%s:%u: VIDIOC_S_STD: ret_set=%i (expected %i), errno=%i\n",
361 		     __FILE__, __LINE__, ret_set, 0, errno);
362 		CU_ASSERT_EQUAL(ret_set, 0);
363 	} else {
364 		CU_ASSERT_EQUAL(ret_get, -1);
365 		CU_ASSERT_EQUAL(errno_get, EINVAL);
366 	}
367 
368 }
369 
test_VIDIOC_S_STD_from_enum()370 void test_VIDIOC_S_STD_from_enum()
371 {
372 	foreach_input(do_test_VIDIOC_S_STD_from_enum);
373 }
374 
do_test_VIDIOC_S_STD_invalid_standard(int ret_input_enum,int errno_input_enum,struct v4l2_input * input)375 static void do_test_VIDIOC_S_STD_invalid_standard(int ret_input_enum,
376 						  int errno_input_enum,
377 						  struct v4l2_input *input)
378 {
379 	int ret_get, errno_get;
380 	int ret_set, errno_set;
381 	v4l2_std_id std_id_orig;
382 	v4l2_std_id std_id;
383 	int f;
384 
385 	f = get_video_fd();
386 
387 	memset(&std_id_orig, 0xff, sizeof(std_id_orig));
388 	ret_get = ioctl(f, VIDIOC_G_STD, &std_id_orig);
389 	errno_get = errno;
390 
391 	dprintf
392 	    ("\t%s:%u: VIDIOC_G_STD: ret_get=%i, errno_get=%i, std_id_orig=0x%llX\n",
393 	     __FILE__, __LINE__, ret_get, errno_get, std_id_orig);
394 
395 	/* Try to continue even if VIDIOC_G_STD retunred with error */
396 	std_id = 1;
397 	while (std_id != 0) {
398 		if (!valid_v4l2_std_id(std_id)) {
399 			ret_set =
400 			    do_set_video_standard(f, std_id, ret_input_enum,
401 						  errno_input_enum, input);
402 			errno_set = errno;
403 
404 			CU_ASSERT_EQUAL(ret_set, -1);
405 			CU_ASSERT_EQUAL(errno_set, EINVAL);
406 			dprintf
407 			    ("\t%s:%u: VIDIOC_S_STD: ret_set=%i, errno_set=%i\n",
408 			     __FILE__, __LINE__, ret_set, errno_set);
409 		}
410 		std_id = std_id << 1;
411 	}
412 
413 	if (ret_get == 0) {
414 		CU_ASSERT_EQUAL(ret_get, 0);
415 
416 		/* Setting the original std_id should not fail */
417 		ret_set =
418 		    do_set_video_standard(f, std_id_orig, ret_input_enum,
419 					  errno_input_enum, input);
420 		errno_set = errno;
421 
422 		dprintf
423 		    ("\t%s:%u: VIDIOC_S_STD: ret_set=%i (expected 0), errno=%i\n",
424 		     __FILE__, __LINE__, ret_set, errno_set);
425 		CU_ASSERT_EQUAL(ret_set, 0);
426 	} else {
427 		CU_ASSERT_EQUAL(ret_get, -1);
428 		CU_ASSERT_EQUAL(errno_get, EINVAL);
429 	}
430 }
431 
test_VIDIOC_S_STD_invalid_standard()432 void test_VIDIOC_S_STD_invalid_standard()
433 {
434 	foreach_input(do_test_VIDIOC_S_STD_invalid_standard);
435 }
436 
do_test_VIDIOC_G_STD_NULL(int ret_input_enum,int errno_input_enum,struct v4l2_input * input)437 static void do_test_VIDIOC_G_STD_NULL(int ret_input_enum, int errno_input_enum,
438 				      struct v4l2_input *input)
439 {
440 	int ret_get, errno_get;
441 	int ret_null, errno_null;
442 	v4l2_std_id std_id;
443 
444 	memset(&std_id, 0, sizeof(std_id));
445 	ret_get = ioctl(get_video_fd(), VIDIOC_G_STD, &std_id);
446 	errno_get = errno;
447 
448 	dprintf("\t%s:%u: VIDIOC_G_STD, ret_get=%i, errno_get=%i\n",
449 		__FILE__, __LINE__, ret_get, errno_get);
450 
451 	ret_null = ioctl(get_video_fd(), VIDIOC_G_STD, NULL);
452 	errno_null = errno;
453 
454 	dprintf("\t%s:%u: VIDIOC_G_STD: ret_null=%i, errno_null=%i\n",
455 		__FILE__, __LINE__, ret_null, errno_null);
456 
457 	if (ret_input_enum == 0) {
458 		CU_ASSERT_EQUAL(ret_input_enum, 0);
459 		if (input->std == 0) {
460 			CU_ASSERT_EQUAL(ret_get, -1);
461 			CU_ASSERT_EQUAL(errno_get, EINVAL);
462 			CU_ASSERT_EQUAL(ret_null, -1);
463 			CU_ASSERT_EQUAL(errno_null, EINVAL);
464 		} else {
465 			if (ret_get == 0) {
466 				CU_ASSERT_EQUAL(ret_get, 0);
467 				CU_ASSERT_EQUAL(ret_null, -1);
468 				CU_ASSERT_EQUAL(errno_null, EFAULT);
469 			} else {
470 				CU_ASSERT_EQUAL(ret_get, -1);
471 				CU_ASSERT_EQUAL(errno_get, EINVAL);
472 				CU_ASSERT_EQUAL(ret_null, -1);
473 				CU_ASSERT_EQUAL(errno_null, EINVAL);
474 			}
475 		}
476 	} else {
477 		CU_ASSERT_EQUAL(ret_input_enum, -1);
478 		CU_ASSERT_EQUAL(errno_input_enum, EINVAL);
479 		if (ret_get == 0) {
480 			CU_ASSERT_EQUAL(ret_get, 0);
481 			CU_ASSERT_EQUAL(ret_null, -1);
482 			CU_ASSERT_EQUAL(errno_null, EFAULT);
483 		} else {
484 			CU_ASSERT_EQUAL(ret_get, -1);
485 			CU_ASSERT_EQUAL(errno_get, EINVAL);
486 			CU_ASSERT_EQUAL(ret_null, -1);
487 			CU_ASSERT_EQUAL(errno_null, EINVAL);
488 		}
489 	}
490 
491 }
492 
test_VIDIOC_G_STD_NULL()493 void test_VIDIOC_G_STD_NULL()
494 {
495 	foreach_input(do_test_VIDIOC_G_STD_NULL);
496 }
497 
do_test_VIDIOC_S_STD_NULL(int ret_input_enum,int errno_input_enum,struct v4l2_input * input)498 static void do_test_VIDIOC_S_STD_NULL(int ret_input_enum, int errno_input_enum,
499 				      struct v4l2_input *input)
500 {
501 	int ret_null, errno_null;
502 
503 	/* TODO: check whether VIDIOC_S_STD is supported at all or not */
504 
505 	ret_null = ioctl(get_video_fd(), VIDIOC_S_STD, NULL);
506 	errno_null = errno;
507 
508 	dprintf("\t%s:%u: VIDIOC_S_STD: ret_null=%i, errno_null=%i\n",
509 		__FILE__, __LINE__, ret_null, errno_null);
510 
511 	if (ret_input_enum == 0) {
512 		CU_ASSERT_EQUAL(ret_input_enum, 0);
513 		if (input->std == 0) {
514 			CU_ASSERT_EQUAL(ret_null, -1);
515 			CU_ASSERT_EQUAL(errno_null, EINVAL);
516 		} else {
517 		}
518 	} else {
519 		CU_ASSERT_EQUAL(ret_input_enum, -1);
520 		CU_ASSERT_EQUAL(errno_input_enum, EINVAL);
521 		CU_ASSERT_EQUAL(ret_null, -1);
522 		CU_ASSERT_EQUAL(errno_null, EFAULT);
523 	}
524 }
525 
test_VIDIOC_S_STD_NULL()526 void test_VIDIOC_S_STD_NULL()
527 {
528 	foreach_input(do_test_VIDIOC_S_STD_NULL);
529 }
530 
531 /* TODO: VIDIOC_S_STD while STREAM_ON */
532