2 * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
3 * Copyright 2007 Red Hat, Inc.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
24 * interpret_edid.c: interpret a primary EDID block
27 #ifdef HAVE_XORG_CONFIG_H
28 #include <xorg-config.h>
33 #include "xf86_OSproc.h"
38 static void get_vendor_section(Uchar
*, struct vendor
*);
39 static void get_version_section(Uchar
*, struct edid_version
*);
40 static void get_display_section(Uchar
*, struct disp_features
*,
41 struct edid_version
*);
42 static void get_established_timing_section(Uchar
*,
43 struct established_timings
*);
44 static void get_std_timing_section(Uchar
*, struct std_timings
*,
45 struct edid_version
*);
46 static void fetch_detailed_block(Uchar
* c
, struct edid_version
*ver
,
47 struct detailed_monitor_section
*det_mon
);
48 static void get_dt_md_section(Uchar
*, struct edid_version
*,
49 struct detailed_monitor_section
*det_mon
);
50 static void copy_string(Uchar
*, Uchar
*);
51 static void get_dst_timing_section(Uchar
*, struct std_timings
*,
52 struct edid_version
*);
53 static void get_monitor_ranges(Uchar
*, struct monitor_ranges
*);
54 static void get_whitepoint_section(Uchar
*, struct whitePoints
*);
55 static void get_detailed_timing_section(Uchar
*, struct detailed_timings
*);
56 static Bool
validate_version(int scrnIndex
, struct edid_version
*);
59 find_ranges_section(struct detailed_monitor_section
*det
, void *ranges
)
61 if (det
->type
== DS_RANGES
&& det
->section
.ranges
.max_clock
)
62 *(struct monitor_ranges
**) ranges
= &det
->section
.ranges
;
66 find_max_detailed_clock(struct detailed_monitor_section
*det
, void *ret
)
68 if (det
->type
== DT
) {
69 *(int *) ret
= max(*((int *) ret
), det
->section
.d_timings
.clock
);
74 handle_edid_quirks(xf86MonPtr m
)
76 struct monitor_ranges
*ranges
= NULL
;
79 * max_clock is only encoded in EDID in tens of MHz, so occasionally we
80 * find a monitor claiming a max of 160 with a mode requiring 162, or
81 * similar. Strictly we should refuse to round up too far, but let's
82 * see how well this works.
85 /* Try to find Monitor Range and max clock, then re-set range value */
86 xf86ForEachDetailedBlock(m
, find_ranges_section
, &ranges
);
87 if (ranges
&& ranges
->max_clock
) {
90 xf86ForEachDetailedBlock(m
, find_max_detailed_clock
, &clock
);
91 if (clock
&& (ranges
->max_clock
* 1e6
< clock
)) {
92 xf86Msg(X_WARNING
, "EDID timing clock %.2f exceeds claimed max "
93 "%dMHz, fixing\n", clock
/ 1.0e6
, ranges
->max_clock
);
94 ranges
->max_clock
= (clock
+ 999999) / 1e6
;
99 struct det_hv_parameter
{
106 handle_detailed_hvsize(struct detailed_monitor_section
*det_mon
, void *data
)
108 struct det_hv_parameter
*p
= (struct det_hv_parameter
*) data
;
111 if (det_mon
->type
== DT
) {
112 struct detailed_timings
*timing
;
114 timing
= &det_mon
->section
.d_timings
;
119 timing_aspect
= (float) timing
->h_size
/ timing
->v_size
;
120 if (fabs(1 - (timing_aspect
/ p
->target_aspect
)) < 0.05) {
121 p
->real_hsize
= max(p
->real_hsize
, timing
->h_size
);
122 p
->real_vsize
= max(p
->real_vsize
, timing
->v_size
);
128 encode_aspect_ratio(xf86MonPtr m
)
131 * some monitors encode the aspect ratio instead of the physical size.
132 * try to find the largest detailed timing that matches that aspect
133 * ratio and use that to fill in the feature section.
135 if ((m
->features
.hsize
== 16 && m
->features
.vsize
== 9) ||
136 (m
->features
.hsize
== 16 && m
->features
.vsize
== 10) ||
137 (m
->features
.hsize
== 4 && m
->features
.vsize
== 3) ||
138 (m
->features
.hsize
== 5 && m
->features
.vsize
== 4)) {
140 struct det_hv_parameter p
;
144 p
.target_aspect
= (float) m
->features
.hsize
/ m
->features
.vsize
;
146 xf86ForEachDetailedBlock(m
, handle_detailed_hvsize
, &p
);
148 if (!p
.real_hsize
|| !p
.real_vsize
) {
149 m
->features
.hsize
= m
->features
.vsize
= 0;
151 else if ((m
->features
.hsize
* 10 == p
.real_hsize
) &&
152 (m
->features
.vsize
* 10 == p
.real_vsize
)) {
153 /* exact match is just unlikely, should do a better check though */
154 m
->features
.hsize
= m
->features
.vsize
= 0;
157 /* convert mm to cm */
158 m
->features
.hsize
= (p
.real_hsize
+ 5) / 10;
159 m
->features
.vsize
= (p
.real_vsize
+ 5) / 10;
162 xf86Msg(X_INFO
, "Quirked EDID physical size to %dx%d cm\n",
163 m
->features
.hsize
, m
->features
.vsize
);
168 xf86InterpretEDID(int scrnIndex
, Uchar
* block
)
174 if (!(m
= xnfcalloc(sizeof(xf86Monitor
), 1)))
176 m
->scrnIndex
= scrnIndex
;
179 get_vendor_section(SECTION(VENDOR_SECTION
, block
), &m
->vendor
);
180 get_version_section(SECTION(VERSION_SECTION
, block
), &m
->ver
);
181 if (!validate_version(scrnIndex
, &m
->ver
))
183 get_display_section(SECTION(DISPLAY_SECTION
, block
), &m
->features
, &m
->ver
);
184 get_established_timing_section(SECTION(ESTABLISHED_TIMING_SECTION
, block
),
186 get_std_timing_section(SECTION(STD_TIMING_SECTION
, block
), m
->timings2
,
188 get_dt_md_section(SECTION(DET_TIMING_SECTION
, block
), &m
->ver
, m
->det_mon
);
189 m
->no_sections
= (int) *(char *) SECTION(NO_EDID
, block
);
191 handle_edid_quirks(m
);
192 encode_aspect_ratio(m
);
202 get_cea_detail_timing(Uchar
* blk
, xf86MonPtr mon
,
203 struct detailed_monitor_section
*det_mon
)
206 int dt_offset
= ((struct cea_ext_body
*) blk
)->dt_offset
;
210 if (dt_offset
< CEA_EXT_MIN_DATA_OFFSET
)
213 for (; dt_offset
< (CEA_EXT_MAX_DATA_OFFSET
- DET_TIMING_INFO_LEN
) &&
214 dt_num
< CEA_EXT_DET_TIMING_NUM
; _NEXT_DT_MD_SECTION(dt_offset
)) {
216 fetch_detailed_block(blk
+ dt_offset
, &mon
->ver
, det_mon
+ dt_num
);
224 handle_cea_detail_block(Uchar
* ext
, xf86MonPtr mon
,
225 handle_detailed_fn fn
, void *data
)
228 struct detailed_monitor_section det_mon
[CEA_EXT_DET_TIMING_NUM
];
231 det_mon_num
= get_cea_detail_timing(ext
, mon
, det_mon
);
233 for (i
= 0; i
< det_mon_num
; i
++)
234 fn(det_mon
+ i
, data
);
238 xf86ForEachDetailedBlock(xf86MonPtr mon
, handle_detailed_fn fn
, void *data
)
246 for (i
= 0; i
< DET_TIMINGS
; i
++)
247 fn(mon
->det_mon
+ i
, data
);
249 for (i
= 0; i
< mon
->no_sections
; i
++) {
250 ext
= mon
->rawData
+ EDID1_LEN
* (i
+ 1);
251 switch (ext
[EXT_TAG
]) {
253 handle_cea_detail_block(ext
, mon
, fn
, data
);
264 static struct cea_data_block
*
265 extract_cea_data_block(Uchar
* ext
, int data_type
)
267 struct cea_ext_body
*cea
;
268 struct cea_data_block
*data_collection
;
269 struct cea_data_block
*data_end
;
271 cea
= (struct cea_ext_body
*) ext
;
273 if (cea
->dt_offset
<= CEA_EXT_MIN_DATA_OFFSET
)
276 data_collection
= &cea
->data_collection
;
277 data_end
= (struct cea_data_block
*) (cea
->dt_offset
+ ext
);
279 for (; data_collection
< data_end
;) {
281 if (data_type
== data_collection
->tag
) {
282 return data_collection
;
284 data_collection
= (void *) ((unsigned char *) data_collection
+
285 data_collection
->len
+ 1);
292 handle_cea_video_block(Uchar
* ext
, handle_video_fn fn
, void *data
)
294 struct cea_video_block
*video
;
295 struct cea_video_block
*video_end
;
296 struct cea_data_block
*data_collection
;
298 data_collection
= extract_cea_data_block(ext
, CEA_VIDEO_BLK
);
299 if (data_collection
== NULL
)
302 video
= &data_collection
->u
.video
;
303 video_end
= (struct cea_video_block
*)
304 ((Uchar
*) video
+ data_collection
->len
);
306 for (; video
< video_end
; video
= video
+ 1) {
312 xf86ForEachVideoBlock(xf86MonPtr mon
, handle_video_fn fn
, void *data
)
320 for (i
= 0; i
< mon
->no_sections
; i
++) {
321 ext
= mon
->rawData
+ EDID1_LEN
* (i
+ 1);
322 switch (ext
[EXT_TAG
]) {
324 handle_cea_video_block(ext
, fn
, data
);
336 xf86InterpretEEDID(int scrnIndex
, Uchar
* block
)
340 m
= xf86InterpretEDID(scrnIndex
, block
);
344 /* extension parse */
350 get_vendor_section(Uchar
* c
, struct vendor
*r
)
357 r
->prod_id
= PROD_ID
;
358 r
->serial
= SERIAL_NO
;
364 get_version_section(Uchar
* c
, struct edid_version
*r
)
366 r
->version
= VERSION
;
367 r
->revision
= REVISION
;
371 get_display_section(Uchar
* c
, struct disp_features
*r
, struct edid_version
*v
)
373 r
->input_type
= INPUT_TYPE
;
374 if (!DIGITAL(r
->input_type
)) {
375 r
->input_voltage
= INPUT_VOLTAGE
;
376 r
->input_setup
= SETUP
;
377 r
->input_sync
= SYNC
;
379 else if (v
->revision
== 2 || v
->revision
== 3) {
382 else if (v
->revision
>= 4) {
384 r
->input_interface
= DIGITAL_INTERFACE
;
386 r
->hsize
= HSIZE_MAX
;
387 r
->vsize
= VSIZE_MAX
;
390 r
->display_type
= DISPLAY_TYPE
;
403 get_established_timing_section(Uchar
* c
, struct established_timings
*r
)
411 get_cvt_timing_section(Uchar
* c
, struct cvt_timings
*r
)
415 for (i
= 0; i
< 4; i
++) {
416 if (c
[0] && c
[1] && c
[2]) {
417 r
[i
].height
= (c
[0] + ((c
[1] & 0xF0) << 8) + 1) * 2;
418 switch (c
[1] & 0xc0) {
420 r
[i
].width
= r
[i
].height
* 4 / 3;
423 r
[i
].width
= r
[i
].height
* 16 / 9;
426 r
[i
].width
= r
[i
].height
* 16 / 10;
429 r
[i
].width
= r
[i
].height
* 15 / 9;
432 switch (c
[2] & 0x60) {
446 r
[i
].rates
= c
[2] & 0x1f;
456 get_std_timing_section(Uchar
* c
, struct std_timings
*r
, struct edid_version
*v
)
460 for (i
= 0; i
< STD_TIMINGS
; i
++) {
464 r
[i
].refresh
= REFRESH_R
;
465 r
[i
].id
= STD_TIMING_ID
;
468 r
[i
].hsize
= r
[i
].vsize
= r
[i
].refresh
= r
[i
].id
= 0;
474 static const unsigned char empty_block
[18];
477 fetch_detailed_block(Uchar
* c
, struct edid_version
*ver
,
478 struct detailed_monitor_section
*det_mon
)
480 if (ver
->version
== 1 && ver
->revision
>= 1 && IS_MONITOR_DESC
) {
481 switch (MONITOR_DESC_TYPE
) {
483 det_mon
->type
= DS_SERIAL
;
484 copy_string(c
, det_mon
->section
.serial
);
487 det_mon
->type
= DS_ASCII_STR
;
488 copy_string(c
, det_mon
->section
.ascii_data
);
491 det_mon
->type
= DS_RANGES
;
492 get_monitor_ranges(c
, &det_mon
->section
.ranges
);
495 det_mon
->type
= DS_NAME
;
496 copy_string(c
, det_mon
->section
.name
);
498 case ADD_COLOR_POINT
:
499 det_mon
->type
= DS_WHITE_P
;
500 get_whitepoint_section(c
, det_mon
->section
.wp
);
502 case ADD_STD_TIMINGS
:
503 det_mon
->type
= DS_STD_TIMINGS
;
504 get_dst_timing_section(c
, det_mon
->section
.std_t
, ver
);
506 case COLOR_MANAGEMENT_DATA
:
507 det_mon
->type
= DS_CMD
;
510 det_mon
->type
= DS_CVT
;
511 get_cvt_timing_section(c
, det_mon
->section
.cvt
);
513 case ADD_EST_TIMINGS
:
514 det_mon
->type
= DS_EST_III
;
515 memcpy(det_mon
->section
.est_iii
, c
+ 6, 6);
518 det_mon
->type
= DS_DUMMY
;
521 det_mon
->type
= DS_UNKOWN
;
524 if (c
[3] <= 0x0F && memcmp(c
, empty_block
, sizeof(empty_block
))) {
525 det_mon
->type
= DS_VENDOR
+ c
[3];
530 get_detailed_timing_section(c
, &det_mon
->section
.d_timings
);
535 get_dt_md_section(Uchar
* c
, struct edid_version
*ver
,
536 struct detailed_monitor_section
*det_mon
)
540 for (i
= 0; i
< DET_TIMINGS
; i
++) {
541 fetch_detailed_block(c
, ver
, det_mon
+ i
);
547 copy_string(Uchar
* c
, Uchar
* s
)
552 for (i
= 0; (i
< 13 && *c
!= 0x0A); i
++)
555 while (i
-- && (*--s
== 0x20))
560 get_dst_timing_section(Uchar
* c
, struct std_timings
*t
, struct edid_version
*v
)
565 for (j
= 0; j
< 5; j
++) {
568 t
[j
].refresh
= REFRESH_R
;
569 t
[j
].id
= STD_TIMING_ID
;
575 get_monitor_ranges(Uchar
* c
, struct monitor_ranges
*r
)
582 if (MAX_CLOCK
!= 0xff) /* is specified? */
583 r
->max_clock
= MAX_CLOCK
* 10 + 5;
585 r
->gtf_2nd_f
= F_2ND_GTF
;
586 r
->gtf_2nd_c
= C_2ND_GTF
;
587 r
->gtf_2nd_m
= M_2ND_GTF
;
588 r
->gtf_2nd_k
= K_2ND_GTF
;
589 r
->gtf_2nd_j
= J_2ND_GTF
;
595 r
->max_clock_khz
= MAX_CLOCK_KHZ
;
596 r
->max_clock
= r
->max_clock_khz
/ 1000;
597 r
->maxwidth
= MAXWIDTH
;
598 r
->supported_aspect
= SUPPORTED_ASPECT
;
599 r
->preferred_aspect
= PREFERRED_ASPECT
;
600 r
->supported_blanking
= SUPPORTED_BLANKING
;
601 r
->supported_scaling
= SUPPORTED_SCALING
;
602 r
->preferred_refresh
= PREFERRED_REFRESH
;
605 r
->max_clock_khz
= 0;
610 get_whitepoint_section(Uchar
* c
, struct whitePoints
*wp
)
612 wp
[0].white_x
= WHITEX1
;
613 wp
[0].white_y
= WHITEY1
;
614 wp
[1].white_x
= WHITEX2
;
615 wp
[1].white_y
= WHITEY2
;
616 wp
[0].index
= WHITE_INDEX1
;
617 wp
[1].index
= WHITE_INDEX2
;
618 wp
[0].white_gamma
= WHITE_GAMMA1
;
619 wp
[1].white_gamma
= WHITE_GAMMA2
;
623 get_detailed_timing_section(Uchar
* c
, struct detailed_timings
*r
)
625 r
->clock
= PIXEL_CLOCK
;
626 r
->h_active
= H_ACTIVE
;
627 r
->h_blanking
= H_BLANK
;
628 r
->v_active
= V_ACTIVE
;
629 r
->v_blanking
= V_BLANK
;
630 r
->h_sync_off
= H_SYNC_OFF
;
631 r
->h_sync_width
= H_SYNC_WIDTH
;
632 r
->v_sync_off
= V_SYNC_OFF
;
633 r
->v_sync_width
= V_SYNC_WIDTH
;
636 r
->h_border
= H_BORDER
;
637 r
->v_border
= V_BORDER
;
638 r
->interlaced
= INTERLACED
;
640 r
->stereo_1
= STEREO1
;
645 #define MAX_EDID_MINOR 4
648 validate_version(int scrnIndex
, struct edid_version
*r
)
650 if (r
->version
!= 1) {
651 xf86DrvMsg(scrnIndex
, X_ERROR
, "Unknown EDID version %d\n", r
->version
);
655 if (r
->revision
> MAX_EDID_MINOR
)
656 xf86DrvMsg(scrnIndex
, X_WARNING
,
657 "Assuming version 1.%d is compatible with 1.%d\n",
658 r
->revision
, MAX_EDID_MINOR
);
664 * Returns true if HDMI, false if definitely not or unknown.
667 xf86MonitorIsHDMI(xf86MonPtr mon
)
669 int i
= 0, version
, offset
;
675 if (!(mon
->flags
& EDID_COMPLETE_RAWDATA
))
678 if (!mon
->no_sections
)
681 edid
= (char *) mon
->rawData
;
685 /* find the CEA extension block */
686 for (i
= 1; i
<= mon
->no_sections
; i
++)
687 if (edid
[i
* 128] == 0x02)
689 if (i
== mon
->no_sections
+ 1)
695 if (version
< 3 || offset
< 4)
698 /* walk the cea data blocks */
699 for (i
= 4; i
< offset
; i
+= (edid
[i
] & 0x1f) + 1) {
702 /* find a vendor specific block */
703 if ((x
[0] & 0xe0) >> 5 == 0x03) {
704 int oui
= (x
[3] << 16) + (x
[2] << 8) + x
[1];
706 /* find the HDMI vendor OUI */
712 /* guess it's not HDMI after all */