First import
[xorg_rtime.git] / xorg-server-1.4 / hw / xfree86 / ddc / interpret_edid.c
blob7b4b2b9eca8f849a4818baf9c2582ec3fb4cf5e1
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
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>
17 static void get_vendor_section(Uchar*, struct vendor *);
18 static void get_version_section(Uchar*, struct edid_version *);
19 static void get_display_section(Uchar*, struct disp_features *,
20 struct edid_version *);
21 static void get_established_timing_section(Uchar*, struct established_timings *);
22 static void get_std_timing_section(Uchar*, struct std_timings *,
23 struct edid_version *);
24 static void get_dt_md_section(Uchar *, struct edid_version *,
25 struct detailed_monitor_section *det_mon);
26 static void copy_string(Uchar *, Uchar *);
27 static void get_dst_timing_section(Uchar *, struct std_timings *,
28 struct edid_version *);
29 static void get_monitor_ranges(Uchar *, struct monitor_ranges *);
30 static void get_whitepoint_section(Uchar *, struct whitePoints *);
31 static void get_detailed_timing_section(Uchar*, struct detailed_timings *);
32 static Bool validate_version(int scrnIndex, struct edid_version *);
34 static void
35 handle_edid_quirks(xf86MonPtr m)
37 int i, j;
38 struct detailed_timings *preferred_timing;
39 struct monitor_ranges *ranges;
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.
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;
70 xf86MonPtr
71 xf86InterpretEDID(int scrnIndex, Uchar *block)
73 xf86MonPtr m;
75 if (!block) return NULL;
76 if (! (m = xnfcalloc(sizeof(xf86Monitor),1))) return NULL;
77 m->scrnIndex = scrnIndex;
78 m->rawData = block;
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);
92 handle_edid_quirks(m);
94 return (m);
96 error:
97 xfree(m);
98 return NULL;
101 static void
102 get_vendor_section(Uchar *c, struct vendor *r)
104 r->name[0] = L1;
105 r->name[1] = L2;
106 r->name[2] = L3;
107 r->name[3] = '\0';
109 r->prod_id = PROD_ID;
110 r->serial = SERIAL_NO;
111 r->week = WEEK;
112 r->year = YEAR;
115 static void
116 get_version_section(Uchar *c, struct edid_version *r)
118 r->version = VERSION;
119 r->revision = REVISION;
122 static void
123 get_display_section(Uchar *c, struct disp_features *r,
124 struct edid_version *v)
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;
149 static void
150 get_established_timing_section(Uchar *c, struct established_timings *r)
152 r->t1 = T1;
153 r->t2 = T2;
154 r->t_manu = T_MANU;
157 static void
158 get_std_timing_section(Uchar *c, struct std_timings *r,
159 struct edid_version *v)
161 int i;
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;
172 NEXT_STD_TIMING;
176 static void
177 get_dt_md_section(Uchar *c, struct edid_version *ver,
178 struct detailed_monitor_section *det_mon)
180 int i;
182 for (i=0;i<DET_TIMINGS;i++) {
183 if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) {
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;
217 } else {
218 det_mon[i].type = DT;
219 get_detailed_timing_section(c,&det_mon[i].section.d_timings);
221 NEXT_DT_MD_SECTION;
225 static void
226 copy_string(Uchar *c, Uchar *s)
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;
236 static void
237 get_dst_timing_section(Uchar *c, struct std_timings *t,
238 struct edid_version *v)
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;
251 static void
252 get_monitor_ranges(Uchar *c, struct monitor_ranges *r)
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;
271 static void
272 get_whitepoint_section(Uchar *c, struct whitePoints *wp)
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;
284 static void
285 get_detailed_timing_section(Uchar *c, struct detailed_timings *r)
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;
307 #define MAX_EDID_MINOR 3
309 static Bool
310 validate_version(int scrnIndex, struct edid_version *r)
312 if (r->version != 1)
313 return FALSE;
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);
320 return TRUE;