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