xf86Mode.c revision 8223e2f2
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 "os.h" 90#include "servermd.h" 91#include "globals.h" 92#include "xf86.h" 93#include "xf86Priv.h" 94#include "edid.h" 95 96static void 97printModeRejectMessage(int index, DisplayModePtr p, int status) 98{ 99 char *type; 100 101 if (p->type & M_T_BUILTIN) 102 type = "built-in "; 103 else if (p->type & M_T_DEFAULT) 104 type = "default "; 105 else if (p->type & M_T_DRIVER) 106 type = "driver "; 107 else 108 type = ""; 109 110 xf86DrvMsg(index, X_INFO, "Not using %smode \"%s\" (%s)\n", type, p->name, 111 xf86ModeStatusToString(status)); 112} 113 114/* 115 * xf86GetNearestClock -- 116 * Find closest clock to given frequency (in kHz). This assumes the 117 * number of clocks is greater than zero. 118 */ 119int 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) || 140 ((gap == minimumGap) && (j < nearestDiv))) { 141 minimumGap = gap; 142 nearestClock = i; 143 nearestDiv = j; 144 if (divider != NULL) 145 *divider = (j - 1) * V_CLKDIV2; 146 } 147 } 148 } 149 return nearestClock; 150} 151 152/* 153 * xf86ModeStatusToString 154 * 155 * Convert a ModeStatus value to a printable message 156 */ 157 158const char * 159xf86ModeStatusToString(ModeStatus status) 160{ 161 switch (status) { 162 case MODE_OK: 163 return "Mode OK"; 164 case MODE_HSYNC: 165 return "hsync out of range"; 166 case MODE_VSYNC: 167 return "vrefresh out of range"; 168 case MODE_H_ILLEGAL: 169 return "illegal horizontal timings"; 170 case MODE_V_ILLEGAL: 171 return "illegal vertical timings"; 172 case MODE_BAD_WIDTH: 173 return "width requires unsupported line pitch"; 174 case MODE_NOMODE: 175 return "no mode of this name"; 176 case MODE_NO_INTERLACE: 177 return "interlace mode not supported"; 178 case MODE_NO_DBLESCAN: 179 return "doublescan mode not supported"; 180 case MODE_NO_VSCAN: 181 return "multiscan mode not supported"; 182 case MODE_MEM: 183 return "insufficient memory for mode"; 184 case MODE_VIRTUAL_X: 185 return "width too large for virtual size"; 186 case MODE_VIRTUAL_Y: 187 return "height too large for virtual size"; 188 case MODE_MEM_VIRT: 189 return "insufficient memory given virtual size"; 190 case MODE_NOCLOCK: 191 return "no clock available for mode"; 192 case MODE_CLOCK_HIGH: 193 return "mode clock too high"; 194 case MODE_CLOCK_LOW: 195 return "mode clock too low"; 196 case MODE_CLOCK_RANGE: 197 return "bad mode clock/interlace/doublescan"; 198 case MODE_BAD_HVALUE: 199 return "horizontal timing out of range"; 200 case MODE_BAD_VVALUE: 201 return "vertical timing out of range"; 202 case MODE_BAD_VSCAN: 203 return "VScan value out of range"; 204 case MODE_HSYNC_NARROW: 205 return "horizontal sync too narrow"; 206 case MODE_HSYNC_WIDE: 207 return "horizontal sync too wide"; 208 case MODE_HBLANK_NARROW: 209 return "horizontal blanking too narrow"; 210 case MODE_HBLANK_WIDE: 211 return "horizontal blanking too wide"; 212 case MODE_VSYNC_NARROW: 213 return "vertical sync too narrow"; 214 case MODE_VSYNC_WIDE: 215 return "vertical sync too wide"; 216 case MODE_VBLANK_NARROW: 217 return "vertical blanking too narrow"; 218 case MODE_VBLANK_WIDE: 219 return "vertical blanking too wide"; 220 case MODE_PANEL: 221 return "exceeds panel dimensions"; 222 case MODE_INTERLACE_WIDTH: 223 return "width too large for interlaced mode"; 224 case MODE_ONE_WIDTH: 225 return "all modes must have the same width"; 226 case MODE_ONE_HEIGHT: 227 return "all modes must have the same height"; 228 case MODE_ONE_SIZE: 229 return "all modes must have the same resolution"; 230 case MODE_NO_REDUCED: 231 return "monitor doesn't support reduced blanking"; 232 case MODE_BANDWIDTH: 233 return "mode requires too much memory bandwidth"; 234 case MODE_BAD: 235 return "unknown reason"; 236 case MODE_ERROR: 237 return "internal error"; 238 default: 239 return "unknown"; 240 } 241} 242 243/* 244 * xf86ShowClockRanges() -- Print the clock ranges allowed 245 * and the clock values scaled by ClockMulFactor and ClockDivFactor 246 */ 247void 248xf86ShowClockRanges(ScrnInfoPtr scrp, ClockRangePtr clockRanges) 249{ 250 ClockRangePtr cp; 251 int MulFactor = 1; 252 int DivFactor = 1; 253 int i, j; 254 int scaledClock; 255 256 for (cp = clockRanges; cp != NULL; cp = cp->next) { 257 DivFactor = max(1, cp->ClockDivFactor); 258 MulFactor = max(1, cp->ClockMulFactor); 259 if (scrp->progClock) { 260 if (cp->minClock) { 261 if (cp->maxClock) { 262 xf86DrvMsg(scrp->scrnIndex, X_INFO, 263 "Clock range: %6.2f to %6.2f MHz\n", 264 (double)cp->minClock / 1000.0, 265 (double)cp->maxClock / 1000.0); 266 } else { 267 xf86DrvMsg(scrp->scrnIndex, X_INFO, 268 "Minimum clock: %6.2f MHz\n", 269 (double)cp->minClock / 1000.0); 270 } 271 } else { 272 if (cp->maxClock) { 273 xf86DrvMsg(scrp->scrnIndex, X_INFO, 274 "Maximum clock: %6.2f MHz\n", 275 (double)cp->maxClock / 1000.0); 276 } 277 } 278 } else if (DivFactor > 1 || MulFactor > 1) { 279 j = 0; 280 for (i = 0; i < scrp->numClocks; i++) { 281 scaledClock = (scrp->clock[i] * DivFactor) / MulFactor; 282 if (scaledClock >= cp->minClock && scaledClock <= cp->maxClock) { 283 if ((j % 8) == 0) { 284 if (j > 0) 285 xf86ErrorF("\n"); 286 xf86DrvMsg(scrp->scrnIndex, X_INFO, "scaled clocks:"); 287 } 288 xf86ErrorF(" %6.2f", (double)scaledClock / 1000.0); 289 j++; 290 } 291 } 292 xf86ErrorF("\n"); 293 } 294 } 295} 296 297static Bool 298modeInClockRange(ClockRangePtr cp, DisplayModePtr p) 299{ 300 return ((p->Clock >= cp->minClock) && 301 (p->Clock <= cp->maxClock) && 302 (cp->interlaceAllowed || !(p->Flags & V_INTERLACE)) && 303 (cp->doubleScanAllowed || 304 ((p->VScan <= 1) && !(p->Flags & V_DBLSCAN)))); 305} 306 307/* 308 * xf86FindClockRangeForMode() [... like the name says ...] 309 */ 310static ClockRangePtr 311xf86FindClockRangeForMode(ClockRangePtr clockRanges, DisplayModePtr p) 312{ 313 ClockRangePtr cp; 314 315 for (cp = clockRanges; ; cp = cp->next) 316 if (!cp || modeInClockRange(cp, p)) 317 return cp; 318} 319 320 321/* 322 * xf86HandleBuiltinMode() - handles built-in modes 323 */ 324static ModeStatus 325xf86HandleBuiltinMode(ScrnInfoPtr scrp, 326 DisplayModePtr p, 327 DisplayModePtr modep, 328 ClockRangePtr clockRanges, 329 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 } else { 368 modep->Clock = p->Clock; 369 modep->ClockIndex = -1; 370 modep->SynthClock = (modep->Clock * MulFactor) 371 / DivFactor; 372 } 373 modep->PrivFlags = cp->PrivFlags; 374 } else { 375 if(!scrp->progClock) { 376 modep->Clock = p->Clock; 377 modep->ClockIndex = p->ClockIndex; 378 modep->SynthClock = p->SynthClock; 379 } else { 380 modep->Clock = p->Clock; 381 modep->ClockIndex = -1; 382 modep->SynthClock = p->SynthClock; 383 } 384 modep->PrivFlags = p->PrivFlags; 385 } 386 modep->type = p->type; 387 modep->HDisplay = p->HDisplay; 388 modep->HSyncStart = p->HSyncStart; 389 modep->HSyncEnd = p->HSyncEnd; 390 modep->HTotal = p->HTotal; 391 modep->HSkew = p->HSkew; 392 modep->VDisplay = p->VDisplay; 393 modep->VSyncStart = p->VSyncStart; 394 modep->VSyncEnd = p->VSyncEnd; 395 modep->VTotal = p->VTotal; 396 modep->VScan = p->VScan; 397 modep->Flags = p->Flags | extraFlags; 398 modep->CrtcHDisplay = p->CrtcHDisplay; 399 modep->CrtcHBlankStart = p->CrtcHBlankStart; 400 modep->CrtcHSyncStart = p->CrtcHSyncStart; 401 modep->CrtcHSyncEnd = p->CrtcHSyncEnd; 402 modep->CrtcHBlankEnd = p->CrtcHBlankEnd; 403 modep->CrtcHTotal = p->CrtcHTotal; 404 modep->CrtcHSkew = p->CrtcHSkew; 405 modep->CrtcVDisplay = p->CrtcVDisplay; 406 modep->CrtcVBlankStart = p->CrtcVBlankStart; 407 modep->CrtcVSyncStart = p->CrtcVSyncStart; 408 modep->CrtcVSyncEnd = p->CrtcVSyncEnd; 409 modep->CrtcVBlankEnd = p->CrtcVBlankEnd; 410 modep->CrtcVTotal = p->CrtcVTotal; 411 modep->CrtcHAdjusted = p->CrtcHAdjusted; 412 modep->CrtcVAdjusted = p->CrtcVAdjusted; 413 modep->HSync = p->HSync; 414 modep->VRefresh = p->VRefresh; 415 modep->Private = p->Private; 416 modep->PrivSize = p->PrivSize; 417 418 p->prev = modep; 419 420 return MODE_OK; 421} 422 423/* 424 * xf86LookupMode 425 * 426 * This function returns a mode from the given list which matches the 427 * given name. When multiple modes with the same name are available, 428 * the method of picking the matching mode is determined by the 429 * strategy selected. 430 * 431 * This function takes the following parameters: 432 * scrp ScrnInfoPtr 433 * modep pointer to the returned mode, which must have the name 434 * field filled in. 435 * clockRanges a list of clock ranges. This is optional when all the 436 * modes are built-in modes. 437 * strategy how to decide which mode to use from multiple modes with 438 * the same name 439 * 440 * In addition, the following fields from the ScrnInfoRec are used: 441 * modePool the list of monitor modes compatible with the driver 442 * clocks a list of discrete clocks 443 * numClocks number of discrete clocks 444 * progClock clock is programmable 445 * 446 * If a mode was found, its values are filled in to the area pointed to 447 * by modep, If a mode was not found the return value indicates the 448 * reason. 449 */ 450 451ModeStatus 452xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep, 453 ClockRangePtr clockRanges, LookupModeFlags strategy) 454{ 455 DisplayModePtr p, bestMode = NULL; 456 ClockRangePtr cp; 457 int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1; 458 double refresh, bestRefresh = 0.0; 459 Bool found = FALSE; 460 int extraFlags = 0; 461 int clockIndex = -1; 462 int MulFactor = 1; 463 int DivFactor = 1; 464 int ModePrivFlags = 0; 465 ModeStatus status = MODE_NOMODE; 466 Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; 467 int n; 468 const int types[] = { 469 M_T_BUILTIN | M_T_PREFERRED, 470 M_T_BUILTIN, 471 M_T_USERDEF | M_T_PREFERRED, 472 M_T_USERDEF, 473 M_T_DRIVER | M_T_PREFERRED, 474 M_T_DRIVER, 475 0 476 }; 477 const int ntypes = sizeof(types) / sizeof(int); 478 479 strategy &= ~(LOOKUP_CLKDIV2 | LOOKUP_OPTIONAL_TOLERANCES); 480 481 /* Some sanity checking */ 482 if (scrp == NULL || scrp->modePool == NULL || 483 (!scrp->progClock && scrp->numClocks == 0)) { 484 ErrorF("xf86LookupMode: called with invalid scrnInfoRec\n"); 485 return MODE_ERROR; 486 } 487 if (modep == NULL || modep->name == NULL) { 488 ErrorF("xf86LookupMode: called with invalid modep\n"); 489 return MODE_ERROR; 490 } 491 for (cp = clockRanges; cp != NULL; cp = cp->next) { 492 /* DivFactor and MulFactor must be > 0 */ 493 cp->ClockDivFactor = max(1, cp->ClockDivFactor); 494 cp->ClockMulFactor = max(1, cp->ClockMulFactor); 495 } 496 497 /* Scan the mode pool for matching names */ 498 for (n = 0; n < ntypes; n++) { 499 int type = types[n]; 500 for (p = scrp->modePool; p != NULL; p = p->next) { 501 502 /* scan through the modes in the sort order above */ 503 if ((p->type & type) != type) 504 continue; 505 506 if (strcmp(p->name, modep->name) == 0) { 507 508 /* Skip over previously rejected modes */ 509 if (p->status != MODE_OK) { 510 if (!found) 511 status = p->status; 512 continue; 513 } 514 515 /* Skip over previously considered modes */ 516 if (p->prev) 517 continue; 518 519 if (p->type & M_T_BUILTIN) { 520 return xf86HandleBuiltinMode(scrp, p,modep, clockRanges, 521 allowDiv2); 522 } 523 524 /* Check clock is in range */ 525 cp = xf86FindClockRangeForMode(clockRanges, p); 526 if (cp == NULL) { 527 /* 528 * XXX Could do more here to provide a more detailed 529 * reason for not finding a mode. 530 */ 531 p->status = MODE_CLOCK_RANGE; 532 if (!found) 533 status = MODE_CLOCK_RANGE; 534 continue; 535 } 536 537 /* 538 * If programmable clock and strategy is not 539 * LOOKUP_BEST_REFRESH, the required mode has been found, 540 * otherwise record the refresh and continue looking. 541 */ 542 if (scrp->progClock) { 543 found = TRUE; 544 if (strategy != LOOKUP_BEST_REFRESH) { 545 bestMode = p; 546 DivFactor = cp->ClockDivFactor; 547 MulFactor = cp->ClockMulFactor; 548 ModePrivFlags = cp->PrivFlags; 549 break; 550 } 551 refresh = xf86ModeVRefresh(p); 552 if (p->Flags & V_INTERLACE) 553 refresh /= INTERLACE_REFRESH_WEIGHT; 554 if (refresh > bestRefresh) { 555 bestMode = p; 556 DivFactor = cp->ClockDivFactor; 557 MulFactor = cp->ClockMulFactor; 558 ModePrivFlags = cp->PrivFlags; 559 bestRefresh = refresh; 560 } 561 continue; 562 } 563 564 /* 565 * Clock is in range, so if it is not a programmable clock, find 566 * a matching clock. 567 */ 568 569 i = xf86GetNearestClock(scrp, p->Clock, allowDiv2, 570 cp->ClockDivFactor, cp->ClockMulFactor, &k); 571 /* 572 * If the clock is too far from the requested clock, this 573 * mode is no good. 574 */ 575 if (k & V_CLKDIV2) 576 gap = abs((p->Clock * 2) - 577 ((scrp->clock[i] * cp->ClockDivFactor) / 578 cp->ClockMulFactor)); 579 else 580 gap = abs(p->Clock - 581 ((scrp->clock[i] * cp->ClockDivFactor) / 582 cp->ClockMulFactor)); 583 if (gap > minimumGap) { 584 p->status = MODE_NOCLOCK; 585 if (!found) 586 status = MODE_NOCLOCK; 587 continue; 588 } 589 found = TRUE; 590 591 if (strategy == LOOKUP_BEST_REFRESH) { 592 refresh = xf86ModeVRefresh(p); 593 if (p->Flags & V_INTERLACE) 594 refresh /= INTERLACE_REFRESH_WEIGHT; 595 if (refresh > bestRefresh) { 596 bestMode = p; 597 DivFactor = cp->ClockDivFactor; 598 MulFactor = cp->ClockMulFactor; 599 ModePrivFlags = cp->PrivFlags; 600 extraFlags = k; 601 clockIndex = i; 602 bestRefresh = refresh; 603 } 604 continue; 605 } 606 if (strategy == LOOKUP_CLOSEST_CLOCK) { 607 if (gap < minimumGap) { 608 bestMode = p; 609 DivFactor = cp->ClockDivFactor; 610 MulFactor = cp->ClockMulFactor; 611 ModePrivFlags = cp->PrivFlags; 612 extraFlags = k; 613 clockIndex = i; 614 minimumGap = gap; 615 } 616 continue; 617 } 618 /* 619 * If strategy is neither LOOKUP_BEST_REFRESH or 620 * LOOKUP_CLOSEST_CLOCK the required mode has been found. 621 */ 622 bestMode = p; 623 DivFactor = cp->ClockDivFactor; 624 MulFactor = cp->ClockMulFactor; 625 ModePrivFlags = cp->PrivFlags; 626 extraFlags = k; 627 clockIndex = i; 628 break; 629 } 630 } 631 if (found) break; 632 } 633 if (!found || bestMode == NULL) 634 return status; 635 636 /* Fill in the mode parameters */ 637 if (scrp->progClock) { 638 modep->Clock = bestMode->Clock; 639 modep->ClockIndex = -1; 640 modep->SynthClock = (modep->Clock * MulFactor) / DivFactor; 641 } else { 642 modep->Clock = (scrp->clock[clockIndex] * DivFactor) / 643 MulFactor; 644 modep->ClockIndex = clockIndex; 645 modep->SynthClock = scrp->clock[clockIndex]; 646 if (extraFlags & V_CLKDIV2) { 647 modep->Clock /= 2; 648 modep->SynthClock /= 2; 649 } 650 } 651 modep->type = bestMode->type; 652 modep->PrivFlags = ModePrivFlags; 653 modep->HDisplay = bestMode->HDisplay; 654 modep->HSyncStart = bestMode->HSyncStart; 655 modep->HSyncEnd = bestMode->HSyncEnd; 656 modep->HTotal = bestMode->HTotal; 657 modep->HSkew = bestMode->HSkew; 658 modep->VDisplay = bestMode->VDisplay; 659 modep->VSyncStart = bestMode->VSyncStart; 660 modep->VSyncEnd = bestMode->VSyncEnd; 661 modep->VTotal = bestMode->VTotal; 662 modep->VScan = bestMode->VScan; 663 modep->Flags = bestMode->Flags | extraFlags; 664 modep->CrtcHDisplay = bestMode->CrtcHDisplay; 665 modep->CrtcHBlankStart = bestMode->CrtcHBlankStart; 666 modep->CrtcHSyncStart = bestMode->CrtcHSyncStart; 667 modep->CrtcHSyncEnd = bestMode->CrtcHSyncEnd; 668 modep->CrtcHBlankEnd = bestMode->CrtcHBlankEnd; 669 modep->CrtcHTotal = bestMode->CrtcHTotal; 670 modep->CrtcHSkew = bestMode->CrtcHSkew; 671 modep->CrtcVDisplay = bestMode->CrtcVDisplay; 672 modep->CrtcVBlankStart = bestMode->CrtcVBlankStart; 673 modep->CrtcVSyncStart = bestMode->CrtcVSyncStart; 674 modep->CrtcVSyncEnd = bestMode->CrtcVSyncEnd; 675 modep->CrtcVBlankEnd = bestMode->CrtcVBlankEnd; 676 modep->CrtcVTotal = bestMode->CrtcVTotal; 677 modep->CrtcHAdjusted = bestMode->CrtcHAdjusted; 678 modep->CrtcVAdjusted = bestMode->CrtcVAdjusted; 679 modep->HSync = bestMode->HSync; 680 modep->VRefresh = bestMode->VRefresh; 681 modep->Private = bestMode->Private; 682 modep->PrivSize = bestMode->PrivSize; 683 684 bestMode->prev = modep; 685 686 return MODE_OK; 687} 688 689/* 690 * xf86CheckModeForMonitor 691 * 692 * This function takes a mode and monitor description, and determines 693 * if the mode is valid for the monitor. 694 */ 695ModeStatus 696xf86CheckModeForMonitor(DisplayModePtr mode, MonPtr monitor) 697{ 698 int i; 699 700 /* Sanity checks */ 701 if (mode == NULL || monitor == NULL) { 702 ErrorF("xf86CheckModeForMonitor: called with invalid parameters\n"); 703 return MODE_ERROR; 704 } 705 706 DebugF("xf86CheckModeForMonitor(%p %s, %p %s)\n", 707 mode, mode->name, monitor, monitor->id); 708 709 /* Some basic mode validity checks */ 710 if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || 711 mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) 712 return MODE_H_ILLEGAL; 713 714 if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || 715 mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) 716 return MODE_V_ILLEGAL; 717 718 if (monitor->nHsync > 0) { 719 /* Check hsync against the allowed ranges */ 720 float hsync = xf86ModeHSync(mode); 721 for (i = 0; i < monitor->nHsync; i++) 722 if ((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) && 723 (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE))) 724 break; 725 726 /* Now see whether we ran out of sync ranges without finding a match */ 727 if (i == monitor->nHsync) 728 return MODE_HSYNC; 729 } 730 731 if (monitor->nVrefresh > 0) { 732 /* Check vrefresh against the allowed ranges */ 733 float vrefrsh = xf86ModeVRefresh(mode); 734 for (i = 0; i < monitor->nVrefresh; i++) 735 if ((vrefrsh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) && 736 (vrefrsh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE))) 737 break; 738 739 /* Now see whether we ran out of refresh ranges without finding a match */ 740 if (i == monitor->nVrefresh) 741 return MODE_VSYNC; 742 } 743 744 /* Force interlaced modes to have an odd VTotal */ 745 if (mode->Flags & V_INTERLACE) 746 mode->CrtcVTotal = mode->VTotal |= 1; 747 748 /* 749 * This code stops cvt -r modes, and only cvt -r modes, from hitting 15y+ 750 * old CRTs which might, when there is a lot of solar flare activity and 751 * when the celestial bodies are unfavourably aligned, implode trying to 752 * sync to it. It's called "Protecting the user from doing anything stupid". 753 * -- libv 754 */ 755 756 if (xf86ModeIsReduced(mode)) { 757 if (!monitor->reducedblanking && !(mode->type & M_T_DRIVER)) 758 return MODE_NO_REDUCED; 759 } 760 761 if ((monitor->maxPixClock) && (mode->Clock > monitor->maxPixClock)) 762 return MODE_CLOCK_HIGH; 763 764 return MODE_OK; 765} 766 767/* 768 * xf86CheckModeSize 769 * 770 * An internal routine to check if a mode fits in video memory. This tries to 771 * avoid overflows that would otherwise occur when video memory size is greater 772 * than 256MB. 773 */ 774static Bool 775xf86CheckModeSize(ScrnInfoPtr scrp, int w, int x, int y) 776{ 777 int bpp = scrp->fbFormat.bitsPerPixel, 778 pad = scrp->fbFormat.scanlinePad; 779 int lineWidth, lastWidth; 780 781 if (scrp->depth == 4) 782 pad *= 4; /* 4 planes */ 783 784 /* Sanity check */ 785 if ((w < 0) || (x < 0) || (y <= 0)) 786 return FALSE; 787 788 lineWidth = (((w * bpp) + pad - 1) / pad) * pad; 789 lastWidth = x * bpp; 790 791 /* 792 * At this point, we need to compare 793 * 794 * (lineWidth * (y - 1)) + lastWidth 795 * 796 * against 797 * 798 * scrp->videoRam * (1024 * 8) 799 * 800 * These are bit quantities. To avoid overflows, do the comparison in 801 * terms of BITMAP_SCANLINE_PAD units. This assumes BITMAP_SCANLINE_PAD 802 * is a power of 2. We currently use 32, which limits us to a video 803 * memory size of 8GB. 804 */ 805 806 lineWidth = (lineWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; 807 lastWidth = (lastWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; 808 809 if ((lineWidth * (y - 1) + lastWidth) > 810 (scrp->videoRam * ((1024 * 8) / BITMAP_SCANLINE_PAD))) 811 return FALSE; 812 813 return TRUE; 814} 815 816/* 817 * xf86InitialCheckModeForDriver 818 * 819 * This function checks if a mode satisfies a driver's initial requirements: 820 * - mode size fits within the available pixel area (memory) 821 * - width lies within the range of supported line pitches 822 * - mode size fits within virtual size (if fixed) 823 * - horizontal timings are in range 824 * 825 * This function takes the following parameters: 826 * scrp ScrnInfoPtr 827 * mode mode to check 828 * maxPitch (optional) maximum line pitch 829 * virtualX (optional) virtual width requested 830 * virtualY (optional) virtual height requested 831 * 832 * In addition, the following fields from the ScrnInfoRec are used: 833 * monitor pointer to structure for monitor section 834 * fbFormat pixel format for the framebuffer 835 * videoRam video memory size (in kB) 836 * maxHValue maximum horizontal timing value 837 * maxVValue maximum vertical timing value 838 */ 839 840ModeStatus 841xf86InitialCheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, 842 ClockRangePtr clockRanges, 843 LookupModeFlags strategy, 844 int maxPitch, int virtualX, int virtualY) 845{ 846 ClockRangePtr cp; 847 ModeStatus status; 848 Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; 849 int i, needDiv2; 850 851 /* Sanity checks */ 852 if (!scrp || !mode || !clockRanges) { 853 ErrorF("xf86InitialCheckModeForDriver: " 854 "called with invalid parameters\n"); 855 return MODE_ERROR; 856 } 857 858 DebugF("xf86InitialCheckModeForDriver(%p, %p %s, %p, 0x%x, %d, %d, %d)\n", 859 scrp, mode, mode->name , clockRanges, strategy, maxPitch, virtualX, virtualY); 860 861 /* Some basic mode validity checks */ 862 if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || 863 mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) 864 return MODE_H_ILLEGAL; 865 866 if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || 867 mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) 868 return MODE_V_ILLEGAL; 869 870 if (!xf86CheckModeSize(scrp, mode->HDisplay, mode->HDisplay, 871 mode->VDisplay)) 872 return MODE_MEM; 873 874 if (maxPitch > 0 && mode->HDisplay > maxPitch) 875 return MODE_BAD_WIDTH; 876 877 if (virtualX > 0 && mode->HDisplay > virtualX) 878 return MODE_VIRTUAL_X; 879 880 if (virtualY > 0 && mode->VDisplay > virtualY) 881 return MODE_VIRTUAL_Y; 882 883 if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue) 884 return MODE_BAD_HVALUE; 885 886 if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue) 887 return MODE_BAD_VVALUE; 888 889 /* 890 * The use of the DisplayModeRec's Crtc* and SynthClock elements below is 891 * provisional, in that they are later reused by the driver at mode-set 892 * time. Here, they are temporarily enlisted to contain the mode timings 893 * as seen by the CRT or panel (rather than the CRTC). The driver's 894 * ValidMode() is allowed to modify these so it can deal with such things 895 * as mode stretching and/or centering. The driver should >NOT< modify the 896 * user-supplied values as these are reported back when mode validation is 897 * said and done. 898 */ 899 /* 900 * NOTE: We (ab)use the mode->Crtc* values here to store timing 901 * information for the calculation of Hsync and Vrefresh. Before 902 * these values are calculated the driver is given the opportunity 903 * to either set these HSync and VRefresh itself or modify the timing 904 * values. 905 * The difference to the final calculation is small but imortand: 906 * here we pass the flag INTERLACE_HALVE_V regardless if the driver 907 * sets it or not. This way our calculation of VRefresh has the same 908 * effect as if we do if (flags & V_INTERLACE) refresh *= 2.0 909 * This dual use of the mode->Crtc* values will certainly create 910 * confusion and is bad software design. However since it's part of 911 * the driver API it's hard to change. 912 */ 913 914 if (scrp->ValidMode) { 915 916 xf86SetModeCrtc(mode, INTERLACE_HALVE_V); 917 918 cp = xf86FindClockRangeForMode(clockRanges, mode); 919 if (!cp) 920 return MODE_CLOCK_RANGE; 921 922 if (cp->ClockMulFactor < 1) 923 cp->ClockMulFactor = 1; 924 if (cp->ClockDivFactor < 1) 925 cp->ClockDivFactor = 1; 926 927 /* 928 * XXX The effect of clock dividers and multipliers on the monitor's 929 * pixel clock needs to be verified. 930 */ 931 if (scrp->progClock) { 932 mode->SynthClock = mode->Clock; 933 } else { 934 i = xf86GetNearestClock(scrp, mode->Clock, allowDiv2, 935 cp->ClockDivFactor, cp->ClockMulFactor, 936 &needDiv2); 937 mode->SynthClock = (scrp->clock[i] * cp->ClockDivFactor) / 938 cp->ClockMulFactor; 939 if (needDiv2 & V_CLKDIV2) 940 mode->SynthClock /= 2; 941 } 942 943 status = (*scrp->ValidMode)(scrp->scrnIndex, mode, FALSE, 944 MODECHECK_INITIAL); 945 if (status != MODE_OK) 946 return status; 947 948 if (mode->HSync <= 0.0) 949 mode->HSync = (float)mode->SynthClock / (float)mode->CrtcHTotal; 950 if (mode->VRefresh <= 0.0) 951 mode->VRefresh = (mode->SynthClock * 1000.0) 952 / (mode->CrtcHTotal * mode->CrtcVTotal); 953 } 954 955 mode->HSync = xf86ModeHSync(mode); 956 mode->VRefresh = xf86ModeVRefresh(mode); 957 958 /* Assume it is OK */ 959 return MODE_OK; 960} 961 962/* 963 * xf86CheckModeForDriver 964 * 965 * This function is for checking modes while the server is running (for 966 * use mainly by the VidMode extension). 967 * 968 * This function checks if a mode satisfies a driver's requirements: 969 * - width lies within the line pitch 970 * - mode size fits within virtual size 971 * - horizontal/vertical timings are in range 972 * 973 * This function takes the following parameters: 974 * scrp ScrnInfoPtr 975 * mode mode to check 976 * flags not (currently) used 977 * 978 * In addition, the following fields from the ScrnInfoRec are used: 979 * maxHValue maximum horizontal timing value 980 * maxVValue maximum vertical timing value 981 * virtualX virtual width 982 * virtualY virtual height 983 * clockRanges allowable clock ranges 984 */ 985 986ModeStatus 987xf86CheckModeForDriver(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 if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue) 1016 return MODE_BAD_HVALUE; 1017 1018 if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue) 1019 return MODE_BAD_VVALUE; 1020 1021 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { 1022 /* DivFactor and MulFactor must be > 0 */ 1023 cp->ClockDivFactor = max(1, cp->ClockDivFactor); 1024 cp->ClockMulFactor = max(1, cp->ClockMulFactor); 1025 } 1026 1027 if (scrp->progClock) { 1028 /* Check clock is in range */ 1029 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { 1030 if (modeInClockRange(cp, mode)) 1031 break; 1032 } 1033 if (cp == NULL) { 1034 return MODE_CLOCK_RANGE; 1035 } 1036 /* 1037 * If programmable clock the required mode has been found 1038 */ 1039 DivFactor = cp->ClockDivFactor; 1040 MulFactor = cp->ClockMulFactor; 1041 ModePrivFlags = cp->PrivFlags; 1042 } else { 1043 status = MODE_CLOCK_RANGE; 1044 /* Check clock is in range */ 1045 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { 1046 if (modeInClockRange(cp, mode)) { 1047 /* 1048 * Clock is in range, so if it is not a programmable clock, 1049 * find a matching clock. 1050 */ 1051 1052 i = xf86GetNearestClock(scrp, mode->Clock, 0, 1053 cp->ClockDivFactor, cp->ClockMulFactor, &k); 1054 /* 1055 * If the clock is too far from the requested clock, this 1056 * mode is no good. 1057 */ 1058 if (k & V_CLKDIV2) 1059 gap = abs((mode->Clock * 2) - 1060 ((scrp->clock[i] * cp->ClockDivFactor) / 1061 cp->ClockMulFactor)); 1062 else 1063 gap = abs(mode->Clock - 1064 ((scrp->clock[i] * cp->ClockDivFactor) / 1065 cp->ClockMulFactor)); 1066 if (gap > minimumGap) { 1067 status = MODE_NOCLOCK; 1068 continue; 1069 } 1070 1071 DivFactor = cp->ClockDivFactor; 1072 MulFactor = cp->ClockMulFactor; 1073 ModePrivFlags = cp->PrivFlags; 1074 extraFlags = k; 1075 clockIndex = i; 1076 break; 1077 } 1078 } 1079 if (cp == NULL) 1080 return status; 1081 } 1082 1083 /* Fill in the mode parameters */ 1084 if (scrp->progClock) { 1085 mode->ClockIndex = -1; 1086 mode->SynthClock = (mode->Clock * MulFactor) / DivFactor; 1087 } else { 1088 mode->Clock = (scrp->clock[clockIndex] * DivFactor) / MulFactor; 1089 mode->ClockIndex = clockIndex; 1090 mode->SynthClock = scrp->clock[clockIndex]; 1091 if (extraFlags & V_CLKDIV2) { 1092 mode->Clock /= 2; 1093 mode->SynthClock /= 2; 1094 } 1095 } 1096 mode->PrivFlags = ModePrivFlags; 1097 1098 return MODE_OK; 1099} 1100 1101static int 1102inferVirtualSize(ScrnInfoPtr scrp, DisplayModePtr modes, int *vx, int *vy) 1103{ 1104 float aspect = 0.0; 1105 MonPtr mon = scrp->monitor; 1106 xf86MonPtr DDC; 1107 int x = 0, y = 0; 1108 DisplayModePtr mode; 1109 1110 if (!mon) 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 if (!(mode->type & (M_T_DRIVER|M_T_USERDEF))) 1145 continue; 1146 mode_aspect = (float)mode->HDisplay / (float)mode->VDisplay; 1147 metaspect = aspect / mode_aspect; 1148 /* 5% slop or so, since we only get size in centimeters */ 1149 if (fabs(1.0 - metaspect) < 0.05) { 1150 if ((mode->HDisplay > x) && (mode->VDisplay > y)) { 1151 x = mode->HDisplay; 1152 y = mode->VDisplay; 1153 } 1154 } 1155 } 1156 1157 if (!x || !y) { 1158 xf86DrvMsg(scrp->scrnIndex, X_WARNING, 1159 "Unable to estimate virtual size\n"); 1160 return 0; 1161 } 1162 1163found: 1164 *vx = x; 1165 *vy = y; 1166 1167 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1168 "Estimated virtual size for aspect ratio %.4f is %dx%d\n", 1169 aspect, *vx, *vy); 1170 1171 return 1; 1172} 1173 1174/* Least common multiple */ 1175static unsigned int 1176LCM(unsigned int x, unsigned int y) 1177{ 1178 unsigned int m = x, n = y, o; 1179 1180 while ((o = m % n)) 1181 { 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 imbedded 1192 * bank boundaries are off-screen. This function returns -1 if such a width 1193 * cannot exist. 1194 */ 1195static int 1196scanLineWidth( 1197 unsigned int xsize, /* pixels */ 1198 unsigned int ysize, /* pixels */ 1199 unsigned int width, /* pixels */ 1200 unsigned long BankSize, /* char's */ 1201 PixmapFormatRec *pBankFormat, 1202 unsigned int nWidthUnit /* bits */ 1203) 1204{ 1205 unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit; 1206 unsigned long minBitsPerScanline, maxBitsPerScanline; 1207 1208 /* Sanity checks */ 1209 1210 if (!nWidthUnit || !pBankFormat) 1211 return -1; 1212 1213 nBitsPerBank = BankSize * 8; 1214 if (nBitsPerBank % pBankFormat->scanlinePad) 1215 return -1; 1216 1217 if (xsize > width) 1218 width = xsize; 1219 nBitsPerScanlinePadUnit = LCM(pBankFormat->scanlinePad, nWidthUnit); 1220 nBitsPerScanline = 1221 (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) / 1222 nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit; 1223 width = nBitsPerScanline / pBankFormat->bitsPerPixel; 1224 1225 if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel)) 1226 return (int)width; 1227 1228 /* 1229 * Scanlines will be server-pad aligned at this point. They will also be 1230 * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded 1231 * bank boundaries are off-screen. 1232 * 1233 * It seems reasonable to limit total frame buffer size to 1/16 of the 1234 * theoretical maximum address space size. On a machine with 32-bit 1235 * addresses (to 8-bit quantities) this turns out to be 256MB. Not only 1236 * does this provide a simple limiting condition for the loops below, but 1237 * it also prevents unsigned long wraparounds. 1238 */ 1239 if (!ysize) 1240 return -1; 1241 1242 minBitsPerScanline = xsize * pBankFormat->bitsPerPixel; 1243 if (minBitsPerScanline > nBitsPerBank) 1244 return -1; 1245 1246 if (ysize == 1) 1247 return (int)width; 1248 1249 maxBitsPerScanline = 1250 (((unsigned long)(-1) >> 1) - minBitsPerScanline) / (ysize - 1); 1251 while (nBitsPerScanline <= maxBitsPerScanline) 1252 { 1253 unsigned long BankBase, BankUnit; 1254 1255 BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) * 1256 nBitsPerBank; 1257 if (!(BankUnit % nBitsPerScanline)) 1258 return (int)width; 1259 1260 for (BankBase = BankUnit; ; BankBase += nBitsPerBank) 1261 { 1262 unsigned long x, y; 1263 1264 y = BankBase / nBitsPerScanline; 1265 if (y >= ysize) 1266 return (int)width; 1267 1268 x = BankBase % nBitsPerScanline; 1269 if (!(x % pBankFormat->bitsPerPixel)) 1270 continue; 1271 1272 if (x < minBitsPerScanline) 1273 { 1274 /* 1275 * Skip ahead certain widths by dividing the excess scanline 1276 * amongst the y's. 1277 */ 1278 y *= nBitsPerScanlinePadUnit; 1279 nBitsPerScanline += 1280 ((x + y - 1) / y) * nBitsPerScanlinePadUnit; 1281 width = nBitsPerScanline / pBankFormat->bitsPerPixel; 1282 break; 1283 } 1284 1285 if (BankBase != BankUnit) 1286 continue; 1287 1288 if (!(nBitsPerScanline % x)) 1289 return (int)width; 1290 1291 BankBase = ((nBitsPerScanline - minBitsPerScanline) / 1292 (nBitsPerScanline - x)) * BankUnit; 1293 } 1294 } 1295 1296 return -1; 1297} 1298 1299/* 1300 * xf86ValidateModes 1301 * 1302 * This function takes a set of mode names, modes and limiting conditions, 1303 * and selects a set of modes and parameters based on those conditions. 1304 * 1305 * This function takes the following parameters: 1306 * scrp ScrnInfoPtr 1307 * availModes the list of modes available for the monitor 1308 * modeNames (optional) list of mode names that the screen is requesting 1309 * clockRanges a list of clock ranges 1310 * linePitches (optional) a list of line pitches 1311 * minPitch (optional) minimum line pitch (in pixels) 1312 * maxPitch (optional) maximum line pitch (in pixels) 1313 * pitchInc (mandatory) pitch increment (in bits) 1314 * minHeight (optional) minimum virtual height (in pixels) 1315 * maxHeight (optional) maximum virtual height (in pixels) 1316 * virtualX (optional) virtual width requested (in pixels) 1317 * virtualY (optional) virtual height requested (in pixels) 1318 * apertureSize size of video aperture (in bytes) 1319 * strategy how to decide which mode to use from multiple modes with 1320 * the same name 1321 * 1322 * In addition, the following fields from the ScrnInfoRec are used: 1323 * clocks a list of discrete clocks 1324 * numClocks number of discrete clocks 1325 * progClock clock is programmable 1326 * monitor pointer to structure for monitor section 1327 * fbFormat format of the framebuffer 1328 * videoRam video memory size 1329 * maxHValue maximum horizontal timing value 1330 * maxVValue maximum vertical timing value 1331 * xInc horizontal timing increment (defaults to 8 pixels) 1332 * 1333 * The function fills in the following ScrnInfoRec fields: 1334 * modePool A subset of the modes available to the monitor which 1335 * are compatible with the driver. 1336 * modes one mode entry for each of the requested modes, with the 1337 * status field filled in to indicate if the mode has been 1338 * accepted or not. 1339 * virtualX the resulting virtual width 1340 * virtualY the resulting virtual height 1341 * displayWidth the resulting line pitch 1342 * 1343 * The function's return value is the number of matching modes found, or -1 1344 * if an unrecoverable error was encountered. 1345 */ 1346 1347int 1348xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, 1349 char **modeNames, ClockRangePtr clockRanges, 1350 int *linePitches, int minPitch, int maxPitch, int pitchInc, 1351 int minHeight, int maxHeight, int virtualX, int virtualY, 1352 int apertureSize, LookupModeFlags strategy) 1353{ 1354 DisplayModePtr p, q, r, new, last, *endp; 1355 int i, numModes = 0; 1356 ModeStatus status; 1357 int linePitch = -1, virtX = 0, virtY = 0; 1358 int newLinePitch, newVirtX, newVirtY; 1359 int modeSize; /* in pixels */ 1360 Bool validateAllDefaultModes = FALSE; 1361 Bool userModes = FALSE; 1362 int saveType; 1363 PixmapFormatRec *BankFormat; 1364 ClockRangePtr cp; 1365 ClockRangePtr storeClockRanges; 1366 int numTimings = 0; 1367 range hsync[MAX_HSYNC]; 1368 range vrefresh[MAX_VREFRESH]; 1369 Bool inferred_virtual = FALSE; 1370 1371 DebugF("xf86ValidateModes(%p, %p, %p, %p,\n\t\t %p, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x)\n", 1372 scrp, availModes, modeNames, clockRanges, 1373 linePitches, minPitch, maxPitch, pitchInc, 1374 minHeight, maxHeight, virtualX, virtualY, 1375 apertureSize, strategy 1376 ); 1377 1378 /* Some sanity checking */ 1379 if (scrp == NULL || scrp->name == NULL || !scrp->monitor || 1380 (!scrp->progClock && scrp->numClocks == 0)) { 1381 ErrorF("xf86ValidateModes: called with invalid scrnInfoRec\n"); 1382 return -1; 1383 } 1384 if (linePitches != NULL && linePitches[0] <= 0) { 1385 ErrorF("xf86ValidateModes: called with invalid linePitches\n"); 1386 return -1; 1387 } 1388 if (pitchInc <= 0) { 1389 ErrorF("xf86ValidateModes: called with invalid pitchInc\n"); 1390 return -1; 1391 } 1392 if ((virtualX > 0) != (virtualY > 0)) { 1393 ErrorF("xf86ValidateModes: called with invalid virtual resolution\n"); 1394 return -1; 1395 } 1396 1397 /* 1398 * If requested by the driver, allow missing hsync and/or vrefresh ranges 1399 * in the monitor section. 1400 */ 1401 if (strategy & LOOKUP_OPTIONAL_TOLERANCES) { 1402 strategy &= ~LOOKUP_OPTIONAL_TOLERANCES; 1403 } else { 1404 const char *type = ""; 1405 1406 if (scrp->monitor->nHsync <= 0) { 1407 if (numTimings > 0) { 1408 scrp->monitor->nHsync = numTimings; 1409 for (i = 0; i < numTimings; i++) { 1410 scrp->monitor->hsync[i].lo = hsync[i].lo; 1411 scrp->monitor->hsync[i].hi = hsync[i].hi; 1412 } 1413 } else { 1414 scrp->monitor->hsync[0].lo = 31.5; 1415 scrp->monitor->hsync[0].hi = 37.9; 1416 scrp->monitor->nHsync = 1; 1417 } 1418 type = "default "; 1419 } 1420 for (i = 0; i < scrp->monitor->nHsync; i++) { 1421 if (scrp->monitor->hsync[i].lo == scrp->monitor->hsync[i].hi) 1422 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1423 "%s: Using %shsync value of %.2f kHz\n", 1424 scrp->monitor->id, type, 1425 scrp->monitor->hsync[i].lo); 1426 else 1427 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1428 "%s: Using %shsync range of %.2f-%.2f kHz\n", 1429 scrp->monitor->id, type, 1430 scrp->monitor->hsync[i].lo, 1431 scrp->monitor->hsync[i].hi); 1432 } 1433 1434 type = ""; 1435 if (scrp->monitor->nVrefresh <= 0) { 1436 if (numTimings > 0) { 1437 scrp->monitor->nVrefresh = numTimings; 1438 for (i = 0; i < numTimings; i++) { 1439 scrp->monitor->vrefresh[i].lo = vrefresh[i].lo; 1440 scrp->monitor->vrefresh[i].hi = vrefresh[i].hi; 1441 } 1442 } else { 1443 scrp->monitor->vrefresh[0].lo = 50; 1444 scrp->monitor->vrefresh[0].hi = 70; 1445 scrp->monitor->nVrefresh = 1; 1446 } 1447 type = "default "; 1448 } 1449 for (i = 0; i < scrp->monitor->nVrefresh; i++) { 1450 if (scrp->monitor->vrefresh[i].lo == scrp->monitor->vrefresh[i].hi) 1451 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1452 "%s: Using %svrefresh value of %.2f Hz\n", 1453 scrp->monitor->id, type, 1454 scrp->monitor->vrefresh[i].lo); 1455 else 1456 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1457 "%s: Using %svrefresh range of %.2f-%.2f Hz\n", 1458 scrp->monitor->id, type, 1459 scrp->monitor->vrefresh[i].lo, 1460 scrp->monitor->vrefresh[i].hi); 1461 } 1462 if (scrp->monitor->maxPixClock) { 1463 xf86DrvMsg(scrp->scrnIndex, X_INFO, 1464 "%s: Using maximum pixel clock of %.2f MHz\n", 1465 scrp->monitor->id, 1466 (float)scrp->monitor->maxPixClock / 1000.0); 1467 } 1468 } 1469 1470 /* 1471 * Store the clockRanges for later use by the VidMode extension. 1472 */ 1473 storeClockRanges = scrp->clockRanges; 1474 while (storeClockRanges != NULL) { 1475 storeClockRanges = storeClockRanges->next; 1476 } 1477 for (cp = clockRanges; cp != NULL; cp = cp->next, 1478 storeClockRanges = storeClockRanges->next) { 1479 storeClockRanges = xnfalloc(sizeof(ClockRange)); 1480 if (scrp->clockRanges == NULL) 1481 scrp->clockRanges = storeClockRanges; 1482 memcpy(storeClockRanges, cp, sizeof(ClockRange)); 1483 } 1484 1485 /* Determine which pixmap format to pass to scanLineWidth() */ 1486 if (scrp->depth > 4) 1487 BankFormat = &scrp->fbFormat; 1488 else 1489 BankFormat = xf86GetPixFormat(scrp, 1); /* >not< scrp->depth! */ 1490 1491 if (scrp->xInc <= 0) 1492 scrp->xInc = 8; /* Suitable for VGA and others */ 1493 1494#define _VIRTUALX(x) ((((x) + scrp->xInc - 1) / scrp->xInc) * scrp->xInc) 1495 1496 /* 1497 * Determine maxPitch if it wasn't given explicitly. Note linePitches 1498 * always takes precedence if is non-NULL. In that case the minPitch and 1499 * maxPitch values passed are ignored. 1500 */ 1501 if (linePitches) { 1502 minPitch = maxPitch = linePitches[0]; 1503 for (i = 1; linePitches[i] > 0; i++) { 1504 if (linePitches[i] > maxPitch) 1505 maxPitch = linePitches[i]; 1506 if (linePitches[i] < minPitch) 1507 minPitch = linePitches[i]; 1508 } 1509 } 1510 1511 /* Initial check of virtual size against other constraints */ 1512 scrp->virtualFrom = X_PROBED; 1513 /* 1514 * Initialise virtX and virtY if the values are fixed. 1515 */ 1516 if (virtualY > 0) { 1517 if (maxHeight > 0 && virtualY > maxHeight) { 1518 xf86DrvMsg(scrp->scrnIndex, X_ERROR, 1519 "Virtual height (%d) is too large for the hardware " 1520 "(max %d)\n", virtualY, maxHeight); 1521 return -1; 1522 } 1523 1524 if (minHeight > 0 && virtualY < minHeight) { 1525 xf86DrvMsg(scrp->scrnIndex, X_ERROR, 1526 "Virtual height (%d) is too small for the hardware " 1527 "(min %d)\n", virtualY, minHeight); 1528 return -1; 1529 } 1530 1531 virtualX = _VIRTUALX(virtualX); 1532 if (linePitches != NULL) { 1533 for (i = 0; linePitches[i] != 0; i++) { 1534 if ((linePitches[i] >= virtualX) && 1535 (linePitches[i] == 1536 scanLineWidth(virtualX, virtualY, linePitches[i], 1537 apertureSize, BankFormat, pitchInc))) { 1538 linePitch = linePitches[i]; 1539 break; 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 scrp->virtualFrom = X_CONFIG; 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 } else { 1600 q->next = new; 1601 } 1602 new->prev = NULL; 1603 q = new; 1604 q->name = xnfstrdup(p->name); 1605 q->status = MODE_OK; 1606 } else { 1607 printModeRejectMessage(scrp->scrnIndex, p, status); 1608 } 1609 } 1610 1611 if (scrp->modePool == NULL) { 1612 xf86DrvMsg(scrp->scrnIndex, X_WARNING, "Mode pool is empty\n"); 1613 return 0; 1614 } 1615 } else { 1616 for (p = scrp->modePool; p != NULL; p = p->next) { 1617 p->prev = NULL; 1618 p->status = MODE_OK; 1619 } 1620 } 1621 1622 /* 1623 * Allocate one entry in scrp->modes for each named mode. 1624 */ 1625 while (scrp->modes) 1626 xf86DeleteMode(&scrp->modes, scrp->modes); 1627 endp = &scrp->modes; 1628 last = NULL; 1629 if (modeNames != NULL) { 1630 for (i = 0; modeNames[i] != NULL; i++) { 1631 userModes = TRUE; 1632 new = xnfcalloc(1, sizeof(DisplayModeRec)); 1633 new->prev = last; 1634 new->type = M_T_USERDEF; 1635 new->name = xnfalloc(strlen(modeNames[i]) + 1); 1636 strcpy(new->name, modeNames[i]); 1637 if (new->prev) 1638 new->prev->next = new; 1639 *endp = last = new; 1640 endp = &new->next; 1641 } 1642 } 1643 1644 /* Lookup each mode */ 1645#ifdef RANDR 1646 if (!xf86Info.disableRandR 1647#ifdef PANORAMIX 1648 && noPanoramiXExtension 1649#endif 1650 ) 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) && 1678 !strcmp(p->name, q->name)) 1679 break; 1680 } 1681 1682 if (p != NULL) 1683 q->prev = p; 1684 else { 1685 /* 1686 * A quick check to not allow default modes with 1687 * horizontal timing parameters that CRTs may have 1688 * problems with. 1689 */ 1690 if (!scrp->monitor->reducedblanking && 1691 (q->type & M_T_DEFAULT) && 1692 ((double)q->HTotal / (double)q->HDisplay) < 1.15) 1693 continue; 1694 1695 if (modeSize < (q->HDisplay * q->VDisplay)) { 1696 r = q; 1697 modeSize = q->HDisplay * q->VDisplay; 1698 } 1699 } 1700 } 1701 } 1702 1703 if (r == NULL) 1704 break; 1705 1706 p = xnfcalloc(1, sizeof(DisplayModeRec)); 1707 p->prev = last; 1708 p->name = xnfalloc(strlen(r->name) + 1); 1709 if (!userModes) 1710 p->type = M_T_USERDEF; 1711 strcpy(p->name, r->name); 1712 if (p->prev) 1713 p->prev->next = p; 1714 *endp = last = p; 1715 endp = &p->next; 1716 } 1717 1718 repeat = FALSE; 1719 lookupNext: 1720 if (repeat && ((status = p->status) != MODE_OK)) 1721 printModeRejectMessage(scrp->scrnIndex, p, status); 1722 saveType = p->type; 1723 status = xf86LookupMode(scrp, p, clockRanges, strategy); 1724 if (repeat && status == MODE_NOMODE) 1725 continue; 1726 if (status != MODE_OK) 1727 printModeRejectMessage(scrp->scrnIndex, p, status); 1728 if (status == MODE_ERROR) { 1729 ErrorF("xf86ValidateModes: " 1730 "unexpected result from xf86LookupMode()\n"); 1731 return -1; 1732 } 1733 if (status != MODE_OK) { 1734 if (p->status == MODE_OK) 1735 p->status = status; 1736 continue; 1737 } 1738 p->type |= saveType; 1739 repeat = TRUE; 1740 1741 newLinePitch = linePitch; 1742 newVirtX = virtX; 1743 newVirtY = virtY; 1744 1745 /* 1746 * Don't let non-user defined modes increase the virtual size 1747 */ 1748 if (!(p->type & M_T_USERDEF) && (numModes > 0)) { 1749 if (p->HDisplay > virtX) { 1750 p->status = MODE_VIRTUAL_X; 1751 goto lookupNext; 1752 } 1753 if (p->VDisplay > virtY) { 1754 p->status = MODE_VIRTUAL_Y; 1755 goto lookupNext; 1756 } 1757 } 1758 /* 1759 * Adjust virtual width and height if the mode is too large for the 1760 * current values and if they are not fixed. 1761 */ 1762 if (virtualX <= 0 && p->HDisplay > newVirtX) 1763 newVirtX = _VIRTUALX(p->HDisplay); 1764 if (virtualY <= 0 && p->VDisplay > newVirtY) { 1765 if (maxHeight > 0 && p->VDisplay > maxHeight) { 1766 p->status = MODE_VIRTUAL_Y; /* ? */ 1767 goto lookupNext; 1768 } 1769 newVirtY = p->VDisplay; 1770 } 1771 1772 /* 1773 * If virtual resolution is to be increased, revalidate it. 1774 */ 1775 if ((virtX != newVirtX) || (virtY != newVirtY)) { 1776 if (linePitches != NULL) { 1777 newLinePitch = -1; 1778 for (i = 0; linePitches[i] != 0; i++) { 1779 if ((linePitches[i] >= newVirtX) && 1780 (linePitches[i] >= linePitch) && 1781 (linePitches[i] == 1782 scanLineWidth(newVirtX, newVirtY, linePitches[i], 1783 apertureSize, BankFormat, pitchInc))) { 1784 newLinePitch = linePitches[i]; 1785 break; 1786 } 1787 } 1788 } else { 1789 if (linePitch < minPitch) 1790 linePitch = minPitch; 1791 newLinePitch = scanLineWidth(newVirtX, newVirtY, linePitch, 1792 apertureSize, BankFormat, 1793 pitchInc); 1794 } 1795 if ((newLinePitch < minPitch) || (newLinePitch > maxPitch)) { 1796 p->status = MODE_BAD_WIDTH; 1797 goto lookupNext; 1798 } 1799 1800 /* 1801 * Check that the pixel area required by the new virtual height 1802 * and line pitch isn't too large. 1803 */ 1804 if (!xf86CheckModeSize(scrp, newLinePitch, newVirtX, newVirtY)) { 1805 p->status = MODE_MEM_VIRT; 1806 goto lookupNext; 1807 } 1808 } 1809 1810 if (scrp->ValidMode) { 1811 /* 1812 * Give the driver a final say, passing it the proposed virtual 1813 * geometry. 1814 */ 1815 scrp->virtualX = newVirtX; 1816 scrp->virtualY = newVirtY; 1817 scrp->displayWidth = newLinePitch; 1818 p->status = (scrp->ValidMode)(scrp->scrnIndex, p, FALSE, 1819 MODECHECK_FINAL); 1820 1821 if (p->status != MODE_OK) { 1822 goto lookupNext; 1823 } 1824 } 1825 1826 /* Mode has passed all the tests */ 1827 virtX = newVirtX; 1828 virtY = newVirtY; 1829 linePitch = newLinePitch; 1830 p->status = MODE_OK; 1831 numModes++; 1832 } 1833 1834 /* 1835 * If we estimated the virtual size above, we may have filtered away all 1836 * the modes that maximally match that size; scan again to find out and 1837 * fix up if so. 1838 */ 1839 if (inferred_virtual) { 1840 int vx = 0, vy = 0; 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 = sizeof(types) / sizeof(int); 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; vy = 0; 1867 for (p = scrp->modes; p; p = p->next) { 1868 /* scan through the modes in the sort order above */ 1869 if ((p->type & type) != type) 1870 continue; 1871 if (p->HDisplay > vx && p->VDisplay > vy) { 1872 vx = p->HDisplay; 1873 vy = p->VDisplay; 1874 } 1875 } 1876 if (vx && vy) 1877 /* Found one */ 1878 break; 1879 } 1880 xf86DrvMsg(scrp->scrnIndex, X_WARNING, 1881 "Shrinking virtual size estimate from %dx%d to %dx%d\n", 1882 virtX, virtY, vx, vy); 1883 virtX = _VIRTUALX(vx); 1884 virtY = vy; 1885 for (p = scrp->modes; p; p = p->next) { 1886 if (numModes > 0) { 1887 if (p->HDisplay > virtX) 1888 p->status = MODE_VIRTUAL_X; 1889 if (p->VDisplay > virtY) 1890 p->status = MODE_VIRTUAL_Y; 1891 if (p->status != MODE_OK) { 1892 numModes--; 1893 printModeRejectMessage(scrp->scrnIndex, p, p->status); 1894 } 1895 } 1896 } 1897 if (linePitches != NULL) { 1898 for (i = 0; linePitches[i] != 0; i++) { 1899 if ((linePitches[i] >= virtX) && 1900 (linePitches[i] == 1901 scanLineWidth(virtX, virtY, linePitches[i], 1902 apertureSize, BankFormat, pitchInc))) { 1903 linePitch = linePitches[i]; 1904 break; 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 1954void 1955xf86DeleteMode(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 } else { 1969 if ((mode->prev != NULL) && (mode->prev->next == mode)) 1970 mode->prev->next = mode->next; 1971 if ((mode->next != NULL) && (mode->next->prev == mode)) 1972 mode->next->prev = mode->prev; 1973 } 1974 1975 free(mode->name); 1976 free(mode); 1977} 1978 1979/* 1980 * xf86PruneDriverModes 1981 * 1982 * Remove modes from the driver's mode list which have been marked as 1983 * invalid. 1984 */ 1985 1986void 1987xf86PruneDriverModes(ScrnInfoPtr scrp) 1988{ 1989 DisplayModePtr first, p, n; 1990 1991 p = scrp->modes; 1992 if (p == NULL) 1993 return; 1994 1995 do { 1996 if (!(first = scrp->modes)) 1997 return; 1998 n = p->next; 1999 if (p->status != MODE_OK) { 2000 xf86DeleteMode(&(scrp->modes), p); 2001 } 2002 p = n; 2003 } while (p != NULL && p != first); 2004 2005 /* modePool is no longer needed, turf it */ 2006 while (scrp->modePool) { 2007 /* 2008 * A modePool mode's prev field is used to hold a pointer to the 2009 * member of the scrp->modes list for which a match was considered. 2010 * Clear that pointer first, otherwise xf86DeleteMode might get 2011 * confused 2012 */ 2013 scrp->modePool->prev = NULL; 2014 xf86DeleteMode(&scrp->modePool, scrp->modePool); 2015 } 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 */ 2026void 2027xf86SetCrtcForModes(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 2054void 2055xf86PrintModes(ScrnInfoPtr scrp) 2056{ 2057 DisplayModePtr p; 2058 float hsync, refresh = 0; 2059 char *desc, *desc2, *prefix, *uprefix; 2060 2061 if (scrp == NULL) 2062 return; 2063 2064 xf86DrvMsg(scrp->scrnIndex, scrp->virtualFrom, "Virtual size is %dx%d " 2065 "(pitch %d)\n", scrp->virtualX, scrp->virtualY, 2066 scrp->displayWidth); 2067 2068 p = scrp->modes; 2069 if (p == NULL) 2070 return; 2071 2072 do { 2073 desc = desc2 = ""; 2074 hsync = xf86ModeHSync(p); 2075 refresh = xf86ModeVRefresh(p); 2076 if (p->Flags & V_INTERLACE) { 2077 desc = " (I)"; 2078 } 2079 if (p->Flags & V_DBLSCAN) { 2080 desc = " (D)"; 2081 } 2082 if (p->VScan > 1) { 2083 desc2 = " (VScan)"; 2084 } 2085 if (p->type & M_T_BUILTIN) 2086 prefix = "Built-in mode"; 2087 else if (p->type & M_T_DEFAULT) 2088 prefix = "Default mode"; 2089 else if (p->type & M_T_DRIVER) 2090 prefix = "Driver mode"; 2091 else 2092 prefix = "Mode"; 2093 if (p->type & M_T_USERDEF) 2094 uprefix = "*"; 2095 else 2096 uprefix = " "; 2097 if (hsync == 0 || refresh == 0) { 2098 if (p->name) 2099 xf86DrvMsg(scrp->scrnIndex, X_CONFIG, 2100 "%s%s \"%s\"\n", uprefix, prefix, p->name); 2101 else 2102 xf86DrvMsg(scrp->scrnIndex, X_PROBED, 2103 "%s%s %dx%d (unnamed)\n", 2104 uprefix, prefix, p->HDisplay, p->VDisplay); 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 } else { 2111 xf86DrvMsg(scrp->scrnIndex, X_CONFIG, 2112 "%s%s \"%s\": %.1f MHz (scaled from %.1f MHz), " 2113 "%.1f kHz, %.1f Hz%s%s\n", 2114 uprefix, prefix, p->name, p->Clock / 1000.0, 2115 p->SynthClock / 1000.0, hsync, refresh, desc, desc2); 2116 } 2117 if (hsync != 0 && refresh != 0) 2118 xf86PrintModeline(scrp->scrnIndex,p); 2119 p = p->next; 2120 } while (p != NULL && p != scrp->modes); 2121} 2122