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>
36 #include "xf86Modes.h"
39 extern XF86ConfigPtr xf86configptr
;
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)
48 * Calculates the horizontal sync rate of a mode.
50 * Exact copy of xf86Mode.c's.
53 xf86ModeHSync(DisplayModePtr mode
)
57 if (mode
->HSync
> 0.0)
59 else if (mode
->HTotal
> 0)
60 hsync
= (float)mode
->Clock
/ (float)mode
->HTotal
;
66 * Calculates the vertical refresh rate of a mode.
68 * Exact copy of xf86Mode.c's.
71 xf86ModeVRefresh(DisplayModePtr mode
)
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
)
81 if (mode
->Flags
& V_DBLSCAN
)
84 refresh
/= (float)(mode
->VScan
);
90 xf86ModeWidth (DisplayModePtr mode
, Rotation rotation
)
92 switch (rotation
& 0xf) {
95 return mode
->HDisplay
;
98 return mode
->VDisplay
;
105 xf86ModeHeight (DisplayModePtr mode
, Rotation rotation
)
107 switch (rotation
& 0xf) {
110 return mode
->VDisplay
;
113 return mode
->HDisplay
;
119 /** Sets a default mode name of <width>x<height> on a mode. */
121 xf86SetModeDefaultName(DisplayModePtr mode
)
123 if (mode
->name
!= NULL
)
126 mode
->name
= XNFprintf("%dx%d", mode
->HDisplay
, mode
->VDisplay
);
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.
138 xf86SetModeCrtc(DisplayModePtr p
, int adjustFlags
)
140 if ((p
== NULL
) || ((p
->type
& M_T_CRTC_C
) == M_T_BUILTIN
))
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;
159 /* Force interlaced modes to have an odd VTotal */
160 /* maybe we should only do this when INTERLACE_HALVE_V is set? */
164 if (p
->Flags
& V_DBLSCAN
) {
165 p
->CrtcVDisplay
*= 2;
166 p
->CrtcVSyncStart
*= 2;
167 p
->CrtcVSyncEnd
*= 2;
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
)
193 pNew
= xnfalloc(sizeof(DisplayModeRec
));
197 if (pNew
->name
== NULL
) {
198 xf86SetModeDefaultName(pMode
);
200 pNew
->name
= xnfstrdup(pMode
->name
);
207 * Duplicates every mode in the given list and returns a pointer to the first
210 * \param modeList doubly-linked mode list
212 _X_EXPORT DisplayModePtr
213 xf86DuplicateModes(ScrnInfoPtr pScrn
, DisplayModePtr modeList
)
215 DisplayModePtr first
= NULL
, last
= NULL
;
218 for (mode
= modeList
; mode
!= NULL
; mode
= mode
->next
) {
221 new = xf86DuplicateMode(mode
);
223 /* Insert pNew into modeList */
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.
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
)
268 /* exact copy of xf86Mode.c */
270 add(char **p
, char *new)
272 *p
= xnfrealloc(*p
, strlen(*p
) + strlen(new) + 2);
278 * Print out a modeline.
280 * Convenient VRefresh printing was added, though, compared to xf86Mode.c
283 xf86PrintModeline(int scrnIndex
,DisplayModePtr mode
)
286 char *flags
= xnfcalloc(1, 1);
289 snprintf(tmp
, 256, "hskew %i", mode
->HSkew
);
293 snprintf(tmp
, 256, "vscan %i", mode
->VScan
);
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");
307 if (mode
->Flags
& V_CLKDIV2
) add(&flags
, "vclk/2");
309 xf86DrvMsg(scrnIndex
, X_INFO
,
310 "Modeline \"%s\"x%.01f %6.2f %i %i %i %i %i %i %i %i%s "
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
));
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.
331 xf86ValidateModesFlags(ScrnInfoPtr pScrn
, DisplayModePtr modeList
,
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.
352 xf86ValidateModesSize(ScrnInfoPtr pScrn
, DisplayModePtr modeList
,
353 int maxX
, int maxY
, int maxPitch
)
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
)
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.
381 xf86ValidateModesSync(ScrnInfoPtr pScrn
, DisplayModePtr modeList
,
386 for (mode
= modeList
; mode
!= NULL
; mode
= mode
->next
) {
391 for (i
= 0; i
< mon
->nHsync
; i
++) {
392 if (xf86ModeHSync(mode
) >= mon
->hsync
[i
].lo
&&
393 xf86ModeHSync(mode
) <= mon
->hsync
[i
].hi
)
399 mode
->status
= MODE_HSYNC
;
402 for (i
= 0; i
< mon
->nVrefresh
; i
++) {
403 if (xf86ModeVRefresh(mode
) >= mon
->vrefresh
[i
].lo
&&
404 xf86ModeVRefresh(mode
) <= mon
->vrefresh
[i
].hi
)
410 mode
->status
= MODE_VSYNC
;
412 if (mode
->next
== modeList
)
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.
428 xf86ValidateModesClocks(ScrnInfoPtr pScrn
, DisplayModePtr modeList
,
429 int *min
, int *max
, int n_ranges
)
434 for (mode
= modeList
; mode
!= NULL
; mode
= mode
->next
) {
436 for (i
= 0; i
< n_ranges
; i
++) {
437 if (mode
->Clock
>= min
[i
] && mode
->Clock
<= max
[i
]) {
443 mode
->status
= MODE_CLOCK_RANGE
;
448 * If the user has specified a set of mode names to use, mark as bad any modes
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.
462 xf86ValidateModesUserConfig(ScrnInfoPtr pScrn
, DisplayModePtr modeList
)
466 if (pScrn
->display
->modes
[0] == NULL
)
469 for (mode
= modeList
; mode
!= NULL
; mode
= mode
->next
) {
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) {
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
493 * This is not in xf86Modes.c, but would be part of the proposed new API.
496 xf86PruneInvalidModes(ScrnInfoPtr pScrn
, DisplayModePtr
*modeList
,
501 for (mode
= *modeList
; mode
!= NULL
;) {
502 DisplayModePtr next
= mode
->next
, first
= *modeList
;
504 if (mode
->status
!= MODE_OK
) {
507 if (mode
->type
& M_T_BUILTIN
)
509 else if (mode
->type
& M_T_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
);
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)
536 DisplayModePtr mode
= 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
));
561 mode
->name
= xstrdup(conf_mode
->ml_identifier
);
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
;
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
;
605 * first we collect the mode lines from the UseModes directive
607 for (modes_link
= conf_monitor
->mon_modes_sect_lst
;
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
;
633 for (i
= 0; xf86DefaultModes
[i
].name
!= NULL
; i
++)
635 DisplayModePtr defMode
= &xf86DefaultModes
[i
];
637 if (!interlaceAllowed
&& (defMode
->Flags
& V_INTERLACE
))
639 if (!doubleScanAllowed
&& (defMode
->Flags
& V_DBLSCAN
))
642 mode
= xalloc(sizeof(DisplayModeRec
));
645 memcpy(mode
,&xf86DefaultModes
[i
],sizeof(DisplayModeRec
));
646 mode
->name
= xstrdup(xf86DefaultModes
[i
].name
);