Commit | Line | Data |
---|---|---|
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 | ||
39 | extern XF86ConfigPtr xf86configptr; | |
40 | ||
41 | /** | |
42 | * Calculates the horizontal sync rate of a mode. | |
43 | */ | |
44 | double | |
45 | xf86ModeHSync(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 | */ | |
60 | double | |
61 | xf86ModeVRefresh(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 | ||
79 | int | |
80 | xf86ModeWidth(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 | ||
94 | int | |
95 | xf86ModeHeight(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. */ | |
110 | unsigned int | |
111 | xf86ModeBandwidth(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. */ | |
128 | void | |
129 | xf86SetModeDefaultName(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 | */ | |
145 | void | |
146 | xf86SetModeCrtc(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 | */ | |
197 | void | |
198 | xf86SaveModeContents(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 | */ | |
211 | DisplayModePtr | |
212 | xf86DuplicateMode(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 | */ | |
235 | DisplayModePtr | |
236 | xf86DuplicateModes(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 | */ | |
268 | Bool | |
269 | xf86ModesEqual(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 | ||
289 | static void | |
290 | add(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 | */ | |
322 | void | |
323 | xf86PrintModeline(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 | */ | |
400 | void | |
401 | xf86ValidateModesFlags(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 | */ | |
421 | void | |
422 | xf86ValidateModesSize(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 | */ | |
465 | void | |
466 | xf86ValidateModesSync(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 | */ | |
510 | void | |
511 | xf86ValidateModesClocks(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 | */ | |
544 | void | |
545 | xf86ValidateModesUserConfig(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 | */ | |
575 | void | |
576 | xf86ValidateModesBandwidth(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 | ||
587 | Bool | |
588 | xf86ModeIsReduced(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 | */ | |
604 | void | |
605 | xf86ValidateModesReducedBlanking(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 | */ | |
619 | void | |
620 | xf86PruneInvalidModes(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 | */ | |
654 | DisplayModePtr | |
655 | xf86ModesAdd(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 | */ | |
676 | static DisplayModePtr | |
677 | xf86GetConfigModes(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 | */ | |
718 | DisplayModePtr | |
719 | xf86GetMonitorModes(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 | */ | |
749 | DisplayModePtr | |
750 | xf86GetDefaultModes(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 | ||
775 | DisplayModePtr | |
776 | xf86PruneDuplicateModes(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 | } |