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 29const 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 57 /* Modeline "720x576" 29.000 720 736 800 880 576 577 580 625 */ 58 { 59 720, 576, 52, 32954, /* PAL Video */ 60 16, 80, 160, KdSyncPositive, /* 32.954 */ 61 1, 45, 49, KdSyncPositive, /* 52.727 */ 62 }, 63 64 /* 640x480 modes */ 65 { 640, 480, 85, 36000, /* VESA */ 66 56, 80, 192, KdSyncNegative, /* 43.269 */ 67 1, 25, 29, KdSyncNegative, /* 85.008 */ 68 }, 69 { 640, 480, 75, 31500, /* VESA */ 70 16, 120, 200, KdSyncNegative, /* 37.500 */ 71 1, 16, 20, KdSyncNegative, /* 75.000 */ 72 }, 73 { 640, 480, 72, 31500, /* VESA */ 74 16, 120, 176, KdSyncNegative, /* 37.861 */ 75 1, 20, 24, KdSyncNegative, /* 72.809 */ 76 }, 77 { 640, 480, 60, 25175, /* VESA */ 78 16, 48, 160, KdSyncNegative, /* 31.469 */ 79 10, 33, 45, KdSyncNegative, /* 59.940 */ 80 }, 81 82 /* 800x600 modes */ 83 { 800, 600, 85, 56250, /* VESA */ 84 32, 152, 248, KdSyncPositive, /* 53.674 */ 85 1, 27, 31, KdSyncPositive, /* 85.061 */ 86 }, 87 { 800, 600, 75, 49500, /* VESA */ 88 16, 160, 256, KdSyncPositive, /* 46.875 */ 89 1, 21, 25, KdSyncPositive, /* 75.000 */ 90 }, 91 /* DEFAULT */ 92#define MONITOR_TIMING_DEFAULT 9 93 { 800, 600, 72, 50000, /* VESA */ 94 56, 64, 240, KdSyncPositive, /* 48.077 */ 95 37, 23, 66, KdSyncPositive, /* 72.188 */ 96 }, 97 { 800, 600, 60, 40000, /* VESA */ 98 40, 88, 256, KdSyncPositive, /* 37.879 */ 99 1, 23, 28, KdSyncPositive, /* 60.317 */ 100 }, 101 { 800, 600, 56, 36000, /* VESA */ 102 24, 128, 224, KdSyncPositive, /* 35.156 */ 103 1, 22, 25, KdSyncPositive, /* 56.250 */ 104 }, 105 106 /* 1024x768 modes */ 107 { 1024, 768, 85, 94500, /* VESA */ 108 48, 208, 352, KdSyncPositive, /* 68.677 */ 109 1, 36, 40, KdSyncPositive, /* 84.997 */ 110 }, 111 { 1024, 768, 75, 78750, /* VESA */ 112 16, 176, 288, KdSyncPositive, /* 60.023 */ 113 1, 28, 32, KdSyncPositive, /* 75.029 */ 114 }, 115 { 1024, 768, 70, 75000, /* VESA */ 116 24, 144, 304, KdSyncNegative, /* 56.476 */ 117 3, 29, 38, KdSyncNegative, /* 70.069 */ 118 }, 119 { 1024, 768, 60, 65000, /* VESA */ 120 24, 160, 320, KdSyncNegative, /* 48.363 */ 121 3, 29, 38, KdSyncNegative, /* 60.004 */ 122 }, 123 124 /* 1152x864 mode */ 125 { 1152, 864, 75, 108000, /* VESA */ 126 64, 256, 448, KdSyncPositive, /* 67.500 */ 127 1, 32, 36, KdSyncPositive, /* 75.000 */ 128 }, 129 130 /* 1152x900 modes */ 131 { 1152, 900, 85, 122500, /* ADDED */ 132 48, 208, 384, KdSyncPositive, /* 79.753 */ 133 1, 32, 38, KdSyncPositive, /* 85.024 */ 134 }, 135 { 1152, 900, 75, 108250, /* ADDED */ 136 32, 208, 384, KdSyncPositive, /* 70.475 */ 137 1, 32, 38, KdSyncPositive, /* 75.133 */ 138 }, 139 { 1152, 900, 70, 100250, /* ADDED */ 140 32, 208, 384, KdSyncPositive, /* 65.267 */ 141 2, 32, 38, KdSyncPositive, /* 69.581 */ 142 }, 143 { 1152, 900, 66, 95000, /* ADDED */ 144 32, 208, 384, KdSyncPositive, /* 61.849 */ 145 1, 32, 38, KdSyncPositive, /* 65.937 */ 146 }, 147 148 /* 1280x854 modes */ 149 { 1280, 854, 103, 12500, /* ADDED */ 150 56, 16, 128, KdSyncPositive, /* 102.554 */ 151 1, 216, 12, KdSyncPositive, 152 }, 153 154 /* 1280x960 modes */ 155 { 1280, 960, 85, 148500, /* VESA */ 156 64, 224, 448, KdSyncPositive, /* 85.938 */ 157 1, 47, 51, KdSyncPositive, /* 85.002 */ 158 }, 159 { 1280, 960, 60, 108000, /* VESA */ 160 96, 312, 520, KdSyncPositive, /* 60.000 */ 161 1, 36, 40, KdSyncPositive, /* 60.000 */ 162 }, 163 164 /* 1280x1024 modes */ 165 { 1280, 1024, 85, 157500, /* VESA */ 166 64, 224, 448, KdSyncPositive, /* 91.146 */ 167 1, 44, 48, KdSyncPositive, /* 85.024 */ 168 }, 169 { 1280, 1024, 75, 135000, /* VESA */ 170 16, 248, 408, KdSyncPositive, /* 79.976 */ 171 1, 38, 42, KdSyncPositive, /* 75.025 */ 172 }, 173 { 1280, 1024, 60, 108000, /* VESA */ 174 48, 248, 408, KdSyncPositive, /* 63.981 */ 175 1, 38, 42, KdSyncPositive, /* 60.020 */ 176 }, 177 178 /* 1600x1200 modes */ 179 { 1600, 1200, 85, 229500, /* VESA */ 180 64, 304, 560, KdSyncPositive, /* 106.250 */ 181 1, 46, 50, KdSyncPositive, /* 85.000 */ 182 }, 183 { 1600, 1200, 75, 202500, /* VESA */ 184 64, 304, 560, KdSyncPositive, /* 93.750 */ 185 1, 46, 50, KdSyncPositive, /* 75.000 */ 186 }, 187 { 1600, 1200, 70, 189000, /* VESA */ 188 64, 304, 560, KdSyncPositive, /* 87.500 */ 189 1, 46, 50, KdSyncPositive, /* 70.000 */ 190 }, 191 { 1600, 1200, 65, 175500, /* VESA */ 192 64, 304, 560, KdSyncPositive, /* 81.250 */ 193 1, 46, 50, KdSyncPositive, /* 65.000 */ 194 }, 195 { 1600, 1200, 60, 162000, /* VESA */ 196 64, 304, 560, KdSyncPositive, /* 75.000 */ 197 1, 46, 50, KdSyncPositive, /* 60.000 */ 198 }, 199 200 /* 1792x1344 modes */ 201 { 1792, 1344, 85, 301500, /* ADDED */ 202 96, 352, 672, KdSyncNegative, /* 122.362 */ 203 1, 92, 96, KdSyncPositive, /* 84.974 */ 204 }, 205 { 1792, 1344, 75, 261000, /* VESA */ 206 96, 352, 664, KdSyncNegative, /* 106.270 */ 207 1, 69, 73, KdSyncPositive, /* 74.997 */ 208 }, 209 { 1792, 1344, 60, 204750, /* VESA */ 210 128, 328, 656, KdSyncNegative, /* 83.640 */ 211 1, 46, 50, KdSyncPositive, /* 60.000 */ 212 }, 213 214#if 0 215 { 1800, 1012, 75 }, 216 { 1906, 1072, 68 }, 217#endif 218 219 /* 1856x1392 modes */ 220 { 1856, 1392, 85, 330500, /* ADDED */ 221 160, 352, 736, KdSyncNegative, /* 127.508 */ 222 1, 104, 108, KdSyncPositive, /* 85.001 */ 223 }, 224 { 1856, 1392, 75, 288000, /* VESA */ 225 128, 352, 704, KdSyncNegative, /* 112.500 */ 226 1, 104, 108, KdSyncPositive, /* 75.000 */ 227 }, 228 { 1856, 1392, 60, 218250, /* VESA */ 229 96, 352, 672, KdSyncNegative, /* 86.333 */ 230 1, 43, 47, KdSyncPositive, /* 59.995 */ 231 }, 232 233 /* 1920x1440 modes */ 234 { 1920, 1440, 85, 341750, /* ADDED */ 235 160, 352, 760, KdSyncNegative, /* 127.512 */ 236 1, 56, 60, KdSyncPositive, /* 85.012 */ 237 }, 238 { 1920, 1440, 75, 297000, /* VESA */ 239 144, 352, 720, KdSyncNegative, /* 112.500 */ 240 1, 56, 60, KdSyncPositive, /* 75.000 */ 241 }, 242 { 1920, 1440, 60, 234000, /* VESA */ 243 128, 244, 680, KdSyncNegative, /* 90.000 */ 244 1, 56, 60, KdSyncPositive, /* 60.000 */ 245 }, 246}; 247 248#define NUM_MONITOR_TIMINGS (sizeof kdMonitorTimings/sizeof kdMonitorTimings[0]) 249 250const int kdNumMonitorTimings = NUM_MONITOR_TIMINGS; 251 252const KdMonitorTiming * 253KdFindMode (KdScreenInfo *screen, 254 Bool (*supported) (KdScreenInfo *, 255 const KdMonitorTiming *)) 256{ 257 int i; 258 const KdMonitorTiming *t; 259 260 for (i = 0, t = kdMonitorTimings; i < NUM_MONITOR_TIMINGS; i++, t++) 261 { 262 if ((*supported) (screen, t) && 263 t->horizontal == screen->width && 264 t->vertical == screen->height && 265 (!screen->rate || t->rate <= screen->rate)) 266 { 267 return t; 268 } 269 } 270 ErrorF("Warning: mode not found, using default\n"); 271 return &kdMonitorTimings[MONITOR_TIMING_DEFAULT]; 272} 273 274static const KdMonitorTiming * 275kdFindPrevSize (const KdMonitorTiming *old) 276{ 277 const KdMonitorTiming *new, *prev; 278 279 if (old == kdMonitorTimings) 280 return 0; 281 new = old; 282 /* 283 * Search for the previous size 284 */ 285 while (new != kdMonitorTimings) 286 { 287 new--; 288 if (new->horizontal != old->horizontal && 289 new->vertical != old->vertical) 290 { 291 break; 292 } 293 } 294 /* 295 * Match the refresh rate (<=) 296 */ 297 while (new != kdMonitorTimings) 298 { 299 prev = new - 1; 300 if (prev->horizontal == new->horizontal && 301 prev->vertical == new->vertical && 302 prev->rate > old->rate) 303 { 304 break; 305 } 306 new--; 307 } 308 return new; 309} 310 311Bool 312KdTuneMode (KdScreenInfo *screen, 313 Bool (*usable) (KdScreenInfo *), 314 Bool (*supported) (KdScreenInfo *, 315 const KdMonitorTiming *)) 316{ 317 const KdMonitorTiming *t; 318 319 while (!(*usable) (screen)) 320 { 321 /* 322 * Fix requested depth and geometry until it works 323 */ 324 if (screen->fb.depth > 16) 325 screen->fb.depth = 16; 326 else if (screen->fb.depth > 8) 327 screen->fb.depth = 8; 328 else 329 { 330 t = kdFindPrevSize (KdFindMode (screen, supported)); 331 if (!t) 332 return FALSE; 333 screen->width = t->horizontal; 334 screen->height = t->vertical; 335 screen->rate = t->rate; 336 } 337 } 338 return TRUE; 339} 340 341#ifdef RANDR 342Bool 343KdRandRGetInfo (ScreenPtr pScreen, 344 int randr, 345 Bool (*supported) (ScreenPtr pScreen, 346 const KdMonitorTiming *)) 347{ 348 KdScreenPriv(pScreen); 349 KdScreenInfo *screen = pScreenPriv->screen; 350 int i; 351 const KdMonitorTiming *t; 352 353 for (i = 0, t = kdMonitorTimings; i < NUM_MONITOR_TIMINGS; i++, t++) 354 { 355 if ((*supported) (pScreen, t)) 356 { 357 RRScreenSizePtr pSize; 358 359 pSize = RRRegisterSize (pScreen, 360 t->horizontal, 361 t->vertical, 362 screen->width_mm, 363 screen->height_mm); 364 if (!pSize) 365 return FALSE; 366 if (!RRRegisterRate (pScreen, pSize, t->rate)) 367 return FALSE; 368 if (t->horizontal == screen->width && 369 t->vertical == screen->height && 370 t->rate == screen->rate) 371 RRSetCurrentConfig (pScreen, randr, t->rate, pSize); 372 } 373 } 374 375 return TRUE; 376} 377 378const KdMonitorTiming * 379KdRandRGetTiming (ScreenPtr pScreen, 380 Bool (*supported) (ScreenPtr pScreen, 381 const KdMonitorTiming *), 382 int rate, 383 RRScreenSizePtr pSize) 384{ 385 int i; 386 const KdMonitorTiming *t; 387 388 for (i = 0, t = kdMonitorTimings; i < NUM_MONITOR_TIMINGS; i++, t++) 389 { 390 if (t->horizontal == pSize->width && 391 t->vertical == pSize->height && 392 t->rate == rate && 393 (*supported) (pScreen, t)) 394 return t; 395 } 396 return 0; 397} 398#endif 399