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 "xf86Crtc.h"
90 #include "os.h"
91 #include "servermd.h"
92 #include "globals.h"
93 #include "xf86.h"
94 #include "xf86Priv.h"
95 #include "edid.h"
96
97 static void
printModeRejectMessage(int index,DisplayModePtr p,int status)98 printModeRejectMessage(int index, DisplayModePtr p, int status)
99 {
100 const char *type;
101
102 if (p->type & M_T_BUILTIN)
103 type = "built-in ";
104 else if (p->type & M_T_DEFAULT)
105 type = "default ";
106 else if (p->type & M_T_DRIVER)
107 type = "driver ";
108 else
109 type = "";
110
111 xf86DrvMsg(index, X_INFO, "Not using %smode \"%s\" (%s)\n", type, p->name,
112 xf86ModeStatusToString(status));
113 }
114
115 /*
116 * Find closest clock to given frequency (in kHz). This assumes the
117 * number of clocks is greater than zero.
118 */
119 static int
xf86GetNearestClock(ScrnInfoPtr scrp,int freq,Bool allowDiv2,int DivFactor,int MulFactor,int * divider)120 xf86GetNearestClock(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
157 const char *
xf86ModeStatusToString(ModeStatus status)158 xf86ModeStatusToString(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 */
246 void
xf86ShowClockRanges(ScrnInfoPtr scrp,ClockRangePtr clockRanges)247 xf86ShowClockRanges(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
299 static Bool
modeInClockRange(ClockRangePtr cp,DisplayModePtr p)300 modeInClockRange(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 */
312 static ClockRangePtr
xf86FindClockRangeForMode(ClockRangePtr clockRanges,DisplayModePtr p)313 xf86FindClockRangeForMode(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 */
325 static ModeStatus
xf86HandleBuiltinMode(ScrnInfoPtr scrp,DisplayModePtr p,DisplayModePtr modep,ClockRangePtr clockRanges,Bool allowDiv2)326 xf86HandleBuiltinMode(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
454 static ModeStatus
xf86LookupMode(ScrnInfoPtr scrp,DisplayModePtr modep,ClockRangePtr clockRanges,LookupModeFlags strategy)455 xf86LookupMode(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 = ARRAY_SIZE(types);
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 */
702 ModeStatus
xf86CheckModeForMonitor(DisplayModePtr mode,MonPtr monitor)703 xf86CheckModeForMonitor(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 */
783 static Bool
xf86CheckModeSize(ScrnInfoPtr scrp,int w,int x,int y)784 xf86CheckModeSize(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 */
845
846 static ModeStatus
xf86InitialCheckModeForDriver(ScrnInfoPtr scrp,DisplayModePtr mode,ClockRangePtr clockRanges,LookupModeFlags strategy,int maxPitch,int virtualX,int virtualY)847 xf86InitialCheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode,
848 ClockRangePtr clockRanges,
849 LookupModeFlags strategy,
850 int maxPitch, int virtualX, int virtualY)
851 {
852 ClockRangePtr cp;
853 ModeStatus status;
854 Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0;
855 int i, needDiv2;
856
857 /* Sanity checks */
858 if (!scrp || !mode || !clockRanges) {
859 ErrorF("xf86InitialCheckModeForDriver: "
860 "called with invalid parameters\n");
861 return MODE_ERROR;
862 }
863
864 DebugF("xf86InitialCheckModeForDriver(%p, %p %s, %p, 0x%x, %d, %d, %d)\n",
865 scrp, mode, mode->name, clockRanges, strategy, maxPitch, virtualX,
866 virtualY);
867
868 /* Some basic mode validity checks */
869 if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart ||
870 mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal)
871 return MODE_H_ILLEGAL;
872
873 if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart ||
874 mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal)
875 return MODE_V_ILLEGAL;
876
877 if (!xf86CheckModeSize(scrp, mode->HDisplay, mode->HDisplay,
878 mode->VDisplay))
879 return MODE_MEM;
880
881 if (maxPitch > 0 && mode->HDisplay > maxPitch)
882 return MODE_BAD_WIDTH;
883
884 if (virtualX > 0 && mode->HDisplay > virtualX)
885 return MODE_VIRTUAL_X;
886
887 if (virtualY > 0 && mode->VDisplay > virtualY)
888 return MODE_VIRTUAL_Y;
889
890 /*
891 * The use of the DisplayModeRec's Crtc* and SynthClock elements below is
892 * provisional, in that they are later reused by the driver at mode-set
893 * time. Here, they are temporarily enlisted to contain the mode timings
894 * as seen by the CRT or panel (rather than the CRTC). The driver's
895 * ValidMode() is allowed to modify these so it can deal with such things
896 * as mode stretching and/or centering. The driver should >NOT< modify the
897 * user-supplied values as these are reported back when mode validation is
898 * said and done.
899 */
900 /*
901 * NOTE: We (ab)use the mode->Crtc* values here to store timing
902 * information for the calculation of Hsync and Vrefresh. Before
903 * these values are calculated the driver is given the opportunity
904 * to either set these HSync and VRefresh itself or modify the timing
905 * values.
906 * The difference to the final calculation is small but imortand:
907 * here we pass the flag INTERLACE_HALVE_V regardless if the driver
908 * sets it or not. This way our calculation of VRefresh has the same
909 * effect as if we do if (flags & V_INTERLACE) refresh *= 2.0
910 * This dual use of the mode->Crtc* values will certainly create
911 * confusion and is bad software design. However since it's part of
912 * the driver API it's hard to change.
913 */
914
915 if (scrp->ValidMode) {
916
917 xf86SetModeCrtc(mode, INTERLACE_HALVE_V);
918
919 cp = xf86FindClockRangeForMode(clockRanges, mode);
920 if (!cp)
921 return MODE_CLOCK_RANGE;
922
923 if (cp->ClockMulFactor < 1)
924 cp->ClockMulFactor = 1;
925 if (cp->ClockDivFactor < 1)
926 cp->ClockDivFactor = 1;
927
928 /*
929 * XXX The effect of clock dividers and multipliers on the monitor's
930 * pixel clock needs to be verified.
931 */
932 if (scrp->progClock) {
933 mode->SynthClock = mode->Clock;
934 }
935 else {
936 i = xf86GetNearestClock(scrp, mode->Clock, allowDiv2,
937 cp->ClockDivFactor, cp->ClockMulFactor,
938 &needDiv2);
939 mode->SynthClock = (scrp->clock[i] * cp->ClockDivFactor) /
940 cp->ClockMulFactor;
941 if (needDiv2 & V_CLKDIV2)
942 mode->SynthClock /= 2;
943 }
944
945 status = (*scrp->ValidMode) (scrp, mode, FALSE,
946 MODECHECK_INITIAL);
947 if (status != MODE_OK)
948 return status;
949
950 if (mode->HSync <= 0.0)
951 mode->HSync = (float) mode->SynthClock / (float) mode->CrtcHTotal;
952 if (mode->VRefresh <= 0.0)
953 mode->VRefresh = (mode->SynthClock * 1000.0)
954 / (mode->CrtcHTotal * mode->CrtcVTotal);
955 }
956
957 mode->HSync = xf86ModeHSync(mode);
958 mode->VRefresh = xf86ModeVRefresh(mode);
959
960 /* Assume it is OK */
961 return MODE_OK;
962 }
963
964 /*
965 * xf86CheckModeForDriver
966 *
967 * This function is for checking modes while the server is running (for
968 * use mainly by the VidMode extension).
969 *
970 * This function checks if a mode satisfies a driver's requirements:
971 * - width lies within the line pitch
972 * - mode size fits within virtual size
973 * - horizontal/vertical timings are in range
974 *
975 * This function takes the following parameters:
976 * scrp ScrnInfoPtr
977 * mode mode to check
978 * flags not (currently) used
979 *
980 * In addition, the following fields from the ScrnInfoRec are used:
981 * virtualX virtual width
982 * virtualY virtual height
983 * clockRanges allowable clock ranges
984 */
985
986 ModeStatus
xf86CheckModeForDriver(ScrnInfoPtr scrp,DisplayModePtr mode,int flags)987 xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, int flags)
988 {
989 ClockRangePtr cp;
990 int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1;
991 int extraFlags = 0;
992 int clockIndex = -1;
993 int MulFactor = 1;
994 int DivFactor = 1;
995 int ModePrivFlags = 0;
996 ModeStatus status = MODE_NOMODE;
997
998 /* Some sanity checking */
999 if (scrp == NULL || (!scrp->progClock && scrp->numClocks == 0)) {
1000 ErrorF("xf86CheckModeForDriver: called with invalid scrnInfoRec\n");
1001 return MODE_ERROR;
1002 }
1003 if (mode == NULL) {
1004 ErrorF("xf86CheckModeForDriver: called with invalid modep\n");
1005 return MODE_ERROR;
1006 }
1007
1008 /* Check the mode size */
1009 if (mode->HDisplay > scrp->virtualX)
1010 return MODE_VIRTUAL_X;
1011
1012 if (mode->VDisplay > scrp->virtualY)
1013 return MODE_VIRTUAL_Y;
1014
1015 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) {
1016 /* DivFactor and MulFactor must be > 0 */
1017 cp->ClockDivFactor = max(1, cp->ClockDivFactor);
1018 cp->ClockMulFactor = max(1, cp->ClockMulFactor);
1019 }
1020
1021 if (scrp->progClock) {
1022 /* Check clock is in range */
1023 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) {
1024 if (modeInClockRange(cp, mode))
1025 break;
1026 }
1027 if (cp == NULL) {
1028 return MODE_CLOCK_RANGE;
1029 }
1030 /*
1031 * If programmable clock the required mode has been found
1032 */
1033 DivFactor = cp->ClockDivFactor;
1034 MulFactor = cp->ClockMulFactor;
1035 ModePrivFlags = cp->PrivFlags;
1036 }
1037 else {
1038 status = MODE_CLOCK_RANGE;
1039 /* Check clock is in range */
1040 for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) {
1041 if (modeInClockRange(cp, mode)) {
1042 /*
1043 * Clock is in range, so if it is not a programmable clock,
1044 * find a matching clock.
1045 */
1046
1047 i = xf86GetNearestClock(scrp, mode->Clock, 0,
1048 cp->ClockDivFactor, cp->ClockMulFactor,
1049 &k);
1050 /*
1051 * If the clock is too far from the requested clock, this
1052 * mode is no good.
1053 */
1054 if (k & V_CLKDIV2)
1055 gap = abs((mode->Clock * 2) -
1056 ((scrp->clock[i] * cp->ClockDivFactor) /
1057 cp->ClockMulFactor));
1058 else
1059 gap = abs(mode->Clock -
1060 ((scrp->clock[i] * cp->ClockDivFactor) /
1061 cp->ClockMulFactor));
1062 if (gap > minimumGap) {
1063 status = MODE_NOCLOCK;
1064 continue;
1065 }
1066
1067 DivFactor = cp->ClockDivFactor;
1068 MulFactor = cp->ClockMulFactor;
1069 ModePrivFlags = cp->PrivFlags;
1070 extraFlags = k;
1071 clockIndex = i;
1072 break;
1073 }
1074 }
1075 if (cp == NULL)
1076 return status;
1077 }
1078
1079 /* Fill in the mode parameters */
1080 if (scrp->progClock) {
1081 mode->ClockIndex = -1;
1082 mode->SynthClock = (mode->Clock * MulFactor) / DivFactor;
1083 }
1084 else {
1085 mode->Clock = (scrp->clock[clockIndex] * DivFactor) / MulFactor;
1086 mode->ClockIndex = clockIndex;
1087 mode->SynthClock = scrp->clock[clockIndex];
1088 if (extraFlags & V_CLKDIV2) {
1089 mode->Clock /= 2;
1090 mode->SynthClock /= 2;
1091 }
1092 }
1093 mode->PrivFlags = ModePrivFlags;
1094
1095 return MODE_OK;
1096 }
1097
1098 static int
inferVirtualSize(ScrnInfoPtr scrp,DisplayModePtr modes,int * vx,int * vy)1099 inferVirtualSize(ScrnInfoPtr scrp, DisplayModePtr modes, int *vx, int *vy)
1100 {
1101 float aspect = 0.0;
1102 MonPtr mon = scrp->monitor;
1103 xf86MonPtr DDC;
1104 int x = 0, y = 0;
1105 DisplayModePtr mode;
1106
1107 if (!mon)
1108 return 0;
1109 DDC = mon->DDC;
1110
1111 if (DDC && DDC->ver.revision >= 4) {
1112 /* For 1.4, we might actually get native pixel format. How novel. */
1113 if (PREFERRED_TIMING_MODE(DDC->features.msc)) {
1114 for (mode = modes; mode; mode = mode->next) {
1115 if (mode->type & (M_T_DRIVER | M_T_PREFERRED)) {
1116 x = mode->HDisplay;
1117 y = mode->VDisplay;
1118 goto found;
1119 }
1120 }
1121 }
1122 /*
1123 * Even if we don't, we might get aspect ratio from extra CVT info
1124 * or from the monitor size fields. TODO.
1125 */
1126 }
1127
1128 /*
1129 * Technically this triggers if either is zero. That wasn't legal
1130 * before EDID 1.4, but right now we'll get that wrong. TODO.
1131 */
1132 if (!aspect) {
1133 if (!mon->widthmm || !mon->heightmm)
1134 aspect = 4.0 / 3.0;
1135 else
1136 aspect = (float) mon->widthmm / (float) mon->heightmm;
1137 }
1138
1139 /* find the largest M_T_DRIVER mode with that aspect ratio */
1140 for (mode = modes; mode; mode = mode->next) {
1141 float mode_aspect, metaspect;
1142
1143 if (!(mode->type & (M_T_DRIVER | M_T_USERDEF)))
1144 continue;
1145 mode_aspect = (float) mode->HDisplay / (float) mode->VDisplay;
1146 metaspect = aspect / mode_aspect;
1147 /* 5% slop or so, since we only get size in centimeters */
1148 if (fabs(1.0 - metaspect) < 0.05) {
1149 if ((mode->HDisplay > x) && (mode->VDisplay > y)) {
1150 x = mode->HDisplay;
1151 y = mode->VDisplay;
1152 }
1153 }
1154 }
1155
1156 if (!x || !y) {
1157 xf86DrvMsg(scrp->scrnIndex, X_WARNING,
1158 "Unable to estimate virtual size\n");
1159 return 0;
1160 }
1161
1162 found:
1163 *vx = x;
1164 *vy = y;
1165
1166 xf86DrvMsg(scrp->scrnIndex, X_INFO,
1167 "Estimated virtual size for aspect ratio %.4f is %dx%d\n",
1168 aspect, *vx, *vy);
1169
1170 return 1;
1171 }
1172
1173 /* Least common multiple */
1174 static unsigned int
LCM(unsigned int x,unsigned int y)1175 LCM(unsigned int x, unsigned int y)
1176 {
1177 unsigned int m = x, n = y, o;
1178
1179 while ((o = m % n)) {
1180 m = n;
1181 n = o;
1182 }
1183
1184 return (x / n) * y;
1185 }
1186
1187 /*
1188 * Given various screen attributes, determine the minimum scanline width such
1189 * that each scanline is server and DDX padded and any pixels with imbedded
1190 * bank boundaries are off-screen. This function returns -1 if such a width
1191 * cannot exist.
1192 */
1193 static int
scanLineWidth(unsigned int xsize,unsigned int ysize,unsigned int width,unsigned long BankSize,PixmapFormatRec * pBankFormat,unsigned int nWidthUnit)1194 scanLineWidth(unsigned int xsize, /* pixels */
1195 unsigned int ysize, /* pixels */
1196 unsigned int width, /* pixels */
1197 unsigned long BankSize, /* char's */
1198 PixmapFormatRec * pBankFormat, unsigned int nWidthUnit /* bits */
1199 )
1200 {
1201 unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit;
1202 unsigned long minBitsPerScanline, maxBitsPerScanline;
1203
1204 /* Sanity checks */
1205
1206 if (!nWidthUnit || !pBankFormat)
1207 return -1;
1208
1209 nBitsPerBank = BankSize * 8;
1210 if (nBitsPerBank % pBankFormat->scanlinePad)
1211 return -1;
1212
1213 if (xsize > width)
1214 width = xsize;
1215 nBitsPerScanlinePadUnit = LCM(pBankFormat->scanlinePad, nWidthUnit);
1216 nBitsPerScanline =
1217 (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) /
1218 nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit;
1219 width = nBitsPerScanline / pBankFormat->bitsPerPixel;
1220
1221 if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel))
1222 return (int) width;
1223
1224 /*
1225 * Scanlines will be server-pad aligned at this point. They will also be
1226 * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded
1227 * bank boundaries are off-screen.
1228 *
1229 * It seems reasonable to limit total frame buffer size to 1/16 of the
1230 * theoretical maximum address space size. On a machine with 32-bit
1231 * addresses (to 8-bit quantities) this turns out to be 256MB. Not only
1232 * does this provide a simple limiting condition for the loops below, but
1233 * it also prevents unsigned long wraparounds.
1234 */
1235 if (!ysize)
1236 return -1;
1237
1238 minBitsPerScanline = xsize * pBankFormat->bitsPerPixel;
1239 if (minBitsPerScanline > nBitsPerBank)
1240 return -1;
1241
1242 if (ysize == 1)
1243 return (int) width;
1244
1245 maxBitsPerScanline =
1246 (((unsigned long) (-1) >> 1) - minBitsPerScanline) / (ysize - 1);
1247 while (nBitsPerScanline <= maxBitsPerScanline) {
1248 unsigned long BankBase, BankUnit;
1249
1250 BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) *
1251 nBitsPerBank;
1252 if (!(BankUnit % nBitsPerScanline))
1253 return (int) width;
1254
1255 for (BankBase = BankUnit;; BankBase += nBitsPerBank) {
1256 unsigned long x, y;
1257
1258 y = BankBase / nBitsPerScanline;
1259 if (y >= ysize)
1260 return (int) width;
1261
1262 x = BankBase % nBitsPerScanline;
1263 if (!(x % pBankFormat->bitsPerPixel))
1264 continue;
1265
1266 if (x < minBitsPerScanline) {
1267 /*
1268 * Skip ahead certain widths by dividing the excess scanline
1269 * amongst the y's.
1270 */
1271 y *= nBitsPerScanlinePadUnit;
1272 nBitsPerScanline += ((x + y - 1) / y) * nBitsPerScanlinePadUnit;
1273 width = nBitsPerScanline / pBankFormat->bitsPerPixel;
1274 break;
1275 }
1276
1277 if (BankBase != BankUnit)
1278 continue;
1279
1280 if (!(nBitsPerScanline % x))
1281 return (int) width;
1282
1283 BankBase = ((nBitsPerScanline - minBitsPerScanline) /
1284 (nBitsPerScanline - x)) * BankUnit;
1285 }
1286 }
1287
1288 return -1;
1289 }
1290
1291 /*
1292 * xf86ValidateModes
1293 *
1294 * This function takes a set of mode names, modes and limiting conditions,
1295 * and selects a set of modes and parameters based on those conditions.
1296 *
1297 * This function takes the following parameters:
1298 * scrp ScrnInfoPtr
1299 * availModes the list of modes available for the monitor
1300 * modeNames (optional) list of mode names that the screen is requesting
1301 * clockRanges a list of clock ranges
1302 * linePitches (optional) a list of line pitches
1303 * minPitch (optional) minimum line pitch (in pixels)
1304 * maxPitch (optional) maximum line pitch (in pixels)
1305 * pitchInc (mandatory) pitch increment (in bits)
1306 * minHeight (optional) minimum virtual height (in pixels)
1307 * maxHeight (optional) maximum virtual height (in pixels)
1308 * virtualX (optional) virtual width requested (in pixels)
1309 * virtualY (optional) virtual height requested (in pixels)
1310 * apertureSize size of video aperture (in bytes)
1311 * strategy how to decide which mode to use from multiple modes with
1312 * the same name
1313 *
1314 * In addition, the following fields from the ScrnInfoRec are used:
1315 * clocks a list of discrete clocks
1316 * numClocks number of discrete clocks
1317 * progClock clock is programmable
1318 * monitor pointer to structure for monitor section
1319 * fbFormat format of the framebuffer
1320 * videoRam video memory size
1321 * xInc horizontal timing increment (defaults to 8 pixels)
1322 *
1323 * The function fills in the following ScrnInfoRec fields:
1324 * modePool A subset of the modes available to the monitor which
1325 * are compatible with the driver.
1326 * modes one mode entry for each of the requested modes, with the
1327 * status field filled in to indicate if the mode has been
1328 * accepted or not.
1329 * virtualX the resulting virtual width
1330 * virtualY the resulting virtual height
1331 * displayWidth the resulting line pitch
1332 *
1333 * The function's return value is the number of matching modes found, or -1
1334 * if an unrecoverable error was encountered.
1335 */
1336
1337 int
xf86ValidateModes(ScrnInfoPtr scrp,DisplayModePtr availModes,const char ** modeNames,ClockRangePtr clockRanges,int * linePitches,int minPitch,int maxPitch,int pitchInc,int minHeight,int maxHeight,int virtualX,int virtualY,int apertureSize,LookupModeFlags strategy)1338 xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes,
1339 const char **modeNames, ClockRangePtr clockRanges,
1340 int *linePitches, int minPitch, int maxPitch, int pitchInc,
1341 int minHeight, int maxHeight, int virtualX, int virtualY,
1342 int apertureSize, LookupModeFlags strategy)
1343 {
1344 DisplayModePtr p, q, r, new, last, *endp;
1345 int i, numModes = 0;
1346 ModeStatus status;
1347 int linePitch = -1, virtX = 0, virtY = 0;
1348 int newLinePitch, newVirtX, newVirtY;
1349 int modeSize; /* in pixels */
1350 Bool validateAllDefaultModes = FALSE;
1351 Bool userModes = FALSE;
1352 int saveType;
1353 PixmapFormatRec *BankFormat;
1354 ClockRangePtr cp;
1355 int numTimings = 0;
1356 range hsync[MAX_HSYNC];
1357 range vrefresh[MAX_VREFRESH];
1358 Bool inferred_virtual = FALSE;
1359
1360 DebugF
1361 ("xf86ValidateModes(%p, %p, %p, %p,\n\t\t %p, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x)\n",
1362 scrp, availModes, modeNames, clockRanges, linePitches, minPitch,
1363 maxPitch, pitchInc, minHeight, maxHeight, virtualX, virtualY,
1364 apertureSize, strategy);
1365
1366 /* Some sanity checking */
1367 if (scrp == NULL || scrp->name == NULL || !scrp->monitor ||
1368 (!scrp->progClock && scrp->numClocks == 0)) {
1369 ErrorF("xf86ValidateModes: called with invalid scrnInfoRec\n");
1370 return -1;
1371 }
1372 if (linePitches != NULL && linePitches[0] <= 0) {
1373 ErrorF("xf86ValidateModes: called with invalid linePitches\n");
1374 return -1;
1375 }
1376 if (pitchInc <= 0) {
1377 ErrorF("xf86ValidateModes: called with invalid pitchInc\n");
1378 return -1;
1379 }
1380 if ((virtualX > 0) != (virtualY > 0)) {
1381 ErrorF("xf86ValidateModes: called with invalid virtual resolution\n");
1382 return -1;
1383 }
1384
1385 /*
1386 * If requested by the driver, allow missing hsync and/or vrefresh ranges
1387 * in the monitor section.
1388 */
1389 if (strategy & LOOKUP_OPTIONAL_TOLERANCES) {
1390 strategy &= ~LOOKUP_OPTIONAL_TOLERANCES;
1391 }
1392 else {
1393 const char *type = "";
1394 Bool specified = FALSE;
1395
1396 if (scrp->monitor->nHsync <= 0) {
1397 if (numTimings > 0) {
1398 scrp->monitor->nHsync = numTimings;
1399 for (i = 0; i < numTimings; i++) {
1400 scrp->monitor->hsync[i].lo = hsync[i].lo;
1401 scrp->monitor->hsync[i].hi = hsync[i].hi;
1402 }
1403 }
1404 else {
1405 scrp->monitor->hsync[0].lo = 31.5;
1406 scrp->monitor->hsync[0].hi = 48.0;
1407 scrp->monitor->nHsync = 1;
1408 }
1409 type = "default ";
1410 }
1411 else {
1412 specified = TRUE;
1413 }
1414 for (i = 0; i < scrp->monitor->nHsync; i++) {
1415 if (scrp->monitor->hsync[i].lo == scrp->monitor->hsync[i].hi)
1416 xf86DrvMsg(scrp->scrnIndex, X_INFO,
1417 "%s: Using %shsync value of %.2f kHz\n",
1418 scrp->monitor->id, type, scrp->monitor->hsync[i].lo);
1419 else
1420 xf86DrvMsg(scrp->scrnIndex, X_INFO,
1421 "%s: Using %shsync range of %.2f-%.2f kHz\n",
1422 scrp->monitor->id, type,
1423 scrp->monitor->hsync[i].lo,
1424 scrp->monitor->hsync[i].hi);
1425 }
1426
1427 type = "";
1428 if (scrp->monitor->nVrefresh <= 0) {
1429 if (numTimings > 0) {
1430 scrp->monitor->nVrefresh = numTimings;
1431 for (i = 0; i < numTimings; i++) {
1432 scrp->monitor->vrefresh[i].lo = vrefresh[i].lo;
1433 scrp->monitor->vrefresh[i].hi = vrefresh[i].hi;
1434 }
1435 }
1436 else {
1437 scrp->monitor->vrefresh[0].lo = 50;
1438 scrp->monitor->vrefresh[0].hi = 70;
1439 scrp->monitor->nVrefresh = 1;
1440 }
1441 type = "default ";
1442 }
1443 else {
1444 specified = TRUE;
1445 }
1446 for (i = 0; i < scrp->monitor->nVrefresh; i++) {
1447 if (scrp->monitor->vrefresh[i].lo == scrp->monitor->vrefresh[i].hi)
1448 xf86DrvMsg(scrp->scrnIndex, X_INFO,
1449 "%s: Using %svrefresh value of %.2f Hz\n",
1450 scrp->monitor->id, type,
1451 scrp->monitor->vrefresh[i].lo);
1452 else
1453 xf86DrvMsg(scrp->scrnIndex, X_INFO,
1454 "%s: Using %svrefresh range of %.2f-%.2f Hz\n",
1455 scrp->monitor->id, type,
1456 scrp->monitor->vrefresh[i].lo,
1457 scrp->monitor->vrefresh[i].hi);
1458 }
1459
1460 type = "";
1461 if (!scrp->monitor->maxPixClock && !specified) {
1462 type = "default ";
1463 scrp->monitor->maxPixClock = 65000.0;
1464 }
1465 if (scrp->monitor->maxPixClock) {
1466 xf86DrvMsg(scrp->scrnIndex, X_INFO,
1467 "%s: Using %smaximum pixel clock of %.2f MHz\n",
1468 scrp->monitor->id, type,
1469 (float) scrp->monitor->maxPixClock / 1000.0);
1470 }
1471 }
1472
1473 /*
1474 * Store the clockRanges for later use by the VidMode extension.
1475 */
1476 nt_list_for_each_entry(cp, clockRanges, next) {
1477 ClockRangePtr newCR = xnfalloc(sizeof(ClockRange));
1478 memcpy(newCR, cp, sizeof(ClockRange));
1479 newCR->next = NULL;
1480 if (scrp->clockRanges == NULL)
1481 scrp->clockRanges = newCR;
1482 else
1483 nt_list_append(newCR, scrp->clockRanges, ClockRange, next);
1484 }
1485
1486 /* Determine which pixmap format to pass to scanLineWidth() */
1487 if (scrp->depth > 4)
1488 BankFormat = &scrp->fbFormat;
1489 else
1490 BankFormat = xf86GetPixFormat(scrp, 1); /* >not< scrp->depth! */
1491
1492 if (scrp->xInc <= 0)
1493 scrp->xInc = 8; /* Suitable for VGA and others */
1494
1495 #define _VIRTUALX(x) ((((x) + scrp->xInc - 1) / scrp->xInc) * scrp->xInc)
1496
1497 /*
1498 * Determine maxPitch if it wasn't given explicitly. Note linePitches
1499 * always takes precedence if is non-NULL. In that case the minPitch and
1500 * maxPitch values passed are ignored.
1501 */
1502 if (linePitches) {
1503 minPitch = maxPitch = linePitches[0];
1504 for (i = 1; linePitches[i] > 0; i++) {
1505 if (linePitches[i] > maxPitch)
1506 maxPitch = linePitches[i];
1507 if (linePitches[i] < minPitch)
1508 minPitch = linePitches[i];
1509 }
1510 }
1511
1512 /*
1513 * Initialise virtX and virtY if the values are fixed.
1514 */
1515 if (virtualY > 0) {
1516 if (maxHeight > 0 && virtualY > maxHeight) {
1517 xf86DrvMsg(scrp->scrnIndex, X_ERROR,
1518 "Virtual height (%d) is too large for the hardware "
1519 "(max %d)\n", virtualY, maxHeight);
1520 return -1;
1521 }
1522
1523 if (minHeight > 0 && virtualY < minHeight) {
1524 xf86DrvMsg(scrp->scrnIndex, X_ERROR,
1525 "Virtual height (%d) is too small for the hardware "
1526 "(min %d)\n", virtualY, minHeight);
1527 return -1;
1528 }
1529
1530 virtualX = _VIRTUALX(virtualX);
1531 if (linePitches != NULL) {
1532 for (i = 0; linePitches[i] != 0; i++) {
1533 if ((linePitches[i] >= virtualX) &&
1534 (linePitches[i] ==
1535 scanLineWidth(virtualX, virtualY, linePitches[i],
1536 apertureSize, BankFormat, pitchInc))) {
1537 linePitch = linePitches[i];
1538 break;
1539 }
1540 }
1541 }
1542 else {
1543 linePitch = scanLineWidth(virtualX, virtualY, minPitch,
1544 apertureSize, BankFormat, pitchInc);
1545 }
1546
1547 if ((linePitch < minPitch) || (linePitch > maxPitch)) {
1548 xf86DrvMsg(scrp->scrnIndex, X_ERROR,
1549 "Virtual width (%d) is too large for the hardware "
1550 "(max %d)\n", virtualX, maxPitch);
1551 return -1;
1552 }
1553
1554 if (!xf86CheckModeSize(scrp, linePitch, virtualX, virtualY)) {
1555 xf86DrvMsg(scrp->scrnIndex, X_ERROR,
1556 "Virtual size (%dx%d) (pitch %d) exceeds video memory\n",
1557 virtualX, virtualY, linePitch);
1558 return -1;
1559 }
1560
1561 virtX = virtualX;
1562 virtY = virtualY;
1563 }
1564 else if (!modeNames || !*modeNames) {
1565 /* No virtual size given in the config, try to infer */
1566 /* XXX this doesn't take m{in,ax}Pitch into account; oh well */
1567 inferred_virtual = inferVirtualSize(scrp, availModes, &virtX, &virtY);
1568 if (inferred_virtual)
1569 linePitch = scanLineWidth(virtX, virtY, minPitch, apertureSize,
1570 BankFormat, pitchInc);
1571 }
1572
1573 /* Print clock ranges and scaled clocks */
1574 xf86ShowClockRanges(scrp, clockRanges);
1575
1576 /*
1577 * If scrp->modePool hasn't been setup yet, set it up now. This allows the
1578 * modes that the driver definitely can't use to be weeded out early. Note
1579 * that a modePool mode's prev field is used to hold a pointer to the
1580 * member of the scrp->modes list for which a match was considered.
1581 */
1582 if (scrp->modePool == NULL) {
1583 q = NULL;
1584 for (p = availModes; p != NULL; p = p->next) {
1585 status = xf86InitialCheckModeForDriver(scrp, p, clockRanges,
1586 strategy, maxPitch,
1587 virtX, virtY);
1588
1589 if (status == MODE_OK) {
1590 status = xf86CheckModeForMonitor(p, scrp->monitor);
1591 }
1592
1593 if (status == MODE_OK) {
1594 new = xnfalloc(sizeof(DisplayModeRec));
1595 *new = *p;
1596 new->next = NULL;
1597 if (!q) {
1598 scrp->modePool = new;
1599 }
1600 else {
1601 q->next = new;
1602 }
1603 new->prev = NULL;
1604 q = new;
1605 q->name = xnfstrdup(p->name);
1606 q->status = MODE_OK;
1607 }
1608 else {
1609 printModeRejectMessage(scrp->scrnIndex, p, status);
1610 }
1611 }
1612
1613 if (scrp->modePool == NULL) {
1614 xf86DrvMsg(scrp->scrnIndex, X_WARNING, "Mode pool is empty\n");
1615 return 0;
1616 }
1617 }
1618 else {
1619 for (p = scrp->modePool; p != NULL; p = p->next) {
1620 p->prev = NULL;
1621 p->status = MODE_OK;
1622 }
1623 }
1624
1625 /*
1626 * Allocate one entry in scrp->modes for each named mode.
1627 */
1628 while (scrp->modes)
1629 xf86DeleteMode(&scrp->modes, scrp->modes);
1630 endp = &scrp->modes;
1631 last = NULL;
1632 if (modeNames != NULL) {
1633 for (i = 0; modeNames[i] != NULL; i++) {
1634 userModes = TRUE;
1635 new = xnfcalloc(1, sizeof(DisplayModeRec));
1636 new->prev = last;
1637 new->type = M_T_USERDEF;
1638 new->name = xnfstrdup(modeNames[i]);
1639 if (new->prev)
1640 new->prev->next = new;
1641 *endp = last = new;
1642 endp = &new->next;
1643 }
1644 }
1645
1646 /* Lookup each mode */
1647 #ifdef PANORAMIX
1648 if (noPanoramiXExtension)
1649 validateAllDefaultModes = TRUE;
1650 #endif
1651
1652 for (p = scrp->modes;; p = p->next) {
1653 Bool repeat;
1654
1655 /*
1656 * If the supplied mode names don't produce a valid mode, scan through
1657 * unconsidered modePool members until one survives validation. This
1658 * is done in decreasing order by mode pixel area.
1659 */
1660
1661 if (p == NULL) {
1662 if ((numModes > 0) && !validateAllDefaultModes)
1663 break;
1664
1665 validateAllDefaultModes = TRUE;
1666 r = NULL;
1667 modeSize = 0;
1668 for (q = scrp->modePool; q != NULL; q = q->next) {
1669 if ((q->prev == NULL) && (q->status == MODE_OK)) {
1670 /*
1671 * Deal with the case where this mode wasn't considered
1672 * because of a builtin mode of the same name.
1673 */
1674 for (p = scrp->modes; p != NULL; p = p->next) {
1675 if ((p->status != MODE_OK) && !strcmp(p->name, q->name))
1676 break;
1677 }
1678
1679 if (p != NULL)
1680 q->prev = p;
1681 else {
1682 /*
1683 * A quick check to not allow default modes with
1684 * horizontal timing parameters that CRTs may have
1685 * problems with.
1686 */
1687 if (!scrp->monitor->reducedblanking &&
1688 (q->type & M_T_DEFAULT) &&
1689 ((double) q->HTotal / (double) q->HDisplay) < 1.15)
1690 continue;
1691
1692 if (modeSize < (q->HDisplay * q->VDisplay)) {
1693 r = q;
1694 modeSize = q->HDisplay * q->VDisplay;
1695 }
1696 }
1697 }
1698 }
1699
1700 if (r == NULL)
1701 break;
1702
1703 p = xnfcalloc(1, sizeof(DisplayModeRec));
1704 p->prev = last;
1705 p->name = xnfstrdup(r->name);
1706 if (!userModes)
1707 p->type = M_T_USERDEF;
1708 if (p->prev)
1709 p->prev->next = p;
1710 *endp = last = p;
1711 endp = &p->next;
1712 }
1713
1714 repeat = FALSE;
1715 lookupNext:
1716 if (repeat && ((status = p->status) != MODE_OK))
1717 printModeRejectMessage(scrp->scrnIndex, p, status);
1718 saveType = p->type;
1719 status = xf86LookupMode(scrp, p, clockRanges, strategy);
1720 if (repeat && status == MODE_NOMODE)
1721 continue;
1722 if (status != MODE_OK)
1723 printModeRejectMessage(scrp->scrnIndex, p, status);
1724 if (status == MODE_ERROR) {
1725 ErrorF("xf86ValidateModes: "
1726 "unexpected result from xf86LookupMode()\n");
1727 return -1;
1728 }
1729 if (status != MODE_OK) {
1730 if (p->status == MODE_OK)
1731 p->status = status;
1732 continue;
1733 }
1734 p->type |= saveType;
1735 repeat = TRUE;
1736
1737 newLinePitch = linePitch;
1738 newVirtX = virtX;
1739 newVirtY = virtY;
1740
1741 /*
1742 * Don't let non-user defined modes increase the virtual size
1743 */
1744 if (!(p->type & M_T_USERDEF) && (numModes > 0)) {
1745 if (p->HDisplay > virtX) {
1746 p->status = MODE_VIRTUAL_X;
1747 goto lookupNext;
1748 }
1749 if (p->VDisplay > virtY) {
1750 p->status = MODE_VIRTUAL_Y;
1751 goto lookupNext;
1752 }
1753 }
1754 /*
1755 * Adjust virtual width and height if the mode is too large for the
1756 * current values and if they are not fixed.
1757 */
1758 if (virtualX <= 0 && p->HDisplay > newVirtX)
1759 newVirtX = _VIRTUALX(p->HDisplay);
1760 if (virtualY <= 0 && p->VDisplay > newVirtY) {
1761 if (maxHeight > 0 && p->VDisplay > maxHeight) {
1762 p->status = MODE_VIRTUAL_Y; /* ? */
1763 goto lookupNext;
1764 }
1765 newVirtY = p->VDisplay;
1766 }
1767
1768 /*
1769 * If virtual resolution is to be increased, revalidate it.
1770 */
1771 if ((virtX != newVirtX) || (virtY != newVirtY)) {
1772 if (linePitches != NULL) {
1773 newLinePitch = -1;
1774 for (i = 0; linePitches[i] != 0; i++) {
1775 if ((linePitches[i] >= newVirtX) &&
1776 (linePitches[i] >= linePitch) &&
1777 (linePitches[i] ==
1778 scanLineWidth(newVirtX, newVirtY, linePitches[i],
1779 apertureSize, BankFormat, pitchInc))) {
1780 newLinePitch = linePitches[i];
1781 break;
1782 }
1783 }
1784 }
1785 else {
1786 if (linePitch < minPitch)
1787 linePitch = minPitch;
1788 newLinePitch = scanLineWidth(newVirtX, newVirtY, linePitch,
1789 apertureSize, BankFormat,
1790 pitchInc);
1791 }
1792 if ((newLinePitch < minPitch) || (newLinePitch > maxPitch)) {
1793 p->status = MODE_BAD_WIDTH;
1794 goto lookupNext;
1795 }
1796
1797 /*
1798 * Check that the pixel area required by the new virtual height
1799 * and line pitch isn't too large.
1800 */
1801 if (!xf86CheckModeSize(scrp, newLinePitch, newVirtX, newVirtY)) {
1802 p->status = MODE_MEM_VIRT;
1803 goto lookupNext;
1804 }
1805 }
1806
1807 if (scrp->ValidMode) {
1808 /*
1809 * Give the driver a final say, passing it the proposed virtual
1810 * geometry.
1811 */
1812 scrp->virtualX = newVirtX;
1813 scrp->virtualY = newVirtY;
1814 scrp->displayWidth = newLinePitch;
1815 p->status = (scrp->ValidMode) (scrp, p, FALSE,
1816 MODECHECK_FINAL);
1817
1818 if (p->status != MODE_OK) {
1819 goto lookupNext;
1820 }
1821 }
1822
1823 /* Mode has passed all the tests */
1824 virtX = newVirtX;
1825 virtY = newVirtY;
1826 linePitch = newLinePitch;
1827 p->status = MODE_OK;
1828 numModes++;
1829 }
1830
1831 /*
1832 * If we estimated the virtual size above, we may have filtered away all
1833 * the modes that maximally match that size; scan again to find out and
1834 * fix up if so.
1835 */
1836 if (inferred_virtual) {
1837 int vx = 0, vy = 0;
1838
1839 for (p = scrp->modes; p; p = p->next) {
1840 if (p->HDisplay > vx && p->VDisplay > vy) {
1841 vx = p->HDisplay;
1842 vy = p->VDisplay;
1843 }
1844 }
1845 if (vx < virtX || vy < virtY) {
1846 const int types[] = {
1847 M_T_BUILTIN | M_T_PREFERRED,
1848 M_T_BUILTIN,
1849 M_T_DRIVER | M_T_PREFERRED,
1850 M_T_DRIVER,
1851 0
1852 };
1853 const int ntypes = ARRAY_SIZE(types);
1854 int n;
1855
1856 /*
1857 * We did not find the estimated virtual size. So now we want to
1858 * find the largest mode available, but we want to search in the
1859 * modes in the order of "types" listed above.
1860 */
1861 for (n = 0; n < ntypes; n++) {
1862 int type = types[n];
1863
1864 vx = 0;
1865 vy = 0;
1866 for (p = scrp->modes; p; p = p->next) {
1867 /* scan through the modes in the sort order above */
1868 if ((p->type & type) != type)
1869 continue;
1870 if (p->HDisplay > vx && p->VDisplay > vy) {
1871 vx = p->HDisplay;
1872 vy = p->VDisplay;
1873 }
1874 }
1875 if (vx && vy)
1876 /* Found one */
1877 break;
1878 }
1879 xf86DrvMsg(scrp->scrnIndex, X_WARNING,
1880 "Shrinking virtual size estimate from %dx%d to %dx%d\n",
1881 virtX, virtY, vx, vy);
1882 virtX = _VIRTUALX(vx);
1883 virtY = vy;
1884 for (p = scrp->modes; p; p = p->next) {
1885 if (numModes > 0) {
1886 if (p->HDisplay > virtX)
1887 p->status = MODE_VIRTUAL_X;
1888 if (p->VDisplay > virtY)
1889 p->status = MODE_VIRTUAL_Y;
1890 if (p->status != MODE_OK) {
1891 numModes--;
1892 printModeRejectMessage(scrp->scrnIndex, p, p->status);
1893 }
1894 }
1895 }
1896 if (linePitches != NULL) {
1897 for (i = 0; linePitches[i] != 0; i++) {
1898 if ((linePitches[i] >= virtX) &&
1899 (linePitches[i] ==
1900 scanLineWidth(virtX, virtY, linePitches[i],
1901 apertureSize, BankFormat, pitchInc))) {
1902 linePitch = linePitches[i];
1903 break;
1904 }
1905 }
1906 }
1907 else {
1908 linePitch = scanLineWidth(virtX, virtY, minPitch,
1909 apertureSize, BankFormat, pitchInc);
1910 }
1911 }
1912 }
1913
1914 /* Update the ScrnInfoRec parameters */
1915
1916 scrp->virtualX = virtX;
1917 scrp->virtualY = virtY;
1918 scrp->displayWidth = linePitch;
1919
1920 if (numModes <= 0)
1921 return 0;
1922
1923 /* Make the mode list into a circular list by joining up the ends */
1924 p = scrp->modes;
1925 while (p->next != NULL)
1926 p = p->next;
1927 /* p is now the last mode on the list */
1928 p->next = scrp->modes;
1929 scrp->modes->prev = p;
1930
1931 if (minHeight > 0 && virtY < minHeight) {
1932 xf86DrvMsg(scrp->scrnIndex, X_ERROR,
1933 "Virtual height (%d) is too small for the hardware "
1934 "(min %d)\n", virtY, minHeight);
1935 return -1;
1936 }
1937
1938 return numModes;
1939 }
1940
1941 /*
1942 * xf86DeleteMode
1943 *
1944 * This function removes a mode from a list of modes.
1945 *
1946 * There are different types of mode lists:
1947 *
1948 * - singly linked linear lists, ending in NULL
1949 * - doubly linked linear lists, starting and ending in NULL
1950 * - doubly linked circular lists
1951 *
1952 */
1953
1954 void
xf86DeleteMode(DisplayModePtr * modeList,DisplayModePtr mode)1955 xf86DeleteMode(DisplayModePtr * modeList, DisplayModePtr mode)
1956 {
1957 /* Catch the easy/insane cases */
1958 if (modeList == NULL || *modeList == NULL || mode == NULL)
1959 return;
1960
1961 /* If the mode is at the start of the list, move the start of the list */
1962 if (*modeList == mode)
1963 *modeList = mode->next;
1964
1965 /* If mode is the only one on the list, set the list to NULL */
1966 if ((mode == mode->prev) && (mode == mode->next)) {
1967 *modeList = NULL;
1968 }
1969 else {
1970 if ((mode->prev != NULL) && (mode->prev->next == mode))
1971 mode->prev->next = mode->next;
1972 if ((mode->next != NULL) && (mode->next->prev == mode))
1973 mode->next->prev = mode->prev;
1974 }
1975
1976 free((void *) mode->name);
1977 free(mode);
1978 }
1979
1980 /*
1981 * xf86PruneDriverModes
1982 *
1983 * Remove modes from the driver's mode list which have been marked as
1984 * invalid.
1985 */
1986
1987 void
xf86PruneDriverModes(ScrnInfoPtr scrp)1988 xf86PruneDriverModes(ScrnInfoPtr scrp)
1989 {
1990 DisplayModePtr first, p, n;
1991
1992 p = scrp->modes;
1993 if (p == NULL)
1994 return;
1995
1996 do {
1997 if (!(first = scrp->modes))
1998 return;
1999 n = p->next;
2000 if (p->status != MODE_OK) {
2001 xf86DeleteMode(&(scrp->modes), p);
2002 }
2003 p = n;
2004 } while (p != NULL && p != first);
2005
2006 /* modePool is no longer needed, turf it */
2007 while (scrp->modePool) {
2008 /*
2009 * A modePool mode's prev field is used to hold a pointer to the
2010 * member of the scrp->modes list for which a match was considered.
2011 * Clear that pointer first, otherwise xf86DeleteMode might get
2012 * confused
2013 */
2014 scrp->modePool->prev = NULL;
2015 xf86DeleteMode(&scrp->modePool, scrp->modePool);
2016 }
2017 }
2018
2019 /*
2020 * xf86SetCrtcForModes
2021 *
2022 * Goes through the screen's mode list, and initialises the Crtc
2023 * parameters for each mode. The initialisation includes adjustments
2024 * for interlaced and double scan modes.
2025 */
2026 void
xf86SetCrtcForModes(ScrnInfoPtr scrp,int adjustFlags)2027 xf86SetCrtcForModes(ScrnInfoPtr scrp, int adjustFlags)
2028 {
2029 DisplayModePtr p;
2030
2031 /*
2032 * Store adjustFlags for use with the VidMode extension. There is an
2033 * implicit assumption here that SetCrtcForModes is called once.
2034 */
2035 scrp->adjustFlags = adjustFlags;
2036
2037 p = scrp->modes;
2038 if (p == NULL)
2039 return;
2040
2041 do {
2042 xf86SetModeCrtc(p, adjustFlags);
2043 DebugF("%sMode %s: %d (%d) %d %d (%d) %d %d (%d) %d %d (%d) %d\n",
2044 (p->type & M_T_DEFAULT) ? "Default " : "",
2045 p->name, p->CrtcHDisplay, p->CrtcHBlankStart,
2046 p->CrtcHSyncStart, p->CrtcHSyncEnd, p->CrtcHBlankEnd,
2047 p->CrtcHTotal, p->CrtcVDisplay, p->CrtcVBlankStart,
2048 p->CrtcVSyncStart, p->CrtcVSyncEnd, p->CrtcVBlankEnd,
2049 p->CrtcVTotal);
2050 p = p->next;
2051 } while (p != NULL && p != scrp->modes);
2052 }
2053
2054 void
xf86PrintModes(ScrnInfoPtr scrp)2055 xf86PrintModes(ScrnInfoPtr scrp)
2056 {
2057 DisplayModePtr p;
2058 float hsync, refresh = 0;
2059 const char *desc, *desc2, *prefix, *uprefix;
2060
2061 if (scrp == NULL)
2062 return;
2063
2064 xf86DrvMsg(scrp->scrnIndex, X_INFO, "Virtual size is %dx%d (pitch %d)\n",
2065 scrp->virtualX, scrp->virtualY, scrp->displayWidth);
2066
2067 p = scrp->modes;
2068 if (p == NULL)
2069 return;
2070
2071 do {
2072 desc = desc2 = "";
2073 hsync = xf86ModeHSync(p);
2074 refresh = xf86ModeVRefresh(p);
2075 if (p->Flags & V_INTERLACE) {
2076 desc = " (I)";
2077 }
2078 if (p->Flags & V_DBLSCAN) {
2079 desc = " (D)";
2080 }
2081 if (p->VScan > 1) {
2082 desc2 = " (VScan)";
2083 }
2084 if (p->type & M_T_BUILTIN)
2085 prefix = "Built-in mode";
2086 else if (p->type & M_T_DEFAULT)
2087 prefix = "Default mode";
2088 else if (p->type & M_T_DRIVER)
2089 prefix = "Driver mode";
2090 else
2091 prefix = "Mode";
2092 if (p->type & M_T_USERDEF)
2093 uprefix = "*";
2094 else
2095 uprefix = " ";
2096 if (hsync == 0 || refresh == 0) {
2097 if (p->name)
2098 xf86DrvMsg(scrp->scrnIndex, X_CONFIG,
2099 "%s%s \"%s\"\n", uprefix, prefix, p->name);
2100 else
2101 xf86DrvMsg(scrp->scrnIndex, X_PROBED,
2102 "%s%s %dx%d (unnamed)\n",
2103 uprefix, prefix, p->HDisplay, p->VDisplay);
2104 }
2105 else if (p->Clock == p->SynthClock) {
2106 xf86DrvMsg(scrp->scrnIndex, X_CONFIG,
2107 "%s%s \"%s\": %.1f MHz, %.1f kHz, %.1f Hz%s%s\n",
2108 uprefix, prefix, p->name, p->Clock / 1000.0,
2109 hsync, refresh, desc, desc2);
2110 }
2111 else {
2112 xf86DrvMsg(scrp->scrnIndex, X_CONFIG,
2113 "%s%s \"%s\": %.1f MHz (scaled from %.1f MHz), "
2114 "%.1f kHz, %.1f Hz%s%s\n",
2115 uprefix, prefix, p->name, p->Clock / 1000.0,
2116 p->SynthClock / 1000.0, hsync, refresh, desc, desc2);
2117 }
2118 if (hsync != 0 && refresh != 0)
2119 xf86PrintModeline(scrp->scrnIndex, p);
2120 p = p->next;
2121 } while (p != NULL && p != scrp->modes);
2122 }
2123