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