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 97static void 98printModeRejectMessage(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 */ 119static int 120xf86GetNearestClock(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 157const char * 158xf86ModeStatusToString(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 */ 246void 247xf86ShowClockRanges(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 299static Bool 300modeInClockRange(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 */ 312static ClockRangePtr 313xf86FindClockRangeForMode(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 */ 325static ModeStatus 326xf86HandleBuiltinMode(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 454static ModeStatus 455xf86LookupMode(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 if (p->name == NULL) 511 continue; 512 513 if (strcmp(p->name, modep->name) == 0) { 514 515 /* Skip over previously rejected modes */ 516 if (p->status != MODE_OK) { 517 if (!found) 518 status = p->status; 519 continue; 520 } 521 522 /* Skip over previously considered modes */ 523 if (p->prev) 524 continue; 525 526 if (p->type & M_T_BUILTIN) { 527 return xf86HandleBuiltinMode(scrp, p, modep, clockRanges, 528 allowDiv2); 529 } 530 531 /* Check clock is in range */ 532 cp = xf86FindClockRangeForMode(clockRanges, p); 533 if (cp == NULL) { 534 /* 535 * XXX Could do more here to provide a more detailed 536 * reason for not finding a mode. 537 */ 538 p->status = MODE_CLOCK_RANGE; 539 if (!found) 540 status = MODE_CLOCK_RANGE; 541 continue; 542 } 543 544 /* 545 * If programmable clock and strategy is not 546 * LOOKUP_BEST_REFRESH, the required mode has been found, 547 * otherwise record the refresh and continue looking. 548 */ 549 if (scrp->progClock) { 550 found = TRUE; 551 if (strategy != LOOKUP_BEST_REFRESH) { 552 bestMode = p; 553 DivFactor = cp->ClockDivFactor; 554 MulFactor = cp->ClockMulFactor; 555 ModePrivFlags = cp->PrivFlags; 556 break; 557 } 558 refresh = xf86ModeVRefresh(p); 559 if (p->Flags & V_INTERLACE) 560 refresh /= INTERLACE_REFRESH_WEIGHT; 561 if (refresh > bestRefresh) { 562 bestMode = p; 563 DivFactor = cp->ClockDivFactor; 564 MulFactor = cp->ClockMulFactor; 565 ModePrivFlags = cp->PrivFlags; 566 bestRefresh = refresh; 567 } 568 continue; 569 } 570 571 /* 572 * Clock is in range, so if it is not a programmable clock, find 573 * a matching clock. 574 */ 575 576 i = xf86GetNearestClock(scrp, p->Clock, allowDiv2, 577 cp->ClockDivFactor, cp->ClockMulFactor, 578 &k); 579 /* 580 * If the clock is too far from the requested clock, this 581 * mode is no good. 582 */ 583 if (k & V_CLKDIV2) 584 gap = abs((p->Clock * 2) - 585 ((scrp->clock[i] * cp->ClockDivFactor) / 586 cp->ClockMulFactor)); 587 else 588 gap = abs(p->Clock - 589 ((scrp->clock[i] * cp->ClockDivFactor) / 590 cp->ClockMulFactor)); 591 if (gap > minimumGap) { 592 p->status = MODE_NOCLOCK; 593 if (!found) 594 status = MODE_NOCLOCK; 595 continue; 596 } 597 found = TRUE; 598 599 if (strategy == LOOKUP_BEST_REFRESH) { 600 refresh = xf86ModeVRefresh(p); 601 if (p->Flags & V_INTERLACE) 602 refresh /= INTERLACE_REFRESH_WEIGHT; 603 if (refresh > bestRefresh) { 604 bestMode = p; 605 DivFactor = cp->ClockDivFactor; 606 MulFactor = cp->ClockMulFactor; 607 ModePrivFlags = cp->PrivFlags; 608 extraFlags = k; 609 clockIndex = i; 610 bestRefresh = refresh; 611 } 612 continue; 613 } 614 if (strategy == LOOKUP_CLOSEST_CLOCK) { 615 if (gap < minimumGap) { 616 bestMode = p; 617 DivFactor = cp->ClockDivFactor; 618 MulFactor = cp->ClockMulFactor; 619 ModePrivFlags = cp->PrivFlags; 620 extraFlags = k; 621 clockIndex = i; 622 minimumGap = gap; 623 } 624 continue; 625 } 626 /* 627 * If strategy is neither LOOKUP_BEST_REFRESH or 628 * LOOKUP_CLOSEST_CLOCK the required mode has been found. 629 */ 630 bestMode = p; 631 DivFactor = cp->ClockDivFactor; 632 MulFactor = cp->ClockMulFactor; 633 ModePrivFlags = cp->PrivFlags; 634 extraFlags = k; 635 clockIndex = i; 636 break; 637 } 638 } 639 if (found) 640 break; 641 } 642 if (!found || bestMode == NULL) 643 return status; 644 645 /* Fill in the mode parameters */ 646 if (scrp->progClock) { 647 modep->Clock = bestMode->Clock; 648 modep->ClockIndex = -1; 649 modep->SynthClock = (modep->Clock * MulFactor) / DivFactor; 650 } 651 else { 652 modep->Clock = (scrp->clock[clockIndex] * DivFactor) / MulFactor; 653 modep->ClockIndex = clockIndex; 654 modep->SynthClock = scrp->clock[clockIndex]; 655 if (extraFlags & V_CLKDIV2) { 656 modep->Clock /= 2; 657 modep->SynthClock /= 2; 658 } 659 } 660 modep->type = bestMode->type; 661 modep->PrivFlags = ModePrivFlags; 662 modep->HDisplay = bestMode->HDisplay; 663 modep->HSyncStart = bestMode->HSyncStart; 664 modep->HSyncEnd = bestMode->HSyncEnd; 665 modep->HTotal = bestMode->HTotal; 666 modep->HSkew = bestMode->HSkew; 667 modep->VDisplay = bestMode->VDisplay; 668 modep->VSyncStart = bestMode->VSyncStart; 669 modep->VSyncEnd = bestMode->VSyncEnd; 670 modep->VTotal = bestMode->VTotal; 671 modep->VScan = bestMode->VScan; 672 modep->Flags = bestMode->Flags | extraFlags; 673 modep->CrtcHDisplay = bestMode->CrtcHDisplay; 674 modep->CrtcHBlankStart = bestMode->CrtcHBlankStart; 675 modep->CrtcHSyncStart = bestMode->CrtcHSyncStart; 676 modep->CrtcHSyncEnd = bestMode->CrtcHSyncEnd; 677 modep->CrtcHBlankEnd = bestMode->CrtcHBlankEnd; 678 modep->CrtcHTotal = bestMode->CrtcHTotal; 679 modep->CrtcHSkew = bestMode->CrtcHSkew; 680 modep->CrtcVDisplay = bestMode->CrtcVDisplay; 681 modep->CrtcVBlankStart = bestMode->CrtcVBlankStart; 682 modep->CrtcVSyncStart = bestMode->CrtcVSyncStart; 683 modep->CrtcVSyncEnd = bestMode->CrtcVSyncEnd; 684 modep->CrtcVBlankEnd = bestMode->CrtcVBlankEnd; 685 modep->CrtcVTotal = bestMode->CrtcVTotal; 686 modep->CrtcHAdjusted = bestMode->CrtcHAdjusted; 687 modep->CrtcVAdjusted = bestMode->CrtcVAdjusted; 688 modep->HSync = bestMode->HSync; 689 modep->VRefresh = bestMode->VRefresh; 690 modep->Private = bestMode->Private; 691 modep->PrivSize = bestMode->PrivSize; 692 693 bestMode->prev = modep; 694 695 return MODE_OK; 696} 697 698/* 699 * xf86CheckModeForMonitor 700 * 701 * This function takes a mode and monitor description, and determines 702 * if the mode is valid for the monitor. 703 */ 704ModeStatus 705xf86CheckModeForMonitor(DisplayModePtr mode, MonPtr monitor) 706{ 707 int i; 708 709 /* Sanity checks */ 710 if (mode == NULL || monitor == NULL) { 711 ErrorF("xf86CheckModeForMonitor: called with invalid parameters\n"); 712 return MODE_ERROR; 713 } 714 715 DebugF("xf86CheckModeForMonitor(%p %s, %p %s)\n", 716 mode, mode->name, monitor, monitor->id); 717 718 /* Some basic mode validity checks */ 719 if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || 720 mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) 721 return MODE_H_ILLEGAL; 722 723 if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || 724 mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) 725 return MODE_V_ILLEGAL; 726 727 if (monitor->nHsync > 0) { 728 /* Check hsync against the allowed ranges */ 729 float hsync = xf86ModeHSync(mode); 730 731 for (i = 0; i < monitor->nHsync; i++) 732 if ((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) && 733 (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE))) 734 break; 735 736 /* Now see whether we ran out of sync ranges without finding a match */ 737 if (i == monitor->nHsync) 738 return MODE_HSYNC; 739 } 740 741 if (monitor->nVrefresh > 0) { 742 /* Check vrefresh against the allowed ranges */ 743 float vrefrsh = xf86ModeVRefresh(mode); 744 745 for (i = 0; i < monitor->nVrefresh; i++) 746 if ((vrefrsh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) && 747 (vrefrsh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE))) 748 break; 749 750 /* Now see whether we ran out of refresh ranges without finding a match */ 751 if (i == monitor->nVrefresh) 752 return MODE_VSYNC; 753 } 754 755 /* Force interlaced modes to have an odd VTotal */ 756 if (mode->Flags & V_INTERLACE) 757 mode->CrtcVTotal = mode->VTotal |= 1; 758 759 /* 760 * This code stops cvt -r modes, and only cvt -r modes, from hitting 15y+ 761 * old CRTs which might, when there is a lot of solar flare activity and 762 * when the celestial bodies are unfavourably aligned, implode trying to 763 * sync to it. It's called "Protecting the user from doing anything stupid". 764 * -- libv 765 */ 766 767 if (xf86ModeIsReduced(mode)) { 768 if (!monitor->reducedblanking && !(mode->type & M_T_DRIVER)) 769 return MODE_NO_REDUCED; 770 } 771 772 if ((monitor->maxPixClock) && (mode->Clock > monitor->maxPixClock)) 773 return MODE_CLOCK_HIGH; 774 775 return MODE_OK; 776} 777 778/* 779 * xf86CheckModeSize 780 * 781 * An internal routine to check if a mode fits in video memory. This tries to 782 * avoid overflows that would otherwise occur when video memory size is greater 783 * than 256MB. 784 */ 785static Bool 786xf86CheckModeSize(ScrnInfoPtr scrp, int w, int x, int y) 787{ 788 int bpp = scrp->fbFormat.bitsPerPixel, pad = scrp->fbFormat.scanlinePad; 789 int lineWidth, lastWidth; 790 791 if (scrp->depth == 4) 792 pad *= 4; /* 4 planes */ 793 794 /* Sanity check */ 795 if ((w < 0) || (x < 0) || (y <= 0)) 796 return FALSE; 797 798 lineWidth = (((w * bpp) + pad - 1) / pad) * pad; 799 lastWidth = x * bpp; 800 801 /* 802 * At this point, we need to compare 803 * 804 * (lineWidth * (y - 1)) + lastWidth 805 * 806 * against 807 * 808 * scrp->videoRam * (1024 * 8) 809 * 810 * These are bit quantities. To avoid overflows, do the comparison in 811 * terms of BITMAP_SCANLINE_PAD units. This assumes BITMAP_SCANLINE_PAD 812 * is a power of 2. We currently use 32, which limits us to a video 813 * memory size of 8GB. 814 */ 815 816 lineWidth = (lineWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; 817 lastWidth = (lastWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; 818 819 if ((lineWidth * (y - 1) + lastWidth) > 820 (scrp->videoRam * ((1024 * 8) / BITMAP_SCANLINE_PAD))) 821 return FALSE; 822 823 return TRUE; 824} 825 826/* 827 * xf86InitialCheckModeForDriver 828 * 829 * This function checks if a mode satisfies a driver's initial requirements: 830 * - mode size fits within the available pixel area (memory) 831 * - width lies within the range of supported line pitches 832 * - mode size fits within virtual size (if fixed) 833 * - horizontal timings are in range 834 * 835 * This function takes the following parameters: 836 * scrp ScrnInfoPtr 837 * mode mode to check 838 * maxPitch (optional) maximum line pitch 839 * virtualX (optional) virtual width requested 840 * virtualY (optional) virtual height requested 841 * 842 * In addition, the following fields from the ScrnInfoRec are used: 843 * monitor pointer to structure for monitor section 844 * fbFormat pixel format for the framebuffer 845 * videoRam video memory size (in kB) 846 */ 847 848static ModeStatus 849xf86InitialCheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, 850 ClockRangePtr clockRanges, 851 LookupModeFlags strategy, 852 int maxPitch, int virtualX, int virtualY) 853{ 854 ClockRangePtr cp; 855 ModeStatus status; 856 Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; 857 int i, needDiv2; 858 859 /* Sanity checks */ 860 if (!scrp || !mode || !clockRanges) { 861 ErrorF("xf86InitialCheckModeForDriver: " 862 "called with invalid parameters\n"); 863 return MODE_ERROR; 864 } 865 866 DebugF("xf86InitialCheckModeForDriver(%p, %p %s, %p, 0x%x, %d, %d, %d)\n", 867 scrp, mode, mode->name, clockRanges, strategy, maxPitch, virtualX, 868 virtualY); 869 870 /* Some basic mode validity checks */ 871 if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || 872 mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) 873 return MODE_H_ILLEGAL; 874 875 if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || 876 mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) 877 return MODE_V_ILLEGAL; 878 879 if (!xf86CheckModeSize(scrp, mode->HDisplay, mode->HDisplay, 880 mode->VDisplay)) 881 return MODE_MEM; 882 883 if (maxPitch > 0 && mode->HDisplay > maxPitch) 884 return MODE_BAD_WIDTH; 885 886 if (virtualX > 0 && mode->HDisplay > virtualX) 887 return MODE_VIRTUAL_X; 888 889 if (virtualY > 0 && mode->VDisplay > virtualY) 890 return MODE_VIRTUAL_Y; 891 892 /* 893 * The use of the DisplayModeRec's Crtc* and SynthClock elements below is 894 * provisional, in that they are later reused by the driver at mode-set 895 * time. Here, they are temporarily enlisted to contain the mode timings 896 * as seen by the CRT or panel (rather than the CRTC). The driver's 897 * ValidMode() is allowed to modify these so it can deal with such things 898 * as mode stretching and/or centering. The driver should >NOT< modify the 899 * user-supplied values as these are reported back when mode validation is 900 * said and done. 901 */ 902 /* 903 * NOTE: We (ab)use the mode->Crtc* values here to store timing 904 * information for the calculation of Hsync and Vrefresh. Before 905 * these values are calculated the driver is given the opportunity 906 * to either set these HSync and VRefresh itself or modify the timing 907 * values. 908 * The difference to the final calculation is small but imortand: 909 * here we pass the flag INTERLACE_HALVE_V regardless if the driver 910 * sets it or not. This way our calculation of VRefresh has the same 911 * effect as if we do if (flags & V_INTERLACE) refresh *= 2.0 912 * This dual use of the mode->Crtc* values will certainly create 913 * confusion and is bad software design. However since it's part of 914 * the driver API it's hard to change. 915 */ 916 917 if (scrp->ValidMode) { 918 919 xf86SetModeCrtc(mode, INTERLACE_HALVE_V); 920 921 cp = xf86FindClockRangeForMode(clockRanges, mode); 922 if (!cp) 923 return MODE_CLOCK_RANGE; 924 925 if (cp->ClockMulFactor < 1) 926 cp->ClockMulFactor = 1; 927 if (cp->ClockDivFactor < 1) 928 cp->ClockDivFactor = 1; 929 930 /* 931 * XXX The effect of clock dividers and multipliers on the monitor's 932 * pixel clock needs to be verified. 933 */ 934 if (scrp->progClock) { 935 mode->SynthClock = mode->Clock; 936 } 937 else { 938 i = xf86GetNearestClock(scrp, mode->Clock, allowDiv2, 939 cp->ClockDivFactor, cp->ClockMulFactor, 940 &needDiv2); 941 mode->SynthClock = (scrp->clock[i] * cp->ClockDivFactor) / 942 cp->ClockMulFactor; 943 if (needDiv2 & V_CLKDIV2) 944 mode->SynthClock /= 2; 945 } 946 947 status = (*scrp->ValidMode) (scrp, mode, FALSE, 948 MODECHECK_INITIAL); 949 if (status != MODE_OK) 950 return status; 951 952 if (mode->HSync <= 0.0) 953 mode->HSync = (float) mode->SynthClock / (float) mode->CrtcHTotal; 954 if (mode->VRefresh <= 0.0) 955 mode->VRefresh = (mode->SynthClock * 1000.0) 956 / (mode->CrtcHTotal * mode->CrtcVTotal); 957 } 958 959 mode->HSync = xf86ModeHSync(mode); 960 mode->VRefresh = xf86ModeVRefresh(mode); 961 962 /* Assume it is OK */ 963 return MODE_OK; 964} 965 966/* 967 * xf86CheckModeForDriver 968 * 969 * This function is for checking modes while the server is running (for 970 * use mainly by the VidMode extension). 971 * 972 * This function checks if a mode satisfies a driver's requirements: 973 * - width lies within the line pitch 974 * - mode size fits within virtual size 975 * - horizontal/vertical timings are in range 976 * 977 * This function takes the following parameters: 978 * scrp ScrnInfoPtr 979 * mode mode to check 980 * flags not (currently) used 981 * 982 * In addition, the following fields from the ScrnInfoRec are used: 983 * virtualX virtual width 984 * virtualY virtual height 985 * clockRanges allowable clock ranges 986 */ 987 988ModeStatus 989xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, int flags) 990{ 991 ClockRangePtr cp; 992 int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1; 993 int extraFlags = 0; 994 int clockIndex = -1; 995 int MulFactor = 1; 996 int DivFactor = 1; 997 int ModePrivFlags = 0; 998 ModeStatus status = MODE_NOMODE; 999 1000 /* Some sanity checking */ 1001 if (scrp == NULL || (!scrp->progClock && scrp->numClocks == 0)) { 1002 ErrorF("xf86CheckModeForDriver: called with invalid scrnInfoRec\n"); 1003 return MODE_ERROR; 1004 } 1005 if (mode == NULL) { 1006 ErrorF("xf86CheckModeForDriver: called with invalid modep\n"); 1007 return MODE_ERROR; 1008 } 1009 1010 /* Check the mode size */ 1011 if (mode->HDisplay > scrp->virtualX) 1012 return MODE_VIRTUAL_X; 1013 1014 if (mode->VDisplay > scrp->virtualY) 1015 return MODE_VIRTUAL_Y; 1016 1017 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { 1018 /* DivFactor and MulFactor must be > 0 */ 1019 cp->ClockDivFactor = max(1, cp->ClockDivFactor); 1020 cp->ClockMulFactor = max(1, cp->ClockMulFactor); 1021 } 1022 1023 if (scrp->progClock) { 1024 /* Check clock is in range */ 1025 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { 1026 if (modeInClockRange(cp, mode)) 1027 break; 1028 } 1029 if (cp == NULL) { 1030 return MODE_CLOCK_RANGE; 1031 } 1032 /* 1033 * If programmable clock the required mode has been found 1034 */ 1035 DivFactor = cp->ClockDivFactor; 1036 MulFactor = cp->ClockMulFactor; 1037 ModePrivFlags = cp->PrivFlags; 1038 } 1039 else { 1040 status = MODE_CLOCK_RANGE; 1041 /* Check clock is in range */ 1042 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { 1043 if (modeInClockRange(cp, mode)) { 1044 /* 1045 * Clock is in range, so if it is not a programmable clock, 1046 * find a matching clock. 1047 */ 1048 1049 i = xf86GetNearestClock(scrp, mode->Clock, 0, 1050 cp->ClockDivFactor, cp->ClockMulFactor, 1051 &k); 1052 /* 1053 * If the clock is too far from the requested clock, this 1054 * mode is no good. 1055 */ 1056 if (k & V_CLKDIV2) 1057 gap = abs((mode->Clock * 2) - 1058 ((scrp->clock[i] * cp->ClockDivFactor) / 1059 cp->ClockMulFactor)); 1060 else 1061 gap = abs(mode->Clock - 1062 ((scrp->clock[i] * cp->ClockDivFactor) / 1063 cp->ClockMulFactor)); 1064 if (gap > minimumGap) { 1065 status = MODE_NOCLOCK; 1066 continue; 1067 } 1068 1069 DivFactor = cp->ClockDivFactor; 1070 MulFactor = cp->ClockMulFactor; 1071 ModePrivFlags = cp->PrivFlags; 1072 extraFlags = k; 1073 clockIndex = i; 1074 break; 1075 } 1076 } 1077 if (cp == NULL) 1078 return status; 1079 } 1080 1081 /* Fill in the mode parameters */ 1082 if (scrp->progClock) { 1083 mode->ClockIndex = -1; 1084 mode->SynthClock = (mode->Clock * MulFactor) / DivFactor; 1085 } 1086 else { 1087 mode->Clock = (scrp->clock[clockIndex] * DivFactor) / MulFactor; 1088 mode->ClockIndex = clockIndex; 1089 mode->SynthClock = scrp->clock[clockIndex]; 1090 if (extraFlags & V_CLKDIV2) { 1091 mode->Clock /= 2; 1092 mode->SynthClock /= 2; 1093 } 1094 } 1095 mode->PrivFlags = ModePrivFlags; 1096 1097 return MODE_OK; 1098} 1099 1100static int 1101inferVirtualSize(ScrnInfoPtr scrp, DisplayModePtr modes, int *vx, int *vy) 1102{ 1103 float aspect = 0.0; 1104 MonPtr mon = scrp->monitor; 1105 xf86MonPtr DDC; 1106 int x = 0, y = 0; 1107 DisplayModePtr mode; 1108 1109 if (!mon) 1110 return 0; 1111 DDC = mon->DDC; 1112 1113 if (DDC && DDC->ver.revision >= 4) { 1114 /* For 1.4, we might actually get native pixel format. How novel. */ 1115 if (PREFERRED_TIMING_MODE(DDC->features.msc)) { 1116 for (mode = modes; mode; mode = mode->next) { 1117 if (mode->type & (M_T_DRIVER | M_T_PREFERRED)) { 1118 x = mode->HDisplay; 1119 y = mode->VDisplay; 1120 goto found; 1121 } 1122 } 1123 } 1124 /* 1125 * Even if we don't, we might get aspect ratio from extra CVT info 1126 * or from the monitor size fields. TODO. 1127 */ 1128 } 1129 1130 /* 1131 * Technically this triggers if either is zero. That wasn't legal 1132 * before EDID 1.4, but right now we'll get that wrong. TODO. 1133 */ 1134 if (!aspect) { 1135 if (!mon->widthmm || !mon->heightmm) 1136 aspect = 4.0 / 3.0; 1137 else 1138 aspect = (float) mon->widthmm / (float) mon->heightmm; 1139 } 1140 1141 /* find the largest M_T_DRIVER mode with that aspect ratio */ 1142 for (mode = modes; mode; mode = mode->next) { 1143 float mode_aspect, metaspect; 1144 1145 if (!(mode->type & (M_T_DRIVER | M_T_USERDEF))) 1146 continue; 1147 mode_aspect = (float) mode->HDisplay / (float) mode->VDisplay; 1148 metaspect = aspect / mode_aspect; 1149 /* 5% slop or so, since we only get size in centimeters */ 1150 if (fabs(1.0 - metaspect) < 0.05) { 1151 if ((mode->HDisplay > x) && (mode->VDisplay > y)) { 1152 x = mode->HDisplay; 1153 y = mode->VDisplay; 1154 } 1155 } 1156 } 1157 1158 if (!x || !y) { 1159 xf86DrvMsg(scrp->scrnIndex, X_WARNING, 1160 "Unable to estimate virtual size\n"); 1161 return 0; 1162 } 1163 1164 found: 1165 *vx = x; 1166 *vy = y; 1167 1168 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1169 "Estimated virtual size for aspect ratio %.4f is %dx%d\n", 1170 aspect, *vx, *vy); 1171 1172 return 1; 1173} 1174 1175/* Least common multiple */ 1176static unsigned int 1177LCM(unsigned int x, unsigned int y) 1178{ 1179 unsigned int m = x, n = y, o; 1180 1181 while ((o = m % n)) { 1182 m = n; 1183 n = o; 1184 } 1185 1186 return (x / n) * y; 1187} 1188 1189/* 1190 * Given various screen attributes, determine the minimum scanline width such 1191 * that each scanline is server and DDX padded and any pixels with embedded 1192 * bank boundaries are off-screen. This function returns -1 if such a width 1193 * cannot exist. 1194 */ 1195static int 1196scanLineWidth(unsigned int xsize, /* pixels */ 1197 unsigned int ysize, /* pixels */ 1198 unsigned int width, /* pixels */ 1199 unsigned long BankSize, /* char's */ 1200 PixmapFormatRec * pBankFormat, unsigned int nWidthUnit /* bits */ 1201 ) 1202{ 1203 unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit; 1204 unsigned long minBitsPerScanline, maxBitsPerScanline; 1205 1206 /* Sanity checks */ 1207 1208 if (!nWidthUnit || !pBankFormat) 1209 return -1; 1210 1211 nBitsPerBank = BankSize * 8; 1212 if (nBitsPerBank % pBankFormat->scanlinePad) 1213 return -1; 1214 1215 if (xsize > width) 1216 width = xsize; 1217 nBitsPerScanlinePadUnit = LCM(pBankFormat->scanlinePad, nWidthUnit); 1218 nBitsPerScanline = 1219 (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) / 1220 nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit; 1221 width = nBitsPerScanline / pBankFormat->bitsPerPixel; 1222 1223 if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel)) 1224 return (int) width; 1225 1226 /* 1227 * Scanlines will be server-pad aligned at this point. They will also be 1228 * a multiple of nWidthUnit bits long. Ensure that pixels with embedded 1229 * bank boundaries are off-screen. 1230 * 1231 * It seems reasonable to limit total frame buffer size to 1/16 of the 1232 * theoretical maximum address space size. On a machine with 32-bit 1233 * addresses (to 8-bit quantities) this turns out to be 256MB. Not only 1234 * does this provide a simple limiting condition for the loops below, but 1235 * it also prevents unsigned long wraparounds. 1236 */ 1237 if (!ysize) 1238 return -1; 1239 1240 minBitsPerScanline = xsize * pBankFormat->bitsPerPixel; 1241 if (minBitsPerScanline > nBitsPerBank) 1242 return -1; 1243 1244 if (ysize == 1) 1245 return (int) width; 1246 1247 maxBitsPerScanline = 1248 (((unsigned long) (-1) >> 1) - minBitsPerScanline) / (ysize - 1); 1249 while (nBitsPerScanline <= maxBitsPerScanline) { 1250 unsigned long BankBase, BankUnit; 1251 1252 BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) * 1253 nBitsPerBank; 1254 if (!(BankUnit % nBitsPerScanline)) 1255 return (int) width; 1256 1257 for (BankBase = BankUnit;; BankBase += nBitsPerBank) { 1258 unsigned long x, y; 1259 1260 y = BankBase / nBitsPerScanline; 1261 if (y >= ysize) 1262 return (int) width; 1263 1264 x = BankBase % nBitsPerScanline; 1265 if (!(x % pBankFormat->bitsPerPixel)) 1266 continue; 1267 1268 if (x < minBitsPerScanline) { 1269 /* 1270 * Skip ahead certain widths by dividing the excess scanline 1271 * amongst the y's. 1272 */ 1273 y *= nBitsPerScanlinePadUnit; 1274 nBitsPerScanline += ((x + y - 1) / y) * nBitsPerScanlinePadUnit; 1275 width = nBitsPerScanline / pBankFormat->bitsPerPixel; 1276 break; 1277 } 1278 1279 if (BankBase != BankUnit) 1280 continue; 1281 1282 if (!(nBitsPerScanline % x)) 1283 return (int) width; 1284 1285 BankBase = ((nBitsPerScanline - minBitsPerScanline) / 1286 (nBitsPerScanline - x)) * BankUnit; 1287 } 1288 } 1289 1290 return -1; 1291} 1292 1293/* 1294 * xf86ValidateModes 1295 * 1296 * This function takes a set of mode names, modes and limiting conditions, 1297 * and selects a set of modes and parameters based on those conditions. 1298 * 1299 * This function takes the following parameters: 1300 * scrp ScrnInfoPtr 1301 * availModes the list of modes available for the monitor 1302 * modeNames (optional) list of mode names that the screen is requesting 1303 * clockRanges a list of clock ranges 1304 * linePitches (optional) a list of line pitches 1305 * minPitch (optional) minimum line pitch (in pixels) 1306 * maxPitch (optional) maximum line pitch (in pixels) 1307 * pitchInc (mandatory) pitch increment (in bits) 1308 * minHeight (optional) minimum virtual height (in pixels) 1309 * maxHeight (optional) maximum virtual height (in pixels) 1310 * virtualX (optional) virtual width requested (in pixels) 1311 * virtualY (optional) virtual height requested (in pixels) 1312 * apertureSize size of video aperture (in bytes) 1313 * strategy how to decide which mode to use from multiple modes with 1314 * the same name 1315 * 1316 * In addition, the following fields from the ScrnInfoRec are used: 1317 * clocks a list of discrete clocks 1318 * numClocks number of discrete clocks 1319 * progClock clock is programmable 1320 * monitor pointer to structure for monitor section 1321 * fbFormat format of the framebuffer 1322 * videoRam video memory size 1323 * xInc horizontal timing increment (defaults to 8 pixels) 1324 * 1325 * The function fills in the following ScrnInfoRec fields: 1326 * modePool A subset of the modes available to the monitor which 1327 * are compatible with the driver. 1328 * modes one mode entry for each of the requested modes, with the 1329 * status field filled in to indicate if the mode has been 1330 * accepted or not. 1331 * virtualX the resulting virtual width 1332 * virtualY the resulting virtual height 1333 * displayWidth the resulting line pitch 1334 * 1335 * The function's return value is the number of matching modes found, or -1 1336 * if an unrecoverable error was encountered. 1337 */ 1338 1339int 1340xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, 1341 const char **modeNames, ClockRangePtr clockRanges, 1342 int *linePitches, int minPitch, int maxPitch, int pitchInc, 1343 int minHeight, int maxHeight, int virtualX, int virtualY, 1344 int apertureSize, LookupModeFlags strategy) 1345{ 1346 DisplayModePtr p, q, r, new, last, *endp; 1347 int i, numModes = 0; 1348 ModeStatus status; 1349 int linePitch = -1, virtX = 0, virtY = 0; 1350 int newLinePitch, newVirtX, newVirtY; 1351 int modeSize; /* in pixels */ 1352 Bool validateAllDefaultModes = FALSE; 1353 Bool userModes = FALSE; 1354 int saveType; 1355 PixmapFormatRec *BankFormat; 1356 ClockRangePtr cp; 1357 int numTimings = 0; 1358 range hsync[MAX_HSYNC]; 1359 range vrefresh[MAX_VREFRESH]; 1360 Bool inferred_virtual = FALSE; 1361 1362 DebugF 1363 ("xf86ValidateModes(%p, %p, %p, %p,\n\t\t %p, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x)\n", 1364 scrp, availModes, modeNames, clockRanges, linePitches, minPitch, 1365 maxPitch, pitchInc, minHeight, maxHeight, virtualX, virtualY, 1366 apertureSize, strategy); 1367 1368 /* Some sanity checking */ 1369 if (scrp == NULL || scrp->name == NULL || !scrp->monitor || 1370 (!scrp->progClock && scrp->numClocks == 0)) { 1371 ErrorF("xf86ValidateModes: called with invalid scrnInfoRec\n"); 1372 return -1; 1373 } 1374 if (linePitches != NULL && linePitches[0] <= 0) { 1375 ErrorF("xf86ValidateModes: called with invalid linePitches\n"); 1376 return -1; 1377 } 1378 if (pitchInc <= 0) { 1379 ErrorF("xf86ValidateModes: called with invalid pitchInc\n"); 1380 return -1; 1381 } 1382 if ((virtualX > 0) != (virtualY > 0)) { 1383 ErrorF("xf86ValidateModes: called with invalid virtual resolution\n"); 1384 return -1; 1385 } 1386 1387 /* 1388 * If requested by the driver, allow missing hsync and/or vrefresh ranges 1389 * in the monitor section. 1390 */ 1391 if (strategy & LOOKUP_OPTIONAL_TOLERANCES) { 1392 strategy &= ~LOOKUP_OPTIONAL_TOLERANCES; 1393 } 1394 else { 1395 const char *type = ""; 1396 Bool specified = FALSE; 1397 1398 if (scrp->monitor->nHsync <= 0) { 1399 if (numTimings > 0) { 1400 scrp->monitor->nHsync = numTimings; 1401 for (i = 0; i < numTimings; i++) { 1402 scrp->monitor->hsync[i].lo = hsync[i].lo; 1403 scrp->monitor->hsync[i].hi = hsync[i].hi; 1404 } 1405 } 1406 else { 1407 scrp->monitor->hsync[0].lo = 31.5; 1408 scrp->monitor->hsync[0].hi = 48.0; 1409 scrp->monitor->nHsync = 1; 1410 } 1411 type = "default "; 1412 } 1413 else { 1414 specified = TRUE; 1415 } 1416 for (i = 0; i < scrp->monitor->nHsync; i++) { 1417 if (scrp->monitor->hsync[i].lo == scrp->monitor->hsync[i].hi) 1418 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1419 "%s: Using %shsync value of %.2f kHz\n", 1420 scrp->monitor->id, type, scrp->monitor->hsync[i].lo); 1421 else 1422 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1423 "%s: Using %shsync range of %.2f-%.2f kHz\n", 1424 scrp->monitor->id, type, 1425 scrp->monitor->hsync[i].lo, 1426 scrp->monitor->hsync[i].hi); 1427 } 1428 1429 type = ""; 1430 if (scrp->monitor->nVrefresh <= 0) { 1431 if (numTimings > 0) { 1432 scrp->monitor->nVrefresh = numTimings; 1433 for (i = 0; i < numTimings; i++) { 1434 scrp->monitor->vrefresh[i].lo = vrefresh[i].lo; 1435 scrp->monitor->vrefresh[i].hi = vrefresh[i].hi; 1436 } 1437 } 1438 else { 1439 scrp->monitor->vrefresh[0].lo = 50; 1440 scrp->monitor->vrefresh[0].hi = 70; 1441 scrp->monitor->nVrefresh = 1; 1442 } 1443 type = "default "; 1444 } 1445 else { 1446 specified = TRUE; 1447 } 1448 for (i = 0; i < scrp->monitor->nVrefresh; i++) { 1449 if (scrp->monitor->vrefresh[i].lo == scrp->monitor->vrefresh[i].hi) 1450 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1451 "%s: Using %svrefresh value of %.2f Hz\n", 1452 scrp->monitor->id, type, 1453 scrp->monitor->vrefresh[i].lo); 1454 else 1455 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1456 "%s: Using %svrefresh range of %.2f-%.2f Hz\n", 1457 scrp->monitor->id, type, 1458 scrp->monitor->vrefresh[i].lo, 1459 scrp->monitor->vrefresh[i].hi); 1460 } 1461 1462 type = ""; 1463 if (!scrp->monitor->maxPixClock && !specified) { 1464 type = "default "; 1465 scrp->monitor->maxPixClock = 65000.0; 1466 } 1467 if (scrp->monitor->maxPixClock) { 1468 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1469 "%s: Using %smaximum pixel clock of %.2f MHz\n", 1470 scrp->monitor->id, type, 1471 (float) scrp->monitor->maxPixClock / 1000.0); 1472 } 1473 } 1474 1475 /* 1476 * Store the clockRanges for later use by the VidMode extension. 1477 */ 1478 nt_list_for_each_entry(cp, clockRanges, next) { 1479 ClockRangePtr newCR = xnfalloc(sizeof(ClockRange)); 1480 memcpy(newCR, cp, sizeof(ClockRange)); 1481 newCR->next = NULL; 1482 if (scrp->clockRanges == NULL) 1483 scrp->clockRanges = newCR; 1484 else 1485 nt_list_append(newCR, scrp->clockRanges, ClockRange, next); 1486 } 1487 1488 /* Determine which pixmap format to pass to scanLineWidth() */ 1489 if (scrp->depth > 4) 1490 BankFormat = &scrp->fbFormat; 1491 else 1492 BankFormat = xf86GetPixFormat(scrp, 1); /* >not< scrp->depth! */ 1493 1494 if (scrp->xInc <= 0) 1495 scrp->xInc = 8; /* Suitable for VGA and others */ 1496 1497#define _VIRTUALX(x) ((((x) + scrp->xInc - 1) / scrp->xInc) * scrp->xInc) 1498 1499 /* 1500 * Determine maxPitch if it wasn't given explicitly. Note linePitches 1501 * always takes precedence if is non-NULL. In that case the minPitch and 1502 * maxPitch values passed are ignored. 1503 */ 1504 if (linePitches) { 1505 minPitch = maxPitch = linePitches[0]; 1506 for (i = 1; linePitches[i] > 0; i++) { 1507 if (linePitches[i] > maxPitch) 1508 maxPitch = linePitches[i]; 1509 if (linePitches[i] < minPitch) 1510 minPitch = linePitches[i]; 1511 } 1512 } 1513 1514 /* 1515 * Initialise virtX and virtY if the values are fixed. 1516 */ 1517 if (virtualY > 0) { 1518 if (maxHeight > 0 && virtualY > maxHeight) { 1519 xf86DrvMsg(scrp->scrnIndex, X_ERROR, 1520 "Virtual height (%d) is too large for the hardware " 1521 "(max %d)\n", virtualY, maxHeight); 1522 return -1; 1523 } 1524 1525 if (minHeight > 0 && virtualY < minHeight) { 1526 xf86DrvMsg(scrp->scrnIndex, X_ERROR, 1527 "Virtual height (%d) is too small for the hardware " 1528 "(min %d)\n", virtualY, minHeight); 1529 return -1; 1530 } 1531 1532 virtualX = _VIRTUALX(virtualX); 1533 if (linePitches != NULL) { 1534 for (i = 0; linePitches[i] != 0; i++) { 1535 if ((linePitches[i] >= virtualX) && 1536 (linePitches[i] == 1537 scanLineWidth(virtualX, virtualY, linePitches[i], 1538 apertureSize, BankFormat, pitchInc))) { 1539 linePitch = linePitches[i]; 1540 break; 1541 } 1542 } 1543 } 1544 else { 1545 linePitch = scanLineWidth(virtualX, virtualY, minPitch, 1546 apertureSize, BankFormat, pitchInc); 1547 } 1548 1549 if ((linePitch < minPitch) || (linePitch > maxPitch)) { 1550 xf86DrvMsg(scrp->scrnIndex, X_ERROR, 1551 "Virtual width (%d) is too large for the hardware " 1552 "(max %d)\n", virtualX, maxPitch); 1553 return -1; 1554 } 1555 1556 if (!xf86CheckModeSize(scrp, linePitch, virtualX, virtualY)) { 1557 xf86DrvMsg(scrp->scrnIndex, X_ERROR, 1558 "Virtual size (%dx%d) (pitch %d) exceeds video memory\n", 1559 virtualX, virtualY, linePitch); 1560 return -1; 1561 } 1562 1563 virtX = virtualX; 1564 virtY = virtualY; 1565 } 1566 else if (!modeNames || !*modeNames) { 1567 /* No virtual size given in the config, try to infer */ 1568 /* XXX this doesn't take m{in,ax}Pitch into account; oh well */ 1569 inferred_virtual = inferVirtualSize(scrp, availModes, &virtX, &virtY); 1570 if (inferred_virtual) 1571 linePitch = scanLineWidth(virtX, virtY, minPitch, apertureSize, 1572 BankFormat, pitchInc); 1573 } 1574 1575 /* Print clock ranges and scaled clocks */ 1576 xf86ShowClockRanges(scrp, clockRanges); 1577 1578 /* 1579 * If scrp->modePool hasn't been setup yet, set it up now. This allows the 1580 * modes that the driver definitely can't use to be weeded out early. Note 1581 * that a modePool mode's prev field is used to hold a pointer to the 1582 * member of the scrp->modes list for which a match was considered. 1583 */ 1584 if (scrp->modePool == NULL) { 1585 q = NULL; 1586 for (p = availModes; p != NULL; p = p->next) { 1587 status = xf86InitialCheckModeForDriver(scrp, p, clockRanges, 1588 strategy, maxPitch, 1589 virtX, virtY); 1590 1591 if (status == MODE_OK) { 1592 status = xf86CheckModeForMonitor(p, scrp->monitor); 1593 } 1594 1595 if (status == MODE_OK) { 1596 new = xnfalloc(sizeof(DisplayModeRec)); 1597 *new = *p; 1598 new->next = NULL; 1599 if (!q) { 1600 scrp->modePool = new; 1601 } 1602 else { 1603 q->next = new; 1604 } 1605 new->prev = NULL; 1606 q = new; 1607 q->name = xnfstrdup(p->name); 1608 q->status = MODE_OK; 1609 } 1610 else { 1611 printModeRejectMessage(scrp->scrnIndex, p, status); 1612 } 1613 } 1614 1615 if (scrp->modePool == NULL) { 1616 xf86DrvMsg(scrp->scrnIndex, X_WARNING, "Mode pool is empty\n"); 1617 return 0; 1618 } 1619 } 1620 else { 1621 for (p = scrp->modePool; p != NULL; p = p->next) { 1622 p->prev = NULL; 1623 p->status = MODE_OK; 1624 } 1625 } 1626 1627 /* 1628 * Allocate one entry in scrp->modes for each named mode. 1629 */ 1630 while (scrp->modes) 1631 xf86DeleteMode(&scrp->modes, scrp->modes); 1632 endp = &scrp->modes; 1633 last = NULL; 1634 if (modeNames != NULL) { 1635 for (i = 0; modeNames[i] != NULL; i++) { 1636 userModes = TRUE; 1637 new = xnfcalloc(1, sizeof(DisplayModeRec)); 1638 new->prev = last; 1639 new->type = M_T_USERDEF; 1640 new->name = xnfstrdup(modeNames[i]); 1641 if (new->prev) 1642 new->prev->next = new; 1643 *endp = last = new; 1644 endp = &new->next; 1645 } 1646 } 1647 1648 /* Lookup each mode */ 1649#ifdef PANORAMIX 1650 if (noPanoramiXExtension) 1651 validateAllDefaultModes = TRUE; 1652#endif 1653 1654 for (p = scrp->modes;; p = p->next) { 1655 Bool repeat; 1656 1657 /* 1658 * If the supplied mode names don't produce a valid mode, scan through 1659 * unconsidered modePool members until one survives validation. This 1660 * is done in decreasing order by mode pixel area. 1661 */ 1662 1663 if (p == NULL) { 1664 if ((numModes > 0) && !validateAllDefaultModes) 1665 break; 1666 1667 validateAllDefaultModes = TRUE; 1668 r = NULL; 1669 modeSize = 0; 1670 for (q = scrp->modePool; q != NULL; q = q->next) { 1671 if ((q->prev == NULL) && (q->status == MODE_OK)) { 1672 /* 1673 * Deal with the case where this mode wasn't considered 1674 * because of a builtin mode of the same name. 1675 */ 1676 for (p = scrp->modes; p != NULL; p = p->next) { 1677 if ((p->status != MODE_OK) && !strcmp(p->name, q->name)) 1678 break; 1679 } 1680 1681 if (p != NULL) 1682 q->prev = p; 1683 else { 1684 /* 1685 * A quick check to not allow default modes with 1686 * horizontal timing parameters that CRTs may have 1687 * problems with. 1688 */ 1689 if (!scrp->monitor->reducedblanking && 1690 (q->type & M_T_DEFAULT) && 1691 ((double) q->HTotal / (double) q->HDisplay) < 1.15) 1692 continue; 1693 1694 if (modeSize < (q->HDisplay * q->VDisplay)) { 1695 r = q; 1696 modeSize = q->HDisplay * q->VDisplay; 1697 } 1698 } 1699 } 1700 } 1701 1702 if (r == NULL) 1703 break; 1704 1705 p = xnfcalloc(1, sizeof(DisplayModeRec)); 1706 p->prev = last; 1707 p->name = xnfstrdup(r->name); 1708 if (!userModes) 1709 p->type = M_T_USERDEF; 1710 if (p->prev) 1711 p->prev->next = p; 1712 *endp = last = p; 1713 endp = &p->next; 1714 } 1715 1716 repeat = FALSE; 1717 lookupNext: 1718 if (repeat && ((status = p->status) != MODE_OK)) 1719 printModeRejectMessage(scrp->scrnIndex, p, status); 1720 saveType = p->type; 1721 status = xf86LookupMode(scrp, p, clockRanges, strategy); 1722 if (repeat && status == MODE_NOMODE) 1723 continue; 1724 if (status != MODE_OK) 1725 printModeRejectMessage(scrp->scrnIndex, p, status); 1726 if (status == MODE_ERROR) { 1727 ErrorF("xf86ValidateModes: " 1728 "unexpected result from xf86LookupMode()\n"); 1729 return -1; 1730 } 1731 if (status != MODE_OK) { 1732 if (p->status == MODE_OK) 1733 p->status = status; 1734 continue; 1735 } 1736 p->type |= saveType; 1737 repeat = TRUE; 1738 1739 newLinePitch = linePitch; 1740 newVirtX = virtX; 1741 newVirtY = virtY; 1742 1743 /* 1744 * Don't let non-user defined modes increase the virtual size 1745 */ 1746 if (!(p->type & M_T_USERDEF) && (numModes > 0)) { 1747 if (p->HDisplay > virtX) { 1748 p->status = MODE_VIRTUAL_X; 1749 goto lookupNext; 1750 } 1751 if (p->VDisplay > virtY) { 1752 p->status = MODE_VIRTUAL_Y; 1753 goto lookupNext; 1754 } 1755 } 1756 /* 1757 * Adjust virtual width and height if the mode is too large for the 1758 * current values and if they are not fixed. 1759 */ 1760 if (virtualX <= 0 && p->HDisplay > newVirtX) 1761 newVirtX = _VIRTUALX(p->HDisplay); 1762 if (virtualY <= 0 && p->VDisplay > newVirtY) { 1763 if (maxHeight > 0 && p->VDisplay > maxHeight) { 1764 p->status = MODE_VIRTUAL_Y; /* ? */ 1765 goto lookupNext; 1766 } 1767 newVirtY = p->VDisplay; 1768 } 1769 1770 /* 1771 * If virtual resolution is to be increased, revalidate it. 1772 */ 1773 if ((virtX != newVirtX) || (virtY != newVirtY)) { 1774 if (linePitches != NULL) { 1775 newLinePitch = -1; 1776 for (i = 0; linePitches[i] != 0; i++) { 1777 if ((linePitches[i] >= newVirtX) && 1778 (linePitches[i] >= linePitch) && 1779 (linePitches[i] == 1780 scanLineWidth(newVirtX, newVirtY, linePitches[i], 1781 apertureSize, BankFormat, pitchInc))) { 1782 newLinePitch = linePitches[i]; 1783 break; 1784 } 1785 } 1786 } 1787 else { 1788 if (linePitch < minPitch) 1789 linePitch = minPitch; 1790 newLinePitch = scanLineWidth(newVirtX, newVirtY, linePitch, 1791 apertureSize, BankFormat, 1792 pitchInc); 1793 } 1794 if ((newLinePitch < minPitch) || (newLinePitch > maxPitch)) { 1795 p->status = MODE_BAD_WIDTH; 1796 goto lookupNext; 1797 } 1798 1799 /* 1800 * Check that the pixel area required by the new virtual height 1801 * and line pitch isn't too large. 1802 */ 1803 if (!xf86CheckModeSize(scrp, newLinePitch, newVirtX, newVirtY)) { 1804 p->status = MODE_MEM_VIRT; 1805 goto lookupNext; 1806 } 1807 } 1808 1809 if (scrp->ValidMode) { 1810 /* 1811 * Give the driver a final say, passing it the proposed virtual 1812 * geometry. 1813 */ 1814 scrp->virtualX = newVirtX; 1815 scrp->virtualY = newVirtY; 1816 scrp->displayWidth = newLinePitch; 1817 p->status = (scrp->ValidMode) (scrp, p, FALSE, 1818 MODECHECK_FINAL); 1819 1820 if (p->status != MODE_OK) { 1821 goto lookupNext; 1822 } 1823 } 1824 1825 /* Mode has passed all the tests */ 1826 virtX = newVirtX; 1827 virtY = newVirtY; 1828 linePitch = newLinePitch; 1829 p->status = MODE_OK; 1830 numModes++; 1831 } 1832 1833 /* 1834 * If we estimated the virtual size above, we may have filtered away all 1835 * the modes that maximally match that size; scan again to find out and 1836 * fix up if so. 1837 */ 1838 if (inferred_virtual) { 1839 int vx = 0, vy = 0; 1840 1841 for (p = scrp->modes; p; p = p->next) { 1842 if (p->HDisplay > vx && p->VDisplay > vy) { 1843 vx = p->HDisplay; 1844 vy = p->VDisplay; 1845 } 1846 } 1847 if (vx < virtX || vy < virtY) { 1848 const int types[] = { 1849 M_T_BUILTIN | M_T_PREFERRED, 1850 M_T_BUILTIN, 1851 M_T_DRIVER | M_T_PREFERRED, 1852 M_T_DRIVER, 1853 0 1854 }; 1855 const int ntypes = ARRAY_SIZE(types); 1856 int n; 1857 1858 /* 1859 * We did not find the estimated virtual size. So now we want to 1860 * find the largest mode available, but we want to search in the 1861 * modes in the order of "types" listed above. 1862 */ 1863 for (n = 0; n < ntypes; n++) { 1864 int type = types[n]; 1865 1866 vx = 0; 1867 vy = 0; 1868 for (p = scrp->modes; p; p = p->next) { 1869 /* scan through the modes in the sort order above */ 1870 if ((p->type & type) != type) 1871 continue; 1872 if (p->HDisplay > vx && p->VDisplay > vy) { 1873 vx = p->HDisplay; 1874 vy = p->VDisplay; 1875 } 1876 } 1877 if (vx && vy) 1878 /* Found one */ 1879 break; 1880 } 1881 xf86DrvMsg(scrp->scrnIndex, X_WARNING, 1882 "Shrinking virtual size estimate from %dx%d to %dx%d\n", 1883 virtX, virtY, vx, vy); 1884 virtX = _VIRTUALX(vx); 1885 virtY = vy; 1886 for (p = scrp->modes; p; p = p->next) { 1887 if (numModes > 0) { 1888 if (p->HDisplay > virtX) 1889 p->status = MODE_VIRTUAL_X; 1890 if (p->VDisplay > virtY) 1891 p->status = MODE_VIRTUAL_Y; 1892 if (p->status != MODE_OK) { 1893 numModes--; 1894 printModeRejectMessage(scrp->scrnIndex, p, p->status); 1895 } 1896 } 1897 } 1898 if (linePitches != NULL) { 1899 for (i = 0; linePitches[i] != 0; i++) { 1900 if ((linePitches[i] >= virtX) && 1901 (linePitches[i] == 1902 scanLineWidth(virtX, virtY, linePitches[i], 1903 apertureSize, BankFormat, pitchInc))) { 1904 linePitch = linePitches[i]; 1905 break; 1906 } 1907 } 1908 } 1909 else { 1910 linePitch = scanLineWidth(virtX, virtY, minPitch, 1911 apertureSize, BankFormat, pitchInc); 1912 } 1913 } 1914 } 1915 1916 /* Update the ScrnInfoRec parameters */ 1917 1918 scrp->virtualX = virtX; 1919 scrp->virtualY = virtY; 1920 scrp->displayWidth = linePitch; 1921 1922 if (numModes <= 0) 1923 return 0; 1924 1925 /* Make the mode list into a circular list by joining up the ends */ 1926 p = scrp->modes; 1927 while (p->next != NULL) 1928 p = p->next; 1929 /* p is now the last mode on the list */ 1930 p->next = scrp->modes; 1931 scrp->modes->prev = p; 1932 1933 if (minHeight > 0 && virtY < minHeight) { 1934 xf86DrvMsg(scrp->scrnIndex, X_ERROR, 1935 "Virtual height (%d) is too small for the hardware " 1936 "(min %d)\n", virtY, minHeight); 1937 return -1; 1938 } 1939 1940 return numModes; 1941} 1942 1943/* 1944 * xf86DeleteMode 1945 * 1946 * This function removes a mode from a list of modes. 1947 * 1948 * There are different types of mode lists: 1949 * 1950 * - singly linked linear lists, ending in NULL 1951 * - doubly linked linear lists, starting and ending in NULL 1952 * - doubly linked circular lists 1953 * 1954 */ 1955 1956void 1957xf86DeleteMode(DisplayModePtr * modeList, DisplayModePtr mode) 1958{ 1959 /* Catch the easy/insane cases */ 1960 if (modeList == NULL || *modeList == NULL || mode == NULL) 1961 return; 1962 1963 /* If the mode is at the start of the list, move the start of the list */ 1964 if (*modeList == mode) 1965 *modeList = mode->next; 1966 1967 /* If mode is the only one on the list, set the list to NULL */ 1968 if ((mode == mode->prev) && (mode == mode->next)) { 1969 *modeList = NULL; 1970 } 1971 else { 1972 if ((mode->prev != NULL) && (mode->prev->next == mode)) 1973 mode->prev->next = mode->next; 1974 if ((mode->next != NULL) && (mode->next->prev == mode)) 1975 mode->next->prev = mode->prev; 1976 } 1977 1978 free((void *) mode->name); 1979 free(mode); 1980} 1981 1982/* 1983 * xf86PruneDriverModes 1984 * 1985 * Remove modes from the driver's mode list which have been marked as 1986 * invalid. 1987 */ 1988 1989void 1990xf86PruneDriverModes(ScrnInfoPtr scrp) 1991{ 1992 DisplayModePtr first, p, n; 1993 1994 p = scrp->modes; 1995 if (p == NULL) 1996 return; 1997 1998 do { 1999 if (!(first = scrp->modes)) 2000 return; 2001 n = p->next; 2002 if (p->status != MODE_OK) { 2003 xf86DeleteMode(&(scrp->modes), p); 2004 } 2005 p = n; 2006 } while (p != NULL && p != first); 2007 2008 /* modePool is no longer needed, turf it */ 2009 while (scrp->modePool) { 2010 /* 2011 * A modePool mode's prev field is used to hold a pointer to the 2012 * member of the scrp->modes list for which a match was considered. 2013 * Clear that pointer first, otherwise xf86DeleteMode might get 2014 * confused 2015 */ 2016 scrp->modePool->prev = NULL; 2017 xf86DeleteMode(&scrp->modePool, scrp->modePool); 2018 } 2019} 2020 2021/* 2022 * xf86SetCrtcForModes 2023 * 2024 * Goes through the screen's mode list, and initialises the Crtc 2025 * parameters for each mode. The initialisation includes adjustments 2026 * for interlaced and double scan modes. 2027 */ 2028void 2029xf86SetCrtcForModes(ScrnInfoPtr scrp, int adjustFlags) 2030{ 2031 DisplayModePtr p; 2032 2033 /* 2034 * Store adjustFlags for use with the VidMode extension. There is an 2035 * implicit assumption here that SetCrtcForModes is called once. 2036 */ 2037 scrp->adjustFlags = adjustFlags; 2038 2039 p = scrp->modes; 2040 if (p == NULL) 2041 return; 2042 2043 do { 2044 xf86SetModeCrtc(p, adjustFlags); 2045 DebugF("%sMode %s: %d (%d) %d %d (%d) %d %d (%d) %d %d (%d) %d\n", 2046 (p->type & M_T_DEFAULT) ? "Default " : "", 2047 p->name, p->CrtcHDisplay, p->CrtcHBlankStart, 2048 p->CrtcHSyncStart, p->CrtcHSyncEnd, p->CrtcHBlankEnd, 2049 p->CrtcHTotal, p->CrtcVDisplay, p->CrtcVBlankStart, 2050 p->CrtcVSyncStart, p->CrtcVSyncEnd, p->CrtcVBlankEnd, 2051 p->CrtcVTotal); 2052 p = p->next; 2053 } while (p != NULL && p != scrp->modes); 2054} 2055 2056void 2057xf86PrintModes(ScrnInfoPtr scrp) 2058{ 2059 DisplayModePtr p; 2060 float hsync, refresh = 0; 2061 const char *desc, *desc2, *prefix, *uprefix; 2062 2063 if (scrp == NULL) 2064 return; 2065 2066 xf86DrvMsg(scrp->scrnIndex, X_INFO, "Virtual size is %dx%d (pitch %d)\n", 2067 scrp->virtualX, scrp->virtualY, scrp->displayWidth); 2068 2069 p = scrp->modes; 2070 if (p == NULL) 2071 return; 2072 2073 do { 2074 desc = desc2 = ""; 2075 hsync = xf86ModeHSync(p); 2076 refresh = xf86ModeVRefresh(p); 2077 if (p->Flags & V_INTERLACE) { 2078 desc = " (I)"; 2079 } 2080 if (p->Flags & V_DBLSCAN) { 2081 desc = " (D)"; 2082 } 2083 if (p->VScan > 1) { 2084 desc2 = " (VScan)"; 2085 } 2086 if (p->type & M_T_BUILTIN) 2087 prefix = "Built-in mode"; 2088 else if (p->type & M_T_DEFAULT) 2089 prefix = "Default mode"; 2090 else if (p->type & M_T_DRIVER) 2091 prefix = "Driver mode"; 2092 else 2093 prefix = "Mode"; 2094 if (p->type & M_T_USERDEF) 2095 uprefix = "*"; 2096 else 2097 uprefix = " "; 2098 if (hsync == 0 || refresh == 0) { 2099 if (p->name) 2100 xf86DrvMsg(scrp->scrnIndex, X_CONFIG, 2101 "%s%s \"%s\"\n", uprefix, prefix, p->name); 2102 else 2103 xf86DrvMsg(scrp->scrnIndex, X_PROBED, 2104 "%s%s %dx%d (unnamed)\n", 2105 uprefix, prefix, p->HDisplay, p->VDisplay); 2106 } 2107 else if (p->Clock == p->SynthClock) { 2108 xf86DrvMsg(scrp->scrnIndex, X_CONFIG, 2109 "%s%s \"%s\": %.1f MHz, %.1f kHz, %.1f Hz%s%s\n", 2110 uprefix, prefix, p->name, p->Clock / 1000.0, 2111 hsync, refresh, desc, desc2); 2112 } 2113 else { 2114 xf86DrvMsg(scrp->scrnIndex, X_CONFIG, 2115 "%s%s \"%s\": %.1f MHz (scaled from %.1f MHz), " 2116 "%.1f kHz, %.1f Hz%s%s\n", 2117 uprefix, prefix, p->name, p->Clock / 1000.0, 2118 p->SynthClock / 1000.0, hsync, refresh, desc, desc2); 2119 } 2120 if (hsync != 0 && refresh != 0) 2121 xf86PrintModeline(scrp->scrnIndex, p); 2122 p = p->next; 2123 } while (p != NULL && p != scrp->modes); 2124} 2125