| 1 | /* |
| 2 | * Copyright 1999 SuSE, Inc. |
| 3 | * |
| 4 | * Permission to use, copy, modify, distribute, and sell this software and its |
| 5 | * documentation for any purpose is hereby granted without fee, provided that |
| 6 | * the above copyright notice appear in all copies and that both that |
| 7 | * copyright notice and this permission notice appear in supporting |
| 8 | * documentation, and that the name of SuSE not be used in advertising or |
| 9 | * publicity pertaining to distribution of the software without specific, |
| 10 | * written prior permission. SuSE makes no representations about the |
| 11 | * suitability of this software for any purpose. It is provided "as is" |
| 12 | * without express or implied warranty. |
| 13 | * |
| 14 | * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL |
| 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE |
| 16 | * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 18 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 19 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 20 | * |
| 21 | * Author: Keith Packard, SuSE, Inc. |
| 22 | */ |
| 23 | |
| 24 | #ifdef HAVE_CONFIG_H |
| 25 | #include <kdrive-config.h> |
| 26 | #endif |
| 27 | #include "kdrive.h" |
| 28 | |
| 29 | const KdMonitorTiming kdMonitorTimings[] = { |
| 30 | /* H V Hz KHz */ |
| 31 | /* FP BP BLANK POLARITY */ |
| 32 | |
| 33 | /* IPAQ modeline: |
| 34 | * |
| 35 | * Modeline "320x240" 5.7222 320 337 340 352 240 241 244 254" |
| 36 | */ |
| 37 | {320, 240, 64, 16256, |
| 38 | 17, 12, 32, KdSyncNegative, |
| 39 | 1, 11, 14, KdSyncNegative, |
| 40 | }, |
| 41 | |
| 42 | /* Other VESA modes */ |
| 43 | {640, 350, 85, 31500, /* VESA */ |
| 44 | 32, 96, 192, KdSyncPositive, /* 26.413 */ |
| 45 | 32, 60, 95, KdSyncNegative, /* 59.354 */ |
| 46 | }, |
| 47 | {640, 400, 60, 31500, /* VESA */ |
| 48 | 32, 96, 192, KdSyncNegative, /* 26.413 */ |
| 49 | 1, 41, 45, KdSyncPositive, /* 59.354 */ |
| 50 | }, |
| 51 | {720, 400, 85, 35500, /* VESA */ |
| 52 | 36, 108, 216, KdSyncNegative, /* 37.927 */ |
| 53 | 1, 42, 46, KdSyncPositive, /* 85.039 */ |
| 54 | }, |
| 55 | |
| 56 | /* Modeline "720x576" 29.000 720 736 800 880 576 577 580 625 */ |
| 57 | { |
| 58 | 720, 576, 52, 32954, /* PAL Video */ |
| 59 | 16, 80, 160, KdSyncPositive, /* 32.954 */ |
| 60 | 1, 45, 49, KdSyncPositive, /* 52.727 */ |
| 61 | }, |
| 62 | |
| 63 | /* 640x480 modes */ |
| 64 | {640, 480, 85, 36000, /* VESA */ |
| 65 | 56, 80, 192, KdSyncNegative, /* 43.269 */ |
| 66 | 1, 25, 29, KdSyncNegative, /* 85.008 */ |
| 67 | }, |
| 68 | {640, 480, 75, 31500, /* VESA */ |
| 69 | 16, 120, 200, KdSyncNegative, /* 37.500 */ |
| 70 | 1, 16, 20, KdSyncNegative, /* 75.000 */ |
| 71 | }, |
| 72 | {640, 480, 72, 31500, /* VESA */ |
| 73 | 16, 120, 176, KdSyncNegative, /* 37.861 */ |
| 74 | 1, 20, 24, KdSyncNegative, /* 72.809 */ |
| 75 | }, |
| 76 | {640, 480, 60, 25175, /* VESA */ |
| 77 | 16, 48, 160, KdSyncNegative, /* 31.469 */ |
| 78 | 10, 33, 45, KdSyncNegative, /* 59.940 */ |
| 79 | }, |
| 80 | |
| 81 | /* 800x600 modes */ |
| 82 | {800, 600, 85, 56250, /* VESA */ |
| 83 | 32, 152, 248, KdSyncPositive, /* 53.674 */ |
| 84 | 1, 27, 31, KdSyncPositive, /* 85.061 */ |
| 85 | }, |
| 86 | {800, 600, 75, 49500, /* VESA */ |
| 87 | 16, 160, 256, KdSyncPositive, /* 46.875 */ |
| 88 | 1, 21, 25, KdSyncPositive, /* 75.000 */ |
| 89 | }, |
| 90 | /* DEFAULT */ |
| 91 | #define MONITOR_TIMING_DEFAULT 9 |
| 92 | {800, 600, 72, 50000, /* VESA */ |
| 93 | 56, 64, 240, KdSyncPositive, /* 48.077 */ |
| 94 | 37, 23, 66, KdSyncPositive, /* 72.188 */ |
| 95 | }, |
| 96 | {800, 600, 60, 40000, /* VESA */ |
| 97 | 40, 88, 256, KdSyncPositive, /* 37.879 */ |
| 98 | 1, 23, 28, KdSyncPositive, /* 60.317 */ |
| 99 | }, |
| 100 | {800, 600, 56, 36000, /* VESA */ |
| 101 | 24, 128, 224, KdSyncPositive, /* 35.156 */ |
| 102 | 1, 22, 25, KdSyncPositive, /* 56.250 */ |
| 103 | }, |
| 104 | |
| 105 | /* 1024x768 modes */ |
| 106 | {1024, 768, 85, 94500, /* VESA */ |
| 107 | 48, 208, 352, KdSyncPositive, /* 68.677 */ |
| 108 | 1, 36, 40, KdSyncPositive, /* 84.997 */ |
| 109 | }, |
| 110 | {1024, 768, 75, 78750, /* VESA */ |
| 111 | 16, 176, 288, KdSyncPositive, /* 60.023 */ |
| 112 | 1, 28, 32, KdSyncPositive, /* 75.029 */ |
| 113 | }, |
| 114 | {1024, 768, 70, 75000, /* VESA */ |
| 115 | 24, 144, 304, KdSyncNegative, /* 56.476 */ |
| 116 | 3, 29, 38, KdSyncNegative, /* 70.069 */ |
| 117 | }, |
| 118 | {1024, 768, 60, 65000, /* VESA */ |
| 119 | 24, 160, 320, KdSyncNegative, /* 48.363 */ |
| 120 | 3, 29, 38, KdSyncNegative, /* 60.004 */ |
| 121 | }, |
| 122 | |
| 123 | /* 1152x864 mode */ |
| 124 | {1152, 864, 75, 108000, /* VESA */ |
| 125 | 64, 256, 448, KdSyncPositive, /* 67.500 */ |
| 126 | 1, 32, 36, KdSyncPositive, /* 75.000 */ |
| 127 | }, |
| 128 | |
| 129 | /* 1152x900 modes */ |
| 130 | {1152, 900, 85, 122500, /* ADDED */ |
| 131 | 48, 208, 384, KdSyncPositive, /* 79.753 */ |
| 132 | 1, 32, 38, KdSyncPositive, /* 85.024 */ |
| 133 | }, |
| 134 | {1152, 900, 75, 108250, /* ADDED */ |
| 135 | 32, 208, 384, KdSyncPositive, /* 70.475 */ |
| 136 | 1, 32, 38, KdSyncPositive, /* 75.133 */ |
| 137 | }, |
| 138 | {1152, 900, 70, 100250, /* ADDED */ |
| 139 | 32, 208, 384, KdSyncPositive, /* 65.267 */ |
| 140 | 2, 32, 38, KdSyncPositive, /* 69.581 */ |
| 141 | }, |
| 142 | {1152, 900, 66, 95000, /* ADDED */ |
| 143 | 32, 208, 384, KdSyncPositive, /* 61.849 */ |
| 144 | 1, 32, 38, KdSyncPositive, /* 65.937 */ |
| 145 | }, |
| 146 | |
| 147 | /* 1280x854 modes */ |
| 148 | {1280, 854, 103, 12500, /* ADDED */ |
| 149 | 56, 16, 128, KdSyncPositive, /* 102.554 */ |
| 150 | 1, 216, 12, KdSyncPositive, |
| 151 | }, |
| 152 | |
| 153 | /* 1280x960 modes */ |
| 154 | {1280, 960, 85, 148500, /* VESA */ |
| 155 | 64, 224, 448, KdSyncPositive, /* 85.938 */ |
| 156 | 1, 47, 51, KdSyncPositive, /* 85.002 */ |
| 157 | }, |
| 158 | {1280, 960, 60, 108000, /* VESA */ |
| 159 | 96, 312, 520, KdSyncPositive, /* 60.000 */ |
| 160 | 1, 36, 40, KdSyncPositive, /* 60.000 */ |
| 161 | }, |
| 162 | |
| 163 | /* 1280x1024 modes */ |
| 164 | {1280, 1024, 85, 157500, /* VESA */ |
| 165 | 64, 224, 448, KdSyncPositive, /* 91.146 */ |
| 166 | 1, 44, 48, KdSyncPositive, /* 85.024 */ |
| 167 | }, |
| 168 | {1280, 1024, 75, 135000, /* VESA */ |
| 169 | 16, 248, 408, KdSyncPositive, /* 79.976 */ |
| 170 | 1, 38, 42, KdSyncPositive, /* 75.025 */ |
| 171 | }, |
| 172 | {1280, 1024, 60, 108000, /* VESA */ |
| 173 | 48, 248, 408, KdSyncPositive, /* 63.981 */ |
| 174 | 1, 38, 42, KdSyncPositive, /* 60.020 */ |
| 175 | }, |
| 176 | |
| 177 | /* 1600x1200 modes */ |
| 178 | {1600, 1200, 85, 229500, /* VESA */ |
| 179 | 64, 304, 560, KdSyncPositive, /* 106.250 */ |
| 180 | 1, 46, 50, KdSyncPositive, /* 85.000 */ |
| 181 | }, |
| 182 | {1600, 1200, 75, 202500, /* VESA */ |
| 183 | 64, 304, 560, KdSyncPositive, /* 93.750 */ |
| 184 | 1, 46, 50, KdSyncPositive, /* 75.000 */ |
| 185 | }, |
| 186 | {1600, 1200, 70, 189000, /* VESA */ |
| 187 | 64, 304, 560, KdSyncPositive, /* 87.500 */ |
| 188 | 1, 46, 50, KdSyncPositive, /* 70.000 */ |
| 189 | }, |
| 190 | {1600, 1200, 65, 175500, /* VESA */ |
| 191 | 64, 304, 560, KdSyncPositive, /* 81.250 */ |
| 192 | 1, 46, 50, KdSyncPositive, /* 65.000 */ |
| 193 | }, |
| 194 | {1600, 1200, 60, 162000, /* VESA */ |
| 195 | 64, 304, 560, KdSyncPositive, /* 75.000 */ |
| 196 | 1, 46, 50, KdSyncPositive, /* 60.000 */ |
| 197 | }, |
| 198 | |
| 199 | /* 1792x1344 modes */ |
| 200 | {1792, 1344, 85, 301500, /* ADDED */ |
| 201 | 96, 352, 672, KdSyncNegative, /* 122.362 */ |
| 202 | 1, 92, 96, KdSyncPositive, /* 84.974 */ |
| 203 | }, |
| 204 | {1792, 1344, 75, 261000, /* VESA */ |
| 205 | 96, 352, 664, KdSyncNegative, /* 106.270 */ |
| 206 | 1, 69, 73, KdSyncPositive, /* 74.997 */ |
| 207 | }, |
| 208 | {1792, 1344, 60, 204750, /* VESA */ |
| 209 | 128, 328, 656, KdSyncNegative, /* 83.640 */ |
| 210 | 1, 46, 50, KdSyncPositive, /* 60.000 */ |
| 211 | }, |
| 212 | |
| 213 | #if 0 |
| 214 | {1800, 1012, 75}, |
| 215 | {1906, 1072, 68}, |
| 216 | #endif |
| 217 | |
| 218 | /* 1856x1392 modes */ |
| 219 | {1856, 1392, 85, 330500, /* ADDED */ |
| 220 | 160, 352, 736, KdSyncNegative, /* 127.508 */ |
| 221 | 1, 104, 108, KdSyncPositive, /* 85.001 */ |
| 222 | }, |
| 223 | {1856, 1392, 75, 288000, /* VESA */ |
| 224 | 128, 352, 704, KdSyncNegative, /* 112.500 */ |
| 225 | 1, 104, 108, KdSyncPositive, /* 75.000 */ |
| 226 | }, |
| 227 | {1856, 1392, 60, 218250, /* VESA */ |
| 228 | 96, 352, 672, KdSyncNegative, /* 86.333 */ |
| 229 | 1, 43, 47, KdSyncPositive, /* 59.995 */ |
| 230 | }, |
| 231 | |
| 232 | /* 1920x1440 modes */ |
| 233 | {1920, 1440, 85, 341750, /* ADDED */ |
| 234 | 160, 352, 760, KdSyncNegative, /* 127.512 */ |
| 235 | 1, 56, 60, KdSyncPositive, /* 85.012 */ |
| 236 | }, |
| 237 | {1920, 1440, 75, 297000, /* VESA */ |
| 238 | 144, 352, 720, KdSyncNegative, /* 112.500 */ |
| 239 | 1, 56, 60, KdSyncPositive, /* 75.000 */ |
| 240 | }, |
| 241 | {1920, 1440, 60, 234000, /* VESA */ |
| 242 | 128, 244, 680, KdSyncNegative, /* 90.000 */ |
| 243 | 1, 56, 60, KdSyncPositive, /* 60.000 */ |
| 244 | }, |
| 245 | }; |
| 246 | |
| 247 | #define NUM_MONITOR_TIMINGS (sizeof kdMonitorTimings/sizeof kdMonitorTimings[0]) |
| 248 | |
| 249 | const int kdNumMonitorTimings = NUM_MONITOR_TIMINGS; |
| 250 | |
| 251 | const KdMonitorTiming * |
| 252 | KdFindMode(KdScreenInfo * screen, |
| 253 | Bool (*supported) (KdScreenInfo *, const KdMonitorTiming *)) |
| 254 | { |
| 255 | int i; |
| 256 | const KdMonitorTiming *t; |
| 257 | |
| 258 | for (i = 0, t = kdMonitorTimings; i < NUM_MONITOR_TIMINGS; i++, t++) { |
| 259 | if ((*supported) (screen, t) && |
| 260 | t->horizontal == screen->width && |
| 261 | t->vertical == screen->height && |
| 262 | (!screen->rate || t->rate <= screen->rate)) { |
| 263 | return t; |
| 264 | } |
| 265 | } |
| 266 | ErrorF("Warning: mode not found, using default\n"); |
| 267 | return &kdMonitorTimings[MONITOR_TIMING_DEFAULT]; |
| 268 | } |
| 269 | |
| 270 | static const KdMonitorTiming * |
| 271 | kdFindPrevSize(const KdMonitorTiming * old) |
| 272 | { |
| 273 | const KdMonitorTiming *new, *prev; |
| 274 | |
| 275 | if (old == kdMonitorTimings) |
| 276 | return 0; |
| 277 | new = old; |
| 278 | /* |
| 279 | * Search for the previous size |
| 280 | */ |
| 281 | while (new != kdMonitorTimings) { |
| 282 | new--; |
| 283 | if (new->horizontal != old->horizontal && |
| 284 | new->vertical != old->vertical) { |
| 285 | break; |
| 286 | } |
| 287 | } |
| 288 | /* |
| 289 | * Match the refresh rate (<=) |
| 290 | */ |
| 291 | while (new != kdMonitorTimings) { |
| 292 | prev = new - 1; |
| 293 | if (prev->horizontal == new->horizontal && |
| 294 | prev->vertical == new->vertical && prev->rate > old->rate) { |
| 295 | break; |
| 296 | } |
| 297 | new--; |
| 298 | } |
| 299 | return new; |
| 300 | } |
| 301 | |
| 302 | Bool |
| 303 | KdTuneMode(KdScreenInfo * screen, |
| 304 | Bool (*usable) (KdScreenInfo *), |
| 305 | Bool (*supported) (KdScreenInfo *, const KdMonitorTiming *)) |
| 306 | { |
| 307 | const KdMonitorTiming *t; |
| 308 | |
| 309 | while (!(*usable) (screen)) { |
| 310 | /* |
| 311 | * Fix requested depth and geometry until it works |
| 312 | */ |
| 313 | if (screen->fb.depth > 16) |
| 314 | screen->fb.depth = 16; |
| 315 | else if (screen->fb.depth > 8) |
| 316 | screen->fb.depth = 8; |
| 317 | else { |
| 318 | t = kdFindPrevSize(KdFindMode(screen, supported)); |
| 319 | if (!t) |
| 320 | return FALSE; |
| 321 | screen->width = t->horizontal; |
| 322 | screen->height = t->vertical; |
| 323 | screen->rate = t->rate; |
| 324 | } |
| 325 | } |
| 326 | return TRUE; |
| 327 | } |
| 328 | |
| 329 | #ifdef RANDR |
| 330 | Bool |
| 331 | KdRandRGetInfo(ScreenPtr pScreen, |
| 332 | int randr, |
| 333 | Bool (*supported) (ScreenPtr pScreen, const KdMonitorTiming *)) |
| 334 | { |
| 335 | KdScreenPriv(pScreen); |
| 336 | KdScreenInfo *screen = pScreenPriv->screen; |
| 337 | int i; |
| 338 | const KdMonitorTiming *t; |
| 339 | |
| 340 | for (i = 0, t = kdMonitorTimings; i < NUM_MONITOR_TIMINGS; i++, t++) { |
| 341 | if ((*supported) (pScreen, t)) { |
| 342 | RRScreenSizePtr pSize; |
| 343 | |
| 344 | pSize = RRRegisterSize(pScreen, |
| 345 | t->horizontal, |
| 346 | t->vertical, |
| 347 | screen->width_mm, screen->height_mm); |
| 348 | if (!pSize) |
| 349 | return FALSE; |
| 350 | if (!RRRegisterRate(pScreen, pSize, t->rate)) |
| 351 | return FALSE; |
| 352 | if (t->horizontal == screen->width && |
| 353 | t->vertical == screen->height && t->rate == screen->rate) |
| 354 | RRSetCurrentConfig(pScreen, randr, t->rate, pSize); |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | return TRUE; |
| 359 | } |
| 360 | |
| 361 | const KdMonitorTiming * |
| 362 | KdRandRGetTiming(ScreenPtr pScreen, |
| 363 | Bool (*supported) (ScreenPtr pScreen, |
| 364 | const KdMonitorTiming *), |
| 365 | int rate, RRScreenSizePtr pSize) |
| 366 | { |
| 367 | int i; |
| 368 | const KdMonitorTiming *t; |
| 369 | |
| 370 | for (i = 0, t = kdMonitorTimings; i < NUM_MONITOR_TIMINGS; i++, t++) { |
| 371 | if (t->horizontal == pSize->width && |
| 372 | t->vertical == pSize->height && |
| 373 | t->rate == rate && (*supported) (pScreen, t)) |
| 374 | return t; |
| 375 | } |
| 376 | return 0; |
| 377 | } |
| 378 | #endif |