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