xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

interpret_edid.c (21411B)


      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
     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
     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
     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
    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
    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
    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
    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
    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
    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 *
    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
    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
    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
    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
    349 cea_db_len(Uchar *db)
    350 {
    351     return db[0] & 0x1f;
    352 }
    353 
    354 static int
    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
    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 
    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 
    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
    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
    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
    455 get_version_section(Uchar * c, struct edid_version *r)
    456 {
    457     r->version = VERSION;
    458     r->revision = REVISION;
    459 }
    460 
    461 static void
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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) && (mon->features.msc & 0x1) &&
    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
    785 xf86MonitorIsHDMI(xf86MonPtr mon)
    786 {
    787     return xf86MonitorFindHDMIBlock(mon) != NULL;
    788 }