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