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 | |