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