From a0b4a1330be6a36ad095222d2ea83927cd33514d Mon Sep 17 00:00:00 2001 From: marha Date: Fri, 25 Nov 2011 08:22:48 +0100 Subject: mesa xserver pixman git update 25 nov 2011 --- xorg-server/hw/xfree86/common/Makefile.am | 2 +- xorg-server/hw/xfree86/common/xf86.h | 1 - xorg-server/hw/xfree86/common/xf86AutoConfig.c | 2 + xorg-server/hw/xfree86/common/xf86Config.c | 21 +- xorg-server/hw/xfree86/common/xf86Config.h | 2 +- xorg-server/hw/xfree86/common/xf86Configure.c | 71 +- xorg-server/hw/xfree86/common/xf86Globals.c | 2 +- xorg-server/hw/xfree86/common/xf86Mode.c | 4260 ++++++++++---------- xorg-server/hw/xfree86/common/xf86Opt.h | 4 +- xorg-server/hw/xfree86/common/xf86Option.c | 12 +- xorg-server/hw/xfree86/common/xf86PM.c | 4 +- xorg-server/hw/xfree86/common/xf86Priv.h | 2 +- xorg-server/hw/xfree86/common/xf86ShowOpts.c | 130 - xorg-server/hw/xfree86/common/xf86Xinput.c | 5 +- xorg-server/hw/xfree86/common/xf86pciBus.c | 30 +- xorg-server/hw/xfree86/common/xf86sbusBus.c | 2 +- xorg-server/hw/xfree86/ddc/xf86DDC.h | 5 - xorg-server/hw/xfree86/doc/ddxDesign.xml | 4 +- xorg-server/hw/xfree86/fbdevhw/fbdevhw.c | 6 +- xorg-server/hw/xfree86/i2c/msp3430.c | 1453 +++---- xorg-server/hw/xfree86/loader/loadmod.c | 11 +- xorg-server/hw/xfree86/modes/xf86Crtc.c | 8 +- xorg-server/hw/xfree86/modes/xf86Crtc.h | 2 +- xorg-server/hw/xfree86/modes/xf86EdidModes.c | 2 +- xorg-server/hw/xfree86/modes/xf86Modes.c | 4 +- xorg-server/hw/xfree86/os-support/bsd/bsd_init.c | 10 +- xorg-server/hw/xfree86/os-support/bus/Sbus.c | 1376 +++---- xorg-server/hw/xfree86/os-support/linux/lnx_init.c | 2 +- .../hw/xfree86/os-support/solaris/sun_agp.c | 2 +- xorg-server/hw/xfree86/parser/Flags.c | 2 +- xorg-server/hw/xfree86/parser/InputClass.c | 15 + xorg-server/hw/xfree86/parser/configProcs.h | 6 +- xorg-server/hw/xfree86/parser/scan.c | 52 +- xorg-server/hw/xfree86/parser/xf86Optrec.h | 2 +- xorg-server/hw/xfree86/parser/xf86Parser.h | 10 +- xorg-server/hw/xfree86/ramdac/BTPriv.h | 2 +- xorg-server/hw/xfree86/ramdac/IBMPriv.h | 2 +- xorg-server/hw/xfree86/ramdac/TIPriv.h | 2 +- xorg-server/hw/xfree86/utils/gtf/gtf.c | 1482 +++---- xorg-server/hw/xfree86/vbe/vbe.c | 2 +- xorg-server/hw/xfree86/x86emu/debug.c | 2 +- 41 files changed, 4466 insertions(+), 4548 deletions(-) delete mode 100644 xorg-server/hw/xfree86/common/xf86ShowOpts.c (limited to 'xorg-server/hw/xfree86') diff --git a/xorg-server/hw/xfree86/common/Makefile.am b/xorg-server/hw/xfree86/common/Makefile.am index a27372103..27921777d 100644 --- a/xorg-server/hw/xfree86/common/Makefile.am +++ b/xorg-server/hw/xfree86/common/Makefile.am @@ -35,7 +35,7 @@ xf86DefModeSet.c: $(srcdir)/modeline2c.awk $(MODEDEFSOURCES) BUILT_SOURCES = xf86DefModeSet.c AM_LDFLAGS = -r -libcommon_la_SOURCES = xf86Configure.c xf86ShowOpts.c xf86Bus.c xf86Config.c \ +libcommon_la_SOURCES = xf86Configure.c xf86Bus.c xf86Config.c \ xf86Cursor.c $(DGASOURCES) xf86DPMS.c \ xf86Events.c xf86Globals.c xf86AutoConfig.c \ xf86Option.c xf86Init.c \ diff --git a/xorg-server/hw/xfree86/common/xf86.h b/xorg-server/hw/xfree86/common/xf86.h index 3185baf3a..f216d5e8c 100644 --- a/xorg-server/hw/xfree86/common/xf86.h +++ b/xorg-server/hw/xfree86/common/xf86.h @@ -104,7 +104,6 @@ extern _X_EXPORT Bool xf86ParsePciBusString(const char *busID, int *bus, int *device, int *func); extern _X_EXPORT Bool xf86ComparePciBusString(const char *busID, int bus, int device, int func); -extern _X_EXPORT void xf86FormatPciBusNumber(int busnum, char *buffer); extern _X_EXPORT Bool xf86IsPrimaryPci(struct pci_device * pPci); extern _X_EXPORT Bool xf86CheckPciMemBase(struct pci_device * pPci, memType base); diff --git a/xorg-server/hw/xfree86/common/xf86AutoConfig.c b/xorg-server/hw/xfree86/common/xf86AutoConfig.c index 7fc6518d3..0c465682a 100644 --- a/xorg-server/hw/xfree86/common/xf86AutoConfig.c +++ b/xorg-server/hw/xfree86/common/xf86AutoConfig.c @@ -267,6 +267,7 @@ listPossibleVideoDrivers(char *matches[], int nmatches) #endif } +#if !defined(sun) /* Fallback to platform default frame buffer driver */ if (i < (nmatches - 1)) { #if !defined(__linux__) && defined(__sparc__) @@ -275,6 +276,7 @@ listPossibleVideoDrivers(char *matches[], int nmatches) matches[i++] = xnfstrdup("fbdev"); #endif } +#endif /* !sun */ } /* copy a screen section and enter the desired driver diff --git a/xorg-server/hw/xfree86/common/xf86Config.c b/xorg-server/hw/xfree86/common/xf86Config.c index cb4be4210..fef4bf1fe 100644 --- a/xorg-server/hw/xfree86/common/xf86Config.c +++ b/xorg-server/hw/xfree86/common/xf86Config.c @@ -195,8 +195,7 @@ xf86ValidateFontPath(char *path) dirlen = p1 - path_elem; else dirlen = strlen(path_elem); - strncpy(dir_elem, path_elem, dirlen); - dir_elem[dirlen] = '\0'; + strlcpy(dir_elem, path_elem, dirlen + 1); flag = stat(dir_elem, &stat_buf); if (flag == 0) if (!S_ISDIR(stat_buf.st_mode)) @@ -249,9 +248,9 @@ xf86ModulelistFromConfig(pointer **optlist) { int count = 0, i = 0; char **modulearray; - char *ignore[] = { "GLcore", "speedo", "bitmap", "drm", - "freetype", "type1", - NULL }; + const char *ignore[] = { "GLcore", "speedo", "bitmap", "drm", + "freetype", "type1", + NULL }; pointer *optarray; XF86LoadPtr modp; Bool found; @@ -523,7 +522,7 @@ fixup_video_driver_list(char **drivers) } static char ** -GenerateDriverlist(char * dirname) +GenerateDriverlist(const char * dirname) { char **ret; const char *subdirs[] = { dirname, NULL }; @@ -554,7 +553,7 @@ xf86DriverlistFromCompile(void) * available is printed. */ static void -xf86ConfigError(char *msg, ...) +xf86ConfigError(const char *msg, ...) { va_list ap; @@ -2301,8 +2300,8 @@ checkInput(serverLayoutPtr layout, Bool implicit_layout) { ConfigStatus xf86HandleConfigFile(Bool autoconfig) { - const char *filename, *dirname, *sysdirname; - char *filesearch, *dirsearch; + char *filename, *dirname, *sysdirname; + const char *filesearch, *dirsearch; MessageType filefrom = X_DEFAULT; MessageType dirfrom = X_DEFAULT; char *scanptr; @@ -2353,6 +2352,10 @@ xf86HandleConfigFile(Bool autoconfig) return CONFIG_NOFILE; } + free(filename); + free(dirname); + free(sysdirname); + if ((xf86configptr = xf86readConfigFile ()) == NULL) { xf86Msg(X_ERROR, "Problem parsing the config file\n"); return CONFIG_PARSE_ERROR; diff --git a/xorg-server/hw/xfree86/common/xf86Config.h b/xorg-server/hw/xfree86/common/xf86Config.h index de287041a..411fc2cc1 100644 --- a/xorg-server/hw/xfree86/common/xf86Config.h +++ b/xorg-server/hw/xfree86/common/xf86Config.h @@ -51,7 +51,7 @@ typedef enum _ConfigStatus { } ConfigStatus; typedef struct _ModuleDefault { - char *name; + const char *name; Bool toLoad; XF86OptionPtr load_opt; } ModuleDefault; diff --git a/xorg-server/hw/xfree86/common/xf86Configure.c b/xorg-server/hw/xfree86/common/xf86Configure.c index 99b8b48d7..24f367ec0 100644 --- a/xorg-server/hw/xfree86/common/xf86Configure.c +++ b/xorg-server/hw/xfree86/common/xf86Configure.c @@ -58,17 +58,17 @@ Bool xf86DoConfigurePass1 = TRUE; static Bool foundMouse = FALSE; #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) -static char *DFLT_MOUSE_DEV = "/dev/sysmouse"; -static char *DFLT_MOUSE_PROTO = "auto"; +static const char *DFLT_MOUSE_DEV = "/dev/sysmouse"; +static const char *DFLT_MOUSE_PROTO = "auto"; #elif defined(linux) -static char DFLT_MOUSE_DEV[] = "/dev/input/mice"; -static char DFLT_MOUSE_PROTO[] = "auto"; +static const char *DFLT_MOUSE_DEV = "/dev/input/mice"; +static const char *DFLT_MOUSE_PROTO = "auto"; #elif defined(WSCONS_SUPPORT) -static char *DFLT_MOUSE_DEV = "/dev/wsmouse"; -static char *DFLT_MOUSE_PROTO = "wsmouse"; +static const char *DFLT_MOUSE_DEV = "/dev/wsmouse"; +static const char *DFLT_MOUSE_PROTO = "wsmouse"; #else -static char *DFLT_MOUSE_DEV = "/dev/mouse"; -static char *DFLT_MOUSE_PROTO = "auto"; +static const char *DFLT_MOUSE_DEV = "/dev/mouse"; +static const char *DFLT_MOUSE_PROTO = "auto"; #endif /* @@ -516,9 +516,9 @@ void DoConfigure(void) { int i,j, screennum = -1; - char *home = NULL; + const char *home = NULL; char filename[PATH_MAX]; - char *addslash = ""; + const char *addslash = ""; XF86ConfigPtr xf86config = NULL; char **vlist, **vl; int *dev2screen; @@ -757,3 +757,54 @@ bail: fflush(stderr); exit(0); } + +/* Xorg -showopts: + * For each driver module installed, print out the list + * of options and their argument types, then exit + * + * Author: Marcus Schaefer, ms@suse.de + */ + +void DoShowOptions (void) { + int i = 0; + char **vlist = 0; + char *pSymbol = 0; + XF86ModuleData *initData = 0; + if (! (vlist = xf86DriverlistFromCompile())) { + ErrorF("Missing output drivers\n"); + goto bail; + } + xf86LoadModules (vlist,0); + free(vlist); + for (i = 0; i < xf86NumDrivers; i++) { + if (xf86DriverList[i]->AvailableOptions) { + OptionInfoPtr pOption = (OptionInfoPtr)(*xf86DriverList[i]->AvailableOptions)(0,0); + if (! pOption) { + ErrorF ("(EE) Couldn't read option table for %s driver\n", + xf86DriverList[i]->driverName + ); + continue; + } + XNFasprintf(&pSymbol, "%sModuleData", + xf86DriverList[i]->driverName); + initData = LoaderSymbol (pSymbol); + if (initData) { + XF86ModuleVersionInfo *vers = initData->vers; + OptionInfoPtr p; + ErrorF ("Driver[%d]:%s[%s] {\n", + i,xf86DriverList[i]->driverName,vers->vendor + ); + for (p = pOption; p->name != NULL; p++) { + ErrorF ("\t%s:%s\n", p->name, + optionTypeToString(p->type)); + } + ErrorF ("}\n"); + } + } + } + bail: + OsCleanup (TRUE); + AbortDDX (EXIT_ERR_DRIVERS); + fflush (stderr); + exit (0); +} diff --git a/xorg-server/hw/xfree86/common/xf86Globals.c b/xorg-server/hw/xfree86/common/xf86Globals.c index f46799615..d576fb915 100644 --- a/xorg-server/hw/xfree86/common/xf86Globals.c +++ b/xorg-server/hw/xfree86/common/xf86Globals.c @@ -163,7 +163,7 @@ const char *xf86VisualNames[] = { }; /* Parameters set only from the command line */ -char *xf86ServerName = "no-name"; +const char *xf86ServerName = "no-name"; Bool xf86fpFlag = FALSE; Bool xf86sFlag = FALSE; Bool xf86bsEnableFlag = FALSE; diff --git a/xorg-server/hw/xfree86/common/xf86Mode.c b/xorg-server/hw/xfree86/common/xf86Mode.c index df0884794..d202d4079 100644 --- a/xorg-server/hw/xfree86/common/xf86Mode.c +++ b/xorg-server/hw/xfree86/common/xf86Mode.c @@ -1,2130 +1,2130 @@ -/* - * Copyright (c) 1997-2003 by The XFree86 Project, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the name of the copyright holder(s) - * and author(s) shall not be used in advertising or otherwise to promote - * the sale, use or other dealings in this Software without prior written - * authorization from the copyright holder(s) and author(s). - */ - -/* - * LCM() and scanLineWidth() are: - * - * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of Marc Aurele La France not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. Marc Aurele La France makes no representations - * about the suitability of this software for any purpose. It is provided - * "as-is" without express or implied warranty. - * - * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO - * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - * - * Copyright 1990,91,92,93 by Thomas Roell, Germany. - * Copyright 1991,92,93 by SGCS (Snitily Graphics Consulting Services), USA. - * - * Permission to use, copy, modify, distribute, and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation, and that the name of Thomas Roell nor - * SGCS be used in advertising or publicity pertaining to distribution - * of the software without specific, written prior permission. - * Thomas Roell nor SGCS makes no representations about the suitability - * of this software for any purpose. It is provided "as is" without - * express or implied warranty. - * - * THOMAS ROELL AND SGCS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS - * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR SGCS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF - * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * Authors: Dirk Hohndel - * David Dawes - * Marc La France - * ... and others - * - * This file includes helper functions for mode related things. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include -#endif - -#include -#include "xf86Modes.h" -#include "os.h" -#include "servermd.h" -#include "globals.h" -#include "xf86.h" -#include "xf86Priv.h" -#include "edid.h" - -static void -printModeRejectMessage(int index, DisplayModePtr p, int status) -{ - char *type; - - if (p->type & M_T_BUILTIN) - type = "built-in "; - else if (p->type & M_T_DEFAULT) - type = "default "; - else if (p->type & M_T_DRIVER) - type = "driver "; - else - type = ""; - - xf86DrvMsg(index, X_INFO, "Not using %smode \"%s\" (%s)\n", type, p->name, - xf86ModeStatusToString(status)); -} - -/* - * xf86GetNearestClock -- - * Find closest clock to given frequency (in kHz). This assumes the - * number of clocks is greater than zero. - */ -int -xf86GetNearestClock(ScrnInfoPtr scrp, int freq, Bool allowDiv2, - int DivFactor, int MulFactor, int *divider) -{ - int nearestClock = 0, nearestDiv = 1; - int minimumGap = abs(freq - scrp->clock[0]); - int i, j, k, gap; - - if (allowDiv2) - k = 2; - else - k = 1; - - /* Must set this here in case the best match is scrp->clock[0] */ - if (divider != NULL) - *divider = 0; - - for (i = 0; i < scrp->numClocks; i++) { - for (j = 1; j <= k; j++) { - gap = abs((freq * j) - ((scrp->clock[i] * DivFactor) / MulFactor)); - if ((gap < minimumGap) || - ((gap == minimumGap) && (j < nearestDiv))) { - minimumGap = gap; - nearestClock = i; - nearestDiv = j; - if (divider != NULL) - *divider = (j - 1) * V_CLKDIV2; - } - } - } - return nearestClock; -} - -/* - * xf86ModeStatusToString - * - * Convert a ModeStatus value to a printable message - */ - -const char * -xf86ModeStatusToString(ModeStatus status) -{ - switch (status) { - case MODE_OK: - return "Mode OK"; - case MODE_HSYNC: - return "hsync out of range"; - case MODE_VSYNC: - return "vrefresh out of range"; - case MODE_H_ILLEGAL: - return "illegal horizontal timings"; - case MODE_V_ILLEGAL: - return "illegal vertical timings"; - case MODE_BAD_WIDTH: - return "width requires unsupported line pitch"; - case MODE_NOMODE: - return "no mode of this name"; - case MODE_NO_INTERLACE: - return "interlace mode not supported"; - case MODE_NO_DBLESCAN: - return "doublescan mode not supported"; - case MODE_NO_VSCAN: - return "multiscan mode not supported"; - case MODE_MEM: - return "insufficient memory for mode"; - case MODE_VIRTUAL_X: - return "width too large for virtual size"; - case MODE_VIRTUAL_Y: - return "height too large for virtual size"; - case MODE_MEM_VIRT: - return "insufficient memory given virtual size"; - case MODE_NOCLOCK: - return "no clock available for mode"; - case MODE_CLOCK_HIGH: - return "mode clock too high"; - case MODE_CLOCK_LOW: - return "mode clock too low"; - case MODE_CLOCK_RANGE: - return "bad mode clock/interlace/doublescan"; - case MODE_BAD_HVALUE: - return "horizontal timing out of range"; - case MODE_BAD_VVALUE: - return "vertical timing out of range"; - case MODE_BAD_VSCAN: - return "VScan value out of range"; - case MODE_HSYNC_NARROW: - return "horizontal sync too narrow"; - case MODE_HSYNC_WIDE: - return "horizontal sync too wide"; - case MODE_HBLANK_NARROW: - return "horizontal blanking too narrow"; - case MODE_HBLANK_WIDE: - return "horizontal blanking too wide"; - case MODE_VSYNC_NARROW: - return "vertical sync too narrow"; - case MODE_VSYNC_WIDE: - return "vertical sync too wide"; - case MODE_VBLANK_NARROW: - return "vertical blanking too narrow"; - case MODE_VBLANK_WIDE: - return "vertical blanking too wide"; - case MODE_PANEL: - return "exceeds panel dimensions"; - case MODE_INTERLACE_WIDTH: - return "width too large for interlaced mode"; - case MODE_ONE_WIDTH: - return "all modes must have the same width"; - case MODE_ONE_HEIGHT: - return "all modes must have the same height"; - case MODE_ONE_SIZE: - return "all modes must have the same resolution"; - case MODE_NO_REDUCED: - return "monitor doesn't support reduced blanking"; - case MODE_BANDWIDTH: - return "mode requires too much memory bandwidth"; - case MODE_BAD: - return "unknown reason"; - case MODE_ERROR: - return "internal error"; - default: - return "unknown"; - } -} - -/* - * xf86ShowClockRanges() -- Print the clock ranges allowed - * and the clock values scaled by ClockMulFactor and ClockDivFactor - */ -void -xf86ShowClockRanges(ScrnInfoPtr scrp, ClockRangePtr clockRanges) -{ - ClockRangePtr cp; - int MulFactor = 1; - int DivFactor = 1; - int i, j; - int scaledClock; - - for (cp = clockRanges; cp != NULL; cp = cp->next) { - DivFactor = max(1, cp->ClockDivFactor); - MulFactor = max(1, cp->ClockMulFactor); - if (scrp->progClock) { - if (cp->minClock) { - if (cp->maxClock) { - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "Clock range: %6.2f to %6.2f MHz\n", - (double)cp->minClock / 1000.0, - (double)cp->maxClock / 1000.0); - } else { - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "Minimum clock: %6.2f MHz\n", - (double)cp->minClock / 1000.0); - } - } else { - if (cp->maxClock) { - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "Maximum clock: %6.2f MHz\n", - (double)cp->maxClock / 1000.0); - } - } - } else if (DivFactor > 1 || MulFactor > 1) { - j = 0; - for (i = 0; i < scrp->numClocks; i++) { - scaledClock = (scrp->clock[i] * DivFactor) / MulFactor; - if (scaledClock >= cp->minClock && scaledClock <= cp->maxClock) { - if ((j % 8) == 0) { - if (j > 0) - xf86ErrorF("\n"); - xf86DrvMsg(scrp->scrnIndex, X_INFO, "scaled clocks:"); - } - xf86ErrorF(" %6.2f", (double)scaledClock / 1000.0); - j++; - } - } - xf86ErrorF("\n"); - } - } -} - -static Bool -modeInClockRange(ClockRangePtr cp, DisplayModePtr p) -{ - return ((p->Clock >= cp->minClock) && - (p->Clock <= cp->maxClock) && - (cp->interlaceAllowed || !(p->Flags & V_INTERLACE)) && - (cp->doubleScanAllowed || - ((p->VScan <= 1) && !(p->Flags & V_DBLSCAN)))); -} - -/* - * xf86FindClockRangeForMode() [... like the name says ...] - */ -static ClockRangePtr -xf86FindClockRangeForMode(ClockRangePtr clockRanges, DisplayModePtr p) -{ - ClockRangePtr cp; - - for (cp = clockRanges; ; cp = cp->next) - if (!cp || modeInClockRange(cp, p)) - return cp; -} - - -/* - * xf86HandleBuiltinMode() - handles built-in modes - */ -static ModeStatus -xf86HandleBuiltinMode(ScrnInfoPtr scrp, - DisplayModePtr p, - DisplayModePtr modep, - ClockRangePtr clockRanges, - Bool allowDiv2) -{ - ClockRangePtr cp; - int extraFlags = 0; - int MulFactor = 1; - int DivFactor = 1; - int clockIndex; - - /* Reject previously rejected modes */ - if (p->status != MODE_OK) - return p->status; - - /* Reject previously considered modes */ - if (p->prev) - return MODE_NOMODE; - - if ((p->type & M_T_CLOCK_C) == M_T_CLOCK_C) { - /* Check clock is in range */ - cp = xf86FindClockRangeForMode(clockRanges, p); - if (cp == NULL){ - modep->type = p->type; - p->status = MODE_CLOCK_RANGE; - return MODE_CLOCK_RANGE; - } - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - if (!scrp->progClock) { - clockIndex = xf86GetNearestClock(scrp, p->Clock, allowDiv2, - cp->ClockDivFactor, - cp->ClockMulFactor, &extraFlags); - modep->Clock = (scrp->clock[clockIndex] * DivFactor) - / MulFactor; - modep->ClockIndex = clockIndex; - modep->SynthClock = scrp->clock[clockIndex]; - if (extraFlags & V_CLKDIV2) { - modep->Clock /= 2; - modep->SynthClock /= 2; - } - } else { - modep->Clock = p->Clock; - modep->ClockIndex = -1; - modep->SynthClock = (modep->Clock * MulFactor) - / DivFactor; - } - modep->PrivFlags = cp->PrivFlags; - } else { - if(!scrp->progClock) { - modep->Clock = p->Clock; - modep->ClockIndex = p->ClockIndex; - modep->SynthClock = p->SynthClock; - } else { - modep->Clock = p->Clock; - modep->ClockIndex = -1; - modep->SynthClock = p->SynthClock; - } - modep->PrivFlags = p->PrivFlags; - } - modep->type = p->type; - modep->HDisplay = p->HDisplay; - modep->HSyncStart = p->HSyncStart; - modep->HSyncEnd = p->HSyncEnd; - modep->HTotal = p->HTotal; - modep->HSkew = p->HSkew; - modep->VDisplay = p->VDisplay; - modep->VSyncStart = p->VSyncStart; - modep->VSyncEnd = p->VSyncEnd; - modep->VTotal = p->VTotal; - modep->VScan = p->VScan; - modep->Flags = p->Flags | extraFlags; - modep->CrtcHDisplay = p->CrtcHDisplay; - modep->CrtcHBlankStart = p->CrtcHBlankStart; - modep->CrtcHSyncStart = p->CrtcHSyncStart; - modep->CrtcHSyncEnd = p->CrtcHSyncEnd; - modep->CrtcHBlankEnd = p->CrtcHBlankEnd; - modep->CrtcHTotal = p->CrtcHTotal; - modep->CrtcHSkew = p->CrtcHSkew; - modep->CrtcVDisplay = p->CrtcVDisplay; - modep->CrtcVBlankStart = p->CrtcVBlankStart; - modep->CrtcVSyncStart = p->CrtcVSyncStart; - modep->CrtcVSyncEnd = p->CrtcVSyncEnd; - modep->CrtcVBlankEnd = p->CrtcVBlankEnd; - modep->CrtcVTotal = p->CrtcVTotal; - modep->CrtcHAdjusted = p->CrtcHAdjusted; - modep->CrtcVAdjusted = p->CrtcVAdjusted; - modep->HSync = p->HSync; - modep->VRefresh = p->VRefresh; - modep->Private = p->Private; - modep->PrivSize = p->PrivSize; - - p->prev = modep; - - return MODE_OK; -} - -/* - * xf86LookupMode - * - * This function returns a mode from the given list which matches the - * given name. When multiple modes with the same name are available, - * the method of picking the matching mode is determined by the - * strategy selected. - * - * This function takes the following parameters: - * scrp ScrnInfoPtr - * modep pointer to the returned mode, which must have the name - * field filled in. - * clockRanges a list of clock ranges. This is optional when all the - * modes are built-in modes. - * strategy how to decide which mode to use from multiple modes with - * the same name - * - * In addition, the following fields from the ScrnInfoRec are used: - * modePool the list of monitor modes compatible with the driver - * clocks a list of discrete clocks - * numClocks number of discrete clocks - * progClock clock is programmable - * - * If a mode was found, its values are filled in to the area pointed to - * by modep, If a mode was not found the return value indicates the - * reason. - */ - -ModeStatus -xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep, - ClockRangePtr clockRanges, LookupModeFlags strategy) -{ - DisplayModePtr p, bestMode = NULL; - ClockRangePtr cp; - int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1; - double refresh, bestRefresh = 0.0; - Bool found = FALSE; - int extraFlags = 0; - int clockIndex = -1; - int MulFactor = 1; - int DivFactor = 1; - int ModePrivFlags = 0; - ModeStatus status = MODE_NOMODE; - Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; - int n; - const int types[] = { - M_T_BUILTIN | M_T_PREFERRED, - M_T_BUILTIN, - M_T_USERDEF | M_T_PREFERRED, - M_T_USERDEF, - M_T_DRIVER | M_T_PREFERRED, - M_T_DRIVER, - 0 - }; - const int ntypes = sizeof(types) / sizeof(int); - - strategy &= ~(LOOKUP_CLKDIV2 | LOOKUP_OPTIONAL_TOLERANCES); - - /* Some sanity checking */ - if (scrp == NULL || scrp->modePool == NULL || - (!scrp->progClock && scrp->numClocks == 0)) { - ErrorF("xf86LookupMode: called with invalid scrnInfoRec\n"); - return MODE_ERROR; - } - if (modep == NULL || modep->name == NULL) { - ErrorF("xf86LookupMode: called with invalid modep\n"); - return MODE_ERROR; - } - for (cp = clockRanges; cp != NULL; cp = cp->next) { - /* DivFactor and MulFactor must be > 0 */ - cp->ClockDivFactor = max(1, cp->ClockDivFactor); - cp->ClockMulFactor = max(1, cp->ClockMulFactor); - } - - /* Scan the mode pool for matching names */ - for (n = 0; n < ntypes; n++) { - int type = types[n]; - for (p = scrp->modePool; p != NULL; p = p->next) { - - /* scan through the modes in the sort order above */ - if ((p->type & type) != type) - continue; - - if (strcmp(p->name, modep->name) == 0) { - - /* Skip over previously rejected modes */ - if (p->status != MODE_OK) { - if (!found) - status = p->status; - continue; - } - - /* Skip over previously considered modes */ - if (p->prev) - continue; - - if (p->type & M_T_BUILTIN) { - return xf86HandleBuiltinMode(scrp, p,modep, clockRanges, - allowDiv2); - } - - /* Check clock is in range */ - cp = xf86FindClockRangeForMode(clockRanges, p); - if (cp == NULL) { - /* - * XXX Could do more here to provide a more detailed - * reason for not finding a mode. - */ - p->status = MODE_CLOCK_RANGE; - if (!found) - status = MODE_CLOCK_RANGE; - continue; - } - - /* - * If programmable clock and strategy is not - * LOOKUP_BEST_REFRESH, the required mode has been found, - * otherwise record the refresh and continue looking. - */ - if (scrp->progClock) { - found = TRUE; - if (strategy != LOOKUP_BEST_REFRESH) { - bestMode = p; - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - break; - } - refresh = xf86ModeVRefresh(p); - if (p->Flags & V_INTERLACE) - refresh /= INTERLACE_REFRESH_WEIGHT; - if (refresh > bestRefresh) { - bestMode = p; - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - bestRefresh = refresh; - } - continue; - } - - /* - * Clock is in range, so if it is not a programmable clock, find - * a matching clock. - */ - - i = xf86GetNearestClock(scrp, p->Clock, allowDiv2, - cp->ClockDivFactor, cp->ClockMulFactor, &k); - /* - * If the clock is too far from the requested clock, this - * mode is no good. - */ - if (k & V_CLKDIV2) - gap = abs((p->Clock * 2) - - ((scrp->clock[i] * cp->ClockDivFactor) / - cp->ClockMulFactor)); - else - gap = abs(p->Clock - - ((scrp->clock[i] * cp->ClockDivFactor) / - cp->ClockMulFactor)); - if (gap > minimumGap) { - p->status = MODE_NOCLOCK; - if (!found) - status = MODE_NOCLOCK; - continue; - } - found = TRUE; - - if (strategy == LOOKUP_BEST_REFRESH) { - refresh = xf86ModeVRefresh(p); - if (p->Flags & V_INTERLACE) - refresh /= INTERLACE_REFRESH_WEIGHT; - if (refresh > bestRefresh) { - bestMode = p; - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - extraFlags = k; - clockIndex = i; - bestRefresh = refresh; - } - continue; - } - if (strategy == LOOKUP_CLOSEST_CLOCK) { - if (gap < minimumGap) { - bestMode = p; - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - extraFlags = k; - clockIndex = i; - minimumGap = gap; - } - continue; - } - /* - * If strategy is neither LOOKUP_BEST_REFRESH or - * LOOKUP_CLOSEST_CLOCK the required mode has been found. - */ - bestMode = p; - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - extraFlags = k; - clockIndex = i; - break; - } - } - if (found) break; - } - if (!found || bestMode == NULL) - return status; - - /* Fill in the mode parameters */ - if (scrp->progClock) { - modep->Clock = bestMode->Clock; - modep->ClockIndex = -1; - modep->SynthClock = (modep->Clock * MulFactor) / DivFactor; - } else { - modep->Clock = (scrp->clock[clockIndex] * DivFactor) / - MulFactor; - modep->ClockIndex = clockIndex; - modep->SynthClock = scrp->clock[clockIndex]; - if (extraFlags & V_CLKDIV2) { - modep->Clock /= 2; - modep->SynthClock /= 2; - } - } - modep->type = bestMode->type; - modep->PrivFlags = ModePrivFlags; - modep->HDisplay = bestMode->HDisplay; - modep->HSyncStart = bestMode->HSyncStart; - modep->HSyncEnd = bestMode->HSyncEnd; - modep->HTotal = bestMode->HTotal; - modep->HSkew = bestMode->HSkew; - modep->VDisplay = bestMode->VDisplay; - modep->VSyncStart = bestMode->VSyncStart; - modep->VSyncEnd = bestMode->VSyncEnd; - modep->VTotal = bestMode->VTotal; - modep->VScan = bestMode->VScan; - modep->Flags = bestMode->Flags | extraFlags; - modep->CrtcHDisplay = bestMode->CrtcHDisplay; - modep->CrtcHBlankStart = bestMode->CrtcHBlankStart; - modep->CrtcHSyncStart = bestMode->CrtcHSyncStart; - modep->CrtcHSyncEnd = bestMode->CrtcHSyncEnd; - modep->CrtcHBlankEnd = bestMode->CrtcHBlankEnd; - modep->CrtcHTotal = bestMode->CrtcHTotal; - modep->CrtcHSkew = bestMode->CrtcHSkew; - modep->CrtcVDisplay = bestMode->CrtcVDisplay; - modep->CrtcVBlankStart = bestMode->CrtcVBlankStart; - modep->CrtcVSyncStart = bestMode->CrtcVSyncStart; - modep->CrtcVSyncEnd = bestMode->CrtcVSyncEnd; - modep->CrtcVBlankEnd = bestMode->CrtcVBlankEnd; - modep->CrtcVTotal = bestMode->CrtcVTotal; - modep->CrtcHAdjusted = bestMode->CrtcHAdjusted; - modep->CrtcVAdjusted = bestMode->CrtcVAdjusted; - modep->HSync = bestMode->HSync; - modep->VRefresh = bestMode->VRefresh; - modep->Private = bestMode->Private; - modep->PrivSize = bestMode->PrivSize; - - bestMode->prev = modep; - - return MODE_OK; -} - -/* - * xf86CheckModeForMonitor - * - * This function takes a mode and monitor description, and determines - * if the mode is valid for the monitor. - */ -ModeStatus -xf86CheckModeForMonitor(DisplayModePtr mode, MonPtr monitor) -{ - int i; - - /* Sanity checks */ - if (mode == NULL || monitor == NULL) { - ErrorF("xf86CheckModeForMonitor: called with invalid parameters\n"); - return MODE_ERROR; - } - - DebugF("xf86CheckModeForMonitor(%p %s, %p %s)\n", - mode, mode->name, monitor, monitor->id); - - /* Some basic mode validity checks */ - if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || - mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) - return MODE_H_ILLEGAL; - - if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || - mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) - return MODE_V_ILLEGAL; - - if (monitor->nHsync > 0) { - /* Check hsync against the allowed ranges */ - float hsync = xf86ModeHSync(mode); - for (i = 0; i < monitor->nHsync; i++) - if ((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) && - (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE))) - break; - - /* Now see whether we ran out of sync ranges without finding a match */ - if (i == monitor->nHsync) - return MODE_HSYNC; - } - - if (monitor->nVrefresh > 0) { - /* Check vrefresh against the allowed ranges */ - float vrefrsh = xf86ModeVRefresh(mode); - for (i = 0; i < monitor->nVrefresh; i++) - if ((vrefrsh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) && - (vrefrsh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE))) - break; - - /* Now see whether we ran out of refresh ranges without finding a match */ - if (i == monitor->nVrefresh) - return MODE_VSYNC; - } - - /* Force interlaced modes to have an odd VTotal */ - if (mode->Flags & V_INTERLACE) - mode->CrtcVTotal = mode->VTotal |= 1; - - /* - * This code stops cvt -r modes, and only cvt -r modes, from hitting 15y+ - * old CRTs which might, when there is a lot of solar flare activity and - * when the celestial bodies are unfavourably aligned, implode trying to - * sync to it. It's called "Protecting the user from doing anything stupid". - * -- libv - */ - - if (xf86ModeIsReduced(mode)) { - if (!monitor->reducedblanking && !(mode->type & M_T_DRIVER)) - return MODE_NO_REDUCED; - } - - if ((monitor->maxPixClock) && (mode->Clock > monitor->maxPixClock)) - return MODE_CLOCK_HIGH; - - return MODE_OK; -} - -/* - * xf86CheckModeSize - * - * An internal routine to check if a mode fits in video memory. This tries to - * avoid overflows that would otherwise occur when video memory size is greater - * than 256MB. - */ -static Bool -xf86CheckModeSize(ScrnInfoPtr scrp, int w, int x, int y) -{ - int bpp = scrp->fbFormat.bitsPerPixel, - pad = scrp->fbFormat.scanlinePad; - int lineWidth, lastWidth; - - if (scrp->depth == 4) - pad *= 4; /* 4 planes */ - - /* Sanity check */ - if ((w < 0) || (x < 0) || (y <= 0)) - return FALSE; - - lineWidth = (((w * bpp) + pad - 1) / pad) * pad; - lastWidth = x * bpp; - - /* - * At this point, we need to compare - * - * (lineWidth * (y - 1)) + lastWidth - * - * against - * - * scrp->videoRam * (1024 * 8) - * - * These are bit quantities. To avoid overflows, do the comparison in - * terms of BITMAP_SCANLINE_PAD units. This assumes BITMAP_SCANLINE_PAD - * is a power of 2. We currently use 32, which limits us to a video - * memory size of 8GB. - */ - - lineWidth = (lineWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; - lastWidth = (lastWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; - - if ((lineWidth * (y - 1) + lastWidth) > - (scrp->videoRam * ((1024 * 8) / BITMAP_SCANLINE_PAD))) - return FALSE; - - return TRUE; -} - -/* - * xf86InitialCheckModeForDriver - * - * This function checks if a mode satisfies a driver's initial requirements: - * - mode size fits within the available pixel area (memory) - * - width lies within the range of supported line pitches - * - mode size fits within virtual size (if fixed) - * - horizontal timings are in range - * - * This function takes the following parameters: - * scrp ScrnInfoPtr - * mode mode to check - * maxPitch (optional) maximum line pitch - * virtualX (optional) virtual width requested - * virtualY (optional) virtual height requested - * - * In addition, the following fields from the ScrnInfoRec are used: - * monitor pointer to structure for monitor section - * fbFormat pixel format for the framebuffer - * videoRam video memory size (in kB) - * maxHValue maximum horizontal timing value - * maxVValue maximum vertical timing value - */ - -ModeStatus -xf86InitialCheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, - ClockRangePtr clockRanges, - LookupModeFlags strategy, - int maxPitch, int virtualX, int virtualY) -{ - ClockRangePtr cp; - ModeStatus status; - Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; - int i, needDiv2; - - /* Sanity checks */ - if (!scrp || !mode || !clockRanges) { - ErrorF("xf86InitialCheckModeForDriver: " - "called with invalid parameters\n"); - return MODE_ERROR; - } - - DebugF("xf86InitialCheckModeForDriver(%p, %p %s, %p, 0x%x, %d, %d, %d)\n", - scrp, mode, mode->name , clockRanges, strategy, maxPitch, virtualX, virtualY); - - /* Some basic mode validity checks */ - if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || - mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) - return MODE_H_ILLEGAL; - - if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || - mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) - return MODE_V_ILLEGAL; - - if (!xf86CheckModeSize(scrp, mode->HDisplay, mode->HDisplay, - mode->VDisplay)) - return MODE_MEM; - - if (maxPitch > 0 && mode->HDisplay > maxPitch) - return MODE_BAD_WIDTH; - - if (virtualX > 0 && mode->HDisplay > virtualX) - return MODE_VIRTUAL_X; - - if (virtualY > 0 && mode->VDisplay > virtualY) - return MODE_VIRTUAL_Y; - - if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue) - return MODE_BAD_HVALUE; - - if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue) - return MODE_BAD_VVALUE; - - /* - * The use of the DisplayModeRec's Crtc* and SynthClock elements below is - * provisional, in that they are later reused by the driver at mode-set - * time. Here, they are temporarily enlisted to contain the mode timings - * as seen by the CRT or panel (rather than the CRTC). The driver's - * ValidMode() is allowed to modify these so it can deal with such things - * as mode stretching and/or centering. The driver should >NOT< modify the - * user-supplied values as these are reported back when mode validation is - * said and done. - */ - /* - * NOTE: We (ab)use the mode->Crtc* values here to store timing - * information for the calculation of Hsync and Vrefresh. Before - * these values are calculated the driver is given the opportunity - * to either set these HSync and VRefresh itself or modify the timing - * values. - * The difference to the final calculation is small but imortand: - * here we pass the flag INTERLACE_HALVE_V regardless if the driver - * sets it or not. This way our calculation of VRefresh has the same - * effect as if we do if (flags & V_INTERLACE) refresh *= 2.0 - * This dual use of the mode->Crtc* values will certainly create - * confusion and is bad software design. However since it's part of - * the driver API it's hard to change. - */ - - if (scrp->ValidMode) { - - xf86SetModeCrtc(mode, INTERLACE_HALVE_V); - - cp = xf86FindClockRangeForMode(clockRanges, mode); - if (!cp) - return MODE_CLOCK_RANGE; - - if (cp->ClockMulFactor < 1) - cp->ClockMulFactor = 1; - if (cp->ClockDivFactor < 1) - cp->ClockDivFactor = 1; - - /* - * XXX The effect of clock dividers and multipliers on the monitor's - * pixel clock needs to be verified. - */ - if (scrp->progClock) { - mode->SynthClock = mode->Clock; - } else { - i = xf86GetNearestClock(scrp, mode->Clock, allowDiv2, - cp->ClockDivFactor, cp->ClockMulFactor, - &needDiv2); - mode->SynthClock = (scrp->clock[i] * cp->ClockDivFactor) / - cp->ClockMulFactor; - if (needDiv2 & V_CLKDIV2) - mode->SynthClock /= 2; - } - - status = (*scrp->ValidMode)(scrp->scrnIndex, mode, FALSE, - MODECHECK_INITIAL); - if (status != MODE_OK) - return status; - - if (mode->HSync <= 0.0) - mode->HSync = (float)mode->SynthClock / (float)mode->CrtcHTotal; - if (mode->VRefresh <= 0.0) - mode->VRefresh = (mode->SynthClock * 1000.0) - / (mode->CrtcHTotal * mode->CrtcVTotal); - } - - mode->HSync = xf86ModeHSync(mode); - mode->VRefresh = xf86ModeVRefresh(mode); - - /* Assume it is OK */ - return MODE_OK; -} - -/* - * xf86CheckModeForDriver - * - * This function is for checking modes while the server is running (for - * use mainly by the VidMode extension). - * - * This function checks if a mode satisfies a driver's requirements: - * - width lies within the line pitch - * - mode size fits within virtual size - * - horizontal/vertical timings are in range - * - * This function takes the following parameters: - * scrp ScrnInfoPtr - * mode mode to check - * flags not (currently) used - * - * In addition, the following fields from the ScrnInfoRec are used: - * maxHValue maximum horizontal timing value - * maxVValue maximum vertical timing value - * virtualX virtual width - * virtualY virtual height - * clockRanges allowable clock ranges - */ - -ModeStatus -xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, int flags) -{ - ClockRangePtr cp; - int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1; - int extraFlags = 0; - int clockIndex = -1; - int MulFactor = 1; - int DivFactor = 1; - int ModePrivFlags = 0; - ModeStatus status = MODE_NOMODE; - - /* Some sanity checking */ - if (scrp == NULL || (!scrp->progClock && scrp->numClocks == 0)) { - ErrorF("xf86CheckModeForDriver: called with invalid scrnInfoRec\n"); - return MODE_ERROR; - } - if (mode == NULL) { - ErrorF("xf86CheckModeForDriver: called with invalid modep\n"); - return MODE_ERROR; - } - - /* Check the mode size */ - if (mode->HDisplay > scrp->virtualX) - return MODE_VIRTUAL_X; - - if (mode->VDisplay > scrp->virtualY) - return MODE_VIRTUAL_Y; - - if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue) - return MODE_BAD_HVALUE; - - if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue) - return MODE_BAD_VVALUE; - - for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { - /* DivFactor and MulFactor must be > 0 */ - cp->ClockDivFactor = max(1, cp->ClockDivFactor); - cp->ClockMulFactor = max(1, cp->ClockMulFactor); - } - - if (scrp->progClock) { - /* Check clock is in range */ - for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { - if (modeInClockRange(cp, mode)) - break; - } - if (cp == NULL) { - return MODE_CLOCK_RANGE; - } - /* - * If programmable clock the required mode has been found - */ - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - } else { - status = MODE_CLOCK_RANGE; - /* Check clock is in range */ - for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { - if (modeInClockRange(cp, mode)) { - /* - * Clock is in range, so if it is not a programmable clock, - * find a matching clock. - */ - - i = xf86GetNearestClock(scrp, mode->Clock, 0, - cp->ClockDivFactor, cp->ClockMulFactor, &k); - /* - * If the clock is too far from the requested clock, this - * mode is no good. - */ - if (k & V_CLKDIV2) - gap = abs((mode->Clock * 2) - - ((scrp->clock[i] * cp->ClockDivFactor) / - cp->ClockMulFactor)); - else - gap = abs(mode->Clock - - ((scrp->clock[i] * cp->ClockDivFactor) / - cp->ClockMulFactor)); - if (gap > minimumGap) { - status = MODE_NOCLOCK; - continue; - } - - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - extraFlags = k; - clockIndex = i; - break; - } - } - if (cp == NULL) - return status; - } - - /* Fill in the mode parameters */ - if (scrp->progClock) { - mode->ClockIndex = -1; - mode->SynthClock = (mode->Clock * MulFactor) / DivFactor; - } else { - mode->Clock = (scrp->clock[clockIndex] * DivFactor) / MulFactor; - mode->ClockIndex = clockIndex; - mode->SynthClock = scrp->clock[clockIndex]; - if (extraFlags & V_CLKDIV2) { - mode->Clock /= 2; - mode->SynthClock /= 2; - } - } - mode->PrivFlags = ModePrivFlags; - - return MODE_OK; -} - -static int -inferVirtualSize(ScrnInfoPtr scrp, DisplayModePtr modes, int *vx, int *vy) -{ - float aspect = 0.0; - MonPtr mon = scrp->monitor; - xf86MonPtr DDC; - int x = 0, y = 0; - DisplayModePtr mode; - - if (!mon) return 0; - DDC = mon->DDC; - - if (DDC && DDC->ver.revision >= 4) { - /* For 1.4, we might actually get native pixel format. How novel. */ - if (PREFERRED_TIMING_MODE(DDC->features.msc)) { - for (mode = modes; mode; mode = mode->next) { - if (mode->type & (M_T_DRIVER | M_T_PREFERRED)) { - x = mode->HDisplay; - y = mode->VDisplay; - goto found; - } - } - } - /* - * Even if we don't, we might get aspect ratio from extra CVT info - * or from the monitor size fields. TODO. - */ - } - - /* - * Technically this triggers if either is zero. That wasn't legal - * before EDID 1.4, but right now we'll get that wrong. TODO. - */ - if (!aspect) { - if (!mon->widthmm || !mon->heightmm) - aspect = 4.0/3.0; - else - aspect = (float)mon->widthmm / (float)mon->heightmm; - } - - /* find the largest M_T_DRIVER mode with that aspect ratio */ - for (mode = modes; mode; mode = mode->next) { - float mode_aspect, metaspect; - if (!(mode->type & (M_T_DRIVER|M_T_USERDEF))) - continue; - mode_aspect = (float)mode->HDisplay / (float)mode->VDisplay; - metaspect = aspect / mode_aspect; - /* 5% slop or so, since we only get size in centimeters */ - if (fabs(1.0 - metaspect) < 0.05) { - if ((mode->HDisplay > x) && (mode->VDisplay > y)) { - x = mode->HDisplay; - y = mode->VDisplay; - } - } - } - - if (!x || !y) { - xf86DrvMsg(scrp->scrnIndex, X_WARNING, - "Unable to estimate virtual size\n"); - return 0; - } - -found: - *vx = x; - *vy = y; - - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "Estimated virtual size for aspect ratio %.4f is %dx%d\n", - aspect, *vx, *vy); - - return 1; -} - -/* Least common multiple */ -static unsigned int -LCM(unsigned int x, unsigned int y) -{ - unsigned int m = x, n = y, o; - - while ((o = m % n)) - { - m = n; - n = o; - } - - return (x / n) * y; -} - -/* - * Given various screen attributes, determine the minimum scanline width such - * that each scanline is server and DDX padded and any pixels with imbedded - * bank boundaries are off-screen. This function returns -1 if such a width - * cannot exist. - */ -static int -scanLineWidth( - unsigned int xsize, /* pixels */ - unsigned int ysize, /* pixels */ - unsigned int width, /* pixels */ - unsigned long BankSize, /* char's */ - PixmapFormatRec *pBankFormat, - unsigned int nWidthUnit /* bits */ -) -{ - unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit; - unsigned long minBitsPerScanline, maxBitsPerScanline; - - /* Sanity checks */ - - if (!nWidthUnit || !pBankFormat) - return -1; - - nBitsPerBank = BankSize * 8; - if (nBitsPerBank % pBankFormat->scanlinePad) - return -1; - - if (xsize > width) - width = xsize; - nBitsPerScanlinePadUnit = LCM(pBankFormat->scanlinePad, nWidthUnit); - nBitsPerScanline = - (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) / - nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit; - width = nBitsPerScanline / pBankFormat->bitsPerPixel; - - if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel)) - return (int)width; - - /* - * Scanlines will be server-pad aligned at this point. They will also be - * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded - * bank boundaries are off-screen. - * - * It seems reasonable to limit total frame buffer size to 1/16 of the - * theoretical maximum address space size. On a machine with 32-bit - * addresses (to 8-bit quantities) this turns out to be 256MB. Not only - * does this provide a simple limiting condition for the loops below, but - * it also prevents unsigned long wraparounds. - */ - if (!ysize) - return -1; - - minBitsPerScanline = xsize * pBankFormat->bitsPerPixel; - if (minBitsPerScanline > nBitsPerBank) - return -1; - - if (ysize == 1) - return (int)width; - - maxBitsPerScanline = - (((unsigned long)(-1) >> 1) - minBitsPerScanline) / (ysize - 1); - while (nBitsPerScanline <= maxBitsPerScanline) - { - unsigned long BankBase, BankUnit; - - BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) * - nBitsPerBank; - if (!(BankUnit % nBitsPerScanline)) - return (int)width; - - for (BankBase = BankUnit; ; BankBase += nBitsPerBank) - { - unsigned long x, y; - - y = BankBase / nBitsPerScanline; - if (y >= ysize) - return (int)width; - - x = BankBase % nBitsPerScanline; - if (!(x % pBankFormat->bitsPerPixel)) - continue; - - if (x < minBitsPerScanline) - { - /* - * Skip ahead certain widths by dividing the excess scanline - * amongst the y's. - */ - y *= nBitsPerScanlinePadUnit; - nBitsPerScanline += - ((x + y - 1) / y) * nBitsPerScanlinePadUnit; - width = nBitsPerScanline / pBankFormat->bitsPerPixel; - break; - } - - if (BankBase != BankUnit) - continue; - - if (!(nBitsPerScanline % x)) - return (int)width; - - BankBase = ((nBitsPerScanline - minBitsPerScanline) / - (nBitsPerScanline - x)) * BankUnit; - } - } - - return -1; -} - -/* - * xf86ValidateModes - * - * This function takes a set of mode names, modes and limiting conditions, - * and selects a set of modes and parameters based on those conditions. - * - * This function takes the following parameters: - * scrp ScrnInfoPtr - * availModes the list of modes available for the monitor - * modeNames (optional) list of mode names that the screen is requesting - * clockRanges a list of clock ranges - * linePitches (optional) a list of line pitches - * minPitch (optional) minimum line pitch (in pixels) - * maxPitch (optional) maximum line pitch (in pixels) - * pitchInc (mandatory) pitch increment (in bits) - * minHeight (optional) minimum virtual height (in pixels) - * maxHeight (optional) maximum virtual height (in pixels) - * virtualX (optional) virtual width requested (in pixels) - * virtualY (optional) virtual height requested (in pixels) - * apertureSize size of video aperture (in bytes) - * strategy how to decide which mode to use from multiple modes with - * the same name - * - * In addition, the following fields from the ScrnInfoRec are used: - * clocks a list of discrete clocks - * numClocks number of discrete clocks - * progClock clock is programmable - * monitor pointer to structure for monitor section - * fbFormat format of the framebuffer - * videoRam video memory size - * maxHValue maximum horizontal timing value - * maxVValue maximum vertical timing value - * xInc horizontal timing increment (defaults to 8 pixels) - * - * The function fills in the following ScrnInfoRec fields: - * modePool A subset of the modes available to the monitor which - * are compatible with the driver. - * modes one mode entry for each of the requested modes, with the - * status field filled in to indicate if the mode has been - * accepted or not. - * virtualX the resulting virtual width - * virtualY the resulting virtual height - * displayWidth the resulting line pitch - * - * The function's return value is the number of matching modes found, or -1 - * if an unrecoverable error was encountered. - */ - -int -xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, - char **modeNames, ClockRangePtr clockRanges, - int *linePitches, int minPitch, int maxPitch, int pitchInc, - int minHeight, int maxHeight, int virtualX, int virtualY, - int apertureSize, LookupModeFlags strategy) -{ - DisplayModePtr p, q, r, new, last, *endp; - int i, numModes = 0; - ModeStatus status; - int linePitch = -1, virtX = 0, virtY = 0; - int newLinePitch, newVirtX, newVirtY; - int modeSize; /* in pixels */ - Bool validateAllDefaultModes = FALSE; - Bool userModes = FALSE; - int saveType; - PixmapFormatRec *BankFormat; - ClockRangePtr cp; - ClockRangePtr storeClockRanges; - int numTimings = 0; - range hsync[MAX_HSYNC]; - range vrefresh[MAX_VREFRESH]; - Bool inferred_virtual = FALSE; - - DebugF("xf86ValidateModes(%p, %p, %p, %p,\n\t\t %p, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x)\n", - scrp, availModes, modeNames, clockRanges, - linePitches, minPitch, maxPitch, pitchInc, - minHeight, maxHeight, virtualX, virtualY, - apertureSize, strategy - ); - - /* Some sanity checking */ - if (scrp == NULL || scrp->name == NULL || !scrp->monitor || - (!scrp->progClock && scrp->numClocks == 0)) { - ErrorF("xf86ValidateModes: called with invalid scrnInfoRec\n"); - return -1; - } - if (linePitches != NULL && linePitches[0] <= 0) { - ErrorF("xf86ValidateModes: called with invalid linePitches\n"); - return -1; - } - if (pitchInc <= 0) { - ErrorF("xf86ValidateModes: called with invalid pitchInc\n"); - return -1; - } - if ((virtualX > 0) != (virtualY > 0)) { - ErrorF("xf86ValidateModes: called with invalid virtual resolution\n"); - return -1; - } - - /* - * If requested by the driver, allow missing hsync and/or vrefresh ranges - * in the monitor section. - */ - if (strategy & LOOKUP_OPTIONAL_TOLERANCES) { - strategy &= ~LOOKUP_OPTIONAL_TOLERANCES; - } else { - const char *type = ""; - Bool specified = FALSE; - - if (scrp->monitor->nHsync <= 0) { - if (numTimings > 0) { - scrp->monitor->nHsync = numTimings; - for (i = 0; i < numTimings; i++) { - scrp->monitor->hsync[i].lo = hsync[i].lo; - scrp->monitor->hsync[i].hi = hsync[i].hi; - } - } else { - scrp->monitor->hsync[0].lo = 31.5; - scrp->monitor->hsync[0].hi = 48.0; - scrp->monitor->nHsync = 1; - } - type = "default "; - } else { - specified = TRUE; - } - for (i = 0; i < scrp->monitor->nHsync; i++) { - if (scrp->monitor->hsync[i].lo == scrp->monitor->hsync[i].hi) - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "%s: Using %shsync value of %.2f kHz\n", - scrp->monitor->id, type, - scrp->monitor->hsync[i].lo); - else - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "%s: Using %shsync range of %.2f-%.2f kHz\n", - scrp->monitor->id, type, - scrp->monitor->hsync[i].lo, - scrp->monitor->hsync[i].hi); - } - - type = ""; - if (scrp->monitor->nVrefresh <= 0) { - if (numTimings > 0) { - scrp->monitor->nVrefresh = numTimings; - for (i = 0; i < numTimings; i++) { - scrp->monitor->vrefresh[i].lo = vrefresh[i].lo; - scrp->monitor->vrefresh[i].hi = vrefresh[i].hi; - } - } else { - scrp->monitor->vrefresh[0].lo = 50; - scrp->monitor->vrefresh[0].hi = 70; - scrp->monitor->nVrefresh = 1; - } - type = "default "; - } else { - specified = TRUE; - } - for (i = 0; i < scrp->monitor->nVrefresh; i++) { - if (scrp->monitor->vrefresh[i].lo == scrp->monitor->vrefresh[i].hi) - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "%s: Using %svrefresh value of %.2f Hz\n", - scrp->monitor->id, type, - scrp->monitor->vrefresh[i].lo); - else - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "%s: Using %svrefresh range of %.2f-%.2f Hz\n", - scrp->monitor->id, type, - scrp->monitor->vrefresh[i].lo, - scrp->monitor->vrefresh[i].hi); - } - - type = ""; - if (!scrp->monitor->maxPixClock && !specified) { - type = "default "; - scrp->monitor->maxPixClock = 65000.0; - } - if (scrp->monitor->maxPixClock) { - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "%s: Using %smaximum pixel clock of %.2f MHz\n", - scrp->monitor->id, type, - (float)scrp->monitor->maxPixClock / 1000.0); - } - } - - /* - * Store the clockRanges for later use by the VidMode extension. - */ - storeClockRanges = scrp->clockRanges; - while (storeClockRanges != NULL) { - storeClockRanges = storeClockRanges->next; - } - for (cp = clockRanges; cp != NULL; cp = cp->next, - storeClockRanges = storeClockRanges->next) { - storeClockRanges = xnfalloc(sizeof(ClockRange)); - if (scrp->clockRanges == NULL) - scrp->clockRanges = storeClockRanges; - memcpy(storeClockRanges, cp, sizeof(ClockRange)); - } - - /* Determine which pixmap format to pass to scanLineWidth() */ - if (scrp->depth > 4) - BankFormat = &scrp->fbFormat; - else - BankFormat = xf86GetPixFormat(scrp, 1); /* >not< scrp->depth! */ - - if (scrp->xInc <= 0) - scrp->xInc = 8; /* Suitable for VGA and others */ - -#define _VIRTUALX(x) ((((x) + scrp->xInc - 1) / scrp->xInc) * scrp->xInc) - - /* - * Determine maxPitch if it wasn't given explicitly. Note linePitches - * always takes precedence if is non-NULL. In that case the minPitch and - * maxPitch values passed are ignored. - */ - if (linePitches) { - minPitch = maxPitch = linePitches[0]; - for (i = 1; linePitches[i] > 0; i++) { - if (linePitches[i] > maxPitch) - maxPitch = linePitches[i]; - if (linePitches[i] < minPitch) - minPitch = linePitches[i]; - } - } - - /* Initial check of virtual size against other constraints */ - scrp->virtualFrom = X_PROBED; - /* - * Initialise virtX and virtY if the values are fixed. - */ - if (virtualY > 0) { - if (maxHeight > 0 && virtualY > maxHeight) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Virtual height (%d) is too large for the hardware " - "(max %d)\n", virtualY, maxHeight); - return -1; - } - - if (minHeight > 0 && virtualY < minHeight) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Virtual height (%d) is too small for the hardware " - "(min %d)\n", virtualY, minHeight); - return -1; - } - - virtualX = _VIRTUALX(virtualX); - if (linePitches != NULL) { - for (i = 0; linePitches[i] != 0; i++) { - if ((linePitches[i] >= virtualX) && - (linePitches[i] == - scanLineWidth(virtualX, virtualY, linePitches[i], - apertureSize, BankFormat, pitchInc))) { - linePitch = linePitches[i]; - break; - } - } - } else { - linePitch = scanLineWidth(virtualX, virtualY, minPitch, - apertureSize, BankFormat, pitchInc); - } - - if ((linePitch < minPitch) || (linePitch > maxPitch)) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Virtual width (%d) is too large for the hardware " - "(max %d)\n", virtualX, maxPitch); - return -1; - } - - if (!xf86CheckModeSize(scrp, linePitch, virtualX, virtualY)) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Virtual size (%dx%d) (pitch %d) exceeds video memory\n", - virtualX, virtualY, linePitch); - return -1; - } - - virtX = virtualX; - virtY = virtualY; - scrp->virtualFrom = X_CONFIG; - } else if (!modeNames || !*modeNames) { - /* No virtual size given in the config, try to infer */ - /* XXX this doesn't take m{in,ax}Pitch into account; oh well */ - inferred_virtual = inferVirtualSize(scrp, availModes, &virtX, &virtY); - if (inferred_virtual) - linePitch = scanLineWidth(virtX, virtY, minPitch, apertureSize, - BankFormat, pitchInc); - } - - /* Print clock ranges and scaled clocks */ - xf86ShowClockRanges(scrp, clockRanges); - - /* - * If scrp->modePool hasn't been setup yet, set it up now. This allows the - * modes that the driver definitely can't use to be weeded out early. Note - * that a modePool mode's prev field is used to hold a pointer to the - * member of the scrp->modes list for which a match was considered. - */ - if (scrp->modePool == NULL) { - q = NULL; - for (p = availModes; p != NULL; p = p->next) { - status = xf86InitialCheckModeForDriver(scrp, p, clockRanges, - strategy, maxPitch, - virtX, virtY); - - if (status == MODE_OK) { - status = xf86CheckModeForMonitor(p, scrp->monitor); - } - - if (status == MODE_OK) { - new = xnfalloc(sizeof(DisplayModeRec)); - *new = *p; - new->next = NULL; - if (!q) { - scrp->modePool = new; - } else { - q->next = new; - } - new->prev = NULL; - q = new; - q->name = xnfstrdup(p->name); - q->status = MODE_OK; - } else { - printModeRejectMessage(scrp->scrnIndex, p, status); - } - } - - if (scrp->modePool == NULL) { - xf86DrvMsg(scrp->scrnIndex, X_WARNING, "Mode pool is empty\n"); - return 0; - } - } else { - for (p = scrp->modePool; p != NULL; p = p->next) { - p->prev = NULL; - p->status = MODE_OK; - } - } - - /* - * Allocate one entry in scrp->modes for each named mode. - */ - while (scrp->modes) - xf86DeleteMode(&scrp->modes, scrp->modes); - endp = &scrp->modes; - last = NULL; - if (modeNames != NULL) { - for (i = 0; modeNames[i] != NULL; i++) { - userModes = TRUE; - new = xnfcalloc(1, sizeof(DisplayModeRec)); - new->prev = last; - new->type = M_T_USERDEF; - new->name = xnfstrdup(modeNames[i]); - if (new->prev) - new->prev->next = new; - *endp = last = new; - endp = &new->next; - } - } - - /* Lookup each mode */ -#ifdef RANDR - if (!xf86Info.disableRandR -#ifdef PANORAMIX - && noPanoramiXExtension -#endif - ) - validateAllDefaultModes = TRUE; -#endif - - for (p = scrp->modes; ; p = p->next) { - Bool repeat; - - /* - * If the supplied mode names don't produce a valid mode, scan through - * unconsidered modePool members until one survives validation. This - * is done in decreasing order by mode pixel area. - */ - - if (p == NULL) { - if ((numModes > 0) && !validateAllDefaultModes) - break; - - validateAllDefaultModes = TRUE; - r = NULL; - modeSize = 0; - for (q = scrp->modePool; q != NULL; q = q->next) { - if ((q->prev == NULL) && (q->status == MODE_OK)) { - /* - * Deal with the case where this mode wasn't considered - * because of a builtin mode of the same name. - */ - for (p = scrp->modes; p != NULL; p = p->next) { - if ((p->status != MODE_OK) && - !strcmp(p->name, q->name)) - break; - } - - if (p != NULL) - q->prev = p; - else { - /* - * A quick check to not allow default modes with - * horizontal timing parameters that CRTs may have - * problems with. - */ - if (!scrp->monitor->reducedblanking && - (q->type & M_T_DEFAULT) && - ((double)q->HTotal / (double)q->HDisplay) < 1.15) - continue; - - if (modeSize < (q->HDisplay * q->VDisplay)) { - r = q; - modeSize = q->HDisplay * q->VDisplay; - } - } - } - } - - if (r == NULL) - break; - - p = xnfcalloc(1, sizeof(DisplayModeRec)); - p->prev = last; - p->name = xnfstrdup(r->name); - if (!userModes) - p->type = M_T_USERDEF; - if (p->prev) - p->prev->next = p; - *endp = last = p; - endp = &p->next; - } - - repeat = FALSE; - lookupNext: - if (repeat && ((status = p->status) != MODE_OK)) - printModeRejectMessage(scrp->scrnIndex, p, status); - saveType = p->type; - status = xf86LookupMode(scrp, p, clockRanges, strategy); - if (repeat && status == MODE_NOMODE) - continue; - if (status != MODE_OK) - printModeRejectMessage(scrp->scrnIndex, p, status); - if (status == MODE_ERROR) { - ErrorF("xf86ValidateModes: " - "unexpected result from xf86LookupMode()\n"); - return -1; - } - if (status != MODE_OK) { - if (p->status == MODE_OK) - p->status = status; - continue; - } - p->type |= saveType; - repeat = TRUE; - - newLinePitch = linePitch; - newVirtX = virtX; - newVirtY = virtY; - - /* - * Don't let non-user defined modes increase the virtual size - */ - if (!(p->type & M_T_USERDEF) && (numModes > 0)) { - if (p->HDisplay > virtX) { - p->status = MODE_VIRTUAL_X; - goto lookupNext; - } - if (p->VDisplay > virtY) { - p->status = MODE_VIRTUAL_Y; - goto lookupNext; - } - } - /* - * Adjust virtual width and height if the mode is too large for the - * current values and if they are not fixed. - */ - if (virtualX <= 0 && p->HDisplay > newVirtX) - newVirtX = _VIRTUALX(p->HDisplay); - if (virtualY <= 0 && p->VDisplay > newVirtY) { - if (maxHeight > 0 && p->VDisplay > maxHeight) { - p->status = MODE_VIRTUAL_Y; /* ? */ - goto lookupNext; - } - newVirtY = p->VDisplay; - } - - /* - * If virtual resolution is to be increased, revalidate it. - */ - if ((virtX != newVirtX) || (virtY != newVirtY)) { - if (linePitches != NULL) { - newLinePitch = -1; - for (i = 0; linePitches[i] != 0; i++) { - if ((linePitches[i] >= newVirtX) && - (linePitches[i] >= linePitch) && - (linePitches[i] == - scanLineWidth(newVirtX, newVirtY, linePitches[i], - apertureSize, BankFormat, pitchInc))) { - newLinePitch = linePitches[i]; - break; - } - } - } else { - if (linePitch < minPitch) - linePitch = minPitch; - newLinePitch = scanLineWidth(newVirtX, newVirtY, linePitch, - apertureSize, BankFormat, - pitchInc); - } - if ((newLinePitch < minPitch) || (newLinePitch > maxPitch)) { - p->status = MODE_BAD_WIDTH; - goto lookupNext; - } - - /* - * Check that the pixel area required by the new virtual height - * and line pitch isn't too large. - */ - if (!xf86CheckModeSize(scrp, newLinePitch, newVirtX, newVirtY)) { - p->status = MODE_MEM_VIRT; - goto lookupNext; - } - } - - if (scrp->ValidMode) { - /* - * Give the driver a final say, passing it the proposed virtual - * geometry. - */ - scrp->virtualX = newVirtX; - scrp->virtualY = newVirtY; - scrp->displayWidth = newLinePitch; - p->status = (scrp->ValidMode)(scrp->scrnIndex, p, FALSE, - MODECHECK_FINAL); - - if (p->status != MODE_OK) { - goto lookupNext; - } - } - - /* Mode has passed all the tests */ - virtX = newVirtX; - virtY = newVirtY; - linePitch = newLinePitch; - p->status = MODE_OK; - numModes++; - } - - /* - * If we estimated the virtual size above, we may have filtered away all - * the modes that maximally match that size; scan again to find out and - * fix up if so. - */ - if (inferred_virtual) { - int vx = 0, vy = 0; - for (p = scrp->modes; p; p = p->next) { - if (p->HDisplay > vx && p->VDisplay > vy) { - vx = p->HDisplay; - vy = p->VDisplay; - } - } - if (vx < virtX || vy < virtY) { - const int types[] = { - M_T_BUILTIN | M_T_PREFERRED, - M_T_BUILTIN, - M_T_DRIVER | M_T_PREFERRED, - M_T_DRIVER, - 0 - }; - const int ntypes = sizeof(types) / sizeof(int); - int n; - - /* - * We did not find the estimated virtual size. So now we want to - * find the largest mode available, but we want to search in the - * modes in the order of "types" listed above. - */ - for (n = 0; n < ntypes; n++) { - int type = types[n]; - - vx = 0; vy = 0; - for (p = scrp->modes; p; p = p->next) { - /* scan through the modes in the sort order above */ - if ((p->type & type) != type) - continue; - if (p->HDisplay > vx && p->VDisplay > vy) { - vx = p->HDisplay; - vy = p->VDisplay; - } - } - if (vx && vy) - /* Found one */ - break; - } - xf86DrvMsg(scrp->scrnIndex, X_WARNING, - "Shrinking virtual size estimate from %dx%d to %dx%d\n", - virtX, virtY, vx, vy); - virtX = _VIRTUALX(vx); - virtY = vy; - for (p = scrp->modes; p; p = p->next) { - if (numModes > 0) { - if (p->HDisplay > virtX) - p->status = MODE_VIRTUAL_X; - if (p->VDisplay > virtY) - p->status = MODE_VIRTUAL_Y; - if (p->status != MODE_OK) { - numModes--; - printModeRejectMessage(scrp->scrnIndex, p, p->status); - } - } - } - if (linePitches != NULL) { - for (i = 0; linePitches[i] != 0; i++) { - if ((linePitches[i] >= virtX) && - (linePitches[i] == - scanLineWidth(virtX, virtY, linePitches[i], - apertureSize, BankFormat, pitchInc))) { - linePitch = linePitches[i]; - break; - } - } - } else { - linePitch = scanLineWidth(virtX, virtY, minPitch, - apertureSize, BankFormat, pitchInc); - } - } - } - - /* Update the ScrnInfoRec parameters */ - - scrp->virtualX = virtX; - scrp->virtualY = virtY; - scrp->displayWidth = linePitch; - - if (numModes <= 0) - return 0; - - /* Make the mode list into a circular list by joining up the ends */ - p = scrp->modes; - while (p->next != NULL) - p = p->next; - /* p is now the last mode on the list */ - p->next = scrp->modes; - scrp->modes->prev = p; - - if (minHeight > 0 && virtY < minHeight) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Virtual height (%d) is too small for the hardware " - "(min %d)\n", virtY, minHeight); - return -1; - } - - return numModes; -} - -/* - * xf86DeleteMode - * - * This function removes a mode from a list of modes. - * - * There are different types of mode lists: - * - * - singly linked linear lists, ending in NULL - * - doubly linked linear lists, starting and ending in NULL - * - doubly linked circular lists - * - */ - -void -xf86DeleteMode(DisplayModePtr *modeList, DisplayModePtr mode) -{ - /* Catch the easy/insane cases */ - if (modeList == NULL || *modeList == NULL || mode == NULL) - return; - - /* If the mode is at the start of the list, move the start of the list */ - if (*modeList == mode) - *modeList = mode->next; - - /* If mode is the only one on the list, set the list to NULL */ - if ((mode == mode->prev) && (mode == mode->next)) { - *modeList = NULL; - } else { - if ((mode->prev != NULL) && (mode->prev->next == mode)) - mode->prev->next = mode->next; - if ((mode->next != NULL) && (mode->next->prev == mode)) - mode->next->prev = mode->prev; - } - - free(mode->name); - free(mode); -} - -/* - * xf86PruneDriverModes - * - * Remove modes from the driver's mode list which have been marked as - * invalid. - */ - -void -xf86PruneDriverModes(ScrnInfoPtr scrp) -{ - DisplayModePtr first, p, n; - - p = scrp->modes; - if (p == NULL) - return; - - do { - if (!(first = scrp->modes)) - return; - n = p->next; - if (p->status != MODE_OK) { - xf86DeleteMode(&(scrp->modes), p); - } - p = n; - } while (p != NULL && p != first); - - /* modePool is no longer needed, turf it */ - while (scrp->modePool) { - /* - * A modePool mode's prev field is used to hold a pointer to the - * member of the scrp->modes list for which a match was considered. - * Clear that pointer first, otherwise xf86DeleteMode might get - * confused - */ - scrp->modePool->prev = NULL; - xf86DeleteMode(&scrp->modePool, scrp->modePool); - } -} - - -/* - * xf86SetCrtcForModes - * - * Goes through the screen's mode list, and initialises the Crtc - * parameters for each mode. The initialisation includes adjustments - * for interlaced and double scan modes. - */ -void -xf86SetCrtcForModes(ScrnInfoPtr scrp, int adjustFlags) -{ - DisplayModePtr p; - - /* - * Store adjustFlags for use with the VidMode extension. There is an - * implicit assumption here that SetCrtcForModes is called once. - */ - scrp->adjustFlags = adjustFlags; - - p = scrp->modes; - if (p == NULL) - return; - - do { - xf86SetModeCrtc(p, adjustFlags); - DebugF("%sMode %s: %d (%d) %d %d (%d) %d %d (%d) %d %d (%d) %d\n", - (p->type & M_T_DEFAULT) ? "Default " : "", - p->name, p->CrtcHDisplay, p->CrtcHBlankStart, - p->CrtcHSyncStart, p->CrtcHSyncEnd, p->CrtcHBlankEnd, - p->CrtcHTotal, p->CrtcVDisplay, p->CrtcVBlankStart, - p->CrtcVSyncStart, p->CrtcVSyncEnd, p->CrtcVBlankEnd, - p->CrtcVTotal); - p = p->next; - } while (p != NULL && p != scrp->modes); -} - -void -xf86PrintModes(ScrnInfoPtr scrp) -{ - DisplayModePtr p; - float hsync, refresh = 0; - char *desc, *desc2, *prefix, *uprefix; - - if (scrp == NULL) - return; - - xf86DrvMsg(scrp->scrnIndex, scrp->virtualFrom, "Virtual size is %dx%d " - "(pitch %d)\n", scrp->virtualX, scrp->virtualY, - scrp->displayWidth); - - p = scrp->modes; - if (p == NULL) - return; - - do { - desc = desc2 = ""; - hsync = xf86ModeHSync(p); - refresh = xf86ModeVRefresh(p); - if (p->Flags & V_INTERLACE) { - desc = " (I)"; - } - if (p->Flags & V_DBLSCAN) { - desc = " (D)"; - } - if (p->VScan > 1) { - desc2 = " (VScan)"; - } - if (p->type & M_T_BUILTIN) - prefix = "Built-in mode"; - else if (p->type & M_T_DEFAULT) - prefix = "Default mode"; - else if (p->type & M_T_DRIVER) - prefix = "Driver mode"; - else - prefix = "Mode"; - if (p->type & M_T_USERDEF) - uprefix = "*"; - else - uprefix = " "; - if (hsync == 0 || refresh == 0) { - if (p->name) - xf86DrvMsg(scrp->scrnIndex, X_CONFIG, - "%s%s \"%s\"\n", uprefix, prefix, p->name); - else - xf86DrvMsg(scrp->scrnIndex, X_PROBED, - "%s%s %dx%d (unnamed)\n", - uprefix, prefix, p->HDisplay, p->VDisplay); - } else if (p->Clock == p->SynthClock) { - xf86DrvMsg(scrp->scrnIndex, X_CONFIG, - "%s%s \"%s\": %.1f MHz, %.1f kHz, %.1f Hz%s%s\n", - uprefix, prefix, p->name, p->Clock / 1000.0, - hsync, refresh, desc, desc2); - } else { - xf86DrvMsg(scrp->scrnIndex, X_CONFIG, - "%s%s \"%s\": %.1f MHz (scaled from %.1f MHz), " - "%.1f kHz, %.1f Hz%s%s\n", - uprefix, prefix, p->name, p->Clock / 1000.0, - p->SynthClock / 1000.0, hsync, refresh, desc, desc2); - } - if (hsync != 0 && refresh != 0) - xf86PrintModeline(scrp->scrnIndex,p); - p = p->next; - } while (p != NULL && p != scrp->modes); -} +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +/* + * LCM() and scanLineWidth() are: + * + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Copyright 1990,91,92,93 by Thomas Roell, Germany. + * Copyright 1991,92,93 by SGCS (Snitily Graphics Consulting Services), USA. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of Thomas Roell nor + * SGCS be used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * Thomas Roell nor SGCS makes no representations about the suitability + * of this software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * THOMAS ROELL AND SGCS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR SGCS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Authors: Dirk Hohndel + * David Dawes + * Marc La France + * ... and others + * + * This file includes helper functions for mode related things. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#include +#include "xf86Modes.h" +#include "os.h" +#include "servermd.h" +#include "globals.h" +#include "xf86.h" +#include "xf86Priv.h" +#include "edid.h" + +static void +printModeRejectMessage(int index, DisplayModePtr p, int status) +{ + const char *type; + + if (p->type & M_T_BUILTIN) + type = "built-in "; + else if (p->type & M_T_DEFAULT) + type = "default "; + else if (p->type & M_T_DRIVER) + type = "driver "; + else + type = ""; + + xf86DrvMsg(index, X_INFO, "Not using %smode \"%s\" (%s)\n", type, p->name, + xf86ModeStatusToString(status)); +} + +/* + * xf86GetNearestClock -- + * Find closest clock to given frequency (in kHz). This assumes the + * number of clocks is greater than zero. + */ +int +xf86GetNearestClock(ScrnInfoPtr scrp, int freq, Bool allowDiv2, + int DivFactor, int MulFactor, int *divider) +{ + int nearestClock = 0, nearestDiv = 1; + int minimumGap = abs(freq - scrp->clock[0]); + int i, j, k, gap; + + if (allowDiv2) + k = 2; + else + k = 1; + + /* Must set this here in case the best match is scrp->clock[0] */ + if (divider != NULL) + *divider = 0; + + for (i = 0; i < scrp->numClocks; i++) { + for (j = 1; j <= k; j++) { + gap = abs((freq * j) - ((scrp->clock[i] * DivFactor) / MulFactor)); + if ((gap < minimumGap) || + ((gap == minimumGap) && (j < nearestDiv))) { + minimumGap = gap; + nearestClock = i; + nearestDiv = j; + if (divider != NULL) + *divider = (j - 1) * V_CLKDIV2; + } + } + } + return nearestClock; +} + +/* + * xf86ModeStatusToString + * + * Convert a ModeStatus value to a printable message + */ + +const char * +xf86ModeStatusToString(ModeStatus status) +{ + switch (status) { + case MODE_OK: + return "Mode OK"; + case MODE_HSYNC: + return "hsync out of range"; + case MODE_VSYNC: + return "vrefresh out of range"; + case MODE_H_ILLEGAL: + return "illegal horizontal timings"; + case MODE_V_ILLEGAL: + return "illegal vertical timings"; + case MODE_BAD_WIDTH: + return "width requires unsupported line pitch"; + case MODE_NOMODE: + return "no mode of this name"; + case MODE_NO_INTERLACE: + return "interlace mode not supported"; + case MODE_NO_DBLESCAN: + return "doublescan mode not supported"; + case MODE_NO_VSCAN: + return "multiscan mode not supported"; + case MODE_MEM: + return "insufficient memory for mode"; + case MODE_VIRTUAL_X: + return "width too large for virtual size"; + case MODE_VIRTUAL_Y: + return "height too large for virtual size"; + case MODE_MEM_VIRT: + return "insufficient memory given virtual size"; + case MODE_NOCLOCK: + return "no clock available for mode"; + case MODE_CLOCK_HIGH: + return "mode clock too high"; + case MODE_CLOCK_LOW: + return "mode clock too low"; + case MODE_CLOCK_RANGE: + return "bad mode clock/interlace/doublescan"; + case MODE_BAD_HVALUE: + return "horizontal timing out of range"; + case MODE_BAD_VVALUE: + return "vertical timing out of range"; + case MODE_BAD_VSCAN: + return "VScan value out of range"; + case MODE_HSYNC_NARROW: + return "horizontal sync too narrow"; + case MODE_HSYNC_WIDE: + return "horizontal sync too wide"; + case MODE_HBLANK_NARROW: + return "horizontal blanking too narrow"; + case MODE_HBLANK_WIDE: + return "horizontal blanking too wide"; + case MODE_VSYNC_NARROW: + return "vertical sync too narrow"; + case MODE_VSYNC_WIDE: + return "vertical sync too wide"; + case MODE_VBLANK_NARROW: + return "vertical blanking too narrow"; + case MODE_VBLANK_WIDE: + return "vertical blanking too wide"; + case MODE_PANEL: + return "exceeds panel dimensions"; + case MODE_INTERLACE_WIDTH: + return "width too large for interlaced mode"; + case MODE_ONE_WIDTH: + return "all modes must have the same width"; + case MODE_ONE_HEIGHT: + return "all modes must have the same height"; + case MODE_ONE_SIZE: + return "all modes must have the same resolution"; + case MODE_NO_REDUCED: + return "monitor doesn't support reduced blanking"; + case MODE_BANDWIDTH: + return "mode requires too much memory bandwidth"; + case MODE_BAD: + return "unknown reason"; + case MODE_ERROR: + return "internal error"; + default: + return "unknown"; + } +} + +/* + * xf86ShowClockRanges() -- Print the clock ranges allowed + * and the clock values scaled by ClockMulFactor and ClockDivFactor + */ +void +xf86ShowClockRanges(ScrnInfoPtr scrp, ClockRangePtr clockRanges) +{ + ClockRangePtr cp; + int MulFactor = 1; + int DivFactor = 1; + int i, j; + int scaledClock; + + for (cp = clockRanges; cp != NULL; cp = cp->next) { + DivFactor = max(1, cp->ClockDivFactor); + MulFactor = max(1, cp->ClockMulFactor); + if (scrp->progClock) { + if (cp->minClock) { + if (cp->maxClock) { + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "Clock range: %6.2f to %6.2f MHz\n", + (double)cp->minClock / 1000.0, + (double)cp->maxClock / 1000.0); + } else { + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "Minimum clock: %6.2f MHz\n", + (double)cp->minClock / 1000.0); + } + } else { + if (cp->maxClock) { + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "Maximum clock: %6.2f MHz\n", + (double)cp->maxClock / 1000.0); + } + } + } else if (DivFactor > 1 || MulFactor > 1) { + j = 0; + for (i = 0; i < scrp->numClocks; i++) { + scaledClock = (scrp->clock[i] * DivFactor) / MulFactor; + if (scaledClock >= cp->minClock && scaledClock <= cp->maxClock) { + if ((j % 8) == 0) { + if (j > 0) + xf86ErrorF("\n"); + xf86DrvMsg(scrp->scrnIndex, X_INFO, "scaled clocks:"); + } + xf86ErrorF(" %6.2f", (double)scaledClock / 1000.0); + j++; + } + } + xf86ErrorF("\n"); + } + } +} + +static Bool +modeInClockRange(ClockRangePtr cp, DisplayModePtr p) +{ + return ((p->Clock >= cp->minClock) && + (p->Clock <= cp->maxClock) && + (cp->interlaceAllowed || !(p->Flags & V_INTERLACE)) && + (cp->doubleScanAllowed || + ((p->VScan <= 1) && !(p->Flags & V_DBLSCAN)))); +} + +/* + * xf86FindClockRangeForMode() [... like the name says ...] + */ +static ClockRangePtr +xf86FindClockRangeForMode(ClockRangePtr clockRanges, DisplayModePtr p) +{ + ClockRangePtr cp; + + for (cp = clockRanges; ; cp = cp->next) + if (!cp || modeInClockRange(cp, p)) + return cp; +} + + +/* + * xf86HandleBuiltinMode() - handles built-in modes + */ +static ModeStatus +xf86HandleBuiltinMode(ScrnInfoPtr scrp, + DisplayModePtr p, + DisplayModePtr modep, + ClockRangePtr clockRanges, + Bool allowDiv2) +{ + ClockRangePtr cp; + int extraFlags = 0; + int MulFactor = 1; + int DivFactor = 1; + int clockIndex; + + /* Reject previously rejected modes */ + if (p->status != MODE_OK) + return p->status; + + /* Reject previously considered modes */ + if (p->prev) + return MODE_NOMODE; + + if ((p->type & M_T_CLOCK_C) == M_T_CLOCK_C) { + /* Check clock is in range */ + cp = xf86FindClockRangeForMode(clockRanges, p); + if (cp == NULL){ + modep->type = p->type; + p->status = MODE_CLOCK_RANGE; + return MODE_CLOCK_RANGE; + } + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + if (!scrp->progClock) { + clockIndex = xf86GetNearestClock(scrp, p->Clock, allowDiv2, + cp->ClockDivFactor, + cp->ClockMulFactor, &extraFlags); + modep->Clock = (scrp->clock[clockIndex] * DivFactor) + / MulFactor; + modep->ClockIndex = clockIndex; + modep->SynthClock = scrp->clock[clockIndex]; + if (extraFlags & V_CLKDIV2) { + modep->Clock /= 2; + modep->SynthClock /= 2; + } + } else { + modep->Clock = p->Clock; + modep->ClockIndex = -1; + modep->SynthClock = (modep->Clock * MulFactor) + / DivFactor; + } + modep->PrivFlags = cp->PrivFlags; + } else { + if(!scrp->progClock) { + modep->Clock = p->Clock; + modep->ClockIndex = p->ClockIndex; + modep->SynthClock = p->SynthClock; + } else { + modep->Clock = p->Clock; + modep->ClockIndex = -1; + modep->SynthClock = p->SynthClock; + } + modep->PrivFlags = p->PrivFlags; + } + modep->type = p->type; + modep->HDisplay = p->HDisplay; + modep->HSyncStart = p->HSyncStart; + modep->HSyncEnd = p->HSyncEnd; + modep->HTotal = p->HTotal; + modep->HSkew = p->HSkew; + modep->VDisplay = p->VDisplay; + modep->VSyncStart = p->VSyncStart; + modep->VSyncEnd = p->VSyncEnd; + modep->VTotal = p->VTotal; + modep->VScan = p->VScan; + modep->Flags = p->Flags | extraFlags; + modep->CrtcHDisplay = p->CrtcHDisplay; + modep->CrtcHBlankStart = p->CrtcHBlankStart; + modep->CrtcHSyncStart = p->CrtcHSyncStart; + modep->CrtcHSyncEnd = p->CrtcHSyncEnd; + modep->CrtcHBlankEnd = p->CrtcHBlankEnd; + modep->CrtcHTotal = p->CrtcHTotal; + modep->CrtcHSkew = p->CrtcHSkew; + modep->CrtcVDisplay = p->CrtcVDisplay; + modep->CrtcVBlankStart = p->CrtcVBlankStart; + modep->CrtcVSyncStart = p->CrtcVSyncStart; + modep->CrtcVSyncEnd = p->CrtcVSyncEnd; + modep->CrtcVBlankEnd = p->CrtcVBlankEnd; + modep->CrtcVTotal = p->CrtcVTotal; + modep->CrtcHAdjusted = p->CrtcHAdjusted; + modep->CrtcVAdjusted = p->CrtcVAdjusted; + modep->HSync = p->HSync; + modep->VRefresh = p->VRefresh; + modep->Private = p->Private; + modep->PrivSize = p->PrivSize; + + p->prev = modep; + + return MODE_OK; +} + +/* + * xf86LookupMode + * + * This function returns a mode from the given list which matches the + * given name. When multiple modes with the same name are available, + * the method of picking the matching mode is determined by the + * strategy selected. + * + * This function takes the following parameters: + * scrp ScrnInfoPtr + * modep pointer to the returned mode, which must have the name + * field filled in. + * clockRanges a list of clock ranges. This is optional when all the + * modes are built-in modes. + * strategy how to decide which mode to use from multiple modes with + * the same name + * + * In addition, the following fields from the ScrnInfoRec are used: + * modePool the list of monitor modes compatible with the driver + * clocks a list of discrete clocks + * numClocks number of discrete clocks + * progClock clock is programmable + * + * If a mode was found, its values are filled in to the area pointed to + * by modep, If a mode was not found the return value indicates the + * reason. + */ + +ModeStatus +xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep, + ClockRangePtr clockRanges, LookupModeFlags strategy) +{ + DisplayModePtr p, bestMode = NULL; + ClockRangePtr cp; + int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1; + double refresh, bestRefresh = 0.0; + Bool found = FALSE; + int extraFlags = 0; + int clockIndex = -1; + int MulFactor = 1; + int DivFactor = 1; + int ModePrivFlags = 0; + ModeStatus status = MODE_NOMODE; + Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; + int n; + const int types[] = { + M_T_BUILTIN | M_T_PREFERRED, + M_T_BUILTIN, + M_T_USERDEF | M_T_PREFERRED, + M_T_USERDEF, + M_T_DRIVER | M_T_PREFERRED, + M_T_DRIVER, + 0 + }; + const int ntypes = sizeof(types) / sizeof(int); + + strategy &= ~(LOOKUP_CLKDIV2 | LOOKUP_OPTIONAL_TOLERANCES); + + /* Some sanity checking */ + if (scrp == NULL || scrp->modePool == NULL || + (!scrp->progClock && scrp->numClocks == 0)) { + ErrorF("xf86LookupMode: called with invalid scrnInfoRec\n"); + return MODE_ERROR; + } + if (modep == NULL || modep->name == NULL) { + ErrorF("xf86LookupMode: called with invalid modep\n"); + return MODE_ERROR; + } + for (cp = clockRanges; cp != NULL; cp = cp->next) { + /* DivFactor and MulFactor must be > 0 */ + cp->ClockDivFactor = max(1, cp->ClockDivFactor); + cp->ClockMulFactor = max(1, cp->ClockMulFactor); + } + + /* Scan the mode pool for matching names */ + for (n = 0; n < ntypes; n++) { + int type = types[n]; + for (p = scrp->modePool; p != NULL; p = p->next) { + + /* scan through the modes in the sort order above */ + if ((p->type & type) != type) + continue; + + if (strcmp(p->name, modep->name) == 0) { + + /* Skip over previously rejected modes */ + if (p->status != MODE_OK) { + if (!found) + status = p->status; + continue; + } + + /* Skip over previously considered modes */ + if (p->prev) + continue; + + if (p->type & M_T_BUILTIN) { + return xf86HandleBuiltinMode(scrp, p,modep, clockRanges, + allowDiv2); + } + + /* Check clock is in range */ + cp = xf86FindClockRangeForMode(clockRanges, p); + if (cp == NULL) { + /* + * XXX Could do more here to provide a more detailed + * reason for not finding a mode. + */ + p->status = MODE_CLOCK_RANGE; + if (!found) + status = MODE_CLOCK_RANGE; + continue; + } + + /* + * If programmable clock and strategy is not + * LOOKUP_BEST_REFRESH, the required mode has been found, + * otherwise record the refresh and continue looking. + */ + if (scrp->progClock) { + found = TRUE; + if (strategy != LOOKUP_BEST_REFRESH) { + bestMode = p; + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + break; + } + refresh = xf86ModeVRefresh(p); + if (p->Flags & V_INTERLACE) + refresh /= INTERLACE_REFRESH_WEIGHT; + if (refresh > bestRefresh) { + bestMode = p; + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + bestRefresh = refresh; + } + continue; + } + + /* + * Clock is in range, so if it is not a programmable clock, find + * a matching clock. + */ + + i = xf86GetNearestClock(scrp, p->Clock, allowDiv2, + cp->ClockDivFactor, cp->ClockMulFactor, &k); + /* + * If the clock is too far from the requested clock, this + * mode is no good. + */ + if (k & V_CLKDIV2) + gap = abs((p->Clock * 2) - + ((scrp->clock[i] * cp->ClockDivFactor) / + cp->ClockMulFactor)); + else + gap = abs(p->Clock - + ((scrp->clock[i] * cp->ClockDivFactor) / + cp->ClockMulFactor)); + if (gap > minimumGap) { + p->status = MODE_NOCLOCK; + if (!found) + status = MODE_NOCLOCK; + continue; + } + found = TRUE; + + if (strategy == LOOKUP_BEST_REFRESH) { + refresh = xf86ModeVRefresh(p); + if (p->Flags & V_INTERLACE) + refresh /= INTERLACE_REFRESH_WEIGHT; + if (refresh > bestRefresh) { + bestMode = p; + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + extraFlags = k; + clockIndex = i; + bestRefresh = refresh; + } + continue; + } + if (strategy == LOOKUP_CLOSEST_CLOCK) { + if (gap < minimumGap) { + bestMode = p; + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + extraFlags = k; + clockIndex = i; + minimumGap = gap; + } + continue; + } + /* + * If strategy is neither LOOKUP_BEST_REFRESH or + * LOOKUP_CLOSEST_CLOCK the required mode has been found. + */ + bestMode = p; + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + extraFlags = k; + clockIndex = i; + break; + } + } + if (found) break; + } + if (!found || bestMode == NULL) + return status; + + /* Fill in the mode parameters */ + if (scrp->progClock) { + modep->Clock = bestMode->Clock; + modep->ClockIndex = -1; + modep->SynthClock = (modep->Clock * MulFactor) / DivFactor; + } else { + modep->Clock = (scrp->clock[clockIndex] * DivFactor) / + MulFactor; + modep->ClockIndex = clockIndex; + modep->SynthClock = scrp->clock[clockIndex]; + if (extraFlags & V_CLKDIV2) { + modep->Clock /= 2; + modep->SynthClock /= 2; + } + } + modep->type = bestMode->type; + modep->PrivFlags = ModePrivFlags; + modep->HDisplay = bestMode->HDisplay; + modep->HSyncStart = bestMode->HSyncStart; + modep->HSyncEnd = bestMode->HSyncEnd; + modep->HTotal = bestMode->HTotal; + modep->HSkew = bestMode->HSkew; + modep->VDisplay = bestMode->VDisplay; + modep->VSyncStart = bestMode->VSyncStart; + modep->VSyncEnd = bestMode->VSyncEnd; + modep->VTotal = bestMode->VTotal; + modep->VScan = bestMode->VScan; + modep->Flags = bestMode->Flags | extraFlags; + modep->CrtcHDisplay = bestMode->CrtcHDisplay; + modep->CrtcHBlankStart = bestMode->CrtcHBlankStart; + modep->CrtcHSyncStart = bestMode->CrtcHSyncStart; + modep->CrtcHSyncEnd = bestMode->CrtcHSyncEnd; + modep->CrtcHBlankEnd = bestMode->CrtcHBlankEnd; + modep->CrtcHTotal = bestMode->CrtcHTotal; + modep->CrtcHSkew = bestMode->CrtcHSkew; + modep->CrtcVDisplay = bestMode->CrtcVDisplay; + modep->CrtcVBlankStart = bestMode->CrtcVBlankStart; + modep->CrtcVSyncStart = bestMode->CrtcVSyncStart; + modep->CrtcVSyncEnd = bestMode->CrtcVSyncEnd; + modep->CrtcVBlankEnd = bestMode->CrtcVBlankEnd; + modep->CrtcVTotal = bestMode->CrtcVTotal; + modep->CrtcHAdjusted = bestMode->CrtcHAdjusted; + modep->CrtcVAdjusted = bestMode->CrtcVAdjusted; + modep->HSync = bestMode->HSync; + modep->VRefresh = bestMode->VRefresh; + modep->Private = bestMode->Private; + modep->PrivSize = bestMode->PrivSize; + + bestMode->prev = modep; + + return MODE_OK; +} + +/* + * xf86CheckModeForMonitor + * + * This function takes a mode and monitor description, and determines + * if the mode is valid for the monitor. + */ +ModeStatus +xf86CheckModeForMonitor(DisplayModePtr mode, MonPtr monitor) +{ + int i; + + /* Sanity checks */ + if (mode == NULL || monitor == NULL) { + ErrorF("xf86CheckModeForMonitor: called with invalid parameters\n"); + return MODE_ERROR; + } + + DebugF("xf86CheckModeForMonitor(%p %s, %p %s)\n", + mode, mode->name, monitor, monitor->id); + + /* Some basic mode validity checks */ + if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || + mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) + return MODE_H_ILLEGAL; + + if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || + mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) + return MODE_V_ILLEGAL; + + if (monitor->nHsync > 0) { + /* Check hsync against the allowed ranges */ + float hsync = xf86ModeHSync(mode); + for (i = 0; i < monitor->nHsync; i++) + if ((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) && + (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE))) + break; + + /* Now see whether we ran out of sync ranges without finding a match */ + if (i == monitor->nHsync) + return MODE_HSYNC; + } + + if (monitor->nVrefresh > 0) { + /* Check vrefresh against the allowed ranges */ + float vrefrsh = xf86ModeVRefresh(mode); + for (i = 0; i < monitor->nVrefresh; i++) + if ((vrefrsh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) && + (vrefrsh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE))) + break; + + /* Now see whether we ran out of refresh ranges without finding a match */ + if (i == monitor->nVrefresh) + return MODE_VSYNC; + } + + /* Force interlaced modes to have an odd VTotal */ + if (mode->Flags & V_INTERLACE) + mode->CrtcVTotal = mode->VTotal |= 1; + + /* + * This code stops cvt -r modes, and only cvt -r modes, from hitting 15y+ + * old CRTs which might, when there is a lot of solar flare activity and + * when the celestial bodies are unfavourably aligned, implode trying to + * sync to it. It's called "Protecting the user from doing anything stupid". + * -- libv + */ + + if (xf86ModeIsReduced(mode)) { + if (!monitor->reducedblanking && !(mode->type & M_T_DRIVER)) + return MODE_NO_REDUCED; + } + + if ((monitor->maxPixClock) && (mode->Clock > monitor->maxPixClock)) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +/* + * xf86CheckModeSize + * + * An internal routine to check if a mode fits in video memory. This tries to + * avoid overflows that would otherwise occur when video memory size is greater + * than 256MB. + */ +static Bool +xf86CheckModeSize(ScrnInfoPtr scrp, int w, int x, int y) +{ + int bpp = scrp->fbFormat.bitsPerPixel, + pad = scrp->fbFormat.scanlinePad; + int lineWidth, lastWidth; + + if (scrp->depth == 4) + pad *= 4; /* 4 planes */ + + /* Sanity check */ + if ((w < 0) || (x < 0) || (y <= 0)) + return FALSE; + + lineWidth = (((w * bpp) + pad - 1) / pad) * pad; + lastWidth = x * bpp; + + /* + * At this point, we need to compare + * + * (lineWidth * (y - 1)) + lastWidth + * + * against + * + * scrp->videoRam * (1024 * 8) + * + * These are bit quantities. To avoid overflows, do the comparison in + * terms of BITMAP_SCANLINE_PAD units. This assumes BITMAP_SCANLINE_PAD + * is a power of 2. We currently use 32, which limits us to a video + * memory size of 8GB. + */ + + lineWidth = (lineWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; + lastWidth = (lastWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; + + if ((lineWidth * (y - 1) + lastWidth) > + (scrp->videoRam * ((1024 * 8) / BITMAP_SCANLINE_PAD))) + return FALSE; + + return TRUE; +} + +/* + * xf86InitialCheckModeForDriver + * + * This function checks if a mode satisfies a driver's initial requirements: + * - mode size fits within the available pixel area (memory) + * - width lies within the range of supported line pitches + * - mode size fits within virtual size (if fixed) + * - horizontal timings are in range + * + * This function takes the following parameters: + * scrp ScrnInfoPtr + * mode mode to check + * maxPitch (optional) maximum line pitch + * virtualX (optional) virtual width requested + * virtualY (optional) virtual height requested + * + * In addition, the following fields from the ScrnInfoRec are used: + * monitor pointer to structure for monitor section + * fbFormat pixel format for the framebuffer + * videoRam video memory size (in kB) + * maxHValue maximum horizontal timing value + * maxVValue maximum vertical timing value + */ + +ModeStatus +xf86InitialCheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, + ClockRangePtr clockRanges, + LookupModeFlags strategy, + int maxPitch, int virtualX, int virtualY) +{ + ClockRangePtr cp; + ModeStatus status; + Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; + int i, needDiv2; + + /* Sanity checks */ + if (!scrp || !mode || !clockRanges) { + ErrorF("xf86InitialCheckModeForDriver: " + "called with invalid parameters\n"); + return MODE_ERROR; + } + + DebugF("xf86InitialCheckModeForDriver(%p, %p %s, %p, 0x%x, %d, %d, %d)\n", + scrp, mode, mode->name , clockRanges, strategy, maxPitch, virtualX, virtualY); + + /* Some basic mode validity checks */ + if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || + mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) + return MODE_H_ILLEGAL; + + if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || + mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) + return MODE_V_ILLEGAL; + + if (!xf86CheckModeSize(scrp, mode->HDisplay, mode->HDisplay, + mode->VDisplay)) + return MODE_MEM; + + if (maxPitch > 0 && mode->HDisplay > maxPitch) + return MODE_BAD_WIDTH; + + if (virtualX > 0 && mode->HDisplay > virtualX) + return MODE_VIRTUAL_X; + + if (virtualY > 0 && mode->VDisplay > virtualY) + return MODE_VIRTUAL_Y; + + if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue) + return MODE_BAD_HVALUE; + + if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue) + return MODE_BAD_VVALUE; + + /* + * The use of the DisplayModeRec's Crtc* and SynthClock elements below is + * provisional, in that they are later reused by the driver at mode-set + * time. Here, they are temporarily enlisted to contain the mode timings + * as seen by the CRT or panel (rather than the CRTC). The driver's + * ValidMode() is allowed to modify these so it can deal with such things + * as mode stretching and/or centering. The driver should >NOT< modify the + * user-supplied values as these are reported back when mode validation is + * said and done. + */ + /* + * NOTE: We (ab)use the mode->Crtc* values here to store timing + * information for the calculation of Hsync and Vrefresh. Before + * these values are calculated the driver is given the opportunity + * to either set these HSync and VRefresh itself or modify the timing + * values. + * The difference to the final calculation is small but imortand: + * here we pass the flag INTERLACE_HALVE_V regardless if the driver + * sets it or not. This way our calculation of VRefresh has the same + * effect as if we do if (flags & V_INTERLACE) refresh *= 2.0 + * This dual use of the mode->Crtc* values will certainly create + * confusion and is bad software design. However since it's part of + * the driver API it's hard to change. + */ + + if (scrp->ValidMode) { + + xf86SetModeCrtc(mode, INTERLACE_HALVE_V); + + cp = xf86FindClockRangeForMode(clockRanges, mode); + if (!cp) + return MODE_CLOCK_RANGE; + + if (cp->ClockMulFactor < 1) + cp->ClockMulFactor = 1; + if (cp->ClockDivFactor < 1) + cp->ClockDivFactor = 1; + + /* + * XXX The effect of clock dividers and multipliers on the monitor's + * pixel clock needs to be verified. + */ + if (scrp->progClock) { + mode->SynthClock = mode->Clock; + } else { + i = xf86GetNearestClock(scrp, mode->Clock, allowDiv2, + cp->ClockDivFactor, cp->ClockMulFactor, + &needDiv2); + mode->SynthClock = (scrp->clock[i] * cp->ClockDivFactor) / + cp->ClockMulFactor; + if (needDiv2 & V_CLKDIV2) + mode->SynthClock /= 2; + } + + status = (*scrp->ValidMode)(scrp->scrnIndex, mode, FALSE, + MODECHECK_INITIAL); + if (status != MODE_OK) + return status; + + if (mode->HSync <= 0.0) + mode->HSync = (float)mode->SynthClock / (float)mode->CrtcHTotal; + if (mode->VRefresh <= 0.0) + mode->VRefresh = (mode->SynthClock * 1000.0) + / (mode->CrtcHTotal * mode->CrtcVTotal); + } + + mode->HSync = xf86ModeHSync(mode); + mode->VRefresh = xf86ModeVRefresh(mode); + + /* Assume it is OK */ + return MODE_OK; +} + +/* + * xf86CheckModeForDriver + * + * This function is for checking modes while the server is running (for + * use mainly by the VidMode extension). + * + * This function checks if a mode satisfies a driver's requirements: + * - width lies within the line pitch + * - mode size fits within virtual size + * - horizontal/vertical timings are in range + * + * This function takes the following parameters: + * scrp ScrnInfoPtr + * mode mode to check + * flags not (currently) used + * + * In addition, the following fields from the ScrnInfoRec are used: + * maxHValue maximum horizontal timing value + * maxVValue maximum vertical timing value + * virtualX virtual width + * virtualY virtual height + * clockRanges allowable clock ranges + */ + +ModeStatus +xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, int flags) +{ + ClockRangePtr cp; + int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1; + int extraFlags = 0; + int clockIndex = -1; + int MulFactor = 1; + int DivFactor = 1; + int ModePrivFlags = 0; + ModeStatus status = MODE_NOMODE; + + /* Some sanity checking */ + if (scrp == NULL || (!scrp->progClock && scrp->numClocks == 0)) { + ErrorF("xf86CheckModeForDriver: called with invalid scrnInfoRec\n"); + return MODE_ERROR; + } + if (mode == NULL) { + ErrorF("xf86CheckModeForDriver: called with invalid modep\n"); + return MODE_ERROR; + } + + /* Check the mode size */ + if (mode->HDisplay > scrp->virtualX) + return MODE_VIRTUAL_X; + + if (mode->VDisplay > scrp->virtualY) + return MODE_VIRTUAL_Y; + + if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue) + return MODE_BAD_HVALUE; + + if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue) + return MODE_BAD_VVALUE; + + for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { + /* DivFactor and MulFactor must be > 0 */ + cp->ClockDivFactor = max(1, cp->ClockDivFactor); + cp->ClockMulFactor = max(1, cp->ClockMulFactor); + } + + if (scrp->progClock) { + /* Check clock is in range */ + for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { + if (modeInClockRange(cp, mode)) + break; + } + if (cp == NULL) { + return MODE_CLOCK_RANGE; + } + /* + * If programmable clock the required mode has been found + */ + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + } else { + status = MODE_CLOCK_RANGE; + /* Check clock is in range */ + for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { + if (modeInClockRange(cp, mode)) { + /* + * Clock is in range, so if it is not a programmable clock, + * find a matching clock. + */ + + i = xf86GetNearestClock(scrp, mode->Clock, 0, + cp->ClockDivFactor, cp->ClockMulFactor, &k); + /* + * If the clock is too far from the requested clock, this + * mode is no good. + */ + if (k & V_CLKDIV2) + gap = abs((mode->Clock * 2) - + ((scrp->clock[i] * cp->ClockDivFactor) / + cp->ClockMulFactor)); + else + gap = abs(mode->Clock - + ((scrp->clock[i] * cp->ClockDivFactor) / + cp->ClockMulFactor)); + if (gap > minimumGap) { + status = MODE_NOCLOCK; + continue; + } + + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + extraFlags = k; + clockIndex = i; + break; + } + } + if (cp == NULL) + return status; + } + + /* Fill in the mode parameters */ + if (scrp->progClock) { + mode->ClockIndex = -1; + mode->SynthClock = (mode->Clock * MulFactor) / DivFactor; + } else { + mode->Clock = (scrp->clock[clockIndex] * DivFactor) / MulFactor; + mode->ClockIndex = clockIndex; + mode->SynthClock = scrp->clock[clockIndex]; + if (extraFlags & V_CLKDIV2) { + mode->Clock /= 2; + mode->SynthClock /= 2; + } + } + mode->PrivFlags = ModePrivFlags; + + return MODE_OK; +} + +static int +inferVirtualSize(ScrnInfoPtr scrp, DisplayModePtr modes, int *vx, int *vy) +{ + float aspect = 0.0; + MonPtr mon = scrp->monitor; + xf86MonPtr DDC; + int x = 0, y = 0; + DisplayModePtr mode; + + if (!mon) return 0; + DDC = mon->DDC; + + if (DDC && DDC->ver.revision >= 4) { + /* For 1.4, we might actually get native pixel format. How novel. */ + if (PREFERRED_TIMING_MODE(DDC->features.msc)) { + for (mode = modes; mode; mode = mode->next) { + if (mode->type & (M_T_DRIVER | M_T_PREFERRED)) { + x = mode->HDisplay; + y = mode->VDisplay; + goto found; + } + } + } + /* + * Even if we don't, we might get aspect ratio from extra CVT info + * or from the monitor size fields. TODO. + */ + } + + /* + * Technically this triggers if either is zero. That wasn't legal + * before EDID 1.4, but right now we'll get that wrong. TODO. + */ + if (!aspect) { + if (!mon->widthmm || !mon->heightmm) + aspect = 4.0/3.0; + else + aspect = (float)mon->widthmm / (float)mon->heightmm; + } + + /* find the largest M_T_DRIVER mode with that aspect ratio */ + for (mode = modes; mode; mode = mode->next) { + float mode_aspect, metaspect; + if (!(mode->type & (M_T_DRIVER|M_T_USERDEF))) + continue; + mode_aspect = (float)mode->HDisplay / (float)mode->VDisplay; + metaspect = aspect / mode_aspect; + /* 5% slop or so, since we only get size in centimeters */ + if (fabs(1.0 - metaspect) < 0.05) { + if ((mode->HDisplay > x) && (mode->VDisplay > y)) { + x = mode->HDisplay; + y = mode->VDisplay; + } + } + } + + if (!x || !y) { + xf86DrvMsg(scrp->scrnIndex, X_WARNING, + "Unable to estimate virtual size\n"); + return 0; + } + +found: + *vx = x; + *vy = y; + + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "Estimated virtual size for aspect ratio %.4f is %dx%d\n", + aspect, *vx, *vy); + + return 1; +} + +/* Least common multiple */ +static unsigned int +LCM(unsigned int x, unsigned int y) +{ + unsigned int m = x, n = y, o; + + while ((o = m % n)) + { + m = n; + n = o; + } + + return (x / n) * y; +} + +/* + * Given various screen attributes, determine the minimum scanline width such + * that each scanline is server and DDX padded and any pixels with imbedded + * bank boundaries are off-screen. This function returns -1 if such a width + * cannot exist. + */ +static int +scanLineWidth( + unsigned int xsize, /* pixels */ + unsigned int ysize, /* pixels */ + unsigned int width, /* pixels */ + unsigned long BankSize, /* char's */ + PixmapFormatRec *pBankFormat, + unsigned int nWidthUnit /* bits */ +) +{ + unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit; + unsigned long minBitsPerScanline, maxBitsPerScanline; + + /* Sanity checks */ + + if (!nWidthUnit || !pBankFormat) + return -1; + + nBitsPerBank = BankSize * 8; + if (nBitsPerBank % pBankFormat->scanlinePad) + return -1; + + if (xsize > width) + width = xsize; + nBitsPerScanlinePadUnit = LCM(pBankFormat->scanlinePad, nWidthUnit); + nBitsPerScanline = + (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) / + nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit; + width = nBitsPerScanline / pBankFormat->bitsPerPixel; + + if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel)) + return (int)width; + + /* + * Scanlines will be server-pad aligned at this point. They will also be + * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded + * bank boundaries are off-screen. + * + * It seems reasonable to limit total frame buffer size to 1/16 of the + * theoretical maximum address space size. On a machine with 32-bit + * addresses (to 8-bit quantities) this turns out to be 256MB. Not only + * does this provide a simple limiting condition for the loops below, but + * it also prevents unsigned long wraparounds. + */ + if (!ysize) + return -1; + + minBitsPerScanline = xsize * pBankFormat->bitsPerPixel; + if (minBitsPerScanline > nBitsPerBank) + return -1; + + if (ysize == 1) + return (int)width; + + maxBitsPerScanline = + (((unsigned long)(-1) >> 1) - minBitsPerScanline) / (ysize - 1); + while (nBitsPerScanline <= maxBitsPerScanline) + { + unsigned long BankBase, BankUnit; + + BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) * + nBitsPerBank; + if (!(BankUnit % nBitsPerScanline)) + return (int)width; + + for (BankBase = BankUnit; ; BankBase += nBitsPerBank) + { + unsigned long x, y; + + y = BankBase / nBitsPerScanline; + if (y >= ysize) + return (int)width; + + x = BankBase % nBitsPerScanline; + if (!(x % pBankFormat->bitsPerPixel)) + continue; + + if (x < minBitsPerScanline) + { + /* + * Skip ahead certain widths by dividing the excess scanline + * amongst the y's. + */ + y *= nBitsPerScanlinePadUnit; + nBitsPerScanline += + ((x + y - 1) / y) * nBitsPerScanlinePadUnit; + width = nBitsPerScanline / pBankFormat->bitsPerPixel; + break; + } + + if (BankBase != BankUnit) + continue; + + if (!(nBitsPerScanline % x)) + return (int)width; + + BankBase = ((nBitsPerScanline - minBitsPerScanline) / + (nBitsPerScanline - x)) * BankUnit; + } + } + + return -1; +} + +/* + * xf86ValidateModes + * + * This function takes a set of mode names, modes and limiting conditions, + * and selects a set of modes and parameters based on those conditions. + * + * This function takes the following parameters: + * scrp ScrnInfoPtr + * availModes the list of modes available for the monitor + * modeNames (optional) list of mode names that the screen is requesting + * clockRanges a list of clock ranges + * linePitches (optional) a list of line pitches + * minPitch (optional) minimum line pitch (in pixels) + * maxPitch (optional) maximum line pitch (in pixels) + * pitchInc (mandatory) pitch increment (in bits) + * minHeight (optional) minimum virtual height (in pixels) + * maxHeight (optional) maximum virtual height (in pixels) + * virtualX (optional) virtual width requested (in pixels) + * virtualY (optional) virtual height requested (in pixels) + * apertureSize size of video aperture (in bytes) + * strategy how to decide which mode to use from multiple modes with + * the same name + * + * In addition, the following fields from the ScrnInfoRec are used: + * clocks a list of discrete clocks + * numClocks number of discrete clocks + * progClock clock is programmable + * monitor pointer to structure for monitor section + * fbFormat format of the framebuffer + * videoRam video memory size + * maxHValue maximum horizontal timing value + * maxVValue maximum vertical timing value + * xInc horizontal timing increment (defaults to 8 pixels) + * + * The function fills in the following ScrnInfoRec fields: + * modePool A subset of the modes available to the monitor which + * are compatible with the driver. + * modes one mode entry for each of the requested modes, with the + * status field filled in to indicate if the mode has been + * accepted or not. + * virtualX the resulting virtual width + * virtualY the resulting virtual height + * displayWidth the resulting line pitch + * + * The function's return value is the number of matching modes found, or -1 + * if an unrecoverable error was encountered. + */ + +int +xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, + char **modeNames, ClockRangePtr clockRanges, + int *linePitches, int minPitch, int maxPitch, int pitchInc, + int minHeight, int maxHeight, int virtualX, int virtualY, + int apertureSize, LookupModeFlags strategy) +{ + DisplayModePtr p, q, r, new, last, *endp; + int i, numModes = 0; + ModeStatus status; + int linePitch = -1, virtX = 0, virtY = 0; + int newLinePitch, newVirtX, newVirtY; + int modeSize; /* in pixels */ + Bool validateAllDefaultModes = FALSE; + Bool userModes = FALSE; + int saveType; + PixmapFormatRec *BankFormat; + ClockRangePtr cp; + ClockRangePtr storeClockRanges; + int numTimings = 0; + range hsync[MAX_HSYNC]; + range vrefresh[MAX_VREFRESH]; + Bool inferred_virtual = FALSE; + + DebugF("xf86ValidateModes(%p, %p, %p, %p,\n\t\t %p, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x)\n", + scrp, availModes, modeNames, clockRanges, + linePitches, minPitch, maxPitch, pitchInc, + minHeight, maxHeight, virtualX, virtualY, + apertureSize, strategy + ); + + /* Some sanity checking */ + if (scrp == NULL || scrp->name == NULL || !scrp->monitor || + (!scrp->progClock && scrp->numClocks == 0)) { + ErrorF("xf86ValidateModes: called with invalid scrnInfoRec\n"); + return -1; + } + if (linePitches != NULL && linePitches[0] <= 0) { + ErrorF("xf86ValidateModes: called with invalid linePitches\n"); + return -1; + } + if (pitchInc <= 0) { + ErrorF("xf86ValidateModes: called with invalid pitchInc\n"); + return -1; + } + if ((virtualX > 0) != (virtualY > 0)) { + ErrorF("xf86ValidateModes: called with invalid virtual resolution\n"); + return -1; + } + + /* + * If requested by the driver, allow missing hsync and/or vrefresh ranges + * in the monitor section. + */ + if (strategy & LOOKUP_OPTIONAL_TOLERANCES) { + strategy &= ~LOOKUP_OPTIONAL_TOLERANCES; + } else { + const char *type = ""; + Bool specified = FALSE; + + if (scrp->monitor->nHsync <= 0) { + if (numTimings > 0) { + scrp->monitor->nHsync = numTimings; + for (i = 0; i < numTimings; i++) { + scrp->monitor->hsync[i].lo = hsync[i].lo; + scrp->monitor->hsync[i].hi = hsync[i].hi; + } + } else { + scrp->monitor->hsync[0].lo = 31.5; + scrp->monitor->hsync[0].hi = 48.0; + scrp->monitor->nHsync = 1; + } + type = "default "; + } else { + specified = TRUE; + } + for (i = 0; i < scrp->monitor->nHsync; i++) { + if (scrp->monitor->hsync[i].lo == scrp->monitor->hsync[i].hi) + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "%s: Using %shsync value of %.2f kHz\n", + scrp->monitor->id, type, + scrp->monitor->hsync[i].lo); + else + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "%s: Using %shsync range of %.2f-%.2f kHz\n", + scrp->monitor->id, type, + scrp->monitor->hsync[i].lo, + scrp->monitor->hsync[i].hi); + } + + type = ""; + if (scrp->monitor->nVrefresh <= 0) { + if (numTimings > 0) { + scrp->monitor->nVrefresh = numTimings; + for (i = 0; i < numTimings; i++) { + scrp->monitor->vrefresh[i].lo = vrefresh[i].lo; + scrp->monitor->vrefresh[i].hi = vrefresh[i].hi; + } + } else { + scrp->monitor->vrefresh[0].lo = 50; + scrp->monitor->vrefresh[0].hi = 70; + scrp->monitor->nVrefresh = 1; + } + type = "default "; + } else { + specified = TRUE; + } + for (i = 0; i < scrp->monitor->nVrefresh; i++) { + if (scrp->monitor->vrefresh[i].lo == scrp->monitor->vrefresh[i].hi) + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "%s: Using %svrefresh value of %.2f Hz\n", + scrp->monitor->id, type, + scrp->monitor->vrefresh[i].lo); + else + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "%s: Using %svrefresh range of %.2f-%.2f Hz\n", + scrp->monitor->id, type, + scrp->monitor->vrefresh[i].lo, + scrp->monitor->vrefresh[i].hi); + } + + type = ""; + if (!scrp->monitor->maxPixClock && !specified) { + type = "default "; + scrp->monitor->maxPixClock = 65000.0; + } + if (scrp->monitor->maxPixClock) { + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "%s: Using %smaximum pixel clock of %.2f MHz\n", + scrp->monitor->id, type, + (float)scrp->monitor->maxPixClock / 1000.0); + } + } + + /* + * Store the clockRanges for later use by the VidMode extension. + */ + storeClockRanges = scrp->clockRanges; + while (storeClockRanges != NULL) { + storeClockRanges = storeClockRanges->next; + } + for (cp = clockRanges; cp != NULL; cp = cp->next, + storeClockRanges = storeClockRanges->next) { + storeClockRanges = xnfalloc(sizeof(ClockRange)); + if (scrp->clockRanges == NULL) + scrp->clockRanges = storeClockRanges; + memcpy(storeClockRanges, cp, sizeof(ClockRange)); + } + + /* Determine which pixmap format to pass to scanLineWidth() */ + if (scrp->depth > 4) + BankFormat = &scrp->fbFormat; + else + BankFormat = xf86GetPixFormat(scrp, 1); /* >not< scrp->depth! */ + + if (scrp->xInc <= 0) + scrp->xInc = 8; /* Suitable for VGA and others */ + +#define _VIRTUALX(x) ((((x) + scrp->xInc - 1) / scrp->xInc) * scrp->xInc) + + /* + * Determine maxPitch if it wasn't given explicitly. Note linePitches + * always takes precedence if is non-NULL. In that case the minPitch and + * maxPitch values passed are ignored. + */ + if (linePitches) { + minPitch = maxPitch = linePitches[0]; + for (i = 1; linePitches[i] > 0; i++) { + if (linePitches[i] > maxPitch) + maxPitch = linePitches[i]; + if (linePitches[i] < minPitch) + minPitch = linePitches[i]; + } + } + + /* Initial check of virtual size against other constraints */ + scrp->virtualFrom = X_PROBED; + /* + * Initialise virtX and virtY if the values are fixed. + */ + if (virtualY > 0) { + if (maxHeight > 0 && virtualY > maxHeight) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Virtual height (%d) is too large for the hardware " + "(max %d)\n", virtualY, maxHeight); + return -1; + } + + if (minHeight > 0 && virtualY < minHeight) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Virtual height (%d) is too small for the hardware " + "(min %d)\n", virtualY, minHeight); + return -1; + } + + virtualX = _VIRTUALX(virtualX); + if (linePitches != NULL) { + for (i = 0; linePitches[i] != 0; i++) { + if ((linePitches[i] >= virtualX) && + (linePitches[i] == + scanLineWidth(virtualX, virtualY, linePitches[i], + apertureSize, BankFormat, pitchInc))) { + linePitch = linePitches[i]; + break; + } + } + } else { + linePitch = scanLineWidth(virtualX, virtualY, minPitch, + apertureSize, BankFormat, pitchInc); + } + + if ((linePitch < minPitch) || (linePitch > maxPitch)) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Virtual width (%d) is too large for the hardware " + "(max %d)\n", virtualX, maxPitch); + return -1; + } + + if (!xf86CheckModeSize(scrp, linePitch, virtualX, virtualY)) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Virtual size (%dx%d) (pitch %d) exceeds video memory\n", + virtualX, virtualY, linePitch); + return -1; + } + + virtX = virtualX; + virtY = virtualY; + scrp->virtualFrom = X_CONFIG; + } else if (!modeNames || !*modeNames) { + /* No virtual size given in the config, try to infer */ + /* XXX this doesn't take m{in,ax}Pitch into account; oh well */ + inferred_virtual = inferVirtualSize(scrp, availModes, &virtX, &virtY); + if (inferred_virtual) + linePitch = scanLineWidth(virtX, virtY, minPitch, apertureSize, + BankFormat, pitchInc); + } + + /* Print clock ranges and scaled clocks */ + xf86ShowClockRanges(scrp, clockRanges); + + /* + * If scrp->modePool hasn't been setup yet, set it up now. This allows the + * modes that the driver definitely can't use to be weeded out early. Note + * that a modePool mode's prev field is used to hold a pointer to the + * member of the scrp->modes list for which a match was considered. + */ + if (scrp->modePool == NULL) { + q = NULL; + for (p = availModes; p != NULL; p = p->next) { + status = xf86InitialCheckModeForDriver(scrp, p, clockRanges, + strategy, maxPitch, + virtX, virtY); + + if (status == MODE_OK) { + status = xf86CheckModeForMonitor(p, scrp->monitor); + } + + if (status == MODE_OK) { + new = xnfalloc(sizeof(DisplayModeRec)); + *new = *p; + new->next = NULL; + if (!q) { + scrp->modePool = new; + } else { + q->next = new; + } + new->prev = NULL; + q = new; + q->name = xnfstrdup(p->name); + q->status = MODE_OK; + } else { + printModeRejectMessage(scrp->scrnIndex, p, status); + } + } + + if (scrp->modePool == NULL) { + xf86DrvMsg(scrp->scrnIndex, X_WARNING, "Mode pool is empty\n"); + return 0; + } + } else { + for (p = scrp->modePool; p != NULL; p = p->next) { + p->prev = NULL; + p->status = MODE_OK; + } + } + + /* + * Allocate one entry in scrp->modes for each named mode. + */ + while (scrp->modes) + xf86DeleteMode(&scrp->modes, scrp->modes); + endp = &scrp->modes; + last = NULL; + if (modeNames != NULL) { + for (i = 0; modeNames[i] != NULL; i++) { + userModes = TRUE; + new = xnfcalloc(1, sizeof(DisplayModeRec)); + new->prev = last; + new->type = M_T_USERDEF; + new->name = xnfstrdup(modeNames[i]); + if (new->prev) + new->prev->next = new; + *endp = last = new; + endp = &new->next; + } + } + + /* Lookup each mode */ +#ifdef RANDR + if (!xf86Info.disableRandR +#ifdef PANORAMIX + && noPanoramiXExtension +#endif + ) + validateAllDefaultModes = TRUE; +#endif + + for (p = scrp->modes; ; p = p->next) { + Bool repeat; + + /* + * If the supplied mode names don't produce a valid mode, scan through + * unconsidered modePool members until one survives validation. This + * is done in decreasing order by mode pixel area. + */ + + if (p == NULL) { + if ((numModes > 0) && !validateAllDefaultModes) + break; + + validateAllDefaultModes = TRUE; + r = NULL; + modeSize = 0; + for (q = scrp->modePool; q != NULL; q = q->next) { + if ((q->prev == NULL) && (q->status == MODE_OK)) { + /* + * Deal with the case where this mode wasn't considered + * because of a builtin mode of the same name. + */ + for (p = scrp->modes; p != NULL; p = p->next) { + if ((p->status != MODE_OK) && + !strcmp(p->name, q->name)) + break; + } + + if (p != NULL) + q->prev = p; + else { + /* + * A quick check to not allow default modes with + * horizontal timing parameters that CRTs may have + * problems with. + */ + if (!scrp->monitor->reducedblanking && + (q->type & M_T_DEFAULT) && + ((double)q->HTotal / (double)q->HDisplay) < 1.15) + continue; + + if (modeSize < (q->HDisplay * q->VDisplay)) { + r = q; + modeSize = q->HDisplay * q->VDisplay; + } + } + } + } + + if (r == NULL) + break; + + p = xnfcalloc(1, sizeof(DisplayModeRec)); + p->prev = last; + p->name = xnfstrdup(r->name); + if (!userModes) + p->type = M_T_USERDEF; + if (p->prev) + p->prev->next = p; + *endp = last = p; + endp = &p->next; + } + + repeat = FALSE; + lookupNext: + if (repeat && ((status = p->status) != MODE_OK)) + printModeRejectMessage(scrp->scrnIndex, p, status); + saveType = p->type; + status = xf86LookupMode(scrp, p, clockRanges, strategy); + if (repeat && status == MODE_NOMODE) + continue; + if (status != MODE_OK) + printModeRejectMessage(scrp->scrnIndex, p, status); + if (status == MODE_ERROR) { + ErrorF("xf86ValidateModes: " + "unexpected result from xf86LookupMode()\n"); + return -1; + } + if (status != MODE_OK) { + if (p->status == MODE_OK) + p->status = status; + continue; + } + p->type |= saveType; + repeat = TRUE; + + newLinePitch = linePitch; + newVirtX = virtX; + newVirtY = virtY; + + /* + * Don't let non-user defined modes increase the virtual size + */ + if (!(p->type & M_T_USERDEF) && (numModes > 0)) { + if (p->HDisplay > virtX) { + p->status = MODE_VIRTUAL_X; + goto lookupNext; + } + if (p->VDisplay > virtY) { + p->status = MODE_VIRTUAL_Y; + goto lookupNext; + } + } + /* + * Adjust virtual width and height if the mode is too large for the + * current values and if they are not fixed. + */ + if (virtualX <= 0 && p->HDisplay > newVirtX) + newVirtX = _VIRTUALX(p->HDisplay); + if (virtualY <= 0 && p->VDisplay > newVirtY) { + if (maxHeight > 0 && p->VDisplay > maxHeight) { + p->status = MODE_VIRTUAL_Y; /* ? */ + goto lookupNext; + } + newVirtY = p->VDisplay; + } + + /* + * If virtual resolution is to be increased, revalidate it. + */ + if ((virtX != newVirtX) || (virtY != newVirtY)) { + if (linePitches != NULL) { + newLinePitch = -1; + for (i = 0; linePitches[i] != 0; i++) { + if ((linePitches[i] >= newVirtX) && + (linePitches[i] >= linePitch) && + (linePitches[i] == + scanLineWidth(newVirtX, newVirtY, linePitches[i], + apertureSize, BankFormat, pitchInc))) { + newLinePitch = linePitches[i]; + break; + } + } + } else { + if (linePitch < minPitch) + linePitch = minPitch; + newLinePitch = scanLineWidth(newVirtX, newVirtY, linePitch, + apertureSize, BankFormat, + pitchInc); + } + if ((newLinePitch < minPitch) || (newLinePitch > maxPitch)) { + p->status = MODE_BAD_WIDTH; + goto lookupNext; + } + + /* + * Check that the pixel area required by the new virtual height + * and line pitch isn't too large. + */ + if (!xf86CheckModeSize(scrp, newLinePitch, newVirtX, newVirtY)) { + p->status = MODE_MEM_VIRT; + goto lookupNext; + } + } + + if (scrp->ValidMode) { + /* + * Give the driver a final say, passing it the proposed virtual + * geometry. + */ + scrp->virtualX = newVirtX; + scrp->virtualY = newVirtY; + scrp->displayWidth = newLinePitch; + p->status = (scrp->ValidMode)(scrp->scrnIndex, p, FALSE, + MODECHECK_FINAL); + + if (p->status != MODE_OK) { + goto lookupNext; + } + } + + /* Mode has passed all the tests */ + virtX = newVirtX; + virtY = newVirtY; + linePitch = newLinePitch; + p->status = MODE_OK; + numModes++; + } + + /* + * If we estimated the virtual size above, we may have filtered away all + * the modes that maximally match that size; scan again to find out and + * fix up if so. + */ + if (inferred_virtual) { + int vx = 0, vy = 0; + for (p = scrp->modes; p; p = p->next) { + if (p->HDisplay > vx && p->VDisplay > vy) { + vx = p->HDisplay; + vy = p->VDisplay; + } + } + if (vx < virtX || vy < virtY) { + const int types[] = { + M_T_BUILTIN | M_T_PREFERRED, + M_T_BUILTIN, + M_T_DRIVER | M_T_PREFERRED, + M_T_DRIVER, + 0 + }; + const int ntypes = sizeof(types) / sizeof(int); + int n; + + /* + * We did not find the estimated virtual size. So now we want to + * find the largest mode available, but we want to search in the + * modes in the order of "types" listed above. + */ + for (n = 0; n < ntypes; n++) { + int type = types[n]; + + vx = 0; vy = 0; + for (p = scrp->modes; p; p = p->next) { + /* scan through the modes in the sort order above */ + if ((p->type & type) != type) + continue; + if (p->HDisplay > vx && p->VDisplay > vy) { + vx = p->HDisplay; + vy = p->VDisplay; + } + } + if (vx && vy) + /* Found one */ + break; + } + xf86DrvMsg(scrp->scrnIndex, X_WARNING, + "Shrinking virtual size estimate from %dx%d to %dx%d\n", + virtX, virtY, vx, vy); + virtX = _VIRTUALX(vx); + virtY = vy; + for (p = scrp->modes; p; p = p->next) { + if (numModes > 0) { + if (p->HDisplay > virtX) + p->status = MODE_VIRTUAL_X; + if (p->VDisplay > virtY) + p->status = MODE_VIRTUAL_Y; + if (p->status != MODE_OK) { + numModes--; + printModeRejectMessage(scrp->scrnIndex, p, p->status); + } + } + } + if (linePitches != NULL) { + for (i = 0; linePitches[i] != 0; i++) { + if ((linePitches[i] >= virtX) && + (linePitches[i] == + scanLineWidth(virtX, virtY, linePitches[i], + apertureSize, BankFormat, pitchInc))) { + linePitch = linePitches[i]; + break; + } + } + } else { + linePitch = scanLineWidth(virtX, virtY, minPitch, + apertureSize, BankFormat, pitchInc); + } + } + } + + /* Update the ScrnInfoRec parameters */ + + scrp->virtualX = virtX; + scrp->virtualY = virtY; + scrp->displayWidth = linePitch; + + if (numModes <= 0) + return 0; + + /* Make the mode list into a circular list by joining up the ends */ + p = scrp->modes; + while (p->next != NULL) + p = p->next; + /* p is now the last mode on the list */ + p->next = scrp->modes; + scrp->modes->prev = p; + + if (minHeight > 0 && virtY < minHeight) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Virtual height (%d) is too small for the hardware " + "(min %d)\n", virtY, minHeight); + return -1; + } + + return numModes; +} + +/* + * xf86DeleteMode + * + * This function removes a mode from a list of modes. + * + * There are different types of mode lists: + * + * - singly linked linear lists, ending in NULL + * - doubly linked linear lists, starting and ending in NULL + * - doubly linked circular lists + * + */ + +void +xf86DeleteMode(DisplayModePtr *modeList, DisplayModePtr mode) +{ + /* Catch the easy/insane cases */ + if (modeList == NULL || *modeList == NULL || mode == NULL) + return; + + /* If the mode is at the start of the list, move the start of the list */ + if (*modeList == mode) + *modeList = mode->next; + + /* If mode is the only one on the list, set the list to NULL */ + if ((mode == mode->prev) && (mode == mode->next)) { + *modeList = NULL; + } else { + if ((mode->prev != NULL) && (mode->prev->next == mode)) + mode->prev->next = mode->next; + if ((mode->next != NULL) && (mode->next->prev == mode)) + mode->next->prev = mode->prev; + } + + free(mode->name); + free(mode); +} + +/* + * xf86PruneDriverModes + * + * Remove modes from the driver's mode list which have been marked as + * invalid. + */ + +void +xf86PruneDriverModes(ScrnInfoPtr scrp) +{ + DisplayModePtr first, p, n; + + p = scrp->modes; + if (p == NULL) + return; + + do { + if (!(first = scrp->modes)) + return; + n = p->next; + if (p->status != MODE_OK) { + xf86DeleteMode(&(scrp->modes), p); + } + p = n; + } while (p != NULL && p != first); + + /* modePool is no longer needed, turf it */ + while (scrp->modePool) { + /* + * A modePool mode's prev field is used to hold a pointer to the + * member of the scrp->modes list for which a match was considered. + * Clear that pointer first, otherwise xf86DeleteMode might get + * confused + */ + scrp->modePool->prev = NULL; + xf86DeleteMode(&scrp->modePool, scrp->modePool); + } +} + + +/* + * xf86SetCrtcForModes + * + * Goes through the screen's mode list, and initialises the Crtc + * parameters for each mode. The initialisation includes adjustments + * for interlaced and double scan modes. + */ +void +xf86SetCrtcForModes(ScrnInfoPtr scrp, int adjustFlags) +{ + DisplayModePtr p; + + /* + * Store adjustFlags for use with the VidMode extension. There is an + * implicit assumption here that SetCrtcForModes is called once. + */ + scrp->adjustFlags = adjustFlags; + + p = scrp->modes; + if (p == NULL) + return; + + do { + xf86SetModeCrtc(p, adjustFlags); + DebugF("%sMode %s: %d (%d) %d %d (%d) %d %d (%d) %d %d (%d) %d\n", + (p->type & M_T_DEFAULT) ? "Default " : "", + p->name, p->CrtcHDisplay, p->CrtcHBlankStart, + p->CrtcHSyncStart, p->CrtcHSyncEnd, p->CrtcHBlankEnd, + p->CrtcHTotal, p->CrtcVDisplay, p->CrtcVBlankStart, + p->CrtcVSyncStart, p->CrtcVSyncEnd, p->CrtcVBlankEnd, + p->CrtcVTotal); + p = p->next; + } while (p != NULL && p != scrp->modes); +} + +void +xf86PrintModes(ScrnInfoPtr scrp) +{ + DisplayModePtr p; + float hsync, refresh = 0; + const char *desc, *desc2, *prefix, *uprefix; + + if (scrp == NULL) + return; + + xf86DrvMsg(scrp->scrnIndex, scrp->virtualFrom, "Virtual size is %dx%d " + "(pitch %d)\n", scrp->virtualX, scrp->virtualY, + scrp->displayWidth); + + p = scrp->modes; + if (p == NULL) + return; + + do { + desc = desc2 = ""; + hsync = xf86ModeHSync(p); + refresh = xf86ModeVRefresh(p); + if (p->Flags & V_INTERLACE) { + desc = " (I)"; + } + if (p->Flags & V_DBLSCAN) { + desc = " (D)"; + } + if (p->VScan > 1) { + desc2 = " (VScan)"; + } + if (p->type & M_T_BUILTIN) + prefix = "Built-in mode"; + else if (p->type & M_T_DEFAULT) + prefix = "Default mode"; + else if (p->type & M_T_DRIVER) + prefix = "Driver mode"; + else + prefix = "Mode"; + if (p->type & M_T_USERDEF) + uprefix = "*"; + else + uprefix = " "; + if (hsync == 0 || refresh == 0) { + if (p->name) + xf86DrvMsg(scrp->scrnIndex, X_CONFIG, + "%s%s \"%s\"\n", uprefix, prefix, p->name); + else + xf86DrvMsg(scrp->scrnIndex, X_PROBED, + "%s%s %dx%d (unnamed)\n", + uprefix, prefix, p->HDisplay, p->VDisplay); + } else if (p->Clock == p->SynthClock) { + xf86DrvMsg(scrp->scrnIndex, X_CONFIG, + "%s%s \"%s\": %.1f MHz, %.1f kHz, %.1f Hz%s%s\n", + uprefix, prefix, p->name, p->Clock / 1000.0, + hsync, refresh, desc, desc2); + } else { + xf86DrvMsg(scrp->scrnIndex, X_CONFIG, + "%s%s \"%s\": %.1f MHz (scaled from %.1f MHz), " + "%.1f kHz, %.1f Hz%s%s\n", + uprefix, prefix, p->name, p->Clock / 1000.0, + p->SynthClock / 1000.0, hsync, refresh, desc, desc2); + } + if (hsync != 0 && refresh != 0) + xf86PrintModeline(scrp->scrnIndex,p); + p = p->next; + } while (p != NULL && p != scrp->modes); +} diff --git a/xorg-server/hw/xfree86/common/xf86Opt.h b/xorg-server/hw/xfree86/common/xf86Opt.h index 88392dc6d..b0fdaa6b6 100644 --- a/xorg-server/hw/xfree86/common/xf86Opt.h +++ b/xorg-server/hw/xfree86/common/xf86Opt.h @@ -72,7 +72,7 @@ typedef struct { extern _X_EXPORT int xf86SetIntOption(XF86OptionPtr optlist, const char *name, int deflt); extern _X_EXPORT double xf86SetRealOption(XF86OptionPtr optlist, const char *name, double deflt); -extern _X_EXPORT char *xf86SetStrOption(XF86OptionPtr optlist, const char *name, char *deflt); +extern _X_EXPORT char *xf86SetStrOption(XF86OptionPtr optlist, const char *name, const char *deflt); extern _X_EXPORT int xf86SetBoolOption(XF86OptionPtr list, const char *name, int deflt ); extern _X_EXPORT double xf86SetPercentOption(XF86OptionPtr list, const char *name, double deflt ); extern _X_EXPORT int xf86CheckIntOption(XF86OptionPtr optlist, const char *name, int deflt); @@ -91,7 +91,7 @@ extern _X_EXPORT char *xf86OptionName(XF86OptionPtr opt); extern _X_EXPORT char *xf86OptionValue(XF86OptionPtr opt); extern _X_EXPORT void xf86OptionListReport(XF86OptionPtr parm); extern _X_EXPORT XF86OptionPtr xf86FindOption(XF86OptionPtr options, const char *name); -extern _X_EXPORT char *xf86FindOptionValue(XF86OptionPtr options, const char *name); +extern _X_EXPORT const char *xf86FindOptionValue(XF86OptionPtr options, const char *name); extern _X_EXPORT void xf86MarkOptionUsed(XF86OptionPtr option); extern _X_EXPORT void xf86MarkOptionUsedByName(XF86OptionPtr options, const char *name); extern _X_EXPORT Bool xf86CheckIfOptionUsed(XF86OptionPtr option); diff --git a/xorg-server/hw/xfree86/common/xf86Option.c b/xorg-server/hw/xfree86/common/xf86Option.c index 9c528782f..dc0a01899 100644 --- a/xorg-server/hw/xfree86/common/xf86Option.c +++ b/xorg-server/hw/xfree86/common/xf86Option.c @@ -187,7 +187,7 @@ LookupRealOption(XF86OptionPtr optlist, const char *name, double deflt, static char * -LookupStrOption(XF86OptionPtr optlist, const char *name, char *deflt, Bool markUsed) +LookupStrOption(XF86OptionPtr optlist, const char *name, const char *deflt, Bool markUsed) { OptionInfoRec o; @@ -243,7 +243,7 @@ xf86SetRealOption(XF86OptionPtr optlist, const char *name, double deflt) char * -xf86SetStrOption(XF86OptionPtr optlist, const char *name, char *deflt) +xf86SetStrOption(XF86OptionPtr optlist, const char *name, const char *deflt) { return LookupStrOption(optlist, name, deflt, TRUE); } @@ -306,7 +306,7 @@ XF86OptionPtr xf86ReplaceIntOption(XF86OptionPtr optlist, const char *name, const int val) { char tmp[16]; - sprintf(tmp,"%i",val); + snprintf(tmp,sizeof(tmp),"%i",val); return xf86AddNewOption(optlist,name,tmp); } @@ -314,7 +314,7 @@ XF86OptionPtr xf86ReplaceRealOption(XF86OptionPtr optlist, const char *name, const double val) { char tmp[32]; - snprintf(tmp,32,"%f",val); + snprintf(tmp,sizeof(tmp),"%f",val); return xf86AddNewOption(optlist,name,tmp); } @@ -328,7 +328,7 @@ XF86OptionPtr xf86ReplacePercentOption(XF86OptionPtr optlist, const char *name, const double val) { char tmp[16]; - sprintf(tmp, "%lf%%", val); + snprintf(tmp, sizeof(tmp), "%lf%%", val); return xf86AddNewOption(optlist,name,tmp); } @@ -416,7 +416,7 @@ xf86FindOption(XF86OptionPtr options, const char *name) } -char * +const char * xf86FindOptionValue(XF86OptionPtr options, const char *name) { return xf86findOptionValue(options, name); diff --git a/xorg-server/hw/xfree86/common/xf86PM.c b/xorg-server/hw/xfree86/common/xf86PM.c index 16b6bdc4a..47e0297d6 100644 --- a/xorg-server/hw/xfree86/common/xf86PM.c +++ b/xorg-server/hw/xfree86/common/xf86PM.c @@ -41,7 +41,7 @@ pmWait (*xf86PMConfirmEventToOs)(int fd,pmEvent event) = NULL; static Bool suspended = FALSE; static int -eventName(pmEvent event, char **str) +eventName(pmEvent event, const char **str) { switch(event) { case XF86_APM_SYS_STANDBY: *str="System Standby Request"; return 0; @@ -179,7 +179,7 @@ xf86HandlePMEvents(int fd, pointer data) if ((n = xf86PMGetEventFromOs(fd,events,MAX_NO_EVENTS))) { do { for (i = 0; i < n; i++) { - char *str = NULL; + const char *str = NULL; int verb = eventName(events[i],&str); xf86MsgVerb(X_INFO,verb,"PM Event received: %s\n",str); diff --git a/xorg-server/hw/xfree86/common/xf86Priv.h b/xorg-server/hw/xfree86/common/xf86Priv.h index 1fe3d7e0d..8c698591e 100644 --- a/xorg-server/hw/xfree86/common/xf86Priv.h +++ b/xorg-server/hw/xfree86/common/xf86Priv.h @@ -69,7 +69,7 @@ extern _X_EXPORT Pix24Flags xf86Pix24; extern _X_EXPORT rgb xf86Weight; extern _X_EXPORT Bool xf86FlipPixels; extern _X_EXPORT Gamma xf86Gamma; -extern _X_EXPORT char *xf86ServerName; +extern _X_EXPORT const char *xf86ServerName; /* Other parameters */ diff --git a/xorg-server/hw/xfree86/common/xf86ShowOpts.c b/xorg-server/hw/xfree86/common/xf86ShowOpts.c deleted file mode 100644 index a8059168d..000000000 --- a/xorg-server/hw/xfree86/common/xf86ShowOpts.c +++ /dev/null @@ -1,130 +0,0 @@ -/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86ShopwOpts.c,v 3.80 2003/10/08 14:58:27 dawes Exp $ */ -/* - * Copyright 2000-2002 by Alan Hourihane, Flint Mountain, North Wales. - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Alan Hourihane not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Alan Hourihane makes no representations - * about the suitability of this software for any purpose. It is provided - * "as is" without express or implied warranty. - * - * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - * - * Author: Marcus Schaefer, ms@suse.de - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "os.h" -#ifdef XFree86LOADER -#include "loaderProcs.h" -#endif -#include "xf86.h" -#include "xf86Config.h" -#include "xf86_OSlib.h" -#include "xf86Priv.h" -/* #include "xf86PciData.h" */ -#define IN_XSERVER -#include "xf86Parser.h" -#include "xf86tokens.h" -#include "Configint.h" -#include "xf86DDC.h" -#if defined(__sparc__) && !defined(__OpenBSD__) -#include "xf86Bus.h" -#include "xf86Sbus.h" -#endif -#include "globals.h" - -static const char* -optionTypeToSting(OptionValueType type) -{ - switch (type) { - case OPTV_NONE: - return ""; - case OPTV_INTEGER: - return ""; - case OPTV_STRING: - return ""; - case OPTV_ANYSTR: - return ""; - case OPTV_REAL: - return ""; - case OPTV_BOOLEAN: - return ""; - case OPTV_FREQ: - return ""; - case OPTV_PERCENT: - return ""; - default: - return ""; - } -} - -void DoShowOptions (void) { - int i = 0; - char **vlist = 0; - char *pSymbol = 0; - XF86ModuleData *initData = 0; - if (! (vlist = xf86DriverlistFromCompile())) { - ErrorF("Missing output drivers\n"); - goto bail; - } - xf86LoadModules (vlist,0); - free(vlist); - for (i = 0; i < xf86NumDrivers; i++) { - if (xf86DriverList[i]->AvailableOptions) { - OptionInfoPtr pOption = (OptionInfoPtr)(*xf86DriverList[i]->AvailableOptions)(0,0); - if (! pOption) { - ErrorF ("(EE) Couldn't read option table for %s driver\n", - xf86DriverList[i]->driverName - ); - continue; - } - XNFasprintf(&pSymbol, "%sModuleData", - xf86DriverList[i]->driverName); - initData = LoaderSymbol (pSymbol); - if (initData) { - XF86ModuleVersionInfo *vers = initData->vers; - OptionInfoPtr p; - ErrorF ("Driver[%d]:%s[%s] {\n", - i,xf86DriverList[i]->driverName,vers->vendor - ); - for (p = pOption; p->name != NULL; p++) { - const char *opttype = optionTypeToSting(p->type); - /* XXX: Why overallocate by 2 bytes? - * Otherwise, this would be strdup() - */ - char *optname = malloc(strlen(p->name) + 2 + 1); - if (!optname) { - continue; - } - sprintf(optname, "%s", p->name); - ErrorF ("\t%s:%s\n", optname,opttype); - } - ErrorF ("}\n"); - } - } - } - bail: - OsCleanup (TRUE); - AbortDDX (EXIT_ERR_DRIVERS); - fflush (stderr); - exit (0); -} diff --git a/xorg-server/hw/xfree86/common/xf86Xinput.c b/xorg-server/hw/xfree86/common/xf86Xinput.c index 7feb48c1e..b9753f01d 100644 --- a/xorg-server/hw/xfree86/common/xf86Xinput.c +++ b/xorg-server/hw/xfree86/common/xf86Xinput.c @@ -460,10 +460,9 @@ HostOS(void) if (*host_os == '\0') { if (uname(&name) >= 0) - strcpy(host_os, name.sysname); + strlcpy(host_os, name.sysname, sizeof(host_os)); else { - strncpy(host_os, "unknown", sizeof(host_os)); - host_os[sizeof(host_os)-1] = '\0'; + strlcpy(host_os, "unknown", sizeof(host_os)); } } return host_os; diff --git a/xorg-server/hw/xfree86/common/xf86pciBus.c b/xorg-server/hw/xfree86/common/xf86pciBus.c index 87dc02512..b95b25359 100644 --- a/xorg-server/hw/xfree86/common/xf86pciBus.c +++ b/xorg-server/hw/xfree86/common/xf86pciBus.c @@ -82,16 +82,6 @@ static struct pci_slot_match xf86IsolateDevice = { PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0 }; -void -xf86FormatPciBusNumber(int busnum, char *buffer) -{ - /* 'buffer' should be at least 8 characters long */ - if (busnum < 256) - sprintf(buffer, "%d", busnum); - else - sprintf(buffer, "%d@%d", busnum & 0x00ff, busnum >> 8); -} - /* * xf86Bus.c interface */ @@ -1072,7 +1062,7 @@ videoPtrToDriverList(struct pci_device *dev, int i; /* Add more entries here if we ever return more than 4 drivers for any device */ - char *driverList[5] = { NULL, NULL, NULL, NULL, NULL }; + const char *driverList[5] = { NULL, NULL, NULL, NULL, NULL }; switch (dev->vendor_id) { @@ -1219,9 +1209,8 @@ matchDriverFromFiles (char** matches, uint16_t match_vendor, uint16_t match_chip /* A tiny bit of sanity checking. We should probably do better */ if (strncmp(&(direntry->d_name[len-4]), ".ids", 4) == 0) { /* We need the full path name to open the file */ - strncpy(path_name, PCI_TXT_IDS_PATH, 256); - strncat(path_name, "/", 1); - strncat(path_name, direntry->d_name, (256 - strlen(path_name) - 1)); + snprintf(path_name, sizeof(path_name), "%s/%s", + PCI_TXT_IDS_PATH, direntry->d_name); fp = fopen(path_name, "r"); if (fp == NULL) { xf86Msg(X_ERROR, "Could not open %s for reading. Exiting.\n", path_name); @@ -1235,8 +1224,7 @@ matchDriverFromFiles (char** matches, uint16_t match_vendor, uint16_t match_chip #endif /* __GLIBC __ */ xchomp(line); if (isdigit(line[0])) { - strncpy(vendor_str, line, 4); - vendor_str[4] = '\0'; + strlcpy(vendor_str, line, sizeof(vendor_str)); vendor = (int)strtol(vendor_str, NULL, 16); if ((strlen(&line[4])) == 0) { chip_str[0] = '\0'; @@ -1248,8 +1236,7 @@ matchDriverFromFiles (char** matches, uint16_t match_vendor, uint16_t match_chip chip = -1; } else { /* Ok, it's a real ID */ - strncpy(chip_str, &line[4], 4); - chip_str[4] = '\0'; + strlcpy(chip_str, &line[4], sizeof(chip_str)); chip = (int)strtol(chip_str, NULL, 16); } } @@ -1349,7 +1336,12 @@ xf86PciConfigureNewDev(void *busData, struct pci_device *pVideo, pVideo = (struct pci_device *) busData; - xf86FormatPciBusNumber(pVideo->bus, busnum); + if (pVideo->bus < 256) + snprintf(busnum, sizeof(busnum), "%d", pVideo->bus); + else + snprintf(busnum, sizeof(busnum), "%d@%d", + pVideo->bus & 0x00ff, pVideo->bus >> 8); + XNFasprintf(&GDev->busID, "PCI:%s:%d:%d", busnum, pVideo->dev, pVideo->func); diff --git a/xorg-server/hw/xfree86/common/xf86sbusBus.c b/xorg-server/hw/xfree86/common/xf86sbusBus.c index 181c6ab00..b7bb913fe 100644 --- a/xorg-server/hw/xfree86/common/xf86sbusBus.c +++ b/xorg-server/hw/xfree86/common/xf86sbusBus.c @@ -88,7 +88,7 @@ xf86SbusProbe(void) xf86SbusInfo = malloc(sizeof(psdp)); *xf86SbusInfo = NULL; for (i = 0; i < 32; i++) { - sprintf(fbDevName, "/dev/fb%d", i); + snprintf(fbDevName, sizeof(fbDevName), "/dev/fb%d", i); CheckSbusDevice(fbDevName, i); } if (sparcPromInit() >= 0) { diff --git a/xorg-server/hw/xfree86/ddc/xf86DDC.h b/xorg-server/hw/xfree86/ddc/xf86DDC.h index af3ba06a5..16a8641c6 100644 --- a/xorg-server/hw/xfree86/ddc/xf86DDC.h +++ b/xorg-server/hw/xfree86/ddc/xf86DDC.h @@ -100,11 +100,6 @@ typedef enum { DDC_QUIRK_DVI_SINGLE_LINK = 1 << 8, } ddc_quirk_t; -DisplayModePtr xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC); - -extern Bool -xf86MonitorIsHDMI(xf86MonPtr mon); - typedef void (* handle_detailed_fn)(struct detailed_monitor_section *,void *); void xf86ForEachDetailedBlock(xf86MonPtr mon, diff --git a/xorg-server/hw/xfree86/doc/ddxDesign.xml b/xorg-server/hw/xfree86/doc/ddxDesign.xml index c406cd744..ca5efc9be 100644 --- a/xorg-server/hw/xfree86/doc/ddxDesign.xml +++ b/xorg-server/hw/xfree86/doc/ddxDesign.xml @@ -34,7 +34,7 @@ &xserver.reldate; X Version 11, Release &fullrelvers; - Xorg server version &xserver.version; + X Server Version &xserver.version; @@ -3187,7 +3187,7 @@ would not need to use these directly.
- char *xf86FindOptionValue(XF86OptionPtr options, const char *name); + const char *xf86FindOptionValue(XF86OptionPtr options, const char *name);
Takes a list of options and an option name, and returns the value diff --git a/xorg-server/hw/xfree86/fbdevhw/fbdevhw.c b/xorg-server/hw/xfree86/fbdevhw/fbdevhw.c index 30a2a9133..d7b4d3c20 100644 --- a/xorg-server/hw/xfree86/fbdevhw/fbdevhw.c +++ b/xorg-server/hw/xfree86/fbdevhw/fbdevhw.c @@ -265,20 +265,20 @@ fbdev_open_pci(struct pci_device * pPci, char **namep) int fd, i; for (i = 0; i < 8; i++) { - sprintf(filename, + snprintf(filename, sizeof(filename), "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics/fb%d", pPci->domain, pPci->bus, pPci->dev, pPci->func, i); fd = open(filename, O_RDONLY, 0); if (fd < 0) { - sprintf(filename, + snprintf(filename, sizeof(filename), "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics:fb%d", pPci->domain, pPci->bus, pPci->dev, pPci->func, i); fd = open(filename, O_RDONLY, 0); } if (fd >= 0) { close(fd); - sprintf(filename, "/dev/fb%d", i); + snprintf(filename, sizeof(filename), "/dev/fb%d", i); fd = open(filename, O_RDWR, 0); if (fd != -1) { diff --git a/xorg-server/hw/xfree86/i2c/msp3430.c b/xorg-server/hw/xfree86/i2c/msp3430.c index b58c3f09c..df8adc435 100644 --- a/xorg-server/hw/xfree86/i2c/msp3430.c +++ b/xorg-server/hw/xfree86/i2c/msp3430.c @@ -1,726 +1,727 @@ -#ifdef HAVE_XORG_CONFIG_H -#include -#endif - -#include -#include - -#include "xf86.h" -#include "xf86i2c.h" -#include "msp3430.h" -#include "i2c_def.h" - -#define CONTROL 0x00 -#define WR_DEM 0x10 -#define RD_DEM 0x11 -#define WR_DSP 0x12 -#define RD_DSP 0x13 - - -void InitMSP34xxG(MSP3430Ptr m); -void InitMSP34x5D(MSP3430Ptr m); -void CheckModeMSP34x5D(MSP3430Ptr m); -char *MSP_getProductName (CARD16 product_id); -void mpause(int milliseconds); - -#define __MSPDEBUG__ 0 - -#if __MSPDEBUG__ > 3 - -void MSPBeep(MSP3430Ptr m, CARD8 freq); -#define __MSPBEEP MSPBeep(m,0x14); - -#else - -#define __MSPBEEP -#endif - -static void SetMSP3430Control(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegValueHigh, CARD8 RegValueLow) -{ - I2CByte data[3]; - - data[0]=RegAddress; - data[1]=RegValueHigh; - data[2]=RegValueLow; - - I2C_WriteRead(&(m->d),data,3,NULL,0); -} - -static void SetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow, - CARD8 RegValueHigh, CARD8 RegValueLow) -{ - I2CByte data[5]; -#ifdef MSP_DEBUG - if(!m->registers_present[RegSubAddressLow]){ - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_ERROR, "Attempt to access non-existent register in MSP34xxX: 0x%02x 0x%02x 0x%02x <- 0x%02x 0x%02x\n", - RegAddress, RegSubAddressHigh, RegSubAddressLow, RegValueHigh, RegValueLow); - } -#endif - - data[0] = RegAddress; - data[1] = RegSubAddressHigh; - data[2] = RegSubAddressLow; - data[3] = RegValueHigh; - data[4] = RegValueLow; - - I2C_WriteRead(&(m->d),data,5,NULL,0); -} - -static void GetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow, - CARD8 *RegValueHigh, CARD8 *RegValueLow) -{ - I2CByte send[3]; - I2CByte receive[2]; - - send[0] = RegAddress; - send[1] = RegSubAddressHigh; - send[2] = RegSubAddressLow; - - I2C_WriteRead(&(m->d), send, 3, receive, 2); - - *RegValueHigh = receive[0]; - *RegValueLow = receive[1]; -} - -#if __MSPDEBUG__ > 2 -static void MSP3430DumpStatus(MSP3430Ptr m) -{ -CARD8 status_hi, status_lo; -CARD8 subaddr, data[2]; - -GetMSP3430Data(m, RD_DEM, 0x02, 0x00, &status_hi, &status_lo); -xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: SAP(8)=%d mono/NICAM(7)=%d stereo=%d %s O_1=%d O_0=%d 2nd car=%d 1st car=%d\n", - status_hi & 1, (status_lo>>7) & 1, (status_lo>>6)&1, - (status_lo>>5)? ( (status_hi>>1)&1? "bad NICAM reception" : "NICAM" ) : - ((status_hi>>1)&1 ? "bogus" : "ANALOG FM/AM") , - (status_lo>>4)&1, (status_lo>>3)&1,!( (status_lo>>2)&1), !((status_lo>>1)&1)); - -GetMSP3430Data(m, RD_DEM, 0x00, 0x7E, &status_hi, &status_lo); -xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: standard result=0x%02x%02x\n", - status_hi, status_lo); -subaddr=0x0; -I2C_WriteRead(&(m->d), &subaddr, 1, data, 2); -xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: control=0x%02x%02x\n", - data[1], data[0]); -} -#endif - -/* wrapper */ -void InitMSP3430(MSP3430Ptr m) -{ - #if __MSPDEBUG__ > 1 - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP3430(m->connector=%d, m->standard=%d, m->chip_family=%d)\n", - m->connector, m->standard, m->chip_family); - #endif - switch (m->chip_family) { - case MSPFAMILY_34x0G: - InitMSP34xxG(m); - break; - case MSPFAMILY_34x5G: - InitMSP34xxG(m); - break; - case MSPFAMILY_34x5D: - InitMSP34x5D(m); - break; - } -} - -/*----------------------------------------------------------------- -| common functions for all MSP34xx chips -|----------------------------------------------------------------*/ - -MSP3430Ptr DetectMSP3430(I2CBusPtr b, I2CSlaveAddr addr) -{ - MSP3430Ptr m; - I2CByte a; - CARD8 hardware_version, major_revision, product_code, rom_version; - Bool supported; - - m = calloc(1,sizeof(MSP3430Rec)); - if(m == NULL)return NULL; - m->d.DevName = strdup("MSP34xx"); - m->d.SlaveAddr = addr; - m->d.pI2CBus = b; - m->d.NextDev = NULL; - m->d.StartTimeout = b->StartTimeout; - m->d.BitTimeout = b->BitTimeout; - m->d.AcknTimeout = b->AcknTimeout; - m->d.ByteTimeout = b->ByteTimeout; - - if(!I2C_WriteRead(&(m->d), NULL, 0, &a, 1)) - { - free(m->d.DevName); - free(m); - return NULL; - } - - - m->standard=MSP3430_NTSC; - m->connector=MSP3430_CONNECTOR_1; - m->mode=MSPMODE_STEREO_A; /*stereo or chanel A if avail. */ - m->c_format=MSPFORMAT_UNKNOWN; - m->c_standard=MSPSTANDARD_UNKNOWN; - m->c_matrix=m->c_fmmatrix=m->c_source=0; - m->volume=0; - m->recheck=FALSE; - - GetMSP3430Data(m, RD_DSP, 0x00, 0x1E, &hardware_version, &major_revision); - GetMSP3430Data(m, RD_DSP, 0x00, 0x1F, &product_code, &rom_version); - m->hardware_version=hardware_version; - m->major_revision=major_revision; - m->product_code=product_code; - m->rom_version=rom_version; - - m->chip_id=((major_revision << 8) | product_code); - - supported=FALSE; - switch (major_revision) { - case 4: /* 34xxD */ - switch (product_code) { - case 0x05: /* 3405D */ - case 0x0A: /* 3410D */ - case 0x0F: /* 3415D */ - m->chip_family=MSPFAMILY_34x5D; - m->recheck=TRUE; - supported=TRUE; - break; - default: - m->chip_family=MSPFAMILY_34x0D; - } - break; - case 7: /* 34xxG */ - switch(product_code){ - case 0x00: - case 0x0A: - case 0x1E: - case 0x28: - case 0x32: - m->chip_family=MSPFAMILY_34x0G; - supported=TRUE; - break; - case 0x0f: - case 0x19: - case 0x2d: - case 0x37: - case 0x41: - m->chip_family=MSPFAMILY_34x5G; - supported=TRUE; - #ifdef MSP_DEBUG - memset(m->registers_present, 0, 256); - #define A(num) m->registers_present[(num)]=1; - #define B(num1, num2) memset(&(m->registers_present[num1]), 1, num2-num1); - A(0x20) - A(0x30) - A(0x40) - A(0x00) - B(0x01, 0x08) - B(0x0B, 0x0E) - A(0x10) - B(0x12,0x14) - A(0x16) - A(0x29) - #undef B - #undef A - #endif - break; - default: - m->chip_family=MSPFAMILY_UNKNOWN; - } - break; - default: - m->chip_family=MSPFAMILY_UNKNOWN; - } - - xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Found %s%s, rom version 0x%02x, chip_id=0x%04x\n", - MSP_getProductName(m->chip_id), supported?"":" (unsupported)", rom_version, m->chip_id); - - if (!supported) { - free(m->d.DevName); - free(m); - return NULL; - } - if(!I2CDevInit(&(m->d))) - { - free(m->d.DevName); - free(m); - return NULL; - } - - return m; -} - -void ResetMSP3430(MSP3430Ptr m) -{ - /* Reset the MSP3430 */ - SetMSP3430Control(m, 0x00, 0x80, 0x00); - /* Set it back to normal operation */ - SetMSP3430Control(m, 0x00, 0x00, 0x00); - - m->c_format=MSPFORMAT_UNKNOWN; - m->c_standard=MSPSTANDARD_UNKNOWN; - m->c_matrix=m->c_fmmatrix=m->c_source=0; - m->volume=0; -} - -void MSP3430SetVolume (MSP3430Ptr m, CARD8 value) -{ - CARD8 result; -#if 0 - CARD8 old_volume; - GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result); - xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 result 0x%02x\n", result); -#endif - /* save an extra Get call */ - result=0; - - SetMSP3430Data(m, WR_DSP, 0x00, 0x00, value, result); - - SetMSP3430Data(m, WR_DSP, 0x00, 0x07, value, 0); - m->volume=value; - -#if __MSPDEBUG__ > 2 - MSP3430DumpStatus(m); - __MSPBEEP - GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result); - xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 volume 0x%02x\n",value); -#endif -} - - -void MSP3430SetSAP (MSP3430Ptr m, int mode) -{ - xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Put actual code to change SAP here\n"); - - SetMSP3430Data(m, WR_DSP, 0x00, 0x08, mode & 0xff, 0x20); -} - - -#if 0 -void MSP3430SetSource(MSP3430Ptr m, CARD8 value) -{ - /* Write to DSP, register 0x0008, (loudspeaker channel source/matrix) */ - /* This sets the source to the TV tuner, for stereo operation */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x08, value, 0x20); -} -#endif - - -char *MSP_getProductName (CARD16 product_id) -{ - switch (product_id) { - case 0x0400: return "MSP3400D"; - case 0x040a: return "MSP3410D"; - case 0x0405: return "MSP3405D"; - case 0x040f: return "MSP3415D"; - case 0x0700: return "MSP3400G"; - case 0x070a: return "MSP3410G"; - case 0x071e: return "MSP3430G"; - case 0x0728: return "MSP3440G"; - case 0x0732: return "MSP3450G"; - case 0x070f: return "MSP3415G"; - case 0x0719: return "MSP3425G"; - case 0x072d: return "MSP3445G"; - case 0x0737: return "MSP3455G"; - case 0x0741: return "MSP3465G"; - } - return "MSP - unknown type"; -} - -#if __MSPDEBUG__ > 2 -/*puts beep in MSP output - freq = 0x01 - 16Hz ... 0x40 - 1kHz ... 0xff - 4kHz -*/ -void MSPBeep(MSP3430Ptr m, CARD8 freq) { - SetMSP3430Data (m, WR_DSP, 0x00, freq, 0x7f, 0x40); - mpause(100); - SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, 0x00); -} -#endif - -void mpause(int milliseconds) { - int i,m; - m=milliseconds/20; - for (i=0;i 1 - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP34xxG(m->connector=%d, m->standard=%d, m->chip_family=%d)\n", - m->connector, m->standard, m->chip_family); - #endif - /* Reset MSP3430 */ - SetMSP3430Control(m, 0x00, 0x80, 0x00); - /* Set it back to normal operation */ - SetMSP3430Control(m, 0x00, 0x00, 0x00); - - /*set MODUS register */ - /* bits: 0 - automatic sound detection */ - /* 1 - enable STATUS change */ - /* 12 - detect 6.5 Mhz carrier as D/K1, D/K2 or D/K NICAM (does not seem to work ) */ - /* 13 - detect 4.5 Mhz carrier as BTSC */ - if ( (m->standard & 0xff) == MSP3430_PAL ) - { - SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x30, 0x03|0x08); /* make O_ pins tristate */ - /* PAL standard */ - SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x01); /* possibly wrong */ - } else { - SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x20, 0x03|0x08); - /* standard selection is M-BTSC-Stereo */ - SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x20); - } - - switch(m->connector){ - case MSP3430_CONNECTOR_1: - SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x03, 0x20); - break; - case MSP3430_CONNECTOR_2: - /* this has not been checked yet.. could be bogus */ - /* SCART Input Prescale: 0 dB gain */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); - SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20); - break; - case MSP3430_CONNECTOR_3: - default: - /* SCART Input Prescale: 0 dB gain */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); - - SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20); - break; - } - - switch(m->standard){ - case MSP3430_PAL: - SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); - SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a); - SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x03); - /* Set volume to FAST_MUTE. */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); - break; - case MSP3430_PAL_DK1: - SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); - SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a); - SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x04); - /* Set volume to FAST_MUTE. */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); - break; - case MSP3430_SECAM: /* is this right ? */ - case MSP3430_NTSC: - /* Write to DSP, register 0x000E, (prescale FM/FM matrix) */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); - - /* Set volume to FAST_MUTE. */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); - break; - } - -} - -/*----------------------------------------------------------------- -| specific functions for all MSP34x5D chips -|----------------------------------------------------------------*/ - -void InitMSP34x5D(MSP3430Ptr m) -{ -int count; -CARD8 high,low; -CARD16 result,standard; -CARD16 peak; - - -if (m->c_format==MSPFORMAT_UNKNOWN) ResetMSP3430(m); -else { - /*mute volume*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x00, 0x00, 0x00); -} - - - - switch(m->connector){ - case MSP3430_CONNECTOR_2: - case MSP3430_CONNECTOR_3: - if (m->c_format!=MSPFORMAT_SCART) { - /* SCART Input Prescale: 0 dB gain */ - SetMSP3430Data (m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); - /* this has not been checked yet.. could be bogus */ - m->c_format=MSPFORMAT_SCART; /*stereo*/ - } - break; - case MSP3430_CONNECTOR_1: - default: - - switch ( m->standard & 0x00ff ) { - case MSP3430_PAL: - switch( m->standard ) { - case MSP3430_PAL_DK1: - standard=MSPSTANDARD_FM_DK1; - break; -/* case MSP3430_PAL_DK2: - standard=MSPSTANDARD_FM_DK2; - break; - case MSP3430_PAL_BG: - may be FM stereo (Germany) or FM NICAM (Scandinavia,spain) - standard=MSPSTANDARD_AUTO; - break; -*/ - default: - standard=MSPSTANDARD_AUTO; - } - break; - case MSP3430_SECAM: - standard=MSPSTANDARD_AUTO; - case MSP3430_NTSC: - /* Only MSP34x5 supported format - Korean NTSC-M*/ - standard=MSPSTANDARD_FM_M; - default: - standard=MSPSTANDARD_AUTO; - } - - /*no NICAM support in MSP3410D - force to autodetect*/ - if ((m->chip_id==0x405) && (standard>=MSPSTANDARD_NICAM_BG)) - standard=MSPSTANDARD_AUTO; - - if (m->c_standard != standard) { - - SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF); - if (standard==MSPSTANDARD_AUTO) { - count = 50; /* time shouldn't exceed 1s, just in case */ - do { - usleep(20000); - GetMSP3430Data (m, RD_DEM, 0x00, 0x7e, &high, &low); - result = ( high << 8 ) | low; - --count; - } while( result > 0x07ff && count > 0 ); - - if ((result > MSPSTANDARD_AUTO)) - standard=result; - else standard=MSPSTANDARD_UNKNOWN; -#if __MSPDEBUG__ > 1 - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Detected audio standard: %d\n",result); -#endif - /* result = MSPSTANDARD_NICAM_L can be one of: - SECAM_L - MSPSTANDARD_NICAM_L - D/K1 - MSPSTANDARD_FM_DK1 - D/K2 - MSPSTANDARD_FM_DK2 - D/K-NICAM - MSPSTANDARD_NICAM_DK*/ - if( standard == MSPSTANDARD_NICAM_L ) { - if ((m->standard & 0x00ff)==MSP3430_PAL) { - /* force PAL D/K */ - standard=MSPSTANDARD_FM_DK1; - SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF); -#if __MSPDEBUG__ > 1 - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO, "Detected 6.5MHz carrier - forced to D/K1 !!!\n" ); -#endif - } - } - } - m->c_standard=standard; - } /*end - standard changed*/ - else { - if (standardc_format=MSPFORMAT_1xFM; - } - else if (standardL ch1->R*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x0c, 0x00, 0x20); - - mpause(250); - GetMSP3430Data (m, RD_DSP, 0x00, 0x1A, &high, &low); - peak = (high << 8) | low; -#if __MSPDEBUG__ > 1 - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Second carrier Quasi-Peak detection: %d\n",peak); -#endif - /*turn on FM DC Notch*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x17, 0x00, 0x00); - - if (peak<5) { - /* if second carrier not detected - only mono from first carrier*/ - m->c_format=MSPFORMAT_1xFM; - } - else { - m->c_format=MSPFORMAT_2xFM; - /*start of FM identification process - FM_WAIT - wait at least 0.5s - used 1s - gives beter resolution*/ - mpause(1000); - } - } - else { - if (standard==MSPSTANDARD_NICAM_L) { - m->c_format=MSPFORMAT_NICAM_AM; - /* set AM prescale */ - SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x7C, 0); - } - else { - m->c_format=MSPFORMAT_NICAM_FM; - /* set FM prescale */ - SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x30, 0); - } - /* set FM deemphasis*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x0f, 0x00, 0); - /* set NICAM prescale to 0dB */ - SetMSP3430Data (m, WR_DSP, 0x00, 0x10, 0x20, 0); - } - - break; - } /*end - case conector*/ - - CheckModeMSP34x5D(m); - - /* Set volume to FAST_MUTE. */ - /*SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);*/ - /*set volume*/ - MSP3430SetVolume(m,m->volume); - - __MSPBEEP - - -} /* EnableMSP34x5D ()... */ - - - - -void CheckModeMSP34x5D(MSP3430Ptr m) { - const char stereo_on=25; - const char stereo_off=20; - const char dual_on=-stereo_on; - const char dual_off=-stereo_off; - char detect; - CARD8 matrix, fmmatrix, source, high, low; - - fmmatrix=0; /*no matrix*/ - source=0; /*FM*/ - switch (m->c_format) { - case MSPFORMAT_NICAM_FM: - case MSPFORMAT_NICAM_AM: - case MSPFORMAT_SCART: - source=( (m->c_format == MSPFORMAT_SCART)?2:1 ); - switch (m->mode) { - case MSPMODE_MONO: - matrix=0x30; /*MONO*/ - break; - case MSPMODE_A: - matrix=0x00; /*A*/ - break; - case MSPMODE_B: - matrix=0x10; /*B*/ - break; - default: - matrix=0x20; /*STEREO*/ - break; - } - break; - default: - case MSPFORMAT_1xFM: - matrix=0x00; /*A*/ - break; - case MSPFORMAT_2xFM: - switch (m->mode) { - case MSPMODE_MONO: - matrix=0x30; /*MONO*/ - break; - case MSPMODE_STEREO: - matrix=0x20; /*STEREO*/ - fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1); - break; - case MSPMODE_AB: - matrix=0x20; /*STEREO*/ - break; - case MSPMODE_A: - matrix=0x00; /*A*/ - break; - case MSPMODE_B: - matrix=0x10; /*B*/ - break; - default: - /*FM_IDENT_CHECK*/ - GetMSP3430Data (m, RD_DSP, 0x00, 0x18, &high, &low); - detect=(char)high; -#if __MSPDEBUG__ > 1 - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Stereo Detection Register: %d\n",detect); -#endif - if (detect>=((m->c_mode==MSPMODE_STEREO)?stereo_off:stereo_on)) { - m->c_mode=MSPMODE_STEREO; - matrix=0x20; /*STEREO*/ - fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1); - } - else if (detect<=((m->c_mode==MSPMODE_AB)?dual_off:dual_on)) { - m->c_mode=MSPMODE_AB; - switch (m->mode) { - case MSPMODE_STEREO_AB: matrix=0x20; break; - case MSPMODE_STEREO_B: matrix=0x10; break; - default: - case MSPMODE_A: matrix=0x00; break; - } - } - else { - m->c_mode=MSPMODE_MONO; - matrix=0x30; /*MONO*/ - } - break; - } /* end - case mode*/ - break; - } - - if (m->c_fmmatrix != fmmatrix) { - GetMSP3430Data (m, RD_DSP, 0x00, 0x0e, &high, &low); - SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, high, fmmatrix); - m->c_fmmatrix = fmmatrix; - } - - if ((m->c_matrix != matrix) || (m->c_source != source)) { - /*set chanel source and matrix for loudspeaker*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x08, source, matrix); - - m->c_matrix = matrix; - m->c_source = source; - } - - if ( ((m->c_format) & 0xF0) == MSPFORMAT_NICAM) - SetMSP3430Data (m, WR_DEM, 0x00, 0x21, 0, 1); - -#if __MSPDEBUG__ > 0 - char *msg; - switch (matrix) { - case 0x30: /*MONO*/ - msg="MONO"; - break; - case 0x00: /*LEFT*/ - msg="MONO/CHANNEL_1"; - break; - case 0x10: /*RIGHT*/ - msg="MONO/CHANNEL_2"; - break; - case 0x20: /*LEFT*/ - msg="STEREO"; - break; - default: - msg="unknown"; - break; - } - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Audio mode set to: %s\n",msg); -#endif -} - +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#include +#include + +#include "xf86.h" +#include "xf86i2c.h" +#include "msp3430.h" +#include "i2c_def.h" + +#define CONTROL 0x00 +#define WR_DEM 0x10 +#define RD_DEM 0x11 +#define WR_DSP 0x12 +#define RD_DSP 0x13 + + +void InitMSP34xxG(MSP3430Ptr m); +void InitMSP34x5D(MSP3430Ptr m); +void CheckModeMSP34x5D(MSP3430Ptr m); +static const char *MSP_getProductName (CARD16 product_id); +void mpause(int milliseconds); + +#define __MSPDEBUG__ 0 + +#if __MSPDEBUG__ > 3 + +void MSPBeep(MSP3430Ptr m, CARD8 freq); +#define __MSPBEEP MSPBeep(m,0x14); + +#else + +#define __MSPBEEP +#endif + +static void SetMSP3430Control(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegValueHigh, CARD8 RegValueLow) +{ + I2CByte data[3]; + + data[0]=RegAddress; + data[1]=RegValueHigh; + data[2]=RegValueLow; + + I2C_WriteRead(&(m->d),data,3,NULL,0); +} + +static void SetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow, + CARD8 RegValueHigh, CARD8 RegValueLow) +{ + I2CByte data[5]; +#ifdef MSP_DEBUG + if(!m->registers_present[RegSubAddressLow]){ + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_ERROR, "Attempt to access non-existent register in MSP34xxX: 0x%02x 0x%02x 0x%02x <- 0x%02x 0x%02x\n", + RegAddress, RegSubAddressHigh, RegSubAddressLow, RegValueHigh, RegValueLow); + } +#endif + + data[0] = RegAddress; + data[1] = RegSubAddressHigh; + data[2] = RegSubAddressLow; + data[3] = RegValueHigh; + data[4] = RegValueLow; + + I2C_WriteRead(&(m->d),data,5,NULL,0); +} + +static void GetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow, + CARD8 *RegValueHigh, CARD8 *RegValueLow) +{ + I2CByte send[3]; + I2CByte receive[2]; + + send[0] = RegAddress; + send[1] = RegSubAddressHigh; + send[2] = RegSubAddressLow; + + I2C_WriteRead(&(m->d), send, 3, receive, 2); + + *RegValueHigh = receive[0]; + *RegValueLow = receive[1]; +} + +#if __MSPDEBUG__ > 2 +static void MSP3430DumpStatus(MSP3430Ptr m) +{ +CARD8 status_hi, status_lo; +CARD8 subaddr, data[2]; + +GetMSP3430Data(m, RD_DEM, 0x02, 0x00, &status_hi, &status_lo); +xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: SAP(8)=%d mono/NICAM(7)=%d stereo=%d %s O_1=%d O_0=%d 2nd car=%d 1st car=%d\n", + status_hi & 1, (status_lo>>7) & 1, (status_lo>>6)&1, + (status_lo>>5)? ( (status_hi>>1)&1? "bad NICAM reception" : "NICAM" ) : + ((status_hi>>1)&1 ? "bogus" : "ANALOG FM/AM") , + (status_lo>>4)&1, (status_lo>>3)&1,!( (status_lo>>2)&1), !((status_lo>>1)&1)); + +GetMSP3430Data(m, RD_DEM, 0x00, 0x7E, &status_hi, &status_lo); +xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: standard result=0x%02x%02x\n", + status_hi, status_lo); +subaddr=0x0; +I2C_WriteRead(&(m->d), &subaddr, 1, data, 2); +xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: control=0x%02x%02x\n", + data[1], data[0]); +} +#endif + +/* wrapper */ +void InitMSP3430(MSP3430Ptr m) +{ + #if __MSPDEBUG__ > 1 + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP3430(m->connector=%d, m->standard=%d, m->chip_family=%d)\n", + m->connector, m->standard, m->chip_family); + #endif + switch (m->chip_family) { + case MSPFAMILY_34x0G: + InitMSP34xxG(m); + break; + case MSPFAMILY_34x5G: + InitMSP34xxG(m); + break; + case MSPFAMILY_34x5D: + InitMSP34x5D(m); + break; + } +} + +/*----------------------------------------------------------------- +| common functions for all MSP34xx chips +|----------------------------------------------------------------*/ + +MSP3430Ptr DetectMSP3430(I2CBusPtr b, I2CSlaveAddr addr) +{ + MSP3430Ptr m; + I2CByte a; + CARD8 hardware_version, major_revision, product_code, rom_version; + Bool supported; + + m = calloc(1,sizeof(MSP3430Rec)); + if(m == NULL)return NULL; + m->d.DevName = strdup("MSP34xx"); + m->d.SlaveAddr = addr; + m->d.pI2CBus = b; + m->d.NextDev = NULL; + m->d.StartTimeout = b->StartTimeout; + m->d.BitTimeout = b->BitTimeout; + m->d.AcknTimeout = b->AcknTimeout; + m->d.ByteTimeout = b->ByteTimeout; + + if(!I2C_WriteRead(&(m->d), NULL, 0, &a, 1)) + { + free(m->d.DevName); + free(m); + return NULL; + } + + + m->standard=MSP3430_NTSC; + m->connector=MSP3430_CONNECTOR_1; + m->mode=MSPMODE_STEREO_A; /*stereo or chanel A if avail. */ + m->c_format=MSPFORMAT_UNKNOWN; + m->c_standard=MSPSTANDARD_UNKNOWN; + m->c_matrix=m->c_fmmatrix=m->c_source=0; + m->volume=0; + m->recheck=FALSE; + + GetMSP3430Data(m, RD_DSP, 0x00, 0x1E, &hardware_version, &major_revision); + GetMSP3430Data(m, RD_DSP, 0x00, 0x1F, &product_code, &rom_version); + m->hardware_version=hardware_version; + m->major_revision=major_revision; + m->product_code=product_code; + m->rom_version=rom_version; + + m->chip_id=((major_revision << 8) | product_code); + + supported=FALSE; + switch (major_revision) { + case 4: /* 34xxD */ + switch (product_code) { + case 0x05: /* 3405D */ + case 0x0A: /* 3410D */ + case 0x0F: /* 3415D */ + m->chip_family=MSPFAMILY_34x5D; + m->recheck=TRUE; + supported=TRUE; + break; + default: + m->chip_family=MSPFAMILY_34x0D; + } + break; + case 7: /* 34xxG */ + switch(product_code){ + case 0x00: + case 0x0A: + case 0x1E: + case 0x28: + case 0x32: + m->chip_family=MSPFAMILY_34x0G; + supported=TRUE; + break; + case 0x0f: + case 0x19: + case 0x2d: + case 0x37: + case 0x41: + m->chip_family=MSPFAMILY_34x5G; + supported=TRUE; + #ifdef MSP_DEBUG + memset(m->registers_present, 0, 256); + #define A(num) m->registers_present[(num)]=1; + #define B(num1, num2) memset(&(m->registers_present[num1]), 1, num2-num1); + A(0x20) + A(0x30) + A(0x40) + A(0x00) + B(0x01, 0x08) + B(0x0B, 0x0E) + A(0x10) + B(0x12,0x14) + A(0x16) + A(0x29) + #undef B + #undef A + #endif + break; + default: + m->chip_family=MSPFAMILY_UNKNOWN; + } + break; + default: + m->chip_family=MSPFAMILY_UNKNOWN; + } + + xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Found %s%s, rom version 0x%02x, chip_id=0x%04x\n", + MSP_getProductName(m->chip_id), supported?"":" (unsupported)", rom_version, m->chip_id); + + if (!supported) { + free(m->d.DevName); + free(m); + return NULL; + } + if(!I2CDevInit(&(m->d))) + { + free(m->d.DevName); + free(m); + return NULL; + } + + return m; +} + +void ResetMSP3430(MSP3430Ptr m) +{ + /* Reset the MSP3430 */ + SetMSP3430Control(m, 0x00, 0x80, 0x00); + /* Set it back to normal operation */ + SetMSP3430Control(m, 0x00, 0x00, 0x00); + + m->c_format=MSPFORMAT_UNKNOWN; + m->c_standard=MSPSTANDARD_UNKNOWN; + m->c_matrix=m->c_fmmatrix=m->c_source=0; + m->volume=0; +} + +void MSP3430SetVolume (MSP3430Ptr m, CARD8 value) +{ + CARD8 result; +#if 0 + CARD8 old_volume; + GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result); + xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 result 0x%02x\n", result); +#endif + /* save an extra Get call */ + result=0; + + SetMSP3430Data(m, WR_DSP, 0x00, 0x00, value, result); + + SetMSP3430Data(m, WR_DSP, 0x00, 0x07, value, 0); + m->volume=value; + +#if __MSPDEBUG__ > 2 + MSP3430DumpStatus(m); + __MSPBEEP + GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result); + xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 volume 0x%02x\n",value); +#endif +} + + +void MSP3430SetSAP (MSP3430Ptr m, int mode) +{ + xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Put actual code to change SAP here\n"); + + SetMSP3430Data(m, WR_DSP, 0x00, 0x08, mode & 0xff, 0x20); +} + + +#if 0 +void MSP3430SetSource(MSP3430Ptr m, CARD8 value) +{ + /* Write to DSP, register 0x0008, (loudspeaker channel source/matrix) */ + /* This sets the source to the TV tuner, for stereo operation */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x08, value, 0x20); +} +#endif + + +static const char * +MSP_getProductName (CARD16 product_id) +{ + switch (product_id) { + case 0x0400: return "MSP3400D"; + case 0x040a: return "MSP3410D"; + case 0x0405: return "MSP3405D"; + case 0x040f: return "MSP3415D"; + case 0x0700: return "MSP3400G"; + case 0x070a: return "MSP3410G"; + case 0x071e: return "MSP3430G"; + case 0x0728: return "MSP3440G"; + case 0x0732: return "MSP3450G"; + case 0x070f: return "MSP3415G"; + case 0x0719: return "MSP3425G"; + case 0x072d: return "MSP3445G"; + case 0x0737: return "MSP3455G"; + case 0x0741: return "MSP3465G"; + } + return "MSP - unknown type"; +} + +#if __MSPDEBUG__ > 2 +/*puts beep in MSP output + freq = 0x01 - 16Hz ... 0x40 - 1kHz ... 0xff - 4kHz +*/ +void MSPBeep(MSP3430Ptr m, CARD8 freq) { + SetMSP3430Data (m, WR_DSP, 0x00, freq, 0x7f, 0x40); + mpause(100); + SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, 0x00); +} +#endif + +void mpause(int milliseconds) { + int i,m; + m=milliseconds/20; + for (i=0;i 1 + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP34xxG(m->connector=%d, m->standard=%d, m->chip_family=%d)\n", + m->connector, m->standard, m->chip_family); + #endif + /* Reset MSP3430 */ + SetMSP3430Control(m, 0x00, 0x80, 0x00); + /* Set it back to normal operation */ + SetMSP3430Control(m, 0x00, 0x00, 0x00); + + /*set MODUS register */ + /* bits: 0 - automatic sound detection */ + /* 1 - enable STATUS change */ + /* 12 - detect 6.5 Mhz carrier as D/K1, D/K2 or D/K NICAM (does not seem to work ) */ + /* 13 - detect 4.5 Mhz carrier as BTSC */ + if ( (m->standard & 0xff) == MSP3430_PAL ) + { + SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x30, 0x03|0x08); /* make O_ pins tristate */ + /* PAL standard */ + SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x01); /* possibly wrong */ + } else { + SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x20, 0x03|0x08); + /* standard selection is M-BTSC-Stereo */ + SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x20); + } + + switch(m->connector){ + case MSP3430_CONNECTOR_1: + SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x03, 0x20); + break; + case MSP3430_CONNECTOR_2: + /* this has not been checked yet.. could be bogus */ + /* SCART Input Prescale: 0 dB gain */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); + SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20); + break; + case MSP3430_CONNECTOR_3: + default: + /* SCART Input Prescale: 0 dB gain */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); + + SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20); + break; + } + + switch(m->standard){ + case MSP3430_PAL: + SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); + SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a); + SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x03); + /* Set volume to FAST_MUTE. */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); + break; + case MSP3430_PAL_DK1: + SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); + SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a); + SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x04); + /* Set volume to FAST_MUTE. */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); + break; + case MSP3430_SECAM: /* is this right ? */ + case MSP3430_NTSC: + /* Write to DSP, register 0x000E, (prescale FM/FM matrix) */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); + + /* Set volume to FAST_MUTE. */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); + break; + } + +} + +/*----------------------------------------------------------------- +| specific functions for all MSP34x5D chips +|----------------------------------------------------------------*/ + +void InitMSP34x5D(MSP3430Ptr m) +{ +int count; +CARD8 high,low; +CARD16 result,standard; +CARD16 peak; + + +if (m->c_format==MSPFORMAT_UNKNOWN) ResetMSP3430(m); +else { + /*mute volume*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x00, 0x00, 0x00); +} + + + + switch(m->connector){ + case MSP3430_CONNECTOR_2: + case MSP3430_CONNECTOR_3: + if (m->c_format!=MSPFORMAT_SCART) { + /* SCART Input Prescale: 0 dB gain */ + SetMSP3430Data (m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); + /* this has not been checked yet.. could be bogus */ + m->c_format=MSPFORMAT_SCART; /*stereo*/ + } + break; + case MSP3430_CONNECTOR_1: + default: + + switch ( m->standard & 0x00ff ) { + case MSP3430_PAL: + switch( m->standard ) { + case MSP3430_PAL_DK1: + standard=MSPSTANDARD_FM_DK1; + break; +/* case MSP3430_PAL_DK2: + standard=MSPSTANDARD_FM_DK2; + break; + case MSP3430_PAL_BG: + may be FM stereo (Germany) or FM NICAM (Scandinavia,spain) + standard=MSPSTANDARD_AUTO; + break; +*/ + default: + standard=MSPSTANDARD_AUTO; + } + break; + case MSP3430_SECAM: + standard=MSPSTANDARD_AUTO; + case MSP3430_NTSC: + /* Only MSP34x5 supported format - Korean NTSC-M*/ + standard=MSPSTANDARD_FM_M; + default: + standard=MSPSTANDARD_AUTO; + } + + /*no NICAM support in MSP3410D - force to autodetect*/ + if ((m->chip_id==0x405) && (standard>=MSPSTANDARD_NICAM_BG)) + standard=MSPSTANDARD_AUTO; + + if (m->c_standard != standard) { + + SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF); + if (standard==MSPSTANDARD_AUTO) { + count = 50; /* time shouldn't exceed 1s, just in case */ + do { + usleep(20000); + GetMSP3430Data (m, RD_DEM, 0x00, 0x7e, &high, &low); + result = ( high << 8 ) | low; + --count; + } while( result > 0x07ff && count > 0 ); + + if ((result > MSPSTANDARD_AUTO)) + standard=result; + else standard=MSPSTANDARD_UNKNOWN; +#if __MSPDEBUG__ > 1 + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Detected audio standard: %d\n",result); +#endif + /* result = MSPSTANDARD_NICAM_L can be one of: + SECAM_L - MSPSTANDARD_NICAM_L + D/K1 - MSPSTANDARD_FM_DK1 + D/K2 - MSPSTANDARD_FM_DK2 + D/K-NICAM - MSPSTANDARD_NICAM_DK*/ + if( standard == MSPSTANDARD_NICAM_L ) { + if ((m->standard & 0x00ff)==MSP3430_PAL) { + /* force PAL D/K */ + standard=MSPSTANDARD_FM_DK1; + SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF); +#if __MSPDEBUG__ > 1 + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO, "Detected 6.5MHz carrier - forced to D/K1 !!!\n" ); +#endif + } + } + } + m->c_standard=standard; + } /*end - standard changed*/ + else { + if (standardc_format=MSPFORMAT_1xFM; + } + else if (standardL ch1->R*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x0c, 0x00, 0x20); + + mpause(250); + GetMSP3430Data (m, RD_DSP, 0x00, 0x1A, &high, &low); + peak = (high << 8) | low; +#if __MSPDEBUG__ > 1 + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Second carrier Quasi-Peak detection: %d\n",peak); +#endif + /*turn on FM DC Notch*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x17, 0x00, 0x00); + + if (peak<5) { + /* if second carrier not detected - only mono from first carrier*/ + m->c_format=MSPFORMAT_1xFM; + } + else { + m->c_format=MSPFORMAT_2xFM; + /*start of FM identification process - FM_WAIT + wait at least 0.5s - used 1s - gives beter resolution*/ + mpause(1000); + } + } + else { + if (standard==MSPSTANDARD_NICAM_L) { + m->c_format=MSPFORMAT_NICAM_AM; + /* set AM prescale */ + SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x7C, 0); + } + else { + m->c_format=MSPFORMAT_NICAM_FM; + /* set FM prescale */ + SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x30, 0); + } + /* set FM deemphasis*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x0f, 0x00, 0); + /* set NICAM prescale to 0dB */ + SetMSP3430Data (m, WR_DSP, 0x00, 0x10, 0x20, 0); + } + + break; + } /*end - case conector*/ + + CheckModeMSP34x5D(m); + + /* Set volume to FAST_MUTE. */ + /*SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);*/ + /*set volume*/ + MSP3430SetVolume(m,m->volume); + + __MSPBEEP + + +} /* EnableMSP34x5D ()... */ + + + + +void CheckModeMSP34x5D(MSP3430Ptr m) { + const char stereo_on=25; + const char stereo_off=20; + const char dual_on=-stereo_on; + const char dual_off=-stereo_off; + char detect; + CARD8 matrix, fmmatrix, source, high, low; + + fmmatrix=0; /*no matrix*/ + source=0; /*FM*/ + switch (m->c_format) { + case MSPFORMAT_NICAM_FM: + case MSPFORMAT_NICAM_AM: + case MSPFORMAT_SCART: + source=( (m->c_format == MSPFORMAT_SCART)?2:1 ); + switch (m->mode) { + case MSPMODE_MONO: + matrix=0x30; /*MONO*/ + break; + case MSPMODE_A: + matrix=0x00; /*A*/ + break; + case MSPMODE_B: + matrix=0x10; /*B*/ + break; + default: + matrix=0x20; /*STEREO*/ + break; + } + break; + default: + case MSPFORMAT_1xFM: + matrix=0x00; /*A*/ + break; + case MSPFORMAT_2xFM: + switch (m->mode) { + case MSPMODE_MONO: + matrix=0x30; /*MONO*/ + break; + case MSPMODE_STEREO: + matrix=0x20; /*STEREO*/ + fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1); + break; + case MSPMODE_AB: + matrix=0x20; /*STEREO*/ + break; + case MSPMODE_A: + matrix=0x00; /*A*/ + break; + case MSPMODE_B: + matrix=0x10; /*B*/ + break; + default: + /*FM_IDENT_CHECK*/ + GetMSP3430Data (m, RD_DSP, 0x00, 0x18, &high, &low); + detect=(char)high; +#if __MSPDEBUG__ > 1 + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Stereo Detection Register: %d\n",detect); +#endif + if (detect>=((m->c_mode==MSPMODE_STEREO)?stereo_off:stereo_on)) { + m->c_mode=MSPMODE_STEREO; + matrix=0x20; /*STEREO*/ + fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1); + } + else if (detect<=((m->c_mode==MSPMODE_AB)?dual_off:dual_on)) { + m->c_mode=MSPMODE_AB; + switch (m->mode) { + case MSPMODE_STEREO_AB: matrix=0x20; break; + case MSPMODE_STEREO_B: matrix=0x10; break; + default: + case MSPMODE_A: matrix=0x00; break; + } + } + else { + m->c_mode=MSPMODE_MONO; + matrix=0x30; /*MONO*/ + } + break; + } /* end - case mode*/ + break; + } + + if (m->c_fmmatrix != fmmatrix) { + GetMSP3430Data (m, RD_DSP, 0x00, 0x0e, &high, &low); + SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, high, fmmatrix); + m->c_fmmatrix = fmmatrix; + } + + if ((m->c_matrix != matrix) || (m->c_source != source)) { + /*set chanel source and matrix for loudspeaker*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x08, source, matrix); + + m->c_matrix = matrix; + m->c_source = source; + } + + if ( ((m->c_format) & 0xF0) == MSPFORMAT_NICAM) + SetMSP3430Data (m, WR_DEM, 0x00, 0x21, 0, 1); + +#if __MSPDEBUG__ > 0 + char *msg; + switch (matrix) { + case 0x30: /*MONO*/ + msg="MONO"; + break; + case 0x00: /*LEFT*/ + msg="MONO/CHANNEL_1"; + break; + case 0x10: /*RIGHT*/ + msg="MONO/CHANNEL_2"; + break; + case 0x20: /*LEFT*/ + msg="STEREO"; + break; + default: + msg="unknown"; + break; + } + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Audio mode set to: %s\n",msg); +#endif +} + diff --git a/xorg-server/hw/xfree86/loader/loadmod.c b/xorg-server/hw/xfree86/loader/loadmod.c index a21f43d63..c697d74ed 100644 --- a/xorg-server/hw/xfree86/loader/loadmod.c +++ b/xorg-server/hw/xfree86/loader/loadmod.c @@ -437,14 +437,11 @@ FindModule(const char *module, const char *dirname, const char **subdirlist, PatternPtr patterns) { char buf[PATH_MAX + 1]; - char *dirpath = NULL; char *name = NULL; - int dirlen; const char **subdirs = NULL; const char **s; - dirpath = (char *)dirname; - if (strlen(dirpath) > PATH_MAX) + if (strlen(dirname) > PATH_MAX) return NULL; subdirs = InitSubdirs(subdirlist); @@ -452,17 +449,15 @@ FindModule(const char *module, const char *dirname, const char **subdirlist, return NULL; for (s = subdirs; *s; s++) { - if ((dirlen = strlen(dirpath) + strlen(*s)) > PATH_MAX) + if ((strlen(dirname) + strlen(*s)) > PATH_MAX) continue; - strcpy(buf, dirpath); + strcpy(buf, dirname); strcat(buf, *s); if ((name = FindModuleInSubdir(buf, module))) break; } FreeSubdirs(subdirs); - if (dirpath != dirname) - free(dirpath); return name; } diff --git a/xorg-server/hw/xfree86/modes/xf86Crtc.c b/xorg-server/hw/xfree86/modes/xf86Crtc.c index 953215196..da9db3460 100644 --- a/xorg-server/hw/xfree86/modes/xf86Crtc.c +++ b/xorg-server/hw/xfree86/modes/xf86Crtc.c @@ -481,7 +481,7 @@ static void xf86OutputSetMonitor (xf86OutputPtr output) { char *option_name; - char *monitor; + const char *monitor; if (!output->name) return; @@ -561,7 +561,7 @@ xf86OutputIgnored (xf86OutputPtr output) return xf86ReturnOptValBool (output->options, OPTION_IGNORE, FALSE); } -static char *direction[4] = { +static const char *direction[4] = { "normal", "left", "inverted", @@ -3063,13 +3063,13 @@ xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus) return mon; } -static char *_xf86ConnectorNames[] = { +static const char *_xf86ConnectorNames[] = { "None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite", "S-Video", "Component", "LFP", "Proprietary", "HDMI", "DisplayPort", }; -char * +const char * xf86ConnectorGetName(xf86ConnectorType connector) { return _xf86ConnectorNames[connector]; diff --git a/xorg-server/hw/xfree86/modes/xf86Crtc.h b/xorg-server/hw/xfree86/modes/xf86Crtc.h index 716499f8d..8d4a08938 100644 --- a/xorg-server/hw/xfree86/modes/xf86Crtc.h +++ b/xorg-server/hw/xfree86/modes/xf86Crtc.h @@ -900,7 +900,7 @@ xf86CrtcSetScreenSubpixelOrder (ScreenPtr pScreen); /* * Get a standard string name for a connector type */ -extern _X_EXPORT char * +extern _X_EXPORT const char * xf86ConnectorGetName(xf86ConnectorType connector); /* diff --git a/xorg-server/hw/xfree86/modes/xf86EdidModes.c b/xorg-server/hw/xfree86/modes/xf86EdidModes.c index 86065f869..0100d2a59 100644 --- a/xorg-server/hw/xfree86/modes/xf86EdidModes.c +++ b/xorg-server/hw/xfree86/modes/xf86EdidModes.c @@ -230,7 +230,7 @@ static Bool quirk_dvi_single_link(int scrnIndex, xf86MonPtr DDC) typedef struct { Bool (*detect) (int scrnIndex, xf86MonPtr DDC); ddc_quirk_t quirk; - char *description; + const char *description; } ddc_quirk_map_t; static const ddc_quirk_map_t ddc_quirks[] = { diff --git a/xorg-server/hw/xfree86/modes/xf86Modes.c b/xorg-server/hw/xfree86/modes/xf86Modes.c index dcd3a2805..49cc14992 100644 --- a/xorg-server/hw/xfree86/modes/xf86Modes.c +++ b/xorg-server/hw/xfree86/modes/xf86Modes.c @@ -272,7 +272,7 @@ xf86ModesEqual(const DisplayModeRec *pMode1, const DisplayModeRec *pMode2) } static void -add(char **p, char *new) +add(char **p, const char *new) { *p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2); strcat(*p, " "); @@ -599,7 +599,7 @@ xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, if (mode->status != MODE_OK) { if (verbose) { - char *type = ""; + const char *type = ""; if (mode->type & M_T_BUILTIN) type = "built-in "; else if (mode->type & M_T_DEFAULT) diff --git a/xorg-server/hw/xfree86/os-support/bsd/bsd_init.c b/xorg-server/hw/xfree86/os-support/bsd/bsd_init.c index b58d6a790..7079d62b4 100644 --- a/xorg-server/hw/xfree86/os-support/bsd/bsd_init.c +++ b/xorg-server/hw/xfree86/os-support/bsd/bsd_init.c @@ -446,7 +446,7 @@ xf86OpenSyscons() } close(fd); - sprintf(vtname, "/dev/ttyv%01x", xf86Info.vtno - 1); + snprintf(vtname, sizeof(vtname), "/dev/ttyv%01x", xf86Info.vtno - 1); if ((fd = open(vtname, SYSCONS_CONSOLE_MODE, 0)) < 0) { FatalError("xf86OpenSyscons: Cannot open %s (%s)", @@ -550,13 +550,13 @@ xf86OpenPcvt() } close(fd); - sprintf(vtname, "%s%01x", vtprefix, xf86Info.vtno - 1); + snprintf(vtname, sizeof(vtname), "%s%01x", vtprefix, xf86Info.vtno - 1); if ((fd = open(vtname, PCVT_CONSOLE_MODE, 0)) < 0) { ErrorF("xf86OpenPcvt: Cannot open %s (%s)", vtname, strerror(errno)); xf86Info.vtno = initialVT; - sprintf(vtname, "%s%01x", vtprefix, xf86Info.vtno - 1); + snprintf(vtname, sizeof(vtname), "%s%01x", vtprefix, xf86Info.vtno - 1); if ((fd = open(vtname, PCVT_CONSOLE_MODE, 0)) < 0) { FatalError("xf86OpenPcvt: Cannot open %s (%s)", vtname, strerror(errno)); @@ -602,9 +602,9 @@ xf86OpenWScons() /* XXX Is this ok? */ for (i = 0; i < 8; i++) { #if defined(__NetBSD__) - sprintf(ttyname, "/dev/ttyE%d", i); + snprintf(ttyname, sizeof(ttyname), "/dev/ttyE%d", i); #elif defined(__OpenBSD__) - sprintf(ttyname, "/dev/ttyC%x", i); + snprintf(ttyname, sizeof(ttyname), "/dev/ttyC%x", i); #endif if ((fd = open(ttyname, 2)) != -1) break; diff --git a/xorg-server/hw/xfree86/os-support/bus/Sbus.c b/xorg-server/hw/xfree86/os-support/bus/Sbus.c index 7c4888126..c02d2cd55 100644 --- a/xorg-server/hw/xfree86/os-support/bus/Sbus.c +++ b/xorg-server/hw/xfree86/os-support/bus/Sbus.c @@ -1,688 +1,688 @@ -/* - * SBUS and OpenPROM access functions. - * - * Copyright (C) 2000 Jakub Jelinek (jakub@redhat.com) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * JAKUB JELINEK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#ifdef sun -#include -#endif -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86_OSlib.h" - -#include "xf86sbusBus.h" -#include "xf86Sbus.h" - -int promRootNode; - -static int promFd = -1; -static int promCurrentNode; -static int promOpenCount = 0; -static int promP1275 = -1; -#define MAX_PROP 128 -#define MAX_VAL (4096-128-4) -static struct openpromio *promOpio; - -sbusDevicePtr *xf86SbusInfo = NULL; - -struct sbus_devtable sbusDeviceTable[] = { - { SBUS_DEVICE_BW2, FBTYPE_SUN2BW, "bwtwo", "sunbw2", "Sun Monochrome (bwtwo)" }, - { SBUS_DEVICE_CG2, FBTYPE_SUN2COLOR, "cgtwo", NULL, "Sun Color2 (cgtwo)" }, - { SBUS_DEVICE_CG3, FBTYPE_SUN3COLOR, "cgthree", "suncg3", "Sun Color3 (cgthree)" }, - { SBUS_DEVICE_CG4, FBTYPE_SUN4COLOR, "cgfour", NULL, "Sun Color4 (cgfour)" }, - { SBUS_DEVICE_CG6, FBTYPE_SUNFAST_COLOR, "cgsix", "suncg6", "Sun GX" }, - { SBUS_DEVICE_CG8, FBTYPE_MEMCOLOR, "cgeight", NULL, "Sun CG8/RasterOps" }, - { SBUS_DEVICE_CG12, FBTYPE_SUNGP3, "cgtwelve", NULL, "Sun GS (cgtwelve)" }, - { SBUS_DEVICE_CG14, FBTYPE_MDICOLOR, "cgfourteen", "suncg14", "Sun SX" }, - { SBUS_DEVICE_GT, FBTYPE_SUNGT, "gt", NULL, "Sun Graphics Tower" }, - { SBUS_DEVICE_MGX, -1, "mgx", NULL, "Quantum 3D MGXplus" }, - { SBUS_DEVICE_LEO, FBTYPE_SUNLEO, "leo", "sunleo", "Sun ZX or Turbo ZX" }, - { SBUS_DEVICE_TCX, FBTYPE_TCXCOLOR, "tcx", "suntcx", "Sun TCX" }, - { SBUS_DEVICE_FFB, FBTYPE_CREATOR, "ffb", "sunffb", "Sun FFB" }, - { SBUS_DEVICE_FFB, FBTYPE_CREATOR, "afb", "sunffb", "Sun Elite3D" }, - { 0, 0, NULL } -}; - -int -promGetSibling(int node) -{ - promOpio->oprom_size = sizeof(int); - - if (node == -1) return 0; - *(int *)promOpio->oprom_array = node; - if (ioctl(promFd, OPROMNEXT, promOpio) < 0) - return 0; - promCurrentNode = *(int *)promOpio->oprom_array; - return *(int *)promOpio->oprom_array; -} - -int -promGetChild(int node) -{ - promOpio->oprom_size = sizeof(int); - - if (!node || node == -1) return 0; - *(int *)promOpio->oprom_array = node; - if (ioctl(promFd, OPROMCHILD, promOpio) < 0) - return 0; - promCurrentNode = *(int *)promOpio->oprom_array; - return *(int *)promOpio->oprom_array; -} - -char * -promGetProperty(const char *prop, int *lenp) -{ - promOpio->oprom_size = MAX_VAL; - - strcpy(promOpio->oprom_array, prop); - if (ioctl(promFd, OPROMGETPROP, promOpio) < 0) - return 0; - if (lenp) *lenp = promOpio->oprom_size; - return promOpio->oprom_array; -} - -int -promGetBool(const char *prop) -{ - promOpio->oprom_size = 0; - - *(int *)promOpio->oprom_array = 0; - for (;;) { - promOpio->oprom_size = MAX_PROP; - if (ioctl(promFd, OPROMNXTPROP, promOpio) < 0) - return 0; - if (!promOpio->oprom_size) - return 0; - if (!strcmp(promOpio->oprom_array, prop)) - return 1; - } -} - -#define PROM_NODE_SIBLING 0x01 -#define PROM_NODE_PREF 0x02 -#define PROM_NODE_SBUS 0x04 -#define PROM_NODE_EBUS 0x08 -#define PROM_NODE_PCI 0x10 - -static int -promSetNode(sbusPromNodePtr pnode) -{ - int node; - - if (!pnode->node || pnode->node == -1) - return -1; - if (pnode->cookie[0] & PROM_NODE_SIBLING) - node = promGetSibling(pnode->cookie[1]); - else - node = promGetChild(pnode->cookie[1]); - if (pnode->node != node) - return -1; - return 0; -} - -static void -promIsP1275(void) -{ -#ifdef linux - FILE *f; - char buffer[1024]; - - if (promP1275 != -1) - return; - promP1275 = 0; - f = fopen("/proc/cpuinfo","r"); - if (!f) return; - while (fgets(buffer, 1024, f) != NULL) - if (!strncmp (buffer, "type", 4) && strstr (buffer, "sun4u")) { - promP1275 = 1; - break; - } - fclose(f); -#elif defined(sun) - struct utsname buffer; - - if ((uname(&buffer) >= 0) && !strcmp(buffer.machine, "sun4u")) - promP1275 = TRUE; - else - promP1275 = FALSE; -#elif defined(__FreeBSD__) - promP1275 = TRUE; -#else -#error Missing promIsP1275() function for this OS -#endif -} - -void -sparcPromClose(void) -{ - if (promOpenCount > 1) { - promOpenCount--; - return; - } - if (promFd != -1) { - close(promFd); - promFd = -1; - } - free(promOpio); - promOpio = NULL; - promOpenCount = 0; -} - -int -sparcPromInit(void) -{ - if (promOpenCount) { - promOpenCount++; - return 0; - } - promFd = open("/dev/openprom", O_RDONLY, 0); - if (promFd == -1) - return -1; - promOpio = (struct openpromio *)malloc(4096); - if (!promOpio) { - sparcPromClose(); - return -1; - } - promRootNode = promGetSibling(0); - if (!promRootNode) { - sparcPromClose(); - return -1; - } - promIsP1275(); - promOpenCount++; - - return 0; -} - -char * -sparcPromGetProperty(sbusPromNodePtr pnode, const char *prop, int *lenp) -{ - if (promSetNode(pnode)) - return NULL; - return promGetProperty(prop, lenp); -} - -int -sparcPromGetBool(sbusPromNodePtr pnode, const char *prop) -{ - if (promSetNode(pnode)) - return 0; - return promGetBool(prop); -} - -static char * -promWalkGetDriverName(int node, int oldnode) -{ - int nextnode; - int len; - char *prop; - int devId, i; - - prop = promGetProperty("device_type", &len); - if (prop && (len > 0)) do { - if (!strcmp(prop, "display")) { - prop = promGetProperty("name", &len); - if (!prop || len <= 0) - break; - while ((*prop >= 'A' && *prop <= 'Z') || *prop == ',') - prop++; - for (i = 0; sbusDeviceTable[i].devId; i++) - if (!strcmp(prop, sbusDeviceTable[i].promName)) - break; - devId = sbusDeviceTable[i].devId; - if (!devId) - break; - if (sbusDeviceTable[i].driverName) - return sbusDeviceTable[i].driverName; - } - } while (0); - - nextnode = promGetChild(node); - if (nextnode) { - char *name; - name = promWalkGetDriverName(nextnode, node); - if (name) - return name; - } - - nextnode = promGetSibling(node); - if (nextnode) - return promWalkGetDriverName(nextnode, node); - return NULL; -} - -char * -sparcDriverName(void) -{ - char *name; - - if (sparcPromInit() < 0) - return NULL; - promGetSibling(0); - name = promWalkGetDriverName(promRootNode, 0); - sparcPromClose(); - return name; -} - -static void -promWalkAssignNodes(int node, int oldnode, int flags, sbusDevicePtr *devicePtrs) -{ - int nextnode; - int len, sbus = flags & PROM_NODE_SBUS; - char *prop; - int devId, i, j; - sbusPromNode pNode, pNode2; - - prop = promGetProperty("device_type", &len); - if (prop && (len > 0)) do { - if (!strcmp(prop, "display")) { - prop = promGetProperty("name", &len); - if (!prop || len <= 0) - break; - while ((*prop >= 'A' && *prop <= 'Z') || *prop == ',') - prop++; - for (i = 0; sbusDeviceTable[i].devId; i++) - if (!strcmp(prop, sbusDeviceTable[i].promName)) - break; - devId = sbusDeviceTable[i].devId; - if (!devId) - break; - if (!sbus) { - if (devId == SBUS_DEVICE_FFB) { - /* - * All /SUNW,ffb outside of SBUS tree come before all - * /SUNW,afb outside of SBUS tree in Linux. - */ - if (!strcmp(prop, "afb")) - flags |= PROM_NODE_PREF; - } else if (devId != SBUS_DEVICE_CG14) - break; - } - for (i = 0; i < 32; i++) { - if (!devicePtrs[i] || devicePtrs[i]->devId != devId) - continue; - if (devicePtrs[i]->node.node) { - if ((devicePtrs[i]->node.cookie[0] & ~PROM_NODE_SIBLING) <= - (flags & ~PROM_NODE_SIBLING)) - continue; - for (j = i + 1, pNode = devicePtrs[i]->node; j < 32; j++) { - if (!devicePtrs[j] || devicePtrs[j]->devId != devId) - continue; - pNode2 = devicePtrs[j]->node; - devicePtrs[j]->node = pNode; - pNode = pNode2; - } - } - devicePtrs[i]->node.node = node; - devicePtrs[i]->node.cookie[0] = flags; - devicePtrs[i]->node.cookie[1] = oldnode; - break; - } - break; - } - } while (0); - - prop = promGetProperty("name", &len); - if (prop && len > 0) { - if (!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) - sbus = PROM_NODE_SBUS; - } - - nextnode = promGetChild(node); - if (nextnode) - promWalkAssignNodes(nextnode, node, sbus, devicePtrs); - - nextnode = promGetSibling(node); - if (nextnode) - promWalkAssignNodes(nextnode, node, PROM_NODE_SIBLING | sbus, devicePtrs); -} - -void -sparcPromAssignNodes(void) -{ - sbusDevicePtr psdp, *psdpp; - int n, holes = 0, i, j; - FILE *f; - sbusDevicePtr devicePtrs[32]; - - memset(devicePtrs, 0, sizeof(devicePtrs)); - for (psdpp = xf86SbusInfo, n = 0; (psdp = *psdpp); psdpp++, n++) { - if (psdp->fbNum != n) - holes = 1; - devicePtrs[psdp->fbNum] = psdp; - } - if (holes && (f = fopen("/proc/fb", "r")) != NULL) { - /* We could not open one of fb devices, check /proc/fb to see what - * were the types of the cards missed. */ - char buffer[64]; - int fbNum, devId; - static struct { - int devId; - char *prefix; - } procFbPrefixes[] = { - { SBUS_DEVICE_BW2, "BWtwo" }, - { SBUS_DEVICE_CG14, "CGfourteen" }, - { SBUS_DEVICE_CG6, "CGsix" }, - { SBUS_DEVICE_CG3, "CGthree" }, - { SBUS_DEVICE_FFB, "Creator" }, - { SBUS_DEVICE_FFB, "Elite 3D" }, - { SBUS_DEVICE_LEO, "Leo" }, - { SBUS_DEVICE_TCX, "TCX" }, - { 0, NULL }, - }; - - while (fscanf(f, "%d %63s\n", &fbNum, buffer) == 2) { - for (i = 0; procFbPrefixes[i].devId; i++) - if (! strncmp(procFbPrefixes[i].prefix, buffer, - strlen(procFbPrefixes[i].prefix))) - break; - devId = procFbPrefixes[i].devId; - if (! devId) continue; - if (devicePtrs[fbNum]) { - if (devicePtrs[fbNum]->devId != devId) - xf86ErrorF("Inconsistent /proc/fb with FBIOGATTR\n"); - } else if (!devicePtrs[fbNum]) { - devicePtrs[fbNum] = psdp = xnfcalloc(sizeof (sbusDevice), 1); - psdp->devId = devId; - psdp->fbNum = fbNum; - psdp->fd = -2; - } - } - fclose(f); - } - promGetSibling(0); - promWalkAssignNodes(promRootNode, 0, PROM_NODE_PREF, devicePtrs); - for (i = 0, j = 0; i < 32; i++) - if (devicePtrs[i] && devicePtrs[i]->fbNum == -1) - j++; - xf86SbusInfo = xnfrealloc(xf86SbusInfo, sizeof(psdp) * (n + j + 1)); - for (i = 0, psdpp = xf86SbusInfo; i < 32; i++) - if (devicePtrs[i]) { - if (devicePtrs[i]->fbNum == -1) { - memmove(psdpp + 1, psdpp, sizeof(psdpp) * (n + 1)); - *psdpp = devicePtrs[i]; - } else - n--; - } -} - -static char * -promGetReg(int type) -{ - char *prop; - int len; - static char regstr[40]; - - regstr[0] = 0; - prop = promGetProperty("reg", &len); - if (prop && len >= 4) { - unsigned int *reg = (unsigned int *)prop; - if (!promP1275 || (type == PROM_NODE_SBUS) || (type == PROM_NODE_EBUS)) - sprintf (regstr, "@%x,%x", reg[0], reg[1]); - else if (type == PROM_NODE_PCI) { - if ((reg[0] >> 8) & 7) - sprintf (regstr, "@%x,%x", (reg[0] >> 11) & 0x1f, (reg[0] >> 8) & 7); - else - sprintf (regstr, "@%x", (reg[0] >> 11) & 0x1f); - } else if (len == 4) - sprintf (regstr, "@%x", reg[0]); - else { - unsigned int regs[2]; - - /* Things get more complicated on UPA. If upa-portid exists, - then address is @upa-portid,second-int-in-reg, otherwise - it is @first-int-in-reg/16,second-int-in-reg (well, probably - upa-portid always exists, but just to be safe). */ - memcpy (regs, reg, sizeof(regs)); - prop = promGetProperty("upa-portid", &len); - if (prop && len == 4) { - reg = (unsigned int *)prop; - sprintf (regstr, "@%x,%x", reg[0], regs[1]); - } else - sprintf (regstr, "@%x,%x", regs[0] >> 4, regs[1]); - } - } - return regstr; -} - -static int -promWalkNode2Pathname(char *path, int parent, int node, int searchNode, int type) -{ - int nextnode; - int len, ntype = type; - char *prop, *p; - - prop = promGetProperty("name", &len); - *path = '/'; - if (!prop || len <= 0) - return 0; - if ((!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) && !type) - ntype = PROM_NODE_SBUS; - else if (!strcmp(prop, "ebus") && type == PROM_NODE_PCI) - ntype = PROM_NODE_EBUS; - else if (!strcmp(prop, "pci") && !type) - ntype = PROM_NODE_PCI; - strcpy (path + 1, prop); - p = promGetReg(type); - if (*p) - strcat (path, p); - if (node == searchNode) - return 1; - nextnode = promGetChild(node); - if (nextnode && - promWalkNode2Pathname(strchr(path, 0), node, nextnode, searchNode, ntype)) - return 1; - nextnode = promGetSibling(node); - if (nextnode && - promWalkNode2Pathname(path, parent, nextnode, searchNode, type)) - return 1; - return 0; -} - -char * -sparcPromNode2Pathname(sbusPromNodePtr pnode) -{ - char *ret; - - if (!pnode->node) return NULL; - ret = malloc(4096); - if (!ret) return NULL; - if (promWalkNode2Pathname(ret, promRootNode, promGetChild(promRootNode), pnode->node, 0)) - return ret; - free(ret); - return NULL; -} - -static int -promWalkPathname2Node(char *name, char *regstr, int parent, int type) -{ - int len, node, ret; - char *prop, *p; - - for (;;) { - prop = promGetProperty("name", &len); - if (!prop || len <= 0) - return 0; - if ((!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) && !type) - type = PROM_NODE_SBUS; - else if (!strcmp(prop, "ebus") && type == PROM_NODE_PCI) - type = PROM_NODE_EBUS; - else if (!strcmp(prop, "pci") && !type) - type = PROM_NODE_PCI; - for (node = promGetChild(parent); node; node = promGetSibling(node)) { - prop = promGetProperty("name", &len); - if (!prop || len <= 0) - continue; - if (*name && strcmp(name, prop)) - continue; - if (*regstr) { - p = promGetReg(type); - if (! *p || strcmp(p + 1, regstr)) - continue; - } - break; - } - if (!node) { - for (node = promGetChild(parent); node; node = promGetSibling(node)) { - ret = promWalkPathname2Node(name, regstr, node, type); - if (ret) return ret; - } - return 0; - } - name = strchr(regstr, 0) + 1; - if (! *name) - return node; - p = strchr(name, '/'); - if (p) - *p = 0; - else - p = strchr(name, 0); - regstr = strchr(name, '@'); - if (regstr) - *regstr++ = 0; - else - regstr = p; - if (name == regstr) - return 0; - parent = node; - } -} - -int -sparcPromPathname2Node(const char *pathName) -{ - int i; - char *name, *regstr, *p; - - i = strlen(pathName); - name = malloc(i + 2); - if (! name) return 0; - strcpy (name, pathName); - name [i + 1] = 0; - if (name[0] != '/') - return 0; - p = strchr(name + 1, '/'); - if (p) - *p = 0; - else - p = strchr(name, 0); - regstr = strchr(name, '@'); - if (regstr) - *regstr++ = 0; - else - regstr = p; - if (name + 1 == regstr) - return 0; - promGetSibling(0); - i = promWalkPathname2Node(name + 1, regstr, promRootNode, 0); - free(name); - return i; -} - -pointer -xf86MapSbusMem(sbusDevicePtr psdp, unsigned long offset, unsigned long size) -{ - pointer ret; - unsigned long pagemask = getpagesize() - 1; - unsigned long off = offset & ~pagemask; - unsigned long len = ((offset + size + pagemask) & ~pagemask) - off; - - if (psdp->fd == -1) { - psdp->fd = open(psdp->device, O_RDWR); - if (psdp->fd == -1) - return NULL; - } else if (psdp->fd < 0) - return NULL; - - ret = (pointer) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, - psdp->fd, off); - if (ret == (pointer) -1) { - ret = (pointer) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, - psdp->fd, off); - } - if (ret == (pointer) -1) - return NULL; - - return (char *)ret + (offset - off); -} - -void -xf86UnmapSbusMem(sbusDevicePtr psdp, pointer addr, unsigned long size) -{ - unsigned long mask = getpagesize() - 1; - unsigned long base = (unsigned long)addr & ~mask; - unsigned long len = (((unsigned long)addr + size + mask) & ~mask) - base; - - munmap ((pointer)base, len); -} - -/* Tell OS that we are driving the HW cursor ourselves. */ -void -xf86SbusHideOsHwCursor(sbusDevicePtr psdp) -{ - struct fbcursor fbcursor; - unsigned char zeros[8]; - - memset(&fbcursor, 0, sizeof(fbcursor)); - memset(&zeros, 0, sizeof(zeros)); - fbcursor.cmap.count = 2; - fbcursor.cmap.red = zeros; - fbcursor.cmap.green = zeros; - fbcursor.cmap.blue = zeros; - fbcursor.image = (char *)zeros; - fbcursor.mask = (char *)zeros; - fbcursor.size.x = 32; - fbcursor.size.y = 1; - fbcursor.set = FB_CUR_SETALL; - ioctl(psdp->fd, FBIOSCURSOR, &fbcursor); -} - -/* Set HW cursor colormap. */ -void -xf86SbusSetOsHwCursorCmap(sbusDevicePtr psdp, int bg, int fg) -{ - struct fbcursor fbcursor; - unsigned char red[2], green[2], blue[2]; - - memset(&fbcursor, 0, sizeof(fbcursor)); - red[0] = bg >> 16; - green[0] = bg >> 8; - blue[0] = bg; - red[1] = fg >> 16; - green[1] = fg >> 8; - blue[1] = fg; - fbcursor.cmap.count = 2; - fbcursor.cmap.red = red; - fbcursor.cmap.green = green; - fbcursor.cmap.blue = blue; - fbcursor.set = FB_CUR_SETCMAP; - ioctl(psdp->fd, FBIOSCURSOR, &fbcursor); -} +/* + * SBUS and OpenPROM access functions. + * + * Copyright (C) 2000 Jakub Jelinek (jakub@redhat.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * JAKUB JELINEK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#ifdef sun +#include +#endif +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" + +#include "xf86sbusBus.h" +#include "xf86Sbus.h" + +int promRootNode; + +static int promFd = -1; +static int promCurrentNode; +static int promOpenCount = 0; +static int promP1275 = -1; +#define MAX_PROP 128 +#define MAX_VAL (4096-128-4) +static struct openpromio *promOpio; + +sbusDevicePtr *xf86SbusInfo = NULL; + +struct sbus_devtable sbusDeviceTable[] = { + { SBUS_DEVICE_BW2, FBTYPE_SUN2BW, "bwtwo", "sunbw2", "Sun Monochrome (bwtwo)" }, + { SBUS_DEVICE_CG2, FBTYPE_SUN2COLOR, "cgtwo", NULL, "Sun Color2 (cgtwo)" }, + { SBUS_DEVICE_CG3, FBTYPE_SUN3COLOR, "cgthree", "suncg3", "Sun Color3 (cgthree)" }, + { SBUS_DEVICE_CG4, FBTYPE_SUN4COLOR, "cgfour", NULL, "Sun Color4 (cgfour)" }, + { SBUS_DEVICE_CG6, FBTYPE_SUNFAST_COLOR, "cgsix", "suncg6", "Sun GX" }, + { SBUS_DEVICE_CG8, FBTYPE_MEMCOLOR, "cgeight", NULL, "Sun CG8/RasterOps" }, + { SBUS_DEVICE_CG12, FBTYPE_SUNGP3, "cgtwelve", NULL, "Sun GS (cgtwelve)" }, + { SBUS_DEVICE_CG14, FBTYPE_MDICOLOR, "cgfourteen", "suncg14", "Sun SX" }, + { SBUS_DEVICE_GT, FBTYPE_SUNGT, "gt", NULL, "Sun Graphics Tower" }, + { SBUS_DEVICE_MGX, -1, "mgx", NULL, "Quantum 3D MGXplus" }, + { SBUS_DEVICE_LEO, FBTYPE_SUNLEO, "leo", "sunleo", "Sun ZX or Turbo ZX" }, + { SBUS_DEVICE_TCX, FBTYPE_TCXCOLOR, "tcx", "suntcx", "Sun TCX" }, + { SBUS_DEVICE_FFB, FBTYPE_CREATOR, "ffb", "sunffb", "Sun FFB" }, + { SBUS_DEVICE_FFB, FBTYPE_CREATOR, "afb", "sunffb", "Sun Elite3D" }, + { 0, 0, NULL } +}; + +int +promGetSibling(int node) +{ + promOpio->oprom_size = sizeof(int); + + if (node == -1) return 0; + *(int *)promOpio->oprom_array = node; + if (ioctl(promFd, OPROMNEXT, promOpio) < 0) + return 0; + promCurrentNode = *(int *)promOpio->oprom_array; + return *(int *)promOpio->oprom_array; +} + +int +promGetChild(int node) +{ + promOpio->oprom_size = sizeof(int); + + if (!node || node == -1) return 0; + *(int *)promOpio->oprom_array = node; + if (ioctl(promFd, OPROMCHILD, promOpio) < 0) + return 0; + promCurrentNode = *(int *)promOpio->oprom_array; + return *(int *)promOpio->oprom_array; +} + +char * +promGetProperty(const char *prop, int *lenp) +{ + promOpio->oprom_size = MAX_VAL; + + strcpy(promOpio->oprom_array, prop); + if (ioctl(promFd, OPROMGETPROP, promOpio) < 0) + return 0; + if (lenp) *lenp = promOpio->oprom_size; + return promOpio->oprom_array; +} + +int +promGetBool(const char *prop) +{ + promOpio->oprom_size = 0; + + *(int *)promOpio->oprom_array = 0; + for (;;) { + promOpio->oprom_size = MAX_PROP; + if (ioctl(promFd, OPROMNXTPROP, promOpio) < 0) + return 0; + if (!promOpio->oprom_size) + return 0; + if (!strcmp(promOpio->oprom_array, prop)) + return 1; + } +} + +#define PROM_NODE_SIBLING 0x01 +#define PROM_NODE_PREF 0x02 +#define PROM_NODE_SBUS 0x04 +#define PROM_NODE_EBUS 0x08 +#define PROM_NODE_PCI 0x10 + +static int +promSetNode(sbusPromNodePtr pnode) +{ + int node; + + if (!pnode->node || pnode->node == -1) + return -1; + if (pnode->cookie[0] & PROM_NODE_SIBLING) + node = promGetSibling(pnode->cookie[1]); + else + node = promGetChild(pnode->cookie[1]); + if (pnode->node != node) + return -1; + return 0; +} + +static void +promIsP1275(void) +{ +#ifdef linux + FILE *f; + char buffer[1024]; + + if (promP1275 != -1) + return; + promP1275 = 0; + f = fopen("/proc/cpuinfo","r"); + if (!f) return; + while (fgets(buffer, 1024, f) != NULL) + if (!strncmp (buffer, "type", 4) && strstr (buffer, "sun4u")) { + promP1275 = 1; + break; + } + fclose(f); +#elif defined(sun) + struct utsname buffer; + + if ((uname(&buffer) >= 0) && !strcmp(buffer.machine, "sun4u")) + promP1275 = TRUE; + else + promP1275 = FALSE; +#elif defined(__FreeBSD__) + promP1275 = TRUE; +#else +#error Missing promIsP1275() function for this OS +#endif +} + +void +sparcPromClose(void) +{ + if (promOpenCount > 1) { + promOpenCount--; + return; + } + if (promFd != -1) { + close(promFd); + promFd = -1; + } + free(promOpio); + promOpio = NULL; + promOpenCount = 0; +} + +int +sparcPromInit(void) +{ + if (promOpenCount) { + promOpenCount++; + return 0; + } + promFd = open("/dev/openprom", O_RDONLY, 0); + if (promFd == -1) + return -1; + promOpio = (struct openpromio *)malloc(4096); + if (!promOpio) { + sparcPromClose(); + return -1; + } + promRootNode = promGetSibling(0); + if (!promRootNode) { + sparcPromClose(); + return -1; + } + promIsP1275(); + promOpenCount++; + + return 0; +} + +char * +sparcPromGetProperty(sbusPromNodePtr pnode, const char *prop, int *lenp) +{ + if (promSetNode(pnode)) + return NULL; + return promGetProperty(prop, lenp); +} + +int +sparcPromGetBool(sbusPromNodePtr pnode, const char *prop) +{ + if (promSetNode(pnode)) + return 0; + return promGetBool(prop); +} + +static char * +promWalkGetDriverName(int node, int oldnode) +{ + int nextnode; + int len; + char *prop; + int devId, i; + + prop = promGetProperty("device_type", &len); + if (prop && (len > 0)) do { + if (!strcmp(prop, "display")) { + prop = promGetProperty("name", &len); + if (!prop || len <= 0) + break; + while ((*prop >= 'A' && *prop <= 'Z') || *prop == ',') + prop++; + for (i = 0; sbusDeviceTable[i].devId; i++) + if (!strcmp(prop, sbusDeviceTable[i].promName)) + break; + devId = sbusDeviceTable[i].devId; + if (!devId) + break; + if (sbusDeviceTable[i].driverName) + return sbusDeviceTable[i].driverName; + } + } while (0); + + nextnode = promGetChild(node); + if (nextnode) { + char *name; + name = promWalkGetDriverName(nextnode, node); + if (name) + return name; + } + + nextnode = promGetSibling(node); + if (nextnode) + return promWalkGetDriverName(nextnode, node); + return NULL; +} + +char * +sparcDriverName(void) +{ + char *name; + + if (sparcPromInit() < 0) + return NULL; + promGetSibling(0); + name = promWalkGetDriverName(promRootNode, 0); + sparcPromClose(); + return name; +} + +static void +promWalkAssignNodes(int node, int oldnode, int flags, sbusDevicePtr *devicePtrs) +{ + int nextnode; + int len, sbus = flags & PROM_NODE_SBUS; + char *prop; + int devId, i, j; + sbusPromNode pNode, pNode2; + + prop = promGetProperty("device_type", &len); + if (prop && (len > 0)) do { + if (!strcmp(prop, "display")) { + prop = promGetProperty("name", &len); + if (!prop || len <= 0) + break; + while ((*prop >= 'A' && *prop <= 'Z') || *prop == ',') + prop++; + for (i = 0; sbusDeviceTable[i].devId; i++) + if (!strcmp(prop, sbusDeviceTable[i].promName)) + break; + devId = sbusDeviceTable[i].devId; + if (!devId) + break; + if (!sbus) { + if (devId == SBUS_DEVICE_FFB) { + /* + * All /SUNW,ffb outside of SBUS tree come before all + * /SUNW,afb outside of SBUS tree in Linux. + */ + if (!strcmp(prop, "afb")) + flags |= PROM_NODE_PREF; + } else if (devId != SBUS_DEVICE_CG14) + break; + } + for (i = 0; i < 32; i++) { + if (!devicePtrs[i] || devicePtrs[i]->devId != devId) + continue; + if (devicePtrs[i]->node.node) { + if ((devicePtrs[i]->node.cookie[0] & ~PROM_NODE_SIBLING) <= + (flags & ~PROM_NODE_SIBLING)) + continue; + for (j = i + 1, pNode = devicePtrs[i]->node; j < 32; j++) { + if (!devicePtrs[j] || devicePtrs[j]->devId != devId) + continue; + pNode2 = devicePtrs[j]->node; + devicePtrs[j]->node = pNode; + pNode = pNode2; + } + } + devicePtrs[i]->node.node = node; + devicePtrs[i]->node.cookie[0] = flags; + devicePtrs[i]->node.cookie[1] = oldnode; + break; + } + break; + } + } while (0); + + prop = promGetProperty("name", &len); + if (prop && len > 0) { + if (!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) + sbus = PROM_NODE_SBUS; + } + + nextnode = promGetChild(node); + if (nextnode) + promWalkAssignNodes(nextnode, node, sbus, devicePtrs); + + nextnode = promGetSibling(node); + if (nextnode) + promWalkAssignNodes(nextnode, node, PROM_NODE_SIBLING | sbus, devicePtrs); +} + +void +sparcPromAssignNodes(void) +{ + sbusDevicePtr psdp, *psdpp; + int n, holes = 0, i, j; + FILE *f; + sbusDevicePtr devicePtrs[32]; + + memset(devicePtrs, 0, sizeof(devicePtrs)); + for (psdpp = xf86SbusInfo, n = 0; (psdp = *psdpp); psdpp++, n++) { + if (psdp->fbNum != n) + holes = 1; + devicePtrs[psdp->fbNum] = psdp; + } + if (holes && (f = fopen("/proc/fb", "r")) != NULL) { + /* We could not open one of fb devices, check /proc/fb to see what + * were the types of the cards missed. */ + char buffer[64]; + int fbNum, devId; + static struct { + int devId; + char *prefix; + } procFbPrefixes[] = { + { SBUS_DEVICE_BW2, "BWtwo" }, + { SBUS_DEVICE_CG14, "CGfourteen" }, + { SBUS_DEVICE_CG6, "CGsix" }, + { SBUS_DEVICE_CG3, "CGthree" }, + { SBUS_DEVICE_FFB, "Creator" }, + { SBUS_DEVICE_FFB, "Elite 3D" }, + { SBUS_DEVICE_LEO, "Leo" }, + { SBUS_DEVICE_TCX, "TCX" }, + { 0, NULL }, + }; + + while (fscanf(f, "%d %63s\n", &fbNum, buffer) == 2) { + for (i = 0; procFbPrefixes[i].devId; i++) + if (! strncmp(procFbPrefixes[i].prefix, buffer, + strlen(procFbPrefixes[i].prefix))) + break; + devId = procFbPrefixes[i].devId; + if (! devId) continue; + if (devicePtrs[fbNum]) { + if (devicePtrs[fbNum]->devId != devId) + xf86ErrorF("Inconsistent /proc/fb with FBIOGATTR\n"); + } else if (!devicePtrs[fbNum]) { + devicePtrs[fbNum] = psdp = xnfcalloc(sizeof (sbusDevice), 1); + psdp->devId = devId; + psdp->fbNum = fbNum; + psdp->fd = -2; + } + } + fclose(f); + } + promGetSibling(0); + promWalkAssignNodes(promRootNode, 0, PROM_NODE_PREF, devicePtrs); + for (i = 0, j = 0; i < 32; i++) + if (devicePtrs[i] && devicePtrs[i]->fbNum == -1) + j++; + xf86SbusInfo = xnfrealloc(xf86SbusInfo, sizeof(psdp) * (n + j + 1)); + for (i = 0, psdpp = xf86SbusInfo; i < 32; i++) + if (devicePtrs[i]) { + if (devicePtrs[i]->fbNum == -1) { + memmove(psdpp + 1, psdpp, sizeof(psdpp) * (n + 1)); + *psdpp = devicePtrs[i]; + } else + n--; + } +} + +static char * +promGetReg(int type) +{ + char *prop; + int len; + static char regstr[40]; + + regstr[0] = 0; + prop = promGetProperty("reg", &len); + if (prop && len >= 4) { + unsigned int *reg = (unsigned int *)prop; + if (!promP1275 || (type == PROM_NODE_SBUS) || (type == PROM_NODE_EBUS)) + snprintf (regstr, sizeof(regstr), "@%x,%x", reg[0], reg[1]); + else if (type == PROM_NODE_PCI) { + if ((reg[0] >> 8) & 7) + snprintf (regstr, sizeof(regstr), "@%x,%x", (reg[0] >> 11) & 0x1f, (reg[0] >> 8) & 7); + else + snprintf (regstr, sizeof(regstr), "@%x", (reg[0] >> 11) & 0x1f); + } else if (len == 4) + snprintf (regstr, sizeof(regstr), "@%x", reg[0]); + else { + unsigned int regs[2]; + + /* Things get more complicated on UPA. If upa-portid exists, + then address is @upa-portid,second-int-in-reg, otherwise + it is @first-int-in-reg/16,second-int-in-reg (well, probably + upa-portid always exists, but just to be safe). */ + memcpy (regs, reg, sizeof(regs)); + prop = promGetProperty("upa-portid", &len); + if (prop && len == 4) { + reg = (unsigned int *)prop; + snprintf (regstr, sizeof(regstr), "@%x,%x", reg[0], regs[1]); + } else + snprintf (regstr, sizeof(regstr), "@%x,%x", regs[0] >> 4, regs[1]); + } + } + return regstr; +} + +static int +promWalkNode2Pathname(char *path, int parent, int node, int searchNode, int type) +{ + int nextnode; + int len, ntype = type; + char *prop, *p; + + prop = promGetProperty("name", &len); + *path = '/'; + if (!prop || len <= 0) + return 0; + if ((!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) && !type) + ntype = PROM_NODE_SBUS; + else if (!strcmp(prop, "ebus") && type == PROM_NODE_PCI) + ntype = PROM_NODE_EBUS; + else if (!strcmp(prop, "pci") && !type) + ntype = PROM_NODE_PCI; + strcpy (path + 1, prop); + p = promGetReg(type); + if (*p) + strcat (path, p); + if (node == searchNode) + return 1; + nextnode = promGetChild(node); + if (nextnode && + promWalkNode2Pathname(strchr(path, 0), node, nextnode, searchNode, ntype)) + return 1; + nextnode = promGetSibling(node); + if (nextnode && + promWalkNode2Pathname(path, parent, nextnode, searchNode, type)) + return 1; + return 0; +} + +char * +sparcPromNode2Pathname(sbusPromNodePtr pnode) +{ + char *ret; + + if (!pnode->node) return NULL; + ret = malloc(4096); + if (!ret) return NULL; + if (promWalkNode2Pathname(ret, promRootNode, promGetChild(promRootNode), pnode->node, 0)) + return ret; + free(ret); + return NULL; +} + +static int +promWalkPathname2Node(char *name, char *regstr, int parent, int type) +{ + int len, node, ret; + char *prop, *p; + + for (;;) { + prop = promGetProperty("name", &len); + if (!prop || len <= 0) + return 0; + if ((!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) && !type) + type = PROM_NODE_SBUS; + else if (!strcmp(prop, "ebus") && type == PROM_NODE_PCI) + type = PROM_NODE_EBUS; + else if (!strcmp(prop, "pci") && !type) + type = PROM_NODE_PCI; + for (node = promGetChild(parent); node; node = promGetSibling(node)) { + prop = promGetProperty("name", &len); + if (!prop || len <= 0) + continue; + if (*name && strcmp(name, prop)) + continue; + if (*regstr) { + p = promGetReg(type); + if (! *p || strcmp(p + 1, regstr)) + continue; + } + break; + } + if (!node) { + for (node = promGetChild(parent); node; node = promGetSibling(node)) { + ret = promWalkPathname2Node(name, regstr, node, type); + if (ret) return ret; + } + return 0; + } + name = strchr(regstr, 0) + 1; + if (! *name) + return node; + p = strchr(name, '/'); + if (p) + *p = 0; + else + p = strchr(name, 0); + regstr = strchr(name, '@'); + if (regstr) + *regstr++ = 0; + else + regstr = p; + if (name == regstr) + return 0; + parent = node; + } +} + +int +sparcPromPathname2Node(const char *pathName) +{ + int i; + char *name, *regstr, *p; + + i = strlen(pathName); + name = malloc(i + 2); + if (! name) return 0; + strcpy (name, pathName); + name [i + 1] = 0; + if (name[0] != '/') + return 0; + p = strchr(name + 1, '/'); + if (p) + *p = 0; + else + p = strchr(name, 0); + regstr = strchr(name, '@'); + if (regstr) + *regstr++ = 0; + else + regstr = p; + if (name + 1 == regstr) + return 0; + promGetSibling(0); + i = promWalkPathname2Node(name + 1, regstr, promRootNode, 0); + free(name); + return i; +} + +pointer +xf86MapSbusMem(sbusDevicePtr psdp, unsigned long offset, unsigned long size) +{ + pointer ret; + unsigned long pagemask = getpagesize() - 1; + unsigned long off = offset & ~pagemask; + unsigned long len = ((offset + size + pagemask) & ~pagemask) - off; + + if (psdp->fd == -1) { + psdp->fd = open(psdp->device, O_RDWR); + if (psdp->fd == -1) + return NULL; + } else if (psdp->fd < 0) + return NULL; + + ret = (pointer) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, + psdp->fd, off); + if (ret == (pointer) -1) { + ret = (pointer) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, + psdp->fd, off); + } + if (ret == (pointer) -1) + return NULL; + + return (char *)ret + (offset - off); +} + +void +xf86UnmapSbusMem(sbusDevicePtr psdp, pointer addr, unsigned long size) +{ + unsigned long mask = getpagesize() - 1; + unsigned long base = (unsigned long)addr & ~mask; + unsigned long len = (((unsigned long)addr + size + mask) & ~mask) - base; + + munmap ((pointer)base, len); +} + +/* Tell OS that we are driving the HW cursor ourselves. */ +void +xf86SbusHideOsHwCursor(sbusDevicePtr psdp) +{ + struct fbcursor fbcursor; + unsigned char zeros[8]; + + memset(&fbcursor, 0, sizeof(fbcursor)); + memset(&zeros, 0, sizeof(zeros)); + fbcursor.cmap.count = 2; + fbcursor.cmap.red = zeros; + fbcursor.cmap.green = zeros; + fbcursor.cmap.blue = zeros; + fbcursor.image = (char *)zeros; + fbcursor.mask = (char *)zeros; + fbcursor.size.x = 32; + fbcursor.size.y = 1; + fbcursor.set = FB_CUR_SETALL; + ioctl(psdp->fd, FBIOSCURSOR, &fbcursor); +} + +/* Set HW cursor colormap. */ +void +xf86SbusSetOsHwCursorCmap(sbusDevicePtr psdp, int bg, int fg) +{ + struct fbcursor fbcursor; + unsigned char red[2], green[2], blue[2]; + + memset(&fbcursor, 0, sizeof(fbcursor)); + red[0] = bg >> 16; + green[0] = bg >> 8; + blue[0] = bg; + red[1] = fg >> 16; + green[1] = fg >> 8; + blue[1] = fg; + fbcursor.cmap.count = 2; + fbcursor.cmap.red = red; + fbcursor.cmap.green = green; + fbcursor.cmap.blue = blue; + fbcursor.set = FB_CUR_SETCMAP; + ioctl(psdp->fd, FBIOSCURSOR, &fbcursor); +} diff --git a/xorg-server/hw/xfree86/os-support/linux/lnx_init.c b/xorg-server/hw/xfree86/os-support/linux/lnx_init.c index f18271f38..5f3e3a9fb 100644 --- a/xorg-server/hw/xfree86/os-support/linux/lnx_init.c +++ b/xorg-server/hw/xfree86/os-support/linux/lnx_init.c @@ -146,7 +146,7 @@ xf86OpenConsole(void) i=0; while (vcs[i] != NULL) { - sprintf(vtname, vcs[i], xf86Info.vtno); /* /dev/tty1-64 */ + snprintf(vtname, sizeof(vtname), vcs[i], xf86Info.vtno); /* /dev/tty1-64 */ if ((xf86Info.consoleFd = open(vtname, O_RDWR|O_NDELAY, 0)) >= 0) break; i++; diff --git a/xorg-server/hw/xfree86/os-support/solaris/sun_agp.c b/xorg-server/hw/xfree86/os-support/solaris/sun_agp.c index 0331ac1c5..8c4e9f5c1 100644 --- a/xorg-server/hw/xfree86/os-support/solaris/sun_agp.c +++ b/xorg-server/hw/xfree86/os-support/solaris/sun_agp.c @@ -233,7 +233,7 @@ xf86DeallocateGARTMemory(int screenNum, int key) if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) return FALSE; - if (ioctl(gartFd, AGPIOC_DEALLOCATE, (int *)key) != 0) { + if (ioctl(gartFd, AGPIOC_DEALLOCATE, (int *)(uintptr_t)key) != 0) { xf86DrvMsg(screenNum, X_WARNING, "xf86DeAllocateGARTMemory: " "deallocation of gart memory with key %d failed\n" "\t(%s)\n", key, strerror(errno)); diff --git a/xorg-server/hw/xfree86/parser/Flags.c b/xorg-server/hw/xfree86/parser/Flags.c index f0a61707b..87fd3edf6 100644 --- a/xorg-server/hw/xfree86/parser/Flags.c +++ b/xorg-server/hw/xfree86/parser/Flags.c @@ -330,7 +330,7 @@ xf86findOption (XF86OptionPtr list, const char *name) * returned. If the option is not found, a NULL is returned. */ -char * +const char * xf86findOptionValue (XF86OptionPtr list, const char *name) { XF86OptionPtr p = xf86findOption (list, name); diff --git a/xorg-server/hw/xfree86/parser/InputClass.c b/xorg-server/hw/xfree86/parser/InputClass.c index 3f801700e..2cdc9125a 100644 --- a/xorg-server/hw/xfree86/parser/InputClass.c +++ b/xorg-server/hw/xfree86/parser/InputClass.c @@ -128,60 +128,70 @@ xf86parseInputClassSection(void) Error(QUOTE_MSG, "MatchProduct"); add_group_entry(&ptr->match_product, xstrtokenize(val.str, TOKEN_SEP)); + free(val.str); break; case MATCH_VENDOR: if (xf86getSubToken(&(ptr->comment)) != STRING) Error(QUOTE_MSG, "MatchVendor"); add_group_entry(&ptr->match_vendor, xstrtokenize(val.str, TOKEN_SEP)); + free(val.str); break; case MATCH_DEVICE_PATH: if (xf86getSubToken(&(ptr->comment)) != STRING) Error(QUOTE_MSG, "MatchDevicePath"); add_group_entry(&ptr->match_device, xstrtokenize(val.str, TOKEN_SEP)); + free(val.str); break; case MATCH_OS: if (xf86getSubToken(&(ptr->comment)) != STRING) Error(QUOTE_MSG, "MatchOS"); add_group_entry(&ptr->match_os, xstrtokenize(val.str, TOKEN_SEP)); + free(val.str); break; case MATCH_PNPID: if (xf86getSubToken(&(ptr->comment)) != STRING) Error(QUOTE_MSG, "MatchPnPID"); add_group_entry(&ptr->match_pnpid, xstrtokenize(val.str, TOKEN_SEP)); + free(val.str); break; case MATCH_USBID: if (xf86getSubToken(&(ptr->comment)) != STRING) Error(QUOTE_MSG, "MatchUSBID"); add_group_entry(&ptr->match_usbid, xstrtokenize(val.str, TOKEN_SEP)); + free(val.str); break; case MATCH_DRIVER: if (xf86getSubToken(&(ptr->comment)) != STRING) Error(QUOTE_MSG, "MatchDriver"); add_group_entry(&ptr->match_driver, xstrtokenize(val.str, TOKEN_SEP)); + free(val.str); break; case MATCH_TAG: if (xf86getSubToken(&(ptr->comment)) != STRING) Error(QUOTE_MSG, "MatchTag"); add_group_entry(&ptr->match_tag, xstrtokenize(val.str, TOKEN_SEP)); + free(val.str); break; case MATCH_LAYOUT: if (xf86getSubToken(&(ptr->comment)) != STRING) Error(QUOTE_MSG, "MatchLayout"); add_group_entry(&ptr->match_layout, xstrtokenize(val.str, TOKEN_SEP)); + free(val.str); break; case MATCH_IS_KEYBOARD: if (xf86getSubToken(&(ptr->comment)) != STRING) Error(QUOTE_MSG, "MatchIsKeyboard"); ptr->is_keyboard.set = xf86getBoolValue(&ptr->is_keyboard.val, val.str); + free(val.str); if (!ptr->is_keyboard.set) Error(BOOL_MSG, "MatchIsKeyboard"); break; @@ -190,6 +200,7 @@ xf86parseInputClassSection(void) Error(QUOTE_MSG, "MatchIsPointer"); ptr->is_pointer.set = xf86getBoolValue(&ptr->is_pointer.val, val.str); + free(val.str); if (!ptr->is_pointer.set) Error(BOOL_MSG, "MatchIsPointer"); break; @@ -198,6 +209,7 @@ xf86parseInputClassSection(void) Error(QUOTE_MSG, "MatchIsJoystick"); ptr->is_joystick.set = xf86getBoolValue(&ptr->is_joystick.val, val.str); + free(val.str); if (!ptr->is_joystick.set) Error(BOOL_MSG, "MatchIsJoystick"); break; @@ -206,6 +218,7 @@ xf86parseInputClassSection(void) Error(QUOTE_MSG, "MatchIsTablet"); ptr->is_tablet.set = xf86getBoolValue(&ptr->is_tablet.val, val.str); + free(val.str); if (!ptr->is_tablet.set) Error(BOOL_MSG, "MatchIsTablet"); break; @@ -214,6 +227,7 @@ xf86parseInputClassSection(void) Error(QUOTE_MSG, "MatchIsTouchpad"); ptr->is_touchpad.set = xf86getBoolValue(&ptr->is_touchpad.val, val.str); + free(val.str); if (!ptr->is_touchpad.set) Error(BOOL_MSG, "MatchIsTouchpad"); break; @@ -222,6 +236,7 @@ xf86parseInputClassSection(void) Error(QUOTE_MSG, "MatchIsTouchscreen"); ptr->is_touchscreen.set = xf86getBoolValue(&ptr->is_touchscreen.val, val.str); + free(val.str); if (!ptr->is_touchscreen.set) Error(BOOL_MSG, "MatchIsTouchscreen"); break; diff --git a/xorg-server/hw/xfree86/parser/configProcs.h b/xorg-server/hw/xfree86/parser/configProcs.h index 7d8a8e53a..114cdfe33 100644 --- a/xorg-server/hw/xfree86/parser/configProcs.h +++ b/xorg-server/hw/xfree86/parser/configProcs.h @@ -95,9 +95,9 @@ int xf86getSubToken(char **comment); int xf86getSubTokenWithTab(char **comment, xf86ConfigSymTabRec *tab); void xf86unGetToken(int token); char *xf86tokenString(void); -void xf86parseError(char *format, ...); -void xf86validationError(char *format, ...); -void xf86setSection(char *section); +void xf86parseError(const char *format, ...); +void xf86validationError(const char *format, ...); +void xf86setSection(const char *section); int xf86getStringToken(xf86ConfigSymTabRec *tab); /* write.c */ /* DRI.c */ diff --git a/xorg-server/hw/xfree86/parser/scan.c b/xorg-server/hw/xfree86/parser/scan.c index 99b325717..9099227bb 100644 --- a/xorg-server/hw/xfree86/parser/scan.c +++ b/xorg-server/hw/xfree86/parser/scan.c @@ -90,7 +90,7 @@ #define CONFIG_BUF_LEN 1024 #define CONFIG_MAX_FILES 64 -static int StringToToken (char *, xf86ConfigSymTabRec *); +static int StringToToken (const char *, xf86ConfigSymTabRec *); static struct { FILE *file; @@ -101,8 +101,6 @@ static int builtinIndex = 0; static int configPos = 0; /* current readers position */ static int configLineNo = 0; /* linenumber */ static char *configBuf, *configRBuf; /* buffer for lines */ -static char *configPath; /* path to config file */ -static char *configDirPath; /* path to config dir */ static char *configSection = NULL; /* name of current section being parsed */ static int numFiles = 0; /* number of config files */ static int curFileIndex = 0; /* index of current config file */ @@ -281,8 +279,10 @@ again: if (builtinConfig[builtinIndex] == NULL) ret = NULL; else { - ret = strncpy(configBuf, builtinConfig[builtinIndex], - CONFIG_BUF_LEN); + strlcpy(configBuf, + builtinConfig[builtinIndex], + CONFIG_BUF_LEN); + ret = configBuf; builtinIndex++; } } @@ -800,14 +800,12 @@ AddConfigDirFiles(const char *dirpath, struct dirent **list, int num) "files opened\n"); warnOnce = TRUE; } - free(list[i]); continue; } path = malloc(PATH_MAX + 1); snprintf(path, PATH_MAX + 1, "%s/%s", dirpath, list[i]->d_name); - free(list[i]); file = fopen(path, "r"); if (!file) { free(path); @@ -858,8 +856,10 @@ OpenConfigDir(const char *path, const char *cmdline, const char *projroot, if (!found) { free(dirpath); dirpath = NULL; - free(list); } + while (num--) + free(list[num]); + free(list); } free(pathcopy); @@ -892,7 +892,8 @@ xf86initConfigFiles(void) * of the located files. * * The return value is a pointer to the actual name of the file that was - * opened. When no file is found, the return value is NULL. + * opened. When no file is found, the return value is NULL. The caller should + * free() the returned value. * * The escape sequences allowed in the search path are defined above. * @@ -914,7 +915,7 @@ xf86initConfigFiles(void) "%P/lib/X11/%X" #endif -const char * +char * xf86openConfigFile(const char *path, const char *cmdline, const char *projroot) { if (!path || !path[0]) @@ -923,8 +924,7 @@ xf86openConfigFile(const char *path, const char *cmdline, const char *projroot) projroot = PROJECTROOT; /* Search for a config file */ - configPath = OpenConfigFile(path, cmdline, projroot, XCONFIGFILE); - return configPath; + return OpenConfigFile(path, cmdline, projroot, XCONFIGFILE); } /* @@ -937,12 +937,13 @@ xf86openConfigFile(const char *path, const char *cmdline, const char *projroot) * fails if it is not found. * * The return value is a pointer to the actual name of the direcoty that was - * opened. When no directory is found, the return value is NULL. + * opened. When no directory is found, the return value is NULL. The caller + * should free() the returned value. * * The escape sequences allowed in the search path are defined above. * */ -const char * +char * xf86openConfigDirFiles(const char *path, const char *cmdline, const char *projroot) { @@ -952,8 +953,7 @@ xf86openConfigDirFiles(const char *path, const char *cmdline, projroot = PROJECTROOT; /* Search for the multiconf directory */ - configDirPath = OpenConfigDir(path, cmdline, projroot, XCONFIGDIR); - return configDirPath; + return OpenConfigDir(path, cmdline, projroot, XCONFIGDIR); } void @@ -961,10 +961,6 @@ xf86closeConfigFile (void) { int i; - free (configPath); - configPath = NULL; - free (configDirPath); - configDirPath = NULL; free (configRBuf); configRBuf = NULL; free (configBuf); @@ -990,11 +986,11 @@ xf86setBuiltinConfig(const char *config[]) } void -xf86parseError (char *format,...) +xf86parseError (const char *format,...) { va_list ap; - char *filename = numFiles ? configFiles[curFileIndex].path : - ""; + const char *filename = numFiles ? configFiles[curFileIndex].path + : ""; ErrorF ("Parse error on line %d of section %s in file %s\n\t", configLineNo, configSection, filename); @@ -1006,11 +1002,11 @@ xf86parseError (char *format,...) } void -xf86validationError (char *format,...) +xf86validationError (const char *format,...) { va_list ap; - char *filename = numFiles ? configFiles[curFileIndex].path : - ""; + const char *filename = numFiles ? configFiles[curFileIndex].path + : ""; ErrorF ("Data incomplete in file %s\n\t", filename); va_start (ap, format); @@ -1021,7 +1017,7 @@ xf86validationError (char *format,...) } void -xf86setSection (char *section) +xf86setSection (const char *section) { free(configSection); configSection = strdup(section); @@ -1038,7 +1034,7 @@ xf86getStringToken (xf86ConfigSymTabRec * tab) } static int -StringToToken (char *str, xf86ConfigSymTabRec * tab) +StringToToken (const char *str, xf86ConfigSymTabRec * tab) { int i; diff --git a/xorg-server/hw/xfree86/parser/xf86Optrec.h b/xorg-server/hw/xfree86/parser/xf86Optrec.h index 61a8c5ff5..b8e9d6192 100644 --- a/xorg-server/hw/xfree86/parser/xf86Optrec.h +++ b/xorg-server/hw/xfree86/parser/xf86Optrec.h @@ -77,7 +77,7 @@ extern _X_EXPORT char *xf86optionValue(XF86OptionPtr opt); extern _X_EXPORT XF86OptionPtr xf86newOption(char *name, char *value); extern _X_EXPORT XF86OptionPtr xf86nextOption(XF86OptionPtr list); extern _X_EXPORT XF86OptionPtr xf86findOption(XF86OptionPtr list, const char *name); -extern _X_EXPORT char *xf86findOptionValue(XF86OptionPtr list, const char *name); +extern _X_EXPORT const char *xf86findOptionValue(XF86OptionPtr list, const char *name); extern _X_EXPORT XF86OptionPtr xf86optionListCreate(const char **options, int count, int used); extern _X_EXPORT XF86OptionPtr xf86optionListMerge(XF86OptionPtr head, XF86OptionPtr tail); extern _X_EXPORT int xf86nameCompare (const char *s1, const char *s2); diff --git a/xorg-server/hw/xfree86/parser/xf86Parser.h b/xorg-server/hw/xfree86/parser/xf86Parser.h index a8785c5fa..7d4662b98 100644 --- a/xorg-server/hw/xfree86/parser/xf86Parser.h +++ b/xorg-server/hw/xfree86/parser/xf86Parser.h @@ -479,7 +479,7 @@ XF86ConfigRec, *XF86ConfigPtr; typedef struct { int token; /* id of the token */ - char *name; /* pointer to the LOWERCASED name */ + const char *name; /* pointer to the LOWERCASED name */ } xf86ConfigSymTabRec, *xf86ConfigSymTabPtr; @@ -487,10 +487,10 @@ xf86ConfigSymTabRec, *xf86ConfigSymTabPtr; * prototypes for public functions */ extern void xf86initConfigFiles(void); -extern const char *xf86openConfigFile(const char *path, const char *cmdline, - const char *projroot); -extern const char *xf86openConfigDirFiles(const char *path, const char *cmdline, - const char *projroot); +extern char *xf86openConfigFile(const char *path, const char *cmdline, + const char *projroot); +extern char *xf86openConfigDirFiles(const char *path, const char *cmdline, + const char *projroot); extern void xf86setBuiltinConfig(const char *config[]); extern XF86ConfigPtr xf86readConfigFile(void); extern void xf86closeConfigFile(void); diff --git a/xorg-server/hw/xfree86/ramdac/BTPriv.h b/xorg-server/hw/xfree86/ramdac/BTPriv.h index 184b4811c..52737768f 100644 --- a/xorg-server/hw/xfree86/ramdac/BTPriv.h +++ b/xorg-server/hw/xfree86/ramdac/BTPriv.h @@ -6,7 +6,7 @@ #include "BT.h" typedef struct { - char *DeviceName; + const char *DeviceName; } xf86BTramdacInfo; extern xf86BTramdacInfo BTramdacDeviceInfo[]; diff --git a/xorg-server/hw/xfree86/ramdac/IBMPriv.h b/xorg-server/hw/xfree86/ramdac/IBMPriv.h index a33da9106..309a193ad 100644 --- a/xorg-server/hw/xfree86/ramdac/IBMPriv.h +++ b/xorg-server/hw/xfree86/ramdac/IBMPriv.h @@ -6,7 +6,7 @@ #include "IBM.h" typedef struct { - char *DeviceName; + const char *DeviceName; } xf86IBMramdacInfo; extern xf86IBMramdacInfo IBMramdacDeviceInfo[]; diff --git a/xorg-server/hw/xfree86/ramdac/TIPriv.h b/xorg-server/hw/xfree86/ramdac/TIPriv.h index 191c9b5ce..20e07f5cc 100644 --- a/xorg-server/hw/xfree86/ramdac/TIPriv.h +++ b/xorg-server/hw/xfree86/ramdac/TIPriv.h @@ -6,7 +6,7 @@ #include "TI.h" typedef struct { - char *DeviceName; + const char *DeviceName; } xf86TIramdacInfo; extern xf86TIramdacInfo TIramdacDeviceInfo[]; diff --git a/xorg-server/hw/xfree86/utils/gtf/gtf.c b/xorg-server/hw/xfree86/utils/gtf/gtf.c index 840626c66..87fcb3f0e 100644 --- a/xorg-server/hw/xfree86/utils/gtf/gtf.c +++ b/xorg-server/hw/xfree86/utils/gtf/gtf.c @@ -1,741 +1,741 @@ -/* gtf.c Generate mode timings using the GTF Timing Standard - * - * gcc gtf.c -o gtf -lm -Wall - * - * Copyright (c) 2001, Andy Ritger aritger@nvidia.com - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * o Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * o Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * o Neither the name of NVIDIA nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT - * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * - * - * This program is based on the Generalized Timing Formula(GTF TM) - * Standard Version: 1.0, Revision: 1.0 - * - * The GTF Document contains the following Copyright information: - * - * Copyright (c) 1994, 1995, 1996 - Video Electronics Standards - * Association. Duplication of this document within VESA member - * companies for review purposes is permitted. All other rights - * reserved. - * - * While every precaution has been taken in the preparation - * of this standard, the Video Electronics Standards Association and - * its contributors assume no responsibility for errors or omissions, - * and make no warranties, expressed or implied, of functionality - * of suitability for any purpose. The sample code contained within - * this standard may be used without restriction. - * - * - * - * The GTF EXCEL(TM) SPREADSHEET, a sample (and the definitive) - * implementation of the GTF Timing Standard, is available at: - * - * ftp://ftp.vesa.org/pub/GTF/GTF_V1R1.xls - * - * - * - * This program takes a desired resolution and vertical refresh rate, - * and computes mode timings according to the GTF Timing Standard. - * These mode timings can then be formatted as an XServer modeline - * or a mode description for use by fbset(8). - * - * - * - * NOTES: - * - * The GTF allows for computation of "margins" (the visible border - * surrounding the addressable video); on most non-overscan type - * systems, the margin period is zero. I've implemented the margin - * computations but not enabled it because 1) I don't really have - * any experience with this, and 2) neither XServer modelines nor - * fbset fb.modes provide an obvious way for margin timings to be - * included in their mode descriptions (needs more investigation). - * - * The GTF provides for computation of interlaced mode timings; - * I've implemented the computations but not enabled them, yet. - * I should probably enable and test this at some point. - * - * - * - * TODO: - * - * o Add support for interlaced modes. - * - * o Implement the other portions of the GTF: compute mode timings - * given either the desired pixel clock or the desired horizontal - * frequency. - * - * o It would be nice if this were more general purpose to do things - * outside the scope of the GTF: like generate double scan mode - * timings, for example. - * - * o Printing digits to the right of the decimal point when the - * digits are 0 annoys me. - * - * o Error checking. - * - */ - -#ifdef HAVE_XORG_CONFIG_H -# include -#endif - -#include -#include -#include -#include - -#define MARGIN_PERCENT 1.8 /* % of active vertical image */ -#define CELL_GRAN 8.0 /* assumed character cell granularity */ -#define MIN_PORCH 1 /* minimum front porch */ -#define V_SYNC_RQD 3 /* width of vsync in lines */ -#define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */ -#define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */ -#define M 600.0 /* blanking formula gradient */ -#define C 40.0 /* blanking formula offset */ -#define K 128.0 /* blanking formula scaling factor */ -#define J 20.0 /* blanking formula scaling factor */ - -/* C' and M' are part of the Blanking Duty Cycle computation */ - -#define C_PRIME (((C - J) * K/256.0) + J) -#define M_PRIME (K/256.0 * M) - - -/* struct definitions */ - -typedef struct __mode -{ - int hr, hss, hse, hfl; - int vr, vss, vse, vfl; - float pclk, h_freq, v_freq; -} mode; - - -typedef struct __options -{ - int x, y; - int xorgmode, fbmode; - float v_freq; -} options; - - - - -/* prototypes */ - -void print_value(int n, char *name, float val); -void print_xf86_mode (mode *m); -void print_fb_mode (mode *m); -mode *vert_refresh (int h_pixels, int v_lines, float freq, - int interlaced, int margins); -options *parse_command_line (int argc, char *argv[]); - - - - -/* - * print_value() - print the result of the named computation; this is - * useful when comparing against the GTF EXCEL spreadsheet. - */ - -int global_verbose = 0; - -void print_value(int n, char *name, float val) -{ - if (global_verbose) { - printf("%2d: %-27s: %15f\n", n, name, val); - } -} - - - -/* print_xf86_mode() - print the XServer modeline, given mode timings. */ - -void print_xf86_mode (mode *m) -{ - printf ("\n"); - printf (" # %dx%d @ %.2f Hz (GTF) hsync: %.2f kHz; pclk: %.2f MHz\n", - m->hr, m->vr, m->v_freq, m->h_freq, m->pclk); - - printf (" Modeline \"%dx%d_%.2f\" %.2f" - " %d %d %d %d" - " %d %d %d %d" - " -HSync +Vsync\n\n", - m->hr, m->vr, m->v_freq, m->pclk, - m->hr, m->hss, m->hse, m->hfl, - m->vr, m->vss, m->vse, m->vfl); - -} - - - -/* - * print_fb_mode() - print a mode description in fbset(8) format; - * see the fb.modes(8) manpage. The timing description used in - * this is rather odd; they use "left and right margin" to refer - * to the portion of the hblank before and after the sync pulse - * by conceptually wrapping the portion of the blank after the pulse - * to infront of the visible region; ie: - * - * - * Timing description I'm accustomed to: - * - * - * - * <--------1--------> <--2--> <--3--> <--4--> - * _________ - * |-------------------|_______| |_______ - * - * R SS SE FL - * - * 1: visible image - * 2: blank before sync (aka front porch) - * 3: sync pulse - * 4: blank after sync (aka back porch) - * R: Resolution - * SS: Sync Start - * SE: Sync End - * FL: Frame Length - * - * - * But the fb.modes format is: - * - * - * <--4--> <--------1--------> <--2--> <--3--> - * _________ - * _______|-------------------|_______| | - * - * The fb.modes(8) manpage refers to <4> and <2> as the left and - * right "margin" (as well as upper and lower margin in the vertical - * direction) -- note that this has nothing to do with the term - * "margin" used in the GTF Timing Standard. - * - * XXX always prints the 32 bit mode -- should I provide a command - * line option to specify the bpp? It's simple enough for a user - * to edit the mode description after it's generated. - */ - -void print_fb_mode (mode *m) -{ - printf ("\n"); - printf ("mode \"%dx%d %.2fHz 32bit (GTF)\"\n", - m->hr, m->vr, m->v_freq); - printf (" # PCLK: %.2f MHz, H: %.2f kHz, V: %.2f Hz\n", - m->pclk, m->h_freq, m->v_freq); - printf (" geometry %d %d %d %d 32\n", - m->hr, m->vr, m->hr, m->vr); - printf (" timings %d %d %d %d %d %d %d\n", - (int) rint(1000000.0/m->pclk),/* pixclock in picoseconds */ - m->hfl - m->hse, /* left margin (in pixels) */ - m->hss - m->hr, /* right margin (in pixels) */ - m->vfl - m->vse, /* upper margin (in pixel lines) */ - m->vss - m->vr, /* lower margin (in pixel lines) */ - m->hse - m->hss, /* horizontal sync length (pixels) */ - m->vse - m->vss); /* vert sync length (pixel lines) */ - printf (" hsync low\n"); - printf (" vsync high\n"); - printf ("endmode\n\n"); - -} - - - - -/* - * vert_refresh() - as defined by the GTF Timing Standard, compute the - * Stage 1 Parameters using the vertical refresh frequency. In other - * words: input a desired resolution and desired refresh rate, and - * output the GTF mode timings. - * - * XXX All the code is in place to compute interlaced modes, but I don't - * feel like testing it right now. - * - * XXX margin computations are implemented but not tested (nor used by - * XServer of fbset mode descriptions, from what I can tell). - */ - -mode *vert_refresh (int h_pixels, int v_lines, float freq, - int interlaced, int margins) -{ - float h_pixels_rnd; - float v_lines_rnd; - float v_field_rate_rqd; - float top_margin; - float bottom_margin; - float interlace; - float h_period_est; - float vsync_plus_bp; - float v_back_porch; - float total_v_lines; - float v_field_rate_est; - float h_period; - float v_field_rate; - float v_frame_rate; - float left_margin; - float right_margin; - float total_active_pixels; - float ideal_duty_cycle; - float h_blank; - float total_pixels; - float pixel_freq; - float h_freq; - - float h_sync; - float h_front_porch; - float v_odd_front_porch_lines; - - mode *m = (mode*) malloc (sizeof (mode)); - - - /* 1. In order to give correct results, the number of horizontal - * pixels requested is first processed to ensure that it is divisible - * by the character size, by rounding it to the nearest character - * cell boundary: - * - * [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND]) - */ - - h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN; - - print_value(1, "[H PIXELS RND]", h_pixels_rnd); - - - /* 2. If interlace is requested, the number of vertical lines assumed - * by the calculation must be halved, as the computation calculates - * the number of vertical lines per field. In either case, the - * number of lines is rounded to the nearest integer. - * - * [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0), - * ROUND([V LINES],0)) - */ - - v_lines_rnd = interlaced ? - rint((float) v_lines) / 2.0 : - rint((float) v_lines); - - print_value(2, "[V LINES RND]", v_lines_rnd); - - - /* 3. Find the frame rate required: - * - * [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2, - * [I/P FREQ RQD]) - */ - - v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq); - - print_value(3, "[V FIELD RATE RQD]", v_field_rate_rqd); - - - /* 4. Find number of lines in Top margin: - * - * [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y", - * ROUND(([MARGIN%]/100*[V LINES RND]),0), - * 0) - */ - - top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0); - - print_value(4, "[TOP MARGIN (LINES)]", top_margin); - - - /* 5. Find number of lines in Bottom margin: - * - * [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y", - * ROUND(([MARGIN%]/100*[V LINES RND]),0), - * 0) - */ - - bottom_margin = margins ? rint(MARGIN_PERCENT/100.0 * v_lines_rnd) : (0.0); - - print_value(5, "[BOT MARGIN (LINES)]", bottom_margin); - - - /* 6. If interlace is required, then set variable [INTERLACE]=0.5: - * - * [INTERLACE]=(IF([INT RQD?]="y",0.5,0)) - */ - - interlace = interlaced ? 0.5 : 0.0; - - print_value(6, "[INTERLACE]", interlace); - - - /* 7. Estimate the Horizontal period - * - * [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) / - * ([V LINES RND] + (2*[TOP MARGIN (LINES)]) + - * [MIN PORCH RND]+[INTERLACE]) * 1000000 - */ - - h_period_est = (((1.0/v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP/1000000.0)) - / (v_lines_rnd + (2*top_margin) + MIN_PORCH + interlace) - * 1000000.0); - - print_value(7, "[H PERIOD EST]", h_period_est); - - - /* 8. Find the number of lines in V sync + back porch: - * - * [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0) - */ - - vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP/h_period_est); - - print_value(8, "[V SYNC+BP]", vsync_plus_bp); - - - /* 9. Find the number of lines in V back porch alone: - * - * [V BACK PORCH] = [V SYNC+BP] - [V SYNC RND] - * - * XXX is "[V SYNC RND]" a typo? should be [V SYNC RQD]? - */ - - v_back_porch = vsync_plus_bp - V_SYNC_RQD; - - print_value(9, "[V BACK PORCH]", v_back_porch); - - - /* 10. Find the total number of lines in Vertical field period: - * - * [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] + - * [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] + - * [MIN PORCH RND] - */ - - total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + - interlace + MIN_PORCH; - - print_value(10, "[TOTAL V LINES]", total_v_lines); - - - /* 11. Estimate the Vertical field frequency: - * - * [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000 - */ - - v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0; - - print_value(11, "[V FIELD RATE EST]", v_field_rate_est); - - - /* 12. Find the actual horizontal period: - * - * [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST]) - */ - - h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est); - - print_value(12, "[H PERIOD]", h_period); - - - /* 13. Find the actual Vertical field frequency: - * - * [V FIELD RATE] = 1 / [H PERIOD] / [TOTAL V LINES] * 1000000 - */ - - v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0; - - print_value(13, "[V FIELD RATE]", v_field_rate); - - - /* 14. Find the Vertical frame frequency: - * - * [V FRAME RATE] = (IF([INT RQD?]="y", [V FIELD RATE]/2, [V FIELD RATE])) - */ - - v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate; - - print_value(14, "[V FRAME RATE]", v_frame_rate); - - - /* 15. Find number of pixels in left margin: - * - * [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", - * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / - * [CELL GRAN RND]),0)) * [CELL GRAN RND], - * 0)) - */ - - left_margin = margins ? - rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : - 0.0; - - print_value(15, "[LEFT MARGIN (PIXELS)]", left_margin); - - - /* 16. Find number of pixels in right margin: - * - * [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", - * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / - * [CELL GRAN RND]),0)) * [CELL GRAN RND], - * 0)) - */ - - right_margin = margins ? - rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : - 0.0; - - print_value(16, "[RIGHT MARGIN (PIXELS)]", right_margin); - - - /* 17. Find total number of active pixels in image and left and right - * margins: - * - * [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] + - * [RIGHT MARGIN (PIXELS)] - */ - - total_active_pixels = h_pixels_rnd + left_margin + right_margin; - - print_value(17, "[TOTAL ACTIVE PIXELS]", total_active_pixels); - - - /* 18. Find the ideal blanking duty cycle from the blanking duty cycle - * equation: - * - * [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000) - */ - - ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0); - - print_value(18, "[IDEAL DUTY CYCLE]", ideal_duty_cycle); - - - /* 19. Find the number of pixels in the blanking time to the nearest - * double character cell: - * - * [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] * - * [IDEAL DUTY CYCLE] / - * (100-[IDEAL DUTY CYCLE]) / - * (2*[CELL GRAN RND])), 0)) - * * (2*[CELL GRAN RND]) - */ - - h_blank = rint(total_active_pixels * - ideal_duty_cycle / - (100.0 - ideal_duty_cycle) / - (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN); - - print_value(19, "[H BLANK (PIXELS)]", h_blank); - - - /* 20. Find total number of pixels: - * - * [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)] - */ - - total_pixels = total_active_pixels + h_blank; - - print_value(20, "[TOTAL PIXELS]", total_pixels); - - - /* 21. Find pixel clock frequency: - * - * [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD] - */ - - pixel_freq = total_pixels / h_period; - - print_value(21, "[PIXEL FREQ]", pixel_freq); - - - /* 22. Find horizontal frequency: - * - * [H FREQ] = 1000 / [H PERIOD] - */ - - h_freq = 1000.0 / h_period; - - print_value(22, "[H FREQ]", h_freq); - - - - /* Stage 1 computations are now complete; I should really pass - the results to another function and do the Stage 2 - computations, but I only need a few more values so I'll just - append the computations here for now */ - - - - /* 17. Find the number of pixels in the horizontal sync period: - * - * [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] / - * [CELL GRAN RND]),0))*[CELL GRAN RND] - */ - - h_sync = rint(H_SYNC_PERCENT/100.0 * total_pixels / CELL_GRAN) * CELL_GRAN; - - print_value(17, "[H SYNC (PIXELS)]", h_sync); - - - /* 18. Find the number of pixels in the horizontal front porch period: - * - * [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)] - */ - - h_front_porch = (h_blank / 2.0) - h_sync; - - print_value(18, "[H FRONT PORCH (PIXELS)]", h_front_porch); - - - /* 36. Find the number of lines in the odd front porch period: - * - * [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE]) - */ - - v_odd_front_porch_lines = MIN_PORCH + interlace; - - print_value(36, "[V ODD FRONT PORCH(LINES)]", v_odd_front_porch_lines); - - - /* finally, pack the results in the mode struct */ - - m->hr = (int) (h_pixels_rnd); - m->hss = (int) (h_pixels_rnd + h_front_porch); - m->hse = (int) (h_pixels_rnd + h_front_porch + h_sync); - m->hfl = (int) (total_pixels); - - m->vr = (int) (v_lines_rnd); - m->vss = (int) (v_lines_rnd + v_odd_front_porch_lines); - m->vse = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD); - m->vfl = (int) (total_v_lines); - - m->pclk = pixel_freq; - m->h_freq = h_freq; - m->v_freq = freq; - - return m; - -} - - - - -/* - * parse_command_line() - parse the command line and return an - * alloced structure containing the results. On error print usage - * and return NULL. - */ - -options *parse_command_line (int argc, char *argv[]) -{ - int n; - - options *o = (options *) calloc (1, sizeof (options)); - - if (argc < 4) goto bad_option; - - o->x = atoi (argv[1]); - o->y = atoi (argv[2]); - o->v_freq = atof (argv[3]); - - /* XXX should check for errors in the above */ - - n = 4; - - while (n < argc) { - if ((strcmp (argv[n], "-v") == 0) || - (strcmp (argv[n], "--verbose") == 0)) { - global_verbose = 1; - } else if ((strcmp (argv[n], "-f") == 0) || - (strcmp (argv[n], "--fbmode") == 0)) { - o->fbmode = 1; - } else if ((strcmp (argv[n], "-x") == 0) || - (strcmp (argv[n], "--xorgmode") == 0) || - (strcmp (argv[n], "--xf86mode") == 0)) { - o->xorgmode = 1; - } else { - goto bad_option; - } - - n++; - } - - /* if neither xorgmode nor fbmode were requested, default to - xorgmode */ - - if (!o->fbmode && !o->xorgmode) o->xorgmode = 1; - - return o; - - bad_option: - - fprintf (stderr, "\n"); - fprintf (stderr, "usage: %s x y refresh [-v|--verbose] " - "[-f|--fbmode] [-x|--xorgmode]\n", argv[0]); - - fprintf (stderr, "\n"); - - fprintf (stderr, " x : the desired horizontal " - "resolution (required)\n"); - fprintf (stderr, " y : the desired vertical " - "resolution (required)\n"); - fprintf (stderr, " refresh : the desired refresh " - "rate (required)\n"); - fprintf (stderr, " -v|--verbose : enable verbose printouts " - "(traces each step of the computation)\n"); - fprintf (stderr, " -f|--fbmode : output an fbset(8)-style mode " - "description\n"); - fprintf (stderr, " -x|--xorgmode : output an "__XSERVERNAME__"-style mode " - "description (this is the default\n" - " if no mode description is requested)\n"); - - fprintf (stderr, "\n"); - - free (o); - return NULL; - -} - - - -int main (int argc, char *argv[]) -{ - mode *m; - options *o; - - o = parse_command_line (argc, argv); - if (!o) exit (1); - - m = vert_refresh (o->x, o->y, o->v_freq, 0, 0); - if (!m) exit (1); - - if (o->xorgmode) - print_xf86_mode(m); - - if (o->fbmode) - print_fb_mode(m); - - return 0; - -} +/* gtf.c Generate mode timings using the GTF Timing Standard + * + * gcc gtf.c -o gtf -lm -Wall + * + * Copyright (c) 2001, Andy Ritger aritger@nvidia.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * o Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * o Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * o Neither the name of NVIDIA nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * + * + * This program is based on the Generalized Timing Formula(GTF TM) + * Standard Version: 1.0, Revision: 1.0 + * + * The GTF Document contains the following Copyright information: + * + * Copyright (c) 1994, 1995, 1996 - Video Electronics Standards + * Association. Duplication of this document within VESA member + * companies for review purposes is permitted. All other rights + * reserved. + * + * While every precaution has been taken in the preparation + * of this standard, the Video Electronics Standards Association and + * its contributors assume no responsibility for errors or omissions, + * and make no warranties, expressed or implied, of functionality + * of suitability for any purpose. The sample code contained within + * this standard may be used without restriction. + * + * + * + * The GTF EXCEL(TM) SPREADSHEET, a sample (and the definitive) + * implementation of the GTF Timing Standard, is available at: + * + * ftp://ftp.vesa.org/pub/GTF/GTF_V1R1.xls + * + * + * + * This program takes a desired resolution and vertical refresh rate, + * and computes mode timings according to the GTF Timing Standard. + * These mode timings can then be formatted as an XServer modeline + * or a mode description for use by fbset(8). + * + * + * + * NOTES: + * + * The GTF allows for computation of "margins" (the visible border + * surrounding the addressable video); on most non-overscan type + * systems, the margin period is zero. I've implemented the margin + * computations but not enabled it because 1) I don't really have + * any experience with this, and 2) neither XServer modelines nor + * fbset fb.modes provide an obvious way for margin timings to be + * included in their mode descriptions (needs more investigation). + * + * The GTF provides for computation of interlaced mode timings; + * I've implemented the computations but not enabled them, yet. + * I should probably enable and test this at some point. + * + * + * + * TODO: + * + * o Add support for interlaced modes. + * + * o Implement the other portions of the GTF: compute mode timings + * given either the desired pixel clock or the desired horizontal + * frequency. + * + * o It would be nice if this were more general purpose to do things + * outside the scope of the GTF: like generate double scan mode + * timings, for example. + * + * o Printing digits to the right of the decimal point when the + * digits are 0 annoys me. + * + * o Error checking. + * + */ + +#ifdef HAVE_XORG_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#define MARGIN_PERCENT 1.8 /* % of active vertical image */ +#define CELL_GRAN 8.0 /* assumed character cell granularity */ +#define MIN_PORCH 1 /* minimum front porch */ +#define V_SYNC_RQD 3 /* width of vsync in lines */ +#define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */ +#define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */ +#define M 600.0 /* blanking formula gradient */ +#define C 40.0 /* blanking formula offset */ +#define K 128.0 /* blanking formula scaling factor */ +#define J 20.0 /* blanking formula scaling factor */ + +/* C' and M' are part of the Blanking Duty Cycle computation */ + +#define C_PRIME (((C - J) * K/256.0) + J) +#define M_PRIME (K/256.0 * M) + + +/* struct definitions */ + +typedef struct __mode +{ + int hr, hss, hse, hfl; + int vr, vss, vse, vfl; + float pclk, h_freq, v_freq; +} mode; + + +typedef struct __options +{ + int x, y; + int xorgmode, fbmode; + float v_freq; +} options; + + + + +/* prototypes */ + +void print_value(int n, const char *name, float val); +void print_xf86_mode (mode *m); +void print_fb_mode (mode *m); +mode *vert_refresh (int h_pixels, int v_lines, float freq, + int interlaced, int margins); +options *parse_command_line (int argc, char *argv[]); + + + + +/* + * print_value() - print the result of the named computation; this is + * useful when comparing against the GTF EXCEL spreadsheet. + */ + +int global_verbose = 0; + +void print_value(int n, const char *name, float val) +{ + if (global_verbose) { + printf("%2d: %-27s: %15f\n", n, name, val); + } +} + + + +/* print_xf86_mode() - print the XServer modeline, given mode timings. */ + +void print_xf86_mode (mode *m) +{ + printf ("\n"); + printf (" # %dx%d @ %.2f Hz (GTF) hsync: %.2f kHz; pclk: %.2f MHz\n", + m->hr, m->vr, m->v_freq, m->h_freq, m->pclk); + + printf (" Modeline \"%dx%d_%.2f\" %.2f" + " %d %d %d %d" + " %d %d %d %d" + " -HSync +Vsync\n\n", + m->hr, m->vr, m->v_freq, m->pclk, + m->hr, m->hss, m->hse, m->hfl, + m->vr, m->vss, m->vse, m->vfl); + +} + + + +/* + * print_fb_mode() - print a mode description in fbset(8) format; + * see the fb.modes(8) manpage. The timing description used in + * this is rather odd; they use "left and right margin" to refer + * to the portion of the hblank before and after the sync pulse + * by conceptually wrapping the portion of the blank after the pulse + * to infront of the visible region; ie: + * + * + * Timing description I'm accustomed to: + * + * + * + * <--------1--------> <--2--> <--3--> <--4--> + * _________ + * |-------------------|_______| |_______ + * + * R SS SE FL + * + * 1: visible image + * 2: blank before sync (aka front porch) + * 3: sync pulse + * 4: blank after sync (aka back porch) + * R: Resolution + * SS: Sync Start + * SE: Sync End + * FL: Frame Length + * + * + * But the fb.modes format is: + * + * + * <--4--> <--------1--------> <--2--> <--3--> + * _________ + * _______|-------------------|_______| | + * + * The fb.modes(8) manpage refers to <4> and <2> as the left and + * right "margin" (as well as upper and lower margin in the vertical + * direction) -- note that this has nothing to do with the term + * "margin" used in the GTF Timing Standard. + * + * XXX always prints the 32 bit mode -- should I provide a command + * line option to specify the bpp? It's simple enough for a user + * to edit the mode description after it's generated. + */ + +void print_fb_mode (mode *m) +{ + printf ("\n"); + printf ("mode \"%dx%d %.2fHz 32bit (GTF)\"\n", + m->hr, m->vr, m->v_freq); + printf (" # PCLK: %.2f MHz, H: %.2f kHz, V: %.2f Hz\n", + m->pclk, m->h_freq, m->v_freq); + printf (" geometry %d %d %d %d 32\n", + m->hr, m->vr, m->hr, m->vr); + printf (" timings %d %d %d %d %d %d %d\n", + (int) rint(1000000.0/m->pclk),/* pixclock in picoseconds */ + m->hfl - m->hse, /* left margin (in pixels) */ + m->hss - m->hr, /* right margin (in pixels) */ + m->vfl - m->vse, /* upper margin (in pixel lines) */ + m->vss - m->vr, /* lower margin (in pixel lines) */ + m->hse - m->hss, /* horizontal sync length (pixels) */ + m->vse - m->vss); /* vert sync length (pixel lines) */ + printf (" hsync low\n"); + printf (" vsync high\n"); + printf ("endmode\n\n"); + +} + + + + +/* + * vert_refresh() - as defined by the GTF Timing Standard, compute the + * Stage 1 Parameters using the vertical refresh frequency. In other + * words: input a desired resolution and desired refresh rate, and + * output the GTF mode timings. + * + * XXX All the code is in place to compute interlaced modes, but I don't + * feel like testing it right now. + * + * XXX margin computations are implemented but not tested (nor used by + * XServer of fbset mode descriptions, from what I can tell). + */ + +mode *vert_refresh (int h_pixels, int v_lines, float freq, + int interlaced, int margins) +{ + float h_pixels_rnd; + float v_lines_rnd; + float v_field_rate_rqd; + float top_margin; + float bottom_margin; + float interlace; + float h_period_est; + float vsync_plus_bp; + float v_back_porch; + float total_v_lines; + float v_field_rate_est; + float h_period; + float v_field_rate; + float v_frame_rate; + float left_margin; + float right_margin; + float total_active_pixels; + float ideal_duty_cycle; + float h_blank; + float total_pixels; + float pixel_freq; + float h_freq; + + float h_sync; + float h_front_porch; + float v_odd_front_porch_lines; + + mode *m = (mode*) malloc (sizeof (mode)); + + + /* 1. In order to give correct results, the number of horizontal + * pixels requested is first processed to ensure that it is divisible + * by the character size, by rounding it to the nearest character + * cell boundary: + * + * [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND]) + */ + + h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN; + + print_value(1, "[H PIXELS RND]", h_pixels_rnd); + + + /* 2. If interlace is requested, the number of vertical lines assumed + * by the calculation must be halved, as the computation calculates + * the number of vertical lines per field. In either case, the + * number of lines is rounded to the nearest integer. + * + * [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0), + * ROUND([V LINES],0)) + */ + + v_lines_rnd = interlaced ? + rint((float) v_lines) / 2.0 : + rint((float) v_lines); + + print_value(2, "[V LINES RND]", v_lines_rnd); + + + /* 3. Find the frame rate required: + * + * [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2, + * [I/P FREQ RQD]) + */ + + v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq); + + print_value(3, "[V FIELD RATE RQD]", v_field_rate_rqd); + + + /* 4. Find number of lines in Top margin: + * + * [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y", + * ROUND(([MARGIN%]/100*[V LINES RND]),0), + * 0) + */ + + top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0); + + print_value(4, "[TOP MARGIN (LINES)]", top_margin); + + + /* 5. Find number of lines in Bottom margin: + * + * [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y", + * ROUND(([MARGIN%]/100*[V LINES RND]),0), + * 0) + */ + + bottom_margin = margins ? rint(MARGIN_PERCENT/100.0 * v_lines_rnd) : (0.0); + + print_value(5, "[BOT MARGIN (LINES)]", bottom_margin); + + + /* 6. If interlace is required, then set variable [INTERLACE]=0.5: + * + * [INTERLACE]=(IF([INT RQD?]="y",0.5,0)) + */ + + interlace = interlaced ? 0.5 : 0.0; + + print_value(6, "[INTERLACE]", interlace); + + + /* 7. Estimate the Horizontal period + * + * [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) / + * ([V LINES RND] + (2*[TOP MARGIN (LINES)]) + + * [MIN PORCH RND]+[INTERLACE]) * 1000000 + */ + + h_period_est = (((1.0/v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP/1000000.0)) + / (v_lines_rnd + (2*top_margin) + MIN_PORCH + interlace) + * 1000000.0); + + print_value(7, "[H PERIOD EST]", h_period_est); + + + /* 8. Find the number of lines in V sync + back porch: + * + * [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0) + */ + + vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP/h_period_est); + + print_value(8, "[V SYNC+BP]", vsync_plus_bp); + + + /* 9. Find the number of lines in V back porch alone: + * + * [V BACK PORCH] = [V SYNC+BP] - [V SYNC RND] + * + * XXX is "[V SYNC RND]" a typo? should be [V SYNC RQD]? + */ + + v_back_porch = vsync_plus_bp - V_SYNC_RQD; + + print_value(9, "[V BACK PORCH]", v_back_porch); + + + /* 10. Find the total number of lines in Vertical field period: + * + * [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] + + * [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] + + * [MIN PORCH RND] + */ + + total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + + interlace + MIN_PORCH; + + print_value(10, "[TOTAL V LINES]", total_v_lines); + + + /* 11. Estimate the Vertical field frequency: + * + * [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000 + */ + + v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0; + + print_value(11, "[V FIELD RATE EST]", v_field_rate_est); + + + /* 12. Find the actual horizontal period: + * + * [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST]) + */ + + h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est); + + print_value(12, "[H PERIOD]", h_period); + + + /* 13. Find the actual Vertical field frequency: + * + * [V FIELD RATE] = 1 / [H PERIOD] / [TOTAL V LINES] * 1000000 + */ + + v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0; + + print_value(13, "[V FIELD RATE]", v_field_rate); + + + /* 14. Find the Vertical frame frequency: + * + * [V FRAME RATE] = (IF([INT RQD?]="y", [V FIELD RATE]/2, [V FIELD RATE])) + */ + + v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate; + + print_value(14, "[V FRAME RATE]", v_frame_rate); + + + /* 15. Find number of pixels in left margin: + * + * [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", + * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / + * [CELL GRAN RND]),0)) * [CELL GRAN RND], + * 0)) + */ + + left_margin = margins ? + rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : + 0.0; + + print_value(15, "[LEFT MARGIN (PIXELS)]", left_margin); + + + /* 16. Find number of pixels in right margin: + * + * [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", + * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / + * [CELL GRAN RND]),0)) * [CELL GRAN RND], + * 0)) + */ + + right_margin = margins ? + rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : + 0.0; + + print_value(16, "[RIGHT MARGIN (PIXELS)]", right_margin); + + + /* 17. Find total number of active pixels in image and left and right + * margins: + * + * [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] + + * [RIGHT MARGIN (PIXELS)] + */ + + total_active_pixels = h_pixels_rnd + left_margin + right_margin; + + print_value(17, "[TOTAL ACTIVE PIXELS]", total_active_pixels); + + + /* 18. Find the ideal blanking duty cycle from the blanking duty cycle + * equation: + * + * [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000) + */ + + ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0); + + print_value(18, "[IDEAL DUTY CYCLE]", ideal_duty_cycle); + + + /* 19. Find the number of pixels in the blanking time to the nearest + * double character cell: + * + * [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] * + * [IDEAL DUTY CYCLE] / + * (100-[IDEAL DUTY CYCLE]) / + * (2*[CELL GRAN RND])), 0)) + * * (2*[CELL GRAN RND]) + */ + + h_blank = rint(total_active_pixels * + ideal_duty_cycle / + (100.0 - ideal_duty_cycle) / + (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN); + + print_value(19, "[H BLANK (PIXELS)]", h_blank); + + + /* 20. Find total number of pixels: + * + * [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)] + */ + + total_pixels = total_active_pixels + h_blank; + + print_value(20, "[TOTAL PIXELS]", total_pixels); + + + /* 21. Find pixel clock frequency: + * + * [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD] + */ + + pixel_freq = total_pixels / h_period; + + print_value(21, "[PIXEL FREQ]", pixel_freq); + + + /* 22. Find horizontal frequency: + * + * [H FREQ] = 1000 / [H PERIOD] + */ + + h_freq = 1000.0 / h_period; + + print_value(22, "[H FREQ]", h_freq); + + + + /* Stage 1 computations are now complete; I should really pass + the results to another function and do the Stage 2 + computations, but I only need a few more values so I'll just + append the computations here for now */ + + + + /* 17. Find the number of pixels in the horizontal sync period: + * + * [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] / + * [CELL GRAN RND]),0))*[CELL GRAN RND] + */ + + h_sync = rint(H_SYNC_PERCENT/100.0 * total_pixels / CELL_GRAN) * CELL_GRAN; + + print_value(17, "[H SYNC (PIXELS)]", h_sync); + + + /* 18. Find the number of pixels in the horizontal front porch period: + * + * [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)] + */ + + h_front_porch = (h_blank / 2.0) - h_sync; + + print_value(18, "[H FRONT PORCH (PIXELS)]", h_front_porch); + + + /* 36. Find the number of lines in the odd front porch period: + * + * [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE]) + */ + + v_odd_front_porch_lines = MIN_PORCH + interlace; + + print_value(36, "[V ODD FRONT PORCH(LINES)]", v_odd_front_porch_lines); + + + /* finally, pack the results in the mode struct */ + + m->hr = (int) (h_pixels_rnd); + m->hss = (int) (h_pixels_rnd + h_front_porch); + m->hse = (int) (h_pixels_rnd + h_front_porch + h_sync); + m->hfl = (int) (total_pixels); + + m->vr = (int) (v_lines_rnd); + m->vss = (int) (v_lines_rnd + v_odd_front_porch_lines); + m->vse = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD); + m->vfl = (int) (total_v_lines); + + m->pclk = pixel_freq; + m->h_freq = h_freq; + m->v_freq = freq; + + return m; + +} + + + + +/* + * parse_command_line() - parse the command line and return an + * alloced structure containing the results. On error print usage + * and return NULL. + */ + +options *parse_command_line (int argc, char *argv[]) +{ + int n; + + options *o = (options *) calloc (1, sizeof (options)); + + if (argc < 4) goto bad_option; + + o->x = atoi (argv[1]); + o->y = atoi (argv[2]); + o->v_freq = atof (argv[3]); + + /* XXX should check for errors in the above */ + + n = 4; + + while (n < argc) { + if ((strcmp (argv[n], "-v") == 0) || + (strcmp (argv[n], "--verbose") == 0)) { + global_verbose = 1; + } else if ((strcmp (argv[n], "-f") == 0) || + (strcmp (argv[n], "--fbmode") == 0)) { + o->fbmode = 1; + } else if ((strcmp (argv[n], "-x") == 0) || + (strcmp (argv[n], "--xorgmode") == 0) || + (strcmp (argv[n], "--xf86mode") == 0)) { + o->xorgmode = 1; + } else { + goto bad_option; + } + + n++; + } + + /* if neither xorgmode nor fbmode were requested, default to + xorgmode */ + + if (!o->fbmode && !o->xorgmode) o->xorgmode = 1; + + return o; + + bad_option: + + fprintf (stderr, "\n"); + fprintf (stderr, "usage: %s x y refresh [-v|--verbose] " + "[-f|--fbmode] [-x|--xorgmode]\n", argv[0]); + + fprintf (stderr, "\n"); + + fprintf (stderr, " x : the desired horizontal " + "resolution (required)\n"); + fprintf (stderr, " y : the desired vertical " + "resolution (required)\n"); + fprintf (stderr, " refresh : the desired refresh " + "rate (required)\n"); + fprintf (stderr, " -v|--verbose : enable verbose printouts " + "(traces each step of the computation)\n"); + fprintf (stderr, " -f|--fbmode : output an fbset(8)-style mode " + "description\n"); + fprintf (stderr, " -x|--xorgmode : output an "__XSERVERNAME__"-style mode " + "description (this is the default\n" + " if no mode description is requested)\n"); + + fprintf (stderr, "\n"); + + free (o); + return NULL; + +} + + + +int main (int argc, char *argv[]) +{ + mode *m; + options *o; + + o = parse_command_line (argc, argv); + if (!o) exit (1); + + m = vert_refresh (o->x, o->y, o->v_freq, 0, 0); + if (!m) exit (1); + + if (o->xorgmode) + print_xf86_mode(m); + + if (o->fbmode) + print_fb_mode(m); + + return 0; + +} diff --git a/xorg-server/hw/xfree86/vbe/vbe.c b/xorg-server/hw/xfree86/vbe/vbe.c index 06a628457..6ecca6858 100644 --- a/xorg-server/hw/xfree86/vbe/vbe.c +++ b/xorg-server/hw/xfree86/vbe/vbe.c @@ -170,7 +170,7 @@ vbeFree(vbeInfoPtr pVbe) static Bool vbeProbeDDC(vbeInfoPtr pVbe) { - char *ddc_level; + const char *ddc_level; int screen = pVbe->pInt10->scrnIndex; if (pVbe->ddc == DDC_NONE) diff --git a/xorg-server/hw/xfree86/x86emu/debug.c b/xorg-server/hw/xfree86/x86emu/debug.c index 5eda90805..04d0741e0 100644 --- a/xorg-server/hw/xfree86/x86emu/debug.c +++ b/xorg-server/hw/xfree86/x86emu/debug.c @@ -172,7 +172,7 @@ void x86emu_decode_printf (char *x) void x86emu_decode_printf2 (char *x, int y) { char temp[100]; - sprintf(temp,x,y); + snprintf(temp,sizeof(temp),x,y); sprintf(M.x86.decoded_buf+M.x86.enc_str_pos,"%s",temp); M.x86.enc_str_pos += strlen(temp); } -- cgit v1.2.3