First import
[xorg_rtime.git] / xorg-server-1.4 / hw / xfree86 / modes / xf86Modes.c
blobf49c2921c12be5ade902adb1cd807e43fde2f4f3
1 /*
2 * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
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).
28 #ifdef HAVE_XORG_CONFIG_H
29 #include <xorg-config.h>
30 #else
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34 #endif
36 #include "xf86Modes.h"
37 #include "xf86Priv.h"
39 extern XF86ConfigPtr xf86configptr;
41 /**
42 * @file this file contains symbols from xf86Mode.c and friends that are static
43 * there but we still want to use. We need to come up with better API here.
46 #if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0)
47 /**
48 * Calculates the horizontal sync rate of a mode.
50 * Exact copy of xf86Mode.c's.
52 _X_EXPORT double
53 xf86ModeHSync(DisplayModePtr mode)
55 double hsync = 0.0;
57 if (mode->HSync > 0.0)
58 hsync = mode->HSync;
59 else if (mode->HTotal > 0)
60 hsync = (float)mode->Clock / (float)mode->HTotal;
62 return hsync;
65 /**
66 * Calculates the vertical refresh rate of a mode.
68 * Exact copy of xf86Mode.c's.
70 _X_EXPORT double
71 xf86ModeVRefresh(DisplayModePtr mode)
73 double refresh = 0.0;
75 if (mode->VRefresh > 0.0)
76 refresh = mode->VRefresh;
77 else if (mode->HTotal > 0 && mode->VTotal > 0) {
78 refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal;
79 if (mode->Flags & V_INTERLACE)
80 refresh *= 2.0;
81 if (mode->Flags & V_DBLSCAN)
82 refresh /= 2.0;
83 if (mode->VScan > 1)
84 refresh /= (float)(mode->VScan);
86 return refresh;
89 _X_EXPORT int
90 xf86ModeWidth (DisplayModePtr mode, Rotation rotation)
92 switch (rotation & 0xf) {
93 case RR_Rotate_0:
94 case RR_Rotate_180:
95 return mode->HDisplay;
96 case RR_Rotate_90:
97 case RR_Rotate_270:
98 return mode->VDisplay;
99 default:
100 return 0;
104 _X_EXPORT int
105 xf86ModeHeight (DisplayModePtr mode, Rotation rotation)
107 switch (rotation & 0xf) {
108 case RR_Rotate_0:
109 case RR_Rotate_180:
110 return mode->VDisplay;
111 case RR_Rotate_90:
112 case RR_Rotate_270:
113 return mode->HDisplay;
114 default:
115 return 0;
119 /** Sets a default mode name of <width>x<height> on a mode. */
120 _X_EXPORT void
121 xf86SetModeDefaultName(DisplayModePtr mode)
123 if (mode->name != NULL)
124 xfree(mode->name);
126 mode->name = XNFprintf("%dx%d", mode->HDisplay, mode->VDisplay);
130 * xf86SetModeCrtc
132 * Initialises the Crtc parameters for a mode. The initialisation includes
133 * adjustments for interlaced and double scan modes.
135 * Exact copy of xf86Mode.c's.
137 _X_EXPORT void
138 xf86SetModeCrtc(DisplayModePtr p, int adjustFlags)
140 if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN))
141 return;
143 p->CrtcHDisplay = p->HDisplay;
144 p->CrtcHSyncStart = p->HSyncStart;
145 p->CrtcHSyncEnd = p->HSyncEnd;
146 p->CrtcHTotal = p->HTotal;
147 p->CrtcHSkew = p->HSkew;
148 p->CrtcVDisplay = p->VDisplay;
149 p->CrtcVSyncStart = p->VSyncStart;
150 p->CrtcVSyncEnd = p->VSyncEnd;
151 p->CrtcVTotal = p->VTotal;
152 if (p->Flags & V_INTERLACE) {
153 if (adjustFlags & INTERLACE_HALVE_V) {
154 p->CrtcVDisplay /= 2;
155 p->CrtcVSyncStart /= 2;
156 p->CrtcVSyncEnd /= 2;
157 p->CrtcVTotal /= 2;
159 /* Force interlaced modes to have an odd VTotal */
160 /* maybe we should only do this when INTERLACE_HALVE_V is set? */
161 p->CrtcVTotal |= 1;
164 if (p->Flags & V_DBLSCAN) {
165 p->CrtcVDisplay *= 2;
166 p->CrtcVSyncStart *= 2;
167 p->CrtcVSyncEnd *= 2;
168 p->CrtcVTotal *= 2;
170 if (p->VScan > 1) {
171 p->CrtcVDisplay *= p->VScan;
172 p->CrtcVSyncStart *= p->VScan;
173 p->CrtcVSyncEnd *= p->VScan;
174 p->CrtcVTotal *= p->VScan;
176 p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay);
177 p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal);
178 p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay);
179 p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal);
181 p->CrtcHAdjusted = FALSE;
182 p->CrtcVAdjusted = FALSE;
186 * Allocates and returns a copy of pMode, including pointers within pMode.
188 _X_EXPORT DisplayModePtr
189 xf86DuplicateMode(DisplayModePtr pMode)
191 DisplayModePtr pNew;
193 pNew = xnfalloc(sizeof(DisplayModeRec));
194 *pNew = *pMode;
195 pNew->next = NULL;
196 pNew->prev = NULL;
197 if (pNew->name == NULL) {
198 xf86SetModeDefaultName(pMode);
199 } else {
200 pNew->name = xnfstrdup(pMode->name);
203 return pNew;
207 * Duplicates every mode in the given list and returns a pointer to the first
208 * mode.
210 * \param modeList doubly-linked mode list
212 _X_EXPORT DisplayModePtr
213 xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList)
215 DisplayModePtr first = NULL, last = NULL;
216 DisplayModePtr mode;
218 for (mode = modeList; mode != NULL; mode = mode->next) {
219 DisplayModePtr new;
221 new = xf86DuplicateMode(mode);
223 /* Insert pNew into modeList */
224 if (last) {
225 last->next = new;
226 new->prev = last;
227 } else {
228 first = new;
229 new->prev = NULL;
231 new->next = NULL;
232 last = new;
235 return first;
239 * Returns true if the given modes should program to the same timings.
241 * This doesn't use Crtc values, as it might be used on ModeRecs without the
242 * Crtc values set. So, it's assumed that the other numbers are enough.
244 * This isn't in xf86Modes.c, but it might deserve to be there.
246 _X_EXPORT Bool
247 xf86ModesEqual(DisplayModePtr pMode1, DisplayModePtr pMode2)
249 if (pMode1->Clock == pMode2->Clock &&
250 pMode1->HDisplay == pMode2->HDisplay &&
251 pMode1->HSyncStart == pMode2->HSyncStart &&
252 pMode1->HSyncEnd == pMode2->HSyncEnd &&
253 pMode1->HTotal == pMode2->HTotal &&
254 pMode1->HSkew == pMode2->HSkew &&
255 pMode1->VDisplay == pMode2->VDisplay &&
256 pMode1->VSyncStart == pMode2->VSyncStart &&
257 pMode1->VSyncEnd == pMode2->VSyncEnd &&
258 pMode1->VTotal == pMode2->VTotal &&
259 pMode1->VScan == pMode2->VScan &&
260 pMode1->Flags == pMode2->Flags)
262 return TRUE;
263 } else {
264 return FALSE;
268 /* exact copy of xf86Mode.c */
269 static void
270 add(char **p, char *new)
272 *p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2);
273 strcat(*p, " ");
274 strcat(*p, new);
278 * Print out a modeline.
280 * Convenient VRefresh printing was added, though, compared to xf86Mode.c
282 _X_EXPORT void
283 xf86PrintModeline(int scrnIndex,DisplayModePtr mode)
285 char tmp[256];
286 char *flags = xnfcalloc(1, 1);
288 if (mode->HSkew) {
289 snprintf(tmp, 256, "hskew %i", mode->HSkew);
290 add(&flags, tmp);
292 if (mode->VScan) {
293 snprintf(tmp, 256, "vscan %i", mode->VScan);
294 add(&flags, tmp);
296 if (mode->Flags & V_INTERLACE) add(&flags, "interlace");
297 if (mode->Flags & V_CSYNC) add(&flags, "composite");
298 if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan");
299 if (mode->Flags & V_BCAST) add(&flags, "bcast");
300 if (mode->Flags & V_PHSYNC) add(&flags, "+hsync");
301 if (mode->Flags & V_NHSYNC) add(&flags, "-hsync");
302 if (mode->Flags & V_PVSYNC) add(&flags, "+vsync");
303 if (mode->Flags & V_NVSYNC) add(&flags, "-vsync");
304 if (mode->Flags & V_PCSYNC) add(&flags, "+csync");
305 if (mode->Flags & V_NCSYNC) add(&flags, "-csync");
306 #if 0
307 if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2");
308 #endif
309 xf86DrvMsg(scrnIndex, X_INFO,
310 "Modeline \"%s\"x%.01f %6.2f %i %i %i %i %i %i %i %i%s "
311 "(%.01f kHz)\n",
312 mode->name, mode->VRefresh, mode->Clock/1000., mode->HDisplay,
313 mode->HSyncStart, mode->HSyncEnd, mode->HTotal,
314 mode->VDisplay, mode->VSyncStart, mode->VSyncEnd,
315 mode->VTotal, flags, xf86ModeHSync(mode));
316 xfree(flags);
318 #endif /* XORG_VERSION_CURRENT <= 7.2.99.2 */
321 * Marks as bad any modes with unsupported flags.
323 * \param modeList doubly-linked or circular list of modes.
324 * \param flags flags supported by the driver.
326 * \bug only V_INTERLACE and V_DBLSCAN are supported. Is that enough?
328 * This is not in xf86Modes.c, but would be part of the proposed new API.
330 _X_EXPORT void
331 xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList,
332 int flags)
334 DisplayModePtr mode;
336 for (mode = modeList; mode != NULL; mode = mode->next) {
337 if (mode->Flags & V_INTERLACE && !(flags & V_INTERLACE))
338 mode->status = MODE_NO_INTERLACE;
339 if (mode->Flags & V_DBLSCAN && !(flags & V_DBLSCAN))
340 mode->status = MODE_NO_DBLESCAN;
345 * Marks as bad any modes extending beyond the given max X, Y, or pitch.
347 * \param modeList doubly-linked or circular list of modes.
349 * This is not in xf86Modes.c, but would be part of the proposed new API.
351 _X_EXPORT void
352 xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList,
353 int maxX, int maxY, int maxPitch)
355 DisplayModePtr mode;
357 for (mode = modeList; mode != NULL; mode = mode->next) {
358 if (maxPitch > 0 && mode->HDisplay > maxPitch)
359 mode->status = MODE_BAD_WIDTH;
361 if (maxX > 0 && mode->HDisplay > maxX)
362 mode->status = MODE_VIRTUAL_X;
364 if (maxY > 0 && mode->VDisplay > maxY)
365 mode->status = MODE_VIRTUAL_Y;
367 if (mode->next == modeList)
368 break;
373 * Marks as bad any modes that aren't supported by the given monitor's
374 * hsync and vrefresh ranges.
376 * \param modeList doubly-linked or circular list of modes.
378 * This is not in xf86Modes.c, but would be part of the proposed new API.
380 _X_EXPORT void
381 xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList,
382 MonPtr mon)
384 DisplayModePtr mode;
386 for (mode = modeList; mode != NULL; mode = mode->next) {
387 Bool bad;
388 int i;
390 bad = TRUE;
391 for (i = 0; i < mon->nHsync; i++) {
392 if (xf86ModeHSync(mode) >= mon->hsync[i].lo &&
393 xf86ModeHSync(mode) <= mon->hsync[i].hi)
395 bad = FALSE;
398 if (bad)
399 mode->status = MODE_HSYNC;
401 bad = TRUE;
402 for (i = 0; i < mon->nVrefresh; i++) {
403 if (xf86ModeVRefresh(mode) >= mon->vrefresh[i].lo &&
404 xf86ModeVRefresh(mode) <= mon->vrefresh[i].hi)
406 bad = FALSE;
409 if (bad)
410 mode->status = MODE_VSYNC;
412 if (mode->next == modeList)
413 break;
418 * Marks as bad any modes extending beyond outside of the given clock ranges.
420 * \param modeList doubly-linked or circular list of modes.
421 * \param min pointer to minimums of clock ranges
422 * \param max pointer to maximums of clock ranges
423 * \param n_ranges number of ranges.
425 * This is not in xf86Modes.c, but would be part of the proposed new API.
427 _X_EXPORT void
428 xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList,
429 int *min, int *max, int n_ranges)
431 DisplayModePtr mode;
432 int i;
434 for (mode = modeList; mode != NULL; mode = mode->next) {
435 Bool good = FALSE;
436 for (i = 0; i < n_ranges; i++) {
437 if (mode->Clock >= min[i] && mode->Clock <= max[i]) {
438 good = TRUE;
439 break;
442 if (!good)
443 mode->status = MODE_CLOCK_RANGE;
448 * If the user has specified a set of mode names to use, mark as bad any modes
449 * not listed.
451 * The user mode names specified are prefixes to names of modes, so "1024x768"
452 * will match modes named "1024x768", "1024x768x75", "1024x768-good", but
453 * "1024x768x75" would only match "1024x768x75" from that list.
455 * MODE_BAD is used as the rejection flag, for lack of a better flag.
457 * \param modeList doubly-linked or circular list of modes.
459 * This is not in xf86Modes.c, but would be part of the proposed new API.
461 _X_EXPORT void
462 xf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList)
464 DisplayModePtr mode;
466 if (pScrn->display->modes[0] == NULL)
467 return;
469 for (mode = modeList; mode != NULL; mode = mode->next) {
470 int i;
471 Bool good = FALSE;
473 for (i = 0; pScrn->display->modes[i] != NULL; i++) {
474 if (strncmp(pScrn->display->modes[i], mode->name,
475 strlen(pScrn->display->modes[i])) == 0) {
476 good = TRUE;
477 break;
480 if (!good)
481 mode->status = MODE_BAD;
487 * Frees any modes from the list with a status other than MODE_OK.
489 * \param modeList pointer to a doubly-linked or circular list of modes.
490 * \param verbose determines whether the reason for mode invalidation is
491 * printed.
493 * This is not in xf86Modes.c, but would be part of the proposed new API.
495 _X_EXPORT void
496 xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
497 Bool verbose)
499 DisplayModePtr mode;
501 for (mode = *modeList; mode != NULL;) {
502 DisplayModePtr next = mode->next, first = *modeList;
504 if (mode->status != MODE_OK) {
505 if (verbose) {
506 char *type = "";
507 if (mode->type & M_T_BUILTIN)
508 type = "built-in ";
509 else if (mode->type & M_T_DEFAULT)
510 type = "default ";
511 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
512 "Not using %smode \"%s\" (%s)\n", type, mode->name,
513 xf86ModeStatusToString(mode->status));
515 xf86DeleteMode(modeList, mode);
518 if (next == first)
519 break;
520 mode = next;
525 * Adds the new mode into the mode list, and returns the new list
527 * \param modes doubly-linked mode list.
529 _X_EXPORT DisplayModePtr
530 xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new)
532 if (modes == NULL)
533 return new;
535 if (new) {
536 DisplayModePtr mode = modes;
538 while (mode->next)
539 mode = mode->next;
541 mode->next = new;
542 new->prev = mode;
545 return modes;
549 * Build a mode list from a list of config file modes
551 static DisplayModePtr
552 xf86GetConfigModes (XF86ConfModeLinePtr conf_mode)
554 DisplayModePtr head = NULL, prev = NULL, mode;
556 for (; conf_mode; conf_mode = (XF86ConfModeLinePtr) conf_mode->list.next)
558 mode = xcalloc(1, sizeof(DisplayModeRec));
559 if (!mode)
560 continue;
561 mode->name = xstrdup(conf_mode->ml_identifier);
562 if (!mode->name)
564 xfree (mode);
565 continue;
567 mode->type = 0;
568 mode->Clock = conf_mode->ml_clock;
569 mode->HDisplay = conf_mode->ml_hdisplay;
570 mode->HSyncStart = conf_mode->ml_hsyncstart;
571 mode->HSyncEnd = conf_mode->ml_hsyncend;
572 mode->HTotal = conf_mode->ml_htotal;
573 mode->VDisplay = conf_mode->ml_vdisplay;
574 mode->VSyncStart = conf_mode->ml_vsyncstart;
575 mode->VSyncEnd = conf_mode->ml_vsyncend;
576 mode->VTotal = conf_mode->ml_vtotal;
577 mode->Flags = conf_mode->ml_flags;
578 mode->HSkew = conf_mode->ml_hskew;
579 mode->VScan = conf_mode->ml_vscan;
581 mode->prev = prev;
582 mode->next = NULL;
583 if (prev)
584 prev->next = mode;
585 else
586 head = mode;
587 prev = mode;
589 return head;
593 * Build a mode list from a monitor configuration
595 _X_EXPORT DisplayModePtr
596 xf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor)
598 DisplayModePtr modes = NULL;
599 XF86ConfModesLinkPtr modes_link;
601 if (!conf_monitor)
602 return NULL;
605 * first we collect the mode lines from the UseModes directive
607 for (modes_link = conf_monitor->mon_modes_sect_lst;
608 modes_link;
609 modes_link = modes_link->list.next)
611 /* If this modes link hasn't been resolved, go look it up now */
612 if (!modes_link->ml_modes)
613 modes_link->ml_modes = xf86findModes (modes_link->ml_modes_str,
614 xf86configptr->conf_modes_lst);
615 if (modes_link->ml_modes)
616 modes = xf86ModesAdd (modes,
617 xf86GetConfigModes (modes_link->ml_modes->mon_modeline_lst));
620 return xf86ModesAdd (modes,
621 xf86GetConfigModes (conf_monitor->mon_modeline_lst));
625 * Build a mode list containing all of the default modes
627 _X_EXPORT DisplayModePtr
628 xf86GetDefaultModes (Bool interlaceAllowed, Bool doubleScanAllowed)
630 DisplayModePtr head = NULL, prev = NULL, mode;
631 int i;
633 for (i = 0; xf86DefaultModes[i].name != NULL; i++)
635 DisplayModePtr defMode = &xf86DefaultModes[i];
637 if (!interlaceAllowed && (defMode->Flags & V_INTERLACE))
638 continue;
639 if (!doubleScanAllowed && (defMode->Flags & V_DBLSCAN))
640 continue;
642 mode = xalloc(sizeof(DisplayModeRec));
643 if (!mode)
644 continue;
645 memcpy(mode,&xf86DefaultModes[i],sizeof(DisplayModeRec));
646 mode->name = xstrdup(xf86DefaultModes[i].name);
647 if (!mode->name)
649 xfree (mode);
650 continue;
652 mode->prev = prev;
653 mode->next = NULL;
654 if (prev)
655 prev->next = mode;
656 else
657 head = mode;
658 prev = mode;
660 return head;