xf86Modes.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#ifdef HAVE_XORG_CONFIG_H 29#include <xorg-config.h> 30#else 31#ifdef HAVE_CONFIG_H 32#include <config.h> 33#endif 34#endif 35 36#include "xf86Modes.h" 37#include "xf86Priv.h" 38 39extern XF86ConfigPtr xf86configptr; 40 41/* 42 * This is the version number where we epoched. These files get copied 43 * into drivers that want to use this setup infrastructure on pre-1.3 44 * servers, so when that happens they need to define these symbols 45 * themselves. However, _in_ the server, we basically always define them now. 46 */ 47#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0) 48 49/** 50 * Calculates the horizontal sync rate of a mode. 51 */ 52double 53xf86ModeHSync(const DisplayModeRec *mode) 54{ 55 double hsync = 0.0; 56 57 if (mode->HSync > 0.0) 58 hsync = mode->HSync; 59 else if (mode->HTotal > 0) 60 hsync = (float)mode->Clock / (float)mode->HTotal; 61 62 return hsync; 63} 64 65/** 66 * Calculates the vertical refresh rate of a mode. 67 */ 68double 69xf86ModeVRefresh(const DisplayModeRec *mode) 70{ 71 double refresh = 0.0; 72 73 if (mode->VRefresh > 0.0) 74 refresh = mode->VRefresh; 75 else if (mode->HTotal > 0 && mode->VTotal > 0) { 76 refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal; 77 if (mode->Flags & V_INTERLACE) 78 refresh *= 2.0; 79 if (mode->Flags & V_DBLSCAN) 80 refresh /= 2.0; 81 if (mode->VScan > 1) 82 refresh /= (float)(mode->VScan); 83 } 84 return refresh; 85} 86 87int 88xf86ModeWidth (const DisplayModeRec *mode, Rotation rotation) 89{ 90 switch (rotation & 0xf) { 91 case RR_Rotate_0: 92 case RR_Rotate_180: 93 return mode->HDisplay; 94 case RR_Rotate_90: 95 case RR_Rotate_270: 96 return mode->VDisplay; 97 default: 98 return 0; 99 } 100} 101 102int 103xf86ModeHeight (const DisplayModeRec *mode, Rotation rotation) 104{ 105 switch (rotation & 0xf) { 106 case RR_Rotate_0: 107 case RR_Rotate_180: 108 return mode->VDisplay; 109 case RR_Rotate_90: 110 case RR_Rotate_270: 111 return mode->HDisplay; 112 default: 113 return 0; 114 } 115} 116 117/** Calculates the memory bandwidth (in MiB/sec) of a mode. */ 118unsigned int 119xf86ModeBandwidth(DisplayModePtr mode, int depth) 120{ 121 float a_active, a_total, active_percent, pixels_per_second; 122 int bytes_per_pixel = bits_to_bytes(depth); 123 124 if (!mode->HTotal || !mode->VTotal || !mode->Clock) 125 return 0; 126 127 a_active = mode->HDisplay * mode->VDisplay; 128 a_total = mode->HTotal * mode->VTotal; 129 active_percent = a_active / a_total; 130 pixels_per_second = active_percent * mode->Clock * 1000.0; 131 132 return (unsigned int)(pixels_per_second * bytes_per_pixel / (1024 * 1024)); 133} 134 135/** Sets a default mode name of <width>x<height> on a mode. */ 136void 137xf86SetModeDefaultName(DisplayModePtr mode) 138{ 139 Bool interlaced = !!(mode->Flags & V_INTERLACE); 140 141 free(mode->name); 142 143 mode->name = XNFprintf("%dx%d%s", mode->HDisplay, mode->VDisplay, 144 interlaced ? "i" : ""); 145} 146 147/* 148 * xf86SetModeCrtc 149 * 150 * Initialises the Crtc parameters for a mode. The initialisation includes 151 * adjustments for interlaced and double scan modes. 152 */ 153void 154xf86SetModeCrtc(DisplayModePtr p, int adjustFlags) 155{ 156 if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN)) 157 return; 158 159 p->CrtcHDisplay = p->HDisplay; 160 p->CrtcHSyncStart = p->HSyncStart; 161 p->CrtcHSyncEnd = p->HSyncEnd; 162 p->CrtcHTotal = p->HTotal; 163 p->CrtcHSkew = p->HSkew; 164 p->CrtcVDisplay = p->VDisplay; 165 p->CrtcVSyncStart = p->VSyncStart; 166 p->CrtcVSyncEnd = p->VSyncEnd; 167 p->CrtcVTotal = p->VTotal; 168 if (p->Flags & V_INTERLACE) { 169 if (adjustFlags & INTERLACE_HALVE_V) { 170 p->CrtcVDisplay /= 2; 171 p->CrtcVSyncStart /= 2; 172 p->CrtcVSyncEnd /= 2; 173 p->CrtcVTotal /= 2; 174 } 175 /* Force interlaced modes to have an odd VTotal */ 176 /* maybe we should only do this when INTERLACE_HALVE_V is set? */ 177 p->CrtcVTotal |= 1; 178 } 179 180 if (p->Flags & V_DBLSCAN) { 181 p->CrtcVDisplay *= 2; 182 p->CrtcVSyncStart *= 2; 183 p->CrtcVSyncEnd *= 2; 184 p->CrtcVTotal *= 2; 185 } 186 if (p->VScan > 1) { 187 p->CrtcVDisplay *= p->VScan; 188 p->CrtcVSyncStart *= p->VScan; 189 p->CrtcVSyncEnd *= p->VScan; 190 p->CrtcVTotal *= p->VScan; 191 } 192 p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay); 193 p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal); 194 p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay); 195 p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal); 196 197 p->CrtcHAdjusted = FALSE; 198 p->CrtcVAdjusted = FALSE; 199} 200 201/** 202 * Allocates and returns a copy of pMode, including pointers within pMode. 203 */ 204DisplayModePtr 205xf86DuplicateMode(const DisplayModeRec *pMode) 206{ 207 DisplayModePtr pNew; 208 209 pNew = xnfalloc(sizeof(DisplayModeRec)); 210 *pNew = *pMode; 211 pNew->next = NULL; 212 pNew->prev = NULL; 213 214 if (pMode->name == NULL) 215 xf86SetModeDefaultName(pNew); 216 else 217 pNew->name = xnfstrdup(pMode->name); 218 219 return pNew; 220} 221 222/** 223 * Duplicates every mode in the given list and returns a pointer to the first 224 * mode. 225 * 226 * \param modeList doubly-linked mode list 227 */ 228DisplayModePtr 229xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList) 230{ 231 DisplayModePtr first = NULL, last = NULL; 232 DisplayModePtr mode; 233 234 for (mode = modeList; mode != NULL; mode = mode->next) { 235 DisplayModePtr new; 236 237 new = xf86DuplicateMode(mode); 238 239 /* Insert pNew into modeList */ 240 if (last) { 241 last->next = new; 242 new->prev = last; 243 } else { 244 first = new; 245 new->prev = NULL; 246 } 247 new->next = NULL; 248 last = new; 249 } 250 251 return first; 252} 253 254/** 255 * Returns true if the given modes should program to the same timings. 256 * 257 * This doesn't use Crtc values, as it might be used on ModeRecs without the 258 * Crtc values set. So, it's assumed that the other numbers are enough. 259 */ 260Bool 261xf86ModesEqual(const DisplayModeRec *pMode1, const DisplayModeRec *pMode2) 262{ 263 if (pMode1->Clock == pMode2->Clock && 264 pMode1->HDisplay == pMode2->HDisplay && 265 pMode1->HSyncStart == pMode2->HSyncStart && 266 pMode1->HSyncEnd == pMode2->HSyncEnd && 267 pMode1->HTotal == pMode2->HTotal && 268 pMode1->HSkew == pMode2->HSkew && 269 pMode1->VDisplay == pMode2->VDisplay && 270 pMode1->VSyncStart == pMode2->VSyncStart && 271 pMode1->VSyncEnd == pMode2->VSyncEnd && 272 pMode1->VTotal == pMode2->VTotal && 273 pMode1->VScan == pMode2->VScan && 274 pMode1->Flags == pMode2->Flags) 275 { 276 return TRUE; 277 } else { 278 return FALSE; 279 } 280} 281 282static void 283add(char **p, char *new) 284{ 285 *p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2); 286 strcat(*p, " "); 287 strcat(*p, new); 288} 289 290/** 291 * Print out a modeline. 292 */ 293void 294xf86PrintModeline(int scrnIndex,DisplayModePtr mode) 295{ 296 char tmp[256]; 297 char *flags = xnfcalloc(1, 1); 298 299 if (mode->HSkew) { 300 snprintf(tmp, 256, "hskew %i", mode->HSkew); 301 add(&flags, tmp); 302 } 303 if (mode->VScan) { 304 snprintf(tmp, 256, "vscan %i", mode->VScan); 305 add(&flags, tmp); 306 } 307 if (mode->Flags & V_INTERLACE) add(&flags, "interlace"); 308 if (mode->Flags & V_CSYNC) add(&flags, "composite"); 309 if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan"); 310 if (mode->Flags & V_BCAST) add(&flags, "bcast"); 311 if (mode->Flags & V_PHSYNC) add(&flags, "+hsync"); 312 if (mode->Flags & V_NHSYNC) add(&flags, "-hsync"); 313 if (mode->Flags & V_PVSYNC) add(&flags, "+vsync"); 314 if (mode->Flags & V_NVSYNC) add(&flags, "-vsync"); 315 if (mode->Flags & V_PCSYNC) add(&flags, "+csync"); 316 if (mode->Flags & V_NCSYNC) add(&flags, "-csync"); 317#if 0 318 if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2"); 319#endif 320 xf86DrvMsg(scrnIndex, X_INFO, 321 "Modeline \"%s\"x%.01f %6.2f %i %i %i %i %i %i %i %i%s " 322 "(%.01f kHz)\n", 323 mode->name, mode->VRefresh, mode->Clock/1000., mode->HDisplay, 324 mode->HSyncStart, mode->HSyncEnd, mode->HTotal, 325 mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, 326 mode->VTotal, flags, xf86ModeHSync(mode)); 327 free(flags); 328} 329#endif /* XORG_VERSION_CURRENT <= 7.2.99.2 */ 330 331/** 332 * Marks as bad any modes with unsupported flags. 333 * 334 * \param modeList doubly-linked list of modes. 335 * \param flags flags supported by the driver. 336 * 337 * \bug only V_INTERLACE and V_DBLSCAN are supported. Is that enough? 338 */ 339void 340xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, 341 int flags) 342{ 343 DisplayModePtr mode; 344 345 if (flags == (V_INTERLACE | V_DBLSCAN)) 346 return; 347 348 for (mode = modeList; mode != NULL; mode = mode->next) { 349 if (mode->Flags & V_INTERLACE && !(flags & V_INTERLACE)) 350 mode->status = MODE_NO_INTERLACE; 351 if (mode->Flags & V_DBLSCAN && !(flags & V_DBLSCAN)) 352 mode->status = MODE_NO_DBLESCAN; 353 } 354} 355 356/** 357 * Marks as bad any modes extending beyond the given max X, Y, or pitch. 358 * 359 * \param modeList doubly-linked list of modes. 360 */ 361void 362xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList, 363 int maxX, int maxY, int maxPitch) 364{ 365 DisplayModePtr mode; 366 367 if (maxPitch <= 0) 368 maxPitch = MAXINT; 369 if (maxX <= 0) 370 maxX = MAXINT; 371 if (maxY <= 0) 372 maxY = MAXINT; 373 374 for (mode = modeList; mode != NULL; mode = mode->next) { 375 if ((xf86ModeWidth(mode, RR_Rotate_0) > maxPitch || 376 xf86ModeWidth(mode, RR_Rotate_0) > maxX || 377 xf86ModeHeight(mode, RR_Rotate_0) > maxY) && 378 (xf86ModeWidth(mode, RR_Rotate_90) > maxPitch || 379 xf86ModeWidth(mode, RR_Rotate_90) > maxX || 380 xf86ModeHeight(mode, RR_Rotate_90) > maxY)) { 381 if (xf86ModeWidth(mode, RR_Rotate_0) > maxPitch || 382 xf86ModeWidth(mode, RR_Rotate_90) > maxPitch) 383 mode->status = MODE_BAD_WIDTH; 384 385 if (xf86ModeWidth(mode, RR_Rotate_0) > maxX || 386 xf86ModeWidth(mode, RR_Rotate_90) > maxX) 387 mode->status = MODE_VIRTUAL_X; 388 389 if (xf86ModeHeight(mode, RR_Rotate_0) > maxY || 390 xf86ModeHeight(mode, RR_Rotate_90) > maxY) 391 mode->status = MODE_VIRTUAL_Y; 392 } 393 394 if (mode->next == modeList) 395 break; 396 } 397} 398 399/** 400 * Marks as bad any modes that aren't supported by the given monitor's 401 * hsync and vrefresh ranges. 402 * 403 * \param modeList doubly-linked list of modes. 404 */ 405void 406xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList, 407 MonPtr mon) 408{ 409 DisplayModePtr mode; 410 411 for (mode = modeList; mode != NULL; mode = mode->next) { 412 Bool bad; 413 int i; 414 415 bad = TRUE; 416 for (i = 0; i < mon->nHsync; i++) { 417 if (xf86ModeHSync(mode) >= mon->hsync[i].lo * (1-SYNC_TOLERANCE) && 418 xf86ModeHSync(mode) <= mon->hsync[i].hi * (1+SYNC_TOLERANCE)) 419 { 420 bad = FALSE; 421 } 422 } 423 if (bad) 424 mode->status = MODE_HSYNC; 425 426 bad = TRUE; 427 for (i = 0; i < mon->nVrefresh; i++) { 428 if (xf86ModeVRefresh(mode) >= mon->vrefresh[i].lo * (1-SYNC_TOLERANCE) && 429 xf86ModeVRefresh(mode) <= mon->vrefresh[i].hi * (1+SYNC_TOLERANCE)) 430 { 431 bad = FALSE; 432 } 433 } 434 if (bad) 435 mode->status = MODE_VSYNC; 436 437 if (mode->next == modeList) 438 break; 439 } 440} 441 442/** 443 * Marks as bad any modes extending beyond outside of the given clock ranges. 444 * 445 * \param modeList doubly-linked list of modes. 446 * \param min pointer to minimums of clock ranges 447 * \param max pointer to maximums of clock ranges 448 * \param n_ranges number of ranges. 449 */ 450void 451xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList, 452 int *min, int *max, int n_ranges) 453{ 454 DisplayModePtr mode; 455 int i; 456 457 for (mode = modeList; mode != NULL; mode = mode->next) { 458 Bool good = FALSE; 459 for (i = 0; i < n_ranges; i++) { 460 if (mode->Clock >= min[i] * (1-SYNC_TOLERANCE) && 461 mode->Clock <= max[i] * (1+SYNC_TOLERANCE)) { 462 good = TRUE; 463 break; 464 } 465 } 466 if (!good) 467 mode->status = MODE_CLOCK_RANGE; 468 } 469} 470 471/** 472 * If the user has specified a set of mode names to use, mark as bad any modes 473 * not listed. 474 * 475 * The user mode names specified are prefixes to names of modes, so "1024x768" 476 * will match modes named "1024x768", "1024x768x75", "1024x768-good", but 477 * "1024x768x75" would only match "1024x768x75" from that list. 478 * 479 * MODE_BAD is used as the rejection flag, for lack of a better flag. 480 * 481 * \param modeList doubly-linked list of modes. 482 */ 483void 484xf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList) 485{ 486 DisplayModePtr mode; 487 488 if (pScrn->display->modes[0] == NULL) 489 return; 490 491 for (mode = modeList; mode != NULL; mode = mode->next) { 492 int i; 493 Bool good = FALSE; 494 495 for (i = 0; pScrn->display->modes[i] != NULL; i++) { 496 if (strncmp(pScrn->display->modes[i], mode->name, 497 strlen(pScrn->display->modes[i])) == 0) { 498 good = TRUE; 499 break; 500 } 501 } 502 if (!good) 503 mode->status = MODE_BAD; 504 } 505} 506 507 508/** 509 * Marks as bad any modes exceeding the given bandwidth. 510 * 511 * \param modeList doubly-linked list of modes. 512 * \param bandwidth bandwidth in MHz. 513 * \param depth color depth. 514 */ 515void 516xf86ValidateModesBandwidth(ScrnInfoPtr pScrn, DisplayModePtr modeList, 517 unsigned int bandwidth, int depth) 518{ 519 DisplayModePtr mode; 520 521 for (mode = modeList; mode != NULL; mode = mode->next) { 522 if (xf86ModeBandwidth(mode, depth) > bandwidth) 523#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) 524 mode->status = MODE_BANDWIDTH; 525#else 526 /* MODE_BANDWIDTH didn't exist in xserver 1.2 */ 527 mode->status = MODE_BAD; 528#endif 529 } 530} 531 532Bool 533xf86ModeIsReduced(const DisplayModeRec *mode) 534{ 535 if ((((mode->HDisplay * 5 / 4) & ~0x07) > mode->HTotal) && 536 ((mode->HTotal - mode->HDisplay) == 160) && 537 ((mode->HSyncEnd - mode->HDisplay) == 80) && 538 ((mode->HSyncEnd - mode->HSyncStart) == 32) && 539 ((mode->VSyncStart - mode->VDisplay) == 3)) 540 return TRUE; 541 return FALSE; 542} 543 544/** 545 * Marks as bad any reduced-blanking modes. 546 * 547 * \param modeList doubly-linked list of modes. 548 */ 549void 550xf86ValidateModesReducedBlanking(ScrnInfoPtr pScrn, DisplayModePtr modeList) 551{ 552 for (; modeList != NULL; modeList = modeList->next) 553 if (xf86ModeIsReduced(modeList)) 554 modeList->status = MODE_NO_REDUCED; 555} 556 557/** 558 * Frees any modes from the list with a status other than MODE_OK. 559 * 560 * \param modeList pointer to a doubly-linked or circular list of modes. 561 * \param verbose determines whether the reason for mode invalidation is 562 * printed. 563 */ 564void 565xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, 566 Bool verbose) 567{ 568 DisplayModePtr mode; 569 570 for (mode = *modeList; mode != NULL;) { 571 DisplayModePtr next = mode->next, first = *modeList; 572 573 if (mode->status != MODE_OK) { 574 if (verbose) { 575 char *type = ""; 576 if (mode->type & M_T_BUILTIN) 577 type = "built-in "; 578 else if (mode->type & M_T_DEFAULT) 579 type = "default "; 580 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 581 "Not using %smode \"%s\" (%s)\n", type, mode->name, 582 xf86ModeStatusToString(mode->status)); 583 } 584 xf86DeleteMode(modeList, mode); 585 } 586 587 if (next == first) 588 break; 589 mode = next; 590 } 591} 592 593/** 594 * Adds the new mode into the mode list, and returns the new list 595 * 596 * \param modes doubly-linked mode list. 597 */ 598DisplayModePtr 599xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new) 600{ 601 if (modes == NULL) 602 return new; 603 604 if (new) { 605 DisplayModePtr mode = modes; 606 607 while (mode->next) 608 mode = mode->next; 609 610 mode->next = new; 611 new->prev = mode; 612 } 613 614 return modes; 615} 616 617/** 618 * Build a mode list from a list of config file modes 619 */ 620static DisplayModePtr 621xf86GetConfigModes (XF86ConfModeLinePtr conf_mode) 622{ 623 DisplayModePtr head = NULL, prev = NULL, mode; 624 625 for (; conf_mode; conf_mode = (XF86ConfModeLinePtr) conf_mode->list.next) 626 { 627 mode = calloc(1, sizeof(DisplayModeRec)); 628 if (!mode) 629 continue; 630 mode->name = xstrdup(conf_mode->ml_identifier); 631 if (!mode->name) 632 { 633 free(mode); 634 continue; 635 } 636 mode->type = 0; 637 mode->Clock = conf_mode->ml_clock; 638 mode->HDisplay = conf_mode->ml_hdisplay; 639 mode->HSyncStart = conf_mode->ml_hsyncstart; 640 mode->HSyncEnd = conf_mode->ml_hsyncend; 641 mode->HTotal = conf_mode->ml_htotal; 642 mode->VDisplay = conf_mode->ml_vdisplay; 643 mode->VSyncStart = conf_mode->ml_vsyncstart; 644 mode->VSyncEnd = conf_mode->ml_vsyncend; 645 mode->VTotal = conf_mode->ml_vtotal; 646 mode->Flags = conf_mode->ml_flags; 647 mode->HSkew = conf_mode->ml_hskew; 648 mode->VScan = conf_mode->ml_vscan; 649 650 mode->prev = prev; 651 mode->next = NULL; 652 if (prev) 653 prev->next = mode; 654 else 655 head = mode; 656 prev = mode; 657 } 658 return head; 659} 660 661/** 662 * Build a mode list from a monitor configuration 663 */ 664DisplayModePtr 665xf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor) 666{ 667 DisplayModePtr modes = NULL; 668 XF86ConfModesLinkPtr modes_link; 669 670 if (!conf_monitor) 671 return NULL; 672 673 /* 674 * first we collect the mode lines from the UseModes directive 675 */ 676 for (modes_link = conf_monitor->mon_modes_sect_lst; 677 modes_link; 678 modes_link = modes_link->list.next) 679 { 680 /* If this modes link hasn't been resolved, go look it up now */ 681 if (!modes_link->ml_modes) 682 modes_link->ml_modes = xf86findModes (modes_link->ml_modes_str, 683 xf86configptr->conf_modes_lst); 684 if (modes_link->ml_modes) 685 modes = xf86ModesAdd (modes, 686 xf86GetConfigModes (modes_link->ml_modes->mon_modeline_lst)); 687 } 688 689 return xf86ModesAdd (modes, 690 xf86GetConfigModes (conf_monitor->mon_modeline_lst)); 691} 692 693/** 694 * Build a mode list containing all of the default modes 695 */ 696DisplayModePtr 697xf86GetDefaultModes (void) 698{ 699 DisplayModePtr head = NULL, mode; 700 int i; 701 702 for (i = 0; i < xf86NumDefaultModes; i++) 703 { 704 const DisplayModeRec *defMode = &xf86DefaultModes[i]; 705 706 mode = xf86DuplicateMode(defMode); 707 head = xf86ModesAdd(head, mode); 708 } 709 return head; 710} 711 712/* 713 * Walk a mode list and prune out duplicates. Will preserve the preferred 714 * mode of an otherwise-duplicate pair. 715 * 716 * Probably best to call this on lists that are all of a single class 717 * (driver, default, user, etc.), otherwise, which mode gets deleted is 718 * not especially well defined. 719 * 720 * Returns the new list. 721 */ 722 723DisplayModePtr 724xf86PruneDuplicateModes(DisplayModePtr modes) 725{ 726 DisplayModePtr m, n, o; 727 728top: 729 for (m = modes; m; m = m->next) { 730 for (n = m->next; n; n = o) { 731 o = n->next; 732 if (xf86ModesEqual(m, n)) { 733 if (n->type & M_T_PREFERRED) { 734 xf86DeleteMode(&modes, m); 735 goto top; 736 } 737 else 738 xf86DeleteMode(&modes, n); 739 } 740 } 741 } 742 743 return modes; 744} 745