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 check_displayid_datablock_revision(x
[1], 0, (x
[1] & 7) == 1);
1145 if (!check_displayid_datablock_length(x
, 29, 29))
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
;
1157 printf(" Image size: %u mm x %u mm\n", hor_size
, vert_size
);
1158 dispid
.image_width
*= 10;
1159 dispid
.image_height
*= 10;
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: ");
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]);
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;
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);
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));
1249 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
1250 switch ((x
[0] >> 5) & 0x3) {
1252 s
+= ", no 3D stereo";
1258 s
+= ", 3D stereo depends on user action";
1262 fail("Reserved stereo 0x03.\n");
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;
1274 edid_cvt_mode(1 + x
[5], t
);
1276 print_timings(" ", &t
, "CVT", s
.c_str());
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))
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]);
1294 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x
[10] + ((x
[11] & 3) << 8));
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");
1303 static const char *colorspace_eotf_combinations
[] = {
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
[] = {
1326 static const char *eotfs
[] = {
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))
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",
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
);
1364 if (len
> 8 && x
[11]) {
1365 printf(" Supported color space and EOTF additional combinations:");
1366 for (i
= 0; i
< x
[11]; i
++) {
1368 printf("\n Number of additional color space and EOTF combinations (%d) is greater than allowed (7).", x
[11]);
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);
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
];
1387 if (!strcmp(colorspace
, eotf
))
1388 printf("%s", colorspace
);
1390 printf("%s/%s", colorspace
, eotf
);
1394 check_displayid_datablock_length(x
, 9 + i
, 9 + i
, 9 + i
);
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)) {
1405 printf(" Container ID: %s\n", containerid2s(x
).c_str());
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;
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;
1428 case 0: printf(" Fixed Average V-Total\n"); break;
1429 case 1: printf(" Fixed Average V-Total and Adaptive V-Total\n"); break;
1431 printf(" Reserved %u\n", v
);
1432 fail("Use of reserved value %u.\n", v
);
1436 printf(" Supports Seamless Transition\n");
1438 printf(" 'Max Single Frame Duration Increase' field value without jitter impact\n");
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);
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));
1463 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
1465 switch ((x
[0] >> 5) & 0x3) {
1467 s
+= ", no 3D stereo";
1473 s
+= ", 3D stereo depends on user action";
1477 fail("Reserved stereo 0x03.\n");
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;
1489 unsigned rb_h_blank
= rb
== RB_CVT_V3
? 80 : 0;
1490 unsigned rb_v_blank
= 460;
1491 bool early_vsync_rqd
= false;
1494 if (rb
== RB_CVT_V2
) {
1495 s
+= ", refresh rate * (1000/1001) supported";
1497 } else if (rb
== RB_CVT_V3
) {
1498 s
+= ", hblank is 160 pixels";
1502 fail("VR_HB must be 0.\n");
1506 s
+= ", YCbCr 4:2:0";
1509 if (rb
== RB_CVT_V3
) {
1510 early_vsync_rqd
= true;
1511 s
+= ", early-vsync";
1513 fail("EVS must be 0.\n");
1517 unsigned refresh
= 1 + x
[5] + (sz
== 6 ? 0 : ((x
[6] & 3) << 8));
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
;
1528 rb_h_blank
= 160 - (delta_hblank
- 5) * 8;
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);
1537 fail("Additional_Vertical_Blank_Time must be 0.\n");
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());
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))
1561 unsigned len
= x
[2];
1563 printf(" Data Structure Type: ");
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",
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");
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;
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
1613 printf(" Type: BLC Info/Corrections, Version: %u\n", x
[1]);
1616 printf(" Type: %u, Version: %u\n", x
[0], x
[1]);
1619 hex_block(" ", x
+ 2, length
- 2);
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];
1632 fail("Length is > 248.\n");
1637 for (i
= 0; i
< len
; i
+= (x
[i
] & 0x1f) + 1) {
1638 cta_block(x
+ i
, dispid
.found_tags
);
1642 fail("Length is %u instead of %u.\n", len
, i
);
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;
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";
1666 headingstr
= "Display Product Primary Use Case";
1667 if (heading
) return headingstr
;
1668 dispid
.is_display
= x
>= 2 && x
<= 8;
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";
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;
1695 dispid
.preparsed_displayid_blocks
++;
1696 while (length
> 0) {
1697 unsigned tag
= x
[offset
];
1698 unsigned len
= x
[offset
+ 2];
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;
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;
1733 if (replace_unique_ids
) {
1734 update_checksum
= true;
1735 memset(x
+ offset
+ 3, 0, 16);
1739 dispid
.preparsed_color_ids
|= 1 << ((x
[offset
+ 1] >> 3) & 0x0f);
1742 dispid
.preparsed_xfer_ids
|= 1 << ((x
[offset
+ 1] >> 4) & 0x0f);
1751 if (length
< 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
)
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;
1779 data_block_oui("Product Identification Data Block (" + utohex(tag
) + ")",
1780 x
+ 3, len
, &ouinum
, true, true, true);
1781 dooutputname
= false;
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
1806 data_block_oui("Product Identification Data Block (" + utohex(tag
) + ")",
1807 x
+ 3, len
, &ouinum
, false, false, true);
1808 dooutputname
= false;
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;
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;
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;
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
);
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
);
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
);
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;
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;
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
);
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)]);
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)]);
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
]);
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))) {
1914 sprintf(type
, "DMT 0x%02x", i
+ 1);
1915 print_timings(" ", find_dmt_id(i
+ 1), type
);
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))) {
1923 sprintf(type
, "VIC %3u", i
+ 1);
1924 print_timings(" ", find_vic_id(i
+ 1), type
);
1927 case 0x09: parse_displayid_video_timing_range_limits(x
); break;
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;
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)]);
1940 case 0x12: parse_displayid_tiled_display_topology(x
, false); break;
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
]);
1946 case 0x20: parse_displayid_product_id(x
); break;
1949 check_displayid_datablock_revision(x
[1], 0x80, 1);
1951 check_displayid_datablock_revision(x
[1], 0x80, 0);
1952 parse_displayid_parameters_v2(x
, block_rev
);
1958 check_displayid_datablock_revision(x
[1], 0x08, 2);
1959 else if (block_rev
== 1)
1960 check_displayid_datablock_revision(x
[1], 0x08, 1);
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
);
1972 check_displayid_datablock_revision(x
[1], 0xe8, 1);
1974 check_displayid_datablock_revision(x
[1], 0xc8);
1976 for (i
= 0; i
< len
/ 2; i
++)
1977 parse_displayid_type_4_8_timing((x
[1] & 0xc0) >> 6,
1979 (x
[4 + i
* 2] << 8));
1981 for (i
= 0; i
< len
; i
++)
1982 parse_displayid_type_4_8_timing((x
[1] & 0xc0) >> 6,
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]);
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;
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
);
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
++;
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());
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",
2039 ext_count
> 1 ? "s" : "",
2040 dispid
.preparsed_displayid_blocks
- 1);
2043 fail("Product Type should be 0 in extension block.\n");
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);
2053 fail("DisplayID length %d is greater than 121.\n", length
);
2058 for (const unsigned char *y
= x
+ 5; length
> 0; y
+= len
) {
2059 len
= displayid_block(version
, y
, length
);
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)
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
);