interpret_edid.c revision 05b261ec
1
2/* interpret_edid.c: interpret a primary EDID block
3 *
4 * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
5 */
6#ifdef HAVE_XORG_CONFIG_H
7#include <xorg-config.h>
8#endif
9
10#include "misc.h"
11#include "xf86.h"
12#include "xf86_OSproc.h"
13#define _PARSE_EDID_
14#include "xf86DDC.h"
15#include <string.h>
16
17static void get_vendor_section(Uchar*, struct vendor *);
18static void get_version_section(Uchar*, struct edid_version *);
19static void get_display_section(Uchar*, struct disp_features *,
20				struct edid_version *);
21static void get_established_timing_section(Uchar*, struct established_timings *);
22static void get_std_timing_section(Uchar*, struct std_timings *,
23				   struct edid_version *);
24static void get_dt_md_section(Uchar *, struct edid_version *,
25			      struct detailed_monitor_section *det_mon);
26static void copy_string(Uchar *, Uchar *);
27static void get_dst_timing_section(Uchar *, struct std_timings *,
28				   struct edid_version *);
29static void get_monitor_ranges(Uchar *, struct monitor_ranges *);
30static void get_whitepoint_section(Uchar *, struct whitePoints *);
31static void get_detailed_timing_section(Uchar*, struct 	detailed_timings *);
32static Bool validate_version(int scrnIndex, struct edid_version *);
33
34static void
35handle_edid_quirks(xf86MonPtr m)
36{
37    int i, j;
38    struct detailed_timings *preferred_timing;
39    struct monitor_ranges *ranges;
40
41    /*
42     * max_clock is only encoded in EDID in tens of MHz, so occasionally we
43     * find a monitor claiming a max of 160 with a mode requiring 162, or
44     * similar.  Strictly we should refuse to round up too far, but let's
45     * see how well this works.
46     */
47    for (i = 0; i < 4; i++) {
48	if (m->det_mon[i].type == DS_RANGES) {
49	    ranges = &m->det_mon[i].section.ranges;
50	    for (j = 0; j < 4; j++) {
51		if (m->det_mon[j].type == DT) {
52		    preferred_timing = &m->det_mon[j].section.d_timings;
53		    if (!ranges->max_clock) continue; /* zero is legal */
54		    if (ranges->max_clock * 1000000 < preferred_timing->clock) {
55			xf86Msg(X_WARNING,
56			    "EDID preferred timing clock %.2fMHz exceeds "
57			    "claimed max %dMHz, fixing\n",
58			    preferred_timing->clock / 1.0e6,
59			    ranges->max_clock);
60			ranges->max_clock =
61			    (preferred_timing->clock+999999)/1000000;
62			return;
63		    }
64		}
65	    }
66	}
67    }
68}
69
70xf86MonPtr
71xf86InterpretEDID(int scrnIndex, Uchar *block)
72{
73    xf86MonPtr m;
74
75    if (!block) return NULL;
76    if (! (m = xnfcalloc(sizeof(xf86Monitor),1))) return NULL;
77    m->scrnIndex = scrnIndex;
78    m->rawData = block;
79
80    get_vendor_section(SECTION(VENDOR_SECTION,block),&m->vendor);
81    get_version_section(SECTION(VERSION_SECTION,block),&m->ver);
82    if (!validate_version(scrnIndex, &m->ver)) goto error;
83    get_display_section(SECTION(DISPLAY_SECTION,block),&m->features,
84			&m->ver);
85    get_established_timing_section(SECTION(ESTABLISHED_TIMING_SECTION,block),
86				   &m->timings1);
87    get_std_timing_section(SECTION(STD_TIMING_SECTION,block),m->timings2,
88			   &m->ver);
89    get_dt_md_section(SECTION(DET_TIMING_SECTION,block),&m->ver, m->det_mon);
90    m->no_sections = (int)*(char *)SECTION(NO_EDID,block);
91
92    handle_edid_quirks(m);
93
94    return (m);
95
96 error:
97    xfree(m);
98    return NULL;
99}
100
101static void
102get_vendor_section(Uchar *c, struct vendor *r)
103{
104    r->name[0] = L1;
105    r->name[1] = L2;
106    r->name[2] = L3;
107    r->name[3] = '\0';
108
109    r->prod_id = PROD_ID;
110    r->serial  = SERIAL_NO;
111    r->week    = WEEK;
112    r->year    = YEAR;
113}
114
115static void
116get_version_section(Uchar *c, struct edid_version *r)
117{
118    r->version  = VERSION;
119    r->revision = REVISION;
120}
121
122static void
123get_display_section(Uchar *c, struct disp_features *r,
124		    struct edid_version *v)
125{
126    r->input_type = INPUT_TYPE;
127    if (!DIGITAL(r->input_type)) {
128	r->input_voltage = INPUT_VOLTAGE;
129	r->input_setup = SETUP;
130	r->input_sync = SYNC;
131    } else if (v->version > 1 || v->revision > 2)
132	r->input_dfp = DFP;
133    r->hsize = HSIZE_MAX;
134    r->vsize = VSIZE_MAX;
135    r->gamma = GAMMA;
136    r->dpms =  DPMS;
137    r->display_type = DISPLAY_TYPE;
138    r->msc = MSC;
139    r->redx = REDX;
140    r->redy = REDY;
141    r->greenx = GREENX;
142    r->greeny = GREENY;
143    r->bluex = BLUEX;
144    r->bluey = BLUEY;
145    r->whitex = WHITEX;
146    r->whitey = WHITEY;
147}
148
149static void
150get_established_timing_section(Uchar *c, struct established_timings *r)
151{
152    r->t1 = T1;
153    r->t2 = T2;
154    r->t_manu = T_MANU;
155}
156
157static void
158get_std_timing_section(Uchar *c, struct std_timings *r,
159		       struct edid_version *v)
160{
161    int i;
162
163    for (i=0;i<STD_TIMINGS;i++){
164	if (VALID_TIMING) {
165	    r[i].hsize = HSIZE1;
166	    VSIZE1(r[i].vsize);
167	    r[i].refresh = REFRESH_R;
168	    r[i].id = STD_TIMING_ID;
169	} else {
170	    r[i].hsize = r[i].vsize = r[i].refresh = r[i].id = 0;
171	}
172	NEXT_STD_TIMING;
173    }
174}
175
176static void
177get_dt_md_section(Uchar *c, struct edid_version *ver,
178		  struct detailed_monitor_section *det_mon)
179{
180  int i;
181
182  for (i=0;i<DET_TIMINGS;i++) {
183    if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) {
184
185      switch (MONITOR_DESC_TYPE) {
186      case SERIAL_NUMBER:
187	det_mon[i].type = DS_SERIAL;
188	copy_string(c,det_mon[i].section.serial);
189	break;
190      case ASCII_STR:
191	det_mon[i].type = DS_ASCII_STR;
192	copy_string(c,det_mon[i].section.ascii_data);
193	break;
194      case MONITOR_RANGES:
195	det_mon[i].type = DS_RANGES;
196	get_monitor_ranges(c,&det_mon[i].section.ranges);
197	break;
198      case MONITOR_NAME:
199	det_mon[i].type = DS_NAME;
200	copy_string(c,det_mon[i].section.name);
201	break;
202      case ADD_COLOR_POINT:
203	det_mon[i].type = DS_WHITE_P;
204	get_whitepoint_section(c,det_mon[i].section.wp);
205	break;
206      case ADD_STD_TIMINGS:
207	det_mon[i].type = DS_STD_TIMINGS;
208	get_dst_timing_section(c,det_mon[i].section.std_t, ver);
209	break;
210      case ADD_DUMMY:
211	det_mon[i].type = DS_DUMMY;
212        break;
213      default:
214        det_mon[i].type = DS_UNKOWN;
215        break;
216      }
217    } else {
218      det_mon[i].type = DT;
219      get_detailed_timing_section(c,&det_mon[i].section.d_timings);
220    }
221    NEXT_DT_MD_SECTION;
222  }
223}
224
225static void
226copy_string(Uchar *c, Uchar *s)
227{
228  int i;
229  c = c + 5;
230  for (i = 0; (i < 13 && *c != 0x0A); i++)
231    *(s++) = *(c++);
232  *s = 0;
233  while (i-- && (*--s == 0x20)) *s = 0;
234}
235
236static void
237get_dst_timing_section(Uchar *c, struct std_timings *t,
238		       struct edid_version *v)
239{
240  int j;
241    c = c + 5;
242    for (j = 0; j < 5; j++) {
243	t[j].hsize = HSIZE1;
244	VSIZE1(t[j].vsize);
245	t[j].refresh = REFRESH_R;
246	t[j].id = STD_TIMING_ID;
247	NEXT_STD_TIMING;
248    }
249}
250
251static void
252get_monitor_ranges(Uchar *c, struct monitor_ranges *r)
253{
254    r->min_v = MIN_V;
255    r->max_v = MAX_V;
256    r->min_h = MIN_H;
257    r->max_h = MAX_H;
258    r->max_clock = 0;
259    if(MAX_CLOCK != 0xff) /* is specified? */
260	r->max_clock = MAX_CLOCK * 10;
261    if (HAVE_2ND_GTF) {
262	r->gtf_2nd_f = F_2ND_GTF;
263	r->gtf_2nd_c = C_2ND_GTF;
264	r->gtf_2nd_m = M_2ND_GTF;
265	r->gtf_2nd_k = K_2ND_GTF;
266	r->gtf_2nd_j = J_2ND_GTF;
267    } else
268	r->gtf_2nd_f = 0;
269}
270
271static void
272get_whitepoint_section(Uchar *c, struct whitePoints *wp)
273{
274    wp[1].white_x = WHITEX1;
275    wp[1].white_y = WHITEY1;
276    wp[2].white_x = WHITEX2;
277    wp[2].white_y = WHITEY2;
278    wp[1].index  = WHITE_INDEX1;
279    wp[2].index  = WHITE_INDEX2;
280    wp[1].white_gamma  = WHITE_GAMMA1;
281    wp[2].white_gamma  = WHITE_GAMMA2;
282}
283
284static void
285get_detailed_timing_section(Uchar *c, struct detailed_timings *r)
286{
287  r->clock = PIXEL_CLOCK;
288  r->h_active = H_ACTIVE;
289  r->h_blanking = H_BLANK;
290  r->v_active = V_ACTIVE;
291  r->v_blanking = V_BLANK;
292  r->h_sync_off = H_SYNC_OFF;
293  r->h_sync_width = H_SYNC_WIDTH;
294  r->v_sync_off = V_SYNC_OFF;
295  r->v_sync_width = V_SYNC_WIDTH;
296  r->h_size = H_SIZE;
297  r->v_size = V_SIZE;
298  r->h_border = H_BORDER;
299  r->v_border = V_BORDER;
300  r->interlaced = INTERLACED;
301  r->stereo = STEREO;
302  r->stereo_1 = STEREO1;
303  r->sync = SYNC_T;
304  r->misc = MISC;
305}
306
307#define MAX_EDID_MINOR 3
308
309static Bool
310validate_version(int scrnIndex, struct edid_version *r)
311{
312    if (r->version != 1)
313	return FALSE;
314
315    if (r->revision > MAX_EDID_MINOR)
316	xf86DrvMsg(scrnIndex, X_WARNING,
317		   "Assuming version 1.%d is compatible with 1.%d\n",
318		   r->revision, MAX_EDID_MINOR);
319
320    return TRUE;
321}
322