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