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