edid-decode: parse_displayid_parameters_v2: add missing version check
[edid-decode.git] / parse-displayid-block.cpp
blob59ff8b72cdf685e031f2aabd6ca6285af5a32b73
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 check_displayid_datablock_revision(x[1], 0, (x[1] & 7) == 1);
1145 if (!check_displayid_datablock_length(x, 29, 29))
1146 return;
1147 if (dispid.has_display_parameters)
1148 fail("Duplicate Display Parameters Data Block.\n");
1149 dispid.has_display_parameters = true;
1151 unsigned hor_size = (x[4] << 8) + x[3];
1152 unsigned vert_size = (x[6] << 8) + x[5];
1154 dispid.image_width = hor_size;
1155 dispid.image_height = vert_size;
1156 if (x[1] & 0x80) {
1157 printf(" Image size: %u mm x %u mm\n", hor_size, vert_size);
1158 dispid.image_width *= 10;
1159 dispid.image_height *= 10;
1160 } else {
1161 printf(" Image size: %.1f mm x %.1f mm\n",
1162 hor_size / 10.0, vert_size / 10.0);
1164 if (dispid.image_width > image_width ||
1165 dispid.image_height > image_height) {
1166 image_width = dispid.image_width;
1167 image_height = dispid.image_height;
1170 unsigned w = (x[8] << 8) + x[7];
1171 unsigned h = (x[10] << 8) + x[9];
1173 printf(" Display native pixel format: %ux%u\n", w, h);
1174 set_displayid_native_res(w, h);
1176 unsigned char v = x[11];
1177 printf(" Scan Orientation: ");
1178 switch (v & 0x07) {
1179 case 0x00: printf("Left to Right, Top to Bottom\n"); break;
1180 case 0x01: printf("Right to Left, Top to Bottom\n"); break;
1181 case 0x02: printf("Top to Bottom, Right to Left\n"); break;
1182 case 0x03: printf("Bottom to Top, Right to Left\n"); break;
1183 case 0x04: printf("Right to Left, Bottom to Top\n"); break;
1184 case 0x05: printf("Left to Right, Bottom to Top\n"); break;
1185 case 0x06: printf("Bottom to Top, Left to Right\n"); break;
1186 case 0x07: printf("Top to Bottom, Left to Right\n"); break;
1188 printf(" Luminance Information: ");
1189 switch ((v >> 3) & 0x03) {
1190 case 0x00: printf("Minimum guaranteed value\n"); break;
1191 case 0x01: printf("Guidance for the Source device\n"); break;
1192 default: printf("Reserved\n"); break;
1194 printf(" Color Information: CIE %u\n",
1195 (v & 0x40) ? 1976 : 1931);
1196 printf(" Audio Speaker Information: %sintegrated\n",
1197 (v & 0x80) ? "not " : "");
1198 printf(" Native Color Chromaticity:\n");
1199 printf(" Primary #1: (%.6f, %.6f)\n",
1200 fp2d(x[0x0c] | ((x[0x0d] & 0x0f) << 8)),
1201 fp2d(((x[0x0d] & 0xf0) >> 4) | (x[0x0e] << 4)));
1202 printf(" Primary #2: (%.6f, %.6f)\n",
1203 fp2d(x[0x0f] | ((x[0x10] & 0x0f) << 8)),
1204 fp2d(((x[0x10] & 0xf0) >> 4) | (x[0x11] << 4)));
1205 printf(" Primary #3: (%.6f, %.6f)\n",
1206 fp2d(x[0x12] | ((x[0x13] & 0x0f) << 8)),
1207 fp2d(((x[0x13] & 0xf0) >> 4) | (x[0x14] << 4)));
1208 printf(" White Point: (%.6f, %.6f)\n",
1209 fp2d(x[0x15] | ((x[0x16] & 0x0f) << 8)),
1210 fp2d(((x[0x16] & 0xf0) >> 4) | (x[0x17] << 4)));
1211 printf(" Native Maximum Luminance (Full Coverage): %s\n",
1212 ieee7542d(x[0x18] | (x[0x19] << 8)).c_str());
1213 printf(" Native Maximum Luminance (10%% Rectangular Coverage): %s\n",
1214 ieee7542d(x[0x1a] | (x[0x1b] << 8)).c_str());
1215 printf(" Native Minimum Luminance: %s\n",
1216 ieee7542d(x[0x1c] | (x[0x1d] << 8)).c_str());
1217 printf(" Native Color Depth: ");
1218 if (!(x[0x1e] & 0x07))
1219 printf("Not defined\n");
1220 else if (bpc444[x[0x1e] & 0x07])
1221 printf("%s bpc\n", bpc444[x[0x1e] & 0x07]);
1222 else
1223 printf("Reserved\n");
1224 printf(" Display Device Technology: ");
1225 switch ((x[0x1e] >> 4) & 0x07) {
1226 case 0x00: printf("Not Specified\n"); break;
1227 case 0x01: printf("Active Matrix LCD\n"); break;
1228 case 0x02: printf("Organic LED\n"); break;
1229 default: printf("Reserved\n"); break;
1231 if (block_rev)
1232 printf(" Display Device Theme Preference: %s\n",
1233 (x[0x1e] & 0x80) ? "Dark Theme Preferred" : "No Preference");
1234 if (x[0x1f] != 0xff)
1235 printf(" Native Gamma EOTF: %.2f\n",
1236 (100 + x[0x1f]) / 100.0);
1239 // tag 0x24
1241 void edid_state::parse_displayid_type_9_timing(const unsigned char *x)
1243 struct timings t = {};
1244 std::string s("aspect ");
1246 t.hact = 1 + (x[1] | (x[2] << 8));
1247 t.vact = 1 + (x[3] | (x[4] << 8));
1248 calc_ratio(&t);
1249 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1250 switch ((x[0] >> 5) & 0x3) {
1251 case 0:
1252 s += ", no 3D stereo";
1253 break;
1254 case 1:
1255 s += ", 3D stereo";
1256 break;
1257 case 2:
1258 s += ", 3D stereo depends on user action";
1259 break;
1260 case 3:
1261 s += ", reserved";
1262 fail("Reserved stereo 0x03.\n");
1263 break;
1265 if (x[0] & 0x10)
1266 s += ", refresh rate * (1000/1001) supported";
1268 switch (x[0] & 0x07) {
1269 case 1: t.rb = RB_CVT_V1; break;
1270 case 2: t.rb = RB_CVT_V2; break;
1271 default: break;
1274 edid_cvt_mode(1 + x[5], t);
1276 print_timings(" ", &t, "CVT", s.c_str());
1279 // tag 0x25
1281 void edid_state::parse_displayid_dynamic_video_timings_range_limits(const unsigned char *x)
1283 check_displayid_datablock_revision(x[1], 0, (x[1] & 7) == 1);
1285 if (!check_displayid_datablock_length(x, 9, 9))
1286 return;
1288 printf(" Minimum Pixel Clock: %u kHz\n",
1289 1 + (x[3] | (x[4] << 8) | (x[5] << 16)));
1290 printf(" Maximum Pixel Clock: %u kHz\n",
1291 1 + (x[6] | (x[7] << 8) | (x[8] << 16)));
1292 printf(" Minimum Vertical Refresh Rate: %u Hz\n", x[9]);
1293 if (x[1] & 7)
1294 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x[10] + ((x[11] & 3) << 8));
1295 else
1296 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x[10]);
1297 printf(" Seamless Dynamic Video Timing Support: %s\n",
1298 (x[11] & 0x80) ? "Yes" : "No");
1301 // tag 0x26
1303 static const char *colorspace_eotf_combinations[] = {
1304 "sRGB",
1305 "BT.601",
1306 "BT.709/BT.1886",
1307 "Adobe RGB",
1308 "DCI-P3",
1309 "BT.2020",
1310 "BT.2020/SMPTE ST 2084"
1313 static const char *colorspace_eotf_reserved[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
1315 static const char *colorspaces[] = {
1316 "Undefined",
1317 "sRGB",
1318 "BT.601",
1319 "BT.709",
1320 "Adobe RGB",
1321 "DCI-P3",
1322 "BT.2020",
1323 "Custom"
1326 static const char *eotfs[] = {
1327 "Undefined",
1328 "sRGB",
1329 "BT.601",
1330 "BT.1886",
1331 "Adobe RGB",
1332 "DCI-P3",
1333 "BT.2020",
1334 "Gamma function",
1335 "SMPTE ST 2084",
1336 "Hybrid Log",
1337 "Custom"
1340 void edid_state::parse_displayid_interface_features(const unsigned char *x)
1342 check_displayid_datablock_revision(x[1]);
1344 if (!check_displayid_datablock_length(x, 9))
1345 return;
1347 dispid.has_display_interface_features = true;
1348 unsigned len = x[2];
1349 if (len > 0) print_flags(" Supported bpc for RGB encoding", x[3], bpc444);
1350 if (len > 1) print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x[4], bpc444);
1351 if (len > 2) print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x[5], bpc4xx);
1352 if (len > 3) print_flags(" Supported bpc for YCbCr 4:2:0 encoding", x[6], bpc4xx);
1353 if (len > 4 && x[7])
1354 printf(" Minimum pixel rate at which YCbCr 4:2:0 encoding is supported: %.3f MHz\n",
1355 74.25 * x[7]);
1356 if (len > 5) print_flags(" Supported audio capability and features (kHz)",
1357 x[8], audiorates, true);
1358 if (len > 6) print_flags(" Supported color space and EOTF standard combination 1",
1359 x[9], colorspace_eotf_combinations);
1360 if (len > 7) print_flags(" Supported color space and EOTF standard combination 2",x[10], colorspace_eotf_reserved);
1362 unsigned i = 0;
1364 if (len > 8 && x[11]) {
1365 printf(" Supported color space and EOTF additional combinations:");
1366 for (i = 0; i < x[11]; i++) {
1367 if (i > 6) {
1368 printf("\n Number of additional color space and EOTF combinations (%d) is greater than allowed (7).", x[11]);
1369 break;
1370 } else if (i + 10 > len) {
1371 printf("\n Number of additional color space and EOTF combinations (%d) is too many to fit in block (%d).", x[11], len - 9);
1372 break;
1375 const char *colorspace = "Out of range";
1376 const char *eotf = "Out of range";
1377 unsigned colorspace_index = (x[12 + i] >> 4) & 0xf;
1378 unsigned eotf_index = x[12 + i] & 0xf;
1380 if (colorspace_index < sizeof(colorspaces) / sizeof(colorspaces[0]))
1381 colorspace = colorspaces[colorspace_index];
1382 if (eotf_index < sizeof(eotfs) / sizeof(eotfs[0]))
1383 eotf = eotfs[eotf_index];
1385 if (i > 0)
1386 printf(", ");
1387 if (!strcmp(colorspace, eotf))
1388 printf("%s", colorspace);
1389 else
1390 printf("%s/%s", colorspace, eotf);
1392 printf("\n");
1394 check_displayid_datablock_length(x, 9 + i, 9 + i, 9 + i);
1397 // tag 0x29
1399 void edid_state::parse_displayid_ContainerID(const unsigned char *x)
1401 check_displayid_datablock_revision(x[1]);
1403 if (check_displayid_datablock_length(x, 16, 16)) {
1404 x += 3;
1405 printf(" Container ID: %s\n", containerid2s(x).c_str());
1409 // tag 0x2b
1411 void edid_state::parse_displayid_adaptive_sync(const unsigned char *x)
1413 check_displayid_datablock_revision(x[1], 0x70);
1415 unsigned size = 6 + ((x[1] >> 4) & 0x7);
1416 unsigned len = x[2];
1417 unsigned descriptor = 1;
1419 x += 3;
1420 if (len % size)
1421 fail("DisplayID payload length %u is not a multiple of %u.\n", len, size);
1422 while (len >= size) {
1423 printf(" Descriptor #%u:\n", descriptor++);
1425 printf(" %sNative Panel Range\n", (x[0] & 1) ? "" : "Non-");
1426 unsigned v = (x[0] >> 2) & 3;
1427 switch (v) {
1428 case 0: printf(" Fixed Average V-Total\n"); break;
1429 case 1: printf(" Fixed Average V-Total and Adaptive V-Total\n"); break;
1430 default:
1431 printf(" Reserved %u\n", v);
1432 fail("Use of reserved value %u.\n", v);
1433 break;
1435 if (x[0] & 0x10)
1436 printf(" Supports Seamless Transition\n");
1437 if (x[0] & 0x02)
1438 printf(" 'Max Single Frame Duration Increase' field value without jitter impact\n");
1439 if (x[0] & 0x20)
1440 printf(" 'Max Single Frame Duration Decrease' field value without jitter impact\n");
1441 printf(" Max Duration Increase: %.2f ms\n", x[1] / 4.0);
1442 printf(" Max Duration Decrease: %.2f ms\n", x[5] / 4.0);
1443 printf(" Min Refresh Rate: %u Hz\n", x[2]);
1444 printf(" Max Refresh Rate: %u Hz\n", 1 + x[3] + (x[4] & 3) * 256);
1446 len -= size;
1447 x += size;
1451 // tag 0x32
1453 void edid_state::parse_displayid_type_10_timing(const unsigned char *x,
1454 unsigned sz, bool is_cta)
1456 struct timings t = {};
1457 std::string name = is_cta ? std::string("VTDB ") + std::to_string(cta.vec_vtdbs.size() + 1) : "CVT";
1458 std::string s("aspect ");
1460 t.hact = 1 + (x[1] | (x[2] << 8));
1461 t.vact = 1 + (x[3] | (x[4] << 8));
1462 calc_ratio(&t);
1463 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1465 switch ((x[0] >> 5) & 0x3) {
1466 case 0:
1467 s += ", no 3D stereo";
1468 break;
1469 case 1:
1470 s += ", 3D stereo";
1471 break;
1472 case 2:
1473 s += ", 3D stereo depends on user action";
1474 break;
1475 case 3:
1476 s += ", reserved";
1477 fail("Reserved stereo 0x03.\n");
1478 break;
1481 switch (x[0] & 0x07) {
1482 case 1: t.rb = RB_CVT_V1; break;
1483 case 2: t.rb = RB_CVT_V2; break;
1484 case 3: t.rb = RB_CVT_V3; break;
1485 default: break;
1488 unsigned rb = t.rb;
1489 unsigned rb_h_blank = rb == RB_CVT_V3 ? 80 : 0;
1490 unsigned rb_v_blank = 460;
1491 bool early_vsync_rqd = false;
1493 if (x[0] & 0x10) {
1494 if (rb == RB_CVT_V2) {
1495 s += ", refresh rate * (1000/1001) supported";
1496 t.rb |= RB_ALT;
1497 } else if (rb == RB_CVT_V3) {
1498 s += ", hblank is 160 pixels";
1499 t.rb |= RB_ALT;
1500 rb_h_blank = 160;
1501 } else {
1502 fail("VR_HB must be 0.\n");
1505 if (x[0] & 0x80)
1506 s += ", YCbCr 4:2:0";
1508 if (x[0] & 0x08) {
1509 if (rb == RB_CVT_V3) {
1510 early_vsync_rqd = true;
1511 s += ", early-vsync";
1512 } else {
1513 fail("EVS must be 0.\n");
1517 unsigned refresh = 1 + x[5] + (sz == 6 ? 0 : ((x[6] & 3) << 8));
1519 if (sz > 6) {
1520 if (rb == RB_CVT_V3) {
1521 unsigned delta_hblank = (x[6] >> 2) & 7;
1523 if (rb_h_blank == 80)
1524 rb_h_blank = 80 + 8 * delta_hblank;
1525 else if (delta_hblank <= 5)
1526 rb_h_blank = 160 + 8 * delta_hblank;
1527 else
1528 rb_h_blank = 160 - (delta_hblank - 5) * 8;
1529 if (delta_hblank)
1530 s += ", delta-hblank=" + std::to_string(delta_hblank);
1532 rb_v_blank += ((x[6] >> 5) & 7) * 35;
1533 if (rb_v_blank > 460)
1534 s += ", add-vblank=" + std::to_string(rb_v_blank - 460);
1535 } else {
1536 if (x[6] & 0xe0)
1537 fail("Additional_Vertical_Blank_Time must be 0.\n");
1538 if (x[6] & 0x1c)
1539 fail("Delta_Horizontal_Blank must be 0.\n");
1543 edid_cvt_mode(refresh, t, rb_h_blank, rb_v_blank, early_vsync_rqd);
1545 print_timings(" ", &t, name.c_str(), s.c_str());
1546 if (is_cta) {
1547 timings_ext te(t, name.c_str(), s);
1548 cta.vec_vtdbs.push_back(te);
1552 // tag 0x7e, OUI 3A-02-92 (VESA)
1554 void edid_state::parse_displayid_vesa(const unsigned char *x)
1556 check_displayid_datablock_revision(x[1]);
1558 if (!check_displayid_datablock_length(x, 5, 7))
1559 return;
1561 unsigned len = x[2];
1562 x += 6;
1563 printf(" Data Structure Type: ");
1564 switch (x[0] & 7) {
1565 case 0: printf("eDP\n"); break;
1566 case 1: printf("DP\n"); break;
1567 default: printf("Reserved (%d)\n", x[0] & 7); break;
1570 if ((x[0] >> 3) & 15)
1571 warn("Reserved bits 6:3 (%d) are not 0.\n", (x[0] >> 3) & 15);
1573 printf(" Default Colorspace and EOTF Handling: %s\n",
1574 (x[0] & 0x80) ? "Native as specified in the Display Parameters DB" : "sRGB");
1576 printf(" Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel: %u\n",
1577 x[1] & 0xf);
1578 if ((x[1] & 0xf) > 8)
1579 warn("Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel exceeds 8.\n");
1581 if ((x[1] >> 4) & 1)
1582 warn("Reserved bit 4 is not 0.\n");
1584 printf(" Multi-SST Operation: ");
1585 switch ((x[1] >> 5) & 3) {
1586 case 0: printf("Not Supported\n"); break;
1587 case 1: printf("Two Streams (number of links shall be 2 or 4)\n"); break;
1588 case 2: printf("Four Streams (number of links shall be 4)\n"); break;
1589 case 3: printf("Reserved\n"); warn("Invalid option for Multi-SST Operation.\n"); break;
1592 if ((x[1] >> 7) & 1)
1593 warn("Reserved bit 7 is not 0.\n");
1595 if (len >= 7) {
1596 double bpp = (x[2] & 0x3f) + (x[3] & 0x0f) / 16.0;
1597 printf(" Pass through timing's target DSC bits per pixel: %.4f\n", bpp);
1601 // tag 0x7f, OUI 00-10-FA (Apple)
1603 void edid_state::parse_displayid_apple(const unsigned char *x)
1605 int length = x[2] - 3;
1607 x += 6;
1609 // Based on the very limited information I found here:
1610 // https://opensource.apple.com/source/IOKitUser/IOKitUser-1445.40.1/graphics.subproj/IODisplayLib.c
1611 switch (x[0]) {
1612 case 1:
1613 printf(" Type: BLC Info/Corrections, Version: %u\n", x[1]);
1614 break;
1615 default:
1616 printf(" Type: %u, Version: %u\n", x[0], x[1]);
1617 break;
1619 hex_block(" ", x + 2, length - 2);
1622 // tag 0x81
1624 void edid_state::parse_displayid_cta_data_block(const unsigned char *x)
1626 check_displayid_datablock_revision(x[1]);
1628 unsigned len = x[2];
1629 unsigned i;
1631 if (len > 248) {
1632 fail("Length is > 248.\n");
1633 len = 248;
1635 x += 3;
1637 for (i = 0; i < len; i += (x[i] & 0x1f) + 1) {
1638 cta_block(x + i, dispid.found_tags);
1641 if (i != len)
1642 fail("Length is %u instead of %u.\n", len, i);
1645 // DisplayID main
1647 std::string edid_state::product_type(unsigned char x, bool heading)
1649 std::string headingstr;
1651 if (dispid.version < 0x20) {
1652 headingstr = "Display Product Type";
1653 if (heading) return headingstr;
1654 dispid.is_display = x == 2 || x == 3 || x == 4 || x == 6;
1655 switch (x) {
1656 case 0: return "Extension Section";
1657 case 1: return "Test Structure; test equipment only";
1658 case 2: return "Display panel or other transducer, LCD or PDP module, etc.";
1659 case 3: return "Standalone display device";
1660 case 4: return "Television receiver";
1661 case 5: return "Repeater/translator";
1662 case 6: return "DIRECT DRIVE monitor";
1663 default: break;
1665 } else {
1666 headingstr = "Display Product Primary Use Case";
1667 if (heading) return headingstr;
1668 dispid.is_display = x >= 2 && x <= 8;
1669 switch (x) {
1670 case 0: return "Same primary use case as the base section";
1671 case 1: return "Test Structure; test equipment only";
1672 case 2: return "None of the listed primary use cases; generic display";
1673 case 3: return "Television (TV) display";
1674 case 4: return "Desktop productivity display";
1675 case 5: return "Desktop gaming display";
1676 case 6: return "Presentation display";
1677 case 7: return "Head-mounted Virtual Reality (VR) display";
1678 case 8: return "Head-mounted Augmented Reality (AR) display";
1679 default: break;
1682 fail("Unknown %s 0x%02x.\n", headingstr.c_str(), x);
1683 return std::string("Unknown " + headingstr + " (") + utohex(x) + ")";
1686 void edid_state::preparse_displayid_block(unsigned char *x)
1688 bool update_checksum = false;
1689 unsigned length = x[2];
1690 unsigned offset = 5;
1692 if (length > 121)
1693 length = 121;
1695 dispid.preparsed_displayid_blocks++;
1696 while (length > 0) {
1697 unsigned tag = x[offset];
1698 unsigned len = x[offset + 2];
1700 switch (tag) {
1701 case 0x00:
1702 case 0x20:
1703 if (replace_unique_ids &&
1704 (x[offset + 0x08] || x[offset + 0x09] ||
1705 x[offset + 0x0a] || x[offset + 0x0b])) {
1706 // Replace by 123456
1707 x[offset + 0x08] = 0x40;
1708 x[offset + 0x09] = 0xe2;
1709 x[offset + 0x0a] = 0x01;
1710 x[offset + 0x0b] = 0x00;
1711 update_checksum = true;
1713 if (replace_unique_ids && x[offset + 0x0c] != 0xff) {
1714 x[offset + 0x0c] = 0;
1715 x[offset + 0x0d] = 0;
1716 update_checksum = true;
1718 break;
1719 case 0x12:
1720 case 0x28:
1721 if (replace_unique_ids &&
1722 (x[offset + 0x15] || x[offset + 0x16] ||
1723 x[offset + 0x17] || x[offset + 0x18])) {
1724 // Replace by 123456
1725 x[offset + 0x15] = 0x40;
1726 x[offset + 0x16] = 0xe2;
1727 x[offset + 0x17] = 0x01;
1728 x[offset + 0x18] = 0x00;
1729 update_checksum = true;
1731 break;
1732 case 0x29:
1733 if (replace_unique_ids) {
1734 update_checksum = true;
1735 memset(x + offset + 3, 0, 16);
1737 break;
1738 case 0x02:
1739 dispid.preparsed_color_ids |= 1 << ((x[offset + 1] >> 3) & 0x0f);
1740 break;
1741 case 0x0e:
1742 dispid.preparsed_xfer_ids |= 1 << ((x[offset + 1] >> 4) & 0x0f);
1743 break;
1744 default:
1745 break;
1748 if (length < 3)
1749 break;
1751 if (length < len + 3)
1752 break;
1754 if (!tag && !len)
1755 break;
1757 length -= len + 3;
1758 offset += len + 3;
1760 if (update_checksum) {
1761 replace_checksum(x + 1, x[2] + 5);
1762 replace_checksum(x, EDID_PAGE_SIZE);
1766 unsigned edid_state::displayid_block(const unsigned version, const unsigned char *x, unsigned length)
1768 unsigned i;
1769 unsigned tag = x[0];
1770 unsigned tag_version = (tag < 0x20) ? 1 : (tag < 0x7f) ? 2 : (tag < 0x80) ? 1 : 0;
1771 bool dooutputname = true;
1772 unsigned len = (length < 3) ? 0 : x[2];
1773 bool hasoui = false;
1774 unsigned ouinum;
1776 switch (tag) {
1777 // DisplayID 1.3:
1778 case 0x00:
1779 data_block_oui("Product Identification Data Block (" + utohex(tag) + ")",
1780 x + 3, len, &ouinum, true, true, true);
1781 dooutputname = false;
1782 hasoui = true;
1783 break;
1784 case 0x01: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
1785 case 0x02: data_block = "Color Characteristics Data Block"; break;
1786 case 0x03: data_block = "Video Timing Modes Type 1 - Detailed Timings Data Block"; break;
1787 case 0x04: data_block = "Video Timing Modes Type 2 - Detailed Timings Data Block"; break;
1788 case 0x05: data_block = "Video Timing Modes Type 3 - Short Timings Data Block"; break;
1789 case 0x06: data_block = "Video Timing Modes Type 4 - DMT Timings Data Block"; break;
1790 case 0x07: data_block = "Supported Timing Modes Type 1 - VESA DMT Timings Data Block"; break;
1791 case 0x08: data_block = "Supported Timing Modes Type 2 - CTA-861 Timings Data Block"; break;
1792 case 0x09: data_block = "Video Timing Range Data Block"; break;
1793 case 0x0a: data_block = "Product Serial Number Data Block"; break;
1794 case 0x0b: data_block = "GP ASCII String Data Block"; break;
1795 case 0x0c: data_block = "Display Device Data Data Block"; break;
1796 case 0x0d: data_block = "Interface Power Sequencing Data Block"; break;
1797 case 0x0e: data_block = "Transfer Characteristics Data Block"; break;
1798 case 0x0f: data_block = "Display Interface Data Block"; break;
1799 case 0x10: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
1800 case 0x11: data_block = "Video Timing Modes Type 5 - Short Timings Data Block"; break;
1801 case 0x12: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
1802 case 0x13: data_block = "Video Timing Modes Type 6 - Detailed Timings Data Block"; break;
1803 // 0x14 .. 0x7e RESERVED for Additional VESA-defined Data Blocks
1804 // DisplayID 2.0
1805 case 0x20:
1806 data_block_oui("Product Identification Data Block (" + utohex(tag) + ")",
1807 x + 3, len, &ouinum, false, false, true);
1808 dooutputname = false;
1809 hasoui = true;
1810 break;
1811 case 0x21: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
1812 case 0x22: data_block = "Video Timing Modes Type 7 - Detailed Timings Data Block"; break;
1813 case 0x23: data_block = "Video Timing Modes Type 8 - Enumerated Timing Codes Data Block"; break;
1814 case 0x24: data_block = "Video Timing Modes Type 9 - Formula-based Timings Data Block"; break;
1815 case 0x25: data_block = "Dynamic Video Timing Range Limits Data Block"; break;
1816 case 0x26: data_block = "Display Interface Features Data Block"; break;
1817 case 0x27: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
1818 case 0x28: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
1819 case 0x29: data_block = "ContainerID Data Block"; break;
1820 case 0x2b: data_block = "Adaptive Sync Data Block"; break;
1821 case 0x32: data_block = "Video Timing Modes Type 10 - Formula-based Timings Data Block"; break;
1822 // 0x2a .. 0x7d RESERVED for Additional VESA-defined Data Blocks
1823 case 0x7e: // DisplayID 2.0
1824 data_block_oui("Vendor-Specific Data Block (" + utohex(tag) + ")",
1825 x + 3, len, &ouinum, false, false, true);
1826 dooutputname = false;
1827 hasoui = true;
1828 tag |= ouinum;
1829 break;
1830 case 0x7f: // DisplayID 1.3
1831 data_block_oui("Vendor-Specific Data Block (" + utohex(tag) + ")",
1832 x + 3, len, &ouinum, false, true, true);
1833 dooutputname = false;
1834 hasoui = true;
1835 tag |= ouinum;
1836 break;
1837 // 0x80 RESERVED
1838 case 0x81: data_block = "CTA-861 DisplayID Data Block"; break;
1839 // 0x82 .. 0xff RESERVED
1840 default: data_block = "Unknown DisplayID Data Block (" + utohex(tag) + ", length " + std::to_string(len) + ")"; break;
1843 if (length < 3) {
1844 // Report a problem when the remaining bytes are not 0.
1845 data_block.clear(); // Probably not a Data Block so clear this.
1846 if (tag || (length > 1 && x[1])) {
1847 printf(" Filler:\n");
1848 fail("Not enough bytes remain (%d) for a DisplayID data block and the DisplayID filler is non-0.\n", length);
1849 hex_block(" ", x, length);
1851 return length;
1854 if (length < len + 3) {
1855 data_block.clear(); // Probably not a Data Block so clear this.
1856 printf(" Filler:\n");
1857 fail("The length of this DisplayID data block (%d) exceeds the number of bytes remaining (%d).\n", len + 3, length);
1858 hex_block(" ", x, length);
1859 return length;
1862 if (!tag && !len) {
1863 // A Product Identification Data Block with no payload bytes is not valid - assume this is the end.
1864 data_block.clear(); // Probably not a Product Identification Data Block so clear this.
1865 if (!memchk(x, length)) {
1866 printf(" Filler:\n");
1867 fail("Non-0 filler bytes in the DisplayID block.\n");
1868 hex_block(" ", x, length);
1870 return length;
1873 if (dooutputname && data_block.length())
1874 printf(" %s:\n", data_block.c_str());
1876 if (version >= 0x20 && tag_version == 1)
1877 fail("Use of DisplayID v1.x tag for DisplayID v%u.%u.\n",
1878 version >> 4, version & 0xf);
1879 if (version < 0x20 && tag_version == 2)
1880 fail("Use of DisplayID v2.0 tag for DisplayID v%u.%u.\n",
1881 version >> 4, version & 0xf);
1883 unsigned block_rev = x[1] & 0x07;
1885 switch (tag) {
1886 case 0x00: parse_displayid_product_id(x); break;
1887 case 0x01: parse_displayid_parameters(x); break;
1888 case 0x02: parse_displayid_color_characteristics(x); break;
1889 case 0x03:
1890 check_displayid_datablock_revision(x[1], 0, block_rev & 1);
1891 for (i = 0; i < len / 20; i++)
1892 parse_displayid_type_1_7_timing(&x[3 + (i * 20)], false, block_rev);
1893 break;
1894 case 0x04:
1895 check_displayid_datablock_revision(x[1]);
1896 for (i = 0; i < len / 11; i++)
1897 parse_displayid_type_2_timing(&x[3 + (i * 11)]);
1898 break;
1899 case 0x05:
1900 check_displayid_datablock_revision(x[1], 0, block_rev & 1);
1901 for (i = 0; i < len / 3; i++)
1902 parse_displayid_type_3_timing(&x[3 + (i * 3)]);
1903 break;
1904 case 0x06:
1905 check_displayid_datablock_revision(x[1], 0xc0, 1);
1906 for (i = 0; i < len; i++)
1907 parse_displayid_type_4_8_timing((x[1] & 0xc0) >> 6, x[3 + i]);
1908 break;
1909 case 0x07:
1910 check_displayid_datablock_revision(x[1]);
1911 for (i = 0; i < min(len, 10) * 8; i++)
1912 if (x[3 + i / 8] & (1 << (i % 8))) {
1913 char type[16];
1914 sprintf(type, "DMT 0x%02x", i + 1);
1915 print_timings(" ", find_dmt_id(i + 1), type);
1917 break;
1918 case 0x08:
1919 check_displayid_datablock_revision(x[1]);
1920 for (i = 0; i < min(len, 8) * 8; i++)
1921 if (x[3 + i / 8] & (1 << (i % 8))) {
1922 char type[16];
1923 sprintf(type, "VIC %3u", i + 1);
1924 print_timings(" ", find_vic_id(i + 1), type);
1926 break;
1927 case 0x09: parse_displayid_video_timing_range_limits(x); break;
1928 case 0x0a:
1929 case 0x0b: parse_displayid_string(x); break;
1930 case 0x0c: parse_displayid_display_device(x); break;
1931 case 0x0d: parse_displayid_intf_power_sequencing(x); break;
1932 case 0x0e: parse_displayid_transfer_characteristics(x); break;
1933 case 0x0f: parse_displayid_display_intf(x); break;
1934 case 0x10: parse_displayid_stereo_display_intf(x); break;
1935 case 0x11:
1936 check_displayid_datablock_revision(x[1]);
1937 for (i = 0; i < len / 7; i++)
1938 parse_displayid_type_5_timing(&x[3 + (i * 7)]);
1939 break;
1940 case 0x12: parse_displayid_tiled_display_topology(x, false); break;
1941 case 0x13:
1942 check_displayid_datablock_revision(x[1]);
1943 for (i = 0; i < len; i += (x[3 + i + 2] & 0x40) ? 17 : 14)
1944 parse_displayid_type_6_timing(&x[3 + i]);
1945 break;
1946 case 0x20: parse_displayid_product_id(x); break;
1947 case 0x21:
1948 if (block_rev >= 1)
1949 check_displayid_datablock_revision(x[1], 0x80, 1);
1950 else
1951 check_displayid_datablock_revision(x[1], 0x80, 0);
1952 parse_displayid_parameters_v2(x, block_rev);
1953 break;
1954 case 0x22: {
1955 unsigned sz = 20;
1957 if (block_rev >= 2)
1958 check_displayid_datablock_revision(x[1], 0x08, 2);
1959 else if (block_rev == 1)
1960 check_displayid_datablock_revision(x[1], 0x08, 1);
1961 else
1962 check_displayid_datablock_revision(x[1]);
1963 sz += (x[1] & 0x70) >> 4;
1964 if (block_rev >= 1 && (x[1] & 0x08))
1965 printf(" These timings support DSC pass-through\n");
1966 for (i = 0; i < len / sz; i++)
1967 parse_displayid_type_1_7_timing(&x[3 + i * sz], true, block_rev);
1968 break;
1970 case 0x23:
1971 if (block_rev)
1972 check_displayid_datablock_revision(x[1], 0xe8, 1);
1973 else
1974 check_displayid_datablock_revision(x[1], 0xc8);
1975 if (x[1] & 0x08) {
1976 for (i = 0; i < len / 2; i++)
1977 parse_displayid_type_4_8_timing((x[1] & 0xc0) >> 6,
1978 x[3 + i * 2] |
1979 (x[4 + i * 2] << 8));
1980 } else {
1981 for (i = 0; i < len; i++)
1982 parse_displayid_type_4_8_timing((x[1] & 0xc0) >> 6,
1983 x[3 + i]);
1985 break;
1986 case 0x24:
1987 check_displayid_datablock_revision(x[1]);
1988 for (i = 0; i < len / 6; i++)
1989 parse_displayid_type_9_timing(&x[3 + i * 6]);
1990 break;
1991 case 0x25: parse_displayid_dynamic_video_timings_range_limits(x); break;
1992 case 0x26: parse_displayid_interface_features(x); break;
1993 case 0x27: parse_displayid_stereo_display_intf(x); break;
1994 case 0x28: parse_displayid_tiled_display_topology(x, true); break;
1995 case 0x29: parse_displayid_ContainerID(x); break;
1996 case 0x2b: parse_displayid_adaptive_sync(x); break;
1997 case 0x32: {
1998 unsigned sz = 6 + ((x[1] & 0x70) >> 4);
2000 check_displayid_datablock_revision(x[1], 0x70);
2001 for (i = 0; i < len / sz; i++)
2002 parse_displayid_type_10_timing(&x[3 + i * sz], sz);
2003 break;
2005 case 0x7e|kOUI_VESA: parse_displayid_vesa(x); break;
2006 case 0x7f|kOUI_Apple: parse_displayid_apple(x); break;
2007 case 0x81: parse_displayid_cta_data_block(x); break;
2008 default: hex_block(" ", x + 3 + (hasoui ? 3 : 0), (len > (hasoui ? 3 : 0)) ? len - (hasoui ? 3 : 0) : 0); break;
2011 if ((tag == 0x00 || tag == 0x20) &&
2012 (!dispid.is_base_block || dispid.block_number > 0))
2013 fail("%s is required to be the first DisplayID Data Block.\n",
2014 data_block.c_str());
2016 dispid.block_number++;
2017 return len + 3;
2020 void edid_state::parse_displayid_block(const unsigned char *x)
2022 unsigned version = x[1];
2023 unsigned length = x[2];
2024 unsigned prod_type = x[3]; // future check: based on type, check for required data blocks
2025 unsigned ext_count = x[4];
2027 printf(" Version: %u.%u\n Extension Count: %u\n",
2028 version >> 4, version & 0xf, ext_count);
2030 if (dispid.is_base_block) {
2031 dispid.version = version;
2032 printf(" %s: %s\n", product_type(prod_type, true).c_str(),
2033 product_type(prod_type, false).c_str());
2034 if (!prod_type)
2035 fail("DisplayID Base Block has no product type.\n");
2036 if (ext_count != dispid.preparsed_displayid_blocks - 1)
2037 fail("Expected %u DisplayID Extension Block%s, but got %u.\n",
2038 ext_count,
2039 ext_count > 1 ? "s" : "",
2040 dispid.preparsed_displayid_blocks - 1);
2041 } else {
2042 if (prod_type)
2043 fail("Product Type should be 0 in extension block.\n");
2044 if (ext_count)
2045 fail("Extension Count should be 0 in extension block.\n");
2046 if (version != dispid.version)
2047 fail("Got version %u.%u, expected %u.%u.\n",
2048 version >> 4, version & 0xf,
2049 dispid.version >> 4, dispid.version & 0xf);
2052 if (length > 121) {
2053 fail("DisplayID length %d is greater than 121.\n", length);
2054 length = 121;
2057 unsigned len;
2058 for (const unsigned char *y = x + 5; length > 0; y += len) {
2059 len = displayid_block(version, y, length);
2060 length -= len;
2064 * DisplayID length field is number of following bytes
2065 * but checksum is calculated over the entire structure
2066 * (excluding DisplayID-in-EDID magic byte)
2068 data_block.clear();
2069 do_checksum(" ", x + 1, x[2] + 5);
2071 unused_bytes = 0x7f - (1 + x[2] + 5);
2072 if (!memchk(x + 1 + x[2] + 5, unused_bytes)) {
2073 data_block = "Padding";
2074 fail("Contains non-zero bytes.\n");
2076 dispid.is_base_block = false;
2079 void edid_state::check_displayid_blocks()
2081 data_block = "DisplayID";
2082 if (!dispid.has_product_identification)
2083 fail("Missing DisplayID Product Identification Data Block.\n");
2084 if (dispid.is_display && !dispid.has_display_parameters)
2085 fail("Missing DisplayID Display Parameters Data Block.\n");
2086 if (dispid.is_display && !dispid.has_display_interface_features)
2087 fail("Missing DisplayID Display Interface Features Data Block.\n");
2088 if (dispid.is_display && !dispid.has_type_1_7)
2089 fail("Missing DisplayID Type %s Detailed Timing Data Block.\n",
2090 dispid.version >= 0x20 ? "VII" : "I");
2091 if (dispid.preferred_timings.empty())
2092 fail("DisplayID expects at least one preferred timing.\n");
2093 if (cta.image_width && dispid.image_width &&
2094 (cta.image_width != dispid.image_width ||
2095 cta.image_height != dispid.image_height))
2096 fail("Image size mismatch: CTA-861: %.1fx%.1fmm DisplayID: %.1fx%.1fmm.\n",
2097 cta.image_width / 10.0, cta.image_height / 10.0,
2098 dispid.image_width / 10.0, dispid.image_height / 10.0);
2099 if (dispid.image_width && dispid.image_width < 25600 && dispid.image_height < 25600 &&
2100 (abs((int)dispid.image_width - (int)base.max_display_width_mm * 10) >= 100 ||
2101 abs((int)dispid.image_height - (int)base.max_display_height_mm * 10) >= 100))
2102 fail("Image size mismatch: DisplayID: %.1fx%.1fmm Base EDID: %u.0x%u.0mm.\n",
2103 dispid.image_width / 10.0, dispid.image_height / 10.0,
2104 base.max_display_width_mm, base.max_display_height_mm);