edid-decode: fix reporting PNP as a proper PNP
[edid-decode.git] / parse-displayid-block.cpp
blobd527bf2edc84323ef0efbd482ef774b1b453948c
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::parse_displayid_parameters(const unsigned char *x)
135 check_displayid_datablock_revision(x[1]);
137 if (!check_displayid_datablock_length(x, 12, 12))
138 return;
140 dispid.has_display_parameters = true;
141 printf(" Image size: %.1f mm x %.1f mm\n",
142 ((x[4] << 8) + x[3]) / 10.0,
143 ((x[6] << 8) + x[5]) / 10.0);
144 printf(" Pixels: %d x %d\n",
145 (x[8] << 8) + x[7], (x[10] << 8) + x[9]);
146 print_flag_lines(" ", " Feature support flags:",
147 x[11], feature_support_flags);
149 if (x[12] != 0xff)
150 printf(" Gamma: %.2f\n", ((x[12] + 100.0) / 100.0));
151 printf(" Aspect ratio: %.2f\n", ((x[13] + 100.0) / 100.0));
152 printf(" Dynamic bpc native: %d\n", (x[14] & 0xf) + 1);
153 printf(" Dynamic bpc overall: %d\n", ((x[14] >> 4) & 0xf) + 1);
156 // tag 0x02
158 static const char *std_colorspace_ids[] = {
159 "sRGB",
160 "BT.601",
161 "BT.709",
162 "Adobe RGB",
163 "DCI-P3",
164 "NTSC",
165 "EBU",
166 "Adobe Wide Gamut RGB",
167 "DICOM"
170 static double fp2d(unsigned short fp)
172 return fp / 4096.0;
175 void edid_state::parse_displayid_color_characteristics(const unsigned char *x)
177 check_displayid_datablock_revision(x[1], 0xf8, 1);
179 unsigned cie_year = (x[1] & 0x80) ? 1976 : 1931;
180 unsigned xfer_id = (x[1] >> 3) & 0x0f;
181 unsigned num_whitepoints = x[3] & 0x0f;
182 unsigned num_primaries = (x[3] >> 4) & 0x07;
183 bool temporal_color = x[3] & 0x80;
184 unsigned offset = 4;
186 printf(" Uses %s color\n", temporal_color ? "temporal" : "spatial");
187 printf(" Uses %u CIE (x, y) coordinates\n", cie_year);
188 if (xfer_id) {
189 printf(" Associated with Transfer Characteristics Data Block with Identifier %u\n", xfer_id);
190 if (!(dispid.preparsed_xfer_ids & (1 << xfer_id)))
191 fail("Missing Transfer Characteristics Data Block with Identifier %u.\n", xfer_id);
193 if (!num_primaries) {
194 printf(" Uses color space %s\n",
195 x[4] >= ARRAY_SIZE(std_colorspace_ids) ? "Reserved" :
196 std_colorspace_ids[x[4]]);
197 offset++;
199 for (unsigned i = 0; i < num_primaries; i++) {
200 unsigned idx = offset + 3 * i;
202 printf(" Primary #%u: (%.4f, %.4f)\n", i,
203 fp2d(x[idx] | ((x[idx + 1] & 0x0f) << 8)),
204 fp2d(((x[idx + 1] & 0xf0) >> 4) | (x[idx + 2] << 4)));
206 offset += 3 * num_primaries;
207 for (unsigned i = 0; i < num_whitepoints; i++) {
208 unsigned idx = offset + 3 * i;
210 printf(" White point #%u: (%.4f, %.4f)\n", i,
211 fp2d(x[idx] | ((x[idx + 1] & 0x0f) << 8)),
212 fp2d(((x[idx + 1] & 0xf0) >> 4) | (x[idx + 2] << 4)));
216 // tag 0x03 and 0x22
218 void edid_state::parse_displayid_type_1_7_timing(const unsigned char *x,
219 bool type7, unsigned block_rev, bool is_cta)
221 struct timings t = {};
222 unsigned hbl, vbl;
223 std::string s("aspect ");
225 dispid.has_type_1_7 = true;
226 t.pixclk_khz = (type7 ? 1 : 10) * (1 + (x[0] + (x[1] << 8) + (x[2] << 16)));
227 switch (x[3] & 0xf) {
228 case 0:
229 s += "1:1";
230 t.hratio = t.vratio = 1;
231 break;
232 case 1:
233 s += "5:4";
234 t.hratio = 5;
235 t.vratio = 4;
236 break;
237 case 2:
238 s += "4:3";
239 t.hratio = 4;
240 t.vratio = 3;
241 break;
242 case 3:
243 s += "15:9";
244 t.hratio = 15;
245 t.vratio = 9;
246 break;
247 case 4:
248 s += "16:9";
249 t.hratio = 16;
250 t.vratio = 9;
251 break;
252 case 5:
253 s += "16:10";
254 t.hratio = 16;
255 t.vratio = 10;
256 break;
257 case 6:
258 s += "64:27";
259 t.hratio = 64;
260 t.vratio = 27;
261 break;
262 case 7:
263 s += "256:135";
264 t.hratio = 256;
265 t.vratio = 135;
266 break;
267 case 8:
268 s += "undefined";
269 break;
270 default:
271 s += "reserved";
272 fail("Unknown aspect 0x%02x.\n", x[3] & 0xf);
273 break;
275 switch ((x[3] >> 5) & 0x3) {
276 case 0:
277 s += ", no 3D stereo";
278 break;
279 case 1:
280 s += ", 3D stereo";
281 break;
282 case 2:
283 s += ", 3D stereo depends on user action";
284 break;
285 case 3:
286 s += ", reserved";
287 fail("Reserved stereo 0x03.\n");
288 break;
290 if (block_rev >= 2 && (x[3] & 0x80))
291 s += ", YCbCr 4:2:0";
293 t.hact = 1 + (x[4] | (x[5] << 8));
294 hbl = 1 + (x[6] | (x[7] << 8));
295 t.hfp = 1 + (x[8] | ((x[9] & 0x7f) << 8));
296 t.hsync = 1 + (x[10] | (x[11] << 8));
297 t.hbp = hbl - t.hfp - t.hsync;
298 if ((x[9] >> 7) & 0x1)
299 t.pos_pol_hsync = true;
300 t.vact = 1 + (x[12] | (x[13] << 8));
301 vbl = 1 + (x[14] | (x[15] << 8));
302 t.vfp = 1 + (x[16] | ((x[17] & 0x7f) << 8));
303 t.vsync = 1 + (x[18] | (x[19] << 8));
304 t.vbp = vbl - t.vfp - t.vsync;
305 if ((x[17] >> 7) & 0x1)
306 t.pos_pol_vsync = true;
308 if (x[3] & 0x10) {
309 t.interlaced = true;
310 t.vfp /= 2;
311 t.vsync /= 2;
312 t.vbp /= 2;
314 if (block_rev < 2 && (x[3] & 0x80)) {
315 s += ", preferred";
316 dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
319 print_timings(" ", &t, "DTD", s.c_str(), true);
320 if (is_cta) {
321 timings_ext te(t, "DTD", s);
322 cta.vec_vtdbs.push_back(te);
324 // Only use a T7VTDB if is cannot be expressed by a
325 // DTD or a T10VTDB.
326 if (t.hact <= 4095 && t.vact <= 4095 &&
327 t.pixclk_khz <= 655360 && !(x[3] & 0xe0)) {
328 fail("This T7VTDB can be represented as an 18-byte DTD.\n");
329 return;
331 unsigned htot = t.hact + t.hfp + t.hsync + t.hbp;
332 unsigned vtot = t.vact + t.vfp + t.vsync + t.vbp;
333 unsigned refresh = (t.pixclk_khz * 1000ULL) / (htot * vtot);
335 for (unsigned rb = RB_NONE; rb <= RB_CVT_V3; rb++) {
336 timings cvt_t = calc_cvt_mode(t.hact, t.vact, refresh, rb);
337 if (match_timings(t, cvt_t)) {
338 fail("This T7VTDB can be represented as a T10VTDB.\n");
339 return;
342 timings cvt_t = calc_cvt_mode(t.hact, t.vact, refresh, RB_CVT_V3,
343 false, false, true);
344 if (match_timings(t, cvt_t))
345 fail("This T7VTDB can be represented as a T10VTDB.\n");
349 // tag 0x04
351 void edid_state::parse_displayid_type_2_timing(const unsigned char *x)
353 struct timings t = {};
354 unsigned hbl, vbl;
355 std::string s("aspect ");
357 t.pixclk_khz = 10 * (1 + (x[0] + (x[1] << 8) + (x[2] << 16)));
358 t.hact = 8 + 8 * (x[4] | ((x[5] & 0x01) << 8));
359 hbl = 8 + 8 * ((x[5] & 0xfe) >> 1);
360 t.hfp = 8 + 8 * ((x[6] & 0xf0) >> 4);
361 t.hsync = 8 + 8 * (x[6] & 0xf);
362 t.hbp = hbl - t.hfp - t.hsync;
363 if ((x[3] >> 3) & 0x1)
364 t.pos_pol_hsync = true;
365 t.vact = 1 + (x[7] | ((x[8] & 0xf) << 8));
366 vbl = 1 + x[9];
367 t.vfp = 1 + (x[10] >> 4);
368 t.vsync = 1 + (x[10] & 0xf);
369 t.vbp = vbl - t.vfp - t.vsync;
370 if ((x[17] >> 2) & 0x1)
371 t.pos_pol_vsync = true;
373 if (x[3] & 0x10) {
374 t.interlaced = true;
375 t.vfp /= 2;
376 t.vsync /= 2;
377 t.vbp /= 2;
380 calc_ratio(&t);
382 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
384 switch ((x[3] >> 5) & 0x3) {
385 case 0:
386 s += ", no 3D stereo";
387 break;
388 case 1:
389 s += ", 3D stereo";
390 break;
391 case 2:
392 s += ", 3D stereo depends on user action";
393 break;
394 case 3:
395 s += ", reserved";
396 fail("Reserved stereo 0x03.\n");
397 break;
399 if (x[3] & 0x80) {
400 s += ", preferred";
401 dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
404 print_timings(" ", &t, "DTD", s.c_str(), true);
407 // tag 0x05
409 void edid_state::parse_displayid_type_3_timing(const unsigned char *x)
411 struct timings t = {};
412 std::string s("aspect ");
414 switch (x[0] & 0xf) {
415 case 0:
416 s += "1:1";
417 t.hratio = t.vratio = 1;
418 break;
419 case 1:
420 s += "5:4";
421 t.hratio = 5;
422 t.vratio = 4;
423 break;
424 case 2:
425 s += "4:3";
426 t.hratio = 4;
427 t.vratio = 3;
428 break;
429 case 3:
430 s += "15:9";
431 t.hratio = 15;
432 t.vratio = 9;
433 break;
434 case 4:
435 s += "16:9";
436 t.hratio = 16;
437 t.vratio = 9;
438 break;
439 case 5:
440 s += "16:10";
441 t.hratio = 16;
442 t.vratio = 10;
443 break;
444 case 6:
445 s += "64:27";
446 t.hratio = 64;
447 t.vratio = 27;
448 break;
449 case 7:
450 s += "256:135";
451 t.hratio = 256;
452 t.vratio = 135;
453 break;
454 case 8:
455 s += "undefined";
456 break;
457 default:
458 s += "reserved";
459 fail("Unknown aspect 0x%02x.\n", x[0] & 0xf);
460 break;
463 t.rb = ((x[0] & 0x70) >> 4) == 1 ? RB_CVT_V1 : RB_NONE;
464 t.hact = 8 + 8 * x[1];
465 t.vact = t.hact * t.vratio / t.hratio;
467 edid_cvt_mode(1 + (x[2] & 0x7f), t);
469 if (x[0] & 0x80) {
470 s += ", preferred";
471 dispid.preferred_timings.push_back(timings_ext(t, "CVT", s));
474 print_timings(" ", &t, "CVT", s.c_str());
477 // tag 0x06 and 0x23
479 void edid_state::parse_displayid_type_4_8_timing(unsigned char type, unsigned short id, bool is_cta)
481 const struct timings *t = NULL;
482 char type_name[16];
484 switch (type) {
485 case 0: t = find_dmt_id(id); sprintf(type_name, "DMT 0x%02x", id); break;
486 case 1: t = find_vic_id(id); sprintf(type_name, "VIC %3u", id); break;
487 case 2: t = find_hdmi_vic_id(id); sprintf(type_name, "HDMI VIC %u", id); break;
488 default: break;
490 if (t)
491 print_timings(" ", t, type_name);
492 if (t && is_cta && !cta.t8vtdb.is_valid()) {
493 timings_ext te(*t, type_name, "");
494 cta.t8vtdb = te;
498 // tag 0x09
500 void edid_state::parse_displayid_video_timing_range_limits(const unsigned char *x)
502 check_displayid_datablock_revision(x[1]);
504 if (!check_displayid_datablock_length(x, 15, 15))
505 return;
506 printf(" Pixel Clock: %.3f-%.3f MHz\n",
507 (double)((x[3] | (x[4] << 8) | (x[5] << 16)) + 1) / 100.0,
508 (double)((x[6] | (x[7] << 8) | (x[8] << 16)) + 1) / 100.0);
509 printf(" Horizontal Frequency: %u-%u kHz\n", x[9], x[10]);
510 printf(" Minimum Horizontal Blanking: %u pixels\n", x[11] | (x[12] << 8));
511 printf(" Vertical Refresh: %u-%u Hz\n", x[13], x[14]);
512 printf(" Minimum Vertical Blanking: %u lines\n", x[15] | (x[16] << 8));
513 if (x[17] & 0x80)
514 printf(" Supports Interlaced\n");
515 if (x[17] & 0x40)
516 printf(" Supports CVT\n");
517 if (x[17] & 0x20)
518 printf(" Supports CVT Reduced Blanking\n");
519 if (x[17] & 0x10)
520 printf(" Discrete frequency display device\n");
523 // tag 0x0a and 0x0b
525 void edid_state::parse_displayid_string(const unsigned char *x)
527 check_displayid_datablock_revision(x[1]);
528 if (check_displayid_datablock_length(x))
529 printf(" Text: '%s'\n", extract_string(x + 3, x[2]));
532 // tag 0x0c
534 void edid_state::parse_displayid_display_device(const unsigned char *x)
536 check_displayid_datablock_revision(x[1]);
538 if (!check_displayid_datablock_length(x, 13, 13))
539 return;
541 printf(" Display Device Technology: ");
542 switch (x[3]) {
543 case 0x00: printf("Monochrome CRT\n"); break;
544 case 0x01: printf("Standard tricolor CRT\n"); break;
545 case 0x02: printf("Other/undefined CRT\n"); break;
546 case 0x10: printf("Passive matrix TN\n"); break;
547 case 0x11: printf("Passive matrix cholesteric LC\n"); break;
548 case 0x12: printf("Passive matrix ferroelectric LC\n"); break;
549 case 0x13: printf("Other passive matrix LC type\n"); break;
550 case 0x14: printf("Active-matrix TN\n"); break;
551 case 0x15: printf("Active-matrix IPS (all types)\n"); break;
552 case 0x16: printf("Active-matrix VA (all types)\n"); break;
553 case 0x17: printf("Active-matrix OCB\n"); break;
554 case 0x18: printf("Active-matrix ferroelectric\n"); break;
555 case 0x1f: printf("Other LC type\n"); break;
556 case 0x20: printf("DC plasma\n"); break;
557 case 0x21: printf("AC plasma\n"); break;
559 switch (x[3] & 0xf0) {
560 case 0x30: printf("Electroluminescent, except OEL/OLED\n"); break;
561 case 0x40: printf("Inorganic LED\n"); break;
562 case 0x50: printf("Organic LED/OEL\n"); break;
563 case 0x60: printf("FED or sim. \"cold-cathode,\" phosphor-based types\n"); break;
564 case 0x70: printf("Electrophoretic\n"); break;
565 case 0x80: printf("Electrochromic\n"); break;
566 case 0x90: printf("Electromechanical\n"); break;
567 case 0xa0: printf("Electrowetting\n"); break;
568 case 0xf0: printf("Other type not defined here\n"); break;
570 printf(" Display operating mode: ");
571 switch (x[4] >> 4) {
572 case 0x00: printf("Direct-view reflective, ambient light\n"); break;
573 case 0x01: printf("Direct-view reflective, ambient light, also has light source\n"); break;
574 case 0x02: printf("Direct-view reflective, uses light source\n"); break;
575 case 0x03: printf("Direct-view transmissive, ambient light\n"); break;
576 case 0x04: printf("Direct-view transmissive, ambient light, also has light source\n"); break;
577 case 0x05: printf("Direct-view transmissive, uses light source\n"); break;
578 case 0x06: printf("Direct-view emissive\n"); break;
579 case 0x07: printf("Direct-view transflective, backlight off by default\n"); break;
580 case 0x08: printf("Direct-view transflective, backlight on by default\n"); break;
581 case 0x09: printf("Transparent display, ambient light\n"); break;
582 case 0x0a: printf("Transparent emissive display\n"); break;
583 case 0x0b: printf("Projection device using reflective light modulator\n"); break;
584 case 0x0c: printf("Projection device using transmissive light modulator\n"); break;
585 case 0x0d: printf("Projection device using emissive image transducer\n"); break;
586 default: printf("Reserved\n"); break;
588 if (x[4] & 0x08)
589 printf(" The backlight may be switched on and off\n");
590 if (x[4] & 0x04)
591 printf(" The backlight's intensity can be controlled\n");
592 unsigned w = x[5] | (x[6] << 8);
593 unsigned h = x[7] | (x[8] << 8);
594 if (w && h) {
595 printf(" Display native pixel format: %ux%u\n", w + 1, h + 1);
596 dispid.native_width = w + 1;
597 dispid.native_height = h + 1;
598 } else if (w || h) {
599 fail("Invalid Native Pixel Format %ux%u.\n", w, h);
601 printf(" Aspect ratio and orientation:\n");
602 printf(" Aspect Ratio: %.2f\n", (100 + x[9]) / 100.0);
603 unsigned char v = x[0x0a];
604 printf(" Default Orientation: ");
605 switch ((v & 0xc0) >> 6) {
606 case 0x00: printf("Landscape\n"); break;
607 case 0x01: printf("Portrait\n"); break;
608 case 0x02: printf("Not Fixed\n"); break;
609 case 0x03: printf("Undefined\n"); break;
611 printf(" Rotation Capability: ");
612 switch ((v & 0x30) >> 4) {
613 case 0x00: printf("None\n"); break;
614 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
615 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
616 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
618 printf(" Zero Pixel Location: ");
619 switch ((v & 0x0c) >> 2) {
620 case 0x00: printf("Upper Left\n"); break;
621 case 0x01: printf("Upper Right\n"); break;
622 case 0x02: printf("Lower Left\n"); break;
623 case 0x03: printf("Lower Right\n"); break;
625 printf(" Scan Direction: ");
626 switch (v & 0x03) {
627 case 0x00: printf("Not defined\n"); break;
628 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
629 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
630 case 0x03: printf("Reserved\n");
631 fail("Scan Direction used the reserved value 0x03.\n");
632 break;
634 printf(" Sub-pixel layout/configuration/shape: ");
635 switch (x[0x0b]) {
636 case 0x00: printf("Not defined\n"); break;
637 case 0x01: printf("RGB vertical stripes\n"); break;
638 case 0x02: printf("RGB horizontal stripes\n"); break;
639 case 0x03: printf("Vertical stripes using primary order\n"); break;
640 case 0x04: printf("Horizontal stripes using primary order\n"); break;
641 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
642 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
643 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
644 case 0x08: printf("Mosaic\n"); break;
645 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
646 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
647 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
648 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
649 default: printf("Reserved\n"); break;
651 printf(" Horizontal and vertical dot/pixel pitch: %.2fx%.2f mm\n",
652 (double)(x[0x0c]) / 100.0, (double)(x[0x0d]) / 100.0);
653 printf(" Color bit depth: %u\n", x[0x0e] & 0x0f);
654 v = x[0x0f];
655 printf(" Response time for %s transition: %u ms\n",
656 (v & 0x80) ? "white-to-black" : "black-to-white", v & 0x7f);
659 // tag 0x0d
661 void edid_state::parse_displayid_intf_power_sequencing(const unsigned char *x)
663 check_displayid_datablock_revision(x[1]);
665 if (!check_displayid_datablock_length(x, 6, 6))
666 return;
668 printf(" Power Sequence T1 Range: %.1f-%u.0 ms\n", (x[3] >> 4) / 10.0, (x[3] & 0xf) * 2);
669 printf(" Power Sequence T2 Range: 0.0-%u.0 ms\n", (x[4] & 0x3f) * 2);
670 printf(" Power Sequence T3 Range: 0.0-%u.0 ms\n", (x[5] & 0x3f) * 2);
671 printf(" Power Sequence T4 Min: %u.0 ms\n", (x[6] & 0x7f) * 10);
672 printf(" Power Sequence T5 Min: %u.0 ms\n", (x[7] & 0x3f) * 10);
673 printf(" Power Sequence T6 Min: %u.0 ms\n", (x[8] & 0x3f) * 10);
676 // tag 0x0e
678 void edid_state::parse_displayid_transfer_characteristics(const unsigned char *x)
680 check_displayid_datablock_revision(x[1], 0xf0, 1);
682 unsigned xfer_id = x[1] >> 4;
683 bool first_is_white = x[3] & 0x80;
684 bool four_param = x[3] & 0x20;
686 if (xfer_id) {
687 printf(" Transfer Characteristics Data Block Identifier: %u\n", xfer_id);
688 if (!(dispid.preparsed_color_ids & (1 << xfer_id)))
689 fail("Missing Color Characteristics Data Block using Identifier %u.\n", xfer_id);
691 if (first_is_white)
692 printf(" The first curve is the 'white' transfer characteristic\n");
693 if (x[3] & 0x40)
694 printf(" Individual response curves\n");
696 unsigned offset = 4;
697 unsigned len = x[2] - 1;
699 for (unsigned i = 0; len; i++) {
700 if ((x[3] & 0x80) && !i)
701 printf(" White curve: ");
702 else
703 printf(" Response curve #%u:",
704 i - first_is_white);
705 unsigned samples = x[offset];
706 if (four_param) {
707 if (samples != 5)
708 fail("Expected 5 samples.\n");
709 printf(" A0=%u A1=%u A2=%u A3=%u Gamma=%.2f\n",
710 x[offset + 1], x[offset + 2], x[offset + 3], x[offset + 4],
711 (double)(x[offset + 5] + 100.0) / 100.0);
712 samples++;
713 } else {
714 double sum = 0;
716 // The spec is not very clear about the number of samples:
717 // should this be interpreted as the actual number of
718 // samples stored in this Data Block, or as the number of
719 // samples in the curve, but where the last sample is not
720 // actually stored since it is always 0x3ff.
722 // The ATP Manager interprets this as the latter, so that's
723 // what we implement here.
724 for (unsigned j = offset + 1; j < offset + samples; j++) {
725 sum += x[j];
726 printf(" %.2f", sum * 100.0 / 1023.0);
728 printf(" 100.00\n");
730 offset += samples;
731 len -= samples;
735 // tag 0x0f
737 void edid_state::parse_displayid_display_intf(const unsigned char *x)
739 check_displayid_datablock_revision(x[1]);
741 if (!check_displayid_datablock_length(x, 10, 10))
742 return;
744 dispid.has_display_interface_features = true;
745 printf(" Interface Type: ");
746 switch (x[3] >> 4) {
747 case 0x00:
748 switch (x[3] & 0xf) {
749 case 0x00: printf("Analog 15HD/VGA\n"); break;
750 case 0x01: printf("Analog VESA NAVI-V (15HD)\n"); break;
751 case 0x02: printf("Analog VESA NAVI-D\n"); break;
752 default: printf("Reserved\n"); break;
754 break;
755 case 0x01: printf("LVDS\n"); break;
756 case 0x02: printf("TMDS\n"); break;
757 case 0x03: printf("RSDS\n"); break;
758 case 0x04: printf("DVI-D\n"); break;
759 case 0x05: printf("DVI-I, analog\n"); break;
760 case 0x06: printf("DVI-I, digital\n"); break;
761 case 0x07: printf("HDMI-A\n"); break;
762 case 0x08: printf("HDMI-B\n"); break;
763 case 0x09: printf("MDDI\n"); break;
764 case 0x0a: printf("DisplayPort\n"); break;
765 case 0x0b: printf("Proprietary Digital Interface\n"); break;
766 default: printf("Reserved\n"); break;
768 if (x[3] >> 4)
769 printf(" Number of Links: %u\n", x[3] & 0xf);
770 printf(" Interface Standard Version: %u.%u\n",
771 x[4] >> 4, x[4] & 0xf);
772 print_flags(" Supported bpc for RGB encoding", x[5], bpc444);
773 print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x[6], bpc444);
774 print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x[7], bpc4xx);
775 printf(" Supported Content Protection: ");
776 switch (x[8] & 0xf) {
777 case 0x00: printf("None\n"); break;
778 case 0x01: printf("HDCP "); break;
779 case 0x02: printf("DTCP "); break;
780 case 0x03: printf("DPCP "); break;
781 default: printf("Reserved "); break;
783 if (x[8] & 0xf)
784 printf("%u.%u\n", x[9] >> 4, x[9] & 0xf);
785 unsigned char v = x[0x0a] & 0xf;
786 printf(" Spread Spectrum: ");
787 switch (x[0x0a] >> 6) {
788 case 0x00: printf("None\n"); break;
789 case 0x01: printf("Down Spread %.1f%%\n", v / 10.0); break;
790 case 0x02: printf("Center Spread %.1f%%\n", v / 10.0); break;
791 case 0x03: printf("Reserved\n"); break;
793 switch (x[3] >> 4) {
794 case 0x01:
795 printf(" LVDS Color Mapping: %s mode\n",
796 (x[0x0b] & 0x10) ? "6 bit compatible" : "normal");
797 if (x[0x0b] & 0x08) printf(" LVDS supports 2.8V\n");
798 if (x[0x0b] & 0x04) printf(" LVDS supports 12V\n");
799 if (x[0x0b] & 0x02) printf(" LVDS supports 5V\n");
800 if (x[0x0b] & 0x01) printf(" LVDS supports 3.3V\n");
801 printf(" LVDS %s Mode\n", (x[0x0c] & 0x04) ? "Fixed" : "DE");
802 if (x[0x0c] & 0x04)
803 printf(" LVDS %s Signal Level\n", (x[0x0c] & 0x02) ? "Low" : "High");
804 else
805 printf(" LVDS DE Polarity Active %s\n", (x[0x0c] & 0x02) ? "Low" : "High");
806 printf(" LVDS Shift Clock Data Strobe at %s Edge\n", (x[0x0c] & 0x01) ? "Rising" : "Falling");
807 break;
808 case 0x0b:
809 printf(" PDI %s Mode\n", (x[0x0b] & 0x04) ? "Fixed" : "DE");
810 if (x[0x0b] & 0x04)
811 printf(" PDI %s Signal Level\n", (x[0x0b] & 0x02) ? "Low" : "High");
812 else
813 printf(" PDI DE Polarity Active %s\n", (x[0x0b] & 0x02) ? "Low" : "High");
814 printf(" PDI Shift Clock Data Strobe at %s Edge\n", (x[0x0b] & 0x01) ? "Rising" : "Falling");
815 break;
819 // tag 0x10 and 0x27
821 void edid_state::parse_displayid_stereo_display_intf(const unsigned char *x)
823 check_displayid_datablock_revision(x[1], 0xc0, 1);
825 switch (x[1] >> 6) {
826 case 0x00: printf(" Timings that explicitly report 3D capability\n"); break;
827 case 0x01: printf(" Timings that explicitly report 3D capability & Timing Codes listed here\n"); break;
828 case 0x02: printf(" All listed timings\n"); break;
829 case 0x03: printf(" Only Timings Codes listed here\n"); break;
832 unsigned len = x[2];
834 switch (x[4]) {
835 case 0x00:
836 printf(" Field Sequential Stereo (L/R Polarity: %s)\n",
837 (x[5] & 1) ? "0/1" : "1/0");
838 break;
839 case 0x01:
840 printf(" Side-by-side Stereo (Left Half = %s Eye View)\n",
841 (x[5] & 1) ? "Right" : "Left");
842 break;
843 case 0x02:
844 printf(" Pixel Interleaved Stereo:\n");
845 for (unsigned y = 0; y < 8; y++) {
846 unsigned char v = x[5 + y];
848 printf(" ");
849 for (int x = 7; x >= 0; x--)
850 printf("%c", (v & (1 << x)) ? 'L' : 'R');
851 printf("\n");
853 break;
854 case 0x03:
855 printf(" Dual Interface, Left and Right Separate\n");
856 printf(" Carries the %s-eye view\n",
857 (x[5] & 1) ? "Right" : "Left");
858 printf(" ");
859 switch ((x[5] >> 1) & 3) {
860 case 0x00: printf("No mirroring\n"); break;
861 case 0x01: printf("Left/Right mirroring\n"); break;
862 case 0x02: printf("Top/Bottom mirroring\n"); break;
863 case 0x03: printf("Reserved\n"); break;
865 break;
866 case 0x04:
867 printf(" Multi-View: %u views, Interleaving Method Code: %u\n",
868 x[5], x[6]);
869 break;
870 case 0x05:
871 printf(" Stacked Frame Stereo (Top Half = %s Eye View)\n",
872 (x[5] & 1) ? "Right" : "Left");
873 break;
874 case 0xff:
875 printf(" Proprietary\n");
876 break;
877 default:
878 printf(" Reserved\n");
879 break;
881 if (!(x[1] & 0x40)) // Has No Timing Codes
882 return;
883 len -= 1 + x[3];
884 x += 4 + x[3];
885 while (1U + (x[0] & 0x1f) <= len) {
886 unsigned num_codes = x[0] & 0x1f;
887 unsigned type = x[0] >> 6;
888 char type_name[16];
890 for (unsigned i = 1; i <= num_codes; i++) {
891 switch (type) {
892 case 0x00:
893 sprintf(type_name, "DMT 0x%02x", x[i]);
894 print_timings(" ", find_dmt_id(x[i]), type_name);
895 break;
896 case 0x01:
897 sprintf(type_name, "VIC %3u", x[i]);
898 print_timings(" ", find_vic_id(x[i]), type_name);
899 break;
900 case 0x02:
901 sprintf(type_name, "HDMI VIC %u", x[i]);
902 print_timings(" ", find_hdmi_vic_id(x[i]), type_name);
903 break;
907 len -= 1 + num_codes;
908 x += 1 + num_codes;
912 // tag 0x11
914 void edid_state::parse_displayid_type_5_timing(const unsigned char *x)
916 struct timings t = {};
917 std::string s("aspect ");
919 t.hact = 1 + (x[2] | (x[3] << 8));
920 t.vact = 1 + (x[4] | (x[5] << 8));
921 calc_ratio(&t);
922 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
923 switch ((x[0] >> 5) & 0x3) {
924 case 0:
925 s += ", no 3D stereo";
926 break;
927 case 1:
928 s += ", 3D stereo";
929 break;
930 case 2:
931 s += ", 3D stereo depends on user action";
932 break;
933 case 3:
934 s += ", reserved";
935 fail("Reserved stereo 0x03.\n");
936 break;
938 if (x[0] & 0x10)
939 s += ", refresh rate * (1000/1001) supported";
941 t.rb = RB_CVT_V2;
942 if ((x[0] & 0x03) == 1)
943 warn("Unexpected use of 'custom reduced blanking'.\n");
944 else if ((x[0] & 0x03) > 1)
945 fail("Invalid Timing Formula.\n");
947 edid_cvt_mode(1 + x[6], t);
949 if (x[0] & 0x80) {
950 s += ", preferred";
951 dispid.preferred_timings.push_back(timings_ext(t, "CVT", s));
954 print_timings(" ", &t, "CVT", s.c_str());
957 // tag 0x12 and 0x28
959 void edid_state::parse_displayid_tiled_display_topology(const unsigned char *x, bool is_v2)
961 check_displayid_datablock_revision(x[1]);
963 if (!check_displayid_datablock_length(x, 22, 22))
964 return;
966 unsigned caps = x[3];
967 unsigned num_v_tile = (x[4] & 0xf) | (x[6] & 0x30);
968 unsigned num_h_tile = (x[4] >> 4) | ((x[6] >> 2) & 0x30);
969 unsigned tile_v_location = (x[5] & 0xf) | ((x[6] & 0x3) << 4);
970 unsigned tile_h_location = (x[5] >> 4) | (((x[6] >> 2) & 0x3) << 4);
971 unsigned tile_width = x[7] | (x[8] << 8);
972 unsigned tile_height = x[9] | (x[10] << 8);
973 unsigned pix_mult = x[11];
975 printf(" Capabilities:\n");
976 printf(" Behavior if it is the only tile: ");
977 switch (caps & 0x07) {
978 case 0x00: printf("Undefined\n"); break;
979 case 0x01: printf("Image is displayed at the Tile Location\n"); break;
980 case 0x02: printf("Image is scaled to fit the entire tiled display\n"); break;
981 case 0x03: printf("Image is cloned to all other tiles\n"); break;
982 default: printf("Reserved\n"); break;
984 printf(" Behavior if more than one tile and fewer than total number of tiles: ");
985 switch ((caps >> 3) & 0x03) {
986 case 0x00: printf("Undefined\n"); break;
987 case 0x01: printf("Image is displayed at the Tile Location\n"); break;
988 default: printf("Reserved\n"); break;
990 if (caps & 0x80)
991 printf(" Tiled display consists of a single physical display enclosure\n");
992 else
993 printf(" Tiled display consists of multiple physical display enclosures\n");
994 printf(" Num horizontal tiles: %u Num vertical tiles: %u\n",
995 num_h_tile + 1, num_v_tile + 1);
996 printf(" Tile location: %u, %u\n", tile_h_location, tile_v_location);
997 printf(" Tile resolution: %ux%u\n", tile_width + 1, tile_height + 1);
998 if (caps & 0x40) {
999 if (pix_mult) {
1000 printf(" Top bevel size: %.1f pixels\n",
1001 pix_mult * x[12] / 10.0);
1002 printf(" Bottom bevel size: %.1f pixels\n",
1003 pix_mult * x[13] / 10.0);
1004 printf(" Right bevel size: %.1f pixels\n",
1005 pix_mult * x[14] / 10.0);
1006 printf(" Left bevel size: %.1f pixels\n",
1007 pix_mult * x[15] / 10.0);
1008 } else {
1009 fail("No bevel information, but the pixel multiplier is non-zero.\n");
1011 printf(" Tile resolution: %ux%u\n", tile_width + 1, tile_height + 1);
1012 } else if (pix_mult) {
1013 fail("No bevel information, but the pixel multiplier is non-zero.\n");
1015 if (is_v2)
1016 printf(" Tiled Display Manufacturer/Vendor ID: %02X-%02X-%02X\n",
1017 x[0x10], x[0x11], x[0x12]);
1018 else
1019 printf(" Tiled Display Manufacturer/Vendor ID: %c%c%c\n",
1020 x[0x10], x[0x11], x[0x12]);
1021 printf(" Tiled Display Product ID Code: %u\n",
1022 x[0x13] | (x[0x14] << 8));
1023 if (hide_serial_numbers)
1024 printf(" Tiled Display Serial Number: ...\n");
1025 else
1026 printf(" Tiled Display Serial Number: %u\n",
1027 x[0x15] | (x[0x16] << 8) | (x[0x17] << 16)| (x[0x18] << 24));
1030 // tag 0x13
1032 void edid_state::parse_displayid_type_6_timing(const unsigned char *x)
1034 struct timings t = {};
1035 std::string s("aspect ");
1037 t.pixclk_khz = 1 + (x[0] + (x[1] << 8) + ((x[2] & 0x3f) << 16));
1038 t.hact = 1 + (x[3] | ((x[4] & 0x3f) << 8));
1039 if ((x[4] >> 7) & 0x1)
1040 t.pos_pol_hsync = true;
1041 unsigned hbl = 1 + (x[7] | ((x[9] & 0xf) << 8));
1042 t.hfp = 1 + (x[8] | ((x[9] & 0xf0) << 4));
1043 t.hsync = 1 + x[10];
1044 t.hbp = hbl - t.hfp - t.hsync;
1045 t.vact = 1 + (x[5] | ((x[6] & 0x3f) << 8));
1046 if ((x[6] >> 7) & 0x1)
1047 t.pos_pol_vsync = true;
1048 unsigned vbl = 1 + x[11];
1049 t.vfp = 1 + x[12];
1050 t.vsync = 1 + (x[13] & 0x0f);
1051 t.vbp = vbl - t.vfp - t.vsync;
1053 if (x[13] & 0x80) {
1054 t.interlaced = true;
1055 t.vfp /= 2;
1056 t.vsync /= 2;
1057 t.vbp /= 2;
1059 calc_ratio(&t);
1060 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1061 if (x[2] & 0x40) {
1062 double aspect_mult = x[14] * 3.0 / 256.0;
1063 unsigned size_mult = 1 + (x[16] >> 4);
1065 t.vsize_mm = size_mult * (1 + (x[15] | ((x[16] & 0xf) << 8)));
1066 t.hsize_mm = t.vsize_mm * aspect_mult;
1069 switch ((x[13] >> 5) & 0x3) {
1070 case 0:
1071 s += ", no 3D stereo";
1072 break;
1073 case 1:
1074 s += ", 3D stereo";
1075 break;
1076 case 2:
1077 s += ", 3D stereo depends on user action";
1078 break;
1079 case 3:
1080 s += ", reserved";
1081 fail("Reserved stereo 0x03.\n");
1082 break;
1085 if (x[2] & 0x80) {
1086 s += ", preferred";
1087 dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
1090 print_timings(" ", &t, "DTD", s.c_str(), true);
1093 static std::string ieee7542d(unsigned short fp)
1095 int exp = ((fp & 0x7c00) >> 10) - 15;
1096 unsigned fract = (fp & 0x3ff) | 0x400;
1098 if (fp == 0x8000)
1099 return "do not use";
1100 if (fp & 0x8000)
1101 return "reserved";
1102 return std::to_string(pow(2, exp) * fract / 1024.0) + " cd/m^2";
1105 // tag 0x21
1107 void edid_state::parse_displayid_parameters_v2(const unsigned char *x,
1108 unsigned block_rev)
1110 if (!check_displayid_datablock_length(x, 29, 29))
1111 return;
1113 unsigned hor_size = (x[4] << 8) + x[3];
1114 unsigned vert_size = (x[6] << 8) + x[5];
1116 dispid.has_display_parameters = true;
1117 if (x[1] & 0x80)
1118 printf(" Image size: %u mm x %u mm\n",
1119 hor_size, vert_size);
1120 else
1121 printf(" Image size: %.1f mm x %.1f mm\n",
1122 hor_size / 10.0, vert_size / 10.0);
1123 unsigned w = (x[8] << 8) + x[7];
1124 unsigned h = (x[10] << 8) + x[9];
1125 if (w && h) {
1126 printf(" Native Format: %ux%u\n", w, h);
1127 dispid.native_width = w;
1128 dispid.native_height = h;
1129 } else if (w || h) {
1130 fail("Invalid Native Format %ux%u.\n", w, h);
1132 unsigned char v = x[11];
1133 printf(" Scan Orientation: ");
1134 switch (v & 0x07) {
1135 case 0x00: printf("Left to Right, Top to Bottom\n"); break;
1136 case 0x01: printf("Right to Left, Top to Bottom\n"); break;
1137 case 0x02: printf("Top to Bottom, Right to Left\n"); break;
1138 case 0x03: printf("Bottom to Top, Right to Left\n"); break;
1139 case 0x04: printf("Right to Left, Bottom to Top\n"); break;
1140 case 0x05: printf("Left to Right, Bottom to Top\n"); break;
1141 case 0x06: printf("Bottom to Top, Left to Right\n"); break;
1142 case 0x07: printf("Top to Bottom, Left to Right\n"); break;
1144 printf(" Luminance Information: ");
1145 switch ((v >> 3) & 0x03) {
1146 case 0x00: printf("Minimum guaranteed value\n"); break;
1147 case 0x01: printf("Guidance for the Source device\n"); break;
1148 default: printf("Reserved\n"); break;
1150 printf(" Color Information: CIE %u\n",
1151 (v & 0x40) ? 1976 : 1931);
1152 printf(" Audio Speaker Information: %sintegrated\n",
1153 (v & 0x80) ? "not " : "");
1154 printf(" Native Color Chromaticity:\n");
1155 printf(" Primary #1: (%.6f, %.6f)\n",
1156 fp2d(x[0x0c] | ((x[0x0d] & 0x0f) << 8)),
1157 fp2d(((x[0x0d] & 0xf0) >> 4) | (x[0x0e] << 4)));
1158 printf(" Primary #2: (%.6f, %.6f)\n",
1159 fp2d(x[0x0f] | ((x[0x10] & 0x0f) << 8)),
1160 fp2d(((x[0x10] & 0xf0) >> 4) | (x[0x11] << 4)));
1161 printf(" Primary #3: (%.6f, %.6f)\n",
1162 fp2d(x[0x12] | ((x[0x13] & 0x0f) << 8)),
1163 fp2d(((x[0x13] & 0xf0) >> 4) | (x[0x14] << 4)));
1164 printf(" White Point: (%.6f, %.6f)\n",
1165 fp2d(x[0x15] | ((x[0x16] & 0x0f) << 8)),
1166 fp2d(((x[0x16] & 0xf0) >> 4) | (x[0x17] << 4)));
1167 printf(" Native Maximum Luminance (Full Coverage): %s\n",
1168 ieee7542d(x[0x18] | (x[0x19] << 8)).c_str());
1169 printf(" Native Maximum Luminance (10%% Rectangular Coverage): %s\n",
1170 ieee7542d(x[0x1a] | (x[0x1b] << 8)).c_str());
1171 printf(" Native Minimum Luminance: %s\n",
1172 ieee7542d(x[0x1c] | (x[0x1d] << 8)).c_str());
1173 printf(" Native Color Depth: ");
1174 if (!(x[0x1e] & 0x07))
1175 printf("Not defined\n");
1176 else if (bpc444[x[0x1e] & 0x07])
1177 printf("%s bpc\n", bpc444[x[0x1e] & 0x07]);
1178 else
1179 printf("Reserved\n");
1180 printf(" Display Device Technology: ");
1181 switch ((x[0x1e] >> 4) & 0x07) {
1182 case 0x00: printf("Not Specified\n"); break;
1183 case 0x01: printf("Active Matrix LCD\n"); break;
1184 case 0x02: printf("Organic LED\n"); break;
1185 default: printf("Reserved\n"); break;
1187 if (block_rev)
1188 printf(" Display Device Theme Preference: %s\n",
1189 (x[0x1e] & 0x80) ? "Dark Theme Preferred" : "No Preference");
1190 if (x[0x1f] != 0xff)
1191 printf(" Native Gamma EOTF: %.2f\n",
1192 (100 + x[0x1f]) / 100.0);
1195 // tag 0x24
1197 void edid_state::parse_displayid_type_9_timing(const unsigned char *x)
1199 struct timings t = {};
1200 std::string s("aspect ");
1202 t.hact = 1 + (x[1] | (x[2] << 8));
1203 t.vact = 1 + (x[3] | (x[4] << 8));
1204 calc_ratio(&t);
1205 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1206 switch ((x[0] >> 5) & 0x3) {
1207 case 0:
1208 s += ", no 3D stereo";
1209 break;
1210 case 1:
1211 s += ", 3D stereo";
1212 break;
1213 case 2:
1214 s += ", 3D stereo depends on user action";
1215 break;
1216 case 3:
1217 s += ", reserved";
1218 fail("Reserved stereo 0x03.\n");
1219 break;
1221 if (x[0] & 0x10)
1222 s += ", refresh rate * (1000/1001) supported";
1224 switch (x[0] & 0x07) {
1225 case 1: t.rb = RB_CVT_V1; break;
1226 case 2: t.rb = RB_CVT_V2; break;
1227 default: break;
1230 edid_cvt_mode(1 + x[5], t);
1232 print_timings(" ", &t, "CVT", s.c_str());
1235 // tag 0x25
1237 void edid_state::parse_displayid_dynamic_video_timings_range_limits(const unsigned char *x)
1239 check_displayid_datablock_revision(x[1], 0, (x[1] & 7) == 1);
1241 if (!check_displayid_datablock_length(x, 9, 9))
1242 return;
1244 printf(" Minimum Pixel Clock: %u kHz\n",
1245 1 + (x[3] | (x[4] << 8) | (x[5] << 16)));
1246 printf(" Maximum Pixel Clock: %u kHz\n",
1247 1 + (x[6] | (x[7] << 8) | (x[8] << 16)));
1248 printf(" Minimum Vertical Refresh Rate: %u Hz\n", x[9]);
1249 if (x[1] & 7)
1250 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x[10] + ((x[11] & 3) << 8));
1251 else
1252 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x[10]);
1253 printf(" Seamless Dynamic Video Timing Support: %s\n",
1254 (x[11] & 0x80) ? "Yes" : "No");
1257 // tag 0x26
1259 static const char *colorspace_eotf_combinations[] = {
1260 "sRGB",
1261 "BT.601",
1262 "BT.709/BT.1886",
1263 "Adobe RGB",
1264 "DCI-P3",
1265 "BT.2020",
1266 "BT.2020/SMPTE ST 2084"
1269 static const char *colorspace_eotf_reserved[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
1271 static const char *colorspaces[] = {
1272 "Undefined",
1273 "sRGB",
1274 "BT.601",
1275 "BT.709",
1276 "Adobe RGB",
1277 "DCI-P3",
1278 "BT.2020",
1279 "Custom"
1282 static const char *eotfs[] = {
1283 "Undefined",
1284 "sRGB",
1285 "BT.601",
1286 "BT.1886",
1287 "Adobe RGB",
1288 "DCI-P3",
1289 "BT.2020",
1290 "Gamma function",
1291 "SMPTE ST 2084",
1292 "Hybrid Log",
1293 "Custom"
1296 void edid_state::parse_displayid_interface_features(const unsigned char *x)
1298 check_displayid_datablock_revision(x[1]);
1300 if (!check_displayid_datablock_length(x, 9))
1301 return;
1303 dispid.has_display_interface_features = true;
1304 unsigned len = x[2];
1305 if (len > 0) print_flags(" Supported bpc for RGB encoding", x[3], bpc444);
1306 if (len > 1) print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x[4], bpc444);
1307 if (len > 2) print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x[5], bpc4xx);
1308 if (len > 3) print_flags(" Supported bpc for YCbCr 4:2:0 encoding", x[6], bpc4xx);
1309 if (len > 4 && x[7])
1310 printf(" Minimum pixel rate at which YCbCr 4:2:0 encoding is supported: %.3f MHz\n",
1311 74.25 * x[7]);
1312 if (len > 5) print_flags(" Supported audio capability and features (kHz)",
1313 x[8], audiorates, true);
1314 if (len > 6) print_flags(" Supported color space and EOTF standard combination 1",
1315 x[9], colorspace_eotf_combinations);
1316 if (len > 7) print_flags(" Supported color space and EOTF standard combination 2",x[10], colorspace_eotf_reserved);
1318 unsigned i = 0;
1320 if (len > 8 && x[11]) {
1321 printf(" Supported color space and EOTF additional combinations:");
1322 for (i = 0; i < x[11]; i++) {
1323 if (i > 6) {
1324 printf("\n Number of additional color space and EOTF combinations (%d) is greater than allowed (7).", x[11]);
1325 break;
1326 } else if (i + 10 > len) {
1327 printf("\n Number of additional color space and EOTF combinations (%d) is too many to fit in block (%d).", x[11], len - 9);
1328 break;
1331 const char *colorspace = "Out of range";
1332 const char *eotf = "Out of range";
1333 unsigned colorspace_index = (x[12 + i] >> 4) & 0xf;
1334 unsigned eotf_index = x[12 + i] & 0xf;
1336 if (colorspace_index < sizeof(colorspaces) / sizeof(colorspaces[0]))
1337 colorspace = colorspaces[colorspace_index];
1338 if (eotf_index < sizeof(eotfs) / sizeof(eotfs[0]))
1339 eotf = eotfs[eotf_index];
1341 if (i > 0)
1342 printf(", ");
1343 if (!strcmp(colorspace, eotf))
1344 printf("%s", colorspace);
1345 else
1346 printf("%s/%s", colorspace, eotf);
1348 printf("\n");
1350 check_displayid_datablock_length(x, 9 + i, 9 + i, 9 + i);
1353 // tag 0x29
1355 void edid_state::parse_displayid_ContainerID(const unsigned char *x)
1357 check_displayid_datablock_revision(x[1]);
1359 if (check_displayid_datablock_length(x, 16, 16)) {
1360 x += 3;
1361 printf(" Container ID: %s\n", containerid2s(x).c_str());
1365 // tag 0x2b
1367 void edid_state::parse_displayid_adaptive_sync(const unsigned char *x)
1369 check_displayid_datablock_revision(x[1], 0x70);
1371 unsigned size = 6 + ((x[1] >> 4) & 0x7);
1372 unsigned len = x[2];
1373 unsigned descriptor = 1;
1375 x += 3;
1376 if (len % size)
1377 fail("DisplayID payload length %u is not a multiple of %u.\n", len, size);
1378 while (len >= size) {
1379 printf(" Descriptor #%u:\n", descriptor++);
1381 printf(" %sNative Panel Range\n", (x[0] & 1) ? "" : "Non-");
1382 unsigned v = (x[0] >> 2) & 3;
1383 switch (v) {
1384 case 0: printf(" Fixed Average V-Total\n"); break;
1385 case 1: printf(" Fixed Average V-Total and Adaptive V-Total\n"); break;
1386 default:
1387 printf(" Reserved %u\n", v);
1388 fail("Use of reserved value %u.\n", v);
1389 break;
1391 if (x[0] & 0x10)
1392 printf(" Supports Seamless Transition\n");
1393 if (x[0] & 0x02)
1394 printf(" 'Max Single Frame Duration Increase' field value without jitter impact\n");
1395 if (x[0] & 0x20)
1396 printf(" 'Max Single Frame Duration Decrease' field value without jitter impact\n");
1397 printf(" Max Duration Increase: %.2f ms\n", x[1] / 4.0);
1398 printf(" Max Duration Decrease: %.2f ms\n", x[5] / 4.0);
1399 printf(" Min Refresh Rate: %u Hz\n", x[2]);
1400 printf(" Max Refresh Rate: %u Hz\n", 1 + x[3] + (x[4] & 3) * 256);
1402 len -= size;
1403 x += size;
1407 // tag 0x32
1409 void edid_state::parse_displayid_type_10_timing(const unsigned char *x,
1410 unsigned sz, bool is_cta)
1412 struct timings t = {};
1413 std::string s("aspect ");
1415 t.hact = 1 + (x[1] | (x[2] << 8));
1416 t.vact = 1 + (x[3] | (x[4] << 8));
1417 calc_ratio(&t);
1418 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1420 switch ((x[0] >> 5) & 0x3) {
1421 case 0:
1422 s += ", no 3D stereo";
1423 break;
1424 case 1:
1425 s += ", 3D stereo";
1426 break;
1427 case 2:
1428 s += ", 3D stereo depends on user action";
1429 break;
1430 case 3:
1431 s += ", reserved";
1432 fail("Reserved stereo 0x03.\n");
1433 break;
1436 switch (x[0] & 0x07) {
1437 case 1: t.rb = RB_CVT_V1; break;
1438 case 2: t.rb = RB_CVT_V2; break;
1439 case 3: t.rb = RB_CVT_V3; break;
1440 default: break;
1443 unsigned rb = t.rb;
1444 unsigned rb_h_blank = rb == RB_CVT_V3 ? 80 : 0;
1446 if (x[0] & 0x10) {
1447 if (rb == RB_CVT_V2) {
1448 s += ", refresh rate * (1000/1001) supported";
1449 t.rb |= RB_ALT;
1450 } else if (rb == RB_CVT_V3) {
1451 s += ", hblank is 160 pixels";
1452 t.rb |= RB_ALT;
1453 rb_h_blank = 160;
1454 } else {
1455 fail("VR_HB must be 0.\n");
1458 if (x[0] & 0x80)
1459 s += ", YCbCr 4:2:0";
1461 unsigned refresh = 1 + x[5] + (sz == 6 ? 0 : ((x[6] & 3) << 8));
1462 double add_vert_time = 0;
1464 if (sz > 6 && rb == RB_CVT_V3) {
1465 unsigned delta_hblank = (x[6] >> 2) & 7;
1467 if (rb_h_blank == 80)
1468 rb_h_blank = 80 + 8 * delta_hblank;
1469 else if (delta_hblank <= 5)
1470 rb_h_blank = 160 + 8 * delta_hblank;
1471 else
1472 rb_h_blank = 160 - (delta_hblank - 5) * 8;
1474 unsigned vblank_time_perc = (x[6] >> 5) & 7;
1476 add_vert_time = (vblank_time_perc * 10000.0) / refresh;
1479 edid_cvt_mode(refresh, t, rb_h_blank, add_vert_time);
1481 print_timings(" ", &t, "CVT", s.c_str());
1482 if (is_cta) {
1483 timings_ext te(t, "CVT", s);
1484 cta.vec_vtdbs.push_back(te);
1488 // tag 0x7e, OUI 3A-02-92 (VESA)
1490 void edid_state::parse_displayid_vesa(const unsigned char *x)
1492 check_displayid_datablock_revision(x[1]);
1494 if (!check_displayid_datablock_length(x, 5, 7))
1495 return;
1497 unsigned len = x[2];
1498 x += 6;
1499 printf(" Data Structure Type: ");
1500 switch (x[0] & 7) {
1501 case 0: printf("eDP\n"); break;
1502 case 1: printf("DP\n"); break;
1503 default: printf("Reserved (%d)\n", x[0] & 7); break;
1506 if ((x[0] >> 3) & 15)
1507 warn("Reserved bits 6:3 (%d) are not 0.\n", (x[0] >> 3) & 15);
1509 printf(" Default Colorspace and EOTF Handling: %s\n",
1510 (x[0] & 0x80) ? "Native as specified in the Display Parameters DB" : "sRGB");
1512 printf(" Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel: %u\n",
1513 x[1] & 0xf);
1514 if ((x[1] & 0xf) > 8)
1515 warn("Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel exceeds 8.\n");
1517 if ((x[1] >> 4) & 1)
1518 warn("Reserved bit 4 is not 0.\n");
1520 printf(" Multi-SST Operation: ");
1521 switch ((x[1] >> 5) & 3) {
1522 case 0: printf("Not Supported\n"); break;
1523 case 1: printf("Two Streams (number of links shall be 2 or 4)\n"); break;
1524 case 2: printf("Four Streams (number of links shall be 4)\n"); break;
1525 case 3: printf("Reserved\n"); warn("Invalid option for Multi-SST Operation.\n"); break;
1528 if ((x[1] >> 7) & 1)
1529 warn("Reserved bit 7 is not 0.\n");
1531 if (len >= 7) {
1532 double bpp = (x[2] & 0x3f) + (x[3] & 0x0f) / 16.0;
1533 printf(" Pass through timing's target DSC bits per pixel: %.4f\n", bpp);
1537 // tag 0x81
1539 void edid_state::parse_displayid_cta_data_block(const unsigned char *x)
1541 check_displayid_datablock_revision(x[1]);
1543 unsigned len = x[2];
1544 unsigned i;
1546 if (len > 248) {
1547 fail("Length is > 248.\n");
1548 len = 248;
1550 x += 3;
1552 for (i = 0; i < len; i += (x[i] & 0x1f) + 1) {
1553 cta_block(x + i, dispid.found_tags);
1556 if (i != len)
1557 fail("Length is %u instead of %u.\n", len, i);
1560 // DisplayID main
1562 std::string edid_state::product_type(unsigned char x, bool heading)
1564 std::string headingstr;
1566 if (dispid.version < 0x20) {
1567 headingstr = "Display Product Type";
1568 if (heading) return headingstr;
1569 dispid.is_display = x == 2 || x == 3 || x == 4 || x == 6;
1570 switch (x) {
1571 case 0: return "Extension Section";
1572 case 1: return "Test Structure; test equipment only";
1573 case 2: return "Display panel or other transducer, LCD or PDP module, etc.";
1574 case 3: return "Standalone display device";
1575 case 4: return "Television receiver";
1576 case 5: return "Repeater/translator";
1577 case 6: return "DIRECT DRIVE monitor";
1578 default: break;
1580 } else {
1581 headingstr = "Display Product Primary Use Case";
1582 if (heading) return headingstr;
1583 dispid.is_display = x >= 2 && x <= 8;
1584 switch (x) {
1585 case 0: return "Same primary use case as the base section";
1586 case 1: return "Test Structure; test equipment only";
1587 case 2: return "None of the listed primary use cases; generic display";
1588 case 3: return "Television (TV) display";
1589 case 4: return "Desktop productivity display";
1590 case 5: return "Desktop gaming display";
1591 case 6: return "Presentation display";
1592 case 7: return "Head-mounted Virtual Reality (VR) display";
1593 case 8: return "Head-mounted Augmented Reality (AR) display";
1594 default: break;
1597 fail("Unknown %s 0x%02x.\n", headingstr.c_str(), x);
1598 return std::string("Unknown " + headingstr + " (") + utohex(x) + ")";
1601 void edid_state::preparse_displayid_block(const unsigned char *x)
1603 unsigned length = x[2];
1605 if (length > 121)
1606 length = 121;
1608 unsigned offset = 5;
1610 dispid.preparsed_displayid_blocks++;
1611 while (length > 0) {
1612 unsigned tag = x[offset];
1613 unsigned len = x[offset + 2];
1615 switch (tag) {
1616 case 0x02:
1617 dispid.preparsed_color_ids |= 1 << ((x[offset + 1] >> 3) & 0x0f);
1618 break;
1619 case 0x0e:
1620 dispid.preparsed_xfer_ids |= 1 << ((x[offset + 1] >> 4) & 0x0f);
1621 break;
1622 default:
1623 break;
1626 if (length < 3)
1627 break;
1629 if (length < len + 3)
1630 break;
1632 if (!tag && !len)
1633 break;
1635 length -= len + 3;
1636 offset += len + 3;
1640 unsigned edid_state::displayid_block(const unsigned version, const unsigned char *x, unsigned length)
1642 unsigned i;
1643 unsigned tag = x[0];
1644 unsigned tag_version = (tag < 0x20) ? 1 : (tag < 0x7f) ? 2 : (tag < 0x80) ? 1 : 0;
1645 bool dooutputname = true;
1646 unsigned len = (length < 3) ? 0 : x[2];
1647 bool hasoui = false;
1648 unsigned ouinum;
1650 switch (tag) {
1651 // DisplayID 1.3:
1652 case 0x00:
1653 data_block_oui("Product Identification Data Block (" + utohex(tag) + ")",
1654 x + 3, len, &ouinum, true, true, true);
1655 dooutputname = false;
1656 hasoui = true;
1657 break;
1658 case 0x01: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
1659 case 0x02: data_block = "Color Characteristics Data Block"; break;
1660 case 0x03: data_block = "Video Timing Modes Type 1 - Detailed Timings Data Block"; break;
1661 case 0x04: data_block = "Video Timing Modes Type 2 - Detailed Timings Data Block"; break;
1662 case 0x05: data_block = "Video Timing Modes Type 3 - Short Timings Data Block"; break;
1663 case 0x06: data_block = "Video Timing Modes Type 4 - DMT Timings Data Block"; break;
1664 case 0x07: data_block = "Supported Timing Modes Type 1 - VESA DMT Timings Data Block"; break;
1665 case 0x08: data_block = "Supported Timing Modes Type 2 - CTA-861 Timings Data Block"; break;
1666 case 0x09: data_block = "Video Timing Range Data Block"; break;
1667 case 0x0a: data_block = "Product Serial Number Data Block"; break;
1668 case 0x0b: data_block = "GP ASCII String Data Block"; break;
1669 case 0x0c: data_block = "Display Device Data Data Block"; break;
1670 case 0x0d: data_block = "Interface Power Sequencing Data Block"; break;
1671 case 0x0e: data_block = "Transfer Characteristics Data Block"; break;
1672 case 0x0f: data_block = "Display Interface Data Block"; break;
1673 case 0x10: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
1674 case 0x11: data_block = "Video Timing Modes Type 5 - Short Timings Data Block"; break;
1675 case 0x12: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
1676 case 0x13: data_block = "Video Timing Modes Type 6 - Detailed Timings Data Block"; break;
1677 // 0x14 .. 0x7e RESERVED for Additional VESA-defined Data Blocks
1678 // DisplayID 2.0
1679 case 0x20:
1680 data_block_oui("Product Identification Data Block (" + utohex(tag) + ")",
1681 x + 3, len, &ouinum, false, false, false);
1682 dooutputname = false;
1683 hasoui = true;
1684 break;
1685 case 0x21: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
1686 case 0x22: data_block = "Video Timing Modes Type 7 - Detailed Timings Data Block"; break;
1687 case 0x23: data_block = "Video Timing Modes Type 8 - Enumerated Timing Codes Data Block"; break;
1688 case 0x24: data_block = "Video Timing Modes Type 9 - Formula-based Timings Data Block"; break;
1689 case 0x25: data_block = "Dynamic Video Timing Range Limits Data Block"; break;
1690 case 0x26: data_block = "Display Interface Features Data Block"; break;
1691 case 0x27: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
1692 case 0x28: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
1693 case 0x29: data_block = "ContainerID Data Block"; break;
1694 case 0x2b: data_block = "Adaptive Sync Data Block"; break;
1695 case 0x32: data_block = "Video Timing Modes Type 10 - Formula-based Timings Data Block"; break;
1696 // 0x2a .. 0x7d RESERVED for Additional VESA-defined Data Blocks
1697 case 0x7e:
1698 data_block_oui("Vendor-Specific Data Block (" + utohex(tag) + ")",
1699 x + 3, len, &ouinum, false, false, true);
1700 dooutputname = false;
1701 hasoui = true;
1702 tag |= ouinum;
1703 break;
1704 case 0x7f:
1705 data_block_oui("Vendor-Specific Data Block (" + utohex(tag) + ")",
1706 x + 3, len, &ouinum, false, true, false);
1707 dooutputname = false;
1708 hasoui = true;
1709 tag |= ouinum;
1710 break;
1711 // 0x80 RESERVED
1712 case 0x81: data_block = "CTA-861 DisplayID Data Block"; break;
1713 // 0x82 .. 0xff RESERVED
1714 default: data_block = "Unknown DisplayID Data Block (" + utohex(tag) + ", length " + std::to_string(length) + ")"; break;
1717 if (length < 3) {
1718 // Report a problem when the remaining bytes are not 0.
1719 data_block.clear(); // Probably not a Data Block so clear this.
1720 if (tag || (length > 1 && x[1])) {
1721 printf(" Filler:\n");
1722 fail("Not enough bytes remain (%d) for a DisplayID data block and the DisplayID filler is non-0.\n", length);
1723 hex_block(" ", x, length);
1725 return length;
1728 if (length < len + 3) {
1729 data_block.clear(); // Probably not a Data Block so clear this.
1730 printf(" Filler:\n");
1731 fail("The length of this DisplayID data block (%d) exceeds the number of bytes remaining (%d).\n", len + 3, length);
1732 hex_block(" ", x, length);
1733 return length;
1736 if (!tag && !len) {
1737 // A Product Identification Data Block with no payload bytes is not valid - assume this is the end.
1738 data_block.clear(); // Probably not a Product Identification Data Block so clear this.
1739 if (!memchk(x, length)) {
1740 printf(" Filler:\n");
1741 fail("Non-0 filler bytes in the DisplayID block.\n");
1742 hex_block(" ", x, length);
1744 return length;
1747 if (dooutputname && data_block.length())
1748 printf(" %s:\n", data_block.c_str());
1750 if (version >= 0x20 && tag_version == 1)
1751 fail("Use of DisplayID v1.x tag for DisplayID v%u.%u.\n",
1752 version >> 4, version & 0xf);
1753 if (version < 0x20 && tag_version == 2)
1754 fail("Use of DisplayID v2.0 tag for DisplayID v%u.%u.\n",
1755 version >> 4, version & 0xf);
1757 unsigned block_rev = x[1] & 0x07;
1759 switch (tag) {
1760 case 0x00: parse_displayid_product_id(x); break;
1761 case 0x01: parse_displayid_parameters(x); break;
1762 case 0x02: parse_displayid_color_characteristics(x); break;
1763 case 0x03:
1764 check_displayid_datablock_revision(x[1], 0, block_rev & 1);
1765 for (i = 0; i < len / 20; i++)
1766 parse_displayid_type_1_7_timing(&x[3 + (i * 20)], false, block_rev);
1767 break;
1768 case 0x04:
1769 check_displayid_datablock_revision(x[1]);
1770 for (i = 0; i < len / 11; i++)
1771 parse_displayid_type_2_timing(&x[3 + (i * 11)]);
1772 break;
1773 case 0x05:
1774 check_displayid_datablock_revision(x[1], 0, block_rev & 1);
1775 for (i = 0; i < len / 3; i++)
1776 parse_displayid_type_3_timing(&x[3 + (i * 3)]);
1777 break;
1778 case 0x06:
1779 check_displayid_datablock_revision(x[1], 0xc0, 1);
1780 for (i = 0; i < len; i++)
1781 parse_displayid_type_4_8_timing((x[1] & 0xc0) >> 6, x[3 + i]);
1782 break;
1783 case 0x07:
1784 check_displayid_datablock_revision(x[1]);
1785 for (i = 0; i < min(len, 10) * 8; i++)
1786 if (x[3 + i / 8] & (1 << (i % 8))) {
1787 char type[16];
1788 sprintf(type, "DMT 0x%02x", i + 1);
1789 print_timings(" ", find_dmt_id(i + 1), type);
1791 break;
1792 case 0x08:
1793 check_displayid_datablock_revision(x[1]);
1794 for (i = 0; i < min(len, 8) * 8; i++)
1795 if (x[3 + i / 8] & (1 << (i % 8))) {
1796 char type[16];
1797 sprintf(type, "VIC %3u", i + 1);
1798 print_timings(" ", find_vic_id(i + 1), type);
1800 break;
1801 case 0x09: parse_displayid_video_timing_range_limits(x); break;
1802 case 0x0a:
1803 case 0x0b: parse_displayid_string(x); break;
1804 case 0x0c: parse_displayid_display_device(x); break;
1805 case 0x0d: parse_displayid_intf_power_sequencing(x); break;
1806 case 0x0e: parse_displayid_transfer_characteristics(x); break;
1807 case 0x0f: parse_displayid_display_intf(x); break;
1808 case 0x10: parse_displayid_stereo_display_intf(x); break;
1809 case 0x11:
1810 check_displayid_datablock_revision(x[1]);
1811 for (i = 0; i < len / 7; i++)
1812 parse_displayid_type_5_timing(&x[3 + (i * 7)]);
1813 break;
1814 case 0x12: parse_displayid_tiled_display_topology(x, false); break;
1815 case 0x13:
1816 check_displayid_datablock_revision(x[1]);
1817 for (i = 0; i < len; i += (x[3 + i + 2] & 0x40) ? 17 : 14)
1818 parse_displayid_type_6_timing(&x[3 + i]);
1819 break;
1820 case 0x20: parse_displayid_product_id(x); break;
1821 case 0x21:
1822 if (block_rev >= 1)
1823 check_displayid_datablock_revision(x[1], 0x80, 1);
1824 else
1825 check_displayid_datablock_revision(x[1], 0x80, 0);
1826 parse_displayid_parameters_v2(x, block_rev);
1827 break;
1828 case 0x22: {
1829 unsigned sz = 20;
1831 if (block_rev >= 2)
1832 check_displayid_datablock_revision(x[1], 0x08, 2);
1833 else if (block_rev == 1)
1834 check_displayid_datablock_revision(x[1], 0x08, 1);
1835 else
1836 check_displayid_datablock_revision(x[1]);
1837 sz += (x[1] & 0x70) >> 4;
1838 if (block_rev >= 1 && (x[1] & 0x08))
1839 printf(" These timings support DSC pass-through\n");
1840 for (i = 0; i < len / sz; i++)
1841 parse_displayid_type_1_7_timing(&x[3 + i * sz], true, block_rev);
1842 break;
1844 case 0x23:
1845 if (block_rev)
1846 check_displayid_datablock_revision(x[1], 0xe8, 1);
1847 else
1848 check_displayid_datablock_revision(x[1], 0xc8);
1849 if (x[1] & 0x08) {
1850 for (i = 0; i < len / 2; i++)
1851 parse_displayid_type_4_8_timing((x[1] & 0xc0) >> 6,
1852 x[3 + i * 2] |
1853 (x[4 + i * 2] << 8));
1854 } else {
1855 for (i = 0; i < len; i++)
1856 parse_displayid_type_4_8_timing((x[1] & 0xc0) >> 6,
1857 x[3 + i]);
1859 break;
1860 case 0x24:
1861 check_displayid_datablock_revision(x[1]);
1862 for (i = 0; i < len / 6; i++)
1863 parse_displayid_type_9_timing(&x[3 + i * 6]);
1864 break;
1865 case 0x25: parse_displayid_dynamic_video_timings_range_limits(x); break;
1866 case 0x26: parse_displayid_interface_features(x); break;
1867 case 0x27: parse_displayid_stereo_display_intf(x); break;
1868 case 0x28: parse_displayid_tiled_display_topology(x, true); break;
1869 case 0x29: parse_displayid_ContainerID(x); break;
1870 case 0x2b: parse_displayid_adaptive_sync(x); break;
1871 case 0x32: {
1872 unsigned sz = 6 + ((x[1] & 0x70) >> 4);
1874 check_displayid_datablock_revision(x[1], 0x70);
1875 for (i = 0; i < len / sz; i++)
1876 parse_displayid_type_10_timing(&x[3 + i * sz], sz);
1877 break;
1879 case 0x7e|kOUI_VESA: parse_displayid_vesa(x); break;
1880 case 0x81: parse_displayid_cta_data_block(x); break;
1881 default: hex_block(" ", x + 3 + (hasoui ? 3 : 0), (len > (hasoui ? 3 : 0)) ? len - (hasoui ? 3 : 0) : 0); break;
1884 if ((tag == 0x00 || tag == 0x20) &&
1885 (!dispid.is_base_block || dispid.block_number > 0))
1886 fail("%s is required to be the first DisplayID Data Block.\n",
1887 data_block.c_str());
1889 dispid.block_number++;
1890 return len + 3;
1893 void edid_state::parse_displayid_block(const unsigned char *x)
1895 unsigned version = x[1];
1896 unsigned length = x[2];
1897 unsigned prod_type = x[3]; // future check: based on type, check for required data blocks
1898 unsigned ext_count = x[4];
1900 printf(" Version: %u.%u\n Extension Count: %u\n",
1901 version >> 4, version & 0xf, ext_count);
1903 if (dispid.is_base_block) {
1904 dispid.version = version;
1905 printf(" %s: %s\n", product_type(prod_type, true).c_str(),
1906 product_type(prod_type, false).c_str());
1907 if (!prod_type)
1908 fail("DisplayID Base Block has no product type.\n");
1909 if (ext_count != dispid.preparsed_displayid_blocks - 1)
1910 fail("Expected %u DisplayID Extension Block%s, but got %u.\n",
1911 ext_count,
1912 ext_count > 1 ? "s" : "",
1913 dispid.preparsed_displayid_blocks - 1);
1914 } else {
1915 if (prod_type)
1916 fail("Product Type should be 0 in extension block.\n");
1917 if (ext_count)
1918 fail("Extension Count should be 0 in extension block.\n");
1919 if (version != dispid.version)
1920 fail("Got version %u.%u, expected %u.%u.\n",
1921 version >> 4, version & 0xf,
1922 dispid.version >> 4, dispid.version & 0xf);
1925 if (length > 121) {
1926 fail("DisplayID length %d is greater than 121.\n", length);
1927 length = 121;
1930 unsigned len;
1931 for (const unsigned char *y = x + 5; length > 0; y += len) {
1932 len = displayid_block(version, y, length);
1933 length -= len;
1937 * DisplayID length field is number of following bytes
1938 * but checksum is calculated over the entire structure
1939 * (excluding DisplayID-in-EDID magic byte)
1941 data_block.clear();
1942 do_checksum(" ", x + 1, x[2] + 5);
1944 if (!memchk(x + 1 + x[2] + 5, 0x7f - (1 + x[2] + 5))) {
1945 data_block = "Padding";
1946 fail("DisplayID padding contains non-zero bytes.\n");
1948 dispid.is_base_block = false;
1951 void edid_state::check_displayid_blocks()
1953 data_block = "DisplayID";
1954 if (!dispid.has_product_identification)
1955 fail("Missing DisplayID Product Identification Data Block.\n");
1956 if (dispid.is_display && !dispid.has_display_parameters)
1957 fail("Missing DisplayID Display Parameters Data Block.\n");
1958 if (dispid.is_display && !dispid.has_display_interface_features)
1959 fail("Missing DisplayID Display Interface Features Data Block.\n");
1960 if (dispid.is_display && !dispid.has_type_1_7)
1961 fail("Missing DisplayID Type %s Detailed Timing Data Block.\n",
1962 dispid.version >= 0x20 ? "VII" : "I");
1963 if (dispid.preferred_timings.empty())
1964 fail("DisplayID expects at least one preferred timing.\n");