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 * print_edid.c: print out all information retrieved from display device
27 #ifdef HAVE_XORG_CONFIG_H
28 #include <xorg-config.h>
36 #include "xf86_OSproc.h"
43 print_vendor(int scrnIndex
, struct vendor
*c
)
45 xf86DrvMsg(scrnIndex
, X_INFO
, "Manufacturer: %s Model: %x Serial#: %u\n",
46 (char *) &c
->name
, c
->prod_id
, c
->serial
);
47 xf86DrvMsg(scrnIndex
, X_INFO
, "Year: %u Week: %u\n", c
->year
, c
->week
);
51 print_version(int scrnIndex
, struct edid_version
*c
)
53 xf86DrvMsg(scrnIndex
, X_INFO
, "EDID Version: %u.%u\n", c
->version
,
57 static const char *digital_interfaces
[] = {
68 print_input_features(int scrnIndex
, struct disp_features
*c
,
69 struct edid_version
*v
)
71 if (DIGITAL(c
->input_type
)) {
72 xf86DrvMsg(scrnIndex
, X_INFO
, "Digital Display Input\n");
73 if (v
->revision
== 2 || v
->revision
== 3) {
74 if (DFP1(c
->input_dfp
))
75 xf86DrvMsg(scrnIndex
, X_INFO
, "DFP 1.x compatible TMDS\n");
77 else if (v
->revision
>= 4) {
78 int interface
= c
->input_interface
;
79 int bpc
= c
->input_bpc
;
82 interface
= 6; /* unknown */
83 if (bpc
== 0 || bpc
== 7)
84 xf86DrvMsg(scrnIndex
, X_INFO
, "Undefined color depth\n");
86 xf86DrvMsg(scrnIndex
, X_INFO
, "%d bits per channel\n",
88 xf86DrvMsg(scrnIndex
, X_INFO
, "Digital interface is %s\n",
89 digital_interfaces
[interface
]);
93 xf86DrvMsg(scrnIndex
, X_INFO
, "Analog Display Input, ");
94 xf86ErrorF("Input Voltage Level: ");
95 switch (c
->input_voltage
) {
97 xf86ErrorF("0.700/0.300 V\n");
100 xf86ErrorF("0.714/0.286 V\n");
103 xf86ErrorF("1.000/0.400 V\n");
106 xf86ErrorF("0.700/0.700 V\n");
109 xf86ErrorF("undefined\n");
111 if (SIG_SETUP(c
->input_setup
))
112 xf86DrvMsg(scrnIndex
, X_INFO
, "Signal levels configurable\n");
113 xf86DrvMsg(scrnIndex
, X_INFO
, "Sync:");
114 if (SEP_SYNC(c
->input_sync
))
115 xf86ErrorF(" Separate");
116 if (COMP_SYNC(c
->input_sync
))
117 xf86ErrorF(" Composite");
118 if (SYNC_O_GREEN(c
->input_sync
))
119 xf86ErrorF(" SyncOnGreen");
120 if (SYNC_SERR(c
->input_sync
))
121 xf86ErrorF("Serration on. "
122 "V.Sync Pulse req. if CompSync or SyncOnGreen\n");
129 print_dpms_features(int scrnIndex
, struct disp_features
*c
,
130 struct edid_version
*v
)
133 xf86DrvMsg(scrnIndex
, X_INFO
, "DPMS capabilities:");
134 if (DPMS_STANDBY(c
->dpms
))
135 xf86ErrorF(" StandBy");
136 if (DPMS_SUSPEND(c
->dpms
))
137 xf86ErrorF(" Suspend");
138 if (DPMS_OFF(c
->dpms
))
142 xf86DrvMsg(scrnIndex
, X_INFO
, "No DPMS capabilities specified");
143 if (!c
->input_type
) { /* analog */
144 switch (c
->display_type
) {
146 xf86ErrorF("; Monochorome/GrayScale Display\n");
149 xf86ErrorF("; RGB/Color Display\n");
152 xf86ErrorF("; Non RGB Multicolor Display\n");
160 int enc
= c
->display_type
;
163 xf86DrvMsg(scrnIndex
, X_INFO
, "Supported color encodings: "
165 enc
& DISP_YCRCB444
? "YCrCb 4:4:4 " : "",
166 enc
& DISP_YCRCB422
? "YCrCb 4:2:2" : "");
169 if (STD_COLOR_SPACE(c
->msc
))
170 xf86DrvMsg(scrnIndex
, X_INFO
,
171 "Default color space is primary color space\n");
173 if (PREFERRED_TIMING_MODE(c
->msc
) || v
->revision
>= 4) {
174 xf86DrvMsg(scrnIndex
, X_INFO
,
175 "First detailed timing is preferred mode\n");
176 if (v
->revision
>= 4)
177 xf86DrvMsg(scrnIndex
, X_INFO
,
178 "Preferred mode is native pixel format and refresh rate\n");
180 else if (v
->revision
== 3) {
181 xf86DrvMsg(scrnIndex
, X_INFO
,
182 "First detailed timing not preferred "
183 "mode in violation of standard!\n");
186 if (v
->revision
>= 4) {
187 if (GFT_SUPPORTED(c
->msc
)) {
188 xf86DrvMsg(scrnIndex
, X_INFO
, "Display is continuous-frequency\n");
192 if (GFT_SUPPORTED(c
->msc
))
193 xf86DrvMsg(scrnIndex
, X_INFO
, "GTF timings supported\n");
198 print_whitepoint(int scrnIndex
, struct disp_features
*disp
)
200 xf86DrvMsg(scrnIndex
, X_INFO
, "redX: %.3f redY: %.3f ",
201 disp
->redx
, disp
->redy
);
202 xf86ErrorF("greenX: %.3f greenY: %.3f\n", disp
->greenx
, disp
->greeny
);
203 xf86DrvMsg(scrnIndex
, X_INFO
, "blueX: %.3f blueY: %.3f ",
204 disp
->bluex
, disp
->bluey
);
205 xf86ErrorF("whiteX: %.3f whiteY: %.3f\n", disp
->whitex
, disp
->whitey
);
209 print_display(int scrnIndex
, struct disp_features
*disp
, struct edid_version
*v
)
211 print_input_features(scrnIndex
, disp
, v
);
212 if (disp
->hsize
&& disp
->vsize
) {
213 xf86DrvMsg(scrnIndex
, X_INFO
, "Max Image Size [cm]: ");
214 xf86ErrorF("horiz.: %i ", disp
->hsize
);
215 xf86ErrorF("vert.: %i\n", disp
->vsize
);
217 else if (v
->revision
>= 4 && (disp
->hsize
|| disp
->vsize
)) {
219 xf86DrvMsg(scrnIndex
, X_INFO
, "Aspect ratio: %.2f (landscape)\n",
220 (disp
->hsize
+ 99) / 100.0);
222 xf86DrvMsg(scrnIndex
, X_INFO
, "Aspect ratio: %.2f (portrait)\n",
223 100.0 / (float) (disp
->vsize
+ 99));
227 xf86DrvMsg(scrnIndex
, X_INFO
, "Indeterminate output size\n");
230 if (!disp
->gamma
&& v
->revision
>= 1.4)
231 xf86DrvMsg(scrnIndex
, X_INFO
, "Gamma defined in extension block\n");
233 xf86DrvMsg(scrnIndex
, X_INFO
, "Gamma: %.2f\n", disp
->gamma
);
235 print_dpms_features(scrnIndex
, disp
, v
);
236 print_whitepoint(scrnIndex
, disp
);
240 print_established_timings(int scrnIndex
, struct established_timings
*t
)
244 if (t
->t1
|| t
->t2
|| t
->t_manu
)
245 xf86DrvMsg(scrnIndex
, X_INFO
, "Supported established timings:\n");
248 xf86DrvMsg(scrnIndex
, X_INFO
, "720x400@70Hz\n");
250 xf86DrvMsg(scrnIndex
, X_INFO
, "720x400@88Hz\n");
252 xf86DrvMsg(scrnIndex
, X_INFO
, "640x480@60Hz\n");
254 xf86DrvMsg(scrnIndex
, X_INFO
, "640x480@67Hz\n");
256 xf86DrvMsg(scrnIndex
, X_INFO
, "640x480@72Hz\n");
258 xf86DrvMsg(scrnIndex
, X_INFO
, "640x480@75Hz\n");
260 xf86DrvMsg(scrnIndex
, X_INFO
, "800x600@56Hz\n");
262 xf86DrvMsg(scrnIndex
, X_INFO
, "800x600@60Hz\n");
265 xf86DrvMsg(scrnIndex
, X_INFO
, "800x600@72Hz\n");
267 xf86DrvMsg(scrnIndex
, X_INFO
, "800x600@75Hz\n");
269 xf86DrvMsg(scrnIndex
, X_INFO
, "832x624@75Hz\n");
271 xf86DrvMsg(scrnIndex
, X_INFO
, "1024x768@87Hz (interlaced)\n");
273 xf86DrvMsg(scrnIndex
, X_INFO
, "1024x768@60Hz\n");
275 xf86DrvMsg(scrnIndex
, X_INFO
, "1024x768@70Hz\n");
277 xf86DrvMsg(scrnIndex
, X_INFO
, "1024x768@75Hz\n");
279 xf86DrvMsg(scrnIndex
, X_INFO
, "1280x1024@75Hz\n");
282 xf86DrvMsg(scrnIndex
, X_INFO
, "1152x864@75Hz\n");
283 xf86DrvMsg(scrnIndex
, X_INFO
, "Manufacturer's mask: %X\n", c
& 0x7F);
287 print_std_timings(int scrnIndex
, struct std_timings
*t
)
292 for (i
= 0; i
< STD_TIMINGS
; i
++) {
293 if (t
[i
].hsize
> 256) { /* sanity check */
295 xf86DrvMsg(scrnIndex
, X_INFO
, "Supported standard timings:\n");
298 xf86DrvMsg(scrnIndex
, X_INFO
,
299 "#%i: hsize: %i vsize %i refresh: %i vid: %i\n",
300 i
, t
[i
].hsize
, t
[i
].vsize
, t
[i
].refresh
, t
[i
].id
);
306 print_cvt_timings(int si
, struct cvt_timings
*t
)
310 for (i
= 0; i
< 4; i
++) {
312 xf86DrvMsg(si
, X_INFO
, "%dx%d @ %s%s%s%s%s Hz\n",
313 t
[i
].width
, t
[i
].height
,
314 t
[i
].rates
& 0x10 ? "50," : "",
315 t
[i
].rates
& 0x08 ? "60," : "",
316 t
[i
].rates
& 0x04 ? "75," : "",
317 t
[i
].rates
& 0x02 ? "85," : "",
318 t
[i
].rates
& 0x01 ? "60RB" : "");
326 print_detailed_timings(int scrnIndex
, struct detailed_timings
*t
)
329 if (t
->clock
> 15000000) { /* sanity check */
330 xf86DrvMsg(scrnIndex
, X_INFO
, "Supported detailed timing:\n");
331 xf86DrvMsg(scrnIndex
, X_INFO
, "clock: %.1f MHz ",
332 t
->clock
/ 1000000.0);
333 xf86ErrorF("Image Size: %i x %i mm\n", t
->h_size
, t
->v_size
);
334 xf86DrvMsg(scrnIndex
, X_INFO
,
335 "h_active: %i h_sync: %i h_sync_end %i h_blank_end %i ",
336 t
->h_active
, t
->h_sync_off
+ t
->h_active
,
337 t
->h_sync_off
+ t
->h_sync_width
+ t
->h_active
,
338 t
->h_active
+ t
->h_blanking
);
339 xf86ErrorF("h_border: %i\n", t
->h_border
);
340 xf86DrvMsg(scrnIndex
, X_INFO
,
341 "v_active: %i v_sync: %i v_sync_end %i v_blanking: %i ",
342 t
->v_active
, t
->v_sync_off
+ t
->v_active
,
343 t
->v_sync_off
+ t
->v_sync_width
+ t
->v_active
,
344 t
->v_active
+ t
->v_blanking
);
345 xf86ErrorF("v_border: %i\n", t
->v_border
);
346 if (IS_STEREO(t
->stereo
)) {
347 xf86DrvMsg(scrnIndex
, X_INFO
, "Stereo: ");
348 if (IS_RIGHT_STEREO(t
->stereo
)) {
350 xf86ErrorF("right channel on sync\n");
352 xf86ErrorF("left channel on sync\n");
354 else if (IS_LEFT_STEREO(t
->stereo
)) {
356 xf86ErrorF("right channel on even line\n");
358 xf86ErrorF("left channel on evel line\n");
360 if (IS_4WAY_STEREO(t
->stereo
)) {
362 xf86ErrorF("4-way interleaved\n");
364 xf86ErrorF("side-by-side interleaved");
370 /* This function handle all detailed patchs,
371 * including EDID and EDID-extension
373 struct det_print_parameter
{
380 handle_detailed_print(struct detailed_monitor_section
*det_mon
, void *data
)
383 struct det_print_parameter
*p
;
385 p
= (struct det_print_parameter
*) data
;
386 scrnIndex
= p
->m
->scrnIndex
;
387 xf86DetTimingApplyQuirks(det_mon
, p
->quirks
,
388 p
->m
->features
.hsize
, p
->m
->features
.vsize
);
390 switch (det_mon
->type
) {
392 print_detailed_timings(scrnIndex
, &det_mon
->section
.d_timings
);
395 xf86DrvMsg(scrnIndex
, X_INFO
, "Serial No: %s\n",
396 det_mon
->section
.serial
);
399 xf86DrvMsg(scrnIndex
, X_INFO
, " %s\n", det_mon
->section
.ascii_data
);
402 xf86DrvMsg(scrnIndex
, X_INFO
, "Monitor name: %s\n",
403 det_mon
->section
.name
);
407 struct monitor_ranges
*r
= &det_mon
->section
.ranges
;
409 xf86DrvMsg(scrnIndex
, X_INFO
,
410 "Ranges: V min: %i V max: %i Hz, H min: %i H max: %i kHz,",
411 r
->min_v
, r
->max_v
, r
->min_h
, r
->max_h
);
412 if (r
->max_clock_khz
!= 0) {
413 xf86ErrorF(" PixClock max %i kHz\n", r
->max_clock_khz
);
415 xf86DrvMsg(scrnIndex
, X_INFO
, "Maximum pixel width: %d\n",
417 xf86DrvMsg(scrnIndex
, X_INFO
, "Supported aspect ratios:");
418 if (r
->supported_aspect
& SUPPORTED_ASPECT_4_3
)
420 r
->preferred_aspect
==
421 PREFERRED_ASPECT_4_3
? "*" : "");
422 if (r
->supported_aspect
& SUPPORTED_ASPECT_16_9
)
423 xf86ErrorF(" 16:9%s",
424 r
->preferred_aspect
==
425 PREFERRED_ASPECT_16_9
? "*" : "");
426 if (r
->supported_aspect
& SUPPORTED_ASPECT_16_10
)
427 xf86ErrorF(" 16:10%s",
428 r
->preferred_aspect
==
429 PREFERRED_ASPECT_16_10
? "*" : "");
430 if (r
->supported_aspect
& SUPPORTED_ASPECT_5_4
)
432 r
->preferred_aspect
==
433 PREFERRED_ASPECT_5_4
? "*" : "");
434 if (r
->supported_aspect
& SUPPORTED_ASPECT_15_9
)
435 xf86ErrorF(" 15:9%s",
436 r
->preferred_aspect
==
437 PREFERRED_ASPECT_15_9
? "*" : "");
439 xf86DrvMsg(scrnIndex
, X_INFO
, "Supported blankings:");
440 if (r
->supported_blanking
& CVT_STANDARD
)
441 xf86ErrorF(" standard");
442 if (r
->supported_blanking
& CVT_REDUCED
)
443 xf86ErrorF(" reduced");
445 xf86DrvMsg(scrnIndex
, X_INFO
, "Supported scalings:");
446 if (r
->supported_scaling
& SCALING_HSHRINK
)
447 xf86ErrorF(" hshrink");
448 if (r
->supported_scaling
& SCALING_HSTRETCH
)
449 xf86ErrorF(" hstretch");
450 if (r
->supported_scaling
& SCALING_VSHRINK
)
451 xf86ErrorF(" vshrink");
452 if (r
->supported_scaling
& SCALING_VSTRETCH
)
453 xf86ErrorF(" vstretch");
455 if (r
->preferred_refresh
)
456 xf86DrvMsg(scrnIndex
, X_INFO
, "Preferred refresh rate: %d\n",
457 r
->preferred_refresh
);
459 xf86DrvMsg(scrnIndex
, X_INFO
, "Buggy monitor, no preferred "
460 "refresh rate given\n");
462 else if (r
->max_clock
!= 0) {
463 xf86ErrorF(" PixClock max %i MHz\n", r
->max_clock
);
468 if (r
->gtf_2nd_f
> 0)
469 xf86DrvMsg(scrnIndex
, X_INFO
, " 2nd GTF parameters: f: %i kHz "
470 "c: %i m: %i k %i j %i\n", r
->gtf_2nd_f
,
471 r
->gtf_2nd_c
, r
->gtf_2nd_m
, r
->gtf_2nd_k
, r
->gtf_2nd_j
);
475 for (j
= 0; j
< 5; j
++)
476 xf86DrvMsg(scrnIndex
, X_INFO
,
477 "#%i: hsize: %i vsize %i refresh: %i "
478 "vid: %i\n", p
->index
, det_mon
->section
.std_t
[j
].hsize
,
479 det_mon
->section
.std_t
[j
].vsize
,
480 det_mon
->section
.std_t
[j
].refresh
,
481 det_mon
->section
.std_t
[j
].id
);
484 for (j
= 0; j
< 2; j
++)
485 if (det_mon
->section
.wp
[j
].index
!= 0)
486 xf86DrvMsg(scrnIndex
, X_INFO
,
487 "White point %i: whiteX: %f, whiteY: %f; gamma: %f\n",
488 det_mon
->section
.wp
[j
].index
,
489 det_mon
->section
.wp
[j
].white_x
,
490 det_mon
->section
.wp
[j
].white_y
,
491 det_mon
->section
.wp
[j
].white_gamma
);
494 xf86DrvMsg(scrnIndex
, X_INFO
, "Color management data: (not decoded)\n");
497 xf86DrvMsg(scrnIndex
, X_INFO
, "CVT 3-byte-code modes:\n");
498 print_cvt_timings(scrnIndex
, det_mon
->section
.cvt
);
501 xf86DrvMsg(scrnIndex
, X_INFO
,
502 "Established timings III: (not decoded)\n");
508 if (det_mon
->type
>= DS_VENDOR
&& det_mon
->type
<= DS_VENDOR_MAX
) {
509 xf86DrvMsg(scrnIndex
, X_INFO
,
510 "Unknown vendor-specific block %hx\n",
511 det_mon
->type
- DS_VENDOR
);
514 p
->index
= p
->index
+ 1;
518 print_number_sections(int scrnIndex
, int num
)
521 xf86DrvMsg(scrnIndex
, X_INFO
, "Number of EDID sections to follow: %i\n",
526 xf86PrintEDID(xf86MonPtr m
)
529 char buf
[EDID_WIDTH
* 2 + 1];
530 struct det_print_parameter p
;
535 print_vendor(m
->scrnIndex
, &m
->vendor
);
536 print_version(m
->scrnIndex
, &m
->ver
);
537 print_display(m
->scrnIndex
, &m
->features
, &m
->ver
);
538 print_established_timings(m
->scrnIndex
, &m
->timings1
);
539 print_std_timings(m
->scrnIndex
, m
->timings2
);
542 p
.quirks
= xf86DDCDetectQuirks(m
->scrnIndex
, m
, FALSE
);
543 xf86ForEachDetailedBlock(m
, handle_detailed_print
, &p
);
544 print_number_sections(m
->scrnIndex
, m
->no_sections
);
546 /* extension block section stuff */
548 xf86DrvMsg(m
->scrnIndex
, X_INFO
, "EDID (in hex):\n");
551 if (m
->flags
& EDID_COMPLETE_RAWDATA
)
552 n
+= m
->no_sections
* 128;
554 for (i
= 0; i
< n
; i
+= j
) {
555 for (j
= 0; j
< EDID_WIDTH
; ++j
) {
556 sprintf(&buf
[j
* 2], "%02x", m
->rawData
[i
+ j
]);
558 xf86DrvMsg(m
->scrnIndex
, X_INFO
, "\t%s\n", buf
);