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