edid-decode: print hdmi 3d audio max channels same as SAT
[edid-decode.git] / parse-displayid-block.cpp
blob75a4eb5789b8f5b31145f89c8989f5ba1066760a
1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright 2006-2012 Red Hat, Inc.
4 * Copyright 2018-2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 * Author: Adam Jackson <ajax@nwnk.net>
7 * Maintainer: Hans Verkuil <hverkuil-cisco@xs4all.nl>
8 */
10 #include <math.h>
12 #include "edid-decode.h"
14 static const char *bpc444[] = {"6", "8", "10", "12", "14", "16", NULL, NULL};
15 static const char *bpc4xx[] = {"8", "10", "12", "14", "16", NULL, NULL, NULL};
16 static const char *audiorates[] = {"32", "44.1", "48", NULL, NULL, NULL, NULL, NULL};
18 // misc functions
20 static void print_flags(const char *label, unsigned char flag_byte,
21 const char **flags, bool reverse = false)
23 if (!flag_byte)
24 return;
26 unsigned countflags = 0;
28 printf("%s: ", label);
29 for (unsigned i = 0; i < 8; i++) {
30 if (flag_byte & (1 << (reverse ? 7 - i : i))) {
31 if (countflags)
32 printf(", ");
33 if (flags[i])
34 printf("%s", flags[i]);
35 else
36 printf("Undefined (%u)", i);
37 countflags++;
40 printf("\n");
43 void edid_state::check_displayid_datablock_revision(unsigned char hdr,
44 unsigned char valid_flags,
45 unsigned char rev)
47 unsigned char revision = hdr & 7;
48 unsigned char flags = hdr & ~7 & ~valid_flags;
50 if (revision != rev)
51 warn("Unexpected revision (%u != %u).\n", revision, rev);
52 if (flags)
53 warn("Unexpected flags (0x%02x).\n", flags);
56 static bool check_displayid_datablock_length(const unsigned char *x,
57 unsigned expectedlenmin = 0,
58 unsigned expectedlenmax = 128 - 2 - 5 - 3,
59 unsigned payloaddumpstart = 0)
61 unsigned char len = x[2];
63 if (expectedlenmin == expectedlenmax && len != expectedlenmax)
64 fail("DisplayID payload length is different than expected (%d != %d).\n", len, expectedlenmax);
65 else if (len > expectedlenmax)
66 fail("DisplayID payload length is greater than expected (%d > %d).\n", len, expectedlenmax);
67 else if (len < expectedlenmin)
68 fail("DisplayID payload length is less than expected (%d < %d).\n", len, expectedlenmin);
69 else
70 return true;
72 if (len > payloaddumpstart)
73 hex_block(" ", x + 3 + payloaddumpstart, len - payloaddumpstart);
74 return false;
77 // tag 0x00 and 0x20
79 void edid_state::parse_displayid_product_id(const unsigned char *x)
81 check_displayid_datablock_revision(x[1]);
83 dispid.has_product_identification = true;
84 printf(" Product Code: %u\n", x[6] | (x[7] << 8));
85 unsigned sn = x[8] | (x[9] << 8) | (x[10] << 16) | (x[11] << 24);
86 if (sn) {
87 if (hide_serial_numbers)
88 printf(" Serial Number: ...\n");
89 else
90 printf(" Serial Number: %u\n", sn);
92 unsigned week = x[12];
93 unsigned year = 2000 + x[13];
94 printf(" %s: %u",
95 week == 0xff ? "Model Year" : "Year of Manufacture", year);
96 if (week && week <= 0x36)
97 printf(", Week %u", week);
98 printf("\n");
99 if (x[14]) {
100 char buf[256];
102 memcpy(buf, x + 15, x[14]);
103 buf[x[14]] = 0;
104 printf(" Product ID: %s\n", buf);
108 // tag 0x01
110 static const char *feature_support_flags[] = {
111 "De-interlacing",
112 "Support ACP, ISRC1, or ISRC2packets",
113 "Fixed pixel format",
114 "Fixed timing",
115 "Power management (DPM)",
116 "Audio input override",
117 "Separate audio inputs provided",
118 "Audio support on video interface"
121 static void print_flag_lines(const char *indent, const char *label,
122 unsigned char flag_byte, const char **flags)
124 if (flag_byte) {
125 printf("%s\n", label);
127 for (int i = 0; i < 8; i++)
128 if (flag_byte & (1 << i))
129 printf("%s%s\n", indent, flags[i]);
133 void edid_state::set_displayid_native_res(unsigned w, unsigned h)
135 if (dispid.native_width &&
136 (dispid.native_width != w || dispid.native_height != h)) {
137 fail("Native resolution mismatch: %ux%u -> %ux%u.\n",
138 dispid.native_width, dispid.native_height, w, h);
139 return;
142 if (!w && !h)
143 return;
145 if (!w ^ !h) {
146 fail("Invalid Native Pixel Format %ux%u.\n", w, h);
147 } else {
148 dispid.native_width = w;
149 dispid.native_height = h;
153 void edid_state::parse_displayid_parameters(const unsigned char *x)
155 check_displayid_datablock_revision(x[1]);
157 if (!check_displayid_datablock_length(x, 12, 12))
158 return;
160 if (dispid.has_display_parameters)
161 fail("Duplicate Display Parameters Data Block.\n");
162 dispid.has_display_parameters = true;
163 dispid.image_width = (x[4] << 8) + x[3];
164 dispid.image_height = (x[6] << 8) + x[5];
165 if (dispid.image_width > image_width ||
166 dispid.image_height > image_height) {
167 image_width = dispid.image_width;
168 image_height = dispid.image_height;
170 printf(" Image size: %.1f mm x %.1f mm\n",
171 dispid.image_width / 10.0, dispid.image_height / 10.0);
172 unsigned w = (x[8] << 8) + x[7];
173 unsigned h = (x[10] << 8) + x[9];
174 printf(" Display native pixel format: %ux%u\n", w, h);
175 set_displayid_native_res(w, h);
176 print_flag_lines(" ", " Feature support flags:",
177 x[11], feature_support_flags);
179 if (x[12] != 0xff)
180 printf(" Gamma: %.2f\n", ((x[12] + 100.0) / 100.0));
181 printf(" Aspect ratio: %.2f\n", ((x[13] + 100.0) / 100.0));
182 printf(" Dynamic bpc native: %d\n", (x[14] & 0xf) + 1);
183 printf(" Dynamic bpc overall: %d\n", ((x[14] >> 4) & 0xf) + 1);
186 // tag 0x02
188 static const char *std_colorspace_ids[] = {
189 "sRGB",
190 "BT.601",
191 "BT.709",
192 "Adobe RGB",
193 "DCI-P3",
194 "NTSC",
195 "EBU",
196 "Adobe Wide Gamut RGB",
197 "DICOM"
200 static double fp2d(unsigned short fp)
202 return fp / 4096.0;
205 void edid_state::parse_displayid_color_characteristics(const unsigned char *x)
207 check_displayid_datablock_revision(x[1], 0xf8, 1);
209 unsigned cie_year = (x[1] & 0x80) ? 1976 : 1931;
210 unsigned xfer_id = (x[1] >> 3) & 0x0f;
211 unsigned num_whitepoints = x[3] & 0x0f;
212 unsigned num_primaries = (x[3] >> 4) & 0x07;
213 bool temporal_color = x[3] & 0x80;
214 unsigned offset = 4;
216 printf(" Uses %s color\n", temporal_color ? "temporal" : "spatial");
217 printf(" Uses %u CIE (x, y) coordinates\n", cie_year);
218 if (xfer_id) {
219 printf(" Associated with Transfer Characteristics Data Block with Identifier %u\n", xfer_id);
220 if (!(dispid.preparsed_xfer_ids & (1 << xfer_id)))
221 fail("Missing Transfer Characteristics Data Block with Identifier %u.\n", xfer_id);
223 if (!num_primaries) {
224 printf(" Uses color space %s\n",
225 x[4] >= ARRAY_SIZE(std_colorspace_ids) ? "Reserved" :
226 std_colorspace_ids[x[4]]);
227 offset++;
229 for (unsigned i = 0; i < num_primaries; i++) {
230 unsigned idx = offset + 3 * i;
232 printf(" Primary #%u: (%.4f, %.4f)\n", i,
233 fp2d(x[idx] | ((x[idx + 1] & 0x0f) << 8)),
234 fp2d(((x[idx + 1] & 0xf0) >> 4) | (x[idx + 2] << 4)));
236 offset += 3 * num_primaries;
237 for (unsigned i = 0; i < num_whitepoints; i++) {
238 unsigned idx = offset + 3 * i;
240 printf(" White point #%u: (%.4f, %.4f)\n", i,
241 fp2d(x[idx] | ((x[idx + 1] & 0x0f) << 8)),
242 fp2d(((x[idx + 1] & 0xf0) >> 4) | (x[idx + 2] << 4)));
246 // tag 0x03 and 0x22
248 void edid_state::parse_displayid_type_1_7_timing(const unsigned char *x,
249 bool type7, unsigned block_rev, bool is_cta)
251 struct timings t = {};
252 unsigned hbl, vbl;
253 std::string name = is_cta ? std::string("VTDB ") + std::to_string(cta.vec_vtdbs.size() + 1) : "DTD";
254 std::string s("aspect ");
256 dispid.has_type_1_7 = true;
257 t.pixclk_khz = (type7 ? 1 : 10) * (1 + (x[0] + (x[1] << 8) + (x[2] << 16)));
258 switch (x[3] & 0xf) {
259 case 0:
260 s += "1:1";
261 t.hratio = t.vratio = 1;
262 break;
263 case 1:
264 s += "5:4";
265 t.hratio = 5;
266 t.vratio = 4;
267 break;
268 case 2:
269 s += "4:3";
270 t.hratio = 4;
271 t.vratio = 3;
272 break;
273 case 3:
274 s += "15:9";
275 t.hratio = 15;
276 t.vratio = 9;
277 break;
278 case 4:
279 s += "16:9";
280 t.hratio = 16;
281 t.vratio = 9;
282 break;
283 case 5:
284 s += "16:10";
285 t.hratio = 16;
286 t.vratio = 10;
287 break;
288 case 6:
289 s += "64:27";
290 t.hratio = 64;
291 t.vratio = 27;
292 break;
293 case 7:
294 s += "256:135";
295 t.hratio = 256;
296 t.vratio = 135;
297 break;
298 case 8:
299 s += "undefined";
300 break;
301 default:
302 s += "reserved";
303 fail("Unknown aspect 0x%02x.\n", x[3] & 0xf);
304 break;
306 switch ((x[3] >> 5) & 0x3) {
307 case 0:
308 s += ", no 3D stereo";
309 break;
310 case 1:
311 s += ", 3D stereo";
312 break;
313 case 2:
314 s += ", 3D stereo depends on user action";
315 break;
316 case 3:
317 s += ", reserved";
318 fail("Reserved stereo 0x03.\n");
319 break;
321 if (block_rev >= 2 && (x[3] & 0x80))
322 s += ", YCbCr 4:2:0";
324 t.hact = 1 + (x[4] | (x[5] << 8));
325 hbl = 1 + (x[6] | (x[7] << 8));
326 t.hfp = 1 + (x[8] | ((x[9] & 0x7f) << 8));
327 t.hsync = 1 + (x[10] | (x[11] << 8));
328 t.hbp = hbl - t.hfp - t.hsync;
329 if ((x[9] >> 7) & 0x1)
330 t.pos_pol_hsync = true;
331 t.vact = 1 + (x[12] | (x[13] << 8));
332 vbl = 1 + (x[14] | (x[15] << 8));
333 t.vfp = 1 + (x[16] | ((x[17] & 0x7f) << 8));
334 t.vsync = 1 + (x[18] | (x[19] << 8));
335 t.vbp = vbl - t.vfp - t.vsync;
336 if ((x[17] >> 7) & 0x1)
337 t.pos_pol_vsync = true;
339 if (x[3] & 0x10) {
340 t.interlaced = true;
341 t.vfp /= 2;
342 t.vsync /= 2;
343 t.vbp /= 2;
345 if (block_rev < 2 && (x[3] & 0x80)) {
346 s += ", preferred";
347 dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
350 print_timings(" ", &t, name.c_str(), s.c_str(), true);
351 if (is_cta) {
352 timings_ext te(t, name.c_str(), s);
353 cta.vec_vtdbs.push_back(te);
355 // Only use a T7VTDB if is cannot be expressed by a
356 // DTD or a T10VTDB.
357 if (t.hact <= 4095 && t.vact <= 4095 &&
358 t.pixclk_khz <= 655360 && !(x[3] & 0xe0)) {
359 fail("This T7VTDB can be represented as an 18-byte DTD.\n");
360 return;
362 unsigned htot = t.hact + t.hfp + t.hsync + t.hbp;
363 unsigned vtot = t.vact + t.vfp + t.vsync + t.vbp;
364 unsigned refresh = (t.pixclk_khz * 1000ULL) / (htot * vtot);
366 for (unsigned rb = RB_NONE; rb <= RB_CVT_V3; rb++) {
367 timings cvt_t = calc_cvt_mode(t.hact, t.vact, refresh, rb);
368 if (match_timings(t, cvt_t)) {
369 fail("This T7VTDB can be represented as a T10VTDB.\n");
370 return;
373 timings cvt_t = calc_cvt_mode(t.hact, t.vact, refresh, RB_CVT_V3,
374 false, false, true);
375 if (match_timings(t, cvt_t))
376 fail("This T7VTDB can be represented as a T10VTDB.\n");
380 // tag 0x04
382 void edid_state::parse_displayid_type_2_timing(const unsigned char *x)
384 struct timings t = {};
385 unsigned hbl, vbl;
386 std::string s("aspect ");
388 t.pixclk_khz = 10 * (1 + (x[0] + (x[1] << 8) + (x[2] << 16)));
389 t.hact = 8 + 8 * (x[4] | ((x[5] & 0x01) << 8));
390 hbl = 8 + 8 * ((x[5] & 0xfe) >> 1);
391 t.hfp = 8 + 8 * ((x[6] & 0xf0) >> 4);
392 t.hsync = 8 + 8 * (x[6] & 0xf);
393 t.hbp = hbl - t.hfp - t.hsync;
394 if ((x[3] >> 3) & 0x1)
395 t.pos_pol_hsync = true;
396 t.vact = 1 + (x[7] | ((x[8] & 0xf) << 8));
397 vbl = 1 + x[9];
398 t.vfp = 1 + (x[10] >> 4);
399 t.vsync = 1 + (x[10] & 0xf);
400 t.vbp = vbl - t.vfp - t.vsync;
401 if ((x[17] >> 2) & 0x1)
402 t.pos_pol_vsync = true;
404 if (x[3] & 0x10) {
405 t.interlaced = true;
406 t.vfp /= 2;
407 t.vsync /= 2;
408 t.vbp /= 2;
411 calc_ratio(&t);
413 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
415 switch ((x[3] >> 5) & 0x3) {
416 case 0:
417 s += ", no 3D stereo";
418 break;
419 case 1:
420 s += ", 3D stereo";
421 break;
422 case 2:
423 s += ", 3D stereo depends on user action";
424 break;
425 case 3:
426 s += ", reserved";
427 fail("Reserved stereo 0x03.\n");
428 break;
430 if (x[3] & 0x80) {
431 s += ", preferred";
432 dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
435 print_timings(" ", &t, "DTD", s.c_str(), true);
438 // tag 0x05
440 void edid_state::parse_displayid_type_3_timing(const unsigned char *x)
442 struct timings t = {};
443 std::string s("aspect ");
445 switch (x[0] & 0xf) {
446 case 0:
447 s += "1:1";
448 t.hratio = t.vratio = 1;
449 break;
450 case 1:
451 s += "5:4";
452 t.hratio = 5;
453 t.vratio = 4;
454 break;
455 case 2:
456 s += "4:3";
457 t.hratio = 4;
458 t.vratio = 3;
459 break;
460 case 3:
461 s += "15:9";
462 t.hratio = 15;
463 t.vratio = 9;
464 break;
465 case 4:
466 s += "16:9";
467 t.hratio = 16;
468 t.vratio = 9;
469 break;
470 case 5:
471 s += "16:10";
472 t.hratio = 16;
473 t.vratio = 10;
474 break;
475 case 6:
476 s += "64:27";
477 t.hratio = 64;
478 t.vratio = 27;
479 break;
480 case 7:
481 s += "256:135";
482 t.hratio = 256;
483 t.vratio = 135;
484 break;
485 case 8:
486 s += "undefined";
487 break;
488 default:
489 s += "reserved";
490 fail("Unknown aspect 0x%02x.\n", x[0] & 0xf);
491 break;
494 t.rb = ((x[0] & 0x70) >> 4) == 1 ? RB_CVT_V1 : RB_NONE;
495 t.hact = 8 + 8 * x[1];
496 t.vact = t.hact * t.vratio / t.hratio;
498 edid_cvt_mode(1 + (x[2] & 0x7f), t);
500 if (x[0] & 0x80) {
501 s += ", preferred";
502 dispid.preferred_timings.push_back(timings_ext(t, "CVT", s));
505 print_timings(" ", &t, "CVT", s.c_str());
508 // tag 0x06 and 0x23
510 void edid_state::parse_displayid_type_4_8_timing(unsigned char type, unsigned short id, bool is_cta)
512 const struct timings *t = NULL;
513 char type_name[16];
515 switch (type) {
516 case 0: t = find_dmt_id(id); sprintf(type_name, "DMT 0x%02x", id); break;
517 case 1: t = find_vic_id(id); sprintf(type_name, "VIC %3u", id); break;
518 case 2: t = find_hdmi_vic_id(id); sprintf(type_name, "HDMI VIC %u", id); break;
519 default: break;
521 if (t)
522 print_timings(" ", t, type_name);
523 if (t && is_cta && !cta.t8vtdb.is_valid()) {
524 timings_ext te(*t, type_name, "");
525 cta.t8vtdb = te;
529 // tag 0x09
531 void edid_state::parse_displayid_video_timing_range_limits(const unsigned char *x)
533 check_displayid_datablock_revision(x[1]);
535 if (!check_displayid_datablock_length(x, 15, 15))
536 return;
537 printf(" Pixel Clock: %.3f-%.3f MHz\n",
538 (double)((x[3] | (x[4] << 8) | (x[5] << 16)) + 1) / 100.0,
539 (double)((x[6] | (x[7] << 8) | (x[8] << 16)) + 1) / 100.0);
540 printf(" Horizontal Frequency: %u-%u kHz\n", x[9], x[10]);
541 printf(" Minimum Horizontal Blanking: %u pixels\n", x[11] | (x[12] << 8));
542 printf(" Vertical Refresh: %u-%u Hz\n", x[13], x[14]);
543 printf(" Minimum Vertical Blanking: %u lines\n", x[15] | (x[16] << 8));
544 if (x[17] & 0x80)
545 printf(" Supports Interlaced\n");
546 if (x[17] & 0x40)
547 printf(" Supports CVT\n");
548 if (x[17] & 0x20)
549 printf(" Supports CVT Reduced Blanking\n");
550 if (x[17] & 0x10)
551 printf(" Discrete frequency display device\n");
554 // tag 0x0a and 0x0b
556 void edid_state::parse_displayid_string(const unsigned char *x)
558 check_displayid_datablock_revision(x[1]);
559 if (check_displayid_datablock_length(x))
560 printf(" Text: '%s'\n", extract_string(x + 3, x[2]));
563 // tag 0x0c
565 void edid_state::parse_displayid_display_device(const unsigned char *x)
567 check_displayid_datablock_revision(x[1]);
569 if (!check_displayid_datablock_length(x, 13, 13))
570 return;
572 printf(" Display Device Technology: ");
573 switch (x[3]) {
574 case 0x00: printf("Monochrome CRT\n"); break;
575 case 0x01: printf("Standard tricolor CRT\n"); break;
576 case 0x02: printf("Other/undefined CRT\n"); break;
577 case 0x10: printf("Passive matrix TN\n"); break;
578 case 0x11: printf("Passive matrix cholesteric LC\n"); break;
579 case 0x12: printf("Passive matrix ferroelectric LC\n"); break;
580 case 0x13: printf("Other passive matrix LC type\n"); break;
581 case 0x14: printf("Active-matrix TN\n"); break;
582 case 0x15: printf("Active-matrix IPS (all types)\n"); break;
583 case 0x16: printf("Active-matrix VA (all types)\n"); break;
584 case 0x17: printf("Active-matrix OCB\n"); break;
585 case 0x18: printf("Active-matrix ferroelectric\n"); break;
586 case 0x1f: printf("Other LC type\n"); break;
587 case 0x20: printf("DC plasma\n"); break;
588 case 0x21: printf("AC plasma\n"); break;
590 switch (x[3] & 0xf0) {
591 case 0x30: printf("Electroluminescent, except OEL/OLED\n"); break;
592 case 0x40: printf("Inorganic LED\n"); break;
593 case 0x50: printf("Organic LED/OEL\n"); break;
594 case 0x60: printf("FED or sim. \"cold-cathode,\" phosphor-based types\n"); break;
595 case 0x70: printf("Electrophoretic\n"); break;
596 case 0x80: printf("Electrochromic\n"); break;
597 case 0x90: printf("Electromechanical\n"); break;
598 case 0xa0: printf("Electrowetting\n"); break;
599 case 0xf0: printf("Other type not defined here\n"); break;
601 printf(" Display operating mode: ");
602 switch (x[4] >> 4) {
603 case 0x00: printf("Direct-view reflective, ambient light\n"); break;
604 case 0x01: printf("Direct-view reflective, ambient light, also has light source\n"); break;
605 case 0x02: printf("Direct-view reflective, uses light source\n"); break;
606 case 0x03: printf("Direct-view transmissive, ambient light\n"); break;
607 case 0x04: printf("Direct-view transmissive, ambient light, also has light source\n"); break;
608 case 0x05: printf("Direct-view transmissive, uses light source\n"); break;
609 case 0x06: printf("Direct-view emissive\n"); break;
610 case 0x07: printf("Direct-view transflective, backlight off by default\n"); break;
611 case 0x08: printf("Direct-view transflective, backlight on by default\n"); break;
612 case 0x09: printf("Transparent display, ambient light\n"); break;
613 case 0x0a: printf("Transparent emissive display\n"); break;
614 case 0x0b: printf("Projection device using reflective light modulator\n"); break;
615 case 0x0c: printf("Projection device using transmissive light modulator\n"); break;
616 case 0x0d: printf("Projection device using emissive image transducer\n"); break;
617 default: printf("Reserved\n"); break;
619 if (x[4] & 0x08)
620 printf(" The backlight may be switched on and off\n");
621 if (x[4] & 0x04)
622 printf(" The backlight's intensity can be controlled\n");
623 unsigned w = x[5] | (x[6] << 8);
624 unsigned h = x[7] | (x[8] << 8);
626 if (w) w++;
627 if (h) h++;
629 printf(" Display native pixel format: %ux%u\n", w, h);
630 set_displayid_native_res(w, h);
631 printf(" Aspect ratio and orientation:\n");
632 printf(" Aspect Ratio: %.2f\n", (100 + x[9]) / 100.0);
633 unsigned char v = x[0x0a];
634 printf(" Default Orientation: ");
635 switch ((v & 0xc0) >> 6) {
636 case 0x00: printf("Landscape\n"); break;
637 case 0x01: printf("Portrait\n"); break;
638 case 0x02: printf("Not Fixed\n"); break;
639 case 0x03: printf("Undefined\n"); break;
641 printf(" Rotation Capability: ");
642 switch ((v & 0x30) >> 4) {
643 case 0x00: printf("None\n"); break;
644 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
645 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
646 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
648 printf(" Zero Pixel Location: ");
649 switch ((v & 0x0c) >> 2) {
650 case 0x00: printf("Upper Left\n"); break;
651 case 0x01: printf("Upper Right\n"); break;
652 case 0x02: printf("Lower Left\n"); break;
653 case 0x03: printf("Lower Right\n"); break;
655 printf(" Scan Direction: ");
656 switch (v & 0x03) {
657 case 0x00: printf("Not defined\n"); break;
658 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
659 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
660 case 0x03: printf("Reserved\n");
661 fail("Scan Direction used the reserved value 0x03.\n");
662 break;
664 printf(" Sub-pixel layout/configuration/shape: ");
665 switch (x[0x0b]) {
666 case 0x00: printf("Not defined\n"); break;
667 case 0x01: printf("RGB vertical stripes\n"); break;
668 case 0x02: printf("RGB horizontal stripes\n"); break;
669 case 0x03: printf("Vertical stripes using primary order\n"); break;
670 case 0x04: printf("Horizontal stripes using primary order\n"); break;
671 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
672 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
673 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
674 case 0x08: printf("Mosaic\n"); break;
675 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
676 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
677 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
678 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
679 default: printf("Reserved\n"); break;
681 printf(" Horizontal and vertical dot/pixel pitch: %.2fx%.2f mm\n",
682 (double)(x[0x0c]) / 100.0, (double)(x[0x0d]) / 100.0);
683 printf(" Color bit depth: %u\n", x[0x0e] & 0x0f);
684 v = x[0x0f];
685 printf(" Response time for %s transition: %u ms\n",
686 (v & 0x80) ? "white-to-black" : "black-to-white", v & 0x7f);
689 // tag 0x0d
691 void edid_state::parse_displayid_intf_power_sequencing(const unsigned char *x)
693 check_displayid_datablock_revision(x[1]);
695 if (!check_displayid_datablock_length(x, 6, 6))
696 return;
698 printf(" Power Sequence T1 Range: %.1f-%u.0 ms\n", (x[3] >> 4) / 10.0, (x[3] & 0xf) * 2);
699 printf(" Power Sequence T2 Range: 0.0-%u.0 ms\n", (x[4] & 0x3f) * 2);
700 printf(" Power Sequence T3 Range: 0.0-%u.0 ms\n", (x[5] & 0x3f) * 2);
701 printf(" Power Sequence T4 Min: %u.0 ms\n", (x[6] & 0x7f) * 10);
702 printf(" Power Sequence T5 Min: %u.0 ms\n", (x[7] & 0x3f) * 10);
703 printf(" Power Sequence T6 Min: %u.0 ms\n", (x[8] & 0x3f) * 10);
706 // tag 0x0e
708 void edid_state::parse_displayid_transfer_characteristics(const unsigned char *x)
710 check_displayid_datablock_revision(x[1], 0xf0, 1);
712 unsigned xfer_id = x[1] >> 4;
713 bool first_is_white = x[3] & 0x80;
714 bool four_param = x[3] & 0x20;
716 if (xfer_id) {
717 printf(" Transfer Characteristics Data Block Identifier: %u\n", xfer_id);
718 if (!(dispid.preparsed_color_ids & (1 << xfer_id)))
719 fail("Missing Color Characteristics Data Block using Identifier %u.\n", xfer_id);
721 if (first_is_white)
722 printf(" The first curve is the 'white' transfer characteristic\n");
723 if (x[3] & 0x40)
724 printf(" Individual response curves\n");
726 unsigned offset = 4;
727 unsigned len = x[2] - 1;
729 for (unsigned i = 0; len; i++) {
730 if ((x[3] & 0x80) && !i)
731 printf(" White curve: ");
732 else
733 printf(" Response curve #%u:",
734 i - first_is_white);
735 unsigned samples = x[offset];
736 if (four_param) {
737 if (samples != 5)
738 fail("Expected 5 samples.\n");
739 printf(" A0=%u A1=%u A2=%u A3=%u Gamma=%.2f\n",
740 x[offset + 1], x[offset + 2], x[offset + 3], x[offset + 4],
741 (double)(x[offset + 5] + 100.0) / 100.0);
742 samples++;
743 } else {
744 double sum = 0;
746 // The spec is not very clear about the number of samples:
747 // should this be interpreted as the actual number of
748 // samples stored in this Data Block, or as the number of
749 // samples in the curve, but where the last sample is not
750 // actually stored since it is always 0x3ff.
752 // The ATP Manager interprets this as the latter, so that's
753 // what we implement here.
754 for (unsigned j = offset + 1; j < offset + samples; j++) {
755 sum += x[j];
756 printf(" %.2f", sum * 100.0 / 1023.0);
758 printf(" 100.00\n");
760 offset += samples;
761 len -= samples;
765 // tag 0x0f
767 void edid_state::parse_displayid_display_intf(const unsigned char *x)
769 check_displayid_datablock_revision(x[1]);
771 if (!check_displayid_datablock_length(x, 10, 10))
772 return;
774 dispid.has_display_interface_features = true;
775 printf(" Interface Type: ");
776 switch (x[3] >> 4) {
777 case 0x00:
778 switch (x[3] & 0xf) {
779 case 0x00: printf("Analog 15HD/VGA\n"); break;
780 case 0x01: printf("Analog VESA NAVI-V (15HD)\n"); break;
781 case 0x02: printf("Analog VESA NAVI-D\n"); break;
782 default: printf("Reserved\n"); break;
784 break;
785 case 0x01: printf("LVDS\n"); break;
786 case 0x02: printf("TMDS\n"); break;
787 case 0x03: printf("RSDS\n"); break;
788 case 0x04: printf("DVI-D\n"); break;
789 case 0x05: printf("DVI-I, analog\n"); break;
790 case 0x06: printf("DVI-I, digital\n"); break;
791 case 0x07: printf("HDMI-A\n"); break;
792 case 0x08: printf("HDMI-B\n"); break;
793 case 0x09: printf("MDDI\n"); break;
794 case 0x0a: printf("DisplayPort\n"); break;
795 case 0x0b: printf("Proprietary Digital Interface\n"); break;
796 default: printf("Reserved\n"); break;
798 if (x[3] >> 4)
799 printf(" Number of Links: %u\n", x[3] & 0xf);
800 printf(" Interface Standard Version: %u.%u\n",
801 x[4] >> 4, x[4] & 0xf);
802 print_flags(" Supported bpc for RGB encoding", x[5], bpc444);
803 print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x[6], bpc444);
804 print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x[7], bpc4xx);
805 printf(" Supported Content Protection: ");
806 switch (x[8] & 0xf) {
807 case 0x00: printf("None\n"); break;
808 case 0x01: printf("HDCP "); break;
809 case 0x02: printf("DTCP "); break;
810 case 0x03: printf("DPCP "); break;
811 default: printf("Reserved "); break;
813 if (x[8] & 0xf)
814 printf("%u.%u\n", x[9] >> 4, x[9] & 0xf);
815 unsigned char v = x[0x0a] & 0xf;
816 printf(" Spread Spectrum: ");
817 switch (x[0x0a] >> 6) {
818 case 0x00: printf("None\n"); break;
819 case 0x01: printf("Down Spread %.1f%%\n", v / 10.0); break;
820 case 0x02: printf("Center Spread %.1f%%\n", v / 10.0); break;
821 case 0x03: printf("Reserved\n"); break;
823 switch (x[3] >> 4) {
824 case 0x01:
825 printf(" LVDS Color Mapping: %s mode\n",
826 (x[0x0b] & 0x10) ? "6 bit compatible" : "normal");
827 if (x[0x0b] & 0x08) printf(" LVDS supports 2.8V\n");
828 if (x[0x0b] & 0x04) printf(" LVDS supports 12V\n");
829 if (x[0x0b] & 0x02) printf(" LVDS supports 5V\n");
830 if (x[0x0b] & 0x01) printf(" LVDS supports 3.3V\n");
831 printf(" LVDS %s Mode\n", (x[0x0c] & 0x04) ? "Fixed" : "DE");
832 if (x[0x0c] & 0x04)
833 printf(" LVDS %s Signal Level\n", (x[0x0c] & 0x02) ? "Low" : "High");
834 else
835 printf(" LVDS DE Polarity Active %s\n", (x[0x0c] & 0x02) ? "Low" : "High");
836 printf(" LVDS Shift Clock Data Strobe at %s Edge\n", (x[0x0c] & 0x01) ? "Rising" : "Falling");
837 break;
838 case 0x0b:
839 printf(" PDI %s Mode\n", (x[0x0b] & 0x04) ? "Fixed" : "DE");
840 if (x[0x0b] & 0x04)
841 printf(" PDI %s Signal Level\n", (x[0x0b] & 0x02) ? "Low" : "High");
842 else
843 printf(" PDI DE Polarity Active %s\n", (x[0x0b] & 0x02) ? "Low" : "High");
844 printf(" PDI Shift Clock Data Strobe at %s Edge\n", (x[0x0b] & 0x01) ? "Rising" : "Falling");
845 break;
849 // tag 0x10 and 0x27
851 void edid_state::parse_displayid_stereo_display_intf(const unsigned char *x)
853 check_displayid_datablock_revision(x[1], 0xc0, 1);
855 switch (x[1] >> 6) {
856 case 0x00: printf(" Timings that explicitly report 3D capability\n"); break;
857 case 0x01: printf(" Timings that explicitly report 3D capability & Timing Codes listed here\n"); break;
858 case 0x02: printf(" All listed timings\n"); break;
859 case 0x03: printf(" Only Timings Codes listed here\n"); break;
862 unsigned len = x[2];
864 switch (x[4]) {
865 case 0x00:
866 printf(" Field Sequential Stereo (L/R Polarity: %s)\n",
867 (x[5] & 1) ? "0/1" : "1/0");
868 break;
869 case 0x01:
870 printf(" Side-by-side Stereo (Left Half = %s Eye View)\n",
871 (x[5] & 1) ? "Right" : "Left");
872 break;
873 case 0x02:
874 printf(" Pixel Interleaved Stereo:\n");
875 for (unsigned y = 0; y < 8; y++) {
876 unsigned char v = x[5 + y];
878 printf(" ");
879 for (int x = 7; x >= 0; x--)
880 printf("%c", (v & (1 << x)) ? 'L' : 'R');
881 printf("\n");
883 break;
884 case 0x03:
885 printf(" Dual Interface, Left and Right Separate\n");
886 printf(" Carries the %s-eye view\n",
887 (x[5] & 1) ? "Right" : "Left");
888 printf(" ");
889 switch ((x[5] >> 1) & 3) {
890 case 0x00: printf("No mirroring\n"); break;
891 case 0x01: printf("Left/Right mirroring\n"); break;
892 case 0x02: printf("Top/Bottom mirroring\n"); break;
893 case 0x03: printf("Reserved\n"); break;
895 break;
896 case 0x04:
897 printf(" Multi-View: %u views, Interleaving Method Code: %u\n",
898 x[5], x[6]);
899 break;
900 case 0x05:
901 printf(" Stacked Frame Stereo (Top Half = %s Eye View)\n",
902 (x[5] & 1) ? "Right" : "Left");
903 break;
904 case 0xff:
905 printf(" Proprietary\n");
906 break;
907 default:
908 printf(" Reserved\n");
909 break;
911 if (!(x[1] & 0x40)) // Has No Timing Codes
912 return;
913 len -= 1 + x[3];
914 x += 4 + x[3];
915 while (1U + (x[0] & 0x1f) <= len) {
916 unsigned num_codes = x[0] & 0x1f;
917 unsigned type = x[0] >> 6;
918 char type_name[16];
920 for (unsigned i = 1; i <= num_codes; i++) {
921 switch (type) {
922 case 0x00:
923 sprintf(type_name, "DMT 0x%02x", x[i]);
924 print_timings(" ", find_dmt_id(x[i]), type_name);
925 break;
926 case 0x01:
927 sprintf(type_name, "VIC %3u", x[i]);
928 print_timings(" ", find_vic_id(x[i]), type_name);
929 break;
930 case 0x02:
931 sprintf(type_name, "HDMI VIC %u", x[i]);
932 print_timings(" ", find_hdmi_vic_id(x[i]), type_name);
933 break;
937 len -= 1 + num_codes;
938 x += 1 + num_codes;
942 // tag 0x11
944 void edid_state::parse_displayid_type_5_timing(const unsigned char *x)
946 struct timings t = {};
947 std::string s("aspect ");
949 t.hact = 1 + (x[2] | (x[3] << 8));
950 t.vact = 1 + (x[4] | (x[5] << 8));
951 calc_ratio(&t);
952 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
953 switch ((x[0] >> 5) & 0x3) {
954 case 0:
955 s += ", no 3D stereo";
956 break;
957 case 1:
958 s += ", 3D stereo";
959 break;
960 case 2:
961 s += ", 3D stereo depends on user action";
962 break;
963 case 3:
964 s += ", reserved";
965 fail("Reserved stereo 0x03.\n");
966 break;
968 if (x[0] & 0x10)
969 s += ", refresh rate * (1000/1001) supported";
971 t.rb = RB_CVT_V2;
972 if ((x[0] & 0x03) == 1)
973 warn("Unexpected use of 'custom reduced blanking'.\n");
974 else if ((x[0] & 0x03) > 1)
975 fail("Invalid Timing Formula.\n");
977 edid_cvt_mode(1 + x[6], t);
979 if (x[0] & 0x80) {
980 s += ", preferred";
981 dispid.preferred_timings.push_back(timings_ext(t, "CVT", s));
984 print_timings(" ", &t, "CVT", s.c_str());
987 // tag 0x12 and 0x28
989 void edid_state::parse_displayid_tiled_display_topology(const unsigned char *x, bool is_v2)
991 check_displayid_datablock_revision(x[1]);
993 if (!check_displayid_datablock_length(x, 22, 22))
994 return;
996 unsigned caps = x[3];
997 unsigned num_v_tile = (x[4] & 0xf) | (x[6] & 0x30);
998 unsigned num_h_tile = (x[4] >> 4) | ((x[6] >> 2) & 0x30);
999 unsigned tile_v_location = (x[5] & 0xf) | ((x[6] & 0x3) << 4);
1000 unsigned tile_h_location = (x[5] >> 4) | (((x[6] >> 2) & 0x3) << 4);
1001 unsigned tile_width = x[7] | (x[8] << 8);
1002 unsigned tile_height = x[9] | (x[10] << 8);
1003 unsigned pix_mult = x[11];
1005 printf(" Capabilities:\n");
1006 printf(" Behavior if it is the only tile: ");
1007 switch (caps & 0x07) {
1008 case 0x00: printf("Undefined\n"); break;
1009 case 0x01: printf("Image is displayed at the Tile Location\n"); break;
1010 case 0x02: printf("Image is scaled to fit the entire tiled display\n"); break;
1011 case 0x03: printf("Image is cloned to all other tiles\n"); break;
1012 default: printf("Reserved\n"); break;
1014 printf(" Behavior if more than one tile and fewer than total number of tiles: ");
1015 switch ((caps >> 3) & 0x03) {
1016 case 0x00: printf("Undefined\n"); break;
1017 case 0x01: printf("Image is displayed at the Tile Location\n"); break;
1018 default: printf("Reserved\n"); break;
1020 if (caps & 0x80)
1021 printf(" Tiled display consists of a single physical display enclosure\n");
1022 else
1023 printf(" Tiled display consists of multiple physical display enclosures\n");
1024 printf(" Num horizontal tiles: %u Num vertical tiles: %u\n",
1025 num_h_tile + 1, num_v_tile + 1);
1026 printf(" Tile location: %u, %u\n", tile_h_location, tile_v_location);
1027 printf(" Tile resolution: %ux%u\n", tile_width + 1, tile_height + 1);
1028 if (caps & 0x40) {
1029 if (pix_mult) {
1030 printf(" Top bezel size: %.1f pixels\n",
1031 pix_mult * x[12] / 10.0);
1032 printf(" Bottom bezel size: %.1f pixels\n",
1033 pix_mult * x[13] / 10.0);
1034 printf(" Right bezel size: %.1f pixels\n",
1035 pix_mult * x[14] / 10.0);
1036 printf(" Left bezel size: %.1f pixels\n",
1037 pix_mult * x[15] / 10.0);
1038 } else {
1039 fail("Bezel information bit is set, but the pixel multiplier is zero.\n");
1041 printf(" Tile resolution: %ux%u\n", tile_width + 1, tile_height + 1);
1042 } else if (pix_mult) {
1043 fail("No bezel information, but the pixel multiplier is non-zero.\n");
1045 if (is_v2)
1046 printf(" Tiled Display Manufacturer/Vendor ID: %02X-%02X-%02X\n",
1047 x[0x10], x[0x11], x[0x12]);
1048 else
1049 printf(" Tiled Display Manufacturer/Vendor ID: %c%c%c\n",
1050 x[0x10], x[0x11], x[0x12]);
1051 printf(" Tiled Display Product ID Code: %u\n",
1052 x[0x13] | (x[0x14] << 8));
1053 unsigned int sn = x[0x15] | (x[0x16] << 8) | (x[0x17] << 16)| (x[0x18] << 24);
1054 if (sn) {
1055 if (hide_serial_numbers)
1056 printf(" Tiled Display Serial Number: ...\n");
1057 else
1058 printf(" Tiled Display Serial Number: %u\n", sn);
1059 } else {
1060 fail("Tiled Display Serial Number must be non-zero.\n");
1064 // tag 0x13
1066 void edid_state::parse_displayid_type_6_timing(const unsigned char *x)
1068 struct timings t = {};
1069 std::string s("aspect ");
1071 t.pixclk_khz = 1 + (x[0] + (x[1] << 8) + ((x[2] & 0x3f) << 16));
1072 t.hact = 1 + (x[3] | ((x[4] & 0x3f) << 8));
1073 if ((x[4] >> 7) & 0x1)
1074 t.pos_pol_hsync = true;
1075 unsigned hbl = 1 + (x[7] | ((x[9] & 0xf) << 8));
1076 t.hfp = 1 + (x[8] | ((x[9] & 0xf0) << 4));
1077 t.hsync = 1 + x[10];
1078 t.hbp = hbl - t.hfp - t.hsync;
1079 t.vact = 1 + (x[5] | ((x[6] & 0x3f) << 8));
1080 if ((x[6] >> 7) & 0x1)
1081 t.pos_pol_vsync = true;
1082 unsigned vbl = 1 + x[11];
1083 t.vfp = 1 + x[12];
1084 t.vsync = 1 + (x[13] & 0x0f);
1085 t.vbp = vbl - t.vfp - t.vsync;
1087 if (x[13] & 0x80) {
1088 t.interlaced = true;
1089 t.vfp /= 2;
1090 t.vsync /= 2;
1091 t.vbp /= 2;
1093 calc_ratio(&t);
1094 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1095 if (x[2] & 0x40) {
1096 double aspect_mult = x[14] * 3.0 / 256.0;
1097 unsigned size_mult = 1 + (x[16] >> 4);
1099 t.vsize_mm = size_mult * (1 + (x[15] | ((x[16] & 0xf) << 8)));
1100 t.hsize_mm = t.vsize_mm * aspect_mult;
1103 switch ((x[13] >> 5) & 0x3) {
1104 case 0:
1105 s += ", no 3D stereo";
1106 break;
1107 case 1:
1108 s += ", 3D stereo";
1109 break;
1110 case 2:
1111 s += ", 3D stereo depends on user action";
1112 break;
1113 case 3:
1114 s += ", reserved";
1115 fail("Reserved stereo 0x03.\n");
1116 break;
1119 if (x[2] & 0x80) {
1120 s += ", preferred";
1121 dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
1124 print_timings(" ", &t, "DTD", s.c_str(), true);
1127 static std::string ieee7542d(unsigned short fp)
1129 int exp = ((fp & 0x7c00) >> 10) - 15;
1130 unsigned fract = (fp & 0x3ff) | 0x400;
1132 if (fp == 0x8000)
1133 return "do not use";
1134 if (fp & 0x8000)
1135 return "reserved";
1136 return std::to_string(pow(2, exp) * fract / 1024.0) + " cd/m^2";
1139 // tag 0x21
1141 void edid_state::parse_displayid_parameters_v2(const unsigned char *x,
1142 unsigned block_rev)
1144 if (!check_displayid_datablock_length(x, 29, 29))
1145 return;
1146 if (dispid.has_display_parameters)
1147 fail("Duplicate Display Parameters Data Block.\n");
1148 dispid.has_display_parameters = true;
1150 unsigned hor_size = (x[4] << 8) + x[3];
1151 unsigned vert_size = (x[6] << 8) + x[5];
1153 dispid.image_width = hor_size;
1154 dispid.image_height = vert_size;
1155 if (x[1] & 0x80) {
1156 printf(" Image size: %u mm x %u mm\n", hor_size, vert_size);
1157 dispid.image_width *= 10;
1158 dispid.image_height *= 10;
1159 } else {
1160 printf(" Image size: %.1f mm x %.1f mm\n",
1161 hor_size / 10.0, vert_size / 10.0);
1163 if (dispid.image_width > image_width ||
1164 dispid.image_height > image_height) {
1165 image_width = dispid.image_width;
1166 image_height = dispid.image_height;
1169 unsigned w = (x[8] << 8) + x[7];
1170 unsigned h = (x[10] << 8) + x[9];
1172 printf(" Display native pixel format: %ux%u\n", w, h);
1173 set_displayid_native_res(w, h);
1175 unsigned char v = x[11];
1176 printf(" Scan Orientation: ");
1177 switch (v & 0x07) {
1178 case 0x00: printf("Left to Right, Top to Bottom\n"); break;
1179 case 0x01: printf("Right to Left, Top to Bottom\n"); break;
1180 case 0x02: printf("Top to Bottom, Right to Left\n"); break;
1181 case 0x03: printf("Bottom to Top, Right to Left\n"); break;
1182 case 0x04: printf("Right to Left, Bottom to Top\n"); break;
1183 case 0x05: printf("Left to Right, Bottom to Top\n"); break;
1184 case 0x06: printf("Bottom to Top, Left to Right\n"); break;
1185 case 0x07: printf("Top to Bottom, Left to Right\n"); break;
1187 printf(" Luminance Information: ");
1188 switch ((v >> 3) & 0x03) {
1189 case 0x00: printf("Minimum guaranteed value\n"); break;
1190 case 0x01: printf("Guidance for the Source device\n"); break;
1191 default: printf("Reserved\n"); break;
1193 printf(" Color Information: CIE %u\n",
1194 (v & 0x40) ? 1976 : 1931);
1195 printf(" Audio Speaker Information: %sintegrated\n",
1196 (v & 0x80) ? "not " : "");
1197 printf(" Native Color Chromaticity:\n");
1198 printf(" Primary #1: (%.6f, %.6f)\n",
1199 fp2d(x[0x0c] | ((x[0x0d] & 0x0f) << 8)),
1200 fp2d(((x[0x0d] & 0xf0) >> 4) | (x[0x0e] << 4)));
1201 printf(" Primary #2: (%.6f, %.6f)\n",
1202 fp2d(x[0x0f] | ((x[0x10] & 0x0f) << 8)),
1203 fp2d(((x[0x10] & 0xf0) >> 4) | (x[0x11] << 4)));
1204 printf(" Primary #3: (%.6f, %.6f)\n",
1205 fp2d(x[0x12] | ((x[0x13] & 0x0f) << 8)),
1206 fp2d(((x[0x13] & 0xf0) >> 4) | (x[0x14] << 4)));
1207 printf(" White Point: (%.6f, %.6f)\n",
1208 fp2d(x[0x15] | ((x[0x16] & 0x0f) << 8)),
1209 fp2d(((x[0x16] & 0xf0) >> 4) | (x[0x17] << 4)));
1210 printf(" Native Maximum Luminance (Full Coverage): %s\n",
1211 ieee7542d(x[0x18] | (x[0x19] << 8)).c_str());
1212 printf(" Native Maximum Luminance (10%% Rectangular Coverage): %s\n",
1213 ieee7542d(x[0x1a] | (x[0x1b] << 8)).c_str());
1214 printf(" Native Minimum Luminance: %s\n",
1215 ieee7542d(x[0x1c] | (x[0x1d] << 8)).c_str());
1216 printf(" Native Color Depth: ");
1217 if (!(x[0x1e] & 0x07))
1218 printf("Not defined\n");
1219 else if (bpc444[x[0x1e] & 0x07])
1220 printf("%s bpc\n", bpc444[x[0x1e] & 0x07]);
1221 else
1222 printf("Reserved\n");
1223 printf(" Display Device Technology: ");
1224 switch ((x[0x1e] >> 4) & 0x07) {
1225 case 0x00: printf("Not Specified\n"); break;
1226 case 0x01: printf("Active Matrix LCD\n"); break;
1227 case 0x02: printf("Organic LED\n"); break;
1228 default: printf("Reserved\n"); break;
1230 if (block_rev)
1231 printf(" Display Device Theme Preference: %s\n",
1232 (x[0x1e] & 0x80) ? "Dark Theme Preferred" : "No Preference");
1233 if (x[0x1f] != 0xff)
1234 printf(" Native Gamma EOTF: %.2f\n",
1235 (100 + x[0x1f]) / 100.0);
1238 // tag 0x24
1240 void edid_state::parse_displayid_type_9_timing(const unsigned char *x)
1242 struct timings t = {};
1243 std::string s("aspect ");
1245 t.hact = 1 + (x[1] | (x[2] << 8));
1246 t.vact = 1 + (x[3] | (x[4] << 8));
1247 calc_ratio(&t);
1248 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1249 switch ((x[0] >> 5) & 0x3) {
1250 case 0:
1251 s += ", no 3D stereo";
1252 break;
1253 case 1:
1254 s += ", 3D stereo";
1255 break;
1256 case 2:
1257 s += ", 3D stereo depends on user action";
1258 break;
1259 case 3:
1260 s += ", reserved";
1261 fail("Reserved stereo 0x03.\n");
1262 break;
1264 if (x[0] & 0x10)
1265 s += ", refresh rate * (1000/1001) supported";
1267 switch (x[0] & 0x07) {
1268 case 1: t.rb = RB_CVT_V1; break;
1269 case 2: t.rb = RB_CVT_V2; break;
1270 default: break;
1273 edid_cvt_mode(1 + x[5], t);
1275 print_timings(" ", &t, "CVT", s.c_str());
1278 // tag 0x25
1280 void edid_state::parse_displayid_dynamic_video_timings_range_limits(const unsigned char *x)
1282 check_displayid_datablock_revision(x[1], 0, (x[1] & 7) == 1);
1284 if (!check_displayid_datablock_length(x, 9, 9))
1285 return;
1287 printf(" Minimum Pixel Clock: %u kHz\n",
1288 1 + (x[3] | (x[4] << 8) | (x[5] << 16)));
1289 printf(" Maximum Pixel Clock: %u kHz\n",
1290 1 + (x[6] | (x[7] << 8) | (x[8] << 16)));
1291 printf(" Minimum Vertical Refresh Rate: %u Hz\n", x[9]);
1292 if (x[1] & 7)
1293 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x[10] + ((x[11] & 3) << 8));
1294 else
1295 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x[10]);
1296 printf(" Seamless Dynamic Video Timing Support: %s\n",
1297 (x[11] & 0x80) ? "Yes" : "No");
1300 // tag 0x26
1302 static const char *colorspace_eotf_combinations[] = {
1303 "sRGB",
1304 "BT.601",
1305 "BT.709/BT.1886",
1306 "Adobe RGB",
1307 "DCI-P3",
1308 "BT.2020",
1309 "BT.2020/SMPTE ST 2084"
1312 static const char *colorspace_eotf_reserved[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
1314 static const char *colorspaces[] = {
1315 "Undefined",
1316 "sRGB",
1317 "BT.601",
1318 "BT.709",
1319 "Adobe RGB",
1320 "DCI-P3",
1321 "BT.2020",
1322 "Custom"
1325 static const char *eotfs[] = {
1326 "Undefined",
1327 "sRGB",
1328 "BT.601",
1329 "BT.1886",
1330 "Adobe RGB",
1331 "DCI-P3",
1332 "BT.2020",
1333 "Gamma function",
1334 "SMPTE ST 2084",
1335 "Hybrid Log",
1336 "Custom"
1339 void edid_state::parse_displayid_interface_features(const unsigned char *x)
1341 check_displayid_datablock_revision(x[1]);
1343 if (!check_displayid_datablock_length(x, 9))
1344 return;
1346 dispid.has_display_interface_features = true;
1347 unsigned len = x[2];
1348 if (len > 0) print_flags(" Supported bpc for RGB encoding", x[3], bpc444);
1349 if (len > 1) print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x[4], bpc444);
1350 if (len > 2) print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x[5], bpc4xx);
1351 if (len > 3) print_flags(" Supported bpc for YCbCr 4:2:0 encoding", x[6], bpc4xx);
1352 if (len > 4 && x[7])
1353 printf(" Minimum pixel rate at which YCbCr 4:2:0 encoding is supported: %.3f MHz\n",
1354 74.25 * x[7]);
1355 if (len > 5) print_flags(" Supported audio capability and features (kHz)",
1356 x[8], audiorates, true);
1357 if (len > 6) print_flags(" Supported color space and EOTF standard combination 1",
1358 x[9], colorspace_eotf_combinations);
1359 if (len > 7) print_flags(" Supported color space and EOTF standard combination 2",x[10], colorspace_eotf_reserved);
1361 unsigned i = 0;
1363 if (len > 8 && x[11]) {
1364 printf(" Supported color space and EOTF additional combinations:");
1365 for (i = 0; i < x[11]; i++) {
1366 if (i > 6) {
1367 printf("\n Number of additional color space and EOTF combinations (%d) is greater than allowed (7).", x[11]);
1368 break;
1369 } else if (i + 10 > len) {
1370 printf("\n Number of additional color space and EOTF combinations (%d) is too many to fit in block (%d).", x[11], len - 9);
1371 break;
1374 const char *colorspace = "Out of range";
1375 const char *eotf = "Out of range";
1376 unsigned colorspace_index = (x[12 + i] >> 4) & 0xf;
1377 unsigned eotf_index = x[12 + i] & 0xf;
1379 if (colorspace_index < sizeof(colorspaces) / sizeof(colorspaces[0]))
1380 colorspace = colorspaces[colorspace_index];
1381 if (eotf_index < sizeof(eotfs) / sizeof(eotfs[0]))
1382 eotf = eotfs[eotf_index];
1384 if (i > 0)
1385 printf(", ");
1386 if (!strcmp(colorspace, eotf))
1387 printf("%s", colorspace);
1388 else
1389 printf("%s/%s", colorspace, eotf);
1391 printf("\n");
1393 check_displayid_datablock_length(x, 9 + i, 9 + i, 9 + i);
1396 // tag 0x29
1398 void edid_state::parse_displayid_ContainerID(const unsigned char *x)
1400 check_displayid_datablock_revision(x[1]);
1402 if (check_displayid_datablock_length(x, 16, 16)) {
1403 x += 3;
1404 printf(" Container ID: %s\n", containerid2s(x).c_str());
1408 // tag 0x2b
1410 void edid_state::parse_displayid_adaptive_sync(const unsigned char *x)
1412 check_displayid_datablock_revision(x[1], 0x70);
1414 unsigned size = 6 + ((x[1] >> 4) & 0x7);
1415 unsigned len = x[2];
1416 unsigned descriptor = 1;
1418 x += 3;
1419 if (len % size)
1420 fail("DisplayID payload length %u is not a multiple of %u.\n", len, size);
1421 while (len >= size) {
1422 printf(" Descriptor #%u:\n", descriptor++);
1424 printf(" %sNative Panel Range\n", (x[0] & 1) ? "" : "Non-");
1425 unsigned v = (x[0] >> 2) & 3;
1426 switch (v) {
1427 case 0: printf(" Fixed Average V-Total\n"); break;
1428 case 1: printf(" Fixed Average V-Total and Adaptive V-Total\n"); break;
1429 default:
1430 printf(" Reserved %u\n", v);
1431 fail("Use of reserved value %u.\n", v);
1432 break;
1434 if (x[0] & 0x10)
1435 printf(" Supports Seamless Transition\n");
1436 if (x[0] & 0x02)
1437 printf(" 'Max Single Frame Duration Increase' field value without jitter impact\n");
1438 if (x[0] & 0x20)
1439 printf(" 'Max Single Frame Duration Decrease' field value without jitter impact\n");
1440 printf(" Max Duration Increase: %.2f ms\n", x[1] / 4.0);
1441 printf(" Max Duration Decrease: %.2f ms\n", x[5] / 4.0);
1442 printf(" Min Refresh Rate: %u Hz\n", x[2]);
1443 printf(" Max Refresh Rate: %u Hz\n", 1 + x[3] + (x[4] & 3) * 256);
1445 len -= size;
1446 x += size;
1450 // tag 0x32
1452 void edid_state::parse_displayid_type_10_timing(const unsigned char *x,
1453 unsigned sz, bool is_cta)
1455 struct timings t = {};
1456 std::string name = is_cta ? std::string("VTDB ") + std::to_string(cta.vec_vtdbs.size() + 1) : "CVT";
1457 std::string s("aspect ");
1459 t.hact = 1 + (x[1] | (x[2] << 8));
1460 t.vact = 1 + (x[3] | (x[4] << 8));
1461 calc_ratio(&t);
1462 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1464 switch ((x[0] >> 5) & 0x3) {
1465 case 0:
1466 s += ", no 3D stereo";
1467 break;
1468 case 1:
1469 s += ", 3D stereo";
1470 break;
1471 case 2:
1472 s += ", 3D stereo depends on user action";
1473 break;
1474 case 3:
1475 s += ", reserved";
1476 fail("Reserved stereo 0x03.\n");
1477 break;
1480 switch (x[0] & 0x07) {
1481 case 1: t.rb = RB_CVT_V1; break;
1482 case 2: t.rb = RB_CVT_V2; break;
1483 case 3: t.rb = RB_CVT_V3; break;
1484 default: break;
1487 unsigned rb = t.rb;
1488 unsigned rb_h_blank = rb == RB_CVT_V3 ? 80 : 0;
1489 unsigned rb_v_blank = 460;
1490 bool early_vsync_rqd = false;
1492 if (x[0] & 0x10) {
1493 if (rb == RB_CVT_V2) {
1494 s += ", refresh rate * (1000/1001) supported";
1495 t.rb |= RB_ALT;
1496 } else if (rb == RB_CVT_V3) {
1497 s += ", hblank is 160 pixels";
1498 t.rb |= RB_ALT;
1499 rb_h_blank = 160;
1500 } else {
1501 fail("VR_HB must be 0.\n");
1504 if (x[0] & 0x80)
1505 s += ", YCbCr 4:2:0";
1507 if (x[0] & 0x08) {
1508 if (rb == RB_CVT_V3) {
1509 early_vsync_rqd = true;
1510 s += ", early-vsync";
1511 } else {
1512 fail("EVS must be 0.\n");
1516 unsigned refresh = 1 + x[5] + (sz == 6 ? 0 : ((x[6] & 3) << 8));
1518 if (sz > 6) {
1519 if (rb == RB_CVT_V3) {
1520 unsigned delta_hblank = (x[6] >> 2) & 7;
1522 if (rb_h_blank == 80)
1523 rb_h_blank = 80 + 8 * delta_hblank;
1524 else if (delta_hblank <= 5)
1525 rb_h_blank = 160 + 8 * delta_hblank;
1526 else
1527 rb_h_blank = 160 - (delta_hblank - 5) * 8;
1528 if (delta_hblank)
1529 s += ", delta-hblank=" + std::to_string(delta_hblank);
1531 rb_v_blank += ((x[6] >> 5) & 7) * 35;
1532 if (rb_v_blank > 460)
1533 s += ", add-vblank=" + std::to_string(rb_v_blank - 460);
1534 } else {
1535 if (x[6] & 0xe0)
1536 fail("Additional_Vertical_Blank_Time must be 0.\n");
1537 if (x[6] & 0x1c)
1538 fail("Delta_Horizontal_Blank must be 0.\n");
1542 edid_cvt_mode(refresh, t, rb_h_blank, rb_v_blank, early_vsync_rqd);
1544 print_timings(" ", &t, name.c_str(), s.c_str());
1545 if (is_cta) {
1546 timings_ext te(t, name.c_str(), s);
1547 cta.vec_vtdbs.push_back(te);
1551 // tag 0x7e, OUI 3A-02-92 (VESA)
1553 void edid_state::parse_displayid_vesa(const unsigned char *x)
1555 check_displayid_datablock_revision(x[1]);
1557 if (!check_displayid_datablock_length(x, 5, 7))
1558 return;
1560 unsigned len = x[2];
1561 x += 6;
1562 printf(" Data Structure Type: ");
1563 switch (x[0] & 7) {
1564 case 0: printf("eDP\n"); break;
1565 case 1: printf("DP\n"); break;
1566 default: printf("Reserved (%d)\n", x[0] & 7); break;
1569 if ((x[0] >> 3) & 15)
1570 warn("Reserved bits 6:3 (%d) are not 0.\n", (x[0] >> 3) & 15);
1572 printf(" Default Colorspace and EOTF Handling: %s\n",
1573 (x[0] & 0x80) ? "Native as specified in the Display Parameters DB" : "sRGB");
1575 printf(" Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel: %u\n",
1576 x[1] & 0xf);
1577 if ((x[1] & 0xf) > 8)
1578 warn("Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel exceeds 8.\n");
1580 if ((x[1] >> 4) & 1)
1581 warn("Reserved bit 4 is not 0.\n");
1583 printf(" Multi-SST Operation: ");
1584 switch ((x[1] >> 5) & 3) {
1585 case 0: printf("Not Supported\n"); break;
1586 case 1: printf("Two Streams (number of links shall be 2 or 4)\n"); break;
1587 case 2: printf("Four Streams (number of links shall be 4)\n"); break;
1588 case 3: printf("Reserved\n"); warn("Invalid option for Multi-SST Operation.\n"); break;
1591 if ((x[1] >> 7) & 1)
1592 warn("Reserved bit 7 is not 0.\n");
1594 if (len >= 7) {
1595 double bpp = (x[2] & 0x3f) + (x[3] & 0x0f) / 16.0;
1596 printf(" Pass through timing's target DSC bits per pixel: %.4f\n", bpp);
1600 // tag 0x7f, OUI 00-10-FA (Apple)
1602 void edid_state::parse_displayid_apple(const unsigned char *x)
1604 int length = x[2] - 3;
1606 x += 6;
1608 // Based on the very limited information I found here:
1609 // https://opensource.apple.com/source/IOKitUser/IOKitUser-1445.40.1/graphics.subproj/IODisplayLib.c
1610 switch (x[0]) {
1611 case 1:
1612 printf(" Type: BLC Info/Corrections, Version: %u\n", x[1]);
1613 break;
1614 default:
1615 printf(" Type: %u, Version: %u\n", x[0], x[1]);
1616 break;
1618 hex_block(" ", x + 2, length - 2);
1621 // tag 0x81
1623 void edid_state::parse_displayid_cta_data_block(const unsigned char *x)
1625 check_displayid_datablock_revision(x[1]);
1627 unsigned len = x[2];
1628 unsigned i;
1630 if (len > 248) {
1631 fail("Length is > 248.\n");
1632 len = 248;
1634 x += 3;
1636 for (i = 0; i < len; i += (x[i] & 0x1f) + 1) {
1637 cta_block(x + i, dispid.found_tags);
1640 if (i != len)
1641 fail("Length is %u instead of %u.\n", len, i);
1644 // DisplayID main
1646 std::string edid_state::product_type(unsigned char x, bool heading)
1648 std::string headingstr;
1650 if (dispid.version < 0x20) {
1651 headingstr = "Display Product Type";
1652 if (heading) return headingstr;
1653 dispid.is_display = x == 2 || x == 3 || x == 4 || x == 6;
1654 switch (x) {
1655 case 0: return "Extension Section";
1656 case 1: return "Test Structure; test equipment only";
1657 case 2: return "Display panel or other transducer, LCD or PDP module, etc.";
1658 case 3: return "Standalone display device";
1659 case 4: return "Television receiver";
1660 case 5: return "Repeater/translator";
1661 case 6: return "DIRECT DRIVE monitor";
1662 default: break;
1664 } else {
1665 headingstr = "Display Product Primary Use Case";
1666 if (heading) return headingstr;
1667 dispid.is_display = x >= 2 && x <= 8;
1668 switch (x) {
1669 case 0: return "Same primary use case as the base section";
1670 case 1: return "Test Structure; test equipment only";
1671 case 2: return "None of the listed primary use cases; generic display";
1672 case 3: return "Television (TV) display";
1673 case 4: return "Desktop productivity display";
1674 case 5: return "Desktop gaming display";
1675 case 6: return "Presentation display";
1676 case 7: return "Head-mounted Virtual Reality (VR) display";
1677 case 8: return "Head-mounted Augmented Reality (AR) display";
1678 default: break;
1681 fail("Unknown %s 0x%02x.\n", headingstr.c_str(), x);
1682 return std::string("Unknown " + headingstr + " (") + utohex(x) + ")";
1685 void edid_state::preparse_displayid_block(unsigned char *x)
1687 bool update_checksum = false;
1688 unsigned length = x[2];
1689 unsigned offset = 5;
1691 if (length > 121)
1692 length = 121;
1694 dispid.preparsed_displayid_blocks++;
1695 while (length > 0) {
1696 unsigned tag = x[offset];
1697 unsigned len = x[offset + 2];
1699 switch (tag) {
1700 case 0x00:
1701 case 0x20:
1702 if (replace_unique_ids &&
1703 (x[offset + 0x08] || x[offset + 0x09] ||
1704 x[offset + 0x0a] || x[offset + 0x0b])) {
1705 // Replace by 123456
1706 x[offset + 0x08] = 0x40;
1707 x[offset + 0x09] = 0xe2;
1708 x[offset + 0x0a] = 0x01;
1709 x[offset + 0x0b] = 0x00;
1710 update_checksum = true;
1712 if (replace_unique_ids && x[offset + 0x0c] != 0xff) {
1713 x[offset + 0x0c] = 0;
1714 x[offset + 0x0d] = 0;
1715 update_checksum = true;
1717 break;
1718 case 0x12:
1719 case 0x28:
1720 if (replace_unique_ids &&
1721 (x[offset + 0x15] || x[offset + 0x16] ||
1722 x[offset + 0x17] || x[offset + 0x18])) {
1723 // Replace by 123456
1724 x[offset + 0x15] = 0x40;
1725 x[offset + 0x16] = 0xe2;
1726 x[offset + 0x17] = 0x01;
1727 x[offset + 0x18] = 0x00;
1728 update_checksum = true;
1730 break;
1731 case 0x29:
1732 if (replace_unique_ids) {
1733 update_checksum = true;
1734 memset(x + offset + 3, 0, 16);
1736 break;
1737 case 0x02:
1738 dispid.preparsed_color_ids |= 1 << ((x[offset + 1] >> 3) & 0x0f);
1739 break;
1740 case 0x0e:
1741 dispid.preparsed_xfer_ids |= 1 << ((x[offset + 1] >> 4) & 0x0f);
1742 break;
1743 default:
1744 break;
1747 if (length < 3)
1748 break;
1750 if (length < len + 3)
1751 break;
1753 if (!tag && !len)
1754 break;
1756 length -= len + 3;
1757 offset += len + 3;
1759 if (update_checksum) {
1760 replace_checksum(x + 1, x[2] + 5);
1761 replace_checksum(x, EDID_PAGE_SIZE);
1765 unsigned edid_state::displayid_block(const unsigned version, const unsigned char *x, unsigned length)
1767 unsigned i;
1768 unsigned tag = x[0];
1769 unsigned tag_version = (tag < 0x20) ? 1 : (tag < 0x7f) ? 2 : (tag < 0x80) ? 1 : 0;
1770 bool dooutputname = true;
1771 unsigned len = (length < 3) ? 0 : x[2];
1772 bool hasoui = false;
1773 unsigned ouinum;
1775 switch (tag) {
1776 // DisplayID 1.3:
1777 case 0x00:
1778 data_block_oui("Product Identification Data Block (" + utohex(tag) + ")",
1779 x + 3, len, &ouinum, true, true, true);
1780 dooutputname = false;
1781 hasoui = true;
1782 break;
1783 case 0x01: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
1784 case 0x02: data_block = "Color Characteristics Data Block"; break;
1785 case 0x03: data_block = "Video Timing Modes Type 1 - Detailed Timings Data Block"; break;
1786 case 0x04: data_block = "Video Timing Modes Type 2 - Detailed Timings Data Block"; break;
1787 case 0x05: data_block = "Video Timing Modes Type 3 - Short Timings Data Block"; break;
1788 case 0x06: data_block = "Video Timing Modes Type 4 - DMT Timings Data Block"; break;
1789 case 0x07: data_block = "Supported Timing Modes Type 1 - VESA DMT Timings Data Block"; break;
1790 case 0x08: data_block = "Supported Timing Modes Type 2 - CTA-861 Timings Data Block"; break;
1791 case 0x09: data_block = "Video Timing Range Data Block"; break;
1792 case 0x0a: data_block = "Product Serial Number Data Block"; break;
1793 case 0x0b: data_block = "GP ASCII String Data Block"; break;
1794 case 0x0c: data_block = "Display Device Data Data Block"; break;
1795 case 0x0d: data_block = "Interface Power Sequencing Data Block"; break;
1796 case 0x0e: data_block = "Transfer Characteristics Data Block"; break;
1797 case 0x0f: data_block = "Display Interface Data Block"; break;
1798 case 0x10: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
1799 case 0x11: data_block = "Video Timing Modes Type 5 - Short Timings Data Block"; break;
1800 case 0x12: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
1801 case 0x13: data_block = "Video Timing Modes Type 6 - Detailed Timings Data Block"; break;
1802 // 0x14 .. 0x7e RESERVED for Additional VESA-defined Data Blocks
1803 // DisplayID 2.0
1804 case 0x20:
1805 data_block_oui("Product Identification Data Block (" + utohex(tag) + ")",
1806 x + 3, len, &ouinum, false, false, true);
1807 dooutputname = false;
1808 hasoui = true;
1809 break;
1810 case 0x21: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
1811 case 0x22: data_block = "Video Timing Modes Type 7 - Detailed Timings Data Block"; break;
1812 case 0x23: data_block = "Video Timing Modes Type 8 - Enumerated Timing Codes Data Block"; break;
1813 case 0x24: data_block = "Video Timing Modes Type 9 - Formula-based Timings Data Block"; break;
1814 case 0x25: data_block = "Dynamic Video Timing Range Limits Data Block"; break;
1815 case 0x26: data_block = "Display Interface Features Data Block"; break;
1816 case 0x27: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
1817 case 0x28: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
1818 case 0x29: data_block = "ContainerID Data Block"; break;
1819 case 0x2b: data_block = "Adaptive Sync Data Block"; break;
1820 case 0x32: data_block = "Video Timing Modes Type 10 - Formula-based Timings Data Block"; break;
1821 // 0x2a .. 0x7d RESERVED for Additional VESA-defined Data Blocks
1822 case 0x7e: // DisplayID 2.0
1823 data_block_oui("Vendor-Specific Data Block (" + utohex(tag) + ")",
1824 x + 3, len, &ouinum, false, false, true);
1825 dooutputname = false;
1826 hasoui = true;
1827 tag |= ouinum;
1828 break;
1829 case 0x7f: // DisplayID 1.3
1830 data_block_oui("Vendor-Specific Data Block (" + utohex(tag) + ")",
1831 x + 3, len, &ouinum, false, true, true);
1832 dooutputname = false;
1833 hasoui = true;
1834 tag |= ouinum;
1835 break;
1836 // 0x80 RESERVED
1837 case 0x81: data_block = "CTA-861 DisplayID Data Block"; break;
1838 // 0x82 .. 0xff RESERVED
1839 default: data_block = "Unknown DisplayID Data Block (" + utohex(tag) + ", length " + std::to_string(len) + ")"; break;
1842 if (length < 3) {
1843 // Report a problem when the remaining bytes are not 0.
1844 data_block.clear(); // Probably not a Data Block so clear this.
1845 if (tag || (length > 1 && x[1])) {
1846 printf(" Filler:\n");
1847 fail("Not enough bytes remain (%d) for a DisplayID data block and the DisplayID filler is non-0.\n", length);
1848 hex_block(" ", x, length);
1850 return length;
1853 if (length < len + 3) {
1854 data_block.clear(); // Probably not a Data Block so clear this.
1855 printf(" Filler:\n");
1856 fail("The length of this DisplayID data block (%d) exceeds the number of bytes remaining (%d).\n", len + 3, length);
1857 hex_block(" ", x, length);
1858 return length;
1861 if (!tag && !len) {
1862 // A Product Identification Data Block with no payload bytes is not valid - assume this is the end.
1863 data_block.clear(); // Probably not a Product Identification Data Block so clear this.
1864 if (!memchk(x, length)) {
1865 printf(" Filler:\n");
1866 fail("Non-0 filler bytes in the DisplayID block.\n");
1867 hex_block(" ", x, length);
1869 return length;
1872 if (dooutputname && data_block.length())
1873 printf(" %s:\n", data_block.c_str());
1875 if (version >= 0x20 && tag_version == 1)
1876 fail("Use of DisplayID v1.x tag for DisplayID v%u.%u.\n",
1877 version >> 4, version & 0xf);
1878 if (version < 0x20 && tag_version == 2)
1879 fail("Use of DisplayID v2.0 tag for DisplayID v%u.%u.\n",
1880 version >> 4, version & 0xf);
1882 unsigned block_rev = x[1] & 0x07;
1884 switch (tag) {
1885 case 0x00: parse_displayid_product_id(x); break;
1886 case 0x01: parse_displayid_parameters(x); break;
1887 case 0x02: parse_displayid_color_characteristics(x); break;
1888 case 0x03:
1889 check_displayid_datablock_revision(x[1], 0, block_rev & 1);
1890 for (i = 0; i < len / 20; i++)
1891 parse_displayid_type_1_7_timing(&x[3 + (i * 20)], false, block_rev);
1892 break;
1893 case 0x04:
1894 check_displayid_datablock_revision(x[1]);
1895 for (i = 0; i < len / 11; i++)
1896 parse_displayid_type_2_timing(&x[3 + (i * 11)]);
1897 break;
1898 case 0x05:
1899 check_displayid_datablock_revision(x[1], 0, block_rev & 1);
1900 for (i = 0; i < len / 3; i++)
1901 parse_displayid_type_3_timing(&x[3 + (i * 3)]);
1902 break;
1903 case 0x06:
1904 check_displayid_datablock_revision(x[1], 0xc0, 1);
1905 for (i = 0; i < len; i++)
1906 parse_displayid_type_4_8_timing((x[1] & 0xc0) >> 6, x[3 + i]);
1907 break;
1908 case 0x07:
1909 check_displayid_datablock_revision(x[1]);
1910 for (i = 0; i < min(len, 10) * 8; i++)
1911 if (x[3 + i / 8] & (1 << (i % 8))) {
1912 char type[16];
1913 sprintf(type, "DMT 0x%02x", i + 1);
1914 print_timings(" ", find_dmt_id(i + 1), type);
1916 break;
1917 case 0x08:
1918 check_displayid_datablock_revision(x[1]);
1919 for (i = 0; i < min(len, 8) * 8; i++)
1920 if (x[3 + i / 8] & (1 << (i % 8))) {
1921 char type[16];
1922 sprintf(type, "VIC %3u", i + 1);
1923 print_timings(" ", find_vic_id(i + 1), type);
1925 break;
1926 case 0x09: parse_displayid_video_timing_range_limits(x); break;
1927 case 0x0a:
1928 case 0x0b: parse_displayid_string(x); break;
1929 case 0x0c: parse_displayid_display_device(x); break;
1930 case 0x0d: parse_displayid_intf_power_sequencing(x); break;
1931 case 0x0e: parse_displayid_transfer_characteristics(x); break;
1932 case 0x0f: parse_displayid_display_intf(x); break;
1933 case 0x10: parse_displayid_stereo_display_intf(x); break;
1934 case 0x11:
1935 check_displayid_datablock_revision(x[1]);
1936 for (i = 0; i < len / 7; i++)
1937 parse_displayid_type_5_timing(&x[3 + (i * 7)]);
1938 break;
1939 case 0x12: parse_displayid_tiled_display_topology(x, false); break;
1940 case 0x13:
1941 check_displayid_datablock_revision(x[1]);
1942 for (i = 0; i < len; i += (x[3 + i + 2] & 0x40) ? 17 : 14)
1943 parse_displayid_type_6_timing(&x[3 + i]);
1944 break;
1945 case 0x20: parse_displayid_product_id(x); break;
1946 case 0x21:
1947 if (block_rev >= 1)
1948 check_displayid_datablock_revision(x[1], 0x80, 1);
1949 else
1950 check_displayid_datablock_revision(x[1], 0x80, 0);
1951 parse_displayid_parameters_v2(x, block_rev);
1952 break;
1953 case 0x22: {
1954 unsigned sz = 20;
1956 if (block_rev >= 2)
1957 check_displayid_datablock_revision(x[1], 0x08, 2);
1958 else if (block_rev == 1)
1959 check_displayid_datablock_revision(x[1], 0x08, 1);
1960 else
1961 check_displayid_datablock_revision(x[1]);
1962 sz += (x[1] & 0x70) >> 4;
1963 if (block_rev >= 1 && (x[1] & 0x08))
1964 printf(" These timings support DSC pass-through\n");
1965 for (i = 0; i < len / sz; i++)
1966 parse_displayid_type_1_7_timing(&x[3 + i * sz], true, block_rev);
1967 break;
1969 case 0x23:
1970 if (block_rev)
1971 check_displayid_datablock_revision(x[1], 0xe8, 1);
1972 else
1973 check_displayid_datablock_revision(x[1], 0xc8);
1974 if (x[1] & 0x08) {
1975 for (i = 0; i < len / 2; i++)
1976 parse_displayid_type_4_8_timing((x[1] & 0xc0) >> 6,
1977 x[3 + i * 2] |
1978 (x[4 + i * 2] << 8));
1979 } else {
1980 for (i = 0; i < len; i++)
1981 parse_displayid_type_4_8_timing((x[1] & 0xc0) >> 6,
1982 x[3 + i]);
1984 break;
1985 case 0x24:
1986 check_displayid_datablock_revision(x[1]);
1987 for (i = 0; i < len / 6; i++)
1988 parse_displayid_type_9_timing(&x[3 + i * 6]);
1989 break;
1990 case 0x25: parse_displayid_dynamic_video_timings_range_limits(x); break;
1991 case 0x26: parse_displayid_interface_features(x); break;
1992 case 0x27: parse_displayid_stereo_display_intf(x); break;
1993 case 0x28: parse_displayid_tiled_display_topology(x, true); break;
1994 case 0x29: parse_displayid_ContainerID(x); break;
1995 case 0x2b: parse_displayid_adaptive_sync(x); break;
1996 case 0x32: {
1997 unsigned sz = 6 + ((x[1] & 0x70) >> 4);
1999 check_displayid_datablock_revision(x[1], 0x70);
2000 for (i = 0; i < len / sz; i++)
2001 parse_displayid_type_10_timing(&x[3 + i * sz], sz);
2002 break;
2004 case 0x7e|kOUI_VESA: parse_displayid_vesa(x); break;
2005 case 0x7f|kOUI_Apple: parse_displayid_apple(x); break;
2006 case 0x81: parse_displayid_cta_data_block(x); break;
2007 default: hex_block(" ", x + 3 + (hasoui ? 3 : 0), (len > (hasoui ? 3 : 0)) ? len - (hasoui ? 3 : 0) : 0); break;
2010 if ((tag == 0x00 || tag == 0x20) &&
2011 (!dispid.is_base_block || dispid.block_number > 0))
2012 fail("%s is required to be the first DisplayID Data Block.\n",
2013 data_block.c_str());
2015 dispid.block_number++;
2016 return len + 3;
2019 void edid_state::parse_displayid_block(const unsigned char *x)
2021 unsigned version = x[1];
2022 unsigned length = x[2];
2023 unsigned prod_type = x[3]; // future check: based on type, check for required data blocks
2024 unsigned ext_count = x[4];
2026 printf(" Version: %u.%u\n Extension Count: %u\n",
2027 version >> 4, version & 0xf, ext_count);
2029 if (dispid.is_base_block) {
2030 dispid.version = version;
2031 printf(" %s: %s\n", product_type(prod_type, true).c_str(),
2032 product_type(prod_type, false).c_str());
2033 if (!prod_type)
2034 fail("DisplayID Base Block has no product type.\n");
2035 if (ext_count != dispid.preparsed_displayid_blocks - 1)
2036 fail("Expected %u DisplayID Extension Block%s, but got %u.\n",
2037 ext_count,
2038 ext_count > 1 ? "s" : "",
2039 dispid.preparsed_displayid_blocks - 1);
2040 } else {
2041 if (prod_type)
2042 fail("Product Type should be 0 in extension block.\n");
2043 if (ext_count)
2044 fail("Extension Count should be 0 in extension block.\n");
2045 if (version != dispid.version)
2046 fail("Got version %u.%u, expected %u.%u.\n",
2047 version >> 4, version & 0xf,
2048 dispid.version >> 4, dispid.version & 0xf);
2051 if (length > 121) {
2052 fail("DisplayID length %d is greater than 121.\n", length);
2053 length = 121;
2056 unsigned len;
2057 for (const unsigned char *y = x + 5; length > 0; y += len) {
2058 len = displayid_block(version, y, length);
2059 length -= len;
2063 * DisplayID length field is number of following bytes
2064 * but checksum is calculated over the entire structure
2065 * (excluding DisplayID-in-EDID magic byte)
2067 data_block.clear();
2068 do_checksum(" ", x + 1, x[2] + 5);
2070 unused_bytes = 0x7f - (1 + x[2] + 5);
2071 if (!memchk(x + 1 + x[2] + 5, unused_bytes)) {
2072 data_block = "Padding";
2073 fail("Contains non-zero bytes.\n");
2075 dispid.is_base_block = false;
2078 void edid_state::check_displayid_blocks()
2080 data_block = "DisplayID";
2081 if (!dispid.has_product_identification)
2082 fail("Missing DisplayID Product Identification Data Block.\n");
2083 if (dispid.is_display && !dispid.has_display_parameters)
2084 fail("Missing DisplayID Display Parameters Data Block.\n");
2085 if (dispid.is_display && !dispid.has_display_interface_features)
2086 fail("Missing DisplayID Display Interface Features Data Block.\n");
2087 if (dispid.is_display && !dispid.has_type_1_7)
2088 fail("Missing DisplayID Type %s Detailed Timing Data Block.\n",
2089 dispid.version >= 0x20 ? "VII" : "I");
2090 if (dispid.preferred_timings.empty())
2091 fail("DisplayID expects at least one preferred timing.\n");
2092 if (cta.image_width && dispid.image_width &&
2093 (cta.image_width != dispid.image_width ||
2094 cta.image_height != dispid.image_height))
2095 fail("Image size mismatch: CTA-861: %.1fx%.1fmm DisplayID: %.1fx%.1fmm.\n",
2096 cta.image_width / 10.0, cta.image_height / 10.0,
2097 dispid.image_width / 10.0, dispid.image_height / 10.0);
2098 if (dispid.image_width && dispid.image_width < 25600 && dispid.image_height < 25600 &&
2099 (abs((int)dispid.image_width - (int)base.max_display_width_mm * 10) >= 100 ||
2100 abs((int)dispid.image_height - (int)base.max_display_height_mm * 10) >= 100))
2101 fail("Image size mismatch: DisplayID: %.1fx%.1fmm Base EDID: %u.0x%u.0mm.\n",
2102 dispid.image_width / 10.0, dispid.image_height / 10.0,
2103 base.max_display_width_mm, base.max_display_height_mm);