1 // SPDX-License-Identifier: MIT
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>
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
};
20 static void print_flags(const char *label
, unsigned char flag_byte
,
21 const char **flags
, bool reverse
= false)
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
))) {
34 printf("%s", flags
[i
]);
36 printf("Undefined (%u)", i
);
43 void edid_state::check_displayid_datablock_revision(unsigned char hdr
,
44 unsigned char valid_flags
,
47 unsigned char revision
= hdr
& 7;
48 unsigned char flags
= hdr
& ~7 & ~valid_flags
;
51 warn("Unexpected revision (%u != %u).\n", revision
, rev
);
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
);
72 if (len
> payloaddumpstart
)
73 hex_block(" ", x
+ 3 + payloaddumpstart
, len
- payloaddumpstart
);
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);
87 if (hide_serial_numbers
)
88 printf(" Serial Number: ...\n");
90 printf(" Serial Number: %u\n", sn
);
92 unsigned week
= x
[12];
93 unsigned year
= 2000 + x
[13];
95 week
== 0xff ? "Model Year" : "Year of Manufacture", year
);
96 if (week
&& week
<= 0x36)
97 printf(", Week %u", week
);
102 memcpy(buf
, x
+ 15, x
[14]);
104 printf(" Product ID: %s\n", buf
);
110 static const char *feature_support_flags
[] = {
112 "Support ACP, ISRC1, or ISRC2packets",
113 "Fixed pixel format",
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
)
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
);
146 fail("Invalid Native Pixel Format %ux%u.\n", w
, h
);
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))
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
);
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);
188 static const char *std_colorspace_ids
[] = {
196 "Adobe Wide Gamut RGB",
200 static double fp2d(unsigned short fp
)
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;
216 printf(" Uses %s color\n", temporal_color
? "temporal" : "spatial");
217 printf(" Uses %u CIE (x, y) coordinates\n", cie_year
);
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]]);
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)));
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
= {};
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) {
261 t
.hratio
= t
.vratio
= 1;
303 fail("Unknown aspect 0x%02x.\n", x
[3] & 0xf);
306 switch ((x
[3] >> 5) & 0x3) {
308 s
+= ", no 3D stereo";
314 s
+= ", 3D stereo depends on user action";
318 fail("Reserved stereo 0x03.\n");
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;
345 if (block_rev
< 2 && (x
[3] & 0x80)) {
347 dispid
.preferred_timings
.push_back(timings_ext(t
, "DTD", s
));
350 print_timings(" ", &t
, name
.c_str(), s
.c_str(), true);
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
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");
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");
373 timings cvt_t
= calc_cvt_mode(t
.hact
, t
.vact
, refresh
, RB_CVT_V3
,
375 if (match_timings(t
, cvt_t
))
376 fail("This T7VTDB can be represented as a T10VTDB.\n");
382 void edid_state::parse_displayid_type_2_timing(const unsigned char *x
)
384 struct timings t
= {};
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));
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;
413 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
415 switch ((x
[3] >> 5) & 0x3) {
417 s
+= ", no 3D stereo";
423 s
+= ", 3D stereo depends on user action";
427 fail("Reserved stereo 0x03.\n");
432 dispid
.preferred_timings
.push_back(timings_ext(t
, "DTD", s
));
435 print_timings(" ", &t
, "DTD", s
.c_str(), true);
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) {
448 t
.hratio
= t
.vratio
= 1;
490 fail("Unknown aspect 0x%02x.\n", x
[0] & 0xf);
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
);
502 dispid
.preferred_timings
.push_back(timings_ext(t
, "CVT", s
));
505 print_timings(" ", &t
, "CVT", s
.c_str());
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
;
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;
522 print_timings(" ", t
, type_name
);
523 if (t
&& is_cta
&& !cta
.t8vtdb
.is_valid()) {
524 timings_ext
te(*t
, type_name
, "");
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))
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));
545 printf(" Supports Interlaced\n");
547 printf(" Supports CVT\n");
549 printf(" Supports CVT Reduced Blanking\n");
551 printf(" Discrete frequency display device\n");
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]));
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))
572 printf(" Display Device Technology: ");
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: ");
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;
620 printf(" The backlight may be switched on and off\n");
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);
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: ");
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");
664 printf(" Sub-pixel layout/configuration/shape: ");
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);
685 printf(" Response time for %s transition: %u ms\n",
686 (v
& 0x80) ? "white-to-black" : "black-to-white", v
& 0x7f);
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))
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);
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;
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
);
722 printf(" The first curve is the 'white' transfer characteristic\n");
724 printf(" Individual response curves\n");
727 unsigned len
= x
[2] - 1;
729 for (unsigned i
= 0; len
; i
++) {
730 if ((x
[3] & 0x80) && !i
)
731 printf(" White curve: ");
733 printf(" Response curve #%u:",
735 unsigned samples
= x
[offset
];
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);
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
++) {
756 printf(" %.2f", sum
* 100.0 / 1023.0);
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))
774 dispid
.has_display_interface_features
= true;
775 printf(" Interface Type: ");
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;
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;
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;
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;
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");
833 printf(" LVDS %s Signal Level\n", (x
[0x0c] & 0x02) ? "Low" : "High");
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");
839 printf(" PDI %s Mode\n", (x
[0x0b] & 0x04) ? "Fixed" : "DE");
841 printf(" PDI %s Signal Level\n", (x
[0x0b] & 0x02) ? "Low" : "High");
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");
851 void edid_state::parse_displayid_stereo_display_intf(const unsigned char *x
)
853 check_displayid_datablock_revision(x
[1], 0xc0, 1);
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;
866 printf(" Field Sequential Stereo (L/R Polarity: %s)\n",
867 (x
[5] & 1) ? "0/1" : "1/0");
870 printf(" Side-by-side Stereo (Left Half = %s Eye View)\n",
871 (x
[5] & 1) ? "Right" : "Left");
874 printf(" Pixel Interleaved Stereo:\n");
875 for (unsigned y
= 0; y
< 8; y
++) {
876 unsigned char v
= x
[5 + y
];
879 for (int x
= 7; x
>= 0; x
--)
880 printf("%c", (v
& (1 << x
)) ? 'L' : 'R');
885 printf(" Dual Interface, Left and Right Separate\n");
886 printf(" Carries the %s-eye view\n",
887 (x
[5] & 1) ? "Right" : "Left");
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;
897 printf(" Multi-View: %u views, Interleaving Method Code: %u\n",
901 printf(" Stacked Frame Stereo (Top Half = %s Eye View)\n",
902 (x
[5] & 1) ? "Right" : "Left");
905 printf(" Proprietary\n");
908 printf(" Reserved\n");
911 if (!(x
[1] & 0x40)) // Has No Timing Codes
915 while (1U + (x
[0] & 0x1f) <= len
) {
916 unsigned num_codes
= x
[0] & 0x1f;
917 unsigned type
= x
[0] >> 6;
920 for (unsigned i
= 1; i
<= num_codes
; i
++) {
923 sprintf(type_name
, "DMT 0x%02x", x
[i
]);
924 print_timings(" ", find_dmt_id(x
[i
]), type_name
);
927 sprintf(type_name
, "VIC %3u", x
[i
]);
928 print_timings(" ", find_vic_id(x
[i
]), type_name
);
931 sprintf(type_name
, "HDMI VIC %u", x
[i
]);
932 print_timings(" ", find_hdmi_vic_id(x
[i
]), type_name
);
937 len
-= 1 + num_codes
;
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));
952 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
953 switch ((x
[0] >> 5) & 0x3) {
955 s
+= ", no 3D stereo";
961 s
+= ", 3D stereo depends on user action";
965 fail("Reserved stereo 0x03.\n");
969 s
+= ", refresh rate * (1000/1001) supported";
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
);
981 dispid
.preferred_timings
.push_back(timings_ext(t
, "CVT", s
));
984 print_timings(" ", &t
, "CVT", s
.c_str());
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))
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;
1021 printf(" Tiled display consists of a single physical display enclosure\n");
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);
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);
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");
1046 printf(" Tiled Display Manufacturer/Vendor ID: %02X-%02X-%02X\n",
1047 x
[0x10], x
[0x11], x
[0x12]);
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);
1055 if (hide_serial_numbers
)
1056 printf(" Tiled Display Serial Number: ...\n");
1058 printf(" Tiled Display Serial Number: %u\n", sn
);
1060 fail("Tiled Display Serial Number must be non-zero.\n");
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];
1084 t
.vsync
= 1 + (x
[13] & 0x0f);
1085 t
.vbp
= vbl
- t
.vfp
- t
.vsync
;
1088 t
.interlaced
= true;
1094 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
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) {
1105 s
+= ", no 3D stereo";
1111 s
+= ", 3D stereo depends on user action";
1115 fail("Reserved stereo 0x03.\n");
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;
1133 return "do not use";
1136 return std::to_string(pow(2, exp
) * fract
/ 1024.0) + " cd/m^2";
1141 void edid_state::parse_displayid_parameters_v2(const unsigned char *x
,
1144 if (!check_displayid_datablock_length(x
, 29, 29))
1146 if (dispid
.has_display_parameters
)
1147 fail("Duplicate Display Parameters Data Block.\n");
1148 dispid
.has_display_parameters
= true;
1150 unsigned hor_size
= (x
[4] << 8) + x
[3];
1151 unsigned vert_size
= (x
[6] << 8) + x
[5];
1153 dispid
.image_width
= hor_size
;
1154 dispid
.image_height
= vert_size
;
1156 printf(" Image size: %u mm x %u mm\n", hor_size
, vert_size
);
1157 dispid
.image_width
*= 10;
1158 dispid
.image_height
*= 10;
1160 printf(" Image size: %.1f mm x %.1f mm\n",
1161 hor_size
/ 10.0, vert_size
/ 10.0);
1163 if (dispid
.image_width
> image_width
||
1164 dispid
.image_height
> image_height
) {
1165 image_width
= dispid
.image_width
;
1166 image_height
= dispid
.image_height
;
1169 unsigned w
= (x
[8] << 8) + x
[7];
1170 unsigned h
= (x
[10] << 8) + x
[9];
1172 printf(" Display native pixel format: %ux%u\n", w
, h
);
1173 set_displayid_native_res(w
, h
);
1175 unsigned char v
= x
[11];
1176 printf(" Scan Orientation: ");
1178 case 0x00: printf("Left to Right, Top to Bottom\n"); break;
1179 case 0x01: printf("Right to Left, Top to Bottom\n"); break;
1180 case 0x02: printf("Top to Bottom, Right to Left\n"); break;
1181 case 0x03: printf("Bottom to Top, Right to Left\n"); break;
1182 case 0x04: printf("Right to Left, Bottom to Top\n"); break;
1183 case 0x05: printf("Left to Right, Bottom to Top\n"); break;
1184 case 0x06: printf("Bottom to Top, Left to Right\n"); break;
1185 case 0x07: printf("Top to Bottom, Left to Right\n"); break;
1187 printf(" Luminance Information: ");
1188 switch ((v
>> 3) & 0x03) {
1189 case 0x00: printf("Minimum guaranteed value\n"); break;
1190 case 0x01: printf("Guidance for the Source device\n"); break;
1191 default: printf("Reserved\n"); break;
1193 printf(" Color Information: CIE %u\n",
1194 (v
& 0x40) ? 1976 : 1931);
1195 printf(" Audio Speaker Information: %sintegrated\n",
1196 (v
& 0x80) ? "not " : "");
1197 printf(" Native Color Chromaticity:\n");
1198 printf(" Primary #1: (%.6f, %.6f)\n",
1199 fp2d(x
[0x0c] | ((x
[0x0d] & 0x0f) << 8)),
1200 fp2d(((x
[0x0d] & 0xf0) >> 4) | (x
[0x0e] << 4)));
1201 printf(" Primary #2: (%.6f, %.6f)\n",
1202 fp2d(x
[0x0f] | ((x
[0x10] & 0x0f) << 8)),
1203 fp2d(((x
[0x10] & 0xf0) >> 4) | (x
[0x11] << 4)));
1204 printf(" Primary #3: (%.6f, %.6f)\n",
1205 fp2d(x
[0x12] | ((x
[0x13] & 0x0f) << 8)),
1206 fp2d(((x
[0x13] & 0xf0) >> 4) | (x
[0x14] << 4)));
1207 printf(" White Point: (%.6f, %.6f)\n",
1208 fp2d(x
[0x15] | ((x
[0x16] & 0x0f) << 8)),
1209 fp2d(((x
[0x16] & 0xf0) >> 4) | (x
[0x17] << 4)));
1210 printf(" Native Maximum Luminance (Full Coverage): %s\n",
1211 ieee7542d(x
[0x18] | (x
[0x19] << 8)).c_str());
1212 printf(" Native Maximum Luminance (10%% Rectangular Coverage): %s\n",
1213 ieee7542d(x
[0x1a] | (x
[0x1b] << 8)).c_str());
1214 printf(" Native Minimum Luminance: %s\n",
1215 ieee7542d(x
[0x1c] | (x
[0x1d] << 8)).c_str());
1216 printf(" Native Color Depth: ");
1217 if (!(x
[0x1e] & 0x07))
1218 printf("Not defined\n");
1219 else if (bpc444
[x
[0x1e] & 0x07])
1220 printf("%s bpc\n", bpc444
[x
[0x1e] & 0x07]);
1222 printf("Reserved\n");
1223 printf(" Display Device Technology: ");
1224 switch ((x
[0x1e] >> 4) & 0x07) {
1225 case 0x00: printf("Not Specified\n"); break;
1226 case 0x01: printf("Active Matrix LCD\n"); break;
1227 case 0x02: printf("Organic LED\n"); break;
1228 default: printf("Reserved\n"); break;
1231 printf(" Display Device Theme Preference: %s\n",
1232 (x
[0x1e] & 0x80) ? "Dark Theme Preferred" : "No Preference");
1233 if (x
[0x1f] != 0xff)
1234 printf(" Native Gamma EOTF: %.2f\n",
1235 (100 + x
[0x1f]) / 100.0);
1240 void edid_state::parse_displayid_type_9_timing(const unsigned char *x
)
1242 struct timings t
= {};
1243 std::string
s("aspect ");
1245 t
.hact
= 1 + (x
[1] | (x
[2] << 8));
1246 t
.vact
= 1 + (x
[3] | (x
[4] << 8));
1248 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
1249 switch ((x
[0] >> 5) & 0x3) {
1251 s
+= ", no 3D stereo";
1257 s
+= ", 3D stereo depends on user action";
1261 fail("Reserved stereo 0x03.\n");
1265 s
+= ", refresh rate * (1000/1001) supported";
1267 switch (x
[0] & 0x07) {
1268 case 1: t
.rb
= RB_CVT_V1
; break;
1269 case 2: t
.rb
= RB_CVT_V2
; break;
1273 edid_cvt_mode(1 + x
[5], t
);
1275 print_timings(" ", &t
, "CVT", s
.c_str());
1280 void edid_state::parse_displayid_dynamic_video_timings_range_limits(const unsigned char *x
)
1282 check_displayid_datablock_revision(x
[1], 0, (x
[1] & 7) == 1);
1284 if (!check_displayid_datablock_length(x
, 9, 9))
1287 printf(" Minimum Pixel Clock: %u kHz\n",
1288 1 + (x
[3] | (x
[4] << 8) | (x
[5] << 16)));
1289 printf(" Maximum Pixel Clock: %u kHz\n",
1290 1 + (x
[6] | (x
[7] << 8) | (x
[8] << 16)));
1291 printf(" Minimum Vertical Refresh Rate: %u Hz\n", x
[9]);
1293 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x
[10] + ((x
[11] & 3) << 8));
1295 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x
[10]);
1296 printf(" Seamless Dynamic Video Timing Support: %s\n",
1297 (x
[11] & 0x80) ? "Yes" : "No");
1302 static const char *colorspace_eotf_combinations
[] = {
1309 "BT.2020/SMPTE ST 2084"
1312 static const char *colorspace_eotf_reserved
[] = { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
1314 static const char *colorspaces
[] = {
1325 static const char *eotfs
[] = {
1339 void edid_state::parse_displayid_interface_features(const unsigned char *x
)
1341 check_displayid_datablock_revision(x
[1]);
1343 if (!check_displayid_datablock_length(x
, 9))
1346 dispid
.has_display_interface_features
= true;
1347 unsigned len
= x
[2];
1348 if (len
> 0) print_flags(" Supported bpc for RGB encoding", x
[3], bpc444
);
1349 if (len
> 1) print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x
[4], bpc444
);
1350 if (len
> 2) print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x
[5], bpc4xx
);
1351 if (len
> 3) print_flags(" Supported bpc for YCbCr 4:2:0 encoding", x
[6], bpc4xx
);
1352 if (len
> 4 && x
[7])
1353 printf(" Minimum pixel rate at which YCbCr 4:2:0 encoding is supported: %.3f MHz\n",
1355 if (len
> 5) print_flags(" Supported audio capability and features (kHz)",
1356 x
[8], audiorates
, true);
1357 if (len
> 6) print_flags(" Supported color space and EOTF standard combination 1",
1358 x
[9], colorspace_eotf_combinations
);
1359 if (len
> 7) print_flags(" Supported color space and EOTF standard combination 2",x
[10], colorspace_eotf_reserved
);
1363 if (len
> 8 && x
[11]) {
1364 printf(" Supported color space and EOTF additional combinations:");
1365 for (i
= 0; i
< x
[11]; i
++) {
1367 printf("\n Number of additional color space and EOTF combinations (%d) is greater than allowed (7).", x
[11]);
1369 } else if (i
+ 10 > len
) {
1370 printf("\n Number of additional color space and EOTF combinations (%d) is too many to fit in block (%d).", x
[11], len
- 9);
1374 const char *colorspace
= "Out of range";
1375 const char *eotf
= "Out of range";
1376 unsigned colorspace_index
= (x
[12 + i
] >> 4) & 0xf;
1377 unsigned eotf_index
= x
[12 + i
] & 0xf;
1379 if (colorspace_index
< sizeof(colorspaces
) / sizeof(colorspaces
[0]))
1380 colorspace
= colorspaces
[colorspace_index
];
1381 if (eotf_index
< sizeof(eotfs
) / sizeof(eotfs
[0]))
1382 eotf
= eotfs
[eotf_index
];
1386 if (!strcmp(colorspace
, eotf
))
1387 printf("%s", colorspace
);
1389 printf("%s/%s", colorspace
, eotf
);
1393 check_displayid_datablock_length(x
, 9 + i
, 9 + i
, 9 + i
);
1398 void edid_state::parse_displayid_ContainerID(const unsigned char *x
)
1400 check_displayid_datablock_revision(x
[1]);
1402 if (check_displayid_datablock_length(x
, 16, 16)) {
1404 printf(" Container ID: %s\n", containerid2s(x
).c_str());
1410 void edid_state::parse_displayid_adaptive_sync(const unsigned char *x
)
1412 check_displayid_datablock_revision(x
[1], 0x70);
1414 unsigned size
= 6 + ((x
[1] >> 4) & 0x7);
1415 unsigned len
= x
[2];
1416 unsigned descriptor
= 1;
1420 fail("DisplayID payload length %u is not a multiple of %u.\n", len
, size
);
1421 while (len
>= size
) {
1422 printf(" Descriptor #%u:\n", descriptor
++);
1424 printf(" %sNative Panel Range\n", (x
[0] & 1) ? "" : "Non-");
1425 unsigned v
= (x
[0] >> 2) & 3;
1427 case 0: printf(" Fixed Average V-Total\n"); break;
1428 case 1: printf(" Fixed Average V-Total and Adaptive V-Total\n"); break;
1430 printf(" Reserved %u\n", v
);
1431 fail("Use of reserved value %u.\n", v
);
1435 printf(" Supports Seamless Transition\n");
1437 printf(" 'Max Single Frame Duration Increase' field value without jitter impact\n");
1439 printf(" 'Max Single Frame Duration Decrease' field value without jitter impact\n");
1440 printf(" Max Duration Increase: %.2f ms\n", x
[1] / 4.0);
1441 printf(" Max Duration Decrease: %.2f ms\n", x
[5] / 4.0);
1442 printf(" Min Refresh Rate: %u Hz\n", x
[2]);
1443 printf(" Max Refresh Rate: %u Hz\n", 1 + x
[3] + (x
[4] & 3) * 256);
1452 void edid_state::parse_displayid_type_10_timing(const unsigned char *x
,
1453 unsigned sz
, bool is_cta
)
1455 struct timings t
= {};
1456 std::string name
= is_cta
? std::string("VTDB ") + std::to_string(cta
.vec_vtdbs
.size() + 1) : "CVT";
1457 std::string
s("aspect ");
1459 t
.hact
= 1 + (x
[1] | (x
[2] << 8));
1460 t
.vact
= 1 + (x
[3] | (x
[4] << 8));
1462 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
1464 switch ((x
[0] >> 5) & 0x3) {
1466 s
+= ", no 3D stereo";
1472 s
+= ", 3D stereo depends on user action";
1476 fail("Reserved stereo 0x03.\n");
1480 switch (x
[0] & 0x07) {
1481 case 1: t
.rb
= RB_CVT_V1
; break;
1482 case 2: t
.rb
= RB_CVT_V2
; break;
1483 case 3: t
.rb
= RB_CVT_V3
; break;
1488 unsigned rb_h_blank
= rb
== RB_CVT_V3
? 80 : 0;
1489 unsigned rb_v_blank
= 460;
1490 bool early_vsync_rqd
= false;
1493 if (rb
== RB_CVT_V2
) {
1494 s
+= ", refresh rate * (1000/1001) supported";
1496 } else if (rb
== RB_CVT_V3
) {
1497 s
+= ", hblank is 160 pixels";
1501 fail("VR_HB must be 0.\n");
1505 s
+= ", YCbCr 4:2:0";
1508 if (rb
== RB_CVT_V3
) {
1509 early_vsync_rqd
= true;
1510 s
+= ", early-vsync";
1512 fail("EVS must be 0.\n");
1516 unsigned refresh
= 1 + x
[5] + (sz
== 6 ? 0 : ((x
[6] & 3) << 8));
1519 if (rb
== RB_CVT_V3
) {
1520 unsigned delta_hblank
= (x
[6] >> 2) & 7;
1522 if (rb_h_blank
== 80)
1523 rb_h_blank
= 80 + 8 * delta_hblank
;
1524 else if (delta_hblank
<= 5)
1525 rb_h_blank
= 160 + 8 * delta_hblank
;
1527 rb_h_blank
= 160 - (delta_hblank
- 5) * 8;
1529 s
+= ", delta-hblank=" + std::to_string(delta_hblank
);
1531 rb_v_blank
+= ((x
[6] >> 5) & 7) * 35;
1532 if (rb_v_blank
> 460)
1533 s
+= ", add-vblank=" + std::to_string(rb_v_blank
- 460);
1536 fail("Additional_Vertical_Blank_Time must be 0.\n");
1538 fail("Delta_Horizontal_Blank must be 0.\n");
1542 edid_cvt_mode(refresh
, t
, rb_h_blank
, rb_v_blank
, early_vsync_rqd
);
1544 print_timings(" ", &t
, name
.c_str(), s
.c_str());
1546 timings_ext
te(t
, name
.c_str(), s
);
1547 cta
.vec_vtdbs
.push_back(te
);
1551 // tag 0x7e, OUI 3A-02-92 (VESA)
1553 void edid_state::parse_displayid_vesa(const unsigned char *x
)
1555 check_displayid_datablock_revision(x
[1]);
1557 if (!check_displayid_datablock_length(x
, 5, 7))
1560 unsigned len
= x
[2];
1562 printf(" Data Structure Type: ");
1564 case 0: printf("eDP\n"); break;
1565 case 1: printf("DP\n"); break;
1566 default: printf("Reserved (%d)\n", x
[0] & 7); break;
1569 if ((x
[0] >> 3) & 15)
1570 warn("Reserved bits 6:3 (%d) are not 0.\n", (x
[0] >> 3) & 15);
1572 printf(" Default Colorspace and EOTF Handling: %s\n",
1573 (x
[0] & 0x80) ? "Native as specified in the Display Parameters DB" : "sRGB");
1575 printf(" Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel: %u\n",
1577 if ((x
[1] & 0xf) > 8)
1578 warn("Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel exceeds 8.\n");
1580 if ((x
[1] >> 4) & 1)
1581 warn("Reserved bit 4 is not 0.\n");
1583 printf(" Multi-SST Operation: ");
1584 switch ((x
[1] >> 5) & 3) {
1585 case 0: printf("Not Supported\n"); break;
1586 case 1: printf("Two Streams (number of links shall be 2 or 4)\n"); break;
1587 case 2: printf("Four Streams (number of links shall be 4)\n"); break;
1588 case 3: printf("Reserved\n"); warn("Invalid option for Multi-SST Operation.\n"); break;
1591 if ((x
[1] >> 7) & 1)
1592 warn("Reserved bit 7 is not 0.\n");
1595 double bpp
= (x
[2] & 0x3f) + (x
[3] & 0x0f) / 16.0;
1596 printf(" Pass through timing's target DSC bits per pixel: %.4f\n", bpp
);
1600 // tag 0x7f, OUI 00-10-FA (Apple)
1602 void edid_state::parse_displayid_apple(const unsigned char *x
)
1604 int length
= x
[2] - 3;
1608 // Based on the very limited information I found here:
1609 // https://opensource.apple.com/source/IOKitUser/IOKitUser-1445.40.1/graphics.subproj/IODisplayLib.c
1612 printf(" Type: BLC Info/Corrections, Version: %u\n", x
[1]);
1615 printf(" Type: %u, Version: %u\n", x
[0], x
[1]);
1618 hex_block(" ", x
+ 2, length
- 2);
1623 void edid_state::parse_displayid_cta_data_block(const unsigned char *x
)
1625 check_displayid_datablock_revision(x
[1]);
1627 unsigned len
= x
[2];
1631 fail("Length is > 248.\n");
1636 for (i
= 0; i
< len
; i
+= (x
[i
] & 0x1f) + 1) {
1637 cta_block(x
+ i
, dispid
.found_tags
);
1641 fail("Length is %u instead of %u.\n", len
, i
);
1646 std::string
edid_state::product_type(unsigned char x
, bool heading
)
1648 std::string headingstr
;
1650 if (dispid
.version
< 0x20) {
1651 headingstr
= "Display Product Type";
1652 if (heading
) return headingstr
;
1653 dispid
.is_display
= x
== 2 || x
== 3 || x
== 4 || x
== 6;
1655 case 0: return "Extension Section";
1656 case 1: return "Test Structure; test equipment only";
1657 case 2: return "Display panel or other transducer, LCD or PDP module, etc.";
1658 case 3: return "Standalone display device";
1659 case 4: return "Television receiver";
1660 case 5: return "Repeater/translator";
1661 case 6: return "DIRECT DRIVE monitor";
1665 headingstr
= "Display Product Primary Use Case";
1666 if (heading
) return headingstr
;
1667 dispid
.is_display
= x
>= 2 && x
<= 8;
1669 case 0: return "Same primary use case as the base section";
1670 case 1: return "Test Structure; test equipment only";
1671 case 2: return "None of the listed primary use cases; generic display";
1672 case 3: return "Television (TV) display";
1673 case 4: return "Desktop productivity display";
1674 case 5: return "Desktop gaming display";
1675 case 6: return "Presentation display";
1676 case 7: return "Head-mounted Virtual Reality (VR) display";
1677 case 8: return "Head-mounted Augmented Reality (AR) display";
1681 fail("Unknown %s 0x%02x.\n", headingstr
.c_str(), x
);
1682 return std::string("Unknown " + headingstr
+ " (") + utohex(x
) + ")";
1685 void edid_state::preparse_displayid_block(unsigned char *x
)
1687 bool update_checksum
= false;
1688 unsigned length
= x
[2];
1689 unsigned offset
= 5;
1694 dispid
.preparsed_displayid_blocks
++;
1695 while (length
> 0) {
1696 unsigned tag
= x
[offset
];
1697 unsigned len
= x
[offset
+ 2];
1702 if (replace_unique_ids
&&
1703 (x
[offset
+ 0x08] || x
[offset
+ 0x09] ||
1704 x
[offset
+ 0x0a] || x
[offset
+ 0x0b])) {
1705 // Replace by 123456
1706 x
[offset
+ 0x08] = 0x40;
1707 x
[offset
+ 0x09] = 0xe2;
1708 x
[offset
+ 0x0a] = 0x01;
1709 x
[offset
+ 0x0b] = 0x00;
1710 update_checksum
= true;
1715 if (replace_unique_ids
&&
1716 (x
[offset
+ 0x15] || x
[offset
+ 0x16] ||
1717 x
[offset
+ 0x17] || x
[offset
+ 0x18])) {
1718 // Replace by 123456
1719 x
[offset
+ 0x15] = 0x40;
1720 x
[offset
+ 0x16] = 0xe2;
1721 x
[offset
+ 0x17] = 0x01;
1722 x
[offset
+ 0x18] = 0x00;
1723 update_checksum
= true;
1727 if (replace_unique_ids
) {
1728 update_checksum
= true;
1729 memset(x
+ offset
+ 3, 0, 16);
1733 dispid
.preparsed_color_ids
|= 1 << ((x
[offset
+ 1] >> 3) & 0x0f);
1736 dispid
.preparsed_xfer_ids
|= 1 << ((x
[offset
+ 1] >> 4) & 0x0f);
1745 if (length
< len
+ 3)
1754 if (update_checksum
) {
1755 replace_checksum(x
+ 1, x
[2] + 5);
1756 replace_checksum(x
, EDID_PAGE_SIZE
);
1760 unsigned edid_state::displayid_block(const unsigned version
, const unsigned char *x
, unsigned length
)
1763 unsigned tag
= x
[0];
1764 unsigned tag_version
= (tag
< 0x20) ? 1 : (tag
< 0x7f) ? 2 : (tag
< 0x80) ? 1 : 0;
1765 bool dooutputname
= true;
1766 unsigned len
= (length
< 3) ? 0 : x
[2];
1767 bool hasoui
= false;
1773 data_block_oui("Product Identification Data Block (" + utohex(tag
) + ")",
1774 x
+ 3, len
, &ouinum
, true, true, true);
1775 dooutputname
= false;
1778 case 0x01: data_block
= "Display Parameters Data Block (" + utohex(tag
) + ")"; break;
1779 case 0x02: data_block
= "Color Characteristics Data Block"; break;
1780 case 0x03: data_block
= "Video Timing Modes Type 1 - Detailed Timings Data Block"; break;
1781 case 0x04: data_block
= "Video Timing Modes Type 2 - Detailed Timings Data Block"; break;
1782 case 0x05: data_block
= "Video Timing Modes Type 3 - Short Timings Data Block"; break;
1783 case 0x06: data_block
= "Video Timing Modes Type 4 - DMT Timings Data Block"; break;
1784 case 0x07: data_block
= "Supported Timing Modes Type 1 - VESA DMT Timings Data Block"; break;
1785 case 0x08: data_block
= "Supported Timing Modes Type 2 - CTA-861 Timings Data Block"; break;
1786 case 0x09: data_block
= "Video Timing Range Data Block"; break;
1787 case 0x0a: data_block
= "Product Serial Number Data Block"; break;
1788 case 0x0b: data_block
= "GP ASCII String Data Block"; break;
1789 case 0x0c: data_block
= "Display Device Data Data Block"; break;
1790 case 0x0d: data_block
= "Interface Power Sequencing Data Block"; break;
1791 case 0x0e: data_block
= "Transfer Characteristics Data Block"; break;
1792 case 0x0f: data_block
= "Display Interface Data Block"; break;
1793 case 0x10: data_block
= "Stereo Display Interface Data Block (" + utohex(tag
) + ")"; break;
1794 case 0x11: data_block
= "Video Timing Modes Type 5 - Short Timings Data Block"; break;
1795 case 0x12: data_block
= "Tiled Display Topology Data Block (" + utohex(tag
) + ")"; break;
1796 case 0x13: data_block
= "Video Timing Modes Type 6 - Detailed Timings Data Block"; break;
1797 // 0x14 .. 0x7e RESERVED for Additional VESA-defined Data Blocks
1800 data_block_oui("Product Identification Data Block (" + utohex(tag
) + ")",
1801 x
+ 3, len
, &ouinum
, false, false, true);
1802 dooutputname
= false;
1805 case 0x21: data_block
= "Display Parameters Data Block (" + utohex(tag
) + ")"; break;
1806 case 0x22: data_block
= "Video Timing Modes Type 7 - Detailed Timings Data Block"; break;
1807 case 0x23: data_block
= "Video Timing Modes Type 8 - Enumerated Timing Codes Data Block"; break;
1808 case 0x24: data_block
= "Video Timing Modes Type 9 - Formula-based Timings Data Block"; break;
1809 case 0x25: data_block
= "Dynamic Video Timing Range Limits Data Block"; break;
1810 case 0x26: data_block
= "Display Interface Features Data Block"; break;
1811 case 0x27: data_block
= "Stereo Display Interface Data Block (" + utohex(tag
) + ")"; break;
1812 case 0x28: data_block
= "Tiled Display Topology Data Block (" + utohex(tag
) + ")"; break;
1813 case 0x29: data_block
= "ContainerID Data Block"; break;
1814 case 0x2b: data_block
= "Adaptive Sync Data Block"; break;
1815 case 0x32: data_block
= "Video Timing Modes Type 10 - Formula-based Timings Data Block"; break;
1816 // 0x2a .. 0x7d RESERVED for Additional VESA-defined Data Blocks
1817 case 0x7e: // DisplayID 2.0
1818 data_block_oui("Vendor-Specific Data Block (" + utohex(tag
) + ")",
1819 x
+ 3, len
, &ouinum
, false, false, true);
1820 dooutputname
= false;
1824 case 0x7f: // DisplayID 1.3
1825 data_block_oui("Vendor-Specific Data Block (" + utohex(tag
) + ")",
1826 x
+ 3, len
, &ouinum
, false, true, true);
1827 dooutputname
= false;
1832 case 0x81: data_block
= "CTA-861 DisplayID Data Block"; break;
1833 // 0x82 .. 0xff RESERVED
1834 default: data_block
= "Unknown DisplayID Data Block (" + utohex(tag
) + ", length " + std::to_string(len
) + ")"; break;
1838 // Report a problem when the remaining bytes are not 0.
1839 data_block
.clear(); // Probably not a Data Block so clear this.
1840 if (tag
|| (length
> 1 && x
[1])) {
1841 printf(" Filler:\n");
1842 fail("Not enough bytes remain (%d) for a DisplayID data block and the DisplayID filler is non-0.\n", length
);
1843 hex_block(" ", x
, length
);
1848 if (length
< len
+ 3) {
1849 data_block
.clear(); // Probably not a Data Block so clear this.
1850 printf(" Filler:\n");
1851 fail("The length of this DisplayID data block (%d) exceeds the number of bytes remaining (%d).\n", len
+ 3, length
);
1852 hex_block(" ", x
, length
);
1857 // A Product Identification Data Block with no payload bytes is not valid - assume this is the end.
1858 data_block
.clear(); // Probably not a Product Identification Data Block so clear this.
1859 if (!memchk(x
, length
)) {
1860 printf(" Filler:\n");
1861 fail("Non-0 filler bytes in the DisplayID block.\n");
1862 hex_block(" ", x
, length
);
1867 if (dooutputname
&& data_block
.length())
1868 printf(" %s:\n", data_block
.c_str());
1870 if (version
>= 0x20 && tag_version
== 1)
1871 fail("Use of DisplayID v1.x tag for DisplayID v%u.%u.\n",
1872 version
>> 4, version
& 0xf);
1873 if (version
< 0x20 && tag_version
== 2)
1874 fail("Use of DisplayID v2.0 tag for DisplayID v%u.%u.\n",
1875 version
>> 4, version
& 0xf);
1877 unsigned block_rev
= x
[1] & 0x07;
1880 case 0x00: parse_displayid_product_id(x
); break;
1881 case 0x01: parse_displayid_parameters(x
); break;
1882 case 0x02: parse_displayid_color_characteristics(x
); break;
1884 check_displayid_datablock_revision(x
[1], 0, block_rev
& 1);
1885 for (i
= 0; i
< len
/ 20; i
++)
1886 parse_displayid_type_1_7_timing(&x
[3 + (i
* 20)], false, block_rev
);
1889 check_displayid_datablock_revision(x
[1]);
1890 for (i
= 0; i
< len
/ 11; i
++)
1891 parse_displayid_type_2_timing(&x
[3 + (i
* 11)]);
1894 check_displayid_datablock_revision(x
[1], 0, block_rev
& 1);
1895 for (i
= 0; i
< len
/ 3; i
++)
1896 parse_displayid_type_3_timing(&x
[3 + (i
* 3)]);
1899 check_displayid_datablock_revision(x
[1], 0xc0, 1);
1900 for (i
= 0; i
< len
; i
++)
1901 parse_displayid_type_4_8_timing((x
[1] & 0xc0) >> 6, x
[3 + i
]);
1904 check_displayid_datablock_revision(x
[1]);
1905 for (i
= 0; i
< min(len
, 10) * 8; i
++)
1906 if (x
[3 + i
/ 8] & (1 << (i
% 8))) {
1908 sprintf(type
, "DMT 0x%02x", i
+ 1);
1909 print_timings(" ", find_dmt_id(i
+ 1), type
);
1913 check_displayid_datablock_revision(x
[1]);
1914 for (i
= 0; i
< min(len
, 8) * 8; i
++)
1915 if (x
[3 + i
/ 8] & (1 << (i
% 8))) {
1917 sprintf(type
, "VIC %3u", i
+ 1);
1918 print_timings(" ", find_vic_id(i
+ 1), type
);
1921 case 0x09: parse_displayid_video_timing_range_limits(x
); break;
1923 case 0x0b: parse_displayid_string(x
); break;
1924 case 0x0c: parse_displayid_display_device(x
); break;
1925 case 0x0d: parse_displayid_intf_power_sequencing(x
); break;
1926 case 0x0e: parse_displayid_transfer_characteristics(x
); break;
1927 case 0x0f: parse_displayid_display_intf(x
); break;
1928 case 0x10: parse_displayid_stereo_display_intf(x
); break;
1930 check_displayid_datablock_revision(x
[1]);
1931 for (i
= 0; i
< len
/ 7; i
++)
1932 parse_displayid_type_5_timing(&x
[3 + (i
* 7)]);
1934 case 0x12: parse_displayid_tiled_display_topology(x
, false); break;
1936 check_displayid_datablock_revision(x
[1]);
1937 for (i
= 0; i
< len
; i
+= (x
[3 + i
+ 2] & 0x40) ? 17 : 14)
1938 parse_displayid_type_6_timing(&x
[3 + i
]);
1940 case 0x20: parse_displayid_product_id(x
); break;
1943 check_displayid_datablock_revision(x
[1], 0x80, 1);
1945 check_displayid_datablock_revision(x
[1], 0x80, 0);
1946 parse_displayid_parameters_v2(x
, block_rev
);
1952 check_displayid_datablock_revision(x
[1], 0x08, 2);
1953 else if (block_rev
== 1)
1954 check_displayid_datablock_revision(x
[1], 0x08, 1);
1956 check_displayid_datablock_revision(x
[1]);
1957 sz
+= (x
[1] & 0x70) >> 4;
1958 if (block_rev
>= 1 && (x
[1] & 0x08))
1959 printf(" These timings support DSC pass-through\n");
1960 for (i
= 0; i
< len
/ sz
; i
++)
1961 parse_displayid_type_1_7_timing(&x
[3 + i
* sz
], true, block_rev
);
1966 check_displayid_datablock_revision(x
[1], 0xe8, 1);
1968 check_displayid_datablock_revision(x
[1], 0xc8);
1970 for (i
= 0; i
< len
/ 2; i
++)
1971 parse_displayid_type_4_8_timing((x
[1] & 0xc0) >> 6,
1973 (x
[4 + i
* 2] << 8));
1975 for (i
= 0; i
< len
; i
++)
1976 parse_displayid_type_4_8_timing((x
[1] & 0xc0) >> 6,
1981 check_displayid_datablock_revision(x
[1]);
1982 for (i
= 0; i
< len
/ 6; i
++)
1983 parse_displayid_type_9_timing(&x
[3 + i
* 6]);
1985 case 0x25: parse_displayid_dynamic_video_timings_range_limits(x
); break;
1986 case 0x26: parse_displayid_interface_features(x
); break;
1987 case 0x27: parse_displayid_stereo_display_intf(x
); break;
1988 case 0x28: parse_displayid_tiled_display_topology(x
, true); break;
1989 case 0x29: parse_displayid_ContainerID(x
); break;
1990 case 0x2b: parse_displayid_adaptive_sync(x
); break;
1992 unsigned sz
= 6 + ((x
[1] & 0x70) >> 4);
1994 check_displayid_datablock_revision(x
[1], 0x70);
1995 for (i
= 0; i
< len
/ sz
; i
++)
1996 parse_displayid_type_10_timing(&x
[3 + i
* sz
], sz
);
1999 case 0x7e|kOUI_VESA
: parse_displayid_vesa(x
); break;
2000 case 0x7f|kOUI_Apple
: parse_displayid_apple(x
); break;
2001 case 0x81: parse_displayid_cta_data_block(x
); break;
2002 default: hex_block(" ", x
+ 3 + (hasoui
? 3 : 0), (len
> (hasoui
? 3 : 0)) ? len
- (hasoui
? 3 : 0) : 0); break;
2005 if ((tag
== 0x00 || tag
== 0x20) &&
2006 (!dispid
.is_base_block
|| dispid
.block_number
> 0))
2007 fail("%s is required to be the first DisplayID Data Block.\n",
2008 data_block
.c_str());
2010 dispid
.block_number
++;
2014 void edid_state::parse_displayid_block(const unsigned char *x
)
2016 unsigned version
= x
[1];
2017 unsigned length
= x
[2];
2018 unsigned prod_type
= x
[3]; // future check: based on type, check for required data blocks
2019 unsigned ext_count
= x
[4];
2021 printf(" Version: %u.%u\n Extension Count: %u\n",
2022 version
>> 4, version
& 0xf, ext_count
);
2024 if (dispid
.is_base_block
) {
2025 dispid
.version
= version
;
2026 printf(" %s: %s\n", product_type(prod_type
, true).c_str(),
2027 product_type(prod_type
, false).c_str());
2029 fail("DisplayID Base Block has no product type.\n");
2030 if (ext_count
!= dispid
.preparsed_displayid_blocks
- 1)
2031 fail("Expected %u DisplayID Extension Block%s, but got %u.\n",
2033 ext_count
> 1 ? "s" : "",
2034 dispid
.preparsed_displayid_blocks
- 1);
2037 fail("Product Type should be 0 in extension block.\n");
2039 fail("Extension Count should be 0 in extension block.\n");
2040 if (version
!= dispid
.version
)
2041 fail("Got version %u.%u, expected %u.%u.\n",
2042 version
>> 4, version
& 0xf,
2043 dispid
.version
>> 4, dispid
.version
& 0xf);
2047 fail("DisplayID length %d is greater than 121.\n", length
);
2052 for (const unsigned char *y
= x
+ 5; length
> 0; y
+= len
) {
2053 len
= displayid_block(version
, y
, length
);
2058 * DisplayID length field is number of following bytes
2059 * but checksum is calculated over the entire structure
2060 * (excluding DisplayID-in-EDID magic byte)
2063 do_checksum(" ", x
+ 1, x
[2] + 5);
2065 unused_bytes
= 0x7f - (1 + x
[2] + 5);
2066 if (!memchk(x
+ 1 + x
[2] + 5, unused_bytes
)) {
2067 data_block
= "Padding";
2068 fail("Contains non-zero bytes.\n");
2070 dispid
.is_base_block
= false;
2073 void edid_state::check_displayid_blocks()
2075 data_block
= "DisplayID";
2076 if (!dispid
.has_product_identification
)
2077 fail("Missing DisplayID Product Identification Data Block.\n");
2078 if (dispid
.is_display
&& !dispid
.has_display_parameters
)
2079 fail("Missing DisplayID Display Parameters Data Block.\n");
2080 if (dispid
.is_display
&& !dispid
.has_display_interface_features
)
2081 fail("Missing DisplayID Display Interface Features Data Block.\n");
2082 if (dispid
.is_display
&& !dispid
.has_type_1_7
)
2083 fail("Missing DisplayID Type %s Detailed Timing Data Block.\n",
2084 dispid
.version
>= 0x20 ? "VII" : "I");
2085 if (dispid
.preferred_timings
.empty())
2086 fail("DisplayID expects at least one preferred timing.\n");
2087 if (cta
.image_width
&& dispid
.image_width
&&
2088 (cta
.image_width
!= dispid
.image_width
||
2089 cta
.image_height
!= dispid
.image_height
))
2090 fail("Image size mismatch: CTA-861: %.1fx%.1fmm DisplayID: %.1fx%.1fmm.\n",
2091 cta
.image_width
/ 10.0, cta
.image_height
/ 10.0,
2092 dispid
.image_width
/ 10.0, dispid
.image_height
/ 10.0);
2093 if (dispid
.image_width
&& dispid
.image_width
< 25600 && dispid
.image_height
< 25600 &&
2094 (abs((int)dispid
.image_width
- (int)base
.max_display_width_mm
* 10) >= 100 ||
2095 abs((int)dispid
.image_height
- (int)base
.max_display_height_mm
* 10) >= 100))
2096 fail("Image size mismatch: DisplayID: %.1fx%.1fmm Base EDID: %u.0x%u.0mm.\n",
2097 dispid
.image_width
/ 10.0, dispid
.image_height
/ 10.0,
2098 base
.max_display_width_mm
, base
.max_display_height_mm
);