xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/ddc/interpret_edid.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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  * 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:
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 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.
23  *
24  * interpret_edid.c: interpret a primary EDID block
25  */
26 
27 #ifdef HAVE_XORG_CONFIG_H
28 #include <xorg-config.h>
29 #endif
30 
31 #include "misc.h"
32 #include "xf86.h"
33 #include "xf86_OSproc.h"
34 #define _PARSE_EDID_
35 #include "xf86DDC.h"
36 #include <string.h>
37 
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 *);
57 
58 static void
find_ranges_section(struct detailed_monitor_section * det,void * ranges)59 find_ranges_section(struct detailed_monitor_section *det, void *ranges)
60 {
61     if (det->type == DS_RANGES && det->section.ranges.max_clock)
62         *(struct monitor_ranges **) ranges = &det->section.ranges;
63 }
64 
65 static void
find_max_detailed_clock(struct detailed_monitor_section * det,void * ret)66 find_max_detailed_clock(struct detailed_monitor_section *det, void *ret)
67 {
68     if (det->type == DT) {
69         *(int *) ret = max(*((int *) ret), det->section.d_timings.clock);
70     }
71 }
72 
73 static void
handle_edid_quirks(xf86MonPtr m)74 handle_edid_quirks(xf86MonPtr m)
75 {
76     struct monitor_ranges *ranges = NULL;
77 
78     /*
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.
83      */
84 
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) {
88         int clock = 0;
89 
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;
95         }
96     }
97 }
98 
99 struct det_hv_parameter {
100     int real_hsize;
101     int real_vsize;
102     float target_aspect;
103 };
104 
105 static void
handle_detailed_hvsize(struct detailed_monitor_section * det_mon,void * data)106 handle_detailed_hvsize(struct detailed_monitor_section *det_mon, void *data)
107 {
108     struct det_hv_parameter *p = (struct det_hv_parameter *) data;
109     float timing_aspect;
110 
111     if (det_mon->type == DT) {
112         struct detailed_timings *timing;
113 
114         timing = &det_mon->section.d_timings;
115 
116         if (!timing->v_size)
117             return;
118 
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);
123         }
124     }
125 }
126 
127 static void
encode_aspect_ratio(xf86MonPtr m)128 encode_aspect_ratio(xf86MonPtr m)
129 {
130     /*
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.
134      */
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)) {
139 
140         struct det_hv_parameter p;
141 
142         p.real_hsize = 0;
143         p.real_vsize = 0;
144         p.target_aspect = (float) m->features.hsize / m->features.vsize;
145 
146         xf86ForEachDetailedBlock(m, handle_detailed_hvsize, &p);
147 
148         if (!p.real_hsize || !p.real_vsize) {
149             m->features.hsize = m->features.vsize = 0;
150         }
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;
155         }
156         else {
157             /* convert mm to cm */
158             m->features.hsize = (p.real_hsize + 5) / 10;
159             m->features.vsize = (p.real_vsize + 5) / 10;
160         }
161 
162         xf86Msg(X_INFO, "Quirked EDID physical size to %dx%d cm\n",
163                 m->features.hsize, m->features.vsize);
164     }
165 }
166 
167 xf86MonPtr
xf86InterpretEDID(int scrnIndex,Uchar * block)168 xf86InterpretEDID(int scrnIndex, Uchar * block)
169 {
170     xf86MonPtr m;
171 
172     if (!block)
173         return NULL;
174     if (!(m = xnfcalloc(sizeof(xf86Monitor), 1)))
175         return NULL;
176     m->scrnIndex = scrnIndex;
177     m->rawData = block;
178 
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))
182         goto error;
183     get_display_section(SECTION(DISPLAY_SECTION, block), &m->features, &m->ver);
184     get_established_timing_section(SECTION(ESTABLISHED_TIMING_SECTION, block),
185                                    &m->timings1);
186     get_std_timing_section(SECTION(STD_TIMING_SECTION, block), m->timings2,
187                            &m->ver);
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);
190 
191     handle_edid_quirks(m);
192     encode_aspect_ratio(m);
193 
194     return m;
195 
196  error:
197     free(m);
198     return NULL;
199 }
200 
201 static int
get_cea_detail_timing(Uchar * blk,xf86MonPtr mon,struct detailed_monitor_section * det_mon)202 get_cea_detail_timing(Uchar * blk, xf86MonPtr mon,
203                       struct detailed_monitor_section *det_mon)
204 {
205     int dt_num;
206     int dt_offset = ((struct cea_ext_body *) blk)->dt_offset;
207 
208     dt_num = 0;
209 
210     if (dt_offset < CEA_EXT_MIN_DATA_OFFSET)
211         return dt_num;
212 
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)) {
215 
216         fetch_detailed_block(blk + dt_offset, &mon->ver, det_mon + dt_num);
217         dt_num = dt_num + 1;
218     }
219 
220     return dt_num;
221 }
222 
223 static void
handle_cea_detail_block(Uchar * ext,xf86MonPtr mon,handle_detailed_fn fn,void * data)224 handle_cea_detail_block(Uchar * ext, xf86MonPtr mon,
225                         handle_detailed_fn fn, void *data)
226 {
227     int i;
228     struct detailed_monitor_section det_mon[CEA_EXT_DET_TIMING_NUM];
229     int det_mon_num;
230 
231     det_mon_num = get_cea_detail_timing(ext, mon, det_mon);
232 
233     for (i = 0; i < det_mon_num; i++)
234         fn(det_mon + i, data);
235 }
236 
237 void
xf86ForEachDetailedBlock(xf86MonPtr mon,handle_detailed_fn fn,void * data)238 xf86ForEachDetailedBlock(xf86MonPtr mon, handle_detailed_fn fn, void *data)
239 {
240     int i;
241     Uchar *ext;
242 
243     if (mon == NULL)
244         return;
245 
246     for (i = 0; i < DET_TIMINGS; i++)
247         fn(mon->det_mon + i, data);
248 
249     for (i = 0; i < mon->no_sections; i++) {
250         ext = mon->rawData + EDID1_LEN * (i + 1);
251         switch (ext[EXT_TAG]) {
252         case CEA_EXT:
253             handle_cea_detail_block(ext, mon, fn, data);
254             break;
255         case VTB_EXT:
256         case DI_EXT:
257         case LS_EXT:
258         case MI_EXT:
259             break;
260         }
261     }
262 }
263 
264 static struct cea_data_block *
extract_cea_data_block(Uchar * ext,int data_type)265 extract_cea_data_block(Uchar * ext, int data_type)
266 {
267     struct cea_ext_body *cea;
268     struct cea_data_block *data_collection;
269     struct cea_data_block *data_end;
270 
271     cea = (struct cea_ext_body *) ext;
272 
273     if (cea->dt_offset <= CEA_EXT_MIN_DATA_OFFSET)
274         return NULL;
275 
276     data_collection = &cea->data_collection;
277     data_end = (struct cea_data_block *) (cea->dt_offset + ext);
278 
279     for (; data_collection < data_end;) {
280 
281         if (data_type == data_collection->tag) {
282             return data_collection;
283         }
284         data_collection = (void *) ((unsigned char *) data_collection +
285                                     data_collection->len + 1);
286     }
287 
288     return NULL;
289 }
290 
291 static void
handle_cea_video_block(Uchar * ext,handle_video_fn fn,void * data)292 handle_cea_video_block(Uchar * ext, handle_video_fn fn, void *data)
293 {
294     struct cea_video_block *video;
295     struct cea_video_block *video_end;
296     struct cea_data_block *data_collection;
297 
298     data_collection = extract_cea_data_block(ext, CEA_VIDEO_BLK);
299     if (data_collection == NULL)
300         return;
301 
302     video = &data_collection->u.video;
303     video_end = (struct cea_video_block *)
304         ((Uchar *) video + data_collection->len);
305 
306     for (; video < video_end; video = video + 1) {
307         fn(video, data);
308     }
309 }
310 
311 void
xf86ForEachVideoBlock(xf86MonPtr mon,handle_video_fn fn,void * data)312 xf86ForEachVideoBlock(xf86MonPtr mon, handle_video_fn fn, void *data)
313 {
314     int i;
315     Uchar *ext;
316 
317     if (mon == NULL)
318         return;
319 
320     for (i = 0; i < mon->no_sections; i++) {
321         ext = mon->rawData + EDID1_LEN * (i + 1);
322         switch (ext[EXT_TAG]) {
323         case CEA_EXT:
324             handle_cea_video_block(ext, fn, data);
325             break;
326         case VTB_EXT:
327         case DI_EXT:
328         case LS_EXT:
329         case MI_EXT:
330             break;
331         }
332     }
333 }
334 
335 static Bool
cea_db_offsets(Uchar * cea,int * start,int * end)336 cea_db_offsets(Uchar *cea, int *start, int *end)
337 {
338     /* Data block offset in CEA extension block */
339     *start = CEA_EXT_MIN_DATA_OFFSET;
340     *end = cea[2];
341     if (*end == 0)
342         *end = CEA_EXT_MAX_DATA_OFFSET;
343     if (*end < CEA_EXT_MIN_DATA_OFFSET || *end > CEA_EXT_MAX_DATA_OFFSET)
344         return FALSE;
345     return TRUE;
346 }
347 
348 static int
cea_db_len(Uchar * db)349 cea_db_len(Uchar *db)
350 {
351     return db[0] & 0x1f;
352 }
353 
354 static int
cea_db_tag(Uchar * db)355 cea_db_tag(Uchar *db)
356 {
357     return db[0] >> 5;
358 }
359 
360 typedef void (*handle_cea_db_fn) (Uchar *, void *);
361 
362 static void
cea_for_each_db(xf86MonPtr mon,handle_cea_db_fn fn,void * data)363 cea_for_each_db(xf86MonPtr mon, handle_cea_db_fn fn, void *data)
364 {
365     int i;
366 
367     if (!mon)
368         return;
369 
370     if (!(mon->flags & EDID_COMPLETE_RAWDATA))
371         return;
372 
373     if (!mon->no_sections)
374         return;
375 
376     if (!mon->rawData)
377         return;
378 
379     for (i = 0; i < mon->no_sections; i++) {
380         int start, end, offset;
381         Uchar *ext;
382 
383         ext = mon->rawData + EDID1_LEN * (i + 1);
384         if (ext[EXT_TAG] != CEA_EXT)
385             continue;
386 
387         if (!cea_db_offsets(ext, &start, &end))
388             continue;
389 
390         for (offset = start;
391              offset < end && offset + cea_db_len(&ext[offset]) < end;
392              offset += cea_db_len(&ext[offset]) + 1)
393                 fn(&ext[offset], data);
394     }
395 }
396 
397 struct find_hdmi_block_data {
398     struct cea_data_block *hdmi;
399 };
400 
find_hdmi_block(Uchar * db,void * data)401 static void find_hdmi_block(Uchar *db, void *data)
402 {
403     struct find_hdmi_block_data *result = data;
404     int oui;
405 
406     if (cea_db_tag(db) != CEA_VENDOR_BLK)
407         return;
408 
409     if (cea_db_len(db) < 5)
410         return;
411 
412     oui = (db[3] << 16) | (db[2] << 8) | db[1];
413     if (oui == IEEE_ID_HDMI)
414         result->hdmi = (struct cea_data_block *)db;
415 }
416 
xf86MonitorFindHDMIBlock(xf86MonPtr mon)417 struct cea_data_block *xf86MonitorFindHDMIBlock(xf86MonPtr mon)
418 {
419     struct find_hdmi_block_data result = { NULL };
420 
421     cea_for_each_db(mon, find_hdmi_block, &result);
422 
423     return result.hdmi;
424 }
425 
426 xf86MonPtr
xf86InterpretEEDID(int scrnIndex,Uchar * block)427 xf86InterpretEEDID(int scrnIndex, Uchar * block)
428 {
429     xf86MonPtr m;
430 
431     m = xf86InterpretEDID(scrnIndex, block);
432     if (!m)
433         return NULL;
434 
435     /* extension parse */
436 
437     return m;
438 }
439 
440 static void
get_vendor_section(Uchar * c,struct vendor * r)441 get_vendor_section(Uchar * c, struct vendor *r)
442 {
443     r->name[0] = L1;
444     r->name[1] = L2;
445     r->name[2] = L3;
446     r->name[3] = '\0';
447 
448     r->prod_id = PROD_ID;
449     r->serial = SERIAL_NO;
450     r->week = WEEK;
451     r->year = YEAR;
452 }
453 
454 static void
get_version_section(Uchar * c,struct edid_version * r)455 get_version_section(Uchar * c, struct edid_version *r)
456 {
457     r->version = VERSION;
458     r->revision = REVISION;
459 }
460 
461 static void
get_display_section(Uchar * c,struct disp_features * r,struct edid_version * v)462 get_display_section(Uchar * c, struct disp_features *r, struct edid_version *v)
463 {
464     r->input_type = INPUT_TYPE;
465     if (!DIGITAL(r->input_type)) {
466         r->input_voltage = INPUT_VOLTAGE;
467         r->input_setup = SETUP;
468         r->input_sync = SYNC;
469     }
470     else if (v->revision == 2 || v->revision == 3) {
471         r->input_dfp = DFP;
472     }
473     else if (v->revision >= 4) {
474         r->input_bpc = BPC;
475         r->input_interface = DIGITAL_INTERFACE;
476     }
477     r->hsize = HSIZE_MAX;
478     r->vsize = VSIZE_MAX;
479     r->gamma = GAMMA;
480     r->dpms = DPMS;
481     r->display_type = DISPLAY_TYPE;
482     r->msc = MSC;
483     r->redx = REDX;
484     r->redy = REDY;
485     r->greenx = GREENX;
486     r->greeny = GREENY;
487     r->bluex = BLUEX;
488     r->bluey = BLUEY;
489     r->whitex = WHITEX;
490     r->whitey = WHITEY;
491 }
492 
493 static void
get_established_timing_section(Uchar * c,struct established_timings * r)494 get_established_timing_section(Uchar * c, struct established_timings *r)
495 {
496     r->t1 = T1;
497     r->t2 = T2;
498     r->t_manu = T_MANU;
499 }
500 
501 static void
get_cvt_timing_section(Uchar * c,struct cvt_timings * r)502 get_cvt_timing_section(Uchar * c, struct cvt_timings *r)
503 {
504     int i;
505 
506     for (i = 0; i < 4; i++) {
507         if (c[0] && c[1] && c[2]) {
508             r[i].height = (c[0] + ((c[1] & 0xF0) << 8) + 1) * 2;
509             switch (c[1] & 0xc0) {
510             case 0x00:
511                 r[i].width = r[i].height * 4 / 3;
512                 break;
513             case 0x40:
514                 r[i].width = r[i].height * 16 / 9;
515                 break;
516             case 0x80:
517                 r[i].width = r[i].height * 16 / 10;
518                 break;
519             case 0xc0:
520                 r[i].width = r[i].height * 15 / 9;
521                 break;
522             }
523             switch (c[2] & 0x60) {
524             case 0x00:
525                 r[i].rate = 50;
526                 break;
527             case 0x20:
528                 r[i].rate = 60;
529                 break;
530             case 0x40:
531                 r[i].rate = 75;
532                 break;
533             case 0x60:
534                 r[i].rate = 85;
535                 break;
536             }
537             r[i].rates = c[2] & 0x1f;
538         }
539         else {
540             return;
541         }
542         c += 3;
543     }
544 }
545 
546 static void
get_std_timing_section(Uchar * c,struct std_timings * r,struct edid_version * v)547 get_std_timing_section(Uchar * c, struct std_timings *r, struct edid_version *v)
548 {
549     int i;
550 
551     for (i = 0; i < STD_TIMINGS; i++) {
552         if (VALID_TIMING) {
553             r[i].hsize = HSIZE1;
554             VSIZE1(r[i].vsize);
555             r[i].refresh = REFRESH_R;
556             r[i].id = STD_TIMING_ID;
557         }
558         else {
559             r[i].hsize = r[i].vsize = r[i].refresh = r[i].id = 0;
560         }
561         NEXT_STD_TIMING;
562     }
563 }
564 
565 static const unsigned char empty_block[18];
566 
567 static void
fetch_detailed_block(Uchar * c,struct edid_version * ver,struct detailed_monitor_section * det_mon)568 fetch_detailed_block(Uchar * c, struct edid_version *ver,
569                      struct detailed_monitor_section *det_mon)
570 {
571     if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) {
572         switch (MONITOR_DESC_TYPE) {
573         case SERIAL_NUMBER:
574             det_mon->type = DS_SERIAL;
575             copy_string(c, det_mon->section.serial);
576             break;
577         case ASCII_STR:
578             det_mon->type = DS_ASCII_STR;
579             copy_string(c, det_mon->section.ascii_data);
580             break;
581         case MONITOR_RANGES:
582             det_mon->type = DS_RANGES;
583             get_monitor_ranges(c, &det_mon->section.ranges);
584             break;
585         case MONITOR_NAME:
586             det_mon->type = DS_NAME;
587             copy_string(c, det_mon->section.name);
588             break;
589         case ADD_COLOR_POINT:
590             det_mon->type = DS_WHITE_P;
591             get_whitepoint_section(c, det_mon->section.wp);
592             break;
593         case ADD_STD_TIMINGS:
594             det_mon->type = DS_STD_TIMINGS;
595             get_dst_timing_section(c, det_mon->section.std_t, ver);
596             break;
597         case COLOR_MANAGEMENT_DATA:
598             det_mon->type = DS_CMD;
599             break;
600         case CVT_3BYTE_DATA:
601             det_mon->type = DS_CVT;
602             get_cvt_timing_section(c, det_mon->section.cvt);
603             break;
604         case ADD_EST_TIMINGS:
605             det_mon->type = DS_EST_III;
606             memcpy(det_mon->section.est_iii, c + 6, 6);
607             break;
608         case ADD_DUMMY:
609             det_mon->type = DS_DUMMY;
610             break;
611         default:
612             det_mon->type = DS_UNKOWN;
613             break;
614         }
615         if (c[3] <= 0x0F && memcmp(c, empty_block, sizeof(empty_block))) {
616             det_mon->type = DS_VENDOR + c[3];
617         }
618     }
619     else {
620         det_mon->type = DT;
621         get_detailed_timing_section(c, &det_mon->section.d_timings);
622     }
623 }
624 
625 static void
get_dt_md_section(Uchar * c,struct edid_version * ver,struct detailed_monitor_section * det_mon)626 get_dt_md_section(Uchar * c, struct edid_version *ver,
627                   struct detailed_monitor_section *det_mon)
628 {
629     int i;
630 
631     for (i = 0; i < DET_TIMINGS; i++) {
632         fetch_detailed_block(c, ver, det_mon + i);
633         NEXT_DT_MD_SECTION;
634     }
635 }
636 
637 static void
copy_string(Uchar * c,Uchar * s)638 copy_string(Uchar * c, Uchar * s)
639 {
640     int i;
641 
642     c = c + 5;
643     for (i = 0; (i < 13 && *c != 0x0A); i++)
644         *(s++) = *(c++);
645     *s = 0;
646     while (i-- && (*--s == 0x20))
647         *s = 0;
648 }
649 
650 static void
get_dst_timing_section(Uchar * c,struct std_timings * t,struct edid_version * v)651 get_dst_timing_section(Uchar * c, struct std_timings *t, struct edid_version *v)
652 {
653     int j;
654 
655     c = c + 5;
656     for (j = 0; j < 5; j++) {
657         t[j].hsize = HSIZE1;
658         VSIZE1(t[j].vsize);
659         t[j].refresh = REFRESH_R;
660         t[j].id = STD_TIMING_ID;
661         NEXT_STD_TIMING;
662     }
663 }
664 
665 static void
get_monitor_ranges(Uchar * c,struct monitor_ranges * r)666 get_monitor_ranges(Uchar * c, struct monitor_ranges *r)
667 {
668     r->min_v = MIN_V;
669     r->max_v = MAX_V;
670     r->min_h = MIN_H;
671     r->max_h = MAX_H;
672     r->max_clock = 0;
673     if (MAX_CLOCK != 0xff)      /* is specified? */
674         r->max_clock = MAX_CLOCK * 10 + 5;
675 
676     r->display_range_timing_flags = c[10];
677 
678     if (HAVE_2ND_GTF) {
679         r->gtf_2nd_f = F_2ND_GTF;
680         r->gtf_2nd_c = C_2ND_GTF;
681         r->gtf_2nd_m = M_2ND_GTF;
682         r->gtf_2nd_k = K_2ND_GTF;
683         r->gtf_2nd_j = J_2ND_GTF;
684     }
685     else {
686         r->gtf_2nd_f = 0;
687     }
688     if (HAVE_CVT) {
689         r->max_clock_khz = MAX_CLOCK_KHZ;
690         r->max_clock = r->max_clock_khz / 1000;
691         r->maxwidth = MAXWIDTH;
692         r->supported_aspect = SUPPORTED_ASPECT;
693         r->preferred_aspect = PREFERRED_ASPECT;
694         r->supported_blanking = SUPPORTED_BLANKING;
695         r->supported_scaling = SUPPORTED_SCALING;
696         r->preferred_refresh = PREFERRED_REFRESH;
697     }
698     else {
699         r->max_clock_khz = 0;
700     }
701 }
702 
703 static void
get_whitepoint_section(Uchar * c,struct whitePoints * wp)704 get_whitepoint_section(Uchar * c, struct whitePoints *wp)
705 {
706     wp[0].white_x = WHITEX1;
707     wp[0].white_y = WHITEY1;
708     wp[1].white_x = WHITEX2;
709     wp[1].white_y = WHITEY2;
710     wp[0].index = WHITE_INDEX1;
711     wp[1].index = WHITE_INDEX2;
712     wp[0].white_gamma = WHITE_GAMMA1;
713     wp[1].white_gamma = WHITE_GAMMA2;
714 }
715 
716 static void
get_detailed_timing_section(Uchar * c,struct detailed_timings * r)717 get_detailed_timing_section(Uchar * c, struct detailed_timings *r)
718 {
719     r->clock = PIXEL_CLOCK;
720     r->h_active = H_ACTIVE;
721     r->h_blanking = H_BLANK;
722     r->v_active = V_ACTIVE;
723     r->v_blanking = V_BLANK;
724     r->h_sync_off = H_SYNC_OFF;
725     r->h_sync_width = H_SYNC_WIDTH;
726     r->v_sync_off = V_SYNC_OFF;
727     r->v_sync_width = V_SYNC_WIDTH;
728     r->h_size = H_SIZE;
729     r->v_size = V_SIZE;
730     r->h_border = H_BORDER;
731     r->v_border = V_BORDER;
732     r->interlaced = INTERLACED;
733     r->stereo = STEREO;
734     r->stereo_1 = STEREO1;
735     r->sync = SYNC_T;
736     r->misc = MISC;
737 }
738 
739 #define MAX_EDID_MINOR 4
740 
741 static Bool
validate_version(int scrnIndex,struct edid_version * r)742 validate_version(int scrnIndex, struct edid_version *r)
743 {
744     if (r->version != 1) {
745         xf86DrvMsg(scrnIndex, X_ERROR, "Unknown EDID version %d\n", r->version);
746         return FALSE;
747     }
748 
749     if (r->revision > MAX_EDID_MINOR)
750         xf86DrvMsg(scrnIndex, X_WARNING,
751                    "Assuming version 1.%d is compatible with 1.%d\n",
752                    r->revision, MAX_EDID_MINOR);
753 
754     return TRUE;
755 }
756 
757 Bool
gtf_supported(xf86MonPtr mon)758 gtf_supported(xf86MonPtr mon)
759 {
760     int i;
761 
762     if (!mon)
763         return FALSE;
764 
765     if ((mon->ver.version == 1) && (mon->ver.revision < 4)) {
766         if (mon->features.msc & 0x1)
767 	    return TRUE;
768     } else {
769         for (i = 0; i < DET_TIMINGS; i++) {
770             struct detailed_monitor_section *det_timing_des = &(mon->det_mon[i]);
771             if (det_timing_des && (det_timing_des->type == DS_RANGES) &&
772                 (det_timing_des->section.ranges.display_range_timing_flags == DR_DEFAULT_GTF
773 		|| det_timing_des->section.ranges.display_range_timing_flags == DR_SECONDARY_GTF))
774 		    return TRUE;
775 	}
776     }
777 
778     return FALSE;
779 }
780 
781 /*
782  * Returns true if HDMI, false if definitely not or unknown.
783  */
784 Bool
xf86MonitorIsHDMI(xf86MonPtr mon)785 xf86MonitorIsHDMI(xf86MonPtr mon)
786 {
787     return xf86MonitorFindHDMIBlock(mon) != NULL;
788 }
789