• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     V4L2 API compliance input/output configuration ioctl tests.
3 
4     Copyright (C) 2011  Hans Verkuil <hverkuil@xs4all.nl>
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
19  */
20 
21 #include <map>
22 #include <set>
23 
24 #include <sys/types.h>
25 
26 #include "v4l2-compliance.h"
27 
checkStd(struct node * node,bool has_std,v4l2_std_id mask,bool is_input)28 static int checkStd(struct node *node, bool has_std, v4l2_std_id mask, bool is_input)
29 {
30 	v4l2_std_id std_mask = 0;
31 	v4l2_std_id std = 0;
32 	struct v4l2_standard enumstd;
33 	unsigned i;
34 	int ret;
35 
36 	ret = doioctl(node, VIDIOC_G_STD, &std);
37 	if (ret && has_std)
38 		return fail("STD cap set, but could not get standard\n");
39 	if (!ret && !has_std)
40 		return fail("STD cap not set, but could still get a standard\n");
41 	if (ret != ENOTTY && ret != ENODATA && !has_std)
42 		return fail("STD cap not set, but got wrong error code (%d)\n", ret);
43 	if (!ret && has_std) {
44 		if (std & ~mask)
45 			warn("current standard is invalid according to the standard mask\n");
46 		if (std == 0)
47 			return fail("Standard == 0?!\n");
48 		if (std & V4L2_STD_ATSC)
49 			return fail("Current standard contains ATSC standards. This is no longer supported\n");
50 	}
51 	ret = doioctl(node, VIDIOC_S_STD, &std);
52 	if (ret && has_std)
53 		return fail("STD cap set, but could not set standard\n");
54 	if (!ret && !has_std)
55 		return fail("STD cap not set, but could still set a standard\n");
56 	std = V4L2_STD_ATSC;
57 	ret = doioctl(node, VIDIOC_S_STD, &std);
58 	if (ret != ENODATA && ret != EINVAL && ret != ENOTTY)
59 		return fail("could set standard to ATSC, which is not supported anymore\n");
60 	for (i = 0; ; i++) {
61 		memset(&enumstd, 0xff, sizeof(enumstd));
62 
63 		enumstd.index = i;
64 		ret = doioctl(node, VIDIOC_ENUMSTD, &enumstd);
65 		if (ret)
66 			break;
67 		std_mask |= enumstd.id;
68 		if (check_ustring(enumstd.name, sizeof(enumstd.name)))
69 			return fail("invalid standard name\n");
70 		if (check_0(enumstd.reserved, sizeof(enumstd.reserved)))
71 			return fail("reserved not zeroed\n");
72 		if (enumstd.framelines == 0)
73 			return fail("framelines not filled\n");
74 		if (enumstd.framelines != 625 && enumstd.framelines != 525)
75 			warn("strange framelines value %d for standard %08llx\n",
76 					enumstd.framelines, enumstd.id);
77 		if (enumstd.frameperiod.numerator == 0 || enumstd.frameperiod.denominator == 0)
78 			return fail("frameperiod is not filled\n");
79 		if (enumstd.index != i)
80 			return fail("index changed!\n");
81 		if (enumstd.id == 0)
82 			return fail("empty standard returned\n");
83 	}
84 	if (i == 0 && has_std)
85 		return fail("STD cap set, but no standards can be enumerated\n");
86 	if (i && !has_std)
87 		return fail("STD cap was not set, but standards can be enumerated\n");
88 	if (ret != ENOTTY && ret != ENODATA && !has_std)
89 		return fail("STD cap not set, but got wrong error code for enumeration (%d)\n", ret);
90 	if (std_mask & V4L2_STD_ATSC)
91 		return fail("STD mask contains ATSC standards. This is no longer supported\n");
92 	if (has_std && std_mask != mask)
93 		return fail("the union of ENUMSTD does not match the standard mask (%llx != %llx)\n",
94 				std_mask, mask);
95 	ret = doioctl(node, VIDIOC_QUERYSTD, &std);
96 	if (!ret && !has_std)
97 		return fail("STD cap was not set, but could still query standard\n");
98 	if (ret != ENOTTY && ret != ENODATA && !has_std)
99 		return fail("STD cap not set, but got wrong error code for query (%d)\n", ret);
100 	if (ret != ENOTTY && !is_input)
101 		return fail("this is an output, but could still query standard\n");
102 	if (!ret && is_input && (std & ~std_mask))
103 		return fail("QUERYSTD gives back an unsupported standard\n");
104 	return 0;
105 }
106 
testStd(struct node * node)107 int testStd(struct node *node)
108 {
109 	int ret;
110 	unsigned i, o;
111 	bool has_std = false;
112 
113 	for (i = 0; i < node->inputs; i++) {
114 		struct v4l2_input input;
115 
116 		input.index = i;
117 		ret = doioctl(node, VIDIOC_ENUMINPUT, &input);
118 		if (ret)
119 			return fail("could not enumerate input %d?!\n", i);
120 		ret = doioctl(node, VIDIOC_S_INPUT, &input.index);
121 		if (ret)
122 			return fail("could not select input %d.\n", i);
123 		if (input.capabilities & V4L2_IN_CAP_STD)
124 			has_std = true;
125 		if (checkStd(node, input.capabilities & V4L2_IN_CAP_STD, input.std, true))
126 			return fail("STD failed for input %d.\n", i);
127 	}
128 
129 	for (o = 0; o < node->outputs; o++) {
130 		struct v4l2_output output;
131 
132 		output.index = o;
133 		ret = doioctl(node, VIDIOC_ENUMOUTPUT, &output);
134 		if (ret)
135 			return fail("could not enumerate output %d?!\n", o);
136 		ret = doioctl(node, VIDIOC_S_OUTPUT, &output.index);
137 		if (ret)
138 			return fail("could not select output %d.\n", o);
139 		if (output.capabilities & V4L2_OUT_CAP_STD)
140 			has_std = true;
141 		if (checkStd(node, output.capabilities & V4L2_OUT_CAP_STD, output.std, false))
142 			return fail("STD failed for output %d.\n", o);
143 	}
144 	return has_std ? 0 : ENOTTY;
145 }
146 
checkTimings(struct node * node,bool has_timings,bool is_input)147 static int checkTimings(struct node *node, bool has_timings, bool is_input)
148 {
149 	struct v4l2_enum_dv_timings enumtimings;
150 	struct v4l2_dv_timings timings;
151 	struct v4l2_format fmt = { 0 };
152 	bool is_mplane = node->g_caps() & (V4L2_CAP_VIDEO_CAPTURE_MPLANE |
153 				       V4L2_CAP_VIDEO_OUTPUT_MPLANE |
154 				       V4L2_CAP_VIDEO_M2M_MPLANE);
155 	unsigned type;
156 	unsigned i;
157 	int ret;
158 
159 	memset(&timings, 0xff, sizeof(timings));
160 	if (node->can_capture)
161 		type = is_mplane ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE;
162 	else
163 		type = is_mplane ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_OUTPUT;
164 	ret = doioctl(node, VIDIOC_G_DV_TIMINGS, &timings);
165 	if (ret && has_timings)
166 		return fail("TIMINGS cap set, but could not get current timings\n");
167 	if (!ret && !has_timings)
168 		return fail("TIMINGS cap not set, but could still get timings\n");
169 	if (ret != ENOTTY && ret != ENODATA && !has_timings)
170 		return fail("TIMINGS cap not set, but got wrong error code (%d)\n", ret);
171 
172 	if (!ret) {
173 		fail_on_test(timings.type != V4L2_DV_BT_656_1120);
174 		fail_on_test(check_0(timings.bt.reserved, sizeof(timings.bt.reserved)));
175 	}
176 
177 	for (i = 0; ; i++) {
178 		memset(&enumtimings, 0xff, sizeof(enumtimings));
179 
180 		enumtimings.index = i;
181 		enumtimings.pad = 0;
182 		ret = doioctl(node, VIDIOC_ENUM_DV_TIMINGS, &enumtimings);
183 		if (ret)
184 			break;
185 		if (check_0(enumtimings.reserved, sizeof(enumtimings.reserved)))
186 			return fail("reserved not zeroed\n");
187 		fail_on_test(check_0(enumtimings.timings.bt.reserved,
188 				     sizeof(enumtimings.timings.bt.reserved)));
189 		if (enumtimings.index != i)
190 			return fail("index changed!\n");
191 		memset(enumtimings.timings.bt.reserved, 0xff,
192 		       sizeof(enumtimings.timings.bt.reserved));
193 		fail_on_test(doioctl(node, VIDIOC_S_DV_TIMINGS, &enumtimings.timings));
194 		fail_on_test(check_0(enumtimings.timings.bt.reserved,
195 				     sizeof(enumtimings.timings.bt.reserved)));
196 
197 		struct v4l2_dv_timings g_timings;
198 		fail_on_test(doioctl(node, VIDIOC_G_DV_TIMINGS, &g_timings));
199 		fail_on_test(g_timings.bt.width != enumtimings.timings.bt.width);
200 		fail_on_test(g_timings.bt.height != enumtimings.timings.bt.height);
201 
202 		if (node->is_vbi || node->is_meta)
203 			continue;
204 		fmt.type = type;
205 		fail_on_test(doioctl(node, VIDIOC_G_FMT, &fmt));
206 
207 		unsigned field = is_mplane ? fmt.fmt.pix_mp.field : fmt.fmt.pix.field;
208 
209 		if (enumtimings.timings.bt.interlaced)
210 			fail_on_test(field == V4L2_FIELD_NONE);
211 		else
212 			fail_on_test(field != V4L2_FIELD_NONE);
213 
214 		unsigned factor = V4L2_FIELD_HAS_T_OR_B(field) ? 2 : 1;
215 
216 		// Test if the new format after setting new timings is either too small
217 		// or more than 1.5 times the width/height. This allows for some
218 		// adjustments to be made to the format, but still detect if the
219 		// format isn't updated by the driver.
220 		if (is_mplane) {
221 			fail_on_test(fmt.fmt.pix_mp.width < enumtimings.timings.bt.width);
222 			fail_on_test(fmt.fmt.pix_mp.width >= enumtimings.timings.bt.width * 1.5);
223 			fail_on_test(fmt.fmt.pix_mp.height * factor < enumtimings.timings.bt.height);
224 			fail_on_test(fmt.fmt.pix_mp.height * factor >= enumtimings.timings.bt.height * 1.5);
225 		} else {
226 			fail_on_test(fmt.fmt.pix.width < enumtimings.timings.bt.width);
227 			fail_on_test(fmt.fmt.pix.width >= enumtimings.timings.bt.width * 1.5);
228 			fail_on_test(fmt.fmt.pix.height * factor < enumtimings.timings.bt.height);
229 			fail_on_test(fmt.fmt.pix.height * factor >= enumtimings.timings.bt.height * 1.5);
230 		}
231 	}
232 	if (i == 0 && has_timings)
233 		return fail("TIMINGS cap set, but no timings can be enumerated\n");
234 	if (i && !has_timings)
235 		return fail("TIMINGS cap was not set, but timings can be enumerated\n");
236 	if (ret != ENOTTY && ret != ENODATA && !has_timings)
237 		return fail("TIMINGS cap not set, but got wrong error code for enumeration (%d)\n", ret);
238 	if (has_timings)
239 		fail_on_test(doioctl(node, VIDIOC_S_DV_TIMINGS, &timings));
240 	ret = doioctl(node, VIDIOC_QUERY_DV_TIMINGS, &timings);
241 	if (!ret)
242 		fail_on_test(check_0(timings.bt.reserved, sizeof(timings.bt.reserved)));
243 	if (!ret && !has_timings)
244 		return fail("TIMINGS cap was not set, but could still query timings\n");
245 	if (ret != ENOTTY && ret != ENODATA && !has_timings)
246 		return fail("TIMINGS cap not set, but got wrong error code for query (%d)\n", ret);
247 	if (ret != ENOTTY && !is_input)
248 		return fail("this is an output, but could still query timings\n");
249 	return 0;
250 }
251 
checkSubDevEnumTimings(struct node * node,__u32 pad)252 static int checkSubDevEnumTimings(struct node *node, __u32 pad)
253 {
254 	struct v4l2_enum_dv_timings enumtimings;
255 	struct v4l2_dv_timings timings;
256 	bool found_fmt_mismatch = false;
257 	bool has_timings;
258 	int ret;
259 
260 	memset(&timings, 0xff, sizeof(timings));
261 	ret = doioctl(node, VIDIOC_G_DV_TIMINGS, &timings);
262 	has_timings = ret != ENOTTY;
263 	fail_on_test(has_timings && ret);
264 	if (has_timings) {
265 		fail_on_test(check_0(timings.bt.reserved, sizeof(timings.bt.reserved)));
266 		memset(timings.bt.reserved, 0xff, sizeof(timings.bt.reserved));
267 		fail_on_test(doioctl(node, VIDIOC_S_DV_TIMINGS, &timings));
268 		fail_on_test(check_0(timings.bt.reserved, sizeof(timings.bt.reserved)));
269 	} else {
270 		fail_on_test(doioctl(node, VIDIOC_S_DV_TIMINGS, &timings) != ENOTTY);
271 		fail_on_test(doioctl(node, VIDIOC_QUERY_DV_TIMINGS, &timings) != ENOTTY);
272 	}
273 
274 	for (unsigned i = 0; ; i++) {
275 		memset(&enumtimings, 0xff, sizeof(enumtimings));
276 
277 		enumtimings.index = i;
278 		enumtimings.pad = pad;
279 		ret = doioctl(node, VIDIOC_ENUM_DV_TIMINGS, &enumtimings);
280 		fail_on_test(ret != ENOTTY && !has_timings);
281 		fail_on_test(ret == ENOTTY && has_timings);
282 		if (ret == ENOTTY)
283 			return ret;
284 		fail_on_test(ret && ret != EINVAL);
285 		fail_on_test(ret && !i);
286 		if (ret)
287 			break;
288 		fail_on_test(check_0(enumtimings.reserved, sizeof(enumtimings.reserved)));
289 		fail_on_test(check_0(enumtimings.timings.bt.reserved,
290 				     sizeof(enumtimings.timings.bt.reserved)));
291 		fail_on_test(enumtimings.index != i);
292 		fail_on_test(enumtimings.pad != pad);
293 		memset(enumtimings.timings.bt.reserved, 0xff,
294 		       sizeof(enumtimings.timings.bt.reserved));
295 		fail_on_test(doioctl(node, VIDIOC_S_DV_TIMINGS, &enumtimings.timings));
296 		fail_on_test(check_0(enumtimings.timings.bt.reserved,
297 				     sizeof(enumtimings.timings.bt.reserved)));
298 
299 		struct v4l2_dv_timings g_timings;
300 
301 		fail_on_test(doioctl(node, VIDIOC_G_DV_TIMINGS, &g_timings));
302 		fail_on_test(g_timings.bt.width != enumtimings.timings.bt.width);
303 		fail_on_test(g_timings.bt.height != enumtimings.timings.bt.height);
304 
305 		if (found_fmt_mismatch)
306 			continue;
307 
308 		struct v4l2_subdev_format fmt;
309 
310 		memset(&fmt, 0, sizeof(fmt));
311 		fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
312 
313 		// Test if the new format after setting new timings is either too small
314 		// or more than 1.5 times the width/height. This allows for some
315 		// adjustments to be made to the format, but still detect if the
316 		// format isn't updated by the driver.
317 		if (!doioctl(node, VIDIOC_SUBDEV_G_FMT, &fmt)) {
318 			if (V4L2_FIELD_HAS_T_OR_B(fmt.format.field))
319 				fmt.format.height *= 2;
320 
321 			if (fmt.format.width < enumtimings.timings.bt.width) {
322 				warn("Active width for pad 0 is %u, which is less than the timings width of %u\n",
323 				     fmt.format.width, enumtimings.timings.bt.width);
324 				found_fmt_mismatch = true;
325 			}
326 			if (fmt.format.width >= enumtimings.timings.bt.width * 1.5) {
327 				warn("Active width for pad 0 is %u, which is more than 1.5 * the timings width of %u\n",
328 				     fmt.format.width, enumtimings.timings.bt.width);
329 				found_fmt_mismatch = true;
330 			}
331 			if (fmt.format.height < enumtimings.timings.bt.height) {
332 				warn("Active height for pad 0 is %u, which is less than the timings height of %u\n",
333 				     fmt.format.height, enumtimings.timings.bt.height);
334 				found_fmt_mismatch = true;
335 			}
336 			if (fmt.format.height >= enumtimings.timings.bt.height * 1.5) {
337 				warn("Active height for pad 0 is %u, which is more than 1.5 * the timings height of %u\n",
338 				     fmt.format.height, enumtimings.timings.bt.height);
339 				found_fmt_mismatch = true;
340 			}
341 		}
342 	}
343 	enumtimings.pad = node->entity.pads;
344 	enumtimings.index = 0;
345 	fail_on_test(doioctl(node, VIDIOC_ENUM_DV_TIMINGS, &enumtimings) != EINVAL);
346 
347 	fail_on_test(doioctl(node, VIDIOC_S_DV_TIMINGS, &timings));
348 	memset(&timings, 0xff, sizeof(timings));
349 	ret = doioctl(node, VIDIOC_QUERY_DV_TIMINGS, &timings);
350 	fail_on_test(ret == ENOTTY);
351 	fail_on_test(ret == ENODATA);
352 	if (!ret || ret == ERANGE)
353 		fail_on_test(check_0(timings.bt.reserved, sizeof(timings.bt.reserved)));
354 	return 0;
355 }
356 
testTimings(struct node * node)357 int testTimings(struct node *node)
358 {
359 	int ret;
360 	unsigned i, o;
361 	bool has_timings = false;
362 
363 	if (node->is_subdev()) {
364 		for (unsigned pad = 0; pad < node->entity.pads; pad++) {
365 			ret = checkSubDevEnumTimings(node, pad);
366 			if (!ret)
367 				has_timings = true;
368 			fail_on_test(ret && ret != ENOTTY);
369 		}
370 		return has_timings ? 0 : ENOTTY;
371 	}
372 
373 	for (i = 0; i < node->inputs; i++) {
374 		struct v4l2_input input;
375 
376 		input.index = i;
377 		ret = doioctl(node, VIDIOC_ENUMINPUT, &input);
378 		if (ret)
379 			return fail("could not enumerate input %d?!\n", i);
380 		ret = doioctl(node, VIDIOC_S_INPUT, &input.index);
381 		if (ret)
382 			return fail("could not select input %d.\n", i);
383 		if (input.capabilities & V4L2_IN_CAP_DV_TIMINGS)
384 			has_timings = true;
385 		if (checkTimings(node, input.capabilities & V4L2_IN_CAP_DV_TIMINGS, true))
386 			return fail("Timings check failed for input %d.\n", i);
387 	}
388 
389 	for (o = 0; o < node->outputs; o++) {
390 		struct v4l2_output output;
391 
392 		output.index = o;
393 		ret = doioctl(node, VIDIOC_ENUMOUTPUT, &output);
394 		if (ret)
395 			return fail("could not enumerate output %d?!\n", o);
396 		ret = doioctl(node, VIDIOC_S_OUTPUT, &output.index);
397 		if (ret)
398 			return fail("could not select output %d.\n", o);
399 		if (output.capabilities & V4L2_OUT_CAP_DV_TIMINGS)
400 			has_timings = true;
401 		if (checkTimings(node, output.capabilities & V4L2_OUT_CAP_DV_TIMINGS, false))
402 			return fail("Timings check failed for output %d.\n", o);
403 	}
404 	return has_timings ? 0 : ENOTTY;
405 }
406 
checkTimingsCap(struct node * node,unsigned pad,bool has_timings)407 static int checkTimingsCap(struct node *node, unsigned pad, bool has_timings)
408 {
409 	struct v4l2_dv_timings_cap timingscap;
410 	int ret;
411 
412 	memset(&timingscap, 0xff, sizeof(timingscap));
413 	timingscap.pad = pad;
414 	ret = doioctl(node, VIDIOC_DV_TIMINGS_CAP, &timingscap);
415 	if (node->is_subdev() && ret == ENOTTY)
416 		return ENOTTY;
417 	if (ret && has_timings)
418 		return fail("TIMINGS cap set, but could not get timings caps\n");
419 	if (!ret && !has_timings)
420 		return fail("TIMINGS cap not set, but could still get timings caps\n");
421 	if (ret && !has_timings)
422 		return 0;
423 	if (check_0(timingscap.reserved, sizeof(timingscap.reserved)))
424 		return fail("reserved not zeroed\n");
425 	fail_on_test(timingscap.pad != pad);
426 	fail_on_test(timingscap.type != V4L2_DV_BT_656_1120);
427 	if (check_0(timingscap.bt.reserved, sizeof(timingscap.bt.reserved)))
428 		return fail("reserved not zeroed\n");
429 	fail_on_test(timingscap.bt.min_width > timingscap.bt.max_width);
430 	fail_on_test(timingscap.bt.min_height > timingscap.bt.max_height);
431 	fail_on_test(timingscap.bt.min_pixelclock > timingscap.bt.max_pixelclock);
432 
433 	if (!node->is_subdev())
434 		return 0;
435 
436 	memset(&timingscap, 0, sizeof(timingscap));
437 	timingscap.pad = node->is_subdev() ? node->entity.pads : 1;
438 	fail_on_test(doioctl(node, VIDIOC_DV_TIMINGS_CAP, &timingscap) != EINVAL);
439 	return 0;
440 }
441 
testTimingsCap(struct node * node)442 int testTimingsCap(struct node *node)
443 {
444 	int ret;
445 	unsigned i, o;
446 	bool has_timings = false;
447 
448 	if (node->is_subdev()) {
449 		for (unsigned pad = 0; pad < node->entity.pads; pad++) {
450 			bool is_input = node->pads[pad].flags & MEDIA_PAD_FL_SINK;
451 
452 			ret = checkTimingsCap(node, pad, true);
453 			if (ret && ret != ENOTTY)
454 				return fail("EDID check failed for %s pad %u.\n",
455 					    is_input ? "sink" : "source", pad);
456 			if (!ret)
457 				has_timings = true;
458 		}
459 		return has_timings ? 0 : ENOTTY;
460 	}
461 
462 	for (i = 0; i < node->inputs; i++) {
463 		struct v4l2_input input;
464 
465 		input.index = i;
466 		ret = doioctl(node, VIDIOC_ENUMINPUT, &input);
467 		if (ret)
468 			return fail("could not enumerate input %d?!\n", i);
469 		ret = doioctl(node, VIDIOC_S_INPUT, &input.index);
470 		if (ret)
471 			return fail("could not select input %d.\n", i);
472 		if (input.capabilities & V4L2_IN_CAP_DV_TIMINGS)
473 			has_timings = true;
474 		if (checkTimingsCap(node, 0, input.capabilities & V4L2_IN_CAP_DV_TIMINGS))
475 			return fail("Timings cap failed for input %d.\n", i);
476 	}
477 
478 	for (o = 0; o < node->outputs; o++) {
479 		struct v4l2_output output;
480 
481 		output.index = o;
482 		ret = doioctl(node, VIDIOC_ENUMOUTPUT, &output);
483 		if (ret)
484 			return fail("could not enumerate output %d?!\n", o);
485 		ret = doioctl(node, VIDIOC_S_OUTPUT, &output.index);
486 		if (ret)
487 			return fail("could not select output %d.\n", o);
488 		if (output.capabilities & V4L2_OUT_CAP_DV_TIMINGS)
489 			has_timings = true;
490 		if (checkTimingsCap(node, 0, output.capabilities & V4L2_OUT_CAP_DV_TIMINGS))
491 			return fail("Timings cap check failed for output %d.\n", o);
492 	}
493 	return has_timings ? 0 : ENOTTY;
494 }
495 
checkEdid(struct node * node,unsigned pad,bool is_input)496 static int checkEdid(struct node *node, unsigned pad, bool is_input)
497 {
498 	struct v4l2_edid edid;
499 	__u8 data[256 * 128] = { 0 };
500 	unsigned blocks;
501 	bool has_edid;
502 	int ret;
503 
504 	memset(edid.reserved, 0xff, sizeof(edid.reserved));
505 	edid.pad = pad;
506 	edid.start_block = 0;
507 	edid.blocks = 0;
508 	edid.edid = (__u8 *)0x0eadbeef;
509 	ret = doioctl(node, VIDIOC_G_EDID, &edid);
510 	if (ret == ENOTTY) {
511 		memset(&edid, 0, sizeof(edid));
512 		edid.pad = pad;
513 		fail_on_test(doioctl(node, VIDIOC_S_EDID, &edid) != ENOTTY);
514 		return ENOTTY;
515 	}
516 	has_edid = ret == 0;
517 	fail_on_test(ret && ret != EINVAL);
518 	fail_on_test(!ret && check_0(edid.reserved, sizeof(edid.reserved)));
519 	fail_on_test(edid.start_block);
520 	fail_on_test(edid.blocks > 256);
521 	fail_on_test(!has_edid && edid.blocks);
522 	fail_on_test(edid.pad != pad);
523 	blocks = edid.blocks;
524 	edid.edid = data;
525 	ret = doioctl(node, VIDIOC_G_EDID, &edid);
526 	if (!has_edid)
527 		fail_on_test(ret != EINVAL);
528 	else
529 		fail_on_test(ret != 0 && ret != ENODATA);
530 	fail_on_test(edid.blocks != blocks);
531 
532 	if (has_edid) {
533 		edid.start_block = edid.blocks ? edid.blocks : 1;
534 		ret = doioctl(node, VIDIOC_G_EDID, &edid);
535 		fail_on_test(ret != EINVAL && ret != ENODATA);
536 		if (blocks > 1) {
537 			edid.start_block = 1;
538 			edid.blocks = blocks;
539 			fail_on_test(doioctl(node, VIDIOC_G_EDID, &edid));
540 			fail_on_test(edid.blocks != blocks - 1);
541 		}
542 
543 		edid.start_block = 0;
544 		edid.blocks = 256;
545 		ret = doioctl(node, VIDIOC_G_EDID, &edid);
546 		fail_on_test(ret && ret != ENODATA);
547 		if (!ret)
548 			fail_on_test(edid.blocks != blocks);
549 		edid.pad = ~0;
550 		fail_on_test(doioctl(node, VIDIOC_G_EDID, &edid) != EINVAL);
551 		edid.pad = pad;
552 	}
553 
554 	memset(edid.reserved, 0xff, sizeof(edid.reserved));
555 	edid.blocks = blocks;
556 	ret = doioctl(node, VIDIOC_S_EDID, &edid);
557 	if (ret == ENOTTY) {
558 		fail_on_test(is_input);
559 		return 0;
560 	}
561 	fail_on_test(!is_input);
562 	if (!has_edid) {
563 		fail_on_test(ret != EINVAL);
564 		return 0;
565 	}
566 	fail_on_test(ret);
567 	fail_on_test(check_0(edid.reserved, sizeof(edid.reserved)));
568 	edid.blocks = blocks;
569 	edid.pad = ~0;
570 	ret = doioctl(node, VIDIOC_S_EDID, &edid);
571 	fail_on_test(ret != EINVAL);
572 	if (blocks < 256) {
573 		edid.blocks = 256;
574 		edid.pad = pad;
575 		ret = doioctl(node, VIDIOC_S_EDID, &edid);
576 		fail_on_test(ret != E2BIG);
577 		fail_on_test(edid.blocks == 0 || edid.blocks >= 256);
578 		fail_on_test(edid.pad != pad);
579 	}
580 	if (!has_mmu)
581 		return 0;
582 	edid.blocks = 1;
583 	edid.pad = pad;
584 	edid.edid = nullptr;
585 	ret = doioctl(node, VIDIOC_S_EDID, &edid);
586 	fail_on_test(ret != EFAULT);
587 	edid.edid = (__u8 *)0x0eadbeef;
588 	ret = doioctl(node, VIDIOC_S_EDID, &edid);
589 	fail_on_test(ret != EFAULT);
590 	return 0;
591 }
592 
testEdid(struct node * node)593 int testEdid(struct node *node)
594 {
595 	bool has_edid = false;
596 	unsigned i, o;
597 	int ret;
598 
599 	if (node->is_subdev()) {
600 		for (unsigned pad = 0; pad < node->entity.pads; pad++) {
601 			bool is_input = node->pads[pad].flags & MEDIA_PAD_FL_SOURCE;
602 
603 			ret = checkEdid(node, pad, is_input);
604 			if (ret && ret != ENOTTY)
605 				return fail("EDID check failed for %s pad %u.\n",
606 					    is_input ? "source" : "sink", pad);
607 			if (!ret)
608 				has_edid = true;
609 		}
610 		return has_edid ? 0 : ENOTTY;
611 	}
612 
613 	for (i = 0; i < node->inputs; i++) {
614 		struct v4l2_input input;
615 
616 		input.index = i;
617 		ret = doioctl(node, VIDIOC_ENUMINPUT, &input);
618 		if (ret)
619 			return fail("could not enumerate input %d?!\n", i);
620 		ret = doioctl(node, VIDIOC_S_INPUT, &input.index);
621 		if (ret)
622 			return fail("could not select input %d.\n", i);
623 		ret = checkEdid(node, i, true);
624 		if (ret && ret != ENOTTY)
625 			return fail("EDID check failed for input %d.\n", i);
626 		if (input.capabilities & V4L2_IN_CAP_DV_TIMINGS)
627 			has_edid = !ret ? true : has_edid;
628 	}
629 
630 	for (o = 0; o < node->outputs; o++) {
631 		struct v4l2_output output;
632 
633 		output.index = o;
634 		ret = doioctl(node, VIDIOC_ENUMOUTPUT, &output);
635 		if (ret)
636 			return fail("could not enumerate output %d?!\n", o);
637 		ret = doioctl(node, VIDIOC_S_OUTPUT, &output.index);
638 		if (ret)
639 			return fail("could not select output %d.\n", o);
640 		ret = checkEdid(node, o, false);
641 		if (ret && ret != ENOTTY)
642 			return fail("EDID check failed for output %d.\n", o);
643 		if (output.capabilities & V4L2_OUT_CAP_DV_TIMINGS)
644 			has_edid = !ret ? true : has_edid;
645 	}
646 	return has_edid ? 0 : ENOTTY;
647 }
648