1 #include <cstdlib>
2 #include <cstring>
3
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <inttypes.h>
8 #include <fcntl.h>
9 #include <ctype.h>
10 #include <errno.h>
11 #include <sys/ioctl.h>
12
13 #include "v4l2-ctl.h"
14
15 #include <linux/v4l2-subdev.h>
16
17 /*
18 * The 24-bit IEEE Registration Identifier for the HDMI-LLC Vendor
19 * Specific Data Block.
20 */
21 #define HDMI_VSDB_EXT_TAG 0x000c03
22 /*
23 * The 24-bit IEEE Registration Identifier for the HDMI-Forum Vendor
24 * Specific Data Block.
25 */
26 #define HF_VSDB_EXT_TAG 0xc45dd8
27
28 #define VID_CAP_EXT_TAG 0
29 #define COLORIMETRY_EXT_TAG 5
30 #define HDR_MD_EXT_TAG 6
31
32 #define VSDB_TAG 3
33 #define SPEAKER_TAG 4
34 #define EXTENDED_TAG 7
35
36 enum format {
37 HEX,
38 RAW,
39 CARRAY
40 };
41
42 static struct v4l2_edid sedid;
43 static char *file_in;
44
45 static struct v4l2_edid gedid;
46 static struct v4l2_edid info_edid;
47 static char *file_out;
48 static enum format gformat;
49 static enum format sformat;
50 static unsigned clear_pad;
51 static long phys_addr = -1;
52
53 static uint8_t toggle_cta861_hdr_flags;
54 #define CTA861_HDR_UNDERSCAN (1 << 6)
55 #define CTA861_HDR_AUDIO (1 << 6)
56 #define CTA861_HDR_YCBCR444 (1 << 5)
57 #define CTA861_HDR_YCBCR422 (1 << 4)
58
59 static uint8_t toggle_speaker1_flags;
60 #define SPEAKER1_FL_FR (1 << 0)
61 #define SPEAKER1_LFE (1 << 1)
62 #define SPEAKER1_FC (1 << 2)
63 #define SPEAKER1_BL_BR (1 << 3)
64 #define SPEAKER1_BC (1 << 4)
65 #define SPEAKER1_FLC_FRC (1 << 5)
66 #define SPEAKER1_RLC_RRC (1 << 6)
67 #define SPEAKER1_FLW_FRW (1 << 7)
68
69 static uint8_t toggle_speaker2_flags;
70 #define SPEAKER2_TPFL_TPFR (1 << 0)
71 #define SPEAKER2_TPC (1 << 1)
72 #define SPEAKER2_TPFC (1 << 2)
73 #define SPEAKER2_LS_RS (1 << 3)
74 #define SPEAKER2_LFE2 (1 << 4)
75 #define SPEAKER2_TPBC (1 << 5)
76 #define SPEAKER2_SIL_SIR (1 << 6)
77 #define SPEAKER2_TPSIL_TPSIR (1 << 7)
78
79 static uint8_t toggle_speaker3_flags;
80 #define SPEAKER3_TPBL_TPBR (1 << 0)
81 #define SPEAKER3_BTFC (1 << 1)
82 #define SPEAKER3_BTFL_BTFR (1 << 2)
83 #define SPEAKER3_TPLS_TPRS (1 << 3)
84
85 static uint8_t toggle_hdmi_vsdb_dc_flags;
86 #define HDMI_VSDB_Y444_BIT (1 << 3)
87 #define HDMI_VSDB_30_BIT (1 << 4)
88 #define HDMI_VSDB_36_BIT (1 << 5)
89 #define HDMI_VSDB_48_BIT (1 << 6)
90 static uint8_t toggle_hdmi_vsdb_cnc_flags;
91 #define HDMI_VSDB_GRAPHICS (1 << 0)
92 #define HDMI_VSDB_PHOTO (1 << 1)
93 #define HDMI_VSDB_CINEMA (1 << 2)
94 #define HDMI_VSDB_GAME (1 << 3)
95 #define HDMI_VSDB_I_LATENCY (1 << 6)
96 #define HDMI_VSDB_LATENCY (1 << 7)
97
98 static uint8_t toggle_hf_vsdb_flags;
99 #define HF_VSDB_SCSD_PRESENT (1 << 7)
100
101 static int mod_s_pt = -1;
102 static int mod_s_it = -1;
103 static int mod_s_ce = -1;
104 static uint8_t toggle_vid_cap_flags;
105 #define VID_CAP_QS (1 << 6)
106 #define VID_CAP_QY (1 << 7)
107
108 static uint8_t toggle_colorimetry_flags1;
109 #define COLORIMETRY_XVYCC601 (1 << 0)
110 #define COLORIMETRY_XVYCC709 (1 << 1)
111 #define COLORIMETRY_SYCC (1 << 2)
112 #define COLORIMETRY_OPYCC (1 << 3)
113 #define COLORIMETRY_OPRGB (1 << 4)
114 #define COLORIMETRY_BT2020CYCC (1 << 5)
115 #define COLORIMETRY_BT2020YCC (1 << 6)
116 #define COLORIMETRY_BT2020RGB (1 << 7)
117
118 static uint8_t toggle_colorimetry_flags2;
119 #define COLORIMETRY_DCIP3 (1 << 0)
120
121 static uint8_t toggle_hdr_md_flags;
122 #define HDR_MD_SDR (1 << 0)
123 #define HDR_MD_HDR (1 << 1)
124 #define HDR_MD_SMPTE_2084 (1 << 2)
125 #define HDR_MD_HLG (1 << 3)
126
edid_usage()127 void edid_usage()
128 {
129 printf("\nEDID options:\n"
130 " --set-edid pad=<pad>[,type=<type>|file=<file>][,format=<fmt>][modifiers]\n"
131 " <pad> is the input or output index for which to set the EDID.\n"
132 " <type> can be 'hdmi', 'hdmi-4k-170mhz', 'hdmi-4k-300mhz', 'hdmi-4k-600mhz',\n"
133 " 'dvid' or 'vga'. A predefined EDID suitable for that connector type will be\n"
134 " set. It has a 1920x1080p60 native resolution for the non-4k variants and a\n"
135 " 3840x2160 resolution for the 4k variants (4kp30 YCbCr 4:2:0 for 170mhz, 4kp30\n"
136 " for 300 mhz and 4kp60 for 600 mhz).\n"
137 " If <file> is '-', then the data is read from stdin, otherwise it is\n"
138 " read from the given file. The file format must be in hex as in get-edid.\n"
139 " The 'type' or 'file' arguments are mutually exclusive. One of the two\n"
140 " must be specified.\n"
141 " <fmt> is one of:\n"
142 " hex: hex numbers in ascii text (default)\n"
143 " raw: raw binary EDID content\n"
144 "\n"
145 " [modifiers] is a comma-separate list of EDID modifiers:\n"
146 "\n"
147 " CTA-861 Header modifiers:\n"
148 " underscan: toggle the underscan bit.\n"
149 " audio: toggle the audio bit.\n"
150 " ycbcr444: toggle the YCbCr 4:4:4 bit.\n"
151 " ycbcr422: toggle the YCbCr 4:2:2 bit.\n"
152 "\n"
153 " Speaker Allocation Data Block modifiers:\n"
154 " fl-fr: Front Left/Right.\n"
155 " lfe: Low Frequency Effects.\n"
156 " fc: Front Center.\n"
157 " bl-br: Back Left/Right.\n"
158 " bc: Back Center.\n"
159 " rlc-frc: Front Left/Right of Center.\n"
160 " rlc-rrc: Rear Left/Right of Center.\n"
161 " flw-frw: Front Left/Right Wide.\n"
162 " tpfl-tpfr: Top Front Left/Right.\n"
163 " tpc: Top Center.\n"
164 " tpfc: Top Front Center.\n"
165 " ls-rs: Left/Right Surround.\n"
166 " lfe2: Low Frequency Effects 2.\n"
167 " tpbc: Top Back Center.\n"
168 " sil-sir: Side Left/Right\n"
169 " tpsil-tpsir: Top Side Left/Right.\n"
170 " tpbl-tpbr: Top Back Left/Right.\n"
171 " btfc: Bottom Front Center.\n"
172 " btfl-btbr: Bottom Front Left/Right.\n"
173 " tpls-tprs: Top Left/Right Surround.\n"
174 "\n"
175 " HDMI Vendor-Specific Data Block modifiers:\n"
176 " pa=<pa>: change the physical address.\n"
177 " y444: toggle the YCbCr 4:4:4 Deep Color bit.\n"
178 " 30-bit: toggle the 30 bits/pixel bit.\n"
179 " 36-bit: toggle the 36 bits/pixel bit.\n"
180 " 48-bit: toggle the 48 bits/pixel bit.\n"
181 " graphics: toggle the Graphics Content Type bit.\n"
182 " photo: toggle the Photo Content Type bit.\n"
183 " cinema: toggle the Cinema Content Type bit.\n"
184 " game: toggle the Game Content Type bit.\n"
185 "\n"
186 " HDMI Forum Vendor-Specific Data Block modifiers:\n"
187 " scdc: toggle the SCDC Present bit.\n"
188 "\n"
189 " CTA-861 Video Capability Descriptor modifiers:\n"
190 " qy: toggle the QY YCC Quantization Range bit.\n"
191 " qs: toggle the QS RGB Quantization Range bit.\n"
192 " s-pt=<0-3>: set the PT Preferred Format Over/underscan bits.\n"
193 " s-it=<0-3>: set the IT Over/underscan bits.\n"
194 " s-ce=<0-3>: set the CE Over/underscan bits.\n"
195 "\n"
196 " CTA-861 Colorimetry Data Block modifiers:\n"
197 " xvycc-601: toggle the xvYCC 601 bit.\n"
198 " xvycc-709: toggle the xvYCC 709 bit.\n"
199 " sycc: toggle the sYCC 601 bit.\n"
200 " opycc: toggle the opYCC 601 bit.\n"
201 " oprgb: toggle the opRGB bit.\n"
202 " bt2020-rgb: toggle the BT2020 RGB bit.\n"
203 " bt2020-ycc: toggle the BT2020 YCC bit.\n"
204 " bt2020-cycc: toggle the BT2020 cYCC bit.\n"
205 " dci-p3: toggle the DCI-P3 bit.\n"
206 "\n"
207 " CTA-861 HDR Static Metadata Data Block modifiers:\n"
208 " sdr: toggle the Traditional gamma SDR bit.\n"
209 " hdr: toggle the Traditional gamma HDR bit.\n"
210 " smpte2084: toggle the SMPTE ST 2084 bit.\n"
211 " hlg: toggle the Hybrid Log-Gamma bit.\n"
212 " --clear-edid <pad> clear the EDID for the input or output index <pad>.\n"
213 " --info-edid <pad> print the current EDID's modifiers\n"
214 " <pad> is the input or output index for which to get the EDID.\n"
215 " --get-edid pad=<pad>,startblock=<startblock>,blocks=<blocks>,format=<fmt>,file=<file>\n"
216 " <pad> is the input or output index for which to get the EDID.\n"
217 " <startblock> is the first block number you want to read. Default 0.\n"
218 " <blocks> is the number of blocks you want to read. Default is\n"
219 " all blocks.\n"
220 " <fmt> is one of:\n"
221 " hex: hex numbers in ascii text (default)\n"
222 " raw: can be piped directly into the edid-decode tool\n"
223 " carray: c-program struct\n"
224 " If <file> is '-' or not the 'file' argument is not supplied, then the data\n"
225 " is written to stdout.\n"
226 " --fix-edid-checksums\n"
227 " If specified then any checksum errors will be fixed silently.\n"
228 );
229 }
230
edid_add_block(struct v4l2_edid * e)231 static void edid_add_block(struct v4l2_edid *e)
232 {
233 e->blocks++;
234 if (e->blocks > 256) {
235 fprintf(stderr, "edid file error: too long\n");
236 free(e->edid);
237 e->edid = NULL;
238 std::exit(EXIT_FAILURE);
239 }
240 e->edid = static_cast<unsigned char *>(realloc(e->edid, e->blocks * 128));
241 }
242
read_edid_file(FILE * f,struct v4l2_edid * e)243 static void read_edid_file(FILE *f, struct v4l2_edid *e)
244 {
245 char value[3] = { 0 };
246 unsigned i = 0;
247 int c;
248
249 fseek(f, SEEK_SET, 0);
250 e->edid = NULL;
251 e->blocks = 0;
252
253 while ((c = fgetc(f)) != EOF) {
254 if (sformat == RAW) {
255 if (i % 256 == 0)
256 edid_add_block(e);
257 e->edid[i / 2] = c;
258 i += 2;
259 continue;
260 }
261 /* Handle '0x' prefix */
262 if ((i & 1) && value[0] == '0' && (c == 'x' || c == 'X'))
263 i--;
264 if (!isxdigit(c))
265 continue;
266 if (i & 0x01) {
267 value[1] = c;
268 if (i % 256 == 1)
269 edid_add_block(e);
270 e->edid[i / 2] = strtoul(value, 0, 16);
271 } else {
272 value[0] = c;
273 }
274 i++;
275 }
276 }
277
crc_calc(const unsigned char * b)278 static unsigned char crc_calc(const unsigned char *b)
279 {
280 unsigned char sum = 0;
281 int i;
282
283 for (i = 0; i < 127; i++)
284 sum += b[i];
285 return 256 - sum;
286 }
287
crc_ok(const unsigned char * b)288 static bool crc_ok(const unsigned char *b)
289 {
290 return crc_calc(b) == b[127];
291 }
292
fix_edid(struct v4l2_edid * e)293 static void fix_edid(struct v4l2_edid *e)
294 {
295 for (unsigned b = 0; b < e->blocks; b++) {
296 unsigned char *buf = e->edid + 128 * b;
297
298 if (!crc_ok(buf))
299 buf[127] = crc_calc(buf);
300 }
301 }
302
verify_edid(struct v4l2_edid * e)303 static bool verify_edid(struct v4l2_edid *e)
304 {
305 bool valid = true;
306
307 for (unsigned b = 0; b < e->blocks; b++) {
308 const unsigned char *buf = e->edid + 128 * b;
309
310 if (!crc_ok(buf)) {
311 fprintf(stderr, "Block %u has a checksum error (should be 0x%02x)\n",
312 b, crc_calc(buf));
313 valid = false;
314 }
315 }
316 return valid;
317 }
318
hexdumpedid(FILE * f,struct v4l2_edid * e)319 static void hexdumpedid(FILE *f, struct v4l2_edid *e)
320 {
321 for (unsigned b = 0; b < e->blocks; b++) {
322 unsigned char *buf = e->edid + 128 * b;
323
324 if (b)
325 fprintf(f, "\n");
326 for (unsigned i = 0; i < 128; i += 0x10) {
327 fprintf(f, "%02x", buf[i]);
328 for (unsigned j = 1; j < 0x10; j++) {
329 fprintf(f, " %02x", buf[i + j]);
330 }
331 fprintf(f, "\n");
332 }
333 if (!crc_ok(buf))
334 fprintf(f, "Block %u has a checksum error (should be 0x%02x)\n",
335 b, crc_calc(buf));
336 }
337 }
338
rawdumpedid(FILE * f,struct v4l2_edid * e)339 static void rawdumpedid(FILE *f, struct v4l2_edid *e)
340 {
341 for (unsigned b = 0; b < e->blocks; b++) {
342 unsigned char *buf = e->edid + 128 * b;
343
344 for (unsigned i = 0; i < 128; i++)
345 fprintf(f, "%c", buf[i]);
346 if (!crc_ok(buf))
347 fprintf(stderr, "Block %u has a checksum error (should be %02x)\n",
348 b, crc_calc(buf));
349 }
350 }
351
carraydumpedid(FILE * f,struct v4l2_edid * e)352 static void carraydumpedid(FILE *f, struct v4l2_edid *e)
353 {
354 fprintf(f, "unsigned char edid[] = {\n");
355 for (unsigned b = 0; b < e->blocks; b++) {
356 unsigned char *buf = e->edid + 128 * b;
357
358 if (b)
359 fprintf(f, "\n");
360 for (unsigned i = 0; i < 128; i += 8) {
361 fprintf(f, "\t0x%02x,", buf[i]);
362 for (unsigned j = 1; j < 8; j++) {
363 fprintf(f, " 0x%02x,", buf[i + j]);
364 }
365 fprintf(f, "\n");
366 }
367 if (!crc_ok(buf))
368 fprintf(f, "\t/* Block %u has a checksum error (should be 0x%02x) */\n",
369 b, crc_calc(buf));
370 }
371 fprintf(f, "};\n");
372 }
373
printedid(FILE * f,struct v4l2_edid * e,enum format gf)374 static void printedid(FILE *f, struct v4l2_edid *e, enum format gf)
375 {
376 switch (gf) {
377 default:
378 case HEX:
379 hexdumpedid(f, e);
380 break;
381 case RAW:
382 rawdumpedid(f, e);
383 break;
384 case CARRAY:
385 carraydumpedid(f, e);
386 break;
387 }
388 }
389
get_edid_tag_location(const unsigned char * edid,unsigned size,unsigned char want_tag,uint32_t ext_tag)390 static int get_edid_tag_location(const unsigned char *edid, unsigned size,
391 unsigned char want_tag, uint32_t ext_tag)
392 {
393 unsigned char d;
394
395 if (size < 256)
396 return -1;
397
398 if (edid[0x7e] != 1 || edid[0x80] != 0x02 || edid[0x81] != 0x03)
399 return -1;
400
401 /* search tag */
402 d = edid[0x82] & 0x7f;
403 if (d <= 4)
404 return -1;
405
406 int i = 0x84;
407 int end = 0x80 + d;
408
409 do {
410 unsigned char tag = edid[i] >> 5;
411 unsigned char len = edid[i] & 0x1f;
412
413 if (tag != want_tag || i + len > end) {
414 i += len + 1;
415 continue;
416 }
417
418 /*
419 * Tag 3 (Vendor-Specific Data Block) has
420 * a 24 bit IEEE identifier.
421 */
422 if (tag == VSDB_TAG && len >= 3 &&
423 edid[i + 1] == (ext_tag & 0xff) &&
424 edid[i + 2] == ((ext_tag >> 8) & 0xff) &&
425 edid[i + 3] == ((ext_tag >> 16) & 0xff))
426 return i;
427 /*
428 * Tag 7 has an extended tag, others (0-2, 4-6)
429 * have no identifiers.
430 */
431 if ((tag < EXTENDED_TAG && tag != VSDB_TAG) ||
432 (tag == EXTENDED_TAG && len >= 1 && edid[i + 1] == ext_tag))
433 return i;
434 i += len + 1;
435 } while (i < end);
436 return -1;
437 }
438
get_edid_cta861_hdr_location(const unsigned char * edid,unsigned size)439 static int get_edid_cta861_hdr_location(const unsigned char *edid, unsigned size)
440 {
441 if (size < 256)
442 return -1;
443
444 if (edid[0x7e] != 1 || edid[0x80] != 0x02 || edid[0x81] != 0x03)
445 return -1;
446
447 return 0x83;
448 }
449
get_edid_spa_location(const unsigned char * edid,unsigned size)450 static int get_edid_spa_location(const unsigned char *edid, unsigned size)
451 {
452 int loc = get_edid_tag_location(edid, size, VSDB_TAG, HDMI_VSDB_EXT_TAG);
453
454 if (loc < 0)
455 return loc;
456
457 return (edid[loc] & 0x1f) >= 5 ? loc + 4 : -1;
458 }
459
get_edid_hdmi_vsdb_location(const unsigned char * edid,unsigned size)460 static int get_edid_hdmi_vsdb_location(const unsigned char *edid, unsigned size)
461 {
462 int loc = get_edid_tag_location(edid, size, VSDB_TAG, HDMI_VSDB_EXT_TAG);
463
464 if (loc < 0)
465 return loc;
466
467 return (edid[loc] & 0x1f) >= 5 ? loc : -1;
468 }
469
get_edid_hf_vsdb_location(const unsigned char * edid,unsigned size)470 static int get_edid_hf_vsdb_location(const unsigned char *edid, unsigned size)
471 {
472 int loc = get_edid_tag_location(edid, size, VSDB_TAG, HF_VSDB_EXT_TAG);
473
474 if (loc < 0)
475 return loc;
476
477 return (edid[loc] & 0x1f) >= 6 ? loc + 5 : -1;
478 }
479
get_edid_speaker_location(const unsigned char * edid,unsigned size)480 static int get_edid_speaker_location(const unsigned char *edid, unsigned size)
481 {
482 int loc = get_edid_tag_location(edid, size, SPEAKER_TAG, 0);
483
484 if (loc < 0)
485 return loc;
486
487 return (edid[loc] & 0x1f) >= 3 ? loc + 1 : -1;
488 }
489
get_edid_vid_cap_location(const unsigned char * edid,unsigned size)490 static int get_edid_vid_cap_location(const unsigned char *edid, unsigned size)
491 {
492 int loc = get_edid_tag_location(edid, size, EXTENDED_TAG, VID_CAP_EXT_TAG);
493
494 if (loc < 0)
495 return loc;
496
497 return (edid[loc] & 0x1f) >= 2 ? loc + 2 : -1;
498 }
499
get_edid_colorimetry_location(const unsigned char * edid,unsigned size)500 static int get_edid_colorimetry_location(const unsigned char *edid, unsigned size)
501 {
502 int loc = get_edid_tag_location(edid, size, EXTENDED_TAG, COLORIMETRY_EXT_TAG);
503
504 if (loc < 0)
505 return loc;
506
507 return (edid[loc] & 0x1f) >= 3 ? loc + 2 : -1;
508 }
509
get_edid_hdr_md_location(const unsigned char * edid,unsigned size)510 static int get_edid_hdr_md_location(const unsigned char *edid, unsigned size)
511 {
512 int loc = get_edid_tag_location(edid, size, EXTENDED_TAG, HDR_MD_EXT_TAG);
513
514 if (loc < 0)
515 return loc;
516
517 return (edid[loc] & 0x1f) >= 3 ? loc + 2 : -1;
518 }
519
set_edid_phys_addr(unsigned char * edid,unsigned size,unsigned short phys_addr)520 static void set_edid_phys_addr(unsigned char *edid, unsigned size, unsigned short phys_addr)
521 {
522 int loc = get_edid_spa_location(edid, size);
523 unsigned char sum = 0;
524 int i;
525
526 if (loc < 0)
527 return;
528 edid[loc] = phys_addr >> 8;
529 edid[loc + 1] = phys_addr & 0xff;
530 loc &= ~0x7f;
531
532 for (i = loc; i < loc + 127; i++)
533 sum += edid[i];
534 edid[i] = 256 - sum;
535 }
536
get_edid_phys_addr(const unsigned char * edid,unsigned size)537 static unsigned short get_edid_phys_addr(const unsigned char *edid, unsigned size)
538 {
539 int loc = get_edid_spa_location(edid, size);
540
541 if (loc < 0)
542 return 0xffff;
543 return (edid[loc] << 8) | edid[loc + 1];
544 }
545
print_edid_mods(const struct v4l2_edid * e)546 static void print_edid_mods(const struct v4l2_edid *e)
547 {
548 unsigned short pa = get_edid_phys_addr(e->edid, e->blocks * 128);
549 int loc;
550
551 loc = get_edid_cta861_hdr_location(e->edid, e->blocks * 128);
552 if (loc >= 0) {
553 uint8_t v = e->edid[loc];
554
555 printf("\nCTA-861 Header\n");
556 printf(" IT Formats Underscanned: %s\n", (v & CTA861_HDR_UNDERSCAN) ? "yes" : "no");
557 printf(" Audio: %s\n", (v & CTA861_HDR_AUDIO) ? "yes" : "no");
558 printf(" YCbCr 4:4:4: %s\n", (v & CTA861_HDR_YCBCR444) ? "yes" : "no");
559 printf(" YCbCr 4:2:2: %s\n", (v & CTA861_HDR_YCBCR422) ? "yes" : "no");
560 }
561 loc = get_edid_speaker_location(e->edid, e->blocks * 128);
562 if (loc >= 0) {
563 uint8_t v = e->edid[loc];
564
565 printf("\nSpeaker Allocation Data Block\n");
566 printf(" FL/FR: %s\n", (v & SPEAKER1_FL_FR) ? "yes" : "no");
567 printf(" LFE: %s\n", (v & SPEAKER1_LFE) ? "yes" : "no");
568 printf(" FC: %s\n", (v & SPEAKER1_FC) ? "yes" : "no");
569 printf(" BL/BR: %s\n", (v & SPEAKER1_BL_BR) ? "yes" : "no");
570 printf(" BC: %s\n", (v & SPEAKER1_BC) ? "yes" : "no");
571 printf(" FLC/FRC: %s\n", (v & SPEAKER1_FLC_FRC) ? "yes" : "no");
572 printf(" RLC/RRC: %s\n", (v & SPEAKER1_RLC_RRC) ? "yes" : "no");
573 printf(" FLW/FRW: %s\n", (v & SPEAKER1_FLW_FRW) ? "yes" : "no");
574
575 v = e->edid[loc + 1];
576 printf(" TpFL/TpFR: %s\n", (v & SPEAKER2_TPFL_TPFR) ? "yes" : "no");
577 printf(" TpC: %s\n", (v & SPEAKER2_TPC) ? "yes" : "no");
578 printf(" TpFC: %s\n", (v & SPEAKER2_TPFC) ? "yes" : "no");
579 printf(" LS/RS: %s\n", (v & SPEAKER2_LS_RS) ? "yes" : "no");
580 printf(" LFE2: %s\n", (v & SPEAKER2_LFE2) ? "yes" : "no");
581 printf(" TpBC: %s\n", (v & SPEAKER2_TPBC) ? "yes" : "no");
582 printf(" SiL/SiR: %s\n", (v & SPEAKER2_SIL_SIR) ? "yes" : "no");
583 printf(" TpSiL/TpSiR: %s\n", (v & SPEAKER2_TPSIL_TPSIR) ? "yes" : "no");
584
585 v = e->edid[loc + 2];
586 printf(" TpBL/TpBR: %s\n", (v & SPEAKER3_TPBL_TPBR) ? "yes" : "no");
587 printf(" BtFC: %s\n", (v & SPEAKER3_BTFC) ? "yes" : "no");
588 printf(" BtLS/BtRS: %s\n", (v & SPEAKER3_BTFL_BTFR) ? "yes" : "no");
589 printf(" TpLS/TpRS: %s\n", (v & SPEAKER3_TPLS_TPRS) ? "yes" : "no");
590 }
591 loc = get_edid_hdmi_vsdb_location(e->edid, e->blocks * 128);
592 if (loc >= 0) {
593 uint8_t len = e->edid[loc] & 0x1f;
594 uint8_t v = len >= 7 ? e->edid[loc + 7] : 0;
595
596 printf("\nHDMI Vendor-Specific Data Block\n");
597 if (v)
598 printf(" Max TMDS Clock: %u MHz\n", v * 5);
599 printf(" Physical Address: %x.%x.%x.%x\n",
600 pa >> 12, (pa >> 8) & 0xf, (pa >> 4) & 0xf, pa & 0xf);
601 if (len >= 6) {
602 v = e->edid[loc + 6];
603 printf(" YCbCr 4:4:4 Deep Color: %s\n", (v & HDMI_VSDB_Y444_BIT) ? "yes" : "no");
604 printf(" 30-bit: %s\n", (v & HDMI_VSDB_30_BIT) ? "yes" : "no");
605 printf(" 36-bit: %s\n", (v & HDMI_VSDB_36_BIT) ? "yes" : "no");
606 printf(" 48-bit: %s\n", (v & HDMI_VSDB_48_BIT) ? "yes" : "no");
607 }
608 if (len >= 8) {
609 v = e->edid[loc + 8];
610 printf(" Graphics: %s\n", (v & HDMI_VSDB_GRAPHICS) ? "yes" : "no");
611 printf(" Photo: %s\n", (v & HDMI_VSDB_PHOTO) ? "yes" : "no");
612 printf(" Cinema: %s\n", (v & HDMI_VSDB_CINEMA) ? "yes" : "no");
613 printf(" Game: %s\n", (v & HDMI_VSDB_GAME) ? "yes" : "no");
614 if ((v & HDMI_VSDB_LATENCY) && len >= 10) {
615 uint8_t lat = e->edid[loc + 9];
616 if (lat == 255)
617 printf(" Video Latency: unsupported\n");
618 else if (lat > 0)
619 printf(" Video Latency: %u.%ums\n",
620 (lat - 1) / 2, ((lat - 1) & 1) ? 0 : 5);
621 lat = e->edid[loc + 10];
622 if (lat == 255)
623 printf(" Audio Latency: unsupported\n");
624 else if (lat > 0)
625 printf(" Audio Latency: %u.%ums\n",
626 (lat - 1) / 2, ((lat - 1) & 1) ? 0 : 5);
627 }
628 if ((v & HDMI_VSDB_I_LATENCY) && len >= 12) {
629 uint8_t lat = e->edid[loc + 11];
630 if (lat == 255)
631 printf(" IL Video Latency: unsupported\n");
632 else if (lat > 0)
633 printf(" IL Video Latency: %u.%ums\n",
634 (lat - 1) / 2, ((lat - 1) & 1) ? 0 : 5);
635 lat = e->edid[loc + 12];
636 if (lat == 255)
637 printf(" IL Audio Latency: unsupported\n");
638 else if (lat > 0)
639 printf(" IL Audio Latency: %u.%ums\n",
640 (lat - 1) / 2, ((lat - 1) & 1) ? 0 : 5);
641 }
642 }
643 }
644 loc = get_edid_hf_vsdb_location(e->edid, e->blocks * 128);
645 if (loc >= 0) {
646 uint8_t v = e->edid[loc];
647
648 printf("\nHDMI Forum Vendor-Specific Data Block\n");
649 if (v)
650 printf(" Max TMDS Character Rate: %u MHz\n", v * 5);
651 v = e->edid[loc + 1];
652 printf(" SCDC Present: %s\n", (v & HF_VSDB_SCSD_PRESENT) ? "yes" : "no");
653 }
654 loc = get_edid_vid_cap_location(e->edid, e->blocks * 128);
655 if (loc >= 0) {
656 static const char *pt_scan[] = {
657 "No Data",
658 "Always Overscanned",
659 "Always Underscanned",
660 "Supports both over- and underscan"
661 };
662 static const char *it_scan[] = {
663 "IT Formats not supported",
664 "Always Overscanned",
665 "Always Underscanned",
666 "Supports both over- and underscan"
667 };
668 static const char *ce_scan[] = {
669 "CE Formats not supported",
670 "Always Overscanned",
671 "Always Underscanned",
672 "Supports both over- and underscan"
673 };
674 uint8_t v = e->edid[loc];
675
676 printf("\nCTA-861 Video Capability Descriptor\n");
677 printf(" RGB Quantization Range: %s\n", (v & VID_CAP_QS) ? "yes" : "no");
678 printf(" YCC Quantization Range: %s\n", (v & VID_CAP_QY) ? "yes" : "no");
679 printf(" PT: %s\n", pt_scan[(v >> 4) & 3]);
680 printf(" IT: %s\n", it_scan[(v >> 2) & 3]);
681 printf(" CE: %s\n", ce_scan[(v >> 0) & 3]);
682 }
683 loc = get_edid_colorimetry_location(e->edid, e->blocks * 128);
684 if (loc >= 0) {
685 uint8_t v1 = e->edid[loc];
686 uint8_t v2 = e->edid[loc + 1];
687
688 printf("\nCTA-861 Colorimetry Data Block\n");
689 printf(" xvYCC 601: %s\n", (v1 & COLORIMETRY_XVYCC601) ? "yes" : "no");
690 printf(" xvYCC 709: %s\n", (v1 & COLORIMETRY_XVYCC709) ? "yes" : "no");
691 printf(" sYCC: %s\n", (v1 & COLORIMETRY_SYCC) ? "yes" : "no");
692 printf(" opRGB: %s\n", (v1 & COLORIMETRY_OPRGB) ? "yes" : "no");
693 printf(" opYCC: %s\n", (v1 & COLORIMETRY_OPYCC) ? "yes" : "no");
694 printf(" BT.2020 RGB: %s\n", (v1 & COLORIMETRY_BT2020RGB) ? "yes" : "no");
695 printf(" BT.2020 YCC: %s\n", (v1 & COLORIMETRY_BT2020YCC) ? "yes" : "no");
696 printf(" BT.2020 cYCC: %s\n", (v1 & COLORIMETRY_BT2020CYCC) ? "yes" : "no");
697 printf(" DCI-P3: %s\n", (v2 & COLORIMETRY_DCIP3) ? "yes" : "no");
698 }
699 loc = get_edid_hdr_md_location(e->edid, e->blocks * 128);
700 if (loc >= 0) {
701 uint8_t v = e->edid[loc];
702
703 printf("\nCTA-861 HDR Static Metadata Data Block\n");
704 printf(" SDR (Traditional Gamma): %s\n", (v & HDR_MD_SDR) ? "yes" : "no");
705 printf(" HDR (Traditional Gamma): %s\n", (v & HDR_MD_HDR) ? "yes" : "no");
706 printf(" SMPTE 2084: %s\n", (v & HDR_MD_SMPTE_2084) ? "yes" : "no");
707 printf(" Hybrid Log-Gamma: %s\n", (v & HDR_MD_HLG) ? "yes" : "no");
708 }
709 }
710
parse_phys_addr(const char * value)711 static unsigned short parse_phys_addr(const char *value)
712 {
713 unsigned p1, p2, p3, p4;
714
715 if (!std::strchr(value, '.'))
716 return strtoul(value, NULL, 0);
717 if (sscanf(value, "%x.%x.%x.%x", &p1, &p2, &p3, &p4) != 4) {
718 fprintf(stderr, "Expected a physical address of the form x.x.x.x\n");
719 return 0xffff;
720 }
721 if (p1 > 0xf || p2 > 0xf || p3 > 0xf || p4 > 0xf) {
722 fprintf(stderr, "Physical address components should never be larger than 0xf\n");
723 return 0xffff;
724 }
725 return (p1 << 12) | (p2 << 8) | (p3 << 4) | p4;
726 }
727
728 /****************** EDIDs *****************************/
729 static uint8_t vga_edid[128] = {
730 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
731 0x31, 0xd8, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00,
732 0x22, 0x1a, 0x01, 0x04, 0x08, 0x30, 0x1e, 0x78,
733 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26,
734 0x0f, 0x50, 0x54, 0x2f, 0xcf, 0x00, 0x31, 0x59,
735 0x45, 0x59, 0x61, 0x59, 0x81, 0x40, 0x81, 0x80,
736 0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x28, 0x3c,
737 0x80, 0xa0, 0x70, 0xb0, 0x23, 0x40, 0x30, 0x20,
738 0x36, 0x00, 0xe0, 0x2c, 0x11, 0x00, 0x00, 0x1a,
739 0x00, 0x00, 0x00, 0xfd, 0x00, 0x31, 0x55, 0x18,
740 0x5e, 0x11, 0x04, 0x12, 0x00, 0xf0, 0xf8, 0x58,
741 0xf0, 0x3c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x76,
742 0x67, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
743 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x10,
744 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
745 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce,
746 };
747
748 static uint8_t dvid_edid[128] = {
749 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
750 0x31, 0xd8, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00,
751 0x22, 0x1a, 0x01, 0x04, 0xa1, 0x30, 0x1e, 0x78,
752 0x07, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26,
753 0x0f, 0x50, 0x54, 0x2f, 0xcf, 0x00, 0x31, 0x59,
754 0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40,
755 0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x28, 0x3c,
756 0x80, 0xa0, 0x70, 0xb0, 0x23, 0x40, 0x30, 0x20,
757 0x36, 0x00, 0xe0, 0x2c, 0x11, 0x00, 0x00, 0x1a,
758 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18,
759 0x5e, 0x11, 0x04, 0x12, 0x00, 0xf0, 0xf8, 0x58,
760 0xf0, 0x3c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x64,
761 0x76, 0x69, 0x2d, 0x64, 0x0a, 0x20, 0x20, 0x20,
762 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x10,
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea,
765 };
766
767 static uint8_t hdmi_edid[256] = {
768 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
769 0x31, 0xd8, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00,
770 0x22, 0x1a, 0x01, 0x03, 0x80, 0x30, 0x1b, 0x78,
771 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26,
772 0x0f, 0x50, 0x54, 0x2f, 0xcf, 0x00, 0x31, 0x59,
773 0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40,
774 0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x02, 0x3a,
775 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
776 0x45, 0x00, 0xe0, 0x0e, 0x11, 0x00, 0x00, 0x1e,
777 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18,
778 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20,
779 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x68,
780 0x64, 0x6d, 0x69, 0x0a, 0x20, 0x20, 0x20, 0x20,
781 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x10,
782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
783 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4,
784
785 0x02, 0x03, 0x2d, 0xf0, 0x4c, 0x10, 0x1f, 0x04,
786 0x13, 0x22, 0x21, 0x20, 0x05, 0x14, 0x02, 0x11,
787 0x01, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00,
788 0x00, 0x68, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x00,
789 0x22, 0x01, 0xe2, 0x00, 0xea, 0xe3, 0x05, 0x00,
790 0x00, 0xe3, 0x06, 0x01, 0x00, 0x1a, 0x36, 0x80,
791 0xa0, 0x70, 0x38, 0x1f, 0x40, 0x30, 0x20, 0x35,
792 0x00, 0xe0, 0x0e, 0x11, 0x00, 0x00, 0x1a, 0x1a,
793 0x1d, 0x00, 0x80, 0x51, 0xd0, 0x1c, 0x20, 0x40,
794 0x80, 0x35, 0x00, 0xe0, 0x0e, 0x11, 0x00, 0x00,
795 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
796 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
797 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d,
801 };
802
803 static uint8_t hdmi_edid_4k_170[256] = {
804 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
805 0x31, 0xd8, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00,
806 0x22, 0x1a, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
807 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26,
808 0x0f, 0x50, 0x54, 0x2f, 0xcf, 0x00, 0x31, 0x59,
809 0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40,
810 0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x02, 0x3a,
811 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
812 0x46, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e,
813 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18,
814 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20,
815 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x68,
816 0x64, 0x6d, 0x69, 0x2d, 0x34, 0x6b, 0x2d, 0x31,
817 0x37, 0x30, 0x0a, 0x20, 0x00, 0x00, 0x00, 0x10,
818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb8,
820
821 0x02, 0x03, 0x32, 0xf0, 0x4c, 0x10, 0x1f, 0x04,
822 0x13, 0x22, 0x21, 0x20, 0x05, 0x14, 0x02, 0x11,
823 0x01, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00,
824 0x00, 0x68, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x00,
825 0x22, 0x01, 0xe2, 0x00, 0xea, 0xe4, 0x0e, 0x5f,
826 0x5e, 0x5d, 0xe3, 0x05, 0x00, 0x00, 0xe3, 0x06,
827 0x01, 0x00, 0x1a, 0x36, 0x80, 0xa0, 0x70, 0x38,
828 0x1f, 0x40, 0x30, 0x20, 0x35, 0x00, 0xc0, 0x1c,
829 0x32, 0x00, 0x00, 0x1a, 0x1a, 0x1d, 0x00, 0x80,
830 0x51, 0xd0, 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00,
831 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1c, 0x00, 0x00,
832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
835 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
836 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e,
837 };
838
839 static uint8_t hdmi_edid_4k_300[256] = {
840 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
841 0x31, 0xd8, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00,
842 0x22, 0x1a, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
843 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26,
844 0x0f, 0x50, 0x54, 0x2f, 0xcf, 0x00, 0x31, 0x59,
845 0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40,
846 0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x04, 0x74,
847 0x00, 0x30, 0xf2, 0x70, 0x5a, 0x80, 0xb0, 0x58,
848 0x8a, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e,
849 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18,
850 0x87, 0x1e, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20,
851 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x68,
852 0x64, 0x6d, 0x69, 0x2d, 0x34, 0x6b, 0x2d, 0x33,
853 0x30, 0x30, 0x0a, 0x20, 0x00, 0x00, 0x00, 0x10,
854 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc5,
856
857 0x02, 0x03, 0x3d, 0xf0, 0x4f, 0x5f, 0x5e, 0x5d,
858 0x10, 0x1f, 0x04, 0x13, 0x22, 0x21, 0x20, 0x05,
859 0x14, 0x02, 0x11, 0x01, 0x23, 0x09, 0x07, 0x07,
860 0x83, 0x01, 0x00, 0x00, 0x6d, 0x03, 0x0c, 0x00,
861 0x10, 0x00, 0x00, 0x3c, 0x21, 0x00, 0x60, 0x01,
862 0x02, 0x03, 0x67, 0xd8, 0x5d, 0xc4, 0x01, 0x00,
863 0x00, 0x00, 0xe2, 0x00, 0xea, 0xe3, 0x05, 0x00,
864 0x00, 0xe3, 0x06, 0x01, 0x00, 0xa3, 0x66, 0x00,
865 0xa0, 0xf0, 0x70, 0x1f, 0x80, 0x30, 0x20, 0x35,
866 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e, 0x1a,
867 0x36, 0x80, 0xa0, 0x70, 0x38, 0x1f, 0x40, 0x30,
868 0x20, 0x35, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00,
869 0x1a, 0x1a, 0x1d, 0x00, 0x80, 0x51, 0xd0, 0x1c,
870 0x20, 0x40, 0x80, 0x35, 0x00, 0xc0, 0x1c, 0x32,
871 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
872 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3,
873 };
874
875 static uint8_t hdmi_edid_4k_600[256] = {
876 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
877 0x31, 0xd8, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00,
878 0x22, 0x1a, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
879 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26,
880 0x0f, 0x50, 0x54, 0x2f, 0xcf, 0x00, 0x31, 0x59,
881 0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40,
882 0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x08, 0xe8,
883 0x00, 0x30, 0xf2, 0x70, 0x5a, 0x80, 0xb0, 0x58,
884 0x8a, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e,
885 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18,
886 0x87, 0x3c, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20,
887 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x68,
888 0x64, 0x6d, 0x69, 0x2d, 0x34, 0x6b, 0x2d, 0x36,
889 0x30, 0x30, 0x0a, 0x20, 0x00, 0x00, 0x00, 0x10,
890 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
891 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2c,
892
893 0x02, 0x03, 0x3f, 0xf0, 0x51, 0x61, 0x60, 0x5f,
894 0x5e, 0x5d, 0x10, 0x1f, 0x04, 0x13, 0x22, 0x21,
895 0x20, 0x05, 0x14, 0x02, 0x11, 0x01, 0x23, 0x09,
896 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x6d, 0x03,
897 0x0c, 0x00, 0x10, 0x00, 0x00, 0x3c, 0x21, 0x00,
898 0x60, 0x01, 0x02, 0x03, 0x67, 0xd8, 0x5d, 0xc4,
899 0x01, 0x78, 0x00, 0x00, 0xe2, 0x00, 0xea, 0xe3,
900 0x05, 0x00, 0x00, 0xe3, 0x06, 0x01, 0x00, 0x4d,
901 0xd0, 0x00, 0xa0, 0xf0, 0x70, 0x3e, 0x80, 0x30,
902 0x20, 0x35, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00,
903 0x1e, 0x1a, 0x36, 0x80, 0xa0, 0x70, 0x38, 0x1f,
904 0x40, 0x30, 0x20, 0x35, 0x00, 0xc0, 0x1c, 0x32,
905 0x00, 0x00, 0x1a, 0x1a, 0x1d, 0x00, 0x80, 0x51,
906 0xd0, 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0xc0,
907 0x1c, 0x32, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
908 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63,
909 };
910
911 /******************************************************/
912
edid_cmd(int ch,char * optarg)913 void edid_cmd(int ch, char *optarg)
914 {
915 char *value, *subs;
916
917 switch (ch) {
918 case OptSetEdid:
919 memset(&sedid, 0, sizeof(sedid));
920 file_in = NULL;
921 if (!optarg)
922 break;
923 subs = optarg;
924 while (*subs != '\0') {
925 static const char *const subopts[] = {
926 "pad",
927 "type",
928 "edid",
929 "file",
930 "format",
931 "pa",
932 "s-pt",
933 "s-it",
934 "s-ce",
935 "y444",
936 "30-bit",
937 "36-bit",
938 "48-bit",
939 "graphics",
940 "photo",
941 "cinema",
942 "game",
943 "scdc",
944 "underscan",
945 "audio",
946 "ycbcr444",
947 "ycbcr422",
948 "qy",
949 "qs",
950 "xvycc-601",
951 "xvycc-709",
952 "sycc",
953 "opycc",
954 "oprgb",
955 "bt2020-rgb",
956 "bt2020-ycc",
957 "bt2020-cycc",
958 "dci-p3",
959 "sdr",
960 "hdr",
961 "smpte2084",
962 "hlg",
963 "fl-fr",
964 "lfe",
965 "fc",
966 "bl-br",
967 "bc",
968 "flc-frc",
969 "rlc-rrc",
970 "flw-frw",
971 "tpfl-tpfr",
972 "tpc",
973 "tpfc",
974 "ls-rs",
975 "lfe2",
976 "tpbc",
977 "sil-sir",
978 "tpsil-tpsir",
979 "tpbl-tpbr",
980 "btfc",
981 "btfl-btbr",
982 "tpls-tprs",
983 NULL
984 };
985
986 int opt = getsubopt(&subs, (char* const*)subopts, &value);
987
988 if (opt == -1) {
989 fprintf(stderr, "Invalid suboptions specified\n");
990 edid_usage();
991 std::exit(EXIT_FAILURE);
992 }
993 if (value == NULL && opt <= 8) {
994 fprintf(stderr, "No value given to suboption <%s>\n",
995 subopts[opt]);
996 edid_usage();
997 std::exit(EXIT_FAILURE);
998 }
999 switch (opt) {
1000 case 0:
1001 sedid.pad = strtoul(value, 0, 0);
1002 break;
1003 case 1:
1004 case 2: /* keep edid for compat reasons, it's the same as type */
1005 if (!strcmp(value, "dvid")) {
1006 sedid.edid = dvid_edid;
1007 sedid.blocks = sizeof(dvid_edid) / 128;
1008 } else if (!strcmp(value, "vga")) {
1009 sedid.edid = vga_edid;
1010 sedid.blocks = sizeof(vga_edid) / 128;
1011 } else if (!strcmp(value, "hdmi-4k-170mhz")) {
1012 sedid.edid = hdmi_edid_4k_170;
1013 sedid.blocks = sizeof(hdmi_edid) / 128;
1014 } else if (!strcmp(value, "hdmi-4k-300mhz")) {
1015 sedid.edid = hdmi_edid_4k_300;
1016 sedid.blocks = sizeof(hdmi_edid) / 128;
1017 } else if (!strcmp(value, "hdmi-4k-600mhz")) {
1018 sedid.edid = hdmi_edid_4k_600;
1019 sedid.blocks = sizeof(hdmi_edid) / 128;
1020 } else if (!strcmp(value, "hdmi")) {
1021 sedid.edid = hdmi_edid;
1022 sedid.blocks = sizeof(hdmi_edid) / 128;
1023 } else {
1024 edid_usage();
1025 std::exit(EXIT_FAILURE);
1026 }
1027 if (file_in) {
1028 fprintf(stderr, "The edid and file options can't be used together.\n");
1029 std::exit(EXIT_FAILURE);
1030 }
1031 break;
1032 case 3:
1033 if (value) {
1034 file_in = value;
1035 if (sedid.edid) {
1036 fprintf(stderr, "The edid and file options can't be used together.\n");
1037 std::exit(EXIT_FAILURE);
1038 }
1039 }
1040 break;
1041 case 4:
1042 if (!strcmp(value, "hex")) {
1043 sformat = HEX;
1044 } else if (!strcmp(value, "raw")) {
1045 sformat = RAW;
1046 } else {
1047 edid_usage();
1048 std::exit(EXIT_FAILURE);
1049 }
1050 break;
1051 case 5:
1052 if (value)
1053 phys_addr = parse_phys_addr(value);
1054 break;
1055 case 6:
1056 mod_s_pt = strtoul(value, 0, 0) & 3;
1057 break;
1058 case 7:
1059 mod_s_it = strtoul(value, 0, 0) & 3;
1060 break;
1061 case 8:
1062 mod_s_ce = strtoul(value, 0, 0) & 3;
1063 break;
1064 case 9: toggle_hdmi_vsdb_dc_flags |= HDMI_VSDB_Y444_BIT; break;
1065 case 10: toggle_hdmi_vsdb_dc_flags |= HDMI_VSDB_30_BIT; break;
1066 case 11: toggle_hdmi_vsdb_dc_flags |= HDMI_VSDB_36_BIT; break;
1067 case 12: toggle_hdmi_vsdb_dc_flags |= HDMI_VSDB_48_BIT; break;
1068 case 13: toggle_hdmi_vsdb_cnc_flags |= HDMI_VSDB_GRAPHICS; break;
1069 case 14: toggle_hdmi_vsdb_cnc_flags |= HDMI_VSDB_PHOTO; break;
1070 case 15: toggle_hdmi_vsdb_cnc_flags |= HDMI_VSDB_CINEMA; break;
1071 case 16: toggle_hdmi_vsdb_cnc_flags |= HDMI_VSDB_GAME; break;
1072 case 17: toggle_hf_vsdb_flags |= HF_VSDB_SCSD_PRESENT; break;
1073 case 18: toggle_cta861_hdr_flags |= CTA861_HDR_UNDERSCAN; break;
1074 case 19: toggle_cta861_hdr_flags |= CTA861_HDR_AUDIO; break;
1075 case 20: toggle_cta861_hdr_flags |= CTA861_HDR_YCBCR444; break;
1076 case 21: toggle_cta861_hdr_flags |= CTA861_HDR_YCBCR422; break;
1077 case 22: toggle_vid_cap_flags |= VID_CAP_QY; break;
1078 case 23: toggle_vid_cap_flags |= VID_CAP_QS; break;
1079 case 24: toggle_colorimetry_flags1 |= COLORIMETRY_XVYCC601; break;
1080 case 25: toggle_colorimetry_flags1 |= COLORIMETRY_XVYCC709; break;
1081 case 26: toggle_colorimetry_flags1 |= COLORIMETRY_SYCC; break;
1082 case 27: toggle_colorimetry_flags1 |= COLORIMETRY_OPYCC; break;
1083 case 28: toggle_colorimetry_flags1 |= COLORIMETRY_OPRGB; break;
1084 case 29: toggle_colorimetry_flags1 |= COLORIMETRY_BT2020RGB; break;
1085 case 30: toggle_colorimetry_flags1 |= COLORIMETRY_BT2020YCC; break;
1086 case 31: toggle_colorimetry_flags1 |= COLORIMETRY_BT2020CYCC; break;
1087 case 32: toggle_colorimetry_flags2 |= COLORIMETRY_DCIP3; break;
1088 case 33: toggle_hdr_md_flags |= HDR_MD_SDR; break;
1089 case 34: toggle_hdr_md_flags |= HDR_MD_HDR; break;
1090 case 35: toggle_hdr_md_flags |= HDR_MD_SMPTE_2084; break;
1091 case 36: toggle_hdr_md_flags |= HDR_MD_HLG; break;
1092 case 37: toggle_speaker1_flags |= SPEAKER1_FL_FR; break;
1093 case 38: toggle_speaker1_flags |= SPEAKER1_LFE; break;
1094 case 39: toggle_speaker1_flags |= SPEAKER1_FC; break;
1095 case 40: toggle_speaker1_flags |= SPEAKER1_BL_BR; break;
1096 case 41: toggle_speaker1_flags |= SPEAKER1_BC; break;
1097 case 42: toggle_speaker1_flags |= SPEAKER1_FLC_FRC; break;
1098 case 43: toggle_speaker1_flags |= SPEAKER1_RLC_RRC; break;
1099 case 44: toggle_speaker1_flags |= SPEAKER1_FLW_FRW; break;
1100 case 45: toggle_speaker2_flags |= SPEAKER2_TPFL_TPFR; break;
1101 case 46: toggle_speaker2_flags |= SPEAKER2_TPC; break;
1102 case 47: toggle_speaker2_flags |= SPEAKER2_TPFC; break;
1103 case 48: toggle_speaker2_flags |= SPEAKER2_LS_RS; break;
1104 case 49: toggle_speaker2_flags |= SPEAKER2_LFE2; break;
1105 case 50: toggle_speaker2_flags |= SPEAKER2_TPBC; break;
1106 case 51: toggle_speaker2_flags |= SPEAKER2_SIL_SIR; break;
1107 case 52: toggle_speaker2_flags |= SPEAKER2_TPSIL_TPSIR; break;
1108 case 53: toggle_speaker3_flags |= SPEAKER3_TPBL_TPBR; break;
1109 case 54: toggle_speaker3_flags |= SPEAKER3_BTFC; break;
1110 case 55: toggle_speaker3_flags |= SPEAKER3_BTFL_BTFR; break;
1111 case 56: toggle_speaker3_flags |= SPEAKER3_TPLS_TPRS; break;
1112 default:
1113 edid_usage();
1114 std::exit(EXIT_FAILURE);
1115 }
1116 }
1117 break;
1118
1119 case OptClearEdid:
1120 if (optarg)
1121 clear_pad = strtoul(optarg, 0, 0);
1122 break;
1123
1124 case OptGetEdid:
1125 memset(&gedid, 0, sizeof(gedid));
1126 gedid.blocks = 256; /* default all blocks */
1127 gformat = HEX; /* default hex output */
1128 file_out = NULL;
1129 if (!optarg)
1130 break;
1131 subs = optarg;
1132 while (*subs != '\0') {
1133 static const char *const subopts[] = {
1134 "pad",
1135 "startblock",
1136 "blocks",
1137 "format",
1138 "file",
1139 NULL
1140 };
1141
1142 switch (parse_subopt(&subs, subopts, &value)) {
1143 case 0:
1144 gedid.pad = strtoul(value, 0, 0);
1145 break;
1146 case 1:
1147 gedid.start_block = strtoul(value, 0, 0);
1148 if (gedid.start_block > 255) {
1149 fprintf(stderr, "startblock %d too large, max 255\n", gedid.start_block);
1150 std::exit(EXIT_FAILURE);
1151 }
1152 break;
1153 case 2:
1154 gedid.blocks = strtoul(value, 0, 0);
1155 break;
1156 case 3:
1157 if (!strcmp(value, "hex")) {
1158 gformat = HEX;
1159 } else if (!strcmp(value, "raw")) {
1160 gformat = RAW;
1161 } else if (!strcmp(value, "carray")) {
1162 gformat = CARRAY;
1163 } else {
1164 edid_usage();
1165 std::exit(EXIT_FAILURE);
1166 }
1167 break;
1168 case 4:
1169 if (value)
1170 file_out = value;
1171 break;
1172 default:
1173 edid_usage();
1174 std::exit(EXIT_FAILURE);
1175 }
1176 }
1177 if (gedid.start_block + gedid.blocks > 256)
1178 gedid.blocks = 256 - gedid.start_block;
1179 break;
1180
1181 case OptInfoEdid:
1182 memset(&info_edid, 0, sizeof(info_edid));
1183 if (optarg)
1184 info_edid.pad = strtoul(optarg, 0, 0);
1185 break;
1186 }
1187 }
1188
edid_set(cv4l_fd & _fd)1189 void edid_set(cv4l_fd &_fd)
1190 {
1191 int fd = _fd.g_fd();
1192 int loc;
1193
1194 if (options[OptClearEdid]) {
1195 struct v4l2_edid edid;
1196
1197 memset(&edid, 0, sizeof(edid));
1198 edid.pad = clear_pad;
1199 doioctl(fd, VIDIOC_S_EDID, &edid);
1200 }
1201
1202 if (options[OptSetEdid]) {
1203 FILE *fin = NULL;
1204 bool must_fix_edid = options[OptFixEdidChecksums];
1205
1206 if (file_in) {
1207 if (!strcmp(file_in, "-"))
1208 fin = stdin;
1209 else
1210 fin = fopen(file_in, "r");
1211 if (!fin) {
1212 fprintf(stderr, "Failed to open %s: %s\n", file_in,
1213 strerror(errno));
1214 std::exit(EXIT_FAILURE);
1215 }
1216 }
1217 if (fin) {
1218 read_edid_file(fin, &sedid);
1219 if (sedid.blocks == 0) {
1220 fprintf(stderr, "%s contained an empty EDID, ignoring.\n",
1221 file_in ? file_in : "stdin");
1222 std::exit(EXIT_FAILURE);
1223 }
1224 }
1225 if (toggle_cta861_hdr_flags || phys_addr >= 0) {
1226 loc = get_edid_cta861_hdr_location(sedid.edid, sedid.blocks * 128);
1227 if (loc >= 0) {
1228 sedid.edid[loc] ^= toggle_cta861_hdr_flags;
1229 if (phys_addr >= 0)
1230 set_edid_phys_addr(sedid.edid, sedid.blocks * 128, phys_addr);
1231 must_fix_edid = true;
1232 }
1233 }
1234 if (toggle_speaker1_flags || toggle_speaker2_flags || toggle_speaker3_flags) {
1235 loc = get_edid_speaker_location(sedid.edid, sedid.blocks * 128);
1236 if (loc >= 0) {
1237 sedid.edid[loc] ^= toggle_speaker1_flags;
1238 sedid.edid[loc + 1] ^= toggle_speaker2_flags;
1239 sedid.edid[loc + 2] ^= toggle_speaker3_flags;
1240 must_fix_edid = true;
1241 }
1242 }
1243 if (toggle_hdmi_vsdb_dc_flags || toggle_hdmi_vsdb_cnc_flags) {
1244 loc = get_edid_hdmi_vsdb_location(sedid.edid, sedid.blocks * 128);
1245
1246 if (loc >= 0) {
1247 uint8_t len = sedid.edid[loc] & 0x1f;
1248
1249 if (len >= 6) {
1250 sedid.edid[loc + 6] ^= toggle_hdmi_vsdb_dc_flags;
1251 must_fix_edid = true;
1252 }
1253 if (len >= 8) {
1254 sedid.edid[loc + 8] ^= toggle_hdmi_vsdb_cnc_flags;
1255 must_fix_edid = true;
1256 }
1257 }
1258 }
1259 if (toggle_hf_vsdb_flags) {
1260 loc = get_edid_hf_vsdb_location(sedid.edid, sedid.blocks * 128);
1261 if (loc >= 0) {
1262 sedid.edid[loc + 1] ^= toggle_hf_vsdb_flags;
1263 must_fix_edid = true;
1264 }
1265 }
1266 if (toggle_vid_cap_flags || mod_s_pt >= 0 ||
1267 mod_s_ce >= 0 || mod_s_it >= 0) {
1268 loc = get_edid_vid_cap_location(sedid.edid, sedid.blocks * 128);
1269 if (loc >= 0) {
1270 sedid.edid[loc] ^= toggle_vid_cap_flags;
1271 if (mod_s_ce >= 0) {
1272 sedid.edid[loc] &= 0xfc;
1273 sedid.edid[loc] |= mod_s_ce << 0;
1274 }
1275 if (mod_s_it >= 0) {
1276 sedid.edid[loc] &= 0xf3;
1277 sedid.edid[loc] |= mod_s_it << 2;
1278 }
1279 if (mod_s_pt >= 0) {
1280 sedid.edid[loc] &= 0xcf;
1281 sedid.edid[loc] |= mod_s_pt << 4;
1282 }
1283 must_fix_edid = true;
1284 }
1285 }
1286 if (toggle_colorimetry_flags1 || toggle_colorimetry_flags2) {
1287 loc = get_edid_colorimetry_location(sedid.edid, sedid.blocks * 128);
1288 if (loc >= 0) {
1289 sedid.edid[loc] ^= toggle_colorimetry_flags1;
1290 sedid.edid[loc + 1] ^= toggle_colorimetry_flags2;
1291 must_fix_edid = true;
1292 }
1293 }
1294 if (toggle_hdr_md_flags) {
1295 loc = get_edid_hdr_md_location(sedid.edid, sedid.blocks * 128);
1296 if (loc >= 0) {
1297 sedid.edid[loc] ^= toggle_hdr_md_flags;
1298 must_fix_edid = true;
1299 }
1300 }
1301 if (must_fix_edid)
1302 fix_edid(&sedid);
1303 print_edid_mods(&sedid);
1304 if (verify_edid(&sedid))
1305 doioctl(fd, VIDIOC_S_EDID, &sedid);
1306 else
1307 fprintf(stderr, "EDID not set due to checksum errors\n");
1308 if (fin) {
1309 if (sedid.edid) {
1310 free(sedid.edid);
1311 sedid.edid = NULL;
1312 }
1313 if (fin != stdin)
1314 fclose(fin);
1315 }
1316 }
1317 }
1318
edid_get(cv4l_fd & _fd)1319 void edid_get(cv4l_fd &_fd)
1320 {
1321 int fd = _fd.g_fd();
1322
1323 if (options[OptGetEdid]) {
1324 FILE *fout = stdout;
1325
1326 if (file_out) {
1327 if (!strcmp(file_out, "-"))
1328 fout = stdout;
1329 else
1330 fout = fopen(file_out, "w+");
1331 if (!fout) {
1332 fprintf(stderr, "Failed to open %s: %s\n", file_out,
1333 strerror(errno));
1334 std::exit(EXIT_FAILURE);
1335 }
1336 }
1337 gedid.edid = static_cast<unsigned char *>(malloc(gedid.blocks * 128));
1338 if (doioctl(fd, VIDIOC_G_EDID, &gedid) == 0) {
1339 if (options[OptFixEdidChecksums])
1340 fix_edid(&gedid);
1341 printedid(fout, &gedid, gformat);
1342 }
1343 if (file_out && fout != stdout)
1344 fclose(fout);
1345 free(gedid.edid);
1346 }
1347 if (options[OptInfoEdid]) {
1348 info_edid.blocks = 2;
1349 info_edid.edid = static_cast<unsigned char *>(malloc(info_edid.blocks * 128));
1350 if (doioctl(fd, VIDIOC_G_EDID, &info_edid) == 0)
1351 print_edid_mods(&info_edid);
1352 free(info_edid.edid);
1353 }
1354 }
1355