Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / common / xf86Mode.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/*
29 * LCM() and scanLineWidth() are:
30 *
31 * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
32 *
33 * Permission to use, copy, modify, distribute, and sell this software and its
34 * documentation for any purpose is hereby granted without fee, provided that
35 * the above copyright notice appear in all copies and that both that copyright
36 * notice and this permission notice appear in supporting documentation, and
37 * that the name of Marc Aurele La France not be used in advertising or
38 * publicity pertaining to distribution of the software without specific,
39 * written prior permission. Marc Aurele La France makes no representations
40 * about the suitability of this software for any purpose. It is provided
41 * "as-is" without express or implied warranty.
42 *
43 * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
44 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
45 * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
46 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
47 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
48 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
49 * PERFORMANCE OF THIS SOFTWARE.
50 *
51 * Copyright 1990,91,92,93 by Thomas Roell, Germany.
52 * Copyright 1991,92,93 by SGCS (Snitily Graphics Consulting Services), USA.
53 *
54 * Permission to use, copy, modify, distribute, and sell this software
55 * and its documentation for any purpose is hereby granted without fee,
56 * provided that the above copyright notice appear in all copies and
57 * that both that copyright notice and this permission notice appear
58 * in supporting documentation, and that the name of Thomas Roell nor
59 * SGCS be used in advertising or publicity pertaining to distribution
60 * of the software without specific, written prior permission.
61 * Thomas Roell nor SGCS makes no representations about the suitability
62 * of this software for any purpose. It is provided "as is" without
63 * express or implied warranty.
64 *
65 * THOMAS ROELL AND SGCS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
66 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
67 * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR SGCS BE LIABLE FOR ANY
68 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
69 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
70 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
71 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
72 */
73
74/*
75 * Authors: Dirk Hohndel <hohndel@XFree86.Org>
76 * David Dawes <dawes@XFree86.Org>
77 * Marc La France <tsi@XFree86.Org>
78 * ... and others
79 *
80 * This file includes helper functions for mode related things.
81 */
82
83#ifdef HAVE_XORG_CONFIG_H
84#include <xorg-config.h>
85#endif
86
87#include <X11/X.h>
88#include "xf86Modes.h"
89#include "os.h"
90#include "servermd.h"
91#include "globals.h"
92#include "xf86.h"
93#include "xf86Priv.h"
94#include "edid.h"
95
96static void
97printModeRejectMessage(int index, DisplayModePtr p, int status)
98{
99 const char *type;
100
101 if (p->type & M_T_BUILTIN)
102 type = "built-in ";
103 else if (p->type & M_T_DEFAULT)
104 type = "default ";
105 else if (p->type & M_T_DRIVER)
106 type = "driver ";
107 else
108 type = "";
109
110 xf86DrvMsg(index, X_INFO, "Not using %smode \"%s\" (%s)\n", type, p->name,
111 xf86ModeStatusToString(status));
112}
113
114/*
115 * xf86GetNearestClock --
116 * Find closest clock to given frequency (in kHz). This assumes the
117 * number of clocks is greater than zero.
118 */
119int
120xf86GetNearestClock(ScrnInfoPtr scrp, int freq, Bool allowDiv2,
121 int DivFactor, int MulFactor, int *divider)
122{
123 int nearestClock = 0, nearestDiv = 1;
124 int minimumGap = abs(freq - scrp->clock[0]);
125 int i, j, k, gap;
126
127 if (allowDiv2)
128 k = 2;
129 else
130 k = 1;
131
132 /* Must set this here in case the best match is scrp->clock[0] */
133 if (divider != NULL)
134 *divider = 0;
135
136 for (i = 0; i < scrp->numClocks; i++) {
137 for (j = 1; j <= k; j++) {
138 gap = abs((freq * j) - ((scrp->clock[i] * DivFactor) / MulFactor));
139 if ((gap < minimumGap) || ((gap == minimumGap) && (j < nearestDiv))) {
140 minimumGap = gap;
141 nearestClock = i;
142 nearestDiv = j;
143 if (divider != NULL)
144 *divider = (j - 1) * V_CLKDIV2;
145 }
146 }
147 }
148 return nearestClock;
149}
150
151/*
152 * xf86ModeStatusToString
153 *
154 * Convert a ModeStatus value to a printable message
155 */
156
157const char *
158xf86ModeStatusToString(ModeStatus status)
159{
160 switch (status) {
161 case MODE_OK:
162 return "Mode OK";
163 case MODE_HSYNC:
164 return "hsync out of range";
165 case MODE_VSYNC:
166 return "vrefresh out of range";
167 case MODE_H_ILLEGAL:
168 return "illegal horizontal timings";
169 case MODE_V_ILLEGAL:
170 return "illegal vertical timings";
171 case MODE_BAD_WIDTH:
172 return "width requires unsupported line pitch";
173 case MODE_NOMODE:
174 return "no mode of this name";
175 case MODE_NO_INTERLACE:
176 return "interlace mode not supported";
177 case MODE_NO_DBLESCAN:
178 return "doublescan mode not supported";
179 case MODE_NO_VSCAN:
180 return "multiscan mode not supported";
181 case MODE_MEM:
182 return "insufficient memory for mode";
183 case MODE_VIRTUAL_X:
184 return "width too large for virtual size";
185 case MODE_VIRTUAL_Y:
186 return "height too large for virtual size";
187 case MODE_MEM_VIRT:
188 return "insufficient memory given virtual size";
189 case MODE_NOCLOCK:
190 return "no clock available for mode";
191 case MODE_CLOCK_HIGH:
192 return "mode clock too high";
193 case MODE_CLOCK_LOW:
194 return "mode clock too low";
195 case MODE_CLOCK_RANGE:
196 return "bad mode clock/interlace/doublescan";
197 case MODE_BAD_HVALUE:
198 return "horizontal timing out of range";
199 case MODE_BAD_VVALUE:
200 return "vertical timing out of range";
201 case MODE_BAD_VSCAN:
202 return "VScan value out of range";
203 case MODE_HSYNC_NARROW:
204 return "horizontal sync too narrow";
205 case MODE_HSYNC_WIDE:
206 return "horizontal sync too wide";
207 case MODE_HBLANK_NARROW:
208 return "horizontal blanking too narrow";
209 case MODE_HBLANK_WIDE:
210 return "horizontal blanking too wide";
211 case MODE_VSYNC_NARROW:
212 return "vertical sync too narrow";
213 case MODE_VSYNC_WIDE:
214 return "vertical sync too wide";
215 case MODE_VBLANK_NARROW:
216 return "vertical blanking too narrow";
217 case MODE_VBLANK_WIDE:
218 return "vertical blanking too wide";
219 case MODE_PANEL:
220 return "exceeds panel dimensions";
221 case MODE_INTERLACE_WIDTH:
222 return "width too large for interlaced mode";
223 case MODE_ONE_WIDTH:
224 return "all modes must have the same width";
225 case MODE_ONE_HEIGHT:
226 return "all modes must have the same height";
227 case MODE_ONE_SIZE:
228 return "all modes must have the same resolution";
229 case MODE_NO_REDUCED:
230 return "monitor doesn't support reduced blanking";
231 case MODE_BANDWIDTH:
232 return "mode requires too much memory bandwidth";
233 case MODE_BAD:
234 return "unknown reason";
235 case MODE_ERROR:
236 return "internal error";
237 default:
238 return "unknown";
239 }
240}
241
242/*
243 * xf86ShowClockRanges() -- Print the clock ranges allowed
244 * and the clock values scaled by ClockMulFactor and ClockDivFactor
245 */
246void
247xf86ShowClockRanges(ScrnInfoPtr scrp, ClockRangePtr clockRanges)
248{
249 ClockRangePtr cp;
250 int MulFactor = 1;
251 int DivFactor = 1;
252 int i, j;
253 int scaledClock;
254
255 for (cp = clockRanges; cp != NULL; cp = cp->next) {
256 DivFactor = max(1, cp->ClockDivFactor);
257 MulFactor = max(1, cp->ClockMulFactor);
258 if (scrp->progClock) {
259 if (cp->minClock) {
260 if (cp->maxClock) {
261 xf86DrvMsg(scrp->scrnIndex, X_INFO,
262 "Clock range: %6.2f to %6.2f MHz\n",
263 (double) cp->minClock / 1000.0,
264 (double) cp->maxClock / 1000.0);
265 }
266 else {
267 xf86DrvMsg(scrp->scrnIndex, X_INFO,
268 "Minimum clock: %6.2f MHz\n",
269 (double) cp->minClock / 1000.0);
270 }
271 }
272 else {
273 if (cp->maxClock) {
274 xf86DrvMsg(scrp->scrnIndex, X_INFO,
275 "Maximum clock: %6.2f MHz\n",
276 (double) cp->maxClock / 1000.0);
277 }
278 }
279 }
280 else if (DivFactor > 1 || MulFactor > 1) {
281 j = 0;
282 for (i = 0; i < scrp->numClocks; i++) {
283 scaledClock = (scrp->clock[i] * DivFactor) / MulFactor;
284 if (scaledClock >= cp->minClock && scaledClock <= cp->maxClock) {
285 if ((j % 8) == 0) {
286 if (j > 0)
287 xf86ErrorF("\n");
288 xf86DrvMsg(scrp->scrnIndex, X_INFO, "scaled clocks:");
289 }
290 xf86ErrorF(" %6.2f", (double) scaledClock / 1000.0);
291 j++;
292 }
293 }
294 xf86ErrorF("\n");
295 }
296 }
297}
298
299static Bool
300modeInClockRange(ClockRangePtr cp, DisplayModePtr p)
301{
302 return ((p->Clock >= cp->minClock) &&
303 (p->Clock <= cp->maxClock) &&
304 (cp->interlaceAllowed || !(p->Flags & V_INTERLACE)) &&
305 (cp->doubleScanAllowed ||
306 ((p->VScan <= 1) && !(p->Flags & V_DBLSCAN))));
307}
308
309/*
310 * xf86FindClockRangeForMode() [... like the name says ...]
311 */
312static ClockRangePtr
313xf86FindClockRangeForMode(ClockRangePtr clockRanges, DisplayModePtr p)
314{
315 ClockRangePtr cp;
316
317 for (cp = clockRanges;; cp = cp->next)
318 if (!cp || modeInClockRange(cp, p))
319 return cp;
320}
321
322/*
323 * xf86HandleBuiltinMode() - handles built-in modes
324 */
325static ModeStatus
326xf86HandleBuiltinMode(ScrnInfoPtr scrp,
327 DisplayModePtr p,
328 DisplayModePtr modep,
329 ClockRangePtr clockRanges, Bool allowDiv2)
330{
331 ClockRangePtr cp;
332 int extraFlags = 0;
333 int MulFactor = 1;
334 int DivFactor = 1;
335 int clockIndex;
336
337 /* Reject previously rejected modes */
338 if (p->status != MODE_OK)
339 return p->status;
340
341 /* Reject previously considered modes */
342 if (p->prev)
343 return MODE_NOMODE;
344
345 if ((p->type & M_T_CLOCK_C) == M_T_CLOCK_C) {
346 /* Check clock is in range */
347 cp = xf86FindClockRangeForMode(clockRanges, p);
348 if (cp == NULL) {
349 modep->type = p->type;
350 p->status = MODE_CLOCK_RANGE;
351 return MODE_CLOCK_RANGE;
352 }
353 DivFactor = cp->ClockDivFactor;
354 MulFactor = cp->ClockMulFactor;
355 if (!scrp->progClock) {
356 clockIndex = xf86GetNearestClock(scrp, p->Clock, allowDiv2,
357 cp->ClockDivFactor,
358 cp->ClockMulFactor, &extraFlags);
359 modep->Clock = (scrp->clock[clockIndex] * DivFactor)
360 / MulFactor;
361 modep->ClockIndex = clockIndex;
362 modep->SynthClock = scrp->clock[clockIndex];
363 if (extraFlags & V_CLKDIV2) {
364 modep->Clock /= 2;
365 modep->SynthClock /= 2;
366 }
367 }
368 else {
369 modep->Clock = p->Clock;
370 modep->ClockIndex = -1;
371 modep->SynthClock = (modep->Clock * MulFactor)
372 / DivFactor;
373 }
374 modep->PrivFlags = cp->PrivFlags;
375 }
376 else {
377 if (!scrp->progClock) {
378 modep->Clock = p->Clock;
379 modep->ClockIndex = p->ClockIndex;
380 modep->SynthClock = p->SynthClock;
381 }
382 else {
383 modep->Clock = p->Clock;
384 modep->ClockIndex = -1;
385 modep->SynthClock = p->SynthClock;
386 }
387 modep->PrivFlags = p->PrivFlags;
388 }
389 modep->type = p->type;
390 modep->HDisplay = p->HDisplay;
391 modep->HSyncStart = p->HSyncStart;
392 modep->HSyncEnd = p->HSyncEnd;
393 modep->HTotal = p->HTotal;
394 modep->HSkew = p->HSkew;
395 modep->VDisplay = p->VDisplay;
396 modep->VSyncStart = p->VSyncStart;
397 modep->VSyncEnd = p->VSyncEnd;
398 modep->VTotal = p->VTotal;
399 modep->VScan = p->VScan;
400 modep->Flags = p->Flags | extraFlags;
401 modep->CrtcHDisplay = p->CrtcHDisplay;
402 modep->CrtcHBlankStart = p->CrtcHBlankStart;
403 modep->CrtcHSyncStart = p->CrtcHSyncStart;
404 modep->CrtcHSyncEnd = p->CrtcHSyncEnd;
405 modep->CrtcHBlankEnd = p->CrtcHBlankEnd;
406 modep->CrtcHTotal = p->CrtcHTotal;
407 modep->CrtcHSkew = p->CrtcHSkew;
408 modep->CrtcVDisplay = p->CrtcVDisplay;
409 modep->CrtcVBlankStart = p->CrtcVBlankStart;
410 modep->CrtcVSyncStart = p->CrtcVSyncStart;
411 modep->CrtcVSyncEnd = p->CrtcVSyncEnd;
412 modep->CrtcVBlankEnd = p->CrtcVBlankEnd;
413 modep->CrtcVTotal = p->CrtcVTotal;
414 modep->CrtcHAdjusted = p->CrtcHAdjusted;
415 modep->CrtcVAdjusted = p->CrtcVAdjusted;
416 modep->HSync = p->HSync;
417 modep->VRefresh = p->VRefresh;
418 modep->Private = p->Private;
419 modep->PrivSize = p->PrivSize;
420
421 p->prev = modep;
422
423 return MODE_OK;
424}
425
426/*
427 * xf86LookupMode
428 *
429 * This function returns a mode from the given list which matches the
430 * given name. When multiple modes with the same name are available,
431 * the method of picking the matching mode is determined by the
432 * strategy selected.
433 *
434 * This function takes the following parameters:
435 * scrp ScrnInfoPtr
436 * modep pointer to the returned mode, which must have the name
437 * field filled in.
438 * clockRanges a list of clock ranges. This is optional when all the
439 * modes are built-in modes.
440 * strategy how to decide which mode to use from multiple modes with
441 * the same name
442 *
443 * In addition, the following fields from the ScrnInfoRec are used:
444 * modePool the list of monitor modes compatible with the driver
445 * clocks a list of discrete clocks
446 * numClocks number of discrete clocks
447 * progClock clock is programmable
448 *
449 * If a mode was found, its values are filled in to the area pointed to
450 * by modep, If a mode was not found the return value indicates the
451 * reason.
452 */
453
454ModeStatus
455xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep,
456 ClockRangePtr clockRanges, LookupModeFlags strategy)
457{
458 DisplayModePtr p, bestMode = NULL;
459 ClockRangePtr cp;
460 int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1;
461 double refresh, bestRefresh = 0.0;
462 Bool found = FALSE;
463 int extraFlags = 0;
464 int clockIndex = -1;
465 int MulFactor = 1;
466 int DivFactor = 1;
467 int ModePrivFlags = 0;
468 ModeStatus status = MODE_NOMODE;
469 Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0;
470 int n;
471
472 const int types[] = {
473 M_T_BUILTIN | M_T_PREFERRED,
474 M_T_BUILTIN,
475 M_T_USERDEF | M_T_PREFERRED,
476 M_T_USERDEF,
477 M_T_DRIVER | M_T_PREFERRED,
478 M_T_DRIVER,
479 0
480 };
481 const int ntypes = sizeof(types) / sizeof(int);
482
483 strategy &= ~(LOOKUP_CLKDIV2 | LOOKUP_OPTIONAL_TOLERANCES);
484
485 /* Some sanity checking */
486 if (scrp == NULL || scrp->modePool == NULL ||
487 (!scrp->progClock && scrp->numClocks == 0)) {
488 ErrorF("xf86LookupMode: called with invalid scrnInfoRec\n");
489 return MODE_ERROR;
490 }
491 if (modep == NULL || modep->name == NULL) {
492 ErrorF("xf86LookupMode: called with invalid modep\n");
493 return MODE_ERROR;
494 }
495 for (cp = clockRanges; cp != NULL; cp = cp->next) {
496 /* DivFactor and MulFactor must be > 0 */
497 cp->ClockDivFactor = max(1, cp->ClockDivFactor);
498 cp->ClockMulFactor = max(1, cp->ClockMulFactor);
499 }
500
501 /* Scan the mode pool for matching names */
502 for (n = 0; n < ntypes; n++) {
503 int type = types[n];
504
505 for (p = scrp->modePool; p != NULL; p = p->next) {
506
507 /* scan through the modes in the sort order above */
508 if ((p->type & type) != type)
509 continue;
510
511 if (strcmp(p->name, modep->name) == 0) {
512
513 /* Skip over previously rejected modes */
514 if (p->status != MODE_OK) {
515 if (!found)
516 status = p->status;
517 continue;
518 }
519
520 /* Skip over previously considered modes */
521 if (p->prev)
522 continue;
523
524 if (p->type & M_T_BUILTIN) {
525 return xf86HandleBuiltinMode(scrp, p, modep, clockRanges,
526 allowDiv2);
527 }
528
529 /* Check clock is in range */
530 cp = xf86FindClockRangeForMode(clockRanges, p);
531 if (cp == NULL) {
532 /*
533 * XXX Could do more here to provide a more detailed
534 * reason for not finding a mode.
535 */
536 p->status = MODE_CLOCK_RANGE;
537 if (!found)
538 status = MODE_CLOCK_RANGE;
539 continue;
540 }
541
542 /*
543 * If programmable clock and strategy is not
544 * LOOKUP_BEST_REFRESH, the required mode has been found,
545 * otherwise record the refresh and continue looking.
546 */
547 if (scrp->progClock) {
548 found = TRUE;
549 if (strategy != LOOKUP_BEST_REFRESH) {
550 bestMode = p;
551 DivFactor = cp->ClockDivFactor;
552 MulFactor = cp->ClockMulFactor;
553 ModePrivFlags = cp->PrivFlags;
554 break;
555 }
556 refresh = xf86ModeVRefresh(p);
557 if (p->Flags & V_INTERLACE)
558 refresh /= INTERLACE_REFRESH_WEIGHT;
559 if (refresh > bestRefresh) {
560 bestMode = p;
561 DivFactor = cp->ClockDivFactor;
562 MulFactor = cp->ClockMulFactor;
563 ModePrivFlags = cp->PrivFlags;
564 bestRefresh = refresh;
565 }
566 continue;
567 }
568
569 /*
570 * Clock is in range, so if it is not a programmable clock, find
571 * a matching clock.
572 */
573
574 i = xf86GetNearestClock(scrp, p->Clock, allowDiv2,
575 cp->ClockDivFactor, cp->ClockMulFactor,
576 &k);
577 /*
578 * If the clock is too far from the requested clock, this
579 * mode is no good.
580 */
581 if (k & V_CLKDIV2)
582 gap = abs((p->Clock * 2) -
583 ((scrp->clock[i] * cp->ClockDivFactor) /
584 cp->ClockMulFactor));
585 else
586 gap = abs(p->Clock -
587 ((scrp->clock[i] * cp->ClockDivFactor) /
588 cp->ClockMulFactor));
589 if (gap > minimumGap) {
590 p->status = MODE_NOCLOCK;
591 if (!found)
592 status = MODE_NOCLOCK;
593 continue;
594 }
595 found = TRUE;
596
597 if (strategy == LOOKUP_BEST_REFRESH) {
598 refresh = xf86ModeVRefresh(p);
599 if (p->Flags & V_INTERLACE)
600 refresh /= INTERLACE_REFRESH_WEIGHT;
601 if (refresh > bestRefresh) {
602 bestMode = p;
603 DivFactor = cp->ClockDivFactor;
604 MulFactor = cp->ClockMulFactor;
605 ModePrivFlags = cp->PrivFlags;
606 extraFlags = k;
607 clockIndex = i;
608 bestRefresh = refresh;
609 }
610 continue;
611 }
612 if (strategy == LOOKUP_CLOSEST_CLOCK) {
613 if (gap < minimumGap) {
614 bestMode = p;
615 DivFactor = cp->ClockDivFactor;
616 MulFactor = cp->ClockMulFactor;
617 ModePrivFlags = cp->PrivFlags;
618 extraFlags = k;
619 clockIndex = i;
620 minimumGap = gap;
621 }
622 continue;
623 }
624 /*
625 * If strategy is neither LOOKUP_BEST_REFRESH or
626 * LOOKUP_CLOSEST_CLOCK the required mode has been found.
627 */
628 bestMode = p;
629 DivFactor = cp->ClockDivFactor;
630 MulFactor = cp->ClockMulFactor;
631 ModePrivFlags = cp->PrivFlags;
632 extraFlags = k;
633 clockIndex = i;
634 break;
635 }
636 }
637 if (found)
638 break;
639 }
640 if (!found || bestMode == NULL)
641 return status;
642
643 /* Fill in the mode parameters */
644 if (scrp->progClock) {
645 modep->Clock = bestMode->Clock;
646 modep->ClockIndex = -1;
647 modep->SynthClock = (modep->Clock * MulFactor) / DivFactor;
648 }
649 else {
650 modep->Clock = (scrp->clock[clockIndex] * DivFactor) / MulFactor;
651 modep->ClockIndex = clockIndex;
652 modep->SynthClock = scrp->clock[clockIndex];
653 if (extraFlags & V_CLKDIV2) {
654 modep->Clock /= 2;
655 modep->SynthClock /= 2;
656 }
657 }
658 modep->type = bestMode->type;
659 modep->PrivFlags = ModePrivFlags;
660 modep->HDisplay = bestMode->HDisplay;
661 modep->HSyncStart = bestMode->HSyncStart;
662 modep->HSyncEnd = bestMode->HSyncEnd;
663 modep->HTotal = bestMode->HTotal;
664 modep->HSkew = bestMode->HSkew;
665 modep->VDisplay = bestMode->VDisplay;
666 modep->VSyncStart = bestMode->VSyncStart;
667 modep->VSyncEnd = bestMode->VSyncEnd;
668 modep->VTotal = bestMode->VTotal;
669 modep->VScan = bestMode->VScan;
670 modep->Flags = bestMode->Flags | extraFlags;
671 modep->CrtcHDisplay = bestMode->CrtcHDisplay;
672 modep->CrtcHBlankStart = bestMode->CrtcHBlankStart;
673 modep->CrtcHSyncStart = bestMode->CrtcHSyncStart;
674 modep->CrtcHSyncEnd = bestMode->CrtcHSyncEnd;
675 modep->CrtcHBlankEnd = bestMode->CrtcHBlankEnd;
676 modep->CrtcHTotal = bestMode->CrtcHTotal;
677 modep->CrtcHSkew = bestMode->CrtcHSkew;
678 modep->CrtcVDisplay = bestMode->CrtcVDisplay;
679 modep->CrtcVBlankStart = bestMode->CrtcVBlankStart;
680 modep->CrtcVSyncStart = bestMode->CrtcVSyncStart;
681 modep->CrtcVSyncEnd = bestMode->CrtcVSyncEnd;
682 modep->CrtcVBlankEnd = bestMode->CrtcVBlankEnd;
683 modep->CrtcVTotal = bestMode->CrtcVTotal;
684 modep->CrtcHAdjusted = bestMode->CrtcHAdjusted;
685 modep->CrtcVAdjusted = bestMode->CrtcVAdjusted;
686 modep->HSync = bestMode->HSync;
687 modep->VRefresh = bestMode->VRefresh;
688 modep->Private = bestMode->Private;
689 modep->PrivSize = bestMode->PrivSize;
690
691 bestMode->prev = modep;
692
693 return MODE_OK;
694}
695
696/*
697 * xf86CheckModeForMonitor
698 *
699 * This function takes a mode and monitor description, and determines
700 * if the mode is valid for the monitor.
701 */
702ModeStatus
703xf86CheckModeForMonitor(DisplayModePtr mode, MonPtr monitor)
704{
705 int i;
706
707 /* Sanity checks */
708 if (mode == NULL || monitor == NULL) {
709 ErrorF("xf86CheckModeForMonitor: called with invalid parameters\n");
710 return MODE_ERROR;
711 }
712
713 DebugF("xf86CheckModeForMonitor(%p %s, %p %s)\n",
714 mode, mode->name, monitor, monitor->id);
715
716 /* Some basic mode validity checks */
717 if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart ||
718 mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal)
719 return MODE_H_ILLEGAL;
720
721 if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart ||
722 mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal)
723 return MODE_V_ILLEGAL;
724
725 if (monitor->nHsync > 0) {
726 /* Check hsync against the allowed ranges */
727 float hsync = xf86ModeHSync(mode);
728
729 for (i = 0; i < monitor->nHsync; i++)
730 if ((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) &&
731 (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE)))
732 break;
733
734 /* Now see whether we ran out of sync ranges without finding a match */
735 if (i == monitor->nHsync)
736 return MODE_HSYNC;
737 }
738
739 if (monitor->nVrefresh > 0) {
740 /* Check vrefresh against the allowed ranges */
741 float vrefrsh = xf86ModeVRefresh(mode);
742
743 for (i = 0; i < monitor->nVrefresh; i++)
744 if ((vrefrsh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) &&
745 (vrefrsh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE)))
746 break;
747
748 /* Now see whether we ran out of refresh ranges without finding a match */
749 if (i == monitor->nVrefresh)
750 return MODE_VSYNC;
751 }
752
753 /* Force interlaced modes to have an odd VTotal */
754 if (mode->Flags & V_INTERLACE)
755 mode->CrtcVTotal = mode->VTotal |= 1;
756
757 /*
758 * This code stops cvt -r modes, and only cvt -r modes, from hitting 15y+
759 * old CRTs which might, when there is a lot of solar flare activity and
760 * when the celestial bodies are unfavourably aligned, implode trying to
761 * sync to it. It's called "Protecting the user from doing anything stupid".
762 * -- libv
763 */
764
765 if (xf86ModeIsReduced(mode)) {
766 if (!monitor->reducedblanking && !(mode->type & M_T_DRIVER))
767 return MODE_NO_REDUCED;
768 }
769
770 if ((monitor->maxPixClock) && (mode->Clock > monitor->maxPixClock))
771 return MODE_CLOCK_HIGH;
772
773 return MODE_OK;
774}
775
776/*
777 * xf86CheckModeSize
778 *
779 * An internal routine to check if a mode fits in video memory. This tries to
780 * avoid overflows that would otherwise occur when video memory size is greater
781 * than 256MB.
782 */
783static Bool
784xf86CheckModeSize(ScrnInfoPtr scrp, int w, int x, int y)
785{
786 int bpp = scrp->fbFormat.bitsPerPixel, pad = scrp->fbFormat.scanlinePad;
787 int lineWidth, lastWidth;
788
789 if (scrp->depth == 4)
790 pad *= 4; /* 4 planes */
791
792 /* Sanity check */
793 if ((w < 0) || (x < 0) || (y <= 0))
794 return FALSE;
795
796 lineWidth = (((w * bpp) + pad - 1) / pad) * pad;
797 lastWidth = x * bpp;
798
799 /*
800 * At this point, we need to compare
801 *
802 * (lineWidth * (y - 1)) + lastWidth
803 *
804 * against
805 *
806 * scrp->videoRam * (1024 * 8)
807 *
808 * These are bit quantities. To avoid overflows, do the comparison in
809 * terms of BITMAP_SCANLINE_PAD units. This assumes BITMAP_SCANLINE_PAD
810 * is a power of 2. We currently use 32, which limits us to a video
811 * memory size of 8GB.
812 */
813
814 lineWidth = (lineWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD;
815 lastWidth = (lastWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD;
816
817 if ((lineWidth * (y - 1) + lastWidth) >
818 (scrp->videoRam * ((1024 * 8) / BITMAP_SCANLINE_PAD)))
819 return FALSE;
820
821 return TRUE;
822}
823
824/*
825 * xf86InitialCheckModeForDriver
826 *
827 * This function checks if a mode satisfies a driver's initial requirements:
828 * - mode size fits within the available pixel area (memory)
829 * - width lies within the range of supported line pitches
830 * - mode size fits within virtual size (if fixed)
831 * - horizontal timings are in range
832 *
833 * This function takes the following parameters:
834 * scrp ScrnInfoPtr
835 * mode mode to check
836 * maxPitch (optional) maximum line pitch
837 * virtualX (optional) virtual width requested
838 * virtualY (optional) virtual height requested
839 *
840 * In addition, the following fields from the ScrnInfoRec are used:
841 * monitor pointer to structure for monitor section
842 * fbFormat pixel format for the framebuffer
843 * videoRam video memory size (in kB)
844 * maxHValue maximum horizontal timing value
845 * maxVValue maximum vertical timing value
846 */
847
848ModeStatus
849xf86InitialCheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode,
850 ClockRangePtr clockRanges,
851 LookupModeFlags strategy,
852 int maxPitch, int virtualX, int virtualY)
853{
854 ClockRangePtr cp;
855 ModeStatus status;
856 Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0;
857 int i, needDiv2;
858
859 /* Sanity checks */
860 if (!scrp || !mode || !clockRanges) {
861 ErrorF("xf86InitialCheckModeForDriver: "
862 "called with invalid parameters\n");
863 return MODE_ERROR;
864 }
865
866 DebugF("xf86InitialCheckModeForDriver(%p, %p %s, %p, 0x%x, %d, %d, %d)\n",
867 scrp, mode, mode->name, clockRanges, strategy, maxPitch, virtualX,
868 virtualY);
869
870 /* Some basic mode validity checks */
871 if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart ||
872 mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal)
873 return MODE_H_ILLEGAL;
874
875 if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart ||
876 mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal)
877 return MODE_V_ILLEGAL;
878
879 if (!xf86CheckModeSize(scrp, mode->HDisplay, mode->HDisplay,
880 mode->VDisplay))
881 return MODE_MEM;
882
883 if (maxPitch > 0 && mode->HDisplay > maxPitch)
884 return MODE_BAD_WIDTH;
885
886 if (virtualX > 0 && mode->HDisplay > virtualX)
887 return MODE_VIRTUAL_X;
888
889 if (virtualY > 0 && mode->VDisplay > virtualY)
890 return MODE_VIRTUAL_Y;
891
892 if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue)
893 return MODE_BAD_HVALUE;
894
895 if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue)
896 return MODE_BAD_VVALUE;
897
898 /*
899 * The use of the DisplayModeRec's Crtc* and SynthClock elements below is
900 * provisional, in that they are later reused by the driver at mode-set
901 * time. Here, they are temporarily enlisted to contain the mode timings
902 * as seen by the CRT or panel (rather than the CRTC). The driver's
903 * ValidMode() is allowed to modify these so it can deal with such things
904 * as mode stretching and/or centering. The driver should >NOT< modify the
905 * user-supplied values as these are reported back when mode validation is
906 * said and done.
907 */
908 /*
909 * NOTE: We (ab)use the mode->Crtc* values here to store timing
910 * information for the calculation of Hsync and Vrefresh. Before
911 * these values are calculated the driver is given the opportunity
912 * to either set these HSync and VRefresh itself or modify the timing
913 * values.
914 * The difference to the final calculation is small but imortand:
915 * here we pass the flag INTERLACE_HALVE_V regardless if the driver
916 * sets it or not. This way our calculation of VRefresh has the same
917 * effect as if we do if (flags & V_INTERLACE) refresh *= 2.0
918 * This dual use of the mode->Crtc* values will certainly create
919 * confusion and is bad software design. However since it's part of
920 * the driver API it's hard to change.
921 */
922
923 if (scrp->ValidMode) {
924
925 xf86SetModeCrtc(mode, INTERLACE_HALVE_V);
926
927 cp = xf86FindClockRangeForMode(clockRanges, mode);
928 if (!cp)
929 return MODE_CLOCK_RANGE;
930
931 if (cp->ClockMulFactor < 1)
932 cp->ClockMulFactor = 1;
933 if (cp->ClockDivFactor < 1)
934 cp->ClockDivFactor = 1;
935
936 /*
937 * XXX The effect of clock dividers and multipliers on the monitor's
938 * pixel clock needs to be verified.
939 */
940 if (scrp->progClock) {
941 mode->SynthClock = mode->Clock;
942 }
943 else {
944 i = xf86GetNearestClock(scrp, mode->Clock, allowDiv2,
945 cp->ClockDivFactor, cp->ClockMulFactor,
946 &needDiv2);
947 mode->SynthClock = (scrp->clock[i] * cp->ClockDivFactor) /
948 cp->ClockMulFactor;
949 if (needDiv2 & V_CLKDIV2)
950 mode->SynthClock /= 2;
951 }
952
953 status = (*scrp->ValidMode) (scrp, mode, FALSE,
954 MODECHECK_INITIAL);
955 if (status != MODE_OK)
956 return status;
957
958 if (mode->HSync <= 0.0)
959 mode->HSync = (float) mode->SynthClock / (float) mode->CrtcHTotal;
960 if (mode->VRefresh <= 0.0)
961 mode->VRefresh = (mode->SynthClock * 1000.0)
962 / (mode->CrtcHTotal * mode->CrtcVTotal);
963 }
964
965 mode->HSync = xf86ModeHSync(mode);
966 mode->VRefresh = xf86ModeVRefresh(mode);
967
968 /* Assume it is OK */
969 return MODE_OK;
970}
971
972/*
973 * xf86CheckModeForDriver
974 *
975 * This function is for checking modes while the server is running (for
976 * use mainly by the VidMode extension).
977 *
978 * This function checks if a mode satisfies a driver's requirements:
979 * - width lies within the line pitch
980 * - mode size fits within virtual size
981 * - horizontal/vertical timings are in range
982 *
983 * This function takes the following parameters:
984 * scrp ScrnInfoPtr
985 * mode mode to check
986 * flags not (currently) used
987 *
988 * In addition, the following fields from the ScrnInfoRec are used:
989 * maxHValue maximum horizontal timing value
990 * maxVValue maximum vertical timing value
991 * virtualX virtual width
992 * virtualY virtual height
993 * clockRanges allowable clock ranges
994 */
995
996ModeStatus
997xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, int flags)
998{
999 ClockRangePtr cp;
1000 int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1;
1001 int extraFlags = 0;
1002 int clockIndex = -1;
1003 int MulFactor = 1;
1004 int DivFactor = 1;
1005 int ModePrivFlags = 0;
1006 ModeStatus status = MODE_NOMODE;
1007
1008 /* Some sanity checking */
1009 if (scrp == NULL || (!scrp->progClock && scrp->numClocks == 0)) {
1010 ErrorF("xf86CheckModeForDriver: called with invalid scrnInfoRec\n");
1011 return MODE_ERROR;
1012 }
1013 if (mode == NULL) {
1014 ErrorF("xf86CheckModeForDriver: called with invalid modep\n");
1015 return MODE_ERROR;
1016 }
1017
1018 /* Check the mode size */
1019 if (mode->HDisplay > scrp->virtualX)
1020 return MODE_VIRTUAL_X;
1021
1022 if (mode->VDisplay > scrp->virtualY)
1023 return MODE_VIRTUAL_Y;
1024
1025 if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue)
1026 return MODE_BAD_HVALUE;
1027
1028 if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue)
1029 return MODE_BAD_VVALUE;
1030
1031 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) {
1032 /* DivFactor and MulFactor must be > 0 */
1033 cp->ClockDivFactor = max(1, cp->ClockDivFactor);
1034 cp->ClockMulFactor = max(1, cp->ClockMulFactor);
1035 }
1036
1037 if (scrp->progClock) {
1038 /* Check clock is in range */
1039 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) {
1040 if (modeInClockRange(cp, mode))
1041 break;
1042 }
1043 if (cp == NULL) {
1044 return MODE_CLOCK_RANGE;
1045 }
1046 /*
1047 * If programmable clock the required mode has been found
1048 */
1049 DivFactor = cp->ClockDivFactor;
1050 MulFactor = cp->ClockMulFactor;
1051 ModePrivFlags = cp->PrivFlags;
1052 }
1053 else {
1054 status = MODE_CLOCK_RANGE;
1055 /* Check clock is in range */
1056 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) {
1057 if (modeInClockRange(cp, mode)) {
1058 /*
1059 * Clock is in range, so if it is not a programmable clock,
1060 * find a matching clock.
1061 */
1062
1063 i = xf86GetNearestClock(scrp, mode->Clock, 0,
1064 cp->ClockDivFactor, cp->ClockMulFactor,
1065 &k);
1066 /*
1067 * If the clock is too far from the requested clock, this
1068 * mode is no good.
1069 */
1070 if (k & V_CLKDIV2)
1071 gap = abs((mode->Clock * 2) -
1072 ((scrp->clock[i] * cp->ClockDivFactor) /
1073 cp->ClockMulFactor));
1074 else
1075 gap = abs(mode->Clock -
1076 ((scrp->clock[i] * cp->ClockDivFactor) /
1077 cp->ClockMulFactor));
1078 if (gap > minimumGap) {
1079 status = MODE_NOCLOCK;
1080 continue;
1081 }
1082
1083 DivFactor = cp->ClockDivFactor;
1084 MulFactor = cp->ClockMulFactor;
1085 ModePrivFlags = cp->PrivFlags;
1086 extraFlags = k;
1087 clockIndex = i;
1088 break;
1089 }
1090 }
1091 if (cp == NULL)
1092 return status;
1093 }
1094
1095 /* Fill in the mode parameters */
1096 if (scrp->progClock) {
1097 mode->ClockIndex = -1;
1098 mode->SynthClock = (mode->Clock * MulFactor) / DivFactor;
1099 }
1100 else {
1101 mode->Clock = (scrp->clock[clockIndex] * DivFactor) / MulFactor;
1102 mode->ClockIndex = clockIndex;
1103 mode->SynthClock = scrp->clock[clockIndex];
1104 if (extraFlags & V_CLKDIV2) {
1105 mode->Clock /= 2;
1106 mode->SynthClock /= 2;
1107 }
1108 }
1109 mode->PrivFlags = ModePrivFlags;
1110
1111 return MODE_OK;
1112}
1113
1114static int
1115inferVirtualSize(ScrnInfoPtr scrp, DisplayModePtr modes, int *vx, int *vy)
1116{
1117 float aspect = 0.0;
1118 MonPtr mon = scrp->monitor;
1119 xf86MonPtr DDC;
1120 int x = 0, y = 0;
1121 DisplayModePtr mode;
1122
1123 if (!mon)
1124 return 0;
1125 DDC = mon->DDC;
1126
1127 if (DDC && DDC->ver.revision >= 4) {
1128 /* For 1.4, we might actually get native pixel format. How novel. */
1129 if (PREFERRED_TIMING_MODE(DDC->features.msc)) {
1130 for (mode = modes; mode; mode = mode->next) {
1131 if (mode->type & (M_T_DRIVER | M_T_PREFERRED)) {
1132 x = mode->HDisplay;
1133 y = mode->VDisplay;
1134 goto found;
1135 }
1136 }
1137 }
1138 /*
1139 * Even if we don't, we might get aspect ratio from extra CVT info
1140 * or from the monitor size fields. TODO.
1141 */
1142 }
1143
1144 /*
1145 * Technically this triggers if either is zero. That wasn't legal
1146 * before EDID 1.4, but right now we'll get that wrong. TODO.
1147 */
1148 if (!aspect) {
1149 if (!mon->widthmm || !mon->heightmm)
1150 aspect = 4.0 / 3.0;
1151 else
1152 aspect = (float) mon->widthmm / (float) mon->heightmm;
1153 }
1154
1155 /* find the largest M_T_DRIVER mode with that aspect ratio */
1156 for (mode = modes; mode; mode = mode->next) {
1157 float mode_aspect, metaspect;
1158
1159 if (!(mode->type & (M_T_DRIVER | M_T_USERDEF)))
1160 continue;
1161 mode_aspect = (float) mode->HDisplay / (float) mode->VDisplay;
1162 metaspect = aspect / mode_aspect;
1163 /* 5% slop or so, since we only get size in centimeters */
1164 if (fabs(1.0 - metaspect) < 0.05) {
1165 if ((mode->HDisplay > x) && (mode->VDisplay > y)) {
1166 x = mode->HDisplay;
1167 y = mode->VDisplay;
1168 }
1169 }
1170 }
1171
1172 if (!x || !y) {
1173 xf86DrvMsg(scrp->scrnIndex, X_WARNING,
1174 "Unable to estimate virtual size\n");
1175 return 0;
1176 }
1177
1178 found:
1179 *vx = x;
1180 *vy = y;
1181
1182 xf86DrvMsg(scrp->scrnIndex, X_INFO,
1183 "Estimated virtual size for aspect ratio %.4f is %dx%d\n",
1184 aspect, *vx, *vy);
1185
1186 return 1;
1187}
1188
1189/* Least common multiple */
1190static unsigned int
1191LCM(unsigned int x, unsigned int y)
1192{
1193 unsigned int m = x, n = y, o;
1194
1195 while ((o = m % n)) {
1196 m = n;
1197 n = o;
1198 }
1199
1200 return (x / n) * y;
1201}
1202
1203/*
1204 * Given various screen attributes, determine the minimum scanline width such
1205 * that each scanline is server and DDX padded and any pixels with imbedded
1206 * bank boundaries are off-screen. This function returns -1 if such a width
1207 * cannot exist.
1208 */
1209static int
1210scanLineWidth(unsigned int xsize, /* pixels */
1211 unsigned int ysize, /* pixels */
1212 unsigned int width, /* pixels */
1213 unsigned long BankSize, /* char's */
1214 PixmapFormatRec * pBankFormat, unsigned int nWidthUnit /* bits */
1215 )
1216{
1217 unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit;
1218 unsigned long minBitsPerScanline, maxBitsPerScanline;
1219
1220 /* Sanity checks */
1221
1222 if (!nWidthUnit || !pBankFormat)
1223 return -1;
1224
1225 nBitsPerBank = BankSize * 8;
1226 if (nBitsPerBank % pBankFormat->scanlinePad)
1227 return -1;
1228
1229 if (xsize > width)
1230 width = xsize;
1231 nBitsPerScanlinePadUnit = LCM(pBankFormat->scanlinePad, nWidthUnit);
1232 nBitsPerScanline =
1233 (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) /
1234 nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit;
1235 width = nBitsPerScanline / pBankFormat->bitsPerPixel;
1236
1237 if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel))
1238 return (int) width;
1239
1240 /*
1241 * Scanlines will be server-pad aligned at this point. They will also be
1242 * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded
1243 * bank boundaries are off-screen.
1244 *
1245 * It seems reasonable to limit total frame buffer size to 1/16 of the
1246 * theoretical maximum address space size. On a machine with 32-bit
1247 * addresses (to 8-bit quantities) this turns out to be 256MB. Not only
1248 * does this provide a simple limiting condition for the loops below, but
1249 * it also prevents unsigned long wraparounds.
1250 */
1251 if (!ysize)
1252 return -1;
1253
1254 minBitsPerScanline = xsize * pBankFormat->bitsPerPixel;
1255 if (minBitsPerScanline > nBitsPerBank)
1256 return -1;
1257
1258 if (ysize == 1)
1259 return (int) width;
1260
1261 maxBitsPerScanline =
1262 (((unsigned long) (-1) >> 1) - minBitsPerScanline) / (ysize - 1);
1263 while (nBitsPerScanline <= maxBitsPerScanline) {
1264 unsigned long BankBase, BankUnit;
1265
1266 BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) *
1267 nBitsPerBank;
1268 if (!(BankUnit % nBitsPerScanline))
1269 return (int) width;
1270
1271 for (BankBase = BankUnit;; BankBase += nBitsPerBank) {
1272 unsigned long x, y;
1273
1274 y = BankBase / nBitsPerScanline;
1275 if (y >= ysize)
1276 return (int) width;
1277
1278 x = BankBase % nBitsPerScanline;
1279 if (!(x % pBankFormat->bitsPerPixel))
1280 continue;
1281
1282 if (x < minBitsPerScanline) {
1283 /*
1284 * Skip ahead certain widths by dividing the excess scanline
1285 * amongst the y's.
1286 */
1287 y *= nBitsPerScanlinePadUnit;
1288 nBitsPerScanline += ((x + y - 1) / y) * nBitsPerScanlinePadUnit;
1289 width = nBitsPerScanline / pBankFormat->bitsPerPixel;
1290 break;
1291 }
1292
1293 if (BankBase != BankUnit)
1294 continue;
1295
1296 if (!(nBitsPerScanline % x))
1297 return (int) width;
1298
1299 BankBase = ((nBitsPerScanline - minBitsPerScanline) /
1300 (nBitsPerScanline - x)) * BankUnit;
1301 }
1302 }
1303
1304 return -1;
1305}
1306
1307/*
1308 * xf86ValidateModes
1309 *
1310 * This function takes a set of mode names, modes and limiting conditions,
1311 * and selects a set of modes and parameters based on those conditions.
1312 *
1313 * This function takes the following parameters:
1314 * scrp ScrnInfoPtr
1315 * availModes the list of modes available for the monitor
1316 * modeNames (optional) list of mode names that the screen is requesting
1317 * clockRanges a list of clock ranges
1318 * linePitches (optional) a list of line pitches
1319 * minPitch (optional) minimum line pitch (in pixels)
1320 * maxPitch (optional) maximum line pitch (in pixels)
1321 * pitchInc (mandatory) pitch increment (in bits)
1322 * minHeight (optional) minimum virtual height (in pixels)
1323 * maxHeight (optional) maximum virtual height (in pixels)
1324 * virtualX (optional) virtual width requested (in pixels)
1325 * virtualY (optional) virtual height requested (in pixels)
1326 * apertureSize size of video aperture (in bytes)
1327 * strategy how to decide which mode to use from multiple modes with
1328 * the same name
1329 *
1330 * In addition, the following fields from the ScrnInfoRec are used:
1331 * clocks a list of discrete clocks
1332 * numClocks number of discrete clocks
1333 * progClock clock is programmable
1334 * monitor pointer to structure for monitor section
1335 * fbFormat format of the framebuffer
1336 * videoRam video memory size
1337 * maxHValue maximum horizontal timing value
1338 * maxVValue maximum vertical timing value
1339 * xInc horizontal timing increment (defaults to 8 pixels)
1340 *
1341 * The function fills in the following ScrnInfoRec fields:
1342 * modePool A subset of the modes available to the monitor which
1343 * are compatible with the driver.
1344 * modes one mode entry for each of the requested modes, with the
1345 * status field filled in to indicate if the mode has been
1346 * accepted or not.
1347 * virtualX the resulting virtual width
1348 * virtualY the resulting virtual height
1349 * displayWidth the resulting line pitch
1350 *
1351 * The function's return value is the number of matching modes found, or -1
1352 * if an unrecoverable error was encountered.
1353 */
1354
1355int
1356xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes,
1357 char **modeNames, ClockRangePtr clockRanges,
1358 int *linePitches, int minPitch, int maxPitch, int pitchInc,
1359 int minHeight, int maxHeight, int virtualX, int virtualY,
1360 int apertureSize, LookupModeFlags strategy)
1361{
1362 DisplayModePtr p, q, r, new, last, *endp;
1363 int i, numModes = 0;
1364 ModeStatus status;
1365 int linePitch = -1, virtX = 0, virtY = 0;
1366 int newLinePitch, newVirtX, newVirtY;
1367 int modeSize; /* in pixels */
1368 Bool validateAllDefaultModes = FALSE;
1369 Bool userModes = FALSE;
1370 int saveType;
1371 PixmapFormatRec *BankFormat;
1372 ClockRangePtr cp;
1373 int numTimings = 0;
1374 range hsync[MAX_HSYNC];
1375 range vrefresh[MAX_VREFRESH];
1376 Bool inferred_virtual = FALSE;
1377
1378 DebugF
1379 ("xf86ValidateModes(%p, %p, %p, %p,\n\t\t %p, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x)\n",
1380 scrp, availModes, modeNames, clockRanges, linePitches, minPitch,
1381 maxPitch, pitchInc, minHeight, maxHeight, virtualX, virtualY,
1382 apertureSize, strategy);
1383
1384 /* Some sanity checking */
1385 if (scrp == NULL || scrp->name == NULL || !scrp->monitor ||
1386 (!scrp->progClock && scrp->numClocks == 0)) {
1387 ErrorF("xf86ValidateModes: called with invalid scrnInfoRec\n");
1388 return -1;
1389 }
1390 if (linePitches != NULL && linePitches[0] <= 0) {
1391 ErrorF("xf86ValidateModes: called with invalid linePitches\n");
1392 return -1;
1393 }
1394 if (pitchInc <= 0) {
1395 ErrorF("xf86ValidateModes: called with invalid pitchInc\n");
1396 return -1;
1397 }
1398 if ((virtualX > 0) != (virtualY > 0)) {
1399 ErrorF("xf86ValidateModes: called with invalid virtual resolution\n");
1400 return -1;
1401 }
1402
1403 /*
1404 * If requested by the driver, allow missing hsync and/or vrefresh ranges
1405 * in the monitor section.
1406 */
1407 if (strategy & LOOKUP_OPTIONAL_TOLERANCES) {
1408 strategy &= ~LOOKUP_OPTIONAL_TOLERANCES;
1409 }
1410 else {
1411 const char *type = "";
1412 Bool specified = FALSE;
1413
1414 if (scrp->monitor->nHsync <= 0) {
1415 if (numTimings > 0) {
1416 scrp->monitor->nHsync = numTimings;
1417 for (i = 0; i < numTimings; i++) {
1418 scrp->monitor->hsync[i].lo = hsync[i].lo;
1419 scrp->monitor->hsync[i].hi = hsync[i].hi;
1420 }
1421 }
1422 else {
1423 scrp->monitor->hsync[0].lo = 31.5;
1424 scrp->monitor->hsync[0].hi = 48.0;
1425 scrp->monitor->nHsync = 1;
1426 }
1427 type = "default ";
1428 }
1429 else {
1430 specified = TRUE;
1431 }
1432 for (i = 0; i < scrp->monitor->nHsync; i++) {
1433 if (scrp->monitor->hsync[i].lo == scrp->monitor->hsync[i].hi)
1434 xf86DrvMsg(scrp->scrnIndex, X_INFO,
1435 "%s: Using %shsync value of %.2f kHz\n",
1436 scrp->monitor->id, type, scrp->monitor->hsync[i].lo);
1437 else
1438 xf86DrvMsg(scrp->scrnIndex, X_INFO,
1439 "%s: Using %shsync range of %.2f-%.2f kHz\n",
1440 scrp->monitor->id, type,
1441 scrp->monitor->hsync[i].lo,
1442 scrp->monitor->hsync[i].hi);
1443 }
1444
1445 type = "";
1446 if (scrp->monitor->nVrefresh <= 0) {
1447 if (numTimings > 0) {
1448 scrp->monitor->nVrefresh = numTimings;
1449 for (i = 0; i < numTimings; i++) {
1450 scrp->monitor->vrefresh[i].lo = vrefresh[i].lo;
1451 scrp->monitor->vrefresh[i].hi = vrefresh[i].hi;
1452 }
1453 }
1454 else {
1455 scrp->monitor->vrefresh[0].lo = 50;
1456 scrp->monitor->vrefresh[0].hi = 70;
1457 scrp->monitor->nVrefresh = 1;
1458 }
1459 type = "default ";
1460 }
1461 else {
1462 specified = TRUE;
1463 }
1464 for (i = 0; i < scrp->monitor->nVrefresh; i++) {
1465 if (scrp->monitor->vrefresh[i].lo == scrp->monitor->vrefresh[i].hi)
1466 xf86DrvMsg(scrp->scrnIndex, X_INFO,
1467 "%s: Using %svrefresh value of %.2f Hz\n",
1468 scrp->monitor->id, type,
1469 scrp->monitor->vrefresh[i].lo);
1470 else
1471 xf86DrvMsg(scrp->scrnIndex, X_INFO,
1472 "%s: Using %svrefresh range of %.2f-%.2f Hz\n",
1473 scrp->monitor->id, type,
1474 scrp->monitor->vrefresh[i].lo,
1475 scrp->monitor->vrefresh[i].hi);
1476 }
1477
1478 type = "";
1479 if (!scrp->monitor->maxPixClock && !specified) {
1480 type = "default ";
1481 scrp->monitor->maxPixClock = 65000.0;
1482 }
1483 if (scrp->monitor->maxPixClock) {
1484 xf86DrvMsg(scrp->scrnIndex, X_INFO,
1485 "%s: Using %smaximum pixel clock of %.2f MHz\n",
1486 scrp->monitor->id, type,
1487 (float) scrp->monitor->maxPixClock / 1000.0);
1488 }
1489 }
1490
1491 /*
1492 * Store the clockRanges for later use by the VidMode extension.
1493 */
1494 nt_list_for_each_entry(cp, clockRanges, next) {
1495 ClockRangePtr newCR = xnfalloc(sizeof(ClockRange));
1496 memcpy(newCR, cp, sizeof(ClockRange));
1497 newCR->next = NULL;
1498 if (scrp->clockRanges == NULL)
1499 scrp->clockRanges = newCR;
1500 else
1501 nt_list_append(newCR, scrp->clockRanges, ClockRange, next);
1502 }
1503
1504 /* Determine which pixmap format to pass to scanLineWidth() */
1505 if (scrp->depth > 4)
1506 BankFormat = &scrp->fbFormat;
1507 else
1508 BankFormat = xf86GetPixFormat(scrp, 1); /* >not< scrp->depth! */
1509
1510 if (scrp->xInc <= 0)
1511 scrp->xInc = 8; /* Suitable for VGA and others */
1512
1513#define _VIRTUALX(x) ((((x) + scrp->xInc - 1) / scrp->xInc) * scrp->xInc)
1514
1515 /*
1516 * Determine maxPitch if it wasn't given explicitly. Note linePitches
1517 * always takes precedence if is non-NULL. In that case the minPitch and
1518 * maxPitch values passed are ignored.
1519 */
1520 if (linePitches) {
1521 minPitch = maxPitch = linePitches[0];
1522 for (i = 1; linePitches[i] > 0; i++) {
1523 if (linePitches[i] > maxPitch)
1524 maxPitch = linePitches[i];
1525 if (linePitches[i] < minPitch)
1526 minPitch = linePitches[i];
1527 }
1528 }
1529
1530 /* Initial check of virtual size against other constraints */
1531 scrp->virtualFrom = X_PROBED;
1532 /*
1533 * Initialise virtX and virtY if the values are fixed.
1534 */
1535 if (virtualY > 0) {
1536 if (maxHeight > 0 && virtualY > maxHeight) {
1537 xf86DrvMsg(scrp->scrnIndex, X_ERROR,
1538 "Virtual height (%d) is too large for the hardware "
1539 "(max %d)\n", virtualY, maxHeight);
1540 return -1;
1541 }
1542
1543 if (minHeight > 0 && virtualY < minHeight) {
1544 xf86DrvMsg(scrp->scrnIndex, X_ERROR,
1545 "Virtual height (%d) is too small for the hardware "
1546 "(min %d)\n", virtualY, minHeight);
1547 return -1;
1548 }
1549
1550 virtualX = _VIRTUALX(virtualX);
1551 if (linePitches != NULL) {
1552 for (i = 0; linePitches[i] != 0; i++) {
1553 if ((linePitches[i] >= virtualX) &&
1554 (linePitches[i] ==
1555 scanLineWidth(virtualX, virtualY, linePitches[i],
1556 apertureSize, BankFormat, pitchInc))) {
1557 linePitch = linePitches[i];
1558 break;
1559 }
1560 }
1561 }
1562 else {
1563 linePitch = scanLineWidth(virtualX, virtualY, minPitch,
1564 apertureSize, BankFormat, pitchInc);
1565 }
1566
1567 if ((linePitch < minPitch) || (linePitch > maxPitch)) {
1568 xf86DrvMsg(scrp->scrnIndex, X_ERROR,
1569 "Virtual width (%d) is too large for the hardware "
1570 "(max %d)\n", virtualX, maxPitch);
1571 return -1;
1572 }
1573
1574 if (!xf86CheckModeSize(scrp, linePitch, virtualX, virtualY)) {
1575 xf86DrvMsg(scrp->scrnIndex, X_ERROR,
1576 "Virtual size (%dx%d) (pitch %d) exceeds video memory\n",
1577 virtualX, virtualY, linePitch);
1578 return -1;
1579 }
1580
1581 virtX = virtualX;
1582 virtY = virtualY;
1583 scrp->virtualFrom = X_CONFIG;
1584 }
1585 else if (!modeNames || !*modeNames) {
1586 /* No virtual size given in the config, try to infer */
1587 /* XXX this doesn't take m{in,ax}Pitch into account; oh well */
1588 inferred_virtual = inferVirtualSize(scrp, availModes, &virtX, &virtY);
1589 if (inferred_virtual)
1590 linePitch = scanLineWidth(virtX, virtY, minPitch, apertureSize,
1591 BankFormat, pitchInc);
1592 }
1593
1594 /* Print clock ranges and scaled clocks */
1595 xf86ShowClockRanges(scrp, clockRanges);
1596
1597 /*
1598 * If scrp->modePool hasn't been setup yet, set it up now. This allows the
1599 * modes that the driver definitely can't use to be weeded out early. Note
1600 * that a modePool mode's prev field is used to hold a pointer to the
1601 * member of the scrp->modes list for which a match was considered.
1602 */
1603 if (scrp->modePool == NULL) {
1604 q = NULL;
1605 for (p = availModes; p != NULL; p = p->next) {
1606 status = xf86InitialCheckModeForDriver(scrp, p, clockRanges,
1607 strategy, maxPitch,
1608 virtX, virtY);
1609
1610 if (status == MODE_OK) {
1611 status = xf86CheckModeForMonitor(p, scrp->monitor);
1612 }
1613
1614 if (status == MODE_OK) {
1615 new = xnfalloc(sizeof(DisplayModeRec));
1616 *new = *p;
1617 new->next = NULL;
1618 if (!q) {
1619 scrp->modePool = new;
1620 }
1621 else {
1622 q->next = new;
1623 }
1624 new->prev = NULL;
1625 q = new;
1626 q->name = xnfstrdup(p->name);
1627 q->status = MODE_OK;
1628 }
1629 else {
1630 printModeRejectMessage(scrp->scrnIndex, p, status);
1631 }
1632 }
1633
1634 if (scrp->modePool == NULL) {
1635 xf86DrvMsg(scrp->scrnIndex, X_WARNING, "Mode pool is empty\n");
1636 return 0;
1637 }
1638 }
1639 else {
1640 for (p = scrp->modePool; p != NULL; p = p->next) {
1641 p->prev = NULL;
1642 p->status = MODE_OK;
1643 }
1644 }
1645
1646 /*
1647 * Allocate one entry in scrp->modes for each named mode.
1648 */
1649 while (scrp->modes)
1650 xf86DeleteMode(&scrp->modes, scrp->modes);
1651 endp = &scrp->modes;
1652 last = NULL;
1653 if (modeNames != NULL) {
1654 for (i = 0; modeNames[i] != NULL; i++) {
1655 userModes = TRUE;
1656 new = xnfcalloc(1, sizeof(DisplayModeRec));
1657 new->prev = last;
1658 new->type = M_T_USERDEF;
1659 new->name = xnfstrdup(modeNames[i]);
1660 if (new->prev)
1661 new->prev->next = new;
1662 *endp = last = new;
1663 endp = &new->next;
1664 }
1665 }
1666
1667 /* Lookup each mode */
1668#ifdef RANDR
1669 if (!xf86Info.disableRandR
1670#ifdef PANORAMIX
1671 && noPanoramiXExtension
1672#endif
1673 )
1674 validateAllDefaultModes = TRUE;
1675#endif
1676
1677 for (p = scrp->modes;; p = p->next) {
1678 Bool repeat;
1679
1680 /*
1681 * If the supplied mode names don't produce a valid mode, scan through
1682 * unconsidered modePool members until one survives validation. This
1683 * is done in decreasing order by mode pixel area.
1684 */
1685
1686 if (p == NULL) {
1687 if ((numModes > 0) && !validateAllDefaultModes)
1688 break;
1689
1690 validateAllDefaultModes = TRUE;
1691 r = NULL;
1692 modeSize = 0;
1693 for (q = scrp->modePool; q != NULL; q = q->next) {
1694 if ((q->prev == NULL) && (q->status == MODE_OK)) {
1695 /*
1696 * Deal with the case where this mode wasn't considered
1697 * because of a builtin mode of the same name.
1698 */
1699 for (p = scrp->modes; p != NULL; p = p->next) {
1700 if ((p->status != MODE_OK) && !strcmp(p->name, q->name))
1701 break;
1702 }
1703
1704 if (p != NULL)
1705 q->prev = p;
1706 else {
1707 /*
1708 * A quick check to not allow default modes with
1709 * horizontal timing parameters that CRTs may have
1710 * problems with.
1711 */
1712 if (!scrp->monitor->reducedblanking &&
1713 (q->type & M_T_DEFAULT) &&
1714 ((double) q->HTotal / (double) q->HDisplay) < 1.15)
1715 continue;
1716
1717 if (modeSize < (q->HDisplay * q->VDisplay)) {
1718 r = q;
1719 modeSize = q->HDisplay * q->VDisplay;
1720 }
1721 }
1722 }
1723 }
1724
1725 if (r == NULL)
1726 break;
1727
1728 p = xnfcalloc(1, sizeof(DisplayModeRec));
1729 p->prev = last;
1730 p->name = xnfstrdup(r->name);
1731 if (!userModes)
1732 p->type = M_T_USERDEF;
1733 if (p->prev)
1734 p->prev->next = p;
1735 *endp = last = p;
1736 endp = &p->next;
1737 }
1738
1739 repeat = FALSE;
1740 lookupNext:
1741 if (repeat && ((status = p->status) != MODE_OK))
1742 printModeRejectMessage(scrp->scrnIndex, p, status);
1743 saveType = p->type;
1744 status = xf86LookupMode(scrp, p, clockRanges, strategy);
1745 if (repeat && status == MODE_NOMODE)
1746 continue;
1747 if (status != MODE_OK)
1748 printModeRejectMessage(scrp->scrnIndex, p, status);
1749 if (status == MODE_ERROR) {
1750 ErrorF("xf86ValidateModes: "
1751 "unexpected result from xf86LookupMode()\n");
1752 return -1;
1753 }
1754 if (status != MODE_OK) {
1755 if (p->status == MODE_OK)
1756 p->status = status;
1757 continue;
1758 }
1759 p->type |= saveType;
1760 repeat = TRUE;
1761
1762 newLinePitch = linePitch;
1763 newVirtX = virtX;
1764 newVirtY = virtY;
1765
1766 /*
1767 * Don't let non-user defined modes increase the virtual size
1768 */
1769 if (!(p->type & M_T_USERDEF) && (numModes > 0)) {
1770 if (p->HDisplay > virtX) {
1771 p->status = MODE_VIRTUAL_X;
1772 goto lookupNext;
1773 }
1774 if (p->VDisplay > virtY) {
1775 p->status = MODE_VIRTUAL_Y;
1776 goto lookupNext;
1777 }
1778 }
1779 /*
1780 * Adjust virtual width and height if the mode is too large for the
1781 * current values and if they are not fixed.
1782 */
1783 if (virtualX <= 0 && p->HDisplay > newVirtX)
1784 newVirtX = _VIRTUALX(p->HDisplay);
1785 if (virtualY <= 0 && p->VDisplay > newVirtY) {
1786 if (maxHeight > 0 && p->VDisplay > maxHeight) {
1787 p->status = MODE_VIRTUAL_Y; /* ? */
1788 goto lookupNext;
1789 }
1790 newVirtY = p->VDisplay;
1791 }
1792
1793 /*
1794 * If virtual resolution is to be increased, revalidate it.
1795 */
1796 if ((virtX != newVirtX) || (virtY != newVirtY)) {
1797 if (linePitches != NULL) {
1798 newLinePitch = -1;
1799 for (i = 0; linePitches[i] != 0; i++) {
1800 if ((linePitches[i] >= newVirtX) &&
1801 (linePitches[i] >= linePitch) &&
1802 (linePitches[i] ==
1803 scanLineWidth(newVirtX, newVirtY, linePitches[i],
1804 apertureSize, BankFormat, pitchInc))) {
1805 newLinePitch = linePitches[i];
1806 break;
1807 }
1808 }
1809 }
1810 else {
1811 if (linePitch < minPitch)
1812 linePitch = minPitch;
1813 newLinePitch = scanLineWidth(newVirtX, newVirtY, linePitch,
1814 apertureSize, BankFormat,
1815 pitchInc);
1816 }
1817 if ((newLinePitch < minPitch) || (newLinePitch > maxPitch)) {
1818 p->status = MODE_BAD_WIDTH;
1819 goto lookupNext;
1820 }
1821
1822 /*
1823 * Check that the pixel area required by the new virtual height
1824 * and line pitch isn't too large.
1825 */
1826 if (!xf86CheckModeSize(scrp, newLinePitch, newVirtX, newVirtY)) {
1827 p->status = MODE_MEM_VIRT;
1828 goto lookupNext;
1829 }
1830 }
1831
1832 if (scrp->ValidMode) {
1833 /*
1834 * Give the driver a final say, passing it the proposed virtual
1835 * geometry.
1836 */
1837 scrp->virtualX = newVirtX;
1838 scrp->virtualY = newVirtY;
1839 scrp->displayWidth = newLinePitch;
1840 p->status = (scrp->ValidMode) (scrp, p, FALSE,
1841 MODECHECK_FINAL);
1842
1843 if (p->status != MODE_OK) {
1844 goto lookupNext;
1845 }
1846 }
1847
1848 /* Mode has passed all the tests */
1849 virtX = newVirtX;
1850 virtY = newVirtY;
1851 linePitch = newLinePitch;
1852 p->status = MODE_OK;
1853 numModes++;
1854 }
1855
1856 /*
1857 * If we estimated the virtual size above, we may have filtered away all
1858 * the modes that maximally match that size; scan again to find out and
1859 * fix up if so.
1860 */
1861 if (inferred_virtual) {
1862 int vx = 0, vy = 0;
1863
1864 for (p = scrp->modes; p; p = p->next) {
1865 if (p->HDisplay > vx && p->VDisplay > vy) {
1866 vx = p->HDisplay;
1867 vy = p->VDisplay;
1868 }
1869 }
1870 if (vx < virtX || vy < virtY) {
1871 const int types[] = {
1872 M_T_BUILTIN | M_T_PREFERRED,
1873 M_T_BUILTIN,
1874 M_T_DRIVER | M_T_PREFERRED,
1875 M_T_DRIVER,
1876 0
1877 };
1878 const int ntypes = sizeof(types) / sizeof(int);
1879 int n;
1880
1881 /*
1882 * We did not find the estimated virtual size. So now we want to
1883 * find the largest mode available, but we want to search in the
1884 * modes in the order of "types" listed above.
1885 */
1886 for (n = 0; n < ntypes; n++) {
1887 int type = types[n];
1888
1889 vx = 0;
1890 vy = 0;
1891 for (p = scrp->modes; p; p = p->next) {
1892 /* scan through the modes in the sort order above */
1893 if ((p->type & type) != type)
1894 continue;
1895 if (p->HDisplay > vx && p->VDisplay > vy) {
1896 vx = p->HDisplay;
1897 vy = p->VDisplay;
1898 }
1899 }
1900 if (vx && vy)
1901 /* Found one */
1902 break;
1903 }
1904 xf86DrvMsg(scrp->scrnIndex, X_WARNING,
1905 "Shrinking virtual size estimate from %dx%d to %dx%d\n",
1906 virtX, virtY, vx, vy);
1907 virtX = _VIRTUALX(vx);
1908 virtY = vy;
1909 for (p = scrp->modes; p; p = p->next) {
1910 if (numModes > 0) {
1911 if (p->HDisplay > virtX)
1912 p->status = MODE_VIRTUAL_X;
1913 if (p->VDisplay > virtY)
1914 p->status = MODE_VIRTUAL_Y;
1915 if (p->status != MODE_OK) {
1916 numModes--;
1917 printModeRejectMessage(scrp->scrnIndex, p, p->status);
1918 }
1919 }
1920 }
1921 if (linePitches != NULL) {
1922 for (i = 0; linePitches[i] != 0; i++) {
1923 if ((linePitches[i] >= virtX) &&
1924 (linePitches[i] ==
1925 scanLineWidth(virtX, virtY, linePitches[i],
1926 apertureSize, BankFormat, pitchInc))) {
1927 linePitch = linePitches[i];
1928 break;
1929 }
1930 }
1931 }
1932 else {
1933 linePitch = scanLineWidth(virtX, virtY, minPitch,
1934 apertureSize, BankFormat, pitchInc);
1935 }
1936 }
1937 }
1938
1939 /* Update the ScrnInfoRec parameters */
1940
1941 scrp->virtualX = virtX;
1942 scrp->virtualY = virtY;
1943 scrp->displayWidth = linePitch;
1944
1945 if (numModes <= 0)
1946 return 0;
1947
1948 /* Make the mode list into a circular list by joining up the ends */
1949 p = scrp->modes;
1950 while (p->next != NULL)
1951 p = p->next;
1952 /* p is now the last mode on the list */
1953 p->next = scrp->modes;
1954 scrp->modes->prev = p;
1955
1956 if (minHeight > 0 && virtY < minHeight) {
1957 xf86DrvMsg(scrp->scrnIndex, X_ERROR,
1958 "Virtual height (%d) is too small for the hardware "
1959 "(min %d)\n", virtY, minHeight);
1960 return -1;
1961 }
1962
1963 return numModes;
1964}
1965
1966/*
1967 * xf86DeleteMode
1968 *
1969 * This function removes a mode from a list of modes.
1970 *
1971 * There are different types of mode lists:
1972 *
1973 * - singly linked linear lists, ending in NULL
1974 * - doubly linked linear lists, starting and ending in NULL
1975 * - doubly linked circular lists
1976 *
1977 */
1978
1979void
1980xf86DeleteMode(DisplayModePtr * modeList, DisplayModePtr mode)
1981{
1982 /* Catch the easy/insane cases */
1983 if (modeList == NULL || *modeList == NULL || mode == NULL)
1984 return;
1985
1986 /* If the mode is at the start of the list, move the start of the list */
1987 if (*modeList == mode)
1988 *modeList = mode->next;
1989
1990 /* If mode is the only one on the list, set the list to NULL */
1991 if ((mode == mode->prev) && (mode == mode->next)) {
1992 *modeList = NULL;
1993 }
1994 else {
1995 if ((mode->prev != NULL) && (mode->prev->next == mode))
1996 mode->prev->next = mode->next;
1997 if ((mode->next != NULL) && (mode->next->prev == mode))
1998 mode->next->prev = mode->prev;
1999 }
2000
2001 free(mode->name);
2002 free(mode);
2003}
2004
2005/*
2006 * xf86PruneDriverModes
2007 *
2008 * Remove modes from the driver's mode list which have been marked as
2009 * invalid.
2010 */
2011
2012void
2013xf86PruneDriverModes(ScrnInfoPtr scrp)
2014{
2015 DisplayModePtr first, p, n;
2016
2017 p = scrp->modes;
2018 if (p == NULL)
2019 return;
2020
2021 do {
2022 if (!(first = scrp->modes))
2023 return;
2024 n = p->next;
2025 if (p->status != MODE_OK) {
2026 xf86DeleteMode(&(scrp->modes), p);
2027 }
2028 p = n;
2029 } while (p != NULL && p != first);
2030
2031 /* modePool is no longer needed, turf it */
2032 while (scrp->modePool) {
2033 /*
2034 * A modePool mode's prev field is used to hold a pointer to the
2035 * member of the scrp->modes list for which a match was considered.
2036 * Clear that pointer first, otherwise xf86DeleteMode might get
2037 * confused
2038 */
2039 scrp->modePool->prev = NULL;
2040 xf86DeleteMode(&scrp->modePool, scrp->modePool);
2041 }
2042}
2043
2044/*
2045 * xf86SetCrtcForModes
2046 *
2047 * Goes through the screen's mode list, and initialises the Crtc
2048 * parameters for each mode. The initialisation includes adjustments
2049 * for interlaced and double scan modes.
2050 */
2051void
2052xf86SetCrtcForModes(ScrnInfoPtr scrp, int adjustFlags)
2053{
2054 DisplayModePtr p;
2055
2056 /*
2057 * Store adjustFlags for use with the VidMode extension. There is an
2058 * implicit assumption here that SetCrtcForModes is called once.
2059 */
2060 scrp->adjustFlags = adjustFlags;
2061
2062 p = scrp->modes;
2063 if (p == NULL)
2064 return;
2065
2066 do {
2067 xf86SetModeCrtc(p, adjustFlags);
2068 DebugF("%sMode %s: %d (%d) %d %d (%d) %d %d (%d) %d %d (%d) %d\n",
2069 (p->type & M_T_DEFAULT) ? "Default " : "",
2070 p->name, p->CrtcHDisplay, p->CrtcHBlankStart,
2071 p->CrtcHSyncStart, p->CrtcHSyncEnd, p->CrtcHBlankEnd,
2072 p->CrtcHTotal, p->CrtcVDisplay, p->CrtcVBlankStart,
2073 p->CrtcVSyncStart, p->CrtcVSyncEnd, p->CrtcVBlankEnd,
2074 p->CrtcVTotal);
2075 p = p->next;
2076 } while (p != NULL && p != scrp->modes);
2077}
2078
2079void
2080xf86PrintModes(ScrnInfoPtr scrp)
2081{
2082 DisplayModePtr p;
2083 float hsync, refresh = 0;
2084 const char *desc, *desc2, *prefix, *uprefix;
2085
2086 if (scrp == NULL)
2087 return;
2088
2089 xf86DrvMsg(scrp->scrnIndex, scrp->virtualFrom, "Virtual size is %dx%d "
2090 "(pitch %d)\n", scrp->virtualX, scrp->virtualY,
2091 scrp->displayWidth);
2092
2093 p = scrp->modes;
2094 if (p == NULL)
2095 return;
2096
2097 do {
2098 desc = desc2 = "";
2099 hsync = xf86ModeHSync(p);
2100 refresh = xf86ModeVRefresh(p);
2101 if (p->Flags & V_INTERLACE) {
2102 desc = " (I)";
2103 }
2104 if (p->Flags & V_DBLSCAN) {
2105 desc = " (D)";
2106 }
2107 if (p->VScan > 1) {
2108 desc2 = " (VScan)";
2109 }
2110 if (p->type & M_T_BUILTIN)
2111 prefix = "Built-in mode";
2112 else if (p->type & M_T_DEFAULT)
2113 prefix = "Default mode";
2114 else if (p->type & M_T_DRIVER)
2115 prefix = "Driver mode";
2116 else
2117 prefix = "Mode";
2118 if (p->type & M_T_USERDEF)
2119 uprefix = "*";
2120 else
2121 uprefix = " ";
2122 if (hsync == 0 || refresh == 0) {
2123 if (p->name)
2124 xf86DrvMsg(scrp->scrnIndex, X_CONFIG,
2125 "%s%s \"%s\"\n", uprefix, prefix, p->name);
2126 else
2127 xf86DrvMsg(scrp->scrnIndex, X_PROBED,
2128 "%s%s %dx%d (unnamed)\n",
2129 uprefix, prefix, p->HDisplay, p->VDisplay);
2130 }
2131 else if (p->Clock == p->SynthClock) {
2132 xf86DrvMsg(scrp->scrnIndex, X_CONFIG,
2133 "%s%s \"%s\": %.1f MHz, %.1f kHz, %.1f Hz%s%s\n",
2134 uprefix, prefix, p->name, p->Clock / 1000.0,
2135 hsync, refresh, desc, desc2);
2136 }
2137 else {
2138 xf86DrvMsg(scrp->scrnIndex, X_CONFIG,
2139 "%s%s \"%s\": %.1f MHz (scaled from %.1f MHz), "
2140 "%.1f kHz, %.1f Hz%s%s\n",
2141 uprefix, prefix, p->name, p->Clock / 1000.0,
2142 p->SynthClock / 1000.0, hsync, refresh, desc, desc2);
2143 }
2144 if (hsync != 0 && refresh != 0)
2145 xf86PrintModeline(scrp->scrnIndex, p);
2146 p = p->next;
2147 } while (p != NULL && p != scrp->modes);
2148}