1 // SPDX-License-Identifier: GPL-2.0
2 
3 /*
4  * video_device_test - Video Device Test
5  *
6  * Copyright (c) 2016 Shuah Khan <shuahkh@osg.samsung.com>
7  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
8  *
9  */
10 
11 /*
12  * This file adds a test for Video Device. This test should not be included
13  * in the Kselftest run. This test should be run when hardware and driver
14  * that makes use of V4L2 API is present.
15  *
16  * This test opens user specified Video Device and calls video ioctls in a
17  * loop once every 10 seconds.
18  *
19  * Usage:
20  *	sudo ./video_device_test -d /dev/videoX
21  *
22  *	While test is running, remove the device or unbind the driver and
23  *	ensure there are no use after free errors and other Oops in the
24  *	dmesg.
25  *	When possible, enable KaSan kernel config option for use-after-free
26  *	error detection.
27 */
28 
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <sys/ioctl.h>
36 #include <sys/stat.h>
37 #include <time.h>
38 #include <linux/videodev2.h>
39 
40 #define PRIORITY_MAX 4
41 
42 int priority_test(int fd)
43 {
44 	/* This test will try to update the priority associated with a file descriptor */
45 
46 	enum v4l2_priority old_priority, new_priority, priority_to_compare;
47 	int ret;
48 	int result = 0;
49 
50 	ret = ioctl(fd, VIDIOC_G_PRIORITY, &old_priority);
51 	if (ret < 0) {
52 		printf("Failed to get priority: %s\n", strerror(errno));
53 		return -1;
54 	}
55 	new_priority = (old_priority + 1) % PRIORITY_MAX;
56 	ret = ioctl(fd, VIDIOC_S_PRIORITY, &new_priority);
57 	if (ret < 0) {
58 		printf("Failed to set priority: %s\n", strerror(errno));
59 		return -1;
60 	}
61 	ret = ioctl(fd, VIDIOC_G_PRIORITY, &priority_to_compare);
62 	if (ret < 0) {
63 		printf("Failed to get new priority: %s\n", strerror(errno));
64 		result = -1;
65 		goto cleanup;
66 	}
67 	if (priority_to_compare != new_priority) {
68 		printf("Priority wasn't set - test failed\n");
69 		result = -1;
70 	}
71 
72 cleanup:
73 	ret = ioctl(fd, VIDIOC_S_PRIORITY, &old_priority);
74 	if (ret < 0) {
75 		printf("Failed to restore priority: %s\n", strerror(errno));
76 		return -1;
77 	}
78 	return result;
79 }
80 
81 int loop_test(int fd)
82 {
83 	int count;
84 	struct v4l2_tuner vtuner;
85 	struct v4l2_capability vcap;
86 	int ret;
87 
88 	/* Generate random number of interations */
89 	srand((unsigned int) time(NULL));
90 	count = rand();
91 
92 	printf("\nNote:\n"
93 	       "While test is running, remove the device or unbind\n"
94 	       "driver and ensure there are no use after free errors\n"
95 	       "and other Oops in the dmesg. When possible, enable KaSan\n"
96 	       "kernel config option for use-after-free error detection.\n\n");
97 
98 	while (count > 0) {
99 		ret = ioctl(fd, VIDIOC_QUERYCAP, &vcap);
100 		if (ret < 0)
101 			printf("VIDIOC_QUERYCAP errno %s\n", strerror(errno));
102 		else
103 			printf("Video device driver %s\n", vcap.driver);
104 
105 		ret = ioctl(fd, VIDIOC_G_TUNER, &vtuner);
106 		if (ret < 0)
107 			printf("VIDIOC_G_TUNER, errno %s\n", strerror(errno));
108 		else
109 			printf("type %d rangelow %d rangehigh %d\n",
110 				vtuner.type, vtuner.rangelow, vtuner.rangehigh);
111 		sleep(10);
112 		count--;
113 	}
114 	return 0;
115 }
116 
117 int main(int argc, char **argv)
118 {
119 	int opt;
120 	char video_dev[256];
121 	int fd;
122 	int test_result;
123 
124 	if (argc < 2) {
125 		printf("Usage: %s [-d </dev/videoX>]\n", argv[0]);
126 		exit(-1);
127 	}
128 
129 	/* Process arguments */
130 	while ((opt = getopt(argc, argv, "d:")) != -1) {
131 		switch (opt) {
132 		case 'd':
133 			strncpy(video_dev, optarg, sizeof(video_dev) - 1);
134 			video_dev[sizeof(video_dev)-1] = '\0';
135 			break;
136 		default:
137 			printf("Usage: %s [-d </dev/videoX>]\n", argv[0]);
138 			exit(-1);
139 		}
140 	}
141 
142 	/* Open Video device and keep it open */
143 	fd = open(video_dev, O_RDWR);
144 	if (fd == -1) {
145 		printf("Video Device open errno %s\n", strerror(errno));
146 		exit(-1);
147 	}
148 
149 	test_result = priority_test(fd);
150 	if (!test_result)
151 		printf("Priority test - PASSED\n");
152 	else
153 		printf("Priority test - FAILED\n");
154 
155 	loop_test(fd);
156 }
157