interpret_edid.c revision 52397711
1/*
2 * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
3 * Copyright 2007 Red Hat, Inc.
4 *
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * them Software is furnished to do so, subject to the following conditions:
11 *
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
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * interpret_edid.c: interpret a primary EDID block
24 */
25
26#ifdef HAVE_XORG_CONFIG_H
27#include <xorg-config.h>
28#endif
29
30#include "misc.h"
31#include "xf86.h"
32#include "xf86_OSproc.h"
33#define _PARSE_EDID_
34#include "xf86DDC.h"
35#include <string.h>
36
37static void get_vendor_section(Uchar*, struct vendor *);
38static void get_version_section(Uchar*, struct edid_version *);
39static void get_display_section(Uchar*, struct disp_features *,
40				struct edid_version *);
41static void get_established_timing_section(Uchar*, struct established_timings *);
42static void get_std_timing_section(Uchar*, struct std_timings *,
43				   struct edid_version *);
44static void get_dt_md_section(Uchar *, struct edid_version *,
45			      struct detailed_monitor_section *det_mon);
46static void copy_string(Uchar *, Uchar *);
47static void get_dst_timing_section(Uchar *, struct std_timings *,
48				   struct edid_version *);
49static void get_monitor_ranges(Uchar *, struct monitor_ranges *);
50static void get_whitepoint_section(Uchar *, struct whitePoints *);
51static void get_detailed_timing_section(Uchar*, struct 	detailed_timings *);
52static Bool validate_version(int scrnIndex, struct edid_version *);
53
54static void
55handle_edid_quirks(xf86MonPtr m)
56{
57    int i, j;
58    struct detailed_timings *preferred_timing;
59    struct monitor_ranges *ranges;
60
61    /*
62     * max_clock is only encoded in EDID in tens of MHz, so occasionally we
63     * find a monitor claiming a max of 160 with a mode requiring 162, or
64     * similar.  Strictly we should refuse to round up too far, but let's
65     * see how well this works.
66     */
67    for (i = 0; i < 4; i++) {
68	if (m->det_mon[i].type == DS_RANGES) {
69	    ranges = &m->det_mon[i].section.ranges;
70	    for (j = 0; j < 4; j++) {
71		if (m->det_mon[j].type == DT) {
72		    preferred_timing = &m->det_mon[j].section.d_timings;
73		    if (!ranges->max_clock) continue; /* zero is legal */
74		    if (ranges->max_clock * 1000000 < preferred_timing->clock) {
75			xf86Msg(X_WARNING,
76			    "EDID preferred timing clock %.2fMHz exceeds "
77			    "claimed max %dMHz, fixing\n",
78			    preferred_timing->clock / 1.0e6,
79			    ranges->max_clock);
80			ranges->max_clock =
81			    (preferred_timing->clock+999999)/1000000;
82			return;
83		    }
84		}
85	    }
86	}
87    }
88
89    /*
90     * some monitors encode the aspect ratio instead of the physical size.
91     * try to find the largest detailed timing that matches that aspect
92     * ratio and use that to fill in the feature section.
93     */
94    if ((m->features.hsize == 16 && m->features.vsize == 9) ||
95	(m->features.hsize == 16 && m->features.vsize == 10) ||
96	(m->features.hsize == 4 && m->features.vsize == 3) ||
97	(m->features.hsize == 5 && m->features.vsize == 4)) {
98	int real_hsize = 0, real_vsize = 0;
99	float target_aspect, timing_aspect;
100
101	target_aspect = (float)m->features.hsize / (float)m->features.vsize;
102	for (i = 0; i < 4; i++) {
103	    if (m->det_mon[i].type == DT) {
104		struct detailed_timings *timing;
105		timing = &m->det_mon[i].section.d_timings;
106
107		if (!timing->v_size)
108		    continue;
109
110		timing_aspect = (float)timing->h_size / (float)timing->v_size;
111		if (fabs(1 - (timing_aspect / target_aspect)) < 0.05) {
112		    real_hsize = max(real_hsize, timing->h_size);
113		    real_vsize = max(real_vsize, timing->v_size);
114		}
115	    }
116	}
117
118	if (!real_hsize || !real_vsize) {
119	    m->features.hsize = m->features.vsize = 0;
120	} else if ((m->features.hsize * 10 == real_hsize) &&
121		   (m->features.vsize * 10 == real_vsize)) {
122	    /* exact match is just unlikely, should do a better check though */
123	    m->features.hsize = m->features.vsize = 0;
124	} else {
125	    /* convert mm to cm */
126	    m->features.hsize = (real_hsize + 5) / 10;
127	    m->features.vsize = (real_vsize + 5) / 10;
128	}
129
130	xf86Msg(X_INFO, "Quirked EDID physical size to %dx%d cm\n",
131		m->features.hsize, m->features.vsize);
132    }
133}
134
135xf86MonPtr
136xf86InterpretEDID(int scrnIndex, Uchar *block)
137{
138    xf86MonPtr m;
139
140    if (!block) return NULL;
141    if (! (m = xnfcalloc(sizeof(xf86Monitor),1))) return NULL;
142    m->scrnIndex = scrnIndex;
143    m->rawData = block;
144
145    get_vendor_section(SECTION(VENDOR_SECTION,block),&m->vendor);
146    get_version_section(SECTION(VERSION_SECTION,block),&m->ver);
147    if (!validate_version(scrnIndex, &m->ver)) goto error;
148    get_display_section(SECTION(DISPLAY_SECTION,block),&m->features,
149			&m->ver);
150    get_established_timing_section(SECTION(ESTABLISHED_TIMING_SECTION,block),
151				   &m->timings1);
152    get_std_timing_section(SECTION(STD_TIMING_SECTION,block),m->timings2,
153			   &m->ver);
154    get_dt_md_section(SECTION(DET_TIMING_SECTION,block),&m->ver, m->det_mon);
155    m->no_sections = (int)*(char *)SECTION(NO_EDID,block);
156
157    handle_edid_quirks(m);
158
159    return (m);
160
161 error:
162    xfree(m);
163    return NULL;
164}
165
166xf86MonPtr
167xf86InterpretEEDID(int scrnIndex, Uchar *block)
168{
169    xf86MonPtr m;
170
171    m = xf86InterpretEDID(scrnIndex, block);
172    if (!m)
173	return NULL;
174
175    /* extension parse */
176
177    return m;
178}
179
180static void
181get_vendor_section(Uchar *c, struct vendor *r)
182{
183    r->name[0] = L1;
184    r->name[1] = L2;
185    r->name[2] = L3;
186    r->name[3] = '\0';
187
188    r->prod_id = PROD_ID;
189    r->serial  = SERIAL_NO;
190    r->week    = WEEK;
191    r->year    = YEAR;
192}
193
194static void
195get_version_section(Uchar *c, struct edid_version *r)
196{
197    r->version  = VERSION;
198    r->revision = REVISION;
199}
200
201static void
202get_display_section(Uchar *c, struct disp_features *r,
203		    struct edid_version *v)
204{
205    r->input_type = INPUT_TYPE;
206    if (!DIGITAL(r->input_type)) {
207	r->input_voltage = INPUT_VOLTAGE;
208	r->input_setup = SETUP;
209	r->input_sync = SYNC;
210    } else if (v->revision == 2 || v->revision == 3) {
211	r->input_dfp = DFP;
212    } else if (v->revision >= 4) {
213	r->input_bpc = BPC;
214	r->input_interface = DIGITAL_INTERFACE;
215    }
216    r->hsize = HSIZE_MAX;
217    r->vsize = VSIZE_MAX;
218    r->gamma = GAMMA;
219    r->dpms =  DPMS;
220    r->display_type = DISPLAY_TYPE;
221    r->msc = MSC;
222    r->redx = REDX;
223    r->redy = REDY;
224    r->greenx = GREENX;
225    r->greeny = GREENY;
226    r->bluex = BLUEX;
227    r->bluey = BLUEY;
228    r->whitex = WHITEX;
229    r->whitey = WHITEY;
230}
231
232static void
233get_established_timing_section(Uchar *c, struct established_timings *r)
234{
235    r->t1 = T1;
236    r->t2 = T2;
237    r->t_manu = T_MANU;
238}
239
240static void
241get_cvt_timing_section(Uchar *c, struct cvt_timings *r)
242{
243    int i;
244
245    for (i = 0; i < 4; i++) {
246	if (c[0] && c[1] && c[2]) {
247	    r[i].height = (c[0] + ((c[1] & 0xF0) << 8) + 1) * 2;
248	    switch (c[1] & 0xc0) {
249		case 0x00: r[i].width = r[i].height * 4 / 3; break;
250		case 0x40: r[i].width = r[i].height * 16 / 9; break;
251		case 0x80: r[i].width = r[i].height * 16 / 10; break;
252		case 0xc0: r[i].width = r[i].height * 15 / 9; break;
253	    }
254	    switch (c[2] & 0x60) {
255		case 0x00: r[i].rate = 50; break;
256		case 0x20: r[i].rate = 60; break;
257		case 0x40: r[i].rate = 75; break;
258		case 0x60: r[i].rate = 85; break;
259	    }
260	    r[i].rates = c[2] & 0x1f;
261	} else {
262	    return;
263	}
264	c += 3;
265    }
266}
267
268static void
269get_std_timing_section(Uchar *c, struct std_timings *r,
270		       struct edid_version *v)
271{
272    int i;
273
274    for (i=0;i<STD_TIMINGS;i++){
275	if (VALID_TIMING) {
276	    r[i].hsize = HSIZE1;
277	    VSIZE1(r[i].vsize);
278	    r[i].refresh = REFRESH_R;
279	    r[i].id = STD_TIMING_ID;
280	} else {
281	    r[i].hsize = r[i].vsize = r[i].refresh = r[i].id = 0;
282	}
283	NEXT_STD_TIMING;
284    }
285}
286
287static const unsigned char empty_block[18];
288
289static void
290get_dt_md_section(Uchar *c, struct edid_version *ver,
291		  struct detailed_monitor_section *det_mon)
292{
293  int i;
294
295  for (i=0;i<DET_TIMINGS;i++) {
296    if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) {
297
298      switch (MONITOR_DESC_TYPE) {
299      case SERIAL_NUMBER:
300	det_mon[i].type = DS_SERIAL;
301	copy_string(c,det_mon[i].section.serial);
302	break;
303      case ASCII_STR:
304	det_mon[i].type = DS_ASCII_STR;
305	copy_string(c,det_mon[i].section.ascii_data);
306	break;
307      case MONITOR_RANGES:
308	det_mon[i].type = DS_RANGES;
309	get_monitor_ranges(c,&det_mon[i].section.ranges);
310	break;
311      case MONITOR_NAME:
312	det_mon[i].type = DS_NAME;
313	copy_string(c,det_mon[i].section.name);
314	break;
315      case ADD_COLOR_POINT:
316	det_mon[i].type = DS_WHITE_P;
317	get_whitepoint_section(c,det_mon[i].section.wp);
318	break;
319      case ADD_STD_TIMINGS:
320	det_mon[i].type = DS_STD_TIMINGS;
321	get_dst_timing_section(c,det_mon[i].section.std_t, ver);
322	break;
323      case COLOR_MANAGEMENT_DATA:
324	det_mon[i].type = DS_CMD;
325	break;
326      case CVT_3BYTE_DATA:
327	det_mon[i].type = DS_CVT;
328	get_cvt_timing_section(c, det_mon[i].section.cvt);
329	break;
330      case ADD_EST_TIMINGS:
331	det_mon[i].type = DS_EST_III;
332	memcpy(det_mon[i].section.est_iii, c + 6, 6);
333	break;
334      case ADD_DUMMY:
335	det_mon[i].type = DS_DUMMY;
336        break;
337      default:
338        det_mon[i].type = DS_UNKOWN;
339        break;
340      }
341      if (c[3] <= 0x0F && memcmp(c, empty_block, sizeof(empty_block))) {
342	det_mon[i].type = DS_VENDOR + c[3];
343      }
344    } else {
345      det_mon[i].type = DT;
346      get_detailed_timing_section(c,&det_mon[i].section.d_timings);
347    }
348    NEXT_DT_MD_SECTION;
349  }
350}
351
352static void
353copy_string(Uchar *c, Uchar *s)
354{
355  int i;
356  c = c + 5;
357  for (i = 0; (i < 13 && *c != 0x0A); i++)
358    *(s++) = *(c++);
359  *s = 0;
360  while (i-- && (*--s == 0x20)) *s = 0;
361}
362
363static void
364get_dst_timing_section(Uchar *c, struct std_timings *t,
365		       struct edid_version *v)
366{
367  int j;
368    c = c + 5;
369    for (j = 0; j < 5; j++) {
370	t[j].hsize = HSIZE1;
371	VSIZE1(t[j].vsize);
372	t[j].refresh = REFRESH_R;
373	t[j].id = STD_TIMING_ID;
374	NEXT_STD_TIMING;
375    }
376}
377
378static void
379get_monitor_ranges(Uchar *c, struct monitor_ranges *r)
380{
381    r->min_v = MIN_V;
382    r->max_v = MAX_V;
383    r->min_h = MIN_H;
384    r->max_h = MAX_H;
385    r->max_clock = 0;
386    if(MAX_CLOCK != 0xff) /* is specified? */
387	r->max_clock = MAX_CLOCK * 10;
388    if (HAVE_2ND_GTF) {
389	r->gtf_2nd_f = F_2ND_GTF;
390	r->gtf_2nd_c = C_2ND_GTF;
391	r->gtf_2nd_m = M_2ND_GTF;
392	r->gtf_2nd_k = K_2ND_GTF;
393	r->gtf_2nd_j = J_2ND_GTF;
394    } else {
395	r->gtf_2nd_f = 0;
396    }
397    if (HAVE_CVT) {
398	r->max_clock_khz = MAX_CLOCK_KHZ;
399	r->max_clock = r->max_clock_khz / 1000;
400	r->maxwidth = MAXWIDTH;
401	r->supported_aspect = SUPPORTED_ASPECT;
402	r->preferred_aspect = PREFERRED_ASPECT;
403	r->supported_blanking = SUPPORTED_BLANKING;
404	r->supported_scaling = SUPPORTED_SCALING;
405	r->preferred_refresh = PREFERRED_REFRESH;
406    } else {
407	r->max_clock_khz = 0;
408    }
409}
410
411static void
412get_whitepoint_section(Uchar *c, struct whitePoints *wp)
413{
414    wp[0].white_x = WHITEX1;
415    wp[0].white_y = WHITEY1;
416    wp[1].white_x = WHITEX2;
417    wp[1].white_y = WHITEY2;
418    wp[0].index  = WHITE_INDEX1;
419    wp[1].index  = WHITE_INDEX2;
420    wp[0].white_gamma  = WHITE_GAMMA1;
421    wp[1].white_gamma  = WHITE_GAMMA2;
422}
423
424static void
425get_detailed_timing_section(Uchar *c, struct detailed_timings *r)
426{
427  r->clock = PIXEL_CLOCK;
428  r->h_active = H_ACTIVE;
429  r->h_blanking = H_BLANK;
430  r->v_active = V_ACTIVE;
431  r->v_blanking = V_BLANK;
432  r->h_sync_off = H_SYNC_OFF;
433  r->h_sync_width = H_SYNC_WIDTH;
434  r->v_sync_off = V_SYNC_OFF;
435  r->v_sync_width = V_SYNC_WIDTH;
436  r->h_size = H_SIZE;
437  r->v_size = V_SIZE;
438  r->h_border = H_BORDER;
439  r->v_border = V_BORDER;
440  r->interlaced = INTERLACED;
441  r->stereo = STEREO;
442  r->stereo_1 = STEREO1;
443  r->sync = SYNC_T;
444  r->misc = MISC;
445}
446
447#define MAX_EDID_MINOR 4
448
449static Bool
450validate_version(int scrnIndex, struct edid_version *r)
451{
452    if (r->version != 1) {
453	xf86DrvMsg(scrnIndex, X_ERROR, "Unknown EDID version %d\n",
454		   r->version);
455	return FALSE;
456    }
457
458    if (r->revision > MAX_EDID_MINOR)
459	xf86DrvMsg(scrnIndex, X_WARNING,
460		   "Assuming version 1.%d is compatible with 1.%d\n",
461		   r->revision, MAX_EDID_MINOR);
462
463    return TRUE;
464}
465
466/*
467 * Returns true if HDMI, false if definitely not or unknown.
468 */
469_X_EXPORT Bool
470xf86MonitorIsHDMI(xf86MonPtr mon)
471{
472    int i = 0, version, offset;
473    char *edid = NULL;
474
475    if (!mon)
476       return FALSE;
477
478    if (!(mon->flags & EDID_COMPLETE_RAWDATA))
479       return FALSE;
480
481    if (!mon->no_sections)
482       return FALSE;
483
484    edid = (char *)mon->rawData;
485    if (!edid)
486       return FALSE;
487
488    /* find the CEA extension block */
489    for (i = 1; i <= mon->no_sections; i++)
490       if (edid[i * 128] == 0x02)
491           break;
492    if (i == mon->no_sections + 1)
493       return FALSE;
494    edid += (i * 128);
495
496    version = edid[1];
497    offset = edid[2];
498    if (version < 3 || offset < 4)
499       return FALSE;
500
501    /* walk the cea data blocks */
502    for (i = 4; i < offset; i += (edid[i] & 0x1f) + 1) {
503       char *x = edid + i;
504
505       /* find a vendor specific block */
506       if ((x[0] & 0xe0) >> 5 == 0x03) {
507           int oui = (x[3] << 16) + (x[2] << 8) + x[1];
508
509           /* find the HDMI vendor OUI */
510           if (oui == 0x000c03)
511               return TRUE;
512       }
513    }
514
515    /* guess it's not HDMI after all */
516    return FALSE;
517}
518