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