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
xf86ModeHSync(const DisplayModeRec * mode)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
xf86ModeVRefresh(const DisplayModeRec * mode)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
xf86ModeWidth(const DisplayModeRec * mode,Rotation rotation)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
xf86ModeHeight(const DisplayModeRec * mode,Rotation rotation)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
xf86ModeBandwidth(DisplayModePtr mode,int depth)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
xf86SetModeDefaultName(DisplayModePtr mode)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
xf86SetModeCrtc(DisplayModePtr p,int adjustFlags)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
xf86SaveModeContents(DisplayModePtr intern,const DisplayModeRec * mode)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
xf86DuplicateMode(const DisplayModeRec * pMode)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
xf86DuplicateModes(ScrnInfoPtr pScrn,DisplayModePtr modeList)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
xf86ModesEqual(const DisplayModeRec * pMode1,const DisplayModeRec * pMode2)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
add(char ** p,const char * new)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
xf86PrintModeline(int scrnIndex,DisplayModePtr mode)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
xf86ValidateModesFlags(ScrnInfoPtr pScrn,DisplayModePtr modeList,int flags)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
xf86ValidateModesSize(ScrnInfoPtr pScrn,DisplayModePtr modeList,int maxX,int maxY,int maxPitch)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
xf86ValidateModesSync(ScrnInfoPtr pScrn,DisplayModePtr modeList,MonPtr mon)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
xf86ValidateModesClocks(ScrnInfoPtr pScrn,DisplayModePtr modeList,int * min,int * max,int n_ranges)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
xf86ValidateModesUserConfig(ScrnInfoPtr pScrn,DisplayModePtr modeList)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
xf86ValidateModesBandwidth(ScrnInfoPtr pScrn,DisplayModePtr modeList,unsigned int bandwidth,int depth)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
xf86ModeIsReduced(const DisplayModeRec * mode)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
xf86ValidateModesReducedBlanking(ScrnInfoPtr pScrn,DisplayModePtr modeList)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
xf86PruneInvalidModes(ScrnInfoPtr pScrn,DisplayModePtr * modeList,Bool verbose)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
xf86ModesAdd(DisplayModePtr modes,DisplayModePtr new)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
xf86GetConfigModes(XF86ConfModeLinePtr conf_mode)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
xf86GetMonitorModes(ScrnInfoPtr pScrn,XF86ConfMonitorPtr conf_monitor)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
xf86GetDefaultModes(void)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
xf86PruneDuplicateModes(DisplayModePtr modes)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
xf86CVTMode(int HDisplay,int VDisplay,float VRefresh,Bool Reduced,Bool Interlaced)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 char *tmp;
807
808 libxcvt_mode_info =
809 libxcvt_gen_mode_info(HDisplay, VDisplay, VRefresh, Reduced, Interlaced);
810
811 XNFasprintf(&tmp, "%dx%d", HDisplay, VDisplay);
812 Mode->name = tmp;
813
814 Mode->VDisplay = libxcvt_mode_info->vdisplay;
815 Mode->HDisplay = libxcvt_mode_info->hdisplay;
816 Mode->Clock = libxcvt_mode_info->dot_clock;
817 Mode->HSyncStart = libxcvt_mode_info->hsync_start;
818 Mode->HSyncEnd = libxcvt_mode_info->hsync_end;
819 Mode->HTotal = libxcvt_mode_info->htotal;
820 Mode->VSyncStart = libxcvt_mode_info->vsync_start;
821 Mode->VSyncEnd = libxcvt_mode_info->vsync_end;
822 Mode->VTotal = libxcvt_mode_info->vtotal;
823 Mode->VRefresh = libxcvt_mode_info->vrefresh;
824 Mode->Flags = libxcvt_mode_info->mode_flags;
825
826 free(libxcvt_mode_info);
827
828 return Mode;
829 }
830