xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

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 }