Home | History | Annotate | Line # | Download | only in modes
      1 /*
      2  * Copyright 2006 Luc Verhaegen.
      3  * Copyright 2008 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, sub license,
      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
     13  * next paragraph) shall be included in all copies or substantial portions
     14  * of the 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 NON-INFRINGEMENT. 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 
     25 /**
     26  * @file This file covers code to convert a xf86MonPtr containing EDID-probed
     27  * information into a list of modes, including applying monitor-specific
     28  * quirks to fix broken EDID data.
     29  */
     30 #ifdef HAVE_XORG_CONFIG_H
     31 #include <xorg-config.h>
     32 #else
     33 #ifdef HAVE_CONFIG_H
     34 #include <config.h>
     35 #endif
     36 #endif
     37 
     38 #define _PARSE_EDID_
     39 #include "xf86.h"
     40 #include "xf86DDC.h"
     41 #include <X11/Xatom.h>
     42 #include "property.h"
     43 #include "propertyst.h"
     44 #include "xf86Crtc.h"
     45 #include <string.h>
     46 #include <math.h>
     47 
     48 static void handle_detailed_rblank(struct detailed_monitor_section *det_mon,
     49                                    void *data)
     50 {
     51     if (det_mon->type == DS_RANGES)
     52         if (det_mon->section.ranges.supported_blanking & CVT_REDUCED)
     53             *(Bool*)data = TRUE;
     54 }
     55 
     56 static Bool
     57 xf86MonitorSupportsReducedBlanking(xf86MonPtr DDC)
     58 {
     59     /* EDID 1.4 explicitly defines RB support */
     60     if (DDC->ver.revision >= 4) {
     61         Bool ret = FALSE;
     62 
     63         xf86ForEachDetailedBlock(DDC, handle_detailed_rblank, &ret);
     64         return ret;
     65     }
     66 
     67     /* For anything older, assume digital means RB support. Boo. */
     68     if (DDC->features.input_type)
     69         return TRUE;
     70 
     71     return FALSE;
     72 }
     73 
     74 static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC)
     75 {
     76     /* Belinea 10 15 55 */
     77     if (memcmp (DDC->vendor.name, "MAX", 4) == 0 &&
     78 	((DDC->vendor.prod_id == 1516) ||
     79 	(DDC->vendor.prod_id == 0x77e)))
     80 	return TRUE;
     81 
     82     /* Acer AL1706 */
     83     if (memcmp (DDC->vendor.name, "ACR", 4) == 0 &&
     84 	DDC->vendor.prod_id == 44358)
     85 	return TRUE;
     86 
     87     /* Bug #10814: Samsung SyncMaster 225BW */
     88     if (memcmp (DDC->vendor.name, "SAM", 4) == 0 &&
     89 	DDC->vendor.prod_id == 596)
     90 	return TRUE;
     91 
     92     /* Bug #10545: Samsung SyncMaster 226BW */
     93     if (memcmp (DDC->vendor.name, "SAM", 4) == 0 &&
     94 	DDC->vendor.prod_id == 638)
     95 	return TRUE;
     96 
     97     /* Acer F51 */
     98     if (memcmp (DDC->vendor.name, "API", 4) == 0 &&
     99 	DDC->vendor.prod_id == 0x7602)
    100 	return TRUE;
    101 
    102 
    103     return FALSE;
    104 }
    105 
    106 static Bool quirk_prefer_large_75 (int scrnIndex, xf86MonPtr DDC)
    107 {
    108     /* Bug #11603: Funai Electronics PM36B */
    109     if (memcmp (DDC->vendor.name, "FCM", 4) == 0 &&
    110 	DDC->vendor.prod_id == 13600)
    111 	return TRUE;
    112 
    113     return FALSE;
    114 }
    115 
    116 static Bool quirk_detailed_h_in_cm (int scrnIndex, xf86MonPtr DDC)
    117 {
    118     /* Bug #11603: Funai Electronics PM36B */
    119     if (memcmp (DDC->vendor.name, "FCM", 4) == 0 &&
    120 	DDC->vendor.prod_id == 13600)
    121 	return TRUE;
    122 
    123     return FALSE;
    124 }
    125 
    126 static Bool quirk_detailed_v_in_cm (int scrnIndex, xf86MonPtr DDC)
    127 {
    128     /* Bug #11603: Funai Electronics PM36B */
    129     if (memcmp (DDC->vendor.name, "FCM", 4) == 0 &&
    130 	DDC->vendor.prod_id == 13600)
    131 	return TRUE;
    132 
    133     /* Bug #21000: LGPhilipsLCD LP154W01-TLAJ */
    134     if (memcmp (DDC->vendor.name, "LPL", 4) == 0 &&
    135 	DDC->vendor.prod_id == 47360)
    136 	return TRUE;
    137 
    138     /* Bug #10304: LGPhilipsLCD LP154W01-A5 */
    139     if (memcmp(DDC->vendor.name, "LPL", 4) == 0 &&
    140 	DDC->vendor.prod_id == 0)
    141 	return TRUE;
    142 
    143     /* Bug #24482: LGPhilipsLCD LP154W01-TLA1 */
    144     if (memcmp(DDC->vendor.name, "LPL", 4) == 0 &&
    145 	DDC->vendor.prod_id == 0x2a00)
    146 	return TRUE;
    147 
    148     /* Bug #28414: HP Compaq NC8430 LP154W01-TLA8 */
    149     if (memcmp (DDC->vendor.name, "LPL", 4) == 0 &&
    150 	DDC->vendor.prod_id == 5750)
    151 	return TRUE;
    152 
    153     /* Bug #21750: Samsung Syncmaster 2333HD */
    154     if (memcmp (DDC->vendor.name, "SAM", 4) == 0 &&
    155 	DDC->vendor.prod_id == 1157)
    156 	return TRUE;
    157 
    158     return FALSE;
    159 }
    160 
    161 static Bool quirk_detailed_use_maximum_size (int scrnIndex, xf86MonPtr DDC)
    162 {
    163     /* Bug #21324: Iiyama Vision Master 450 */
    164     if (memcmp (DDC->vendor.name, "IVM", 4) == 0 &&
    165 	DDC->vendor.prod_id == 6400)
    166 	return TRUE;
    167 
    168     /* Bug #41141: Acer Aspire One */
    169     if (memcmp (DDC->vendor.name, "LGD", 4) == 0 &&
    170 	DDC->vendor.prod_id == 0x7f01)
    171 	return TRUE;
    172 
    173     return FALSE;
    174 }
    175 
    176 static Bool quirk_135_clock_too_high (int scrnIndex, xf86MonPtr DDC)
    177 {
    178     /* Envision Peripherals, Inc. EN-7100e.  See bug #9550. */
    179     if (memcmp (DDC->vendor.name, "EPI", 4) == 0 &&
    180 	DDC->vendor.prod_id == 59264)
    181 	return TRUE;
    182 
    183     return FALSE;
    184 }
    185 
    186 static Bool quirk_first_detailed_preferred (int scrnIndex, xf86MonPtr DDC)
    187 {
    188     /* Philips 107p5 CRT. Reported on xorg@ with pastebin. */
    189     if (memcmp (DDC->vendor.name, "PHL", 4) == 0 &&
    190 	DDC->vendor.prod_id == 57364)
    191 	return TRUE;
    192 
    193     /* Proview AY765C 17" LCD. See bug #15160*/
    194     if (memcmp (DDC->vendor.name, "PTS", 4) == 0 &&
    195 	DDC->vendor.prod_id == 765)
    196 	return TRUE;
    197 
    198     /* ACR of some sort RH #284231 */
    199     if (memcmp (DDC->vendor.name, "ACR", 4) == 0 &&
    200 	DDC->vendor.prod_id == 2423)
    201 	return TRUE;
    202 
    203     /* Peacock Ergovision 19.  See rh#492359 */
    204     if (memcmp (DDC->vendor.name, "PEA", 4) == 0 &&
    205 	DDC->vendor.prod_id == 9003)
    206 	return TRUE;
    207 
    208     return FALSE;
    209 }
    210 
    211 static Bool quirk_detailed_sync_pp(int scrnIndex, xf86MonPtr DDC)
    212 {
    213     /* Bug #12439: Samsung SyncMaster 205BW */
    214     if (memcmp (DDC->vendor.name, "SAM", 4) == 0 &&
    215 	DDC->vendor.prod_id == 541)
    216 	return TRUE;
    217     return FALSE;
    218 }
    219 
    220 /* This should probably be made more generic */
    221 static Bool quirk_dvi_single_link(int scrnIndex, xf86MonPtr DDC)
    222 {
    223     /* Red Hat bug #453106: Apple 23" Cinema Display */
    224     if (memcmp (DDC->vendor.name, "APL", 4) == 0 &&
    225 	DDC->vendor.prod_id == 0x921c)
    226 	return TRUE;
    227     return FALSE;
    228 }
    229 
    230 typedef struct {
    231     Bool	(*detect) (int scrnIndex, xf86MonPtr DDC);
    232     ddc_quirk_t	quirk;
    233     char	*description;
    234 } ddc_quirk_map_t;
    235 
    236 static const ddc_quirk_map_t ddc_quirks[] = {
    237     {
    238 	quirk_prefer_large_60,   DDC_QUIRK_PREFER_LARGE_60,
    239 	"Detailed timing is not preferred, use largest mode at 60Hz"
    240     },
    241     {
    242 	quirk_135_clock_too_high,   DDC_QUIRK_135_CLOCK_TOO_HIGH,
    243 	"Recommended 135MHz pixel clock is too high"
    244     },
    245     {
    246 	quirk_prefer_large_75,   DDC_QUIRK_PREFER_LARGE_75,
    247 	"Detailed timing is not preferred, use largest mode at 75Hz"
    248     },
    249     {
    250 	quirk_detailed_h_in_cm,   DDC_QUIRK_DETAILED_H_IN_CM,
    251 	"Detailed timings give horizontal size in cm."
    252     },
    253     {
    254 	quirk_detailed_v_in_cm,   DDC_QUIRK_DETAILED_V_IN_CM,
    255 	"Detailed timings give vertical size in cm."
    256     },
    257     {
    258 	quirk_detailed_use_maximum_size,   DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE,
    259 	"Use maximum size instead of detailed timing sizes."
    260     },
    261     {
    262 	quirk_first_detailed_preferred, DDC_QUIRK_FIRST_DETAILED_PREFERRED,
    263 	"First detailed timing was not marked as preferred."
    264     },
    265     {
    266 	quirk_detailed_sync_pp, DDC_QUIRK_DETAILED_SYNC_PP,
    267 	"Use +hsync +vsync for detailed timing."
    268     },
    269     {
    270 	quirk_dvi_single_link, DDC_QUIRK_DVI_SINGLE_LINK,
    271 	"Forcing maximum pixel clock to single DVI link."
    272     },
    273     {
    274 	NULL,		DDC_QUIRK_NONE,
    275 	"No known quirks"
    276     },
    277 };
    278 
    279 /*
    280  * These more or less come from the DMT spec.  The 720x400 modes are
    281  * inferred from historical 80x25 practice.  The 640x480@67 and 832x624@75
    282  * modes are old-school Mac modes.  The EDID spec says the 1152x864@75 mode
    283  * should be 1152x870, again for the Mac, but instead we use the x864 DMT
    284  * mode.
    285  *
    286  * The DMT modes have been fact-checked; the rest are mild guesses.
    287  */
    288 #define MODEPREFIX NULL, NULL, NULL, 0, M_T_DRIVER
    289 #define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0
    290 
    291 static const DisplayModeRec DDCEstablishedModes[17] = {
    292     { MODEPREFIX,    40000,  800,  840,  968, 1056, 0,  600,  601,  605,  628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */
    293     { MODEPREFIX,    36000,  800,  824,  896, 1024, 0,  600,  601,  603,  625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */
    294     { MODEPREFIX,    31500,  640,  656,  720,  840, 0,  480,  481,  484,  500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */
    295     { MODEPREFIX,    31500,  640,  664,  704,  832, 0,  480,  489,  492,  520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */
    296     { MODEPREFIX,    30240,  640,  704,  768,  864, 0,  480,  483,  486,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@67Hz */
    297     { MODEPREFIX,    25175,  640,  656,  752,  800, 0,  480,  490,  492,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */
    298     { MODEPREFIX,    35500,  720,  738,  846,  900, 0,  400,  421,  423,  449, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 720x400@88Hz */
    299     { MODEPREFIX,    28320,  720,  738,  846,  900, 0,  400,  412,  414,  449, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@70Hz */
    300     { MODEPREFIX,   135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */
    301     { MODEPREFIX,    78750, 1024, 1040, 1136, 1312, 0,  768,  769,  772,  800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */
    302     { MODEPREFIX,    75000, 1024, 1048, 1184, 1328, 0,  768,  771,  777,  806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */
    303     { MODEPREFIX,    65000, 1024, 1048, 1184, 1344, 0,  768,  771,  777,  806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */
    304     { MODEPREFIX,    44900, 1024, 1032, 1208, 1264, 0,  768,  768,  772,  817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz */
    305     { MODEPREFIX,    57284,  832,  864,  928, 1152, 0,  624,  625,  628,  667, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 832x624@75Hz */
    306     { MODEPREFIX,    49500,  800,  816,  896, 1056, 0,  600,  601,  604,  625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */
    307     { MODEPREFIX,    50000,  800,  856,  976, 1040, 0,  600,  637,  643,  666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */
    308     { MODEPREFIX,   108000, 1152, 1216, 1344, 1600, 0,  864,  865,  868,  900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */
    309 };
    310 
    311 static DisplayModePtr
    312 DDCModesFromEstablished(int scrnIndex, struct established_timings *timing,
    313 			ddc_quirk_t quirks)
    314 {
    315     DisplayModePtr Modes = NULL, Mode = NULL;
    316     CARD32 bits = (timing->t1) | (timing->t2 << 8) |
    317         ((timing->t_manu & 0x80) << 9);
    318     int i;
    319 
    320     for (i = 0; i < 17; i++) {
    321         if (bits & (0x01 << i)) {
    322             Mode = xf86DuplicateMode(&DDCEstablishedModes[i]);
    323             Modes = xf86ModesAdd(Modes, Mode);
    324         }
    325     }
    326 
    327     return Modes;
    328 }
    329 
    330 /* Autogenerated from the DMT spec */
    331 const DisplayModeRec DMTModes[] = {
    332     { MODEPREFIX,    31500,  640,  672,  736,  832, 0,  350,  382,  385,  445, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x350@85Hz */
    333     { MODEPREFIX,    31500,  640,  672,  736,  832, 0,  400,  401,  404,  445, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 640x400@85Hz */
    334     { MODEPREFIX,    35500,  720,  756,  828,  936, 0,  400,  401,  404,  446, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@85Hz */
    335     { MODEPREFIX,    25175,  640,  656,  752,  800, 0,  480,  490,  492,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */
    336     { MODEPREFIX,    31500,  640,  664,  704,  832, 0,  480,  489,  492,  520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */
    337     { MODEPREFIX,    31500,  640,  656,  720,  840, 0,  480,  481,  484,  500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */
    338     { MODEPREFIX,    36000,  640,  696,  752,  832, 0,  480,  481,  484,  509, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@85Hz */
    339     { MODEPREFIX,    36000,  800,  824,  896, 1024, 0,  600,  601,  603,  625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */
    340     { MODEPREFIX,    40000,  800,  840,  968, 1056, 0,  600,  601,  605,  628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */
    341     { MODEPREFIX,    50000,  800,  856,  976, 1040, 0,  600,  637,  643,  666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */
    342     { MODEPREFIX,    49500,  800,  816,  896, 1056, 0,  600,  601,  604,  625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */
    343     { MODEPREFIX,    56250,  800,  832,  896, 1048, 0,  600,  601,  604,  631, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@85Hz */
    344     { MODEPREFIX,    73250,  800,  848,  880,  960, 0,  600,  603,  607,  636, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 800x600@120Hz RB */
    345     { MODEPREFIX,    33750,  848,  864,  976, 1088, 0,  480,  486,  494,  517, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 848x480@60Hz */
    346     { MODEPREFIX,    44900, 1024, 1032, 1208, 1264, 0,  768,  768,  772,  817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz (interlaced) */
    347     { MODEPREFIX,    65000, 1024, 1048, 1184, 1344, 0,  768,  771,  777,  806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */
    348     { MODEPREFIX,    75000, 1024, 1048, 1184, 1328, 0,  768,  771,  777,  806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */
    349     { MODEPREFIX,    78750, 1024, 1040, 1136, 1312, 0,  768,  769,  772,  800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */
    350     { MODEPREFIX,    94500, 1024, 1072, 1168, 1376, 0,  768,  769,  772,  808, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@85Hz */
    351     { MODEPREFIX,   115500, 1024, 1072, 1104, 1184, 0,  768,  771,  775,  813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@120Hz RB */
    352     { MODEPREFIX,   108000, 1152, 1216, 1344, 1600, 0,  864,  865,  868,  900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */
    353     { MODEPREFIX,    68250, 1280, 1328, 1360, 1440, 0,  768,  771,  778,  790, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x768@60Hz RB */
    354     { MODEPREFIX,    79500, 1280, 1344, 1472, 1664, 0,  768,  771,  778,  798, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@60Hz */
    355     { MODEPREFIX,   102250, 1280, 1360, 1488, 1696, 0,  768,  771,  778,  805, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@75Hz */
    356     { MODEPREFIX,   117500, 1280, 1360, 1496, 1712, 0,  768,  771,  778,  809, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@85Hz */
    357     { MODEPREFIX,   140250, 1280, 1328, 1360, 1440, 0,  768,  771,  778,  813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x768@120Hz RB */
    358     { MODEPREFIX,    71000, 1280, 1328, 1360, 1440, 0,  800,  803,  809,  823, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x800@60Hz RB */
    359     { MODEPREFIX,    83500, 1280, 1352, 1480, 1680, 0,  800,  803,  809,  831, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@60Hz */
    360     { MODEPREFIX,   106500, 1280, 1360, 1488, 1696, 0,  800,  803,  809,  838, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@75Hz */
    361     { MODEPREFIX,   122500, 1280, 1360, 1496, 1712, 0,  800,  803,  809,  843, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@85Hz */
    362     { MODEPREFIX,   146250, 1280, 1328, 1360, 1440, 0,  800,  803,  809,  847, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x800@120Hz RB */
    363     { MODEPREFIX,   108000, 1280, 1376, 1488, 1800, 0,  960,  961,  964, 1000, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x960@60Hz */
    364     { MODEPREFIX,   148500, 1280, 1344, 1504, 1728, 0,  960,  961,  964, 1011, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x960@85Hz */
    365     { MODEPREFIX,   175500, 1280, 1328, 1360, 1440, 0,  960,  963,  967, 1017, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x960@120Hz RB */
    366     { MODEPREFIX,   108000, 1280, 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@60Hz */
    367     { MODEPREFIX,   135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */
    368     { MODEPREFIX,   157500, 1280, 1344, 1504, 1728, 0, 1024, 1025, 1028, 1072, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@85Hz */
    369     { MODEPREFIX,   187250, 1280, 1328, 1360, 1440, 0, 1024, 1027, 1034, 1084, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x1024@120Hz RB */
    370     { MODEPREFIX,    85500, 1360, 1424, 1536, 1792, 0,  768,  771,  777,  795, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1360x768@60Hz */
    371     { MODEPREFIX,   148250, 1360, 1408, 1440, 1520, 0,  768,  771,  776,  813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1360x768@120Hz RB */
    372     { MODEPREFIX,   101000, 1400, 1448, 1480, 1560, 0, 1050, 1053, 1057, 1080, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1400x1050@60Hz RB */
    373     { MODEPREFIX,   121750, 1400, 1488, 1632, 1864, 0, 1050, 1053, 1057, 1089, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@60Hz */
    374     { MODEPREFIX,   156000, 1400, 1504, 1648, 1896, 0, 1050, 1053, 1057, 1099, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@75Hz */
    375     { MODEPREFIX,   179500, 1400, 1504, 1656, 1912, 0, 1050, 1053, 1057, 1105, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@85Hz */
    376     { MODEPREFIX,   208000, 1400, 1448, 1480, 1560, 0, 1050, 1053, 1057, 1112, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1400x1050@120Hz RB */
    377     { MODEPREFIX,    88750, 1440, 1488, 1520, 1600, 0,  900,  903,  909,  926, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1440x900@60Hz RB */
    378     { MODEPREFIX,   106500, 1440, 1520, 1672, 1904, 0,  900,  903,  909,  934, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@60Hz */
    379     { MODEPREFIX,   136750, 1440, 1536, 1688, 1936, 0,  900,  903,  909,  942, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@75Hz */
    380     { MODEPREFIX,   157000, 1440, 1544, 1696, 1952, 0,  900,  903,  909,  948, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@85Hz */
    381     { MODEPREFIX,   182750, 1440, 1488, 1520, 1600, 0,  900,  903,  909,  953, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1440x900@120Hz RB */
    382     { MODEPREFIX,   162000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@60Hz */
    383     { MODEPREFIX,   175500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@65Hz */
    384     { MODEPREFIX,   189000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@70Hz */
    385     { MODEPREFIX,   202500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@75Hz */
    386     { MODEPREFIX,   229500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@85Hz */
    387     { MODEPREFIX,   268250, 1600, 1648, 1680, 1760, 0, 1200, 1203, 1207, 1271, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1600x1200@120Hz RB */
    388     { MODEPREFIX,   119000, 1680, 1728, 1760, 1840, 0, 1050, 1053, 1059, 1080, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1680x1050@60Hz RB */
    389     { MODEPREFIX,   146250, 1680, 1784, 1960, 2240, 0, 1050, 1053, 1059, 1089, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@60Hz */
    390     { MODEPREFIX,   187000, 1680, 1800, 1976, 2272, 0, 1050, 1053, 1059, 1099, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@75Hz */
    391     { MODEPREFIX,   214750, 1680, 1808, 1984, 2288, 0, 1050, 1053, 1059, 1105, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@85Hz */
    392     { MODEPREFIX,   245500, 1680, 1728, 1760, 1840, 0, 1050, 1053, 1059, 1112, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1680x1050@120Hz RB */
    393     { MODEPREFIX,   204750, 1792, 1920, 2120, 2448, 0, 1344, 1345, 1348, 1394, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1792x1344@60Hz */
    394     { MODEPREFIX,   261000, 1792, 1888, 2104, 2456, 0, 1344, 1345, 1348, 1417, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1792x1344@75Hz */
    395     { MODEPREFIX,   333250, 1792, 1840, 1872, 1952, 0, 1344, 1347, 1351, 1423, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1792x1344@120Hz RB */
    396     { MODEPREFIX,   218250, 1856, 1952, 2176, 2528, 0, 1392, 1393, 1396, 1439, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1856x1392@60Hz */
    397     { MODEPREFIX,   288000, 1856, 1984, 2208, 2560, 0, 1392, 1393, 1396, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1856x1392@75Hz */
    398     { MODEPREFIX,   356500, 1856, 1904, 1936, 2016, 0, 1392, 1395, 1399, 1474, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1856x1392@120Hz RB */
    399     { MODEPREFIX,   154000, 1920, 1968, 2000, 2080, 0, 1200, 1203, 1209, 1235, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1200@60Hz RB */
    400     { MODEPREFIX,   193250, 1920, 2056, 2256, 2592, 0, 1200, 1203, 1209, 1245, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@60Hz */
    401     { MODEPREFIX,   245250, 1920, 2056, 2264, 2608, 0, 1200, 1203, 1209, 1255, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@75Hz */
    402     { MODEPREFIX,   281250, 1920, 2064, 2272, 2624, 0, 1200, 1203, 1209, 1262, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@85Hz */
    403     { MODEPREFIX,   317000, 1920, 1968, 2000, 2080, 0, 1200, 1203, 1209, 1271, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1200@120Hz RB */
    404     { MODEPREFIX,   234000, 1920, 2048, 2256, 2600, 0, 1440, 1441, 1444, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1440@60Hz */
    405     { MODEPREFIX,   297000, 1920, 2064, 2288, 2640, 0, 1440, 1441, 1444, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1440@75Hz */
    406     { MODEPREFIX,   380500, 1920, 1968, 2000, 2080, 0, 1440, 1443, 1447, 1525, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1440@120Hz RB */
    407     { MODEPREFIX,   268500, 2560, 2608, 2640, 2720, 0, 1600, 1603, 1609, 1646, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 2560x1600@60Hz RB */
    408     { MODEPREFIX,   348500, 2560, 2752, 3032, 3504, 0, 1600, 1603, 1609, 1658, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@60Hz */
    409     { MODEPREFIX,   443250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1672, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@75Hz */
    410     { MODEPREFIX,   505250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@85Hz */
    411     { MODEPREFIX,   552750, 2560, 2608, 2640, 2720, 0, 1600, 1603, 1609, 1694, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 2560x1600@120Hz RB */
    412 };
    413 
    414 #define LEVEL_DMT 0
    415 #define LEVEL_GTF 1
    416 #define LEVEL_CVT 2
    417 
    418 static int
    419 MonitorStandardTimingLevel(xf86MonPtr DDC)
    420 {
    421     if (DDC->ver.revision >= 2) {
    422 	if (DDC->ver.revision >= 4 && CVT_SUPPORTED(DDC->features.msc)) {
    423 	    return LEVEL_CVT;
    424 	}
    425 	return LEVEL_GTF;
    426     }
    427     return LEVEL_DMT;
    428 }
    429 
    430 static int
    431 ModeRefresh(const DisplayModeRec *mode)
    432 {
    433     return (int)(xf86ModeVRefresh(mode) + 0.5);
    434 }
    435 
    436 /*
    437  * If rb is not set, then we'll not consider reduced-blanking modes as
    438  * part of the DMT pool.  For the 'standard' EDID mode descriptor there's
    439  * no way to specify whether the mode should be RB or not.
    440  */
    441 DisplayModePtr
    442 FindDMTMode(int hsize, int vsize, int refresh, Bool rb)
    443 {
    444     int i;
    445     const DisplayModeRec *ret;
    446 
    447     for (i = 0; i < sizeof(DMTModes) / sizeof(DisplayModeRec); i++) {
    448 	ret = &DMTModes[i];
    449 
    450 	if (!rb && xf86ModeIsReduced(ret))
    451 	    continue;
    452 
    453 	if (ret->HDisplay == hsize &&
    454 	    ret->VDisplay == vsize &&
    455 	    refresh == ModeRefresh(ret))
    456 	    return xf86DuplicateMode(ret);
    457     }
    458 
    459     return NULL;
    460 }
    461 
    462 /*
    463  * Appendix B of the EDID 1.4 spec defines the right thing to do here.
    464  * If the timing given here matches a mode defined in the VESA DMT standard,
    465  * we _must_ use that.  If the device supports CVT modes, then we should
    466  * generate a CVT timing.  If both of the above fail, use GTF.
    467  *
    468  * There are some wrinkles here.  EDID 1.1 and 1.0 sinks can't really
    469  * "support" GTF, since it wasn't a standard yet; so if they ask for a
    470  * timing in this section that isn't defined in DMT, returning a GTF mode
    471  * may not actually be valid.  EDID 1.3 sinks often report support for
    472  * some CVT modes, but they are not required to support CVT timings for
    473  * modes in the standard timing descriptor, so we should _not_ treat them
    474  * as CVT-compliant (unless specified in an extension block I suppose).
    475  *
    476  * EDID 1.4 requires that all sink devices support both GTF and CVT timings
    477  * for modes in this section, but does say that CVT is preferred.
    478  */
    479 static DisplayModePtr
    480 DDCModesFromStandardTiming(struct std_timings *timing, ddc_quirk_t quirks,
    481 			   int timing_level, Bool rb)
    482 {
    483     DisplayModePtr Modes = NULL, Mode = NULL;
    484     int i, hsize, vsize, refresh;
    485 
    486     for (i = 0; i < STD_TIMINGS; i++) {
    487 	hsize = timing[i].hsize;
    488 	vsize = timing[i].vsize;
    489 	refresh = timing[i].refresh;
    490 
    491 	/* HDTV hack, because you can't say 1366 */
    492 	if (refresh == 60 &&
    493 	    ((hsize == 1360 && vsize == 765) ||
    494 	     (hsize == 1368 && vsize == 769))) {
    495 	    Mode = xf86CVTMode(1366, 768, 60, FALSE, FALSE);
    496 	    Mode->HDisplay = 1366;
    497 	    Mode->HSyncStart--;
    498 	    Mode->HSyncEnd--;
    499 	} else if (hsize && vsize && refresh) {
    500 	    Mode = FindDMTMode(hsize, vsize, refresh, rb);
    501 
    502 	    if (!Mode) {
    503 		if (timing_level == LEVEL_CVT)
    504 		    /* pass rb here too? */
    505 		    Mode = xf86CVTMode(hsize, vsize, refresh, FALSE, FALSE);
    506 		else if (timing_level == LEVEL_GTF)
    507 		    Mode = xf86GTFMode(hsize, vsize, refresh, FALSE, FALSE);
    508 	    }
    509 
    510 	}
    511 
    512 	if (Mode) {
    513 	    Mode->type = M_T_DRIVER;
    514 	    Modes = xf86ModesAdd(Modes, Mode);
    515 	}
    516 	Mode = NULL;
    517     }
    518 
    519     return Modes;
    520 }
    521 
    522 static void
    523 DDCModeDoInterlaceQuirks(DisplayModePtr mode)
    524 {
    525     /*
    526      * EDID is delightfully ambiguous about how interlaced modes are to be
    527      * encoded.  X's internal representation is of frame height, but some
    528      * HDTV detailed timings are encoded as field height.
    529      *
    530      * The format list here is from CEA, in frame size.  Technically we
    531      * should be checking refresh rate too.  Whatever.
    532      */
    533     static const struct {
    534 	int w, h;
    535     } cea_interlaced[] = {
    536 	{ 1920, 1080 },
    537 	{  720,  480 },
    538 	{ 1440,  480 },
    539 	{ 2880,  480 },
    540 	{  720,  576 },
    541 	{ 1440,  576 },
    542 	{ 2880,  576 },
    543     };
    544     static const int n_modes = sizeof(cea_interlaced)/sizeof(cea_interlaced[0]);
    545     int i;
    546 
    547     for (i = 0; i < n_modes; i++) {
    548 	if ((mode->HDisplay == cea_interlaced[i].w) &&
    549 	    (mode->VDisplay == cea_interlaced[i].h / 2)) {
    550 	    mode->VDisplay *= 2;
    551 	    mode->VSyncStart *= 2;
    552 	    mode->VSyncEnd *= 2;
    553 	    mode->VTotal *= 2;
    554 	    mode->VTotal |= 1;
    555 	}
    556     }
    557 
    558     mode->Flags |= V_INTERLACE;
    559 }
    560 
    561 /*
    562  *
    563  */
    564 static DisplayModePtr
    565 DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing,
    566 			  Bool preferred, ddc_quirk_t quirks)
    567 {
    568     DisplayModePtr Mode;
    569 
    570     /*
    571      * Refuse to create modes that are insufficiently large.  64 is a random
    572      * number, maybe the spec says something about what the minimum is.  In
    573      * particular I see this frequently with _old_ EDID, 1.0 or so, so maybe
    574      * our parser is just being too aggresive there.
    575      */
    576     if (timing->h_active < 64 || timing->v_active < 64) {
    577 	xf86DrvMsg(scrnIndex, X_INFO,
    578 		   "%s: Ignoring tiny %dx%d mode\n", __func__,
    579 		   timing->h_active, timing->v_active);
    580 	return NULL;
    581     }
    582 
    583     /* We don't do stereo */
    584     if (timing->stereo) {
    585         xf86DrvMsg(scrnIndex, X_INFO,
    586 		   "%s: Ignoring: We don't handle stereo.\n", __func__);
    587         return NULL;
    588     }
    589 
    590     /* We only do seperate sync currently */
    591     if (timing->sync != 0x03) {
    592          xf86DrvMsg(scrnIndex, X_INFO,
    593 		    "%s: %dx%d Warning: We only handle separate"
    594                     " sync.\n", __func__, timing->h_active, timing->v_active);
    595     }
    596 
    597     Mode = xnfcalloc(1, sizeof(DisplayModeRec));
    598 
    599     Mode->type = M_T_DRIVER;
    600     if (preferred)
    601 	Mode->type |= M_T_PREFERRED;
    602 
    603     if( ( quirks & DDC_QUIRK_135_CLOCK_TOO_HIGH ) &&
    604 	timing->clock == 135000000 )
    605         Mode->Clock = 108880;
    606     else
    607         Mode->Clock = timing->clock / 1000.0;
    608 
    609     Mode->HDisplay = timing->h_active;
    610     Mode->HSyncStart = timing->h_active + timing->h_sync_off;
    611     Mode->HSyncEnd = Mode->HSyncStart + timing->h_sync_width;
    612     Mode->HTotal = timing->h_active + timing->h_blanking;
    613 
    614     Mode->VDisplay = timing->v_active;
    615     Mode->VSyncStart = timing->v_active + timing->v_sync_off;
    616     Mode->VSyncEnd = Mode->VSyncStart + timing->v_sync_width;
    617     Mode->VTotal = timing->v_active + timing->v_blanking;
    618 
    619     /* perform basic check on the detail timing */
    620     if (Mode->HSyncEnd > Mode->HTotal || Mode->VSyncEnd > Mode->VTotal) {
    621 	free(Mode);
    622 	return NULL;
    623     }
    624 
    625     /* We ignore h/v_size and h/v_border for now. */
    626 
    627     if (timing->interlaced)
    628 	DDCModeDoInterlaceQuirks(Mode);
    629 
    630     if (quirks & DDC_QUIRK_DETAILED_SYNC_PP)
    631 	Mode->Flags |= V_PVSYNC | V_PHSYNC;
    632     else {
    633 	if (timing->misc & 0x02)
    634 	    Mode->Flags |= V_PVSYNC;
    635 	else
    636 	    Mode->Flags |= V_NVSYNC;
    637 
    638 	if (timing->misc & 0x01)
    639 	    Mode->Flags |= V_PHSYNC;
    640 	else
    641 	    Mode->Flags |= V_NHSYNC;
    642     }
    643 
    644     xf86SetModeDefaultName(Mode);
    645 
    646     return Mode;
    647 }
    648 
    649 static DisplayModePtr
    650 DDCModesFromCVT(int scrnIndex, struct cvt_timings *t)
    651 {
    652     DisplayModePtr modes = NULL;
    653     int i;
    654 
    655     for (i = 0; i < 4; i++) {
    656 	if (t[i].height) {
    657 	    if (t[i].rates & 0x10)
    658 		modes = xf86ModesAdd(modes,
    659 			xf86CVTMode(t[i].width, t[i].height, 50, 0, 0));
    660 	    if (t[i].rates & 0x08)
    661 		modes = xf86ModesAdd(modes,
    662 			xf86CVTMode(t[i].width, t[i].height, 60, 0, 0));
    663 	    if (t[i].rates & 0x04)
    664 		modes = xf86ModesAdd(modes,
    665 			xf86CVTMode(t[i].width, t[i].height, 75, 0, 0));
    666 	    if (t[i].rates & 0x02)
    667 		modes = xf86ModesAdd(modes,
    668 			xf86CVTMode(t[i].width, t[i].height, 85, 0, 0));
    669 	    if (t[i].rates & 0x01)
    670 		modes = xf86ModesAdd(modes,
    671 			xf86CVTMode(t[i].width, t[i].height, 60, 1, 0));
    672 	} else break;
    673     }
    674 
    675     return modes;
    676 }
    677 
    678 static const struct {
    679     short w;
    680     short h;
    681     short r;
    682     short rb;
    683 } EstIIIModes[] = {
    684     /* byte 6 */
    685     { 640, 350, 85, 0 },
    686     { 640, 400, 85, 0 },
    687     { 720, 400, 85, 0 },
    688     { 640, 480, 85, 0 },
    689     { 848, 480, 60, 0 },
    690     { 800, 600, 85, 0 },
    691     { 1024, 768, 85, 0 },
    692     { 1152, 864, 75, 0 },
    693     /* byte 7 */
    694     { 1280, 768, 60, 1 },
    695     { 1280, 768, 60, 0 },
    696     { 1280, 768, 75, 0 },
    697     { 1280, 768, 85, 0 },
    698     { 1280, 960, 60, 0 },
    699     { 1280, 960, 85, 0 },
    700     { 1280, 1024, 60, 0 },
    701     { 1280, 1024, 85, 0 },
    702     /* byte 8 */
    703     { 1360, 768, 60, 0 },
    704     { 1440, 900, 60, 1 },
    705     { 1440, 900, 60, 0 },
    706     { 1440, 900, 75, 0 },
    707     { 1440, 900, 85, 0 },
    708     { 1400, 1050, 60, 1 },
    709     { 1400, 1050, 60, 0 },
    710     { 1400, 1050, 75, 0 },
    711     /* byte 9 */
    712     { 1400, 1050, 85, 0 },
    713     { 1680, 1050, 60, 1 },
    714     { 1680, 1050, 60, 0 },
    715     { 1680, 1050, 75, 0 },
    716     { 1680, 1050, 85, 0 },
    717     { 1600, 1200, 60, 0 },
    718     { 1600, 1200, 65, 0 },
    719     { 1600, 1200, 70, 0 },
    720     /* byte 10 */
    721     { 1600, 1200, 75, 0 },
    722     { 1600, 1200, 85, 0 },
    723     { 1792, 1344, 60, 0 },
    724     { 1792, 1344, 85, 0 },
    725     { 1856, 1392, 60, 0 },
    726     { 1856, 1392, 75, 0 },
    727     { 1920, 1200, 60, 1 },
    728     { 1920, 1200, 60, 0 },
    729     /* byte 11 */
    730     { 1920, 1200, 75, 0 },
    731     { 1920, 1200, 85, 0 },
    732     { 1920, 1440, 60, 0 },
    733     { 1920, 1440, 75, 0 },
    734 };
    735 
    736 static DisplayModePtr
    737 DDCModesFromEstIII(unsigned char *est)
    738 {
    739     DisplayModePtr modes = NULL;
    740     int i, j, m;
    741 
    742     for (i = 0; i < 6; i++) {
    743 	for (j = 7; j > 0; j--) {
    744 	    if (est[i] & (1 << j)) {
    745 		m = (i * 8) + (7 - j);
    746 		modes = xf86ModesAdd(modes,
    747 				     FindDMTMode(EstIIIModes[m].w,
    748 						 EstIIIModes[m].h,
    749 						 EstIIIModes[m].r,
    750 						 EstIIIModes[m].rb));
    751 	    }
    752 	}
    753     }
    754 
    755     return modes;
    756 }
    757 
    758 /*
    759  * This is only valid when the sink claims to be continuous-frequency
    760  * but does not supply a detailed range descriptor.  Such sinks are
    761  * arguably broken.  Currently the mode validation code isn't aware of
    762  * this; the non-RANDR code even punts the decision of optional sync
    763  * range checking to the driver.  Loss.
    764  */
    765 static void
    766 DDCGuessRangesFromModes(int scrnIndex, MonPtr Monitor, DisplayModePtr Modes)
    767 {
    768     DisplayModePtr Mode = Modes;
    769 
    770     if (!Monitor || !Modes)
    771         return;
    772 
    773     /* set up the ranges for scanning through the modes */
    774     Monitor->nHsync = 1;
    775     Monitor->hsync[0].lo = 1024.0;
    776     Monitor->hsync[0].hi = 0.0;
    777 
    778     Monitor->nVrefresh = 1;
    779     Monitor->vrefresh[0].lo = 1024.0;
    780     Monitor->vrefresh[0].hi = 0.0;
    781 
    782     while (Mode) {
    783         if (!Mode->HSync)
    784             Mode->HSync = ((float) Mode->Clock ) / ((float) Mode->HTotal);
    785 
    786         if (!Mode->VRefresh)
    787             Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) /
    788                 ((float) (Mode->HTotal * Mode->VTotal));
    789 
    790         if (Mode->HSync < Monitor->hsync[0].lo)
    791             Monitor->hsync[0].lo = Mode->HSync;
    792 
    793         if (Mode->HSync > Monitor->hsync[0].hi)
    794             Monitor->hsync[0].hi = Mode->HSync;
    795 
    796         if (Mode->VRefresh < Monitor->vrefresh[0].lo)
    797             Monitor->vrefresh[0].lo = Mode->VRefresh;
    798 
    799         if (Mode->VRefresh > Monitor->vrefresh[0].hi)
    800             Monitor->vrefresh[0].hi = Mode->VRefresh;
    801 
    802         Mode = Mode->next;
    803     }
    804 }
    805 
    806 ddc_quirk_t
    807 xf86DDCDetectQuirks(int scrnIndex, xf86MonPtr DDC, Bool verbose)
    808 {
    809     ddc_quirk_t	quirks;
    810     int i;
    811 
    812     quirks = DDC_QUIRK_NONE;
    813     for (i = 0; ddc_quirks[i].detect; i++) {
    814 	if (ddc_quirks[i].detect (scrnIndex, DDC)) {
    815 	    if (verbose) {
    816 		xf86DrvMsg (scrnIndex, X_INFO, "    EDID quirk: %s\n",
    817 			    ddc_quirks[i].description);
    818 	    }
    819 	    quirks |= ddc_quirks[i].quirk;
    820 	}
    821     }
    822 
    823     return quirks;
    824 }
    825 
    826 void xf86DetTimingApplyQuirks(struct detailed_monitor_section *det_mon,
    827                               ddc_quirk_t quirks,
    828                               int hsize, int vsize)
    829 {
    830     if (det_mon->type != DT)
    831         return;
    832 
    833     if (quirks & DDC_QUIRK_DETAILED_H_IN_CM)
    834         det_mon->section.d_timings.h_size *= 10;
    835 
    836     if (quirks & DDC_QUIRK_DETAILED_V_IN_CM)
    837         det_mon->section.d_timings.v_size *= 10;
    838 
    839     if (quirks & DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
    840         det_mon->section.d_timings.h_size = 10 * hsize;
    841         det_mon->section.d_timings.v_size = 10 * vsize;
    842     }
    843 }
    844 
    845 /**
    846  * Applies monitor-specific quirks to the decoded EDID information.
    847  *
    848  * Note that some quirks applying to the mode list are still implemented in
    849  * xf86DDCGetModes.
    850  */
    851 void
    852 xf86DDCApplyQuirks(int scrnIndex, xf86MonPtr DDC)
    853 {
    854     ddc_quirk_t quirks = xf86DDCDetectQuirks (scrnIndex, DDC, FALSE);
    855     int i;
    856 
    857     for (i = 0; i < DET_TIMINGS; i++) {
    858         xf86DetTimingApplyQuirks(DDC->det_mon + i, quirks,
    859                                  DDC->features.hsize,
    860                                  DDC->features.vsize);
    861     }
    862 }
    863 
    864 /**
    865  * Walks the modes list, finding the mode with the largest area which is
    866  * closest to the target refresh rate, and marks it as the only preferred mode.
    867 */
    868 static void
    869 xf86DDCSetPreferredRefresh(int scrnIndex, DisplayModePtr modes,
    870 			   float target_refresh)
    871 {
    872 	DisplayModePtr	mode, best = modes;
    873 
    874 	for (mode = modes; mode; mode = mode->next)
    875 	{
    876 	    mode->type &= ~M_T_PREFERRED;
    877 
    878 	    if (mode == best) continue;
    879 
    880 	    if (mode->HDisplay * mode->VDisplay >
    881 		best->HDisplay * best->VDisplay)
    882 	    {
    883 		best = mode;
    884 		continue;
    885 	    }
    886 	    if (mode->HDisplay * mode->VDisplay ==
    887 		best->HDisplay * best->VDisplay)
    888 	    {
    889 		double	mode_refresh = xf86ModeVRefresh (mode);
    890 		double	best_refresh = xf86ModeVRefresh (best);
    891 		double	mode_dist = fabs(mode_refresh - target_refresh);
    892 		double	best_dist = fabs(best_refresh - target_refresh);
    893 
    894 		if (mode_dist < best_dist)
    895 		{
    896 		    best = mode;
    897 		    continue;
    898 		}
    899 	    }
    900 	}
    901 	if (best)
    902 	    best->type |= M_T_PREFERRED;
    903 }
    904 
    905 #define CEA_VIDEO_MODES_NUM  64
    906 static const DisplayModeRec CEAVideoModes[CEA_VIDEO_MODES_NUM] = {
    907     { MODEPREFIX,    25175,  640,  656,  752,  800, 0,  480,  490,  492,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 1:640x480@60Hz */
    908     { MODEPREFIX,    27000,  720,  736,  798,  858, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 2:720x480@60Hz */
    909     { MODEPREFIX,    27000,  720,  736,  798,  858, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 3:720x480@60Hz */
    910     { MODEPREFIX,    74250, 1280, 1390, 1430, 1650, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 4: 1280x720@60Hz */
    911     { MODEPREFIX,    74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 5:1920x1080i@60Hz */
    912     { MODEPREFIX,    27000, 1440, 1478, 1602, 1716, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 6:1440x480i@60Hz */
    913     { MODEPREFIX,    27000, 1440, 1478, 1602, 1716, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 7:1440x480i@60Hz */
    914     { MODEPREFIX,    27000, 1440, 1478, 1602, 1716, 0,  240,  244,  247,  262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 8:1440x240@60Hz */
    915     { MODEPREFIX,    27000, 1440, 1478, 1602, 1716, 0,  240,  244,  247,  262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 9:1440x240@60Hz */
    916     { MODEPREFIX,    54000, 2880, 2956, 3204, 3432, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 10:2880x480i@60Hz */
    917     { MODEPREFIX,    54000, 2880, 2956, 3204, 3432, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 11:2880x480i@60Hz */
    918     { MODEPREFIX,    54000, 2880, 2956, 3204, 3432, 0,  240,  244,  247,  262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 12:2880x240@60Hz */
    919     { MODEPREFIX,    54000, 2880, 2956, 3204, 3432, 0,  240,  244,  247,  262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 13:2880x240@60Hz */
    920     { MODEPREFIX,    54000, 1440, 1472, 1596, 1716, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 14:1440x480@60Hz */
    921     { MODEPREFIX,    54000, 1440, 1472, 1596, 1716, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 15:1440x480@60Hz */
    922     { MODEPREFIX,   148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 16:1920x1080@60Hz */
    923     { MODEPREFIX,    27000,  720,  732,  796,  864, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 17:720x576@50Hz */
    924     { MODEPREFIX,    27000,  720,  732,  796,  864, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 18:720x576@50Hz */
    925     { MODEPREFIX,    74250, 1280, 1720, 1760, 1980, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 19: 1280x720@50Hz */
    926     { MODEPREFIX,    74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 20:1920x1080i@50Hz */
    927     { MODEPREFIX,    27000, 1440, 1464, 1590, 1728, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 21:1440x576i@50Hz */
    928     { MODEPREFIX,    27000, 1440, 1464, 1590, 1728, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 22:1440x576i@50Hz */
    929     { MODEPREFIX,    27000, 1440, 1464, 1590, 1728, 0,  288,  290,  293,  312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 23:1440x288@50Hz */
    930     { MODEPREFIX,    27000, 1440, 1464, 1590, 1728, 0,  288,  290,  293,  312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 24:1440x288@50Hz */
    931     { MODEPREFIX,    54000, 2880, 2928, 3180, 3456, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 25:2880x576i@50Hz */
    932     { MODEPREFIX,    54000, 2880, 2928, 3180, 3456, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 26:2880x576i@50Hz */
    933     { MODEPREFIX,    54000, 2880, 2928, 3180, 3456, 0,  288,  290,  293,  312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 27:2880x288@50Hz */
    934     { MODEPREFIX,    54000, 2880, 2928, 3180, 3456, 0,  288,  290,  293,  312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 28:2880x288@50Hz */
    935     { MODEPREFIX,    54000, 1440, 1464, 1592, 1728, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 29:1440x576@50Hz */
    936     { MODEPREFIX,    54000, 1440, 1464, 1592, 1728, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 30:1440x576@50Hz */
    937     { MODEPREFIX,   148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 31:1920x1080@50Hz */
    938     { MODEPREFIX,    74250, 1920, 2558, 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 32:1920x1080@24Hz */
    939     { MODEPREFIX,    74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 33:1920x1080@25Hz */
    940     { MODEPREFIX,    74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 34:1920x1080@30Hz */
    941     { MODEPREFIX,   108000, 2880, 2944, 3192, 3432, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 35:2880x480@60Hz */
    942     { MODEPREFIX,   108000, 2880, 2944, 3192, 3432, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 36:2880x480@60Hz */
    943     { MODEPREFIX,   108000, 2880, 2928, 3184, 3456, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 37:2880x576@50Hz */
    944     { MODEPREFIX,   108000, 2880, 2928, 3184, 3456, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 38:2880x576@50Hz */
    945     { MODEPREFIX,    72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, V_PHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 39:1920x1080i@50Hz */
    946     { MODEPREFIX,   148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 40:1920x1080i@100Hz */
    947     { MODEPREFIX,   148500, 1280, 1720, 1760, 1980, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 41:1280x720@100Hz */
    948     { MODEPREFIX,    54000,  720,  732,  796,  864, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 42:720x576@100Hz */
    949     { MODEPREFIX,    54000,  720,  732,  796,  864, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 43:720x576@100Hz */
    950     { MODEPREFIX,    54000, 1440, 1464, 1590, 1728, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 44:1440x576i@100Hz */
    951     { MODEPREFIX,    54000, 1440, 1464, 1590, 1728, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 45:1440x576i@100Hz */
    952     { MODEPREFIX,   148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 46:1920x1080i@120Hz */
    953     { MODEPREFIX,   148500, 1280, 1390, 1430, 1650, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 47:1280x720@120Hz */
    954     { MODEPREFIX,    54000,  720,  736,  798,  858, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 48:720x480@120Hz */
    955     { MODEPREFIX,    54000,  720,  736,  798,  858, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 49:720x480@120Hz */
    956     { MODEPREFIX,    54000, 1440, 1478, 1602, 1716, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 50:1440x480i@120Hz */
    957     { MODEPREFIX,    54000, 1440, 1478, 1602, 1716, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 51:1440x480i@120Hz */
    958     { MODEPREFIX,   108000,  720,  732,  796,  864, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 52:720x576@200Hz */
    959     { MODEPREFIX,   108000,  720,  732,  796,  864, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 53:720x576@200Hz */
    960     { MODEPREFIX,   108000, 1440, 1464, 1590, 1728, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 54:1440x576i@200Hz */
    961     { MODEPREFIX,   108000, 1440, 1464, 1590, 1728, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 55:1440x576i@200Hz */
    962     { MODEPREFIX,   108000,  720,  736,  798,  858, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 56:720x480@240Hz */
    963     { MODEPREFIX,   108000,  720,  736,  798,  858, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 57:720x480@240Hz */
    964     { MODEPREFIX,   108000, 1440, 1478, 1602, 1716, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 58:1440x480i@240 */
    965     { MODEPREFIX,   108000, 1440, 1478, 1602, 1716, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 59:1440x480i@240 */
    966     { MODEPREFIX,    59400, 1280, 3040, 3080, 3300, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 60: 1280x720@24Hz */
    967     { MODEPREFIX,    74250, 1280, 3700, 3740, 3960, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 61: 1280x720@25Hz */
    968     { MODEPREFIX,    74250, 1280, 3040, 3080, 3300, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 62: 1280x720@30Hz */
    969     { MODEPREFIX,   297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 63: 1920x1080@120Hz */
    970     { MODEPREFIX,   297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 64:1920x1080@100Hz */
    971 };
    972 
    973 /* chose mode line by cea short video descriptor*/
    974 static void handle_cea_svd(struct cea_video_block *video, void *data)
    975 {
    976     DisplayModePtr Mode;
    977     DisplayModePtr *Modes = (DisplayModePtr *) data;
    978     int vid;
    979 
    980     vid = video ->video_code & 0x7f;
    981     if (vid < CEA_VIDEO_MODES_NUM) {
    982 	Mode = xf86DuplicateMode(CEAVideoModes + vid);
    983 	*Modes = xf86ModesAdd(*Modes, Mode);
    984     }
    985 }
    986 
    987 static DisplayModePtr
    988 DDCModesFromCEAExtension(int scrnIndex, xf86MonPtr MonPtr)
    989 {
    990     DisplayModePtr Modes = NULL;
    991 
    992     xf86ForEachVideoBlock(MonPtr,
    993                           handle_cea_svd,
    994                           &Modes);
    995 
    996     return Modes;
    997 }
    998 
    999 struct det_modes_parameter {
   1000     xf86MonPtr DDC;
   1001     ddc_quirk_t quirks;
   1002     DisplayModePtr  Modes;
   1003     Bool rb;
   1004     Bool preferred;
   1005     int timing_level;
   1006 };
   1007 
   1008 static void handle_detailed_modes(struct detailed_monitor_section *det_mon,
   1009 	                          void *data)
   1010 {
   1011     DisplayModePtr  Mode;
   1012     struct det_modes_parameter *p = (struct det_modes_parameter *)data;
   1013 
   1014     xf86DetTimingApplyQuirks(det_mon,p->quirks,
   1015                              p->DDC->features.hsize,
   1016                              p->DDC->features.vsize);
   1017 
   1018     switch (det_mon->type) {
   1019     case DT:
   1020         Mode = DDCModeFromDetailedTiming(p->DDC->scrnIndex,
   1021                                          &det_mon->section.d_timings,
   1022                                          p->preferred,
   1023                                          p->quirks);
   1024         p->preferred = FALSE;
   1025         p->Modes = xf86ModesAdd(p->Modes, Mode);
   1026         break;
   1027     case DS_STD_TIMINGS:
   1028         Mode = DDCModesFromStandardTiming(det_mon->section.std_t,
   1029                                           p->quirks, p->timing_level,p->rb);
   1030         p->Modes = xf86ModesAdd(p->Modes, Mode);
   1031         break;
   1032     case DS_CVT:
   1033         Mode = DDCModesFromCVT(p->DDC->scrnIndex, det_mon->section.cvt);
   1034         p->Modes = xf86ModesAdd(p->Modes, Mode);
   1035         break;
   1036     case DS_EST_III:
   1037 	Mode = DDCModesFromEstIII(det_mon->section.est_iii);
   1038 	p->Modes = xf86ModesAdd(p->Modes, Mode);
   1039 	break;
   1040     default:
   1041         break;
   1042     }
   1043 }
   1044 
   1045 DisplayModePtr
   1046 xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
   1047 {
   1048     DisplayModePtr  Modes = NULL, Mode;
   1049     ddc_quirk_t	    quirks;
   1050     Bool	    preferred, rb;
   1051     int		    timing_level;
   1052     struct det_modes_parameter p;
   1053 
   1054     xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n",
   1055 		DDC->vendor.name, DDC->vendor.prod_id);
   1056 
   1057     quirks = xf86DDCDetectQuirks(scrnIndex, DDC, TRUE);
   1058 
   1059     preferred = PREFERRED_TIMING_MODE(DDC->features.msc);
   1060     if (DDC->ver.revision >= 4)
   1061 	preferred = TRUE;
   1062     if (quirks & DDC_QUIRK_FIRST_DETAILED_PREFERRED)
   1063 	preferred = TRUE;
   1064     if (quirks & (DDC_QUIRK_PREFER_LARGE_60 | DDC_QUIRK_PREFER_LARGE_75))
   1065 	preferred = FALSE;
   1066 
   1067     rb = xf86MonitorSupportsReducedBlanking(DDC);
   1068 
   1069     timing_level = MonitorStandardTimingLevel(DDC);
   1070 
   1071     p.quirks = quirks;
   1072     p.DDC = DDC;
   1073     p.Modes = Modes;
   1074     p.rb = rb;
   1075     p.preferred = preferred;
   1076     p.timing_level = timing_level;
   1077     xf86ForEachDetailedBlock(DDC, handle_detailed_modes, &p);
   1078     Modes = p.Modes;
   1079 
   1080     /* Add established timings */
   1081     Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1, quirks);
   1082     Modes = xf86ModesAdd(Modes, Mode);
   1083 
   1084     /* Add standard timings */
   1085     Mode = DDCModesFromStandardTiming(DDC->timings2, quirks, timing_level, rb);
   1086     Modes = xf86ModesAdd(Modes, Mode);
   1087 
   1088     /* Add cea-extension mode timings */
   1089     Mode = DDCModesFromCEAExtension(scrnIndex,DDC);
   1090     Modes = xf86ModesAdd(Modes, Mode);
   1091 
   1092     if (quirks & DDC_QUIRK_PREFER_LARGE_60)
   1093 	xf86DDCSetPreferredRefresh(scrnIndex, Modes, 60);
   1094 
   1095     if (quirks & DDC_QUIRK_PREFER_LARGE_75)
   1096 	xf86DDCSetPreferredRefresh(scrnIndex, Modes, 75);
   1097 
   1098     Modes = xf86PruneDuplicateModes(Modes);
   1099 
   1100     return Modes;
   1101 }
   1102 
   1103 struct det_mon_parameter {
   1104     MonPtr Monitor;
   1105     ddc_quirk_t quirks;
   1106     Bool have_hsync;
   1107     Bool have_vrefresh;
   1108     Bool have_maxpixclock;
   1109 };
   1110 
   1111 static void handle_detailed_monset(struct detailed_monitor_section *det_mon,
   1112                                    void *data)
   1113 {
   1114     int clock;
   1115     struct det_mon_parameter *p = (struct det_mon_parameter *)data;
   1116     int scrnIndex = ((xf86MonPtr)(p->Monitor->DDC))->scrnIndex;
   1117 
   1118     switch (det_mon->type) {
   1119     case DS_RANGES:
   1120         if (!p->have_hsync) {
   1121             if (!p->Monitor->nHsync)
   1122                 xf86DrvMsg(scrnIndex, X_INFO,
   1123                     "Using EDID range info for horizontal sync\n");
   1124                 p->Monitor->hsync[p->Monitor->nHsync].lo =
   1125                     det_mon->section.ranges.min_h;
   1126                 p->Monitor->hsync[p->Monitor->nHsync].hi =
   1127                     det_mon->section.ranges.max_h;
   1128                 p->Monitor->nHsync++;
   1129         } else {
   1130             xf86DrvMsg(scrnIndex, X_INFO,
   1131                 "Using hsync ranges from config file\n");
   1132         }
   1133 
   1134         if (!p->have_vrefresh) {
   1135             if (!p->Monitor->nVrefresh)
   1136                 xf86DrvMsg(scrnIndex, X_INFO,
   1137                     "Using EDID range info for vertical refresh\n");
   1138             p->Monitor->vrefresh[p->Monitor->nVrefresh].lo =
   1139                 det_mon->section.ranges.min_v;
   1140             p->Monitor->vrefresh[p->Monitor->nVrefresh].hi =
   1141                 det_mon->section.ranges.max_v;
   1142             p->Monitor->nVrefresh++;
   1143         } else {
   1144             xf86DrvMsg(scrnIndex, X_INFO,
   1145                 "Using vrefresh ranges from config file\n");
   1146         }
   1147 
   1148         clock = det_mon->section.ranges.max_clock * 1000;
   1149         if (p->quirks & DDC_QUIRK_DVI_SINGLE_LINK)
   1150             clock = min(clock, 165000);
   1151         if (!p->have_maxpixclock && clock > p->Monitor->maxPixClock)
   1152             p->Monitor->maxPixClock = clock;
   1153 
   1154         break;
   1155     default:
   1156         break;
   1157     }
   1158 }
   1159 
   1160 /*
   1161  * Fill out MonPtr with xf86MonPtr information.
   1162  */
   1163 void
   1164 xf86EdidMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC)
   1165 {
   1166     DisplayModePtr Modes = NULL, Mode;
   1167     struct det_mon_parameter p;
   1168 
   1169     if (!Monitor || !DDC)
   1170         return;
   1171 
   1172     Monitor->DDC = DDC;
   1173 
   1174     if (Monitor->widthmm <= 0 || Monitor->heightmm <= 0) {
   1175 	Monitor->widthmm = 10 * DDC->features.hsize;
   1176 	Monitor->heightmm = 10 * DDC->features.vsize;
   1177     }
   1178 
   1179     Monitor->reducedblanking = xf86MonitorSupportsReducedBlanking(DDC);
   1180 
   1181     Modes = xf86DDCGetModes(scrnIndex, DDC);
   1182 
   1183     /* Go through the detailed monitor sections */
   1184     p.Monitor = Monitor;
   1185     p.quirks = xf86DDCDetectQuirks(scrnIndex, Monitor->DDC, FALSE);
   1186     p.have_hsync = (Monitor->nHsync != 0);
   1187     p.have_vrefresh = (Monitor->nVrefresh != 0);
   1188     p.have_maxpixclock = (Monitor->maxPixClock != 0);
   1189     xf86ForEachDetailedBlock(DDC, handle_detailed_monset, &p);
   1190 
   1191     if (Modes) {
   1192         /* Print Modes */
   1193         xf86DrvMsg(scrnIndex, X_INFO, "Printing DDC gathered Modelines:\n");
   1194 
   1195         Mode = Modes;
   1196         while (Mode) {
   1197             xf86PrintModeline(scrnIndex, Mode);
   1198             Mode = Mode->next;
   1199         }
   1200 
   1201         /* Do we still need ranges to be filled in? */
   1202         if (!Monitor->nHsync || !Monitor->nVrefresh)
   1203             DDCGuessRangesFromModes(scrnIndex, Monitor, Modes);
   1204 
   1205         /* look for last Mode */
   1206         Mode = Modes;
   1207 
   1208         while (Mode->next)
   1209             Mode = Mode->next;
   1210 
   1211         /* add to MonPtr */
   1212         if (Monitor->Modes) {
   1213             Monitor->Last->next = Modes;
   1214             Modes->prev = Monitor->Last;
   1215             Monitor->Last = Mode;
   1216         } else {
   1217             Monitor->Modes = Modes;
   1218             Monitor->Last = Mode;
   1219         }
   1220     }
   1221 }
   1222