xf86Mode.c revision 4642e01f
1/* 2 * Copyright (c) 1997-2003 by The XFree86 Project, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Except as contained in this notice, the name of the copyright holder(s) 23 * and author(s) shall not be used in advertising or otherwise to promote 24 * the sale, use or other dealings in this Software without prior written 25 * authorization from the copyright holder(s) and author(s). 26 */ 27 28/* 29 * Authors: Dirk Hohndel <hohndel@XFree86.Org> 30 * David Dawes <dawes@XFree86.Org> 31 * Marc La France <tsi@XFree86.Org> 32 * ... and others 33 * 34 * This file includes helper functions for mode related things. 35 */ 36 37#ifdef HAVE_XORG_CONFIG_H 38#include <xorg-config.h> 39#endif 40 41#include <X11/X.h> 42#include "xf86Modes.h" 43#include "os.h" 44#include "servermd.h" 45#include "mibank.h" 46#include "globals.h" 47#include "xf86.h" 48#include "xf86Priv.h" 49#include "edid.h" 50 51static void 52printModeRejectMessage(int index, DisplayModePtr p, int status) 53{ 54 char *type; 55 56 if (p->type & M_T_BUILTIN) 57 type = "built-in "; 58 else if (p->type & M_T_DEFAULT) 59 type = "default "; 60 else if (p->type & M_T_DRIVER) 61 type = "driver "; 62 else 63 type = ""; 64 65 xf86DrvMsg(index, X_INFO, "Not using %smode \"%s\" (%s)\n", type, p->name, 66 xf86ModeStatusToString(status)); 67} 68 69/* 70 * xf86GetNearestClock -- 71 * Find closest clock to given frequency (in kHz). This assumes the 72 * number of clocks is greater than zero. 73 */ 74_X_EXPORT int 75xf86GetNearestClock(ScrnInfoPtr scrp, int freq, Bool allowDiv2, 76 int DivFactor, int MulFactor, int *divider) 77{ 78 int nearestClock = 0, nearestDiv = 1; 79 int minimumGap = abs(freq - scrp->clock[0]); 80 int i, j, k, gap; 81 82 if (allowDiv2) 83 k = 2; 84 else 85 k = 1; 86 87 /* Must set this here in case the best match is scrp->clock[0] */ 88 if (divider != NULL) 89 *divider = 0; 90 91 for (i = 0; i < scrp->numClocks; i++) { 92 for (j = 1; j <= k; j++) { 93 gap = abs((freq * j) - ((scrp->clock[i] * DivFactor) / MulFactor)); 94 if ((gap < minimumGap) || 95 ((gap == minimumGap) && (j < nearestDiv))) { 96 minimumGap = gap; 97 nearestClock = i; 98 nearestDiv = j; 99 if (divider != NULL) 100 *divider = (j - 1) * V_CLKDIV2; 101 } 102 } 103 } 104 return nearestClock; 105} 106 107/* 108 * xf86ModeStatusToString 109 * 110 * Convert a ModeStatus value to a printable message 111 */ 112 113_X_EXPORT const char * 114xf86ModeStatusToString(ModeStatus status) 115{ 116 switch (status) { 117 case MODE_OK: 118 return "Mode OK"; 119 case MODE_HSYNC: 120 return "hsync out of range"; 121 case MODE_VSYNC: 122 return "vrefresh out of range"; 123 case MODE_H_ILLEGAL: 124 return "illegal horizontal timings"; 125 case MODE_V_ILLEGAL: 126 return "illegal vertical timings"; 127 case MODE_BAD_WIDTH: 128 return "width requires unsupported line pitch"; 129 case MODE_NOMODE: 130 return "no mode of this name"; 131 case MODE_NO_INTERLACE: 132 return "interlace mode not supported"; 133 case MODE_NO_DBLESCAN: 134 return "doublescan mode not supported"; 135 case MODE_NO_VSCAN: 136 return "multiscan mode not supported"; 137 case MODE_MEM: 138 return "insufficient memory for mode"; 139 case MODE_VIRTUAL_X: 140 return "width too large for virtual size"; 141 case MODE_VIRTUAL_Y: 142 return "height too large for virtual size"; 143 case MODE_MEM_VIRT: 144 return "insufficient memory given virtual size"; 145 case MODE_NOCLOCK: 146 return "no clock available for mode"; 147 case MODE_CLOCK_HIGH: 148 return "mode clock too high"; 149 case MODE_CLOCK_LOW: 150 return "mode clock too low"; 151 case MODE_CLOCK_RANGE: 152 return "bad mode clock/interlace/doublescan"; 153 case MODE_BAD_HVALUE: 154 return "horizontal timing out of range"; 155 case MODE_BAD_VVALUE: 156 return "vertical timing out of range"; 157 case MODE_BAD_VSCAN: 158 return "VScan value out of range"; 159 case MODE_HSYNC_NARROW: 160 return "horizontal sync too narrow"; 161 case MODE_HSYNC_WIDE: 162 return "horizontal sync too wide"; 163 case MODE_HBLANK_NARROW: 164 return "horizontal blanking too narrow"; 165 case MODE_HBLANK_WIDE: 166 return "horizontal blanking too wide"; 167 case MODE_VSYNC_NARROW: 168 return "vertical sync too narrow"; 169 case MODE_VSYNC_WIDE: 170 return "vertical sync too wide"; 171 case MODE_VBLANK_NARROW: 172 return "vertical blanking too narrow"; 173 case MODE_VBLANK_WIDE: 174 return "vertical blanking too wide"; 175 case MODE_PANEL: 176 return "exceeds panel dimensions"; 177 case MODE_INTERLACE_WIDTH: 178 return "width too large for interlaced mode"; 179 case MODE_ONE_WIDTH: 180 return "all modes must have the same width"; 181 case MODE_ONE_HEIGHT: 182 return "all modes must have the same height"; 183 case MODE_ONE_SIZE: 184 return "all modes must have the same resolution"; 185 case MODE_NO_REDUCED: 186 return "monitor doesn't support reduced blanking"; 187 case MODE_BANDWIDTH: 188 return "mode requires too much memory bandwidth"; 189 case MODE_BAD: 190 return "unknown reason"; 191 case MODE_ERROR: 192 return "internal error"; 193 default: 194 return "unknown"; 195 } 196} 197 198/* 199 * xf86ShowClockRanges() -- Print the clock ranges allowed 200 * and the clock values scaled by ClockMulFactor and ClockDivFactor 201 */ 202_X_EXPORT void 203xf86ShowClockRanges(ScrnInfoPtr scrp, ClockRangePtr clockRanges) 204{ 205 ClockRangePtr cp; 206 int MulFactor = 1; 207 int DivFactor = 1; 208 int i, j; 209 int scaledClock; 210 211 for (cp = clockRanges; cp != NULL; cp = cp->next) { 212 DivFactor = max(1, cp->ClockDivFactor); 213 MulFactor = max(1, cp->ClockMulFactor); 214 if (scrp->progClock) { 215 if (cp->minClock) { 216 if (cp->maxClock) { 217 xf86DrvMsg(scrp->scrnIndex, X_INFO, 218 "Clock range: %6.2f to %6.2f MHz\n", 219 (double)cp->minClock / 1000.0, 220 (double)cp->maxClock / 1000.0); 221 } else { 222 xf86DrvMsg(scrp->scrnIndex, X_INFO, 223 "Minimum clock: %6.2f MHz\n", 224 (double)cp->minClock / 1000.0); 225 } 226 } else { 227 if (cp->maxClock) { 228 xf86DrvMsg(scrp->scrnIndex, X_INFO, 229 "Maximum clock: %6.2f MHz\n", 230 (double)cp->maxClock / 1000.0); 231 } 232 } 233 } else if (DivFactor > 1 || MulFactor > 1) { 234 j = 0; 235 for (i = 0; i < scrp->numClocks; i++) { 236 scaledClock = (scrp->clock[i] * DivFactor) / MulFactor; 237 if (scaledClock >= cp->minClock && scaledClock <= cp->maxClock) { 238 if ((j % 8) == 0) { 239 if (j > 0) 240 xf86ErrorF("\n"); 241 xf86DrvMsg(scrp->scrnIndex, X_INFO, "scaled clocks:"); 242 } 243 xf86ErrorF(" %6.2f", (double)scaledClock / 1000.0); 244 j++; 245 } 246 } 247 xf86ErrorF("\n"); 248 } 249 } 250} 251 252 253/* 254 * xf86FindClockRangeForMode() [... like the name says ...] 255 */ 256static ClockRangePtr 257xf86FindClockRangeForMode(ClockRangePtr clockRanges, DisplayModePtr p) 258{ 259 ClockRangePtr cp; 260 261 for (cp = clockRanges; ; cp = cp->next) 262 if (!cp || 263 ((p->Clock >= cp->minClock) && 264 (p->Clock <= cp->maxClock) && 265 (cp->interlaceAllowed || !(p->Flags & V_INTERLACE)) && 266 (cp->doubleScanAllowed || 267 ((p->VScan <= 1) && !(p->Flags & V_DBLSCAN))))) 268 return cp; 269} 270 271 272/* 273 * xf86HandleBuiltinMode() - handles built-in modes 274 */ 275static ModeStatus 276xf86HandleBuiltinMode(ScrnInfoPtr scrp, 277 DisplayModePtr p, 278 DisplayModePtr modep, 279 ClockRangePtr clockRanges, 280 Bool allowDiv2) 281{ 282 ClockRangePtr cp; 283 int extraFlags = 0; 284 int MulFactor = 1; 285 int DivFactor = 1; 286 int clockIndex; 287 288 /* Reject previously rejected modes */ 289 if (p->status != MODE_OK) 290 return p->status; 291 292 /* Reject previously considered modes */ 293 if (p->prev) 294 return MODE_NOMODE; 295 296 if ((p->type & M_T_CLOCK_C) == M_T_CLOCK_C) { 297 /* Check clock is in range */ 298 cp = xf86FindClockRangeForMode(clockRanges, p); 299 if (cp == NULL){ 300 modep->type = p->type; 301 p->status = MODE_CLOCK_RANGE; 302 return MODE_CLOCK_RANGE; 303 } 304 DivFactor = cp->ClockDivFactor; 305 MulFactor = cp->ClockMulFactor; 306 if (!scrp->progClock) { 307 clockIndex = xf86GetNearestClock(scrp, p->Clock, allowDiv2, 308 cp->ClockDivFactor, 309 cp->ClockMulFactor, &extraFlags); 310 modep->Clock = (scrp->clock[clockIndex] * DivFactor) 311 / MulFactor; 312 modep->ClockIndex = clockIndex; 313 modep->SynthClock = scrp->clock[clockIndex]; 314 if (extraFlags & V_CLKDIV2) { 315 modep->Clock /= 2; 316 modep->SynthClock /= 2; 317 } 318 } else { 319 modep->Clock = p->Clock; 320 modep->ClockIndex = -1; 321 modep->SynthClock = (modep->Clock * MulFactor) 322 / DivFactor; 323 } 324 modep->PrivFlags = cp->PrivFlags; 325 } else { 326 if(!scrp->progClock) { 327 modep->Clock = p->Clock; 328 modep->ClockIndex = p->ClockIndex; 329 modep->SynthClock = p->SynthClock; 330 } else { 331 modep->Clock = p->Clock; 332 modep->ClockIndex = -1; 333 modep->SynthClock = p->SynthClock; 334 } 335 modep->PrivFlags = p->PrivFlags; 336 } 337 modep->type = p->type; 338 modep->HDisplay = p->HDisplay; 339 modep->HSyncStart = p->HSyncStart; 340 modep->HSyncEnd = p->HSyncEnd; 341 modep->HTotal = p->HTotal; 342 modep->HSkew = p->HSkew; 343 modep->VDisplay = p->VDisplay; 344 modep->VSyncStart = p->VSyncStart; 345 modep->VSyncEnd = p->VSyncEnd; 346 modep->VTotal = p->VTotal; 347 modep->VScan = p->VScan; 348 modep->Flags = p->Flags | extraFlags; 349 modep->CrtcHDisplay = p->CrtcHDisplay; 350 modep->CrtcHBlankStart = p->CrtcHBlankStart; 351 modep->CrtcHSyncStart = p->CrtcHSyncStart; 352 modep->CrtcHSyncEnd = p->CrtcHSyncEnd; 353 modep->CrtcHBlankEnd = p->CrtcHBlankEnd; 354 modep->CrtcHTotal = p->CrtcHTotal; 355 modep->CrtcHSkew = p->CrtcHSkew; 356 modep->CrtcVDisplay = p->CrtcVDisplay; 357 modep->CrtcVBlankStart = p->CrtcVBlankStart; 358 modep->CrtcVSyncStart = p->CrtcVSyncStart; 359 modep->CrtcVSyncEnd = p->CrtcVSyncEnd; 360 modep->CrtcVBlankEnd = p->CrtcVBlankEnd; 361 modep->CrtcVTotal = p->CrtcVTotal; 362 modep->CrtcHAdjusted = p->CrtcHAdjusted; 363 modep->CrtcVAdjusted = p->CrtcVAdjusted; 364 modep->HSync = p->HSync; 365 modep->VRefresh = p->VRefresh; 366 modep->Private = p->Private; 367 modep->PrivSize = p->PrivSize; 368 369 p->prev = modep; 370 371 return MODE_OK; 372} 373 374/* 375 * xf86LookupMode 376 * 377 * This function returns a mode from the given list which matches the 378 * given name. When multiple modes with the same name are available, 379 * the method of picking the matching mode is determined by the 380 * strategy selected. 381 * 382 * This function takes the following parameters: 383 * scrp ScrnInfoPtr 384 * modep pointer to the returned mode, which must have the name 385 * field filled in. 386 * clockRanges a list of clock ranges. This is optional when all the 387 * modes are built-in modes. 388 * strategy how to decide which mode to use from multiple modes with 389 * the same name 390 * 391 * In addition, the following fields from the ScrnInfoRec are used: 392 * modePool the list of monitor modes compatible with the driver 393 * clocks a list of discrete clocks 394 * numClocks number of discrete clocks 395 * progClock clock is programmable 396 * 397 * If a mode was found, its values are filled in to the area pointed to 398 * by modep, If a mode was not found the return value indicates the 399 * reason. 400 */ 401 402_X_EXPORT ModeStatus 403xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep, 404 ClockRangePtr clockRanges, LookupModeFlags strategy) 405{ 406 DisplayModePtr p, bestMode = NULL; 407 ClockRangePtr cp; 408 int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1; 409 double refresh, bestRefresh = 0.0; 410 Bool found = FALSE; 411 int extraFlags = 0; 412 int clockIndex = -1; 413 int MulFactor = 1; 414 int DivFactor = 1; 415 int ModePrivFlags = 0; 416 ModeStatus status = MODE_NOMODE; 417 Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; 418 int n; 419 const int types[] = { 420 M_T_BUILTIN | M_T_PREFERRED, 421 M_T_BUILTIN, 422 M_T_USERDEF | M_T_PREFERRED, 423 M_T_USERDEF, 424 M_T_DRIVER | M_T_PREFERRED, 425 M_T_DRIVER, 426 0 427 }; 428 const int ntypes = sizeof(types) / sizeof(int); 429 430 strategy &= ~(LOOKUP_CLKDIV2 | LOOKUP_OPTIONAL_TOLERANCES); 431 432 /* Some sanity checking */ 433 if (scrp == NULL || scrp->modePool == NULL || 434 (!scrp->progClock && scrp->numClocks == 0)) { 435 ErrorF("xf86LookupMode: called with invalid scrnInfoRec\n"); 436 return MODE_ERROR; 437 } 438 if (modep == NULL || modep->name == NULL) { 439 ErrorF("xf86LookupMode: called with invalid modep\n"); 440 return MODE_ERROR; 441 } 442 for (cp = clockRanges; cp != NULL; cp = cp->next) { 443 /* DivFactor and MulFactor must be > 0 */ 444 cp->ClockDivFactor = max(1, cp->ClockDivFactor); 445 cp->ClockMulFactor = max(1, cp->ClockMulFactor); 446 } 447 448 /* Scan the mode pool for matching names */ 449 for (n = 0; n < ntypes; n++) { 450 int type = types[n]; 451 for (p = scrp->modePool; p != NULL; p = p->next) { 452 453 /* scan through the modes in the sort order above */ 454 if ((p->type & type) != type) 455 continue; 456 457 if (strcmp(p->name, modep->name) == 0) { 458 459 /* Skip over previously rejected modes */ 460 if (p->status != MODE_OK) { 461 if (!found) 462 status = p->status; 463 continue; 464 } 465 466 /* Skip over previously considered modes */ 467 if (p->prev) 468 continue; 469 470 if (p->type & M_T_BUILTIN) { 471 return xf86HandleBuiltinMode(scrp, p,modep, clockRanges, 472 allowDiv2); 473 } 474 475 /* Check clock is in range */ 476 cp = xf86FindClockRangeForMode(clockRanges, p); 477 if (cp == NULL) { 478 /* 479 * XXX Could do more here to provide a more detailed 480 * reason for not finding a mode. 481 */ 482 p->status = MODE_CLOCK_RANGE; 483 if (!found) 484 status = MODE_CLOCK_RANGE; 485 continue; 486 } 487 488 /* 489 * If programmable clock and strategy is not 490 * LOOKUP_BEST_REFRESH, the required mode has been found, 491 * otherwise record the refresh and continue looking. 492 */ 493 if (scrp->progClock) { 494 found = TRUE; 495 if (strategy != LOOKUP_BEST_REFRESH) { 496 bestMode = p; 497 DivFactor = cp->ClockDivFactor; 498 MulFactor = cp->ClockMulFactor; 499 ModePrivFlags = cp->PrivFlags; 500 break; 501 } 502 refresh = xf86ModeVRefresh(p); 503 if (p->Flags & V_INTERLACE) 504 refresh /= INTERLACE_REFRESH_WEIGHT; 505 if (refresh > bestRefresh) { 506 bestMode = p; 507 DivFactor = cp->ClockDivFactor; 508 MulFactor = cp->ClockMulFactor; 509 ModePrivFlags = cp->PrivFlags; 510 bestRefresh = refresh; 511 } 512 continue; 513 } 514 515 /* 516 * Clock is in range, so if it is not a programmable clock, find 517 * a matching clock. 518 */ 519 520 i = xf86GetNearestClock(scrp, p->Clock, allowDiv2, 521 cp->ClockDivFactor, cp->ClockMulFactor, &k); 522 /* 523 * If the clock is too far from the requested clock, this 524 * mode is no good. 525 */ 526 if (k & V_CLKDIV2) 527 gap = abs((p->Clock * 2) - 528 ((scrp->clock[i] * cp->ClockDivFactor) / 529 cp->ClockMulFactor)); 530 else 531 gap = abs(p->Clock - 532 ((scrp->clock[i] * cp->ClockDivFactor) / 533 cp->ClockMulFactor)); 534 if (gap > minimumGap) { 535 p->status = MODE_NOCLOCK; 536 if (!found) 537 status = MODE_NOCLOCK; 538 continue; 539 } 540 found = TRUE; 541 542 if (strategy == LOOKUP_BEST_REFRESH) { 543 refresh = xf86ModeVRefresh(p); 544 if (p->Flags & V_INTERLACE) 545 refresh /= INTERLACE_REFRESH_WEIGHT; 546 if (refresh > bestRefresh) { 547 bestMode = p; 548 DivFactor = cp->ClockDivFactor; 549 MulFactor = cp->ClockMulFactor; 550 ModePrivFlags = cp->PrivFlags; 551 extraFlags = k; 552 clockIndex = i; 553 bestRefresh = refresh; 554 } 555 continue; 556 } 557 if (strategy == LOOKUP_CLOSEST_CLOCK) { 558 if (gap < minimumGap) { 559 bestMode = p; 560 DivFactor = cp->ClockDivFactor; 561 MulFactor = cp->ClockMulFactor; 562 ModePrivFlags = cp->PrivFlags; 563 extraFlags = k; 564 clockIndex = i; 565 minimumGap = gap; 566 } 567 continue; 568 } 569 /* 570 * If strategy is neither LOOKUP_BEST_REFRESH or 571 * LOOKUP_CLOSEST_CLOCK the required mode has been found. 572 */ 573 bestMode = p; 574 DivFactor = cp->ClockDivFactor; 575 MulFactor = cp->ClockMulFactor; 576 ModePrivFlags = cp->PrivFlags; 577 extraFlags = k; 578 clockIndex = i; 579 break; 580 } 581 } 582 if (found) break; 583 } 584 if (!found || bestMode == NULL) 585 return status; 586 587 /* Fill in the mode parameters */ 588 if (scrp->progClock) { 589 modep->Clock = bestMode->Clock; 590 modep->ClockIndex = -1; 591 modep->SynthClock = (modep->Clock * MulFactor) / DivFactor; 592 } else { 593 modep->Clock = (scrp->clock[clockIndex] * DivFactor) / 594 MulFactor; 595 modep->ClockIndex = clockIndex; 596 modep->SynthClock = scrp->clock[clockIndex]; 597 if (extraFlags & V_CLKDIV2) { 598 modep->Clock /= 2; 599 modep->SynthClock /= 2; 600 } 601 } 602 modep->type = bestMode->type; 603 modep->PrivFlags = ModePrivFlags; 604 modep->HDisplay = bestMode->HDisplay; 605 modep->HSyncStart = bestMode->HSyncStart; 606 modep->HSyncEnd = bestMode->HSyncEnd; 607 modep->HTotal = bestMode->HTotal; 608 modep->HSkew = bestMode->HSkew; 609 modep->VDisplay = bestMode->VDisplay; 610 modep->VSyncStart = bestMode->VSyncStart; 611 modep->VSyncEnd = bestMode->VSyncEnd; 612 modep->VTotal = bestMode->VTotal; 613 modep->VScan = bestMode->VScan; 614 modep->Flags = bestMode->Flags | extraFlags; 615 modep->CrtcHDisplay = bestMode->CrtcHDisplay; 616 modep->CrtcHBlankStart = bestMode->CrtcHBlankStart; 617 modep->CrtcHSyncStart = bestMode->CrtcHSyncStart; 618 modep->CrtcHSyncEnd = bestMode->CrtcHSyncEnd; 619 modep->CrtcHBlankEnd = bestMode->CrtcHBlankEnd; 620 modep->CrtcHTotal = bestMode->CrtcHTotal; 621 modep->CrtcHSkew = bestMode->CrtcHSkew; 622 modep->CrtcVDisplay = bestMode->CrtcVDisplay; 623 modep->CrtcVBlankStart = bestMode->CrtcVBlankStart; 624 modep->CrtcVSyncStart = bestMode->CrtcVSyncStart; 625 modep->CrtcVSyncEnd = bestMode->CrtcVSyncEnd; 626 modep->CrtcVBlankEnd = bestMode->CrtcVBlankEnd; 627 modep->CrtcVTotal = bestMode->CrtcVTotal; 628 modep->CrtcHAdjusted = bestMode->CrtcHAdjusted; 629 modep->CrtcVAdjusted = bestMode->CrtcVAdjusted; 630 modep->HSync = bestMode->HSync; 631 modep->VRefresh = bestMode->VRefresh; 632 modep->Private = bestMode->Private; 633 modep->PrivSize = bestMode->PrivSize; 634 635 bestMode->prev = modep; 636 637 return MODE_OK; 638} 639 640/* 641 * xf86CheckModeForMonitor 642 * 643 * This function takes a mode and monitor description, and determines 644 * if the mode is valid for the monitor. 645 */ 646_X_EXPORT ModeStatus 647xf86CheckModeForMonitor(DisplayModePtr mode, MonPtr monitor) 648{ 649 int i; 650 651 /* Sanity checks */ 652 if (mode == NULL || monitor == NULL) { 653 ErrorF("xf86CheckModeForMonitor: called with invalid parameters\n"); 654 return MODE_ERROR; 655 } 656 657#ifdef DEBUG 658 ErrorF("xf86CheckModeForMonitor(%p %s, %p %s)\n", 659 mode, mode->name, monitor, monitor->id); 660#endif 661 662 /* Some basic mode validity checks */ 663 if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || 664 mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) 665 return MODE_H_ILLEGAL; 666 667 if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || 668 mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) 669 return MODE_V_ILLEGAL; 670 671 if (monitor->nHsync > 0) { 672 /* Check hsync against the allowed ranges */ 673 float hsync = xf86ModeHSync(mode); 674 for (i = 0; i < monitor->nHsync; i++) 675 if ((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) && 676 (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE))) 677 break; 678 679 /* Now see whether we ran out of sync ranges without finding a match */ 680 if (i == monitor->nHsync) 681 return MODE_HSYNC; 682 } 683 684 if (monitor->nVrefresh > 0) { 685 /* Check vrefresh against the allowed ranges */ 686 float vrefrsh = xf86ModeVRefresh(mode); 687 for (i = 0; i < monitor->nVrefresh; i++) 688 if ((vrefrsh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) && 689 (vrefrsh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE))) 690 break; 691 692 /* Now see whether we ran out of refresh ranges without finding a match */ 693 if (i == monitor->nVrefresh) 694 return MODE_VSYNC; 695 } 696 697 /* Force interlaced modes to have an odd VTotal */ 698 if (mode->Flags & V_INTERLACE) 699 mode->CrtcVTotal = mode->VTotal |= 1; 700 701 /* 702 * This code stops cvt -r modes, and only cvt -r modes, from hitting 15y+ 703 * old CRTs which might, when there is a lot of solar flare activity and 704 * when the celestial bodies are unfavourably aligned, implode trying to 705 * sync to it. It's called "Protecting the user from doing anything stupid". 706 * -- libv 707 */ 708 709 if (xf86ModeIsReduced(mode)) { 710 if (!monitor->reducedblanking && !(mode->type & M_T_DRIVER)) 711 return MODE_NO_REDUCED; 712 } 713 714 if ((monitor->maxPixClock) && (mode->Clock > monitor->maxPixClock)) 715 return MODE_CLOCK_HIGH; 716 717 return MODE_OK; 718} 719 720/* 721 * xf86CheckModeSize 722 * 723 * An internal routine to check if a mode fits in video memory. This tries to 724 * avoid overflows that would otherwise occur when video memory size is greater 725 * than 256MB. 726 */ 727static Bool 728xf86CheckModeSize(ScrnInfoPtr scrp, int w, int x, int y) 729{ 730 int bpp = scrp->fbFormat.bitsPerPixel, 731 pad = scrp->fbFormat.scanlinePad; 732 int lineWidth, lastWidth; 733 734 if (scrp->depth == 4) 735 pad *= 4; /* 4 planes */ 736 737 /* Sanity check */ 738 if ((w < 0) || (x < 0) || (y <= 0)) 739 return FALSE; 740 741 lineWidth = (((w * bpp) + pad - 1) / pad) * pad; 742 lastWidth = x * bpp; 743 744 /* 745 * At this point, we need to compare 746 * 747 * (lineWidth * (y - 1)) + lastWidth 748 * 749 * against 750 * 751 * scrp->videoRam * (1024 * 8) 752 * 753 * These are bit quantities. To avoid overflows, do the comparison in 754 * terms of BITMAP_SCANLINE_PAD units. This assumes BITMAP_SCANLINE_PAD 755 * is a power of 2. We currently use 32, which limits us to a video 756 * memory size of 8GB. 757 */ 758 759 lineWidth = (lineWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; 760 lastWidth = (lastWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; 761 762 if ((lineWidth * (y - 1) + lastWidth) > 763 (scrp->videoRam * ((1024 * 8) / BITMAP_SCANLINE_PAD))) 764 return FALSE; 765 766 return TRUE; 767} 768 769/* 770 * xf86InitialCheckModeForDriver 771 * 772 * This function checks if a mode satisfies a driver's initial requirements: 773 * - mode size fits within the available pixel area (memory) 774 * - width lies within the range of supported line pitches 775 * - mode size fits within virtual size (if fixed) 776 * - horizontal timings are in range 777 * 778 * This function takes the following parameters: 779 * scrp ScrnInfoPtr 780 * mode mode to check 781 * maxPitch (optional) maximum line pitch 782 * virtualX (optional) virtual width requested 783 * virtualY (optional) virtual height requested 784 * 785 * In addition, the following fields from the ScrnInfoRec are used: 786 * monitor pointer to structure for monitor section 787 * fbFormat pixel format for the framebuffer 788 * videoRam video memory size (in kB) 789 * maxHValue maximum horizontal timing value 790 * maxVValue maximum vertical timing value 791 */ 792 793_X_EXPORT ModeStatus 794xf86InitialCheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, 795 ClockRangePtr clockRanges, 796 LookupModeFlags strategy, 797 int maxPitch, int virtualX, int virtualY) 798{ 799 ClockRangePtr cp; 800 ModeStatus status; 801 Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; 802 int i, needDiv2; 803 804 /* Sanity checks */ 805 if (!scrp || !mode || !clockRanges) { 806 ErrorF("xf86InitialCheckModeForDriver: " 807 "called with invalid parameters\n"); 808 return MODE_ERROR; 809 } 810 811#ifdef DEBUG 812 ErrorF("xf86InitialCheckModeForDriver(%p, %p %s, %p, 0x%x, %d, %d, %d)\n", 813 scrp, mode, mode->name , clockRanges, strategy, maxPitch, virtualX, virtualY); 814#endif 815 816 /* Some basic mode validity checks */ 817 if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || 818 mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) 819 return MODE_H_ILLEGAL; 820 821 if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || 822 mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) 823 return MODE_V_ILLEGAL; 824 825 if (!xf86CheckModeSize(scrp, mode->HDisplay, mode->HDisplay, 826 mode->VDisplay)) 827 return MODE_MEM; 828 829 if (maxPitch > 0 && mode->HDisplay > maxPitch) 830 return MODE_BAD_WIDTH; 831 832 if (virtualX > 0 && mode->HDisplay > virtualX) 833 return MODE_VIRTUAL_X; 834 835 if (virtualY > 0 && mode->VDisplay > virtualY) 836 return MODE_VIRTUAL_Y; 837 838 if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue) 839 return MODE_BAD_HVALUE; 840 841 if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue) 842 return MODE_BAD_VVALUE; 843 844 /* 845 * The use of the DisplayModeRec's Crtc* and SynthClock elements below is 846 * provisional, in that they are later reused by the driver at mode-set 847 * time. Here, they are temporarily enlisted to contain the mode timings 848 * as seen by the CRT or panel (rather than the CRTC). The driver's 849 * ValidMode() is allowed to modify these so it can deal with such things 850 * as mode stretching and/or centering. The driver should >NOT< modify the 851 * user-supplied values as these are reported back when mode validation is 852 * said and done. 853 */ 854 /* 855 * NOTE: We (ab)use the mode->Crtc* values here to store timing 856 * information for the calculation of Hsync and Vrefresh. Before 857 * these values are calculated the driver is given the opportunity 858 * to either set these HSync and VRefresh itself or modify the timing 859 * values. 860 * The difference to the final calculation is small but imortand: 861 * here we pass the flag INTERLACE_HALVE_V regardless if the driver 862 * sets it or not. This way our calculation of VRefresh has the same 863 * effect as if we do if (flags & V_INTERLACE) refresh *= 2.0 864 * This dual use of the mode->Crtc* values will certainly create 865 * confusion and is bad software design. However since it's part of 866 * the driver API it's hard to change. 867 */ 868 869 if (scrp->ValidMode) { 870 871 xf86SetModeCrtc(mode, INTERLACE_HALVE_V); 872 873 cp = xf86FindClockRangeForMode(clockRanges, mode); 874 if (!cp) 875 return MODE_CLOCK_RANGE; 876 877 if (cp->ClockMulFactor < 1) 878 cp->ClockMulFactor = 1; 879 if (cp->ClockDivFactor < 1) 880 cp->ClockDivFactor = 1; 881 882 /* 883 * XXX The effect of clock dividers and multipliers on the monitor's 884 * pixel clock needs to be verified. 885 */ 886 if (scrp->progClock) { 887 mode->SynthClock = mode->Clock; 888 } else { 889 i = xf86GetNearestClock(scrp, mode->Clock, allowDiv2, 890 cp->ClockDivFactor, cp->ClockMulFactor, 891 &needDiv2); 892 mode->SynthClock = (scrp->clock[i] * cp->ClockDivFactor) / 893 cp->ClockMulFactor; 894 if (needDiv2 & V_CLKDIV2) 895 mode->SynthClock /= 2; 896 } 897 898 status = (*scrp->ValidMode)(scrp->scrnIndex, mode, FALSE, 899 MODECHECK_INITIAL); 900 if (status != MODE_OK) 901 return status; 902 903 if (mode->HSync <= 0.0) 904 mode->HSync = (float)mode->SynthClock / (float)mode->CrtcHTotal; 905 if (mode->VRefresh <= 0.0) 906 mode->VRefresh = (mode->SynthClock * 1000.0) 907 / (mode->CrtcHTotal * mode->CrtcVTotal); 908 } 909 910 mode->HSync = xf86ModeHSync(mode); 911 mode->VRefresh = xf86ModeVRefresh(mode); 912 913 /* Assume it is OK */ 914 return MODE_OK; 915} 916 917/* 918 * xf86CheckModeForDriver 919 * 920 * This function is for checking modes while the server is running (for 921 * use mainly by the VidMode extension). 922 * 923 * This function checks if a mode satisfies a driver's requirements: 924 * - width lies within the line pitch 925 * - mode size fits within virtual size 926 * - horizontal/vertical timings are in range 927 * 928 * This function takes the following parameters: 929 * scrp ScrnInfoPtr 930 * mode mode to check 931 * flags not (currently) used 932 * 933 * In addition, the following fields from the ScrnInfoRec are used: 934 * maxHValue maximum horizontal timing value 935 * maxVValue maximum vertical timing value 936 * virtualX virtual width 937 * virtualY virtual height 938 * clockRanges allowable clock ranges 939 */ 940 941_X_EXPORT ModeStatus 942xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, int flags) 943{ 944 ClockRangesPtr cp; 945 int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1; 946 int extraFlags = 0; 947 int clockIndex = -1; 948 int MulFactor = 1; 949 int DivFactor = 1; 950 int ModePrivFlags = 0; 951 Bool allowDiv2; 952 ModeStatus status = MODE_NOMODE; 953 954 /* Some sanity checking */ 955 if (scrp == NULL || (!scrp->progClock && scrp->numClocks == 0)) { 956 ErrorF("xf86CheckModeForDriver: called with invalid scrnInfoRec\n"); 957 return MODE_ERROR; 958 } 959 if (mode == NULL) { 960 ErrorF("xf86CheckModeForDriver: called with invalid modep\n"); 961 return MODE_ERROR; 962 } 963 964 /* Check the mode size */ 965 if (mode->HDisplay > scrp->virtualX) 966 return MODE_VIRTUAL_X; 967 968 if (mode->VDisplay > scrp->virtualY) 969 return MODE_VIRTUAL_Y; 970 971 if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue) 972 return MODE_BAD_HVALUE; 973 974 if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue) 975 return MODE_BAD_VVALUE; 976 977 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { 978 /* DivFactor and MulFactor must be > 0 */ 979 cp->ClockDivFactor = max(1, cp->ClockDivFactor); 980 cp->ClockMulFactor = max(1, cp->ClockMulFactor); 981 } 982 983 if (scrp->progClock) { 984 /* Check clock is in range */ 985 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { 986 if ((cp->minClock <= mode->Clock) && 987 (cp->maxClock >= mode->Clock) && 988 (cp->interlaceAllowed || !(mode->Flags & V_INTERLACE)) && 989 (cp->doubleScanAllowed || 990 ((!(mode->Flags & V_DBLSCAN)) && (mode->VScan <= 1)))) 991 break; 992 } 993 if (cp == NULL) { 994 return MODE_CLOCK_RANGE; 995 } 996 /* 997 * If programmable clock the required mode has been found 998 */ 999 DivFactor = cp->ClockDivFactor; 1000 MulFactor = cp->ClockMulFactor; 1001 ModePrivFlags = cp->PrivFlags; 1002 } else { 1003 status = MODE_CLOCK_RANGE; 1004 /* Check clock is in range */ 1005 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { 1006 if ((cp->minClock <= mode->Clock) && 1007 (cp->maxClock >= mode->Clock) && 1008 (cp->interlaceAllowed || !(mode->Flags & V_INTERLACE)) && 1009 (cp->doubleScanAllowed || 1010 ((!(mode->Flags & V_DBLSCAN)) && (mode->VScan <= 1)))) { 1011 1012 /* 1013 * Clock is in range, so if it is not a programmable clock, 1014 * find a matching clock. 1015 */ 1016 1017 allowDiv2 = (cp->strategy & LOOKUP_CLKDIV2) != 0; 1018 i = xf86GetNearestClock(scrp, mode->Clock, allowDiv2, 1019 cp->ClockDivFactor, cp->ClockMulFactor, &k); 1020 /* 1021 * If the clock is too far from the requested clock, this 1022 * mode is no good. 1023 */ 1024 if (k & V_CLKDIV2) 1025 gap = abs((mode->Clock * 2) - 1026 ((scrp->clock[i] * cp->ClockDivFactor) / 1027 cp->ClockMulFactor)); 1028 else 1029 gap = abs(mode->Clock - 1030 ((scrp->clock[i] * cp->ClockDivFactor) / 1031 cp->ClockMulFactor)); 1032 if (gap > minimumGap) { 1033 status = MODE_NOCLOCK; 1034 continue; 1035 } 1036 1037 DivFactor = cp->ClockDivFactor; 1038 MulFactor = cp->ClockMulFactor; 1039 ModePrivFlags = cp->PrivFlags; 1040 extraFlags = k; 1041 clockIndex = i; 1042 break; 1043 } 1044 } 1045 if (cp == NULL) 1046 return status; 1047 } 1048 1049 /* Fill in the mode parameters */ 1050 if (scrp->progClock) { 1051 mode->ClockIndex = -1; 1052 mode->SynthClock = (mode->Clock * MulFactor) / DivFactor; 1053 } else { 1054 mode->Clock = (scrp->clock[clockIndex] * DivFactor) / MulFactor; 1055 mode->ClockIndex = clockIndex; 1056 mode->SynthClock = scrp->clock[clockIndex]; 1057 if (extraFlags & V_CLKDIV2) { 1058 mode->Clock /= 2; 1059 mode->SynthClock /= 2; 1060 } 1061 } 1062 mode->PrivFlags = ModePrivFlags; 1063 1064 return MODE_OK; 1065} 1066 1067static int 1068inferVirtualSize(ScrnInfoPtr scrp, DisplayModePtr modes, int *vx, int *vy) 1069{ 1070 float aspect = 0.0; 1071 MonPtr mon = scrp->monitor; 1072 xf86MonPtr DDC; 1073 int x = 0, y = 0; 1074 DisplayModePtr mode; 1075 1076 if (!mon) return 0; 1077 DDC = mon->DDC; 1078 1079 if (DDC && DDC->ver.revision >= 4) { 1080 /* For 1.4, we might actually get native pixel format. How novel. */ 1081 if (PREFERRED_TIMING_MODE(DDC->features.msc)) { 1082 for (mode = modes; mode; mode = mode->next) { 1083 if (mode->type & (M_T_DRIVER | M_T_PREFERRED)) { 1084 x = mode->HDisplay; 1085 y = mode->VDisplay; 1086 goto found; 1087 } 1088 } 1089 } 1090 /* 1091 * Even if we don't, we might get aspect ratio from extra CVT info 1092 * or from the monitor size fields. TODO. 1093 */ 1094 } 1095 1096 /* 1097 * Technically this triggers if either is zero. That wasn't legal 1098 * before EDID 1.4, but right now we'll get that wrong. TODO. 1099 */ 1100 if (!aspect) { 1101 if (!mon->widthmm || !mon->heightmm) 1102 aspect = 4.0/3.0; 1103 else 1104 aspect = (float)mon->widthmm / (float)mon->heightmm; 1105 } 1106 1107 /* find the largest M_T_DRIVER mode with that aspect ratio */ 1108 for (mode = modes; mode; mode = mode->next) { 1109 float mode_aspect, metaspect; 1110 if (!(mode->type & (M_T_DRIVER|M_T_USERDEF))) 1111 continue; 1112 mode_aspect = (float)mode->HDisplay / (float)mode->VDisplay; 1113 metaspect = aspect / mode_aspect; 1114 /* 5% slop or so, since we only get size in centimeters */ 1115 if (fabs(1.0 - metaspect) < 0.05) { 1116 if ((mode->HDisplay > x) && (mode->VDisplay > y)) { 1117 x = mode->HDisplay; 1118 y = mode->VDisplay; 1119 } 1120 } 1121 } 1122 1123 if (!x || !y) { 1124 xf86DrvMsg(scrp->scrnIndex, X_WARNING, 1125 "Unable to estimate virtual size\n"); 1126 return 0; 1127 } 1128 1129found: 1130 *vx = x; 1131 *vy = y; 1132 1133 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1134 "Estimated virtual size for aspect ratio %.4f is %dx%d\n", 1135 aspect, *vx, *vy); 1136 1137 return 1; 1138} 1139 1140/* 1141 * xf86ValidateModes 1142 * 1143 * This function takes a set of mode names, modes and limiting conditions, 1144 * and selects a set of modes and parameters based on those conditions. 1145 * 1146 * This function takes the following parameters: 1147 * scrp ScrnInfoPtr 1148 * availModes the list of modes available for the monitor 1149 * modeNames (optional) list of mode names that the screen is requesting 1150 * clockRanges a list of clock ranges 1151 * linePitches (optional) a list of line pitches 1152 * minPitch (optional) minimum line pitch (in pixels) 1153 * maxPitch (optional) maximum line pitch (in pixels) 1154 * pitchInc (mandatory) pitch increment (in bits) 1155 * minHeight (optional) minimum virtual height (in pixels) 1156 * maxHeight (optional) maximum virtual height (in pixels) 1157 * virtualX (optional) virtual width requested (in pixels) 1158 * virtualY (optional) virtual height requested (in pixels) 1159 * apertureSize size of video aperture (in bytes) 1160 * strategy how to decide which mode to use from multiple modes with 1161 * the same name 1162 * 1163 * In addition, the following fields from the ScrnInfoRec are used: 1164 * clocks a list of discrete clocks 1165 * numClocks number of discrete clocks 1166 * progClock clock is programmable 1167 * monitor pointer to structure for monitor section 1168 * fbFormat format of the framebuffer 1169 * videoRam video memory size 1170 * maxHValue maximum horizontal timing value 1171 * maxVValue maximum vertical timing value 1172 * xInc horizontal timing increment (defaults to 8 pixels) 1173 * 1174 * The function fills in the following ScrnInfoRec fields: 1175 * modePool A subset of the modes available to the monitor which 1176 * are compatible with the driver. 1177 * modes one mode entry for each of the requested modes, with the 1178 * status field filled in to indicate if the mode has been 1179 * accepted or not. 1180 * virtualX the resulting virtual width 1181 * virtualY the resulting virtual height 1182 * displayWidth the resulting line pitch 1183 * 1184 * The function's return value is the number of matching modes found, or -1 1185 * if an unrecoverable error was encountered. 1186 */ 1187 1188_X_EXPORT int 1189xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, 1190 char **modeNames, ClockRangePtr clockRanges, 1191 int *linePitches, int minPitch, int maxPitch, int pitchInc, 1192 int minHeight, int maxHeight, int virtualX, int virtualY, 1193 int apertureSize, LookupModeFlags strategy) 1194{ 1195 DisplayModePtr p, q, r, new, last, *endp; 1196 int i, numModes = 0; 1197 ModeStatus status; 1198 int linePitch = -1, virtX = 0, virtY = 0; 1199 int newLinePitch, newVirtX, newVirtY; 1200 int modeSize; /* in pixels */ 1201 Bool validateAllDefaultModes = FALSE; 1202 Bool userModes = FALSE; 1203 int saveType; 1204 PixmapFormatRec *BankFormat; 1205 ClockRangePtr cp; 1206 ClockRangesPtr storeClockRanges; 1207 double targetRefresh = 0.0; 1208 int numTimings = 0; 1209 range hsync[MAX_HSYNC]; 1210 range vrefresh[MAX_VREFRESH]; 1211 Bool inferred_virtual = FALSE; 1212 1213#ifdef DEBUG 1214 ErrorF("xf86ValidateModes(%p, %p, %p, %p,\n\t\t %p, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x)\n", 1215 scrp, availModes, modeNames, clockRanges, 1216 linePitches, minPitch, maxPitch, pitchInc, 1217 minHeight, maxHeight, virtualX, virtualY, 1218 apertureSize, strategy 1219 ); 1220#endif 1221 1222 /* Some sanity checking */ 1223 if (scrp == NULL || scrp->name == NULL || !scrp->monitor || 1224 (!scrp->progClock && scrp->numClocks == 0)) { 1225 ErrorF("xf86ValidateModes: called with invalid scrnInfoRec\n"); 1226 return -1; 1227 } 1228 if (linePitches != NULL && linePitches[0] <= 0) { 1229 ErrorF("xf86ValidateModes: called with invalid linePitches\n"); 1230 return -1; 1231 } 1232 if (pitchInc <= 0) { 1233 ErrorF("xf86ValidateModes: called with invalid pitchInc\n"); 1234 return -1; 1235 } 1236 if ((virtualX > 0) != (virtualY > 0)) { 1237 ErrorF("xf86ValidateModes: called with invalid virtual resolution\n"); 1238 return -1; 1239 } 1240 1241 /* 1242 * If requested by the driver, allow missing hsync and/or vrefresh ranges 1243 * in the monitor section. 1244 */ 1245 if (strategy & LOOKUP_OPTIONAL_TOLERANCES) { 1246 strategy &= ~LOOKUP_OPTIONAL_TOLERANCES; 1247 } else { 1248 const char *type = ""; 1249 1250 if (scrp->monitor->nHsync <= 0) { 1251 if (numTimings > 0) { 1252 scrp->monitor->nHsync = numTimings; 1253 for (i = 0; i < numTimings; i++) { 1254 scrp->monitor->hsync[i].lo = hsync[i].lo; 1255 scrp->monitor->hsync[i].hi = hsync[i].hi; 1256 } 1257 } else { 1258 scrp->monitor->hsync[0].lo = 31.5; 1259 scrp->monitor->hsync[0].hi = 37.9; 1260 scrp->monitor->nHsync = 1; 1261 } 1262 type = "default "; 1263 } 1264 for (i = 0; i < scrp->monitor->nHsync; i++) { 1265 if (scrp->monitor->hsync[i].lo == scrp->monitor->hsync[i].hi) 1266 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1267 "%s: Using %shsync value of %.2f kHz\n", 1268 scrp->monitor->id, type, 1269 scrp->monitor->hsync[i].lo); 1270 else 1271 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1272 "%s: Using %shsync range of %.2f-%.2f kHz\n", 1273 scrp->monitor->id, type, 1274 scrp->monitor->hsync[i].lo, 1275 scrp->monitor->hsync[i].hi); 1276 } 1277 1278 type = ""; 1279 if (scrp->monitor->nVrefresh <= 0) { 1280 if (numTimings > 0) { 1281 scrp->monitor->nVrefresh = numTimings; 1282 for (i = 0; i < numTimings; i++) { 1283 scrp->monitor->vrefresh[i].lo = vrefresh[i].lo; 1284 scrp->monitor->vrefresh[i].hi = vrefresh[i].hi; 1285 } 1286 } else { 1287 scrp->monitor->vrefresh[0].lo = 50; 1288 scrp->monitor->vrefresh[0].hi = 70; 1289 scrp->monitor->nVrefresh = 1; 1290 } 1291 type = "default "; 1292 } 1293 for (i = 0; i < scrp->monitor->nVrefresh; i++) { 1294 if (scrp->monitor->vrefresh[i].lo == scrp->monitor->vrefresh[i].hi) 1295 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1296 "%s: Using %svrefresh value of %.2f Hz\n", 1297 scrp->monitor->id, type, 1298 scrp->monitor->vrefresh[i].lo); 1299 else 1300 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1301 "%s: Using %svrefresh range of %.2f-%.2f Hz\n", 1302 scrp->monitor->id, type, 1303 scrp->monitor->vrefresh[i].lo, 1304 scrp->monitor->vrefresh[i].hi); 1305 } 1306 if (scrp->monitor->maxPixClock) { 1307 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1308 "%s: Using maximum pixel clock of %.2f MHz\n", 1309 scrp->monitor->id, 1310 (float)scrp->monitor->maxPixClock / 1000.0); 1311 } 1312 } 1313 1314 /* 1315 * Store the clockRanges for later use by the VidMode extension. Must 1316 * also store the strategy, since ClockDiv2 flag is stored there. 1317 */ 1318 storeClockRanges = scrp->clockRanges; 1319 while (storeClockRanges != NULL) { 1320 storeClockRanges = storeClockRanges->next; 1321 } 1322 for (cp = clockRanges; cp != NULL; cp = cp->next, 1323 storeClockRanges = storeClockRanges->next) { 1324 storeClockRanges = xnfalloc(sizeof(ClockRanges)); 1325 if (scrp->clockRanges == NULL) 1326 scrp->clockRanges = storeClockRanges; 1327 memcpy(storeClockRanges, cp, sizeof(ClockRange)); 1328 storeClockRanges->strategy = strategy; 1329 } 1330 1331 /* Determine which pixmap format to pass to miScanLineWidth() */ 1332 if (scrp->depth > 4) 1333 BankFormat = &scrp->fbFormat; 1334 else 1335 BankFormat = xf86GetPixFormat(scrp, 1); /* >not< scrp->depth! */ 1336 1337 if (scrp->xInc <= 0) 1338 scrp->xInc = 8; /* Suitable for VGA and others */ 1339 1340#define _VIRTUALX(x) ((((x) + scrp->xInc - 1) / scrp->xInc) * scrp->xInc) 1341 1342 /* 1343 * Determine maxPitch if it wasn't given explicitly. Note linePitches 1344 * always takes precedence if is non-NULL. In that case the minPitch and 1345 * maxPitch values passed are ignored. 1346 */ 1347 if (linePitches) { 1348 minPitch = maxPitch = linePitches[0]; 1349 for (i = 1; linePitches[i] > 0; i++) { 1350 if (linePitches[i] > maxPitch) 1351 maxPitch = linePitches[i]; 1352 if (linePitches[i] < minPitch) 1353 minPitch = linePitches[i]; 1354 } 1355 } 1356 1357 /* Initial check of virtual size against other constraints */ 1358 scrp->virtualFrom = X_PROBED; 1359 /* 1360 * Initialise virtX and virtY if the values are fixed. 1361 */ 1362 if (virtualY > 0) { 1363 if (maxHeight > 0 && virtualY > maxHeight) { 1364 xf86DrvMsg(scrp->scrnIndex, X_ERROR, 1365 "Virtual height (%d) is too large for the hardware " 1366 "(max %d)\n", virtualY, maxHeight); 1367 return -1; 1368 } 1369 1370 if (minHeight > 0 && virtualY < minHeight) { 1371 xf86DrvMsg(scrp->scrnIndex, X_ERROR, 1372 "Virtual height (%d) is too small for the hardware " 1373 "(min %d)\n", virtualY, minHeight); 1374 return -1; 1375 } 1376 1377 virtualX = _VIRTUALX(virtualX); 1378 if (linePitches != NULL) { 1379 for (i = 0; linePitches[i] != 0; i++) { 1380 if ((linePitches[i] >= virtualX) && 1381 (linePitches[i] == 1382 miScanLineWidth(virtualX, virtualY, linePitches[i], 1383 apertureSize, BankFormat, pitchInc))) { 1384 linePitch = linePitches[i]; 1385 break; 1386 } 1387 } 1388 } else { 1389 linePitch = miScanLineWidth(virtualX, virtualY, minPitch, 1390 apertureSize, BankFormat, pitchInc); 1391 } 1392 1393 if ((linePitch < minPitch) || (linePitch > maxPitch)) { 1394 xf86DrvMsg(scrp->scrnIndex, X_ERROR, 1395 "Virtual width (%d) is too large for the hardware " 1396 "(max %d)\n", virtualX, maxPitch); 1397 return -1; 1398 } 1399 1400 if (!xf86CheckModeSize(scrp, linePitch, virtualX, virtualY)) { 1401 xf86DrvMsg(scrp->scrnIndex, X_ERROR, 1402 "Virtual size (%dx%d) (pitch %d) exceeds video memory\n", 1403 virtualX, virtualY, linePitch); 1404 return -1; 1405 } 1406 1407 virtX = virtualX; 1408 virtY = virtualY; 1409 scrp->virtualFrom = X_CONFIG; 1410 } else if (!modeNames || !*modeNames) { 1411 /* No virtual size given in the config, try to infer */ 1412 /* XXX this doesn't take m{in,ax}Pitch into account; oh well */ 1413 inferred_virtual = inferVirtualSize(scrp, availModes, &virtX, &virtY); 1414 if (inferred_virtual) 1415 linePitch = miScanLineWidth(virtX, virtY, minPitch, apertureSize, 1416 BankFormat, pitchInc); 1417 } 1418 1419 /* Print clock ranges and scaled clocks */ 1420 xf86ShowClockRanges(scrp, clockRanges); 1421 1422 /* 1423 * If scrp->modePool hasn't been setup yet, set it up now. This allows the 1424 * modes that the driver definitely can't use to be weeded out early. Note 1425 * that a modePool mode's prev field is used to hold a pointer to the 1426 * member of the scrp->modes list for which a match was considered. 1427 */ 1428 if (scrp->modePool == NULL) { 1429 q = NULL; 1430 for (p = availModes; p != NULL; p = p->next) { 1431 status = xf86InitialCheckModeForDriver(scrp, p, clockRanges, 1432 strategy, maxPitch, 1433 virtX, virtY); 1434 1435 if (status == MODE_OK) { 1436 status = xf86CheckModeForMonitor(p, scrp->monitor); 1437 } 1438 1439 if (status == MODE_OK) { 1440 new = xnfalloc(sizeof(DisplayModeRec)); 1441 *new = *p; 1442 new->next = NULL; 1443 if (!q) { 1444 scrp->modePool = new; 1445 } else { 1446 q->next = new; 1447 } 1448 new->prev = NULL; 1449 q = new; 1450 q->name = xnfstrdup(p->name); 1451 q->status = MODE_OK; 1452 } else { 1453 printModeRejectMessage(scrp->scrnIndex, p, status); 1454 } 1455 } 1456 1457 if (scrp->modePool == NULL) { 1458 xf86DrvMsg(scrp->scrnIndex, X_WARNING, "Mode pool is empty\n"); 1459 return 0; 1460 } 1461 } else { 1462 for (p = scrp->modePool; p != NULL; p = p->next) { 1463 p->prev = NULL; 1464 p->status = MODE_OK; 1465 } 1466 } 1467 1468 /* 1469 * Go through the mode pool and see if any modes match the target 1470 * refresh rate, (if specified). If no modes match, abandon the target. 1471 */ 1472 targetRefresh = xf86SetRealOption(scrp->options, 1473 "TargetRefresh", 0.0); 1474 if (targetRefresh > 0.0) { 1475 for (p = scrp->modePool; p != NULL; p = p->next) { 1476 if (xf86ModeVRefresh(p) > targetRefresh * (1.0 - SYNC_TOLERANCE)) 1477 break; 1478 } 1479 if (!p) 1480 targetRefresh = 0.0; 1481 } 1482 1483 if (targetRefresh > 0.0) { 1484 xf86DrvMsg(scrp->scrnIndex, X_CONFIG, 1485 "Target refresh rate is %.1f Hz\n", targetRefresh); 1486 } 1487 1488 /* 1489 * Allocate one entry in scrp->modes for each named mode. 1490 */ 1491 while (scrp->modes) 1492 xf86DeleteMode(&scrp->modes, scrp->modes); 1493 endp = &scrp->modes; 1494 last = NULL; 1495 if (modeNames != NULL) { 1496 for (i = 0; modeNames[i] != NULL; i++) { 1497 userModes = TRUE; 1498 new = xnfcalloc(1, sizeof(DisplayModeRec)); 1499 new->prev = last; 1500 new->type = M_T_USERDEF; 1501 new->name = xnfalloc(strlen(modeNames[i]) + 1); 1502 strcpy(new->name, modeNames[i]); 1503 if (new->prev) 1504 new->prev->next = new; 1505 *endp = last = new; 1506 endp = &new->next; 1507 } 1508 } 1509 1510 /* Lookup each mode */ 1511#ifdef RANDR 1512 if (!xf86Info.disableRandR 1513#ifdef PANORAMIX 1514 && noPanoramiXExtension 1515#endif 1516 ) 1517 validateAllDefaultModes = TRUE; 1518#endif 1519 1520 for (p = scrp->modes; ; p = p->next) { 1521 Bool repeat; 1522 1523 /* 1524 * If the supplied mode names don't produce a valid mode, scan through 1525 * unconsidered modePool members until one survives validation. This 1526 * is done in decreasing order by mode pixel area. 1527 */ 1528 1529 if (p == NULL) { 1530 if ((numModes > 0) && !validateAllDefaultModes) 1531 break; 1532 1533 validateAllDefaultModes = TRUE; 1534 r = NULL; 1535 modeSize = 0; 1536 for (q = scrp->modePool; q != NULL; q = q->next) { 1537 if ((q->prev == NULL) && (q->status == MODE_OK)) { 1538 /* 1539 * Deal with the case where this mode wasn't considered 1540 * because of a builtin mode of the same name. 1541 */ 1542 for (p = scrp->modes; p != NULL; p = p->next) { 1543 if ((p->status != MODE_OK) && 1544 !strcmp(p->name, q->name)) 1545 break; 1546 } 1547 1548 if (p != NULL) 1549 q->prev = p; 1550 else { 1551 /* 1552 * A quick check to not allow default modes with 1553 * horizontal timing parameters that CRTs may have 1554 * problems with. 1555 */ 1556 if (!scrp->monitor->reducedblanking && 1557 (q->type & M_T_DEFAULT) && 1558 ((double)q->HTotal / (double)q->HDisplay) < 1.15) 1559 continue; 1560 1561 /* 1562 * If there is a target refresh rate, skip modes that 1563 * don't match up. 1564 */ 1565 if (xf86ModeVRefresh(q) < 1566 (1.0 - SYNC_TOLERANCE) * targetRefresh) 1567 continue; 1568 1569 if (modeSize < (q->HDisplay * q->VDisplay)) { 1570 r = q; 1571 modeSize = q->HDisplay * q->VDisplay; 1572 } 1573 } 1574 } 1575 } 1576 1577 if (r == NULL) 1578 break; 1579 1580 p = xnfcalloc(1, sizeof(DisplayModeRec)); 1581 p->prev = last; 1582 p->name = xnfalloc(strlen(r->name) + 1); 1583 if (!userModes) 1584 p->type = M_T_USERDEF; 1585 strcpy(p->name, r->name); 1586 if (p->prev) 1587 p->prev->next = p; 1588 *endp = last = p; 1589 endp = &p->next; 1590 } 1591 1592 repeat = FALSE; 1593 lookupNext: 1594 if (repeat && ((status = p->status) != MODE_OK)) 1595 printModeRejectMessage(scrp->scrnIndex, p, status); 1596 saveType = p->type; 1597 status = xf86LookupMode(scrp, p, clockRanges, strategy); 1598 if (repeat && status == MODE_NOMODE) 1599 continue; 1600 if (status != MODE_OK) 1601 printModeRejectMessage(scrp->scrnIndex, p, status); 1602 if (status == MODE_ERROR) { 1603 ErrorF("xf86ValidateModes: " 1604 "unexpected result from xf86LookupMode()\n"); 1605 return -1; 1606 } 1607 if (status != MODE_OK) { 1608 if (p->status == MODE_OK) 1609 p->status = status; 1610 continue; 1611 } 1612 p->type |= saveType; 1613 repeat = TRUE; 1614 1615 newLinePitch = linePitch; 1616 newVirtX = virtX; 1617 newVirtY = virtY; 1618 1619 /* 1620 * Don't let non-user defined modes increase the virtual size 1621 */ 1622 if (!(p->type & M_T_USERDEF) && (numModes > 0)) { 1623 if (p->HDisplay > virtX) { 1624 p->status = MODE_VIRTUAL_X; 1625 goto lookupNext; 1626 } 1627 if (p->VDisplay > virtY) { 1628 p->status = MODE_VIRTUAL_Y; 1629 goto lookupNext; 1630 } 1631 } 1632 /* 1633 * Adjust virtual width and height if the mode is too large for the 1634 * current values and if they are not fixed. 1635 */ 1636 if (virtualX <= 0 && p->HDisplay > newVirtX) 1637 newVirtX = _VIRTUALX(p->HDisplay); 1638 if (virtualY <= 0 && p->VDisplay > newVirtY) { 1639 if (maxHeight > 0 && p->VDisplay > maxHeight) { 1640 p->status = MODE_VIRTUAL_Y; /* ? */ 1641 goto lookupNext; 1642 } 1643 newVirtY = p->VDisplay; 1644 } 1645 1646 /* 1647 * If virtual resolution is to be increased, revalidate it. 1648 */ 1649 if ((virtX != newVirtX) || (virtY != newVirtY)) { 1650 if (linePitches != NULL) { 1651 newLinePitch = -1; 1652 for (i = 0; linePitches[i] != 0; i++) { 1653 if ((linePitches[i] >= newVirtX) && 1654 (linePitches[i] >= linePitch) && 1655 (linePitches[i] == 1656 miScanLineWidth(newVirtX, newVirtY, linePitches[i], 1657 apertureSize, BankFormat, pitchInc))) { 1658 newLinePitch = linePitches[i]; 1659 break; 1660 } 1661 } 1662 } else { 1663 if (linePitch < minPitch) 1664 linePitch = minPitch; 1665 newLinePitch = miScanLineWidth(newVirtX, newVirtY, linePitch, 1666 apertureSize, BankFormat, 1667 pitchInc); 1668 } 1669 if ((newLinePitch < minPitch) || (newLinePitch > maxPitch)) { 1670 p->status = MODE_BAD_WIDTH; 1671 goto lookupNext; 1672 } 1673 1674 /* 1675 * Check that the pixel area required by the new virtual height 1676 * and line pitch isn't too large. 1677 */ 1678 if (!xf86CheckModeSize(scrp, newLinePitch, newVirtX, newVirtY)) { 1679 p->status = MODE_MEM_VIRT; 1680 goto lookupNext; 1681 } 1682 } 1683 1684 if (scrp->ValidMode) { 1685 /* 1686 * Give the driver a final say, passing it the proposed virtual 1687 * geometry. 1688 */ 1689 scrp->virtualX = newVirtX; 1690 scrp->virtualY = newVirtY; 1691 scrp->displayWidth = newLinePitch; 1692 p->status = (scrp->ValidMode)(scrp->scrnIndex, p, FALSE, 1693 MODECHECK_FINAL); 1694 1695 if (p->status != MODE_OK) { 1696 goto lookupNext; 1697 } 1698 } 1699 1700 /* Mode has passed all the tests */ 1701 virtX = newVirtX; 1702 virtY = newVirtY; 1703 linePitch = newLinePitch; 1704 p->status = MODE_OK; 1705 numModes++; 1706 } 1707 1708#undef _VIRTUALX 1709 1710 /* 1711 * If we estimated the virtual size above, we may have filtered away all 1712 * the modes that maximally match that size; scan again to find out and 1713 * fix up if so. 1714 */ 1715 if (inferred_virtual) { 1716 int vx = 0, vy = 0; 1717 for (p = scrp->modes; p; p = p->next) { 1718 if (p->HDisplay > vx && p->VDisplay > vy) { 1719 vx = p->HDisplay; 1720 vy = p->VDisplay; 1721 } 1722 } 1723 if (vx < virtX || vy < virtY) { 1724 xf86DrvMsg(scrp->scrnIndex, X_WARNING, 1725 "Shrinking virtual size estimate from %dx%d to %dx%d\n", 1726 virtX, virtY, vx, vy); 1727 virtX = vx; 1728 virtY = vy; 1729 linePitch = miScanLineWidth(vx, vy, minPitch, apertureSize, 1730 BankFormat, pitchInc); 1731 } 1732 } 1733 1734 /* Update the ScrnInfoRec parameters */ 1735 1736 scrp->virtualX = virtX; 1737 scrp->virtualY = virtY; 1738 scrp->displayWidth = linePitch; 1739 1740 if (numModes <= 0) 1741 return 0; 1742 1743 /* Make the mode list into a circular list by joining up the ends */ 1744 p = scrp->modes; 1745 while (p->next != NULL) 1746 p = p->next; 1747 /* p is now the last mode on the list */ 1748 p->next = scrp->modes; 1749 scrp->modes->prev = p; 1750 1751 if (minHeight > 0 && virtY < minHeight) { 1752 xf86DrvMsg(scrp->scrnIndex, X_ERROR, 1753 "Virtual height (%d) is too small for the hardware " 1754 "(min %d)\n", virtY, minHeight); 1755 return -1; 1756 } 1757 1758 return numModes; 1759} 1760 1761/* 1762 * xf86DeleteMode 1763 * 1764 * This function removes a mode from a list of modes. 1765 * 1766 * There are different types of mode lists: 1767 * 1768 * - singly linked linear lists, ending in NULL 1769 * - doubly linked linear lists, starting and ending in NULL 1770 * - doubly linked circular lists 1771 * 1772 */ 1773 1774_X_EXPORT void 1775xf86DeleteMode(DisplayModePtr *modeList, DisplayModePtr mode) 1776{ 1777 /* Catch the easy/insane cases */ 1778 if (modeList == NULL || *modeList == NULL || mode == NULL) 1779 return; 1780 1781 /* If the mode is at the start of the list, move the start of the list */ 1782 if (*modeList == mode) 1783 *modeList = mode->next; 1784 1785 /* If mode is the only one on the list, set the list to NULL */ 1786 if ((mode == mode->prev) && (mode == mode->next)) { 1787 *modeList = NULL; 1788 } else { 1789 if ((mode->prev != NULL) && (mode->prev->next == mode)) 1790 mode->prev->next = mode->next; 1791 if ((mode->next != NULL) && (mode->next->prev == mode)) 1792 mode->next->prev = mode->prev; 1793 } 1794 1795 xfree(mode->name); 1796 xfree(mode); 1797} 1798 1799/* 1800 * xf86PruneDriverModes 1801 * 1802 * Remove modes from the driver's mode list which have been marked as 1803 * invalid. 1804 */ 1805 1806_X_EXPORT void 1807xf86PruneDriverModes(ScrnInfoPtr scrp) 1808{ 1809 DisplayModePtr first, p, n; 1810 1811 p = scrp->modes; 1812 if (p == NULL) 1813 return; 1814 1815 do { 1816 if (!(first = scrp->modes)) 1817 return; 1818 n = p->next; 1819 if (p->status != MODE_OK) { 1820 xf86DeleteMode(&(scrp->modes), p); 1821 } 1822 p = n; 1823 } while (p != NULL && p != first); 1824 1825 /* modePool is no longer needed, turf it */ 1826 while (scrp->modePool) { 1827 /* 1828 * A modePool mode's prev field is used to hold a pointer to the 1829 * member of the scrp->modes list for which a match was considered. 1830 * Clear that pointer first, otherwise xf86DeleteMode might get 1831 * confused 1832 */ 1833 scrp->modePool->prev = NULL; 1834 xf86DeleteMode(&scrp->modePool, scrp->modePool); 1835 } 1836} 1837 1838 1839/* 1840 * xf86SetCrtcForModes 1841 * 1842 * Goes through the screen's mode list, and initialises the Crtc 1843 * parameters for each mode. The initialisation includes adjustments 1844 * for interlaced and double scan modes. 1845 */ 1846_X_EXPORT void 1847xf86SetCrtcForModes(ScrnInfoPtr scrp, int adjustFlags) 1848{ 1849 DisplayModePtr p; 1850 1851 /* 1852 * Store adjustFlags for use with the VidMode extension. There is an 1853 * implicit assumption here that SetCrtcForModes is called once. 1854 */ 1855 scrp->adjustFlags = adjustFlags; 1856 1857 p = scrp->modes; 1858 if (p == NULL) 1859 return; 1860 1861 do { 1862 xf86SetModeCrtc(p, adjustFlags); 1863#ifdef DEBUG 1864 ErrorF("%sMode %s: %d (%d) %d %d (%d) %d %d (%d) %d %d (%d) %d\n", 1865 (p->type & M_T_DEFAULT) ? "Default " : "", 1866 p->name, p->CrtcHDisplay, p->CrtcHBlankStart, 1867 p->CrtcHSyncStart, p->CrtcHSyncEnd, p->CrtcHBlankEnd, 1868 p->CrtcHTotal, p->CrtcVDisplay, p->CrtcVBlankStart, 1869 p->CrtcVSyncStart, p->CrtcVSyncEnd, p->CrtcVBlankEnd, 1870 p->CrtcVTotal); 1871#endif 1872 p = p->next; 1873 } while (p != NULL && p != scrp->modes); 1874} 1875 1876 1877#if 0 1878static void 1879add(char **p, char *new) 1880{ 1881 *p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2); 1882 strcat(*p, " "); 1883 strcat(*p, new); 1884} 1885 1886_X_EXPORT void 1887xf86PrintModeline(int scrnIndex,DisplayModePtr mode) 1888{ 1889 char tmp[256]; 1890 char *flags = xnfcalloc(1, 1); 1891 1892 if (mode->HSkew) { 1893 snprintf(tmp, 256, "hskew %i", mode->HSkew); 1894 add(&flags, tmp); 1895 } 1896 if (mode->VScan) { 1897 snprintf(tmp, 256, "vscan %i", mode->VScan); 1898 add(&flags, tmp); 1899 } 1900 if (mode->Flags & V_INTERLACE) add(&flags, "interlace"); 1901 if (mode->Flags & V_CSYNC) add(&flags, "composite"); 1902 if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan"); 1903 if (mode->Flags & V_BCAST) add(&flags, "bcast"); 1904 if (mode->Flags & V_PHSYNC) add(&flags, "+hsync"); 1905 if (mode->Flags & V_NHSYNC) add(&flags, "-hsync"); 1906 if (mode->Flags & V_PVSYNC) add(&flags, "+vsync"); 1907 if (mode->Flags & V_NVSYNC) add(&flags, "-vsync"); 1908 if (mode->Flags & V_PCSYNC) add(&flags, "+csync"); 1909 if (mode->Flags & V_NCSYNC) add(&flags, "-csync"); 1910#if 0 1911 if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2"); 1912#endif 1913 xf86DrvMsgVerb(scrnIndex, X_INFO, 3, 1914 "Modeline \"%s\" %6.2f %i %i %i %i %i %i %i %i%s\n", 1915 mode->name, mode->Clock/1000., mode->HDisplay, 1916 mode->HSyncStart, mode->HSyncEnd, mode->HTotal, 1917 mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, 1918 mode->VTotal, flags); 1919 xfree(flags); 1920} 1921#endif 1922 1923_X_EXPORT void 1924xf86PrintModes(ScrnInfoPtr scrp) 1925{ 1926 DisplayModePtr p; 1927 float hsync, refresh = 0; 1928 char *desc, *desc2, *prefix, *uprefix; 1929 1930 if (scrp == NULL) 1931 return; 1932 1933 xf86DrvMsg(scrp->scrnIndex, scrp->virtualFrom, "Virtual size is %dx%d " 1934 "(pitch %d)\n", scrp->virtualX, scrp->virtualY, 1935 scrp->displayWidth); 1936 1937 p = scrp->modes; 1938 if (p == NULL) 1939 return; 1940 1941 do { 1942 desc = desc2 = ""; 1943 hsync = xf86ModeHSync(p); 1944 refresh = xf86ModeVRefresh(p); 1945 if (p->Flags & V_INTERLACE) { 1946 desc = " (I)"; 1947 } 1948 if (p->Flags & V_DBLSCAN) { 1949 desc = " (D)"; 1950 } 1951 if (p->VScan > 1) { 1952 desc2 = " (VScan)"; 1953 } 1954 if (p->type & M_T_BUILTIN) 1955 prefix = "Built-in mode"; 1956 else if (p->type & M_T_DEFAULT) 1957 prefix = "Default mode"; 1958 else if (p->type & M_T_DRIVER) 1959 prefix = "Driver mode"; 1960 else 1961 prefix = "Mode"; 1962 if (p->type & M_T_USERDEF) 1963 uprefix = "*"; 1964 else 1965 uprefix = " "; 1966 if (hsync == 0 || refresh == 0) { 1967 if (p->name) 1968 xf86DrvMsg(scrp->scrnIndex, X_CONFIG, 1969 "%s%s \"%s\"\n", uprefix, prefix, p->name); 1970 else 1971 xf86DrvMsg(scrp->scrnIndex, X_PROBED, 1972 "%s%s %dx%d (unnamed)\n", 1973 uprefix, prefix, p->HDisplay, p->VDisplay); 1974 } else if (p->Clock == p->SynthClock) { 1975 xf86DrvMsg(scrp->scrnIndex, X_CONFIG, 1976 "%s%s \"%s\": %.1f MHz, %.1f kHz, %.1f Hz%s%s\n", 1977 uprefix, prefix, p->name, p->Clock / 1000.0, 1978 hsync, refresh, desc, desc2); 1979 } else { 1980 xf86DrvMsg(scrp->scrnIndex, X_CONFIG, 1981 "%s%s \"%s\": %.1f MHz (scaled from %.1f MHz), " 1982 "%.1f kHz, %.1f Hz%s%s\n", 1983 uprefix, prefix, p->name, p->Clock / 1000.0, 1984 p->SynthClock / 1000.0, hsync, refresh, desc, desc2); 1985 } 1986 if (hsync != 0 && refresh != 0) 1987 xf86PrintModeline(scrp->scrnIndex,p); 1988 p = p->next; 1989 } while (p != NULL && p != scrp->modes); 1990} 1991 1992#if 0 1993/** 1994 * Adds the new mode into the mode list, and returns the new list 1995 * 1996 * \param modes doubly-linked mode list. 1997 */ 1998_X_EXPORT DisplayModePtr 1999xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new) 2000{ 2001 if (modes == NULL) 2002 return new; 2003 2004 if (new) { 2005 DisplayModePtr mode = modes; 2006 2007 while (mode->next) 2008 mode = mode->next; 2009 2010 mode->next = new; 2011 new->prev = mode; 2012 } 2013 2014 return modes; 2015} 2016#endif 2017