From 8a191c08ddda2e66fa26f148d6c21959bb08f923 Mon Sep 17 00:00:00 2001 From: marha Date: Sun, 20 Feb 2011 12:29:25 +0000 Subject: xserver xkeyboard-config libX11 pixman mesa git update 2011 --- xorg-server/hw/xfree86/common/xf86Init.c | 2994 ++++++------ xorg-server/hw/xfree86/common/xf86VidMode.c | 2 +- xorg-server/hw/xfree86/common/xf86xv.c | 210 +- xorg-server/hw/xfree86/common/xf86xv.h | 3 + xorg-server/hw/xfree86/common/xf86xvpriv.h | 6 +- xorg-server/hw/xfree86/dri2/dri2.c | 2 +- xorg-server/hw/xfree86/fbdevhw/fbdevhw.c | 56 +- xorg-server/hw/xfree86/int10/helper_exec.c | 1466 +++--- xorg-server/hw/xfree86/modes/xf86Crtc.c | 6563 +++++++++++++-------------- 9 files changed, 5646 insertions(+), 5656 deletions(-) (limited to 'xorg-server/hw/xfree86') diff --git a/xorg-server/hw/xfree86/common/xf86Init.c b/xorg-server/hw/xfree86/common/xf86Init.c index a1fda54cd..e017d9dce 100644 --- a/xorg-server/hw/xfree86/common/xf86Init.c +++ b/xorg-server/hw/xfree86/common/xf86Init.c @@ -1,1497 +1,1497 @@ -/* - * Loosely based on code bearing the following copyright: - * - * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. - */ -/* - * Copyright (c) 1992-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). - */ - -#ifdef HAVE_XORG_CONFIG_H -#include -#endif - -#include -#include - -#undef HAS_UTSNAME -#if !defined(WIN32) -#define HAS_UTSNAME 1 -#include -#endif - -#include -#include -#include -#include -#include "input.h" -#include "servermd.h" -#include "windowstr.h" -#include "scrnintstr.h" -#include "site.h" -#include "mi.h" - -#include "compiler.h" - -#include "loaderProcs.h" -#ifdef XFreeXDGA -#include "dgaproc.h" -#endif - -#define XF86_OS_PRIVS -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86Config.h" -#include "xf86_OSlib.h" -#include "xf86cmap.h" -#include "xorgVersion.h" -#include "xf86Build.h" -#include "mipointer.h" -#include -#include -#include "xf86DDC.h" -#include "xf86Xinput.h" -#include "xf86InPriv.h" -#include "picturestr.h" - -#include "xf86Bus.h" -#include "xf86VGAarbiter.h" -#include "globals.h" - -#ifdef DPMSExtension -#include -#include "dpmsproc.h" -#endif -#include - - -#ifdef XF86PM -void (*xf86OSPMClose)(void) = NULL; -#endif -static Bool xorgHWOpenConsole = FALSE; - -/* Common pixmap formats */ - -static PixmapFormatRec formats[MAXFORMATS] = { - { 1, 1, BITMAP_SCANLINE_PAD }, - { 4, 8, BITMAP_SCANLINE_PAD }, - { 8, 8, BITMAP_SCANLINE_PAD }, - { 15, 16, BITMAP_SCANLINE_PAD }, - { 16, 16, BITMAP_SCANLINE_PAD }, - { 24, 32, BITMAP_SCANLINE_PAD }, - { 32, 32, BITMAP_SCANLINE_PAD }, -}; -static int numFormats = 7; -static Bool formatsDone = FALSE; - -#ifndef OSNAME -#define OSNAME " unknown" -#endif -#ifndef OSVENDOR -#define OSVENDOR "" -#endif -#ifndef PRE_RELEASE -#define PRE_RELEASE XORG_VERSION_SNAP -#endif - -static void -xf86PrintBanner(void) -{ -#if PRE_RELEASE - xf86ErrorFVerb(0, "\n" - "This is a pre-release version of the X server from " XVENDORNAME ".\n" - "It is not supported in any way.\n" - "Bugs may be filed in the bugzilla at http://bugs.freedesktop.org/.\n" - "Select the \"xorg\" product for bugs you find in this release.\n" - "Before reporting bugs in pre-release versions please check the\n" - "latest version in the X.Org Foundation git repository.\n" - "See http://wiki.x.org/wiki/GitPage for git access instructions.\n"); -#endif - xf86ErrorFVerb(0, "\nX.Org X Server %d.%d.%d", - XORG_VERSION_MAJOR, - XORG_VERSION_MINOR, - XORG_VERSION_PATCH); -#if XORG_VERSION_SNAP > 0 - xf86ErrorFVerb(0, ".%d", XORG_VERSION_SNAP); -#endif - -#if XORG_VERSION_SNAP >= 900 - /* When the minor number is 99, that signifies that the we are making - * a release candidate for a major version. (X.0.0) - * When the patch number is 99, that signifies that the we are making - * a release candidate for a minor version. (X.Y.0) - * When the patch number is < 99, then we are making a release - * candidate for the next point release. (X.Y.Z) - */ -#if XORG_VERSION_MINOR >= 99 - xf86ErrorFVerb(0, " (%d.0.0 RC %d)", XORG_VERSION_MAJOR+1, - XORG_VERSION_SNAP - 900); -#elif XORG_VERSION_PATCH == 99 - xf86ErrorFVerb(0, " (%d.%d.0 RC %d)", XORG_VERSION_MAJOR, - XORG_VERSION_MINOR + 1, XORG_VERSION_SNAP - 900); -#else - xf86ErrorFVerb(0, " (%d.%d.%d RC %d)", XORG_VERSION_MAJOR, - XORG_VERSION_MINOR, XORG_VERSION_PATCH + 1, - XORG_VERSION_SNAP - 900); -#endif -#endif - -#ifdef XORG_CUSTOM_VERSION - xf86ErrorFVerb(0, " (%s)", XORG_CUSTOM_VERSION); -#endif -#ifndef XORG_DATE -# define XORG_DATE "Unknown" -#endif - xf86ErrorFVerb(0, "\nRelease Date: %s\n", XORG_DATE); - xf86ErrorFVerb(0, "X Protocol Version %d, Revision %d\n", - X_PROTOCOL, X_PROTOCOL_REVISION); - xf86ErrorFVerb(0, "Build Operating System: %s %s\n", OSNAME, OSVENDOR); -#ifdef HAS_UTSNAME - { - struct utsname name; - - /* Linux & BSD state that 0 is success, SysV (including Solaris, HP-UX, - and Irix) and Single Unix Spec 3 just say that non-negative is success. - All agree that failure is represented by a negative number. - */ - if (uname(&name) >= 0) { - xf86ErrorFVerb(0, "Current Operating System: %s %s %s %s %s\n", - name.sysname, name.nodename, name.release, name.version, name.machine); -#ifdef linux - do { - char buf[80]; - int fd = open("/proc/cmdline", O_RDONLY); - if (fd != -1) { - xf86ErrorFVerb(0, "Kernel command line: "); - memset(buf, 0, 80); - while (read(fd, buf, 80) > 0) { - xf86ErrorFVerb(0, "%.80s", buf); - memset(buf, 0, 80); - } - close(fd); - } - } while (0); -#endif - } - } -#endif -#if defined(BUILD_DATE) && (BUILD_DATE > 19000000) - { - struct tm t; - char buf[100]; - - memset(&t, 0, sizeof(t)); - memset(buf, 0, sizeof(buf)); - t.tm_mday = BUILD_DATE % 100; - t.tm_mon = (BUILD_DATE / 100) % 100 - 1; - t.tm_year = BUILD_DATE / 10000 - 1900; -#if defined(BUILD_TIME) - t.tm_sec = BUILD_TIME % 100; - t.tm_min = (BUILD_TIME / 100) % 100; - t.tm_hour = (BUILD_TIME / 10000) % 100; - if (strftime(buf, sizeof(buf), "%d %B %Y %I:%M:%S%p", &t)) - xf86ErrorFVerb(0, "Build Date: %s\n", buf); -#else - if (strftime(buf, sizeof(buf), "%d %B %Y", &t)) - xf86ErrorFVerb(0, "Build Date: %s\n", buf); -#endif - } -#endif -#if defined(BUILDERSTRING) - xf86ErrorFVerb(0, "%s \n", BUILDERSTRING); -#endif - xf86ErrorFVerb(0, "Current version of pixman: %s\n", - pixman_version_string()); - xf86ErrorFVerb(0, "\tBefore reporting problems, check " - ""__VENDORDWEBSUPPORT__"\n" - "\tto make sure that you have the latest version.\n"); -} - -static void -xf86PrintMarkers(void) -{ - LogPrintMarkers(); -} - -static Bool -xf86CreateRootWindow(WindowPtr pWin) -{ - int ret = TRUE; - int err = Success; - ScreenPtr pScreen = pWin->drawable.pScreen; - RootWinPropPtr pProp; - CreateWindowProcPtr CreateWindow = (CreateWindowProcPtr) - dixLookupPrivate(&pScreen->devPrivates, xf86CreateRootWindowKey); - - DebugF("xf86CreateRootWindow(%p)\n", pWin); - - if ( pScreen->CreateWindow != xf86CreateRootWindow ) { - /* Can't find hook we are hung on */ - xf86DrvMsg(pScreen->myNum, X_WARNING /* X_ERROR */, - "xf86CreateRootWindow %p called when not in pScreen->CreateWindow %p n", - (void *)xf86CreateRootWindow, - (void *)pScreen->CreateWindow ); - } - - /* Unhook this function ... */ - pScreen->CreateWindow = CreateWindow; - dixSetPrivate(&pScreen->devPrivates, xf86CreateRootWindowKey, NULL); - - /* ... and call the previous CreateWindow fuction, if any */ - if (NULL!=pScreen->CreateWindow) { - ret = (*pScreen->CreateWindow)(pWin); - } - - /* Now do our stuff */ - if (xf86RegisteredPropertiesTable != NULL) { - if (pWin->parent == NULL && xf86RegisteredPropertiesTable != NULL) { - for (pProp = xf86RegisteredPropertiesTable[pScreen->myNum]; - pProp != NULL && err==Success; - pProp = pProp->next ) - { - Atom prop; - - prop = MakeAtom(pProp->name, strlen(pProp->name), TRUE); - err = dixChangeWindowProperty(serverClient, pWin, - prop, pProp->type, - pProp->format, PropModeReplace, - pProp->size, pProp->data, - FALSE); - } - - /* Look at err */ - ret &= (err==Success); - - } else { - xf86Msg(X_ERROR, "xf86CreateRootWindow unexpectedly called with " - "non-root window %p (parent %p)\n", - (void *)pWin, (void *)pWin->parent); - ret = FALSE; - } - } - - DebugF("xf86CreateRootWindow() returns %d\n", ret); - return ret; -} - - -static void -InstallSignalHandlers(void) -{ - /* - * Install signal handler for unexpected signals - */ - xf86Info.caughtSignal=FALSE; - if (!xf86Info.notrapSignals) { - OsRegisterSigWrapper(xf86SigWrapper); - } else { - signal(SIGSEGV, SIG_DFL); - signal(SIGILL, SIG_DFL); -#ifdef SIGEMT - signal(SIGEMT, SIG_DFL); -#endif - signal(SIGFPE, SIG_DFL); - signal(SIGBUS, SIG_DFL); - signal(SIGSYS, SIG_DFL); - signal(SIGXCPU, SIG_DFL); - signal(SIGXFSZ, SIG_DFL); - } -} - -/* - * InitOutput -- - * Initialize screenInfo for all actually accessible framebuffers. - * That includes vt-manager setup, querying all possible devices and - * collecting the pixmap formats. - */ -void -InitOutput(ScreenInfo *pScreenInfo, int argc, char **argv) -{ - int i, j, k, scr_index, was_blocked = 0; - char **modulelist; - pointer *optionlist; - Pix24Flags screenpix24, pix24; - MessageType pix24From = X_DEFAULT; - Bool pix24Fail = FALSE; - Bool autoconfig = FALSE; - GDevPtr configured_device; - - xf86Initialising = TRUE; - - if (serverGeneration == 1) { - if ((xf86ServerName = strrchr(argv[0], '/')) != 0) - xf86ServerName++; - else - xf86ServerName = argv[0]; - - xf86PrintBanner(); - xf86PrintMarkers(); - if (xf86LogFile) { - time_t t; - const char *ct; - t = time(NULL); - ct = ctime(&t); - xf86MsgVerb(xf86LogFileFrom, 0, "Log file: \"%s\", Time: %s", - xf86LogFile, ct); - } - - /* Read and parse the config file */ - if (!xf86DoConfigure && !xf86DoShowOptions) { - switch (xf86HandleConfigFile(FALSE)) { - case CONFIG_OK: - break; - case CONFIG_PARSE_ERROR: - xf86Msg(X_ERROR, "Error parsing the config file\n"); - return; - case CONFIG_NOFILE: - autoconfig = TRUE; - break; - } - } - - InstallSignalHandlers(); - - /* Initialise the loader */ - LoaderInit(); - - /* Tell the loader the default module search path */ - LoaderSetPath(xf86ModulePath); - - if (xf86Info.ignoreABI) { - LoaderSetOptions(LDR_OPT_ABI_MISMATCH_NONFATAL); - } - - if (xf86DoShowOptions) - DoShowOptions(); - - /* Do a general bus probe. This will be a PCI probe for x86 platforms */ - xf86BusProbe(); - - if (xf86DoConfigure) - DoConfigure(); - - if (autoconfig) { - if (!xf86AutoConfig()) { - xf86Msg(X_ERROR, "Auto configuration failed\n"); - return; - } - } - -#ifdef XF86PM - xf86OSPMClose = xf86OSPMOpen(); -#endif - - /* Load all modules specified explicitly in the config file */ - if ((modulelist = xf86ModulelistFromConfig(&optionlist))) { - xf86LoadModules(modulelist, optionlist); - free(modulelist); - free(optionlist); - } - - /* Load all driver modules specified in the config file */ - /* If there aren't any specified in the config file, autoconfig them */ - /* FIXME: Does not handle multiple active screen sections, but I'm not - * sure if we really want to handle that case*/ - configured_device = xf86ConfigLayout.screens->screen->device; - if ((!configured_device) || (!configured_device->driver)) { - if (!autoConfigDevice(configured_device)) { - xf86Msg(X_ERROR, "Automatic driver configuration failed\n"); - return ; - } - } - if ((modulelist = xf86DriverlistFromConfig())) { - xf86LoadModules(modulelist, NULL); - free(modulelist); - } - - /* Load all input driver modules specified in the config file. */ - if ((modulelist = xf86InputDriverlistFromConfig())) { - xf86LoadModules(modulelist, NULL); - free(modulelist); - } - - /* - * It is expected that xf86AddDriver()/xf86AddInputDriver will be - * called for each driver as it is loaded. Those functions save the - * module pointers for drivers. - * XXX Nothing keeps track of them for other modules. - */ - /* XXX What do we do if not all of these could be loaded? */ - - /* - * At this point, xf86DriverList[] is all filled in with entries for - * each of the drivers to try and xf86NumDrivers has the number of - * drivers. If there are none, return now. - */ - - if (xf86NumDrivers == 0) { - xf86Msg(X_ERROR, "No drivers available.\n"); - return; - } - - /* - * Call each of the Identify functions and call the driverFunc to check - * if HW access is required. The Identify functions print out some - * identifying information, and anything else that might be - * needed at this early stage. - */ - - for (i = 0; i < xf86NumDrivers; i++) { - if (xf86DriverList[i]->Identify != NULL) - xf86DriverList[i]->Identify(0); - - if (!xorgHWAccess || !xorgHWOpenConsole) { - xorgHWFlags flags; - if(!xf86DriverList[i]->driverFunc - || !xf86DriverList[i]->driverFunc(NULL, - GET_REQUIRED_HW_INTERFACES, - &flags)) - flags = HW_IO; - - if(NEED_IO_ENABLED(flags)) - xorgHWAccess = TRUE; - if(!(flags & HW_SKIP_CONSOLE)) - xorgHWOpenConsole = TRUE; - } - } - - if (xorgHWOpenConsole) - xf86OpenConsole(); - else - xf86Info.dontVTSwitch = TRUE; - - if (xf86BusConfig() == FALSE) - return; - - xf86PostProbe(); - - /* - * Sort the drivers to match the requested ording. Using a slow - * bubble sort. - */ - for (j = 0; j < xf86NumScreens - 1; j++) { - for (i = 0; i < xf86NumScreens - j - 1; i++) { - if (xf86Screens[i + 1]->confScreen->screennum < - xf86Screens[i]->confScreen->screennum) { - ScrnInfoPtr tmpScrn = xf86Screens[i + 1]; - xf86Screens[i + 1] = xf86Screens[i]; - xf86Screens[i] = tmpScrn; - } - } - } - /* Fix up the indexes */ - for (i = 0; i < xf86NumScreens; i++) { - xf86Screens[i]->scrnIndex = i; - } - - /* - * Call the driver's PreInit()'s to complete initialisation for the first - * generation. - */ - - for (i = 0; i < xf86NumScreens; i++) { - xf86VGAarbiterScrnInit(xf86Screens[i]); - xf86VGAarbiterLock(xf86Screens[i]); - if (xf86Screens[i]->PreInit && - xf86Screens[i]->PreInit(xf86Screens[i], 0)) - xf86Screens[i]->configured = TRUE; - xf86VGAarbiterUnlock(xf86Screens[i]); - } - for (i = 0; i < xf86NumScreens; i++) - if (!xf86Screens[i]->configured) - xf86DeleteScreen(i--, 0); - - /* - * If no screens left, return now. - */ - - if (xf86NumScreens == 0) { - xf86Msg(X_ERROR, - "Screen(s) found, but none have a usable configuration.\n"); - return; - } - - for (i = 0; i < xf86NumScreens; i++) { - if (xf86Screens[i]->name == NULL) { - XNFasprintf(&xf86Screens[i]->name, "screen%d", i); - xf86MsgVerb(X_WARNING, 0, - "Screen driver %d has no name set, using `%s'.\n", - i, xf86Screens[i]->name); - } - } - - /* Remove (unload) drivers that are not required */ - for (i = 0; i < xf86NumDrivers; i++) - if (xf86DriverList[i] && xf86DriverList[i]->refCount <= 0) - xf86DeleteDriver(i); - - /* - * At this stage we know how many screens there are. - */ - - for (i = 0; i < xf86NumScreens; i++) - xf86InitViewport(xf86Screens[i]); - - /* - * Collect all pixmap formats and check for conflicts at the display - * level. Should we die here? Or just delete the offending screens? - */ - screenpix24 = Pix24DontCare; - for (i = 0; i < xf86NumScreens; i++) { - if (xf86Screens[i]->imageByteOrder != - xf86Screens[0]->imageByteOrder) - FatalError("Inconsistent display bitmapBitOrder. Exiting\n"); - if (xf86Screens[i]->bitmapScanlinePad != - xf86Screens[0]->bitmapScanlinePad) - FatalError("Inconsistent display bitmapScanlinePad. Exiting\n"); - if (xf86Screens[i]->bitmapScanlineUnit != - xf86Screens[0]->bitmapScanlineUnit) - FatalError("Inconsistent display bitmapScanlineUnit. Exiting\n"); - if (xf86Screens[i]->bitmapBitOrder != - xf86Screens[0]->bitmapBitOrder) - FatalError("Inconsistent display bitmapBitOrder. Exiting\n"); - - /* Determine the depth 24 pixmap format the screens would like */ - if (xf86Screens[i]->pixmap24 != Pix24DontCare) { - if (screenpix24 == Pix24DontCare) - screenpix24 = xf86Screens[i]->pixmap24; - else if (screenpix24 != xf86Screens[i]->pixmap24) - FatalError("Inconsistent depth 24 pixmap format. Exiting\n"); - } - } - /* check if screenpix24 is consistent with the config/cmdline */ - if (xf86Info.pixmap24 != Pix24DontCare) { - pix24 = xf86Info.pixmap24; - pix24From = xf86Info.pix24From; - if (screenpix24 != Pix24DontCare && screenpix24 != xf86Info.pixmap24) - pix24Fail = TRUE; - } else if (screenpix24 != Pix24DontCare) { - pix24 = screenpix24; - pix24From = X_PROBED; - } else - pix24 = Pix24Use32; - - if (pix24Fail) - FatalError("Screen(s) can't use the required depth 24 pixmap format" - " (%d). Exiting\n", PIX24TOBPP(pix24)); - - /* Initialise the depth 24 format */ - for (j = 0; j < numFormats && formats[j].depth != 24; j++) - ; - formats[j].bitsPerPixel = PIX24TOBPP(pix24); - - /* Collect additional formats */ - for (i = 0; i < xf86NumScreens; i++) { - for (j = 0; j < xf86Screens[i]->numFormats; j++) { - for (k = 0; ; k++) { - if (k >= numFormats) { - if (k >= MAXFORMATS) - FatalError("Too many pixmap formats! Exiting\n"); - formats[k] = xf86Screens[i]->formats[j]; - numFormats++; - break; - } - if (formats[k].depth == xf86Screens[i]->formats[j].depth) { - if ((formats[k].bitsPerPixel == - xf86Screens[i]->formats[j].bitsPerPixel) && - (formats[k].scanlinePad == - xf86Screens[i]->formats[j].scanlinePad)) - break; - FatalError("Inconsistent pixmap format for depth %d." - " Exiting\n", formats[k].depth); - } - } - } - } - formatsDone = TRUE; - - if (xf86Info.vtno >= 0 ) { -#define VT_ATOM_NAME "XFree86_VT" - Atom VTAtom=-1; - CARD32 *VT = NULL; - int ret; - - /* This memory needs to stay available until the screen has been - initialized, and we can create the property for real. - */ - if ( (VT = malloc(sizeof(CARD32)))==NULL ) { - FatalError("Unable to make VT property - out of memory. Exiting...\n"); - } - *VT = xf86Info.vtno; - - VTAtom = MakeAtom(VT_ATOM_NAME, sizeof(VT_ATOM_NAME) - 1, TRUE); - - for (i = 0, ret = Success; i < xf86NumScreens && ret == Success; i++) { - ret = xf86RegisterRootWindowProperty(xf86Screens[i]->scrnIndex, - VTAtom, XA_INTEGER, 32, - 1, VT ); - if (ret != Success) - xf86DrvMsg(xf86Screens[i]->scrnIndex, X_WARNING, - "Failed to register VT property\n"); - } - } - - /* If a screen uses depth 24, show what the pixmap format is */ - for (i = 0; i < xf86NumScreens; i++) { - if (xf86Screens[i]->depth == 24) { - xf86Msg(pix24From, "Depth 24 pixmap format is %d bpp\n", - PIX24TOBPP(pix24)); - break; - } - } - } else { - /* - * serverGeneration != 1; some OSs have to do things here, too. - */ - if (xorgHWOpenConsole) - xf86OpenConsole(); - -#ifdef XF86PM - /* - should we reopen it here? We need to deal with an already opened - device. We could leave this to the OS layer. For now we simply - close it here - */ - if (xf86OSPMClose) - xf86OSPMClose(); - if ((xf86OSPMClose = xf86OSPMOpen()) != NULL) - xf86MsgVerb(X_INFO, 3, "APM registered successfully\n"); -#endif - - /* Make sure full I/O access is enabled */ - if (xorgHWAccess) - xf86EnableIO(); - } - - /* - * Use the previously collected parts to setup pScreenInfo - */ - - pScreenInfo->imageByteOrder = xf86Screens[0]->imageByteOrder; - pScreenInfo->bitmapScanlinePad = xf86Screens[0]->bitmapScanlinePad; - pScreenInfo->bitmapScanlineUnit = xf86Screens[0]->bitmapScanlineUnit; - pScreenInfo->bitmapBitOrder = xf86Screens[0]->bitmapBitOrder; - pScreenInfo->numPixmapFormats = numFormats; - for (i = 0; i < numFormats; i++) - pScreenInfo->formats[i] = formats[i]; - - /* Make sure the server's VT is active */ - - if (serverGeneration != 1) { - xf86Resetting = TRUE; - /* All screens are in the same state, so just check the first */ - if (!xf86Screens[0]->vtSema) { -#ifdef HAS_USL_VTS - ioctl(xf86Info.consoleFd, VT_RELDISP, VT_ACKACQ); -#endif - xf86AccessEnter(); - was_blocked = xf86BlockSIGIO(); - } - } - - for (i = 0; i < xf86NumScreens; i++) - if (!xf86ColormapAllocatePrivates(xf86Screens[i])) - FatalError("Cannot register DDX private keys"); - - if (!dixRegisterPrivateKey(&xf86ScreenKeyRec, PRIVATE_SCREEN, 0) || - !dixRegisterPrivateKey(&xf86CreateRootWindowKeyRec, PRIVATE_SCREEN, 0)) - FatalError("Cannot register DDX private keys"); - - for (i = 0; i < xf86NumScreens; i++) { - xf86VGAarbiterLock(xf86Screens[i]); - /* - * Almost everything uses these defaults, and many of those that - * don't, will wrap them. - */ - xf86Screens[i]->EnableDisableFBAccess = xf86EnableDisableFBAccess; -#ifdef XFreeXDGA - xf86Screens[i]->SetDGAMode = xf86SetDGAMode; -#endif - xf86Screens[i]->DPMSSet = NULL; - xf86Screens[i]->LoadPalette = NULL; - xf86Screens[i]->SetOverscan = NULL; - xf86Screens[i]->DriverFunc = NULL; - xf86Screens[i]->pScreen = NULL; - scr_index = AddScreen(xf86Screens[i]->ScreenInit, argc, argv); - xf86VGAarbiterUnlock(xf86Screens[i]); - if (scr_index == i) { - /* - * Hook in our ScrnInfoRec, and initialise some other pScreen - * fields. - */ - dixSetPrivate(&screenInfo.screens[scr_index]->devPrivates, - xf86ScreenKey, xf86Screens[i]); - xf86Screens[i]->pScreen = screenInfo.screens[scr_index]; - /* The driver should set this, but make sure it is set anyway */ - xf86Screens[i]->vtSema = TRUE; - } else { - /* This shouldn't normally happen */ - FatalError("AddScreen/ScreenInit failed for driver %d\n", i); - } - - DebugF("InitOutput - xf86Screens[%d]->pScreen = %p\n", - i, xf86Screens[i]->pScreen ); - DebugF("xf86Screens[%d]->pScreen->CreateWindow = %p\n", - i, xf86Screens[i]->pScreen->CreateWindow ); - - dixSetPrivate(&screenInfo.screens[scr_index]->devPrivates, - xf86CreateRootWindowKey, - xf86Screens[i]->pScreen->CreateWindow); - xf86Screens[i]->pScreen->CreateWindow = xf86CreateRootWindow; - - if (PictureGetSubpixelOrder (xf86Screens[i]->pScreen) == SubPixelUnknown) - { - xf86MonPtr DDC = (xf86MonPtr)(xf86Screens[i]->monitor->DDC); - PictureSetSubpixelOrder (xf86Screens[i]->pScreen, - DDC ? - (DDC->features.input_type ? - SubPixelHorizontalRGB : SubPixelNone) : - SubPixelUnknown); - } -#ifdef RANDR - if (!xf86Info.disableRandR) - xf86RandRInit (screenInfo.screens[scr_index]); - xf86Msg(xf86Info.randRFrom, "RandR %s\n", - xf86Info.disableRandR ? "disabled" : "enabled"); -#endif - } - - xf86VGAarbiterWrapFunctions(); - xf86UnblockSIGIO(was_blocked); - - xf86InitOrigins(); - - xf86Resetting = FALSE; - xf86Initialising = FALSE; - - RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, xf86Wakeup, - NULL); -} - -/* - * InitInput -- - * Initialize all supported input devices. - */ - -void -InitInput(int argc, char **argv) -{ - InputInfoPtr* pDev; - DeviceIntPtr dev; - - xf86Info.vtRequestsPending = FALSE; - - mieqInit(); - - GetEventList(&xf86Events); - - /* Call the PreInit function for each input device instance. */ - for (pDev = xf86ConfigLayout.inputs; pDev && *pDev; pDev++) { - /* Replace obsolete keyboard driver with kbd */ - if (!xf86NameCmp((*pDev)->driver, "keyboard")) { - strcpy((*pDev)->driver, "kbd"); - } - - /* If one fails, the others will too */ - if (xf86NewInputDevice(*pDev, &dev, TRUE) == BadAlloc) - break; - } - - config_init(); -} - -void -CloseInput (void) -{ - config_fini(); -} - -/* - * OsVendorInit -- - * OS/Vendor-specific initialisations. Called from OsInit(), which - * is called by dix before establishing the well known sockets. - */ - -void -OsVendorInit(void) -{ - static Bool beenHere = FALSE; - - signal(SIGCHLD, SIG_DFL); /* Need to wait for child processes */ - - if (!beenHere) { - umask(022); - xf86LogInit(); - } - - /* Set stderr to non-blocking. */ -#ifndef O_NONBLOCK -#if defined(FNDELAY) -#define O_NONBLOCK FNDELAY -#elif defined(O_NDELAY) -#define O_NONBLOCK O_NDELAY -#endif - -#ifdef O_NONBLOCK - if (!beenHere) { - if (geteuid() == 0 && getuid() != geteuid()) - { - int status; - - status = fcntl(fileno(stderr), F_GETFL, 0); - if (status != -1) { - fcntl(fileno(stderr), F_SETFL, status | O_NONBLOCK); - } - } - } -#endif -#endif - - beenHere = TRUE; -} - -/* - * ddxGiveUp -- - * Device dependent cleanup. Called by by dix before normal server death. - * For SYSV386 we must switch the terminal back to normal mode. No error- - * checking here, since there should be restored as much as possible. - */ - -void -ddxGiveUp(void) -{ - int i; - - xf86VGAarbiterFini(); - -#ifdef XF86PM - if (xf86OSPMClose) - xf86OSPMClose(); - xf86OSPMClose = NULL; -#endif - - for (i = 0; i < xf86NumScreens; i++) { - /* - * zero all access functions to - * trap calls when switched away. - */ - xf86Screens[i]->vtSema = FALSE; - } - -#ifdef XFreeXDGA - DGAShutdown(); -#endif - - if (xorgHWOpenConsole) - xf86CloseConsole(); - - xf86CloseLog(); - - /* If an unexpected signal was caught, dump a core for debugging */ - if (xf86Info.caughtSignal) - OsAbort(); -} - - - -/* - * AbortDDX -- - * DDX - specific abort routine. Called by AbortServer(). The attempt is - * made to restore all original setting of the displays. Also all devices - * are closed. - */ - -void -AbortDDX(void) -{ - int i; - - xf86BlockSIGIO(); - - /* - * try to restore the original video state - */ -#ifdef DPMSExtension /* Turn screens back on */ - if (DPMSPowerLevel != DPMSModeOn) - DPMSSet(serverClient, DPMSModeOn); -#endif - if (xf86Screens) { - for (i = 0; i < xf86NumScreens; i++) - if (xf86Screens[i]->vtSema) { - /* - * if we are aborting before ScreenInit() has finished - * we might not have been wrapped yet. Therefore enable - * screen explicitely. - */ - xf86VGAarbiterLock(xf86Screens[i]); - (xf86Screens[i]->LeaveVT)(i, 0); - xf86VGAarbiterUnlock(xf86Screens[i]); - } - } - - xf86AccessLeave(); - - /* - * This is needed for an abnormal server exit, since the normal exit stuff - * MUST also be performed (i.e. the vt must be left in a defined state) - */ - ddxGiveUp(); -} - -void -OsVendorFatalError(void) -{ -#ifdef VENDORSUPPORT - ErrorF("\nPlease refer to your Operating System Vendor support pages\n" - "at %s for support on this crash.\n",VENDORSUPPORT); -#else - ErrorF("\nPlease consult the "XVENDORNAME" support \n" - "\t at "__VENDORDWEBSUPPORT__"\n for help. \n"); -#endif - if (xf86LogFile && xf86LogFileWasOpened) - ErrorF("Please also check the log file at \"%s\" for additional " - "information.\n", xf86LogFile); - ErrorF("\n"); -} - -int -xf86SetVerbosity(int verb) -{ - int save = xf86Verbose; - - xf86Verbose = verb; - LogSetParameter(XLOG_VERBOSITY, verb); - return save; -} - -int -xf86SetLogVerbosity(int verb) -{ - int save = xf86LogVerbose; - - xf86LogVerbose = verb; - LogSetParameter(XLOG_FILE_VERBOSITY, verb); - return save; -} - -static void -xf86PrintDefaultModulePath(void) -{ - ErrorF("%s\n", DEFAULT_MODULE_PATH); -} - -static void -xf86PrintDefaultLibraryPath(void) -{ - ErrorF("%s\n", DEFAULT_LIBRARY_PATH); -} - -/* - * ddxProcessArgument -- - * Process device-dependent command line args. Returns 0 if argument is - * not device dependent, otherwise Count of number of elements of argv - * that are part of a device dependent commandline option. - * - */ - -/* ARGSUSED */ -int -ddxProcessArgument(int argc, char **argv, int i) -{ -#define CHECK_FOR_REQUIRED_ARGUMENT() \ - if (((i + 1) >= argc) || (!argv[i + 1])) { \ - ErrorF("Required argument to %s not specified\n", argv[i]); \ - UseMsg(); \ - FatalError("Required argument to %s not specified\n", argv[i]); \ - } - - /* First the options that are only allowed for root */ - if (!strcmp(argv[i], "-modulepath") || !strcmp(argv[i], "-logfile")) { - if ( (geteuid() == 0) && (getuid() != 0) ) { - FatalError("The '%s' option can only be used by root.\n", argv[i]); - } - else if (!strcmp(argv[i], "-modulepath")) - { - char *mp; - CHECK_FOR_REQUIRED_ARGUMENT(); - mp = strdup(argv[i + 1]); - if (!mp) - FatalError("Can't allocate memory for ModulePath\n"); - xf86ModulePath = mp; - xf86ModPathFrom = X_CMDLINE; - return 2; - } - else if (!strcmp(argv[i], "-logfile")) - { - char *lf; - CHECK_FOR_REQUIRED_ARGUMENT(); - lf = strdup(argv[i + 1]); - if (!lf) - FatalError("Can't allocate memory for LogFile\n"); - xf86LogFile = lf; - xf86LogFileFrom = X_CMDLINE; - return 2; - } - } - if (!strcmp(argv[i], "-config") || !strcmp(argv[i], "-xf86config")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - if (getuid() != 0 && !xf86PathIsSafe(argv[i + 1])) { - FatalError("\nInvalid argument for %s\n" - "\tFor non-root users, the file specified with %s must be\n" - "\ta relative path and must not contain any \"..\" elements.\n" - "\tUsing default "__XCONFIGFILE__" search path.\n\n", - argv[i], argv[i]); - } - xf86ConfigFile = argv[i + 1]; - return 2; - } - if (!strcmp(argv[i], "-configdir")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - if (getuid() != 0 && !xf86PathIsSafe(argv[i + 1])) { - FatalError("\nInvalid argument for %s\n" - "\tFor non-root users, the file specified with %s must be\n" - "\ta relative path and must not contain any \"..\" elements.\n" - "\tUsing default "__XCONFIGDIR__" search path.\n\n", - argv[i], argv[i]); - } - xf86ConfigDir = argv[i + 1]; - return 2; - } - if (!strcmp(argv[i],"-flipPixels")) - { - xf86FlipPixels = TRUE; - return 1; - } -#ifdef XF86VIDMODE - if (!strcmp(argv[i],"-disableVidMode")) - { - xf86VidModeDisabled = TRUE; - return 1; - } - if (!strcmp(argv[i],"-allowNonLocalXvidtune")) - { - xf86VidModeAllowNonLocal = TRUE; - return 1; - } -#endif - if (!strcmp(argv[i],"-allowMouseOpenFail")) - { - xf86AllowMouseOpenFail = TRUE; - return 1; - } - if (!strcmp(argv[i],"-ignoreABI")) - { - LoaderSetOptions(LDR_OPT_ABI_MISMATCH_NONFATAL); - return 1; - } - if (!strcmp(argv[i],"-verbose")) - { - if (++i < argc && argv[i]) - { - char *end; - long val; - val = strtol(argv[i], &end, 0); - if (*end == '\0') - { - xf86SetVerbosity(val); - return 2; - } - } - xf86SetVerbosity(++xf86Verbose); - return 1; - } - if (!strcmp(argv[i],"-logverbose")) - { - if (++i < argc && argv[i]) - { - char *end; - long val; - val = strtol(argv[i], &end, 0); - if (*end == '\0') - { - xf86SetLogVerbosity(val); - return 2; - } - } - xf86SetLogVerbosity(++xf86LogVerbose); - return 1; - } - if (!strcmp(argv[i],"-quiet")) - { - xf86SetVerbosity(-1); - return 1; - } - if (!strcmp(argv[i],"-showconfig") || !strcmp(argv[i],"-version")) - { - xf86PrintBanner(); - exit(0); - } - if (!strcmp(argv[i],"-showDefaultModulePath")) - { - xf86PrintDefaultModulePath(); - exit(0); - } - if (!strcmp(argv[i],"-showDefaultLibPath")) - { - xf86PrintDefaultLibraryPath(); - exit(0); - } - /* Notice the -fp flag, but allow it to pass to the dix layer */ - if (!strcmp(argv[i], "-fp")) - { - xf86fpFlag = TRUE; - return 0; - } - /* Notice the -bs flag, but allow it to pass to the dix layer */ - if (!strcmp(argv[i], "-bs")) - { - xf86bsDisableFlag = TRUE; - return 0; - } - /* Notice the +bs flag, but allow it to pass to the dix layer */ - if (!strcmp(argv[i], "+bs")) - { - xf86bsEnableFlag = TRUE; - return 0; - } - /* Notice the -s flag, but allow it to pass to the dix layer */ - if (!strcmp(argv[i], "-s")) - { - xf86sFlag = TRUE; - return 0; - } - if (!strcmp(argv[i], "-pixmap24")) - { - xf86Pix24 = Pix24Use24; - return 1; - } - if (!strcmp(argv[i], "-pixmap32")) - { - xf86Pix24 = Pix24Use32; - return 1; - } - if (!strcmp(argv[i], "-fbbpp")) - { - int bpp; - CHECK_FOR_REQUIRED_ARGUMENT(); - if (sscanf(argv[++i], "%d", &bpp) == 1) - { - xf86FbBpp = bpp; - return 2; - } - else - { - ErrorF("Invalid fbbpp\n"); - return 0; - } - } - if (!strcmp(argv[i], "-depth")) - { - int depth; - CHECK_FOR_REQUIRED_ARGUMENT(); - if (sscanf(argv[++i], "%d", &depth) == 1) - { - xf86Depth = depth; - return 2; - } - else - { - ErrorF("Invalid depth\n"); - return 0; - } - } - if (!strcmp(argv[i], "-weight")) - { - int red, green, blue; - CHECK_FOR_REQUIRED_ARGUMENT(); - if (sscanf(argv[++i], "%1d%1d%1d", &red, &green, &blue) == 3) - { - xf86Weight.red = red; - xf86Weight.green = green; - xf86Weight.blue = blue; - return 2; - } - else - { - ErrorF("Invalid weighting\n"); - return 0; - } - } - if (!strcmp(argv[i], "-gamma") || !strcmp(argv[i], "-rgamma") || - !strcmp(argv[i], "-ggamma") || !strcmp(argv[i], "-bgamma")) - { - double gamma; - CHECK_FOR_REQUIRED_ARGUMENT(); - if (sscanf(argv[++i], "%lf", &gamma) == 1) { - if (gamma < GAMMA_MIN || gamma > GAMMA_MAX) { - ErrorF("gamma out of range, only %.2f <= gamma_value <= %.1f" - " is valid\n", GAMMA_MIN, GAMMA_MAX); - return 0; - } - if (!strcmp(argv[i-1], "-gamma")) - xf86Gamma.red = xf86Gamma.green = xf86Gamma.blue = gamma; - else if (!strcmp(argv[i-1], "-rgamma")) xf86Gamma.red = gamma; - else if (!strcmp(argv[i-1], "-ggamma")) xf86Gamma.green = gamma; - else if (!strcmp(argv[i-1], "-bgamma")) xf86Gamma.blue = gamma; - return 2; - } - } - if (!strcmp(argv[i], "-layout")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - xf86LayoutName = argv[++i]; - return 2; - } - if (!strcmp(argv[i], "-screen")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - xf86ScreenName = argv[++i]; - return 2; - } - if (!strcmp(argv[i], "-pointer")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - xf86PointerName = argv[++i]; - return 2; - } - if (!strcmp(argv[i], "-keyboard")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - xf86KeyboardName = argv[++i]; - return 2; - } - if (!strcmp(argv[i], "-nosilk")) - { - xf86silkenMouseDisableFlag = TRUE; - return 1; - } -#ifdef HAVE_ACPI - if (!strcmp(argv[i], "-noacpi")) - { - xf86acpiDisableFlag = TRUE; - return 1; - } -#endif - if (!strcmp(argv[i], "-configure")) - { - if (getuid() != 0 && geteuid() == 0) { - ErrorF("The '-configure' option can only be used by root.\n"); - exit(1); - } - xf86DoConfigure = TRUE; - xf86AllowMouseOpenFail = TRUE; - return 1; - } - if (!strcmp(argv[i], "-showopts")) - { - if (getuid() != 0 && geteuid() == 0) { - ErrorF("The '-showopts' option can only be used by root.\n"); - exit(1); - } - xf86DoShowOptions = TRUE; - return 1; - } - if (!strcmp(argv[i], "-isolateDevice")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - if (strncmp(argv[++i], "PCI:", 4)) { - FatalError("Bus types other than PCI not yet isolable\n"); - } - xf86PciIsolateDevice(argv[i]); - return 2; - } - /* Notice cmdline xkbdir, but pass to dix as well */ - if (!strcmp(argv[i], "-xkbdir")) - { - xf86xkbdirFlag = TRUE; - return 0; - } - - /* OS-specific processing */ - return xf86ProcessArgument(argc, argv, i); -} - -/* - * ddxUseMsg -- - * Print out correct use of device dependent commandline options. - * Maybe the user now knows what really to do ... - */ - -void -ddxUseMsg(void) -{ - ErrorF("\n"); - ErrorF("\n"); - ErrorF("Device Dependent Usage\n"); - if (getuid() == 0 || geteuid() != 0) - { - ErrorF("-modulepath paths specify the module search path\n"); - ErrorF("-logfile file specify a log file name\n"); - ErrorF("-configure probe for devices and write an "__XCONFIGFILE__"\n"); - ErrorF("-showopts print available options for all installed drivers\n"); - } - ErrorF("-config file specify a configuration file, relative to the\n"); - ErrorF(" "__XCONFIGFILE__" search path, only root can use absolute\n"); - ErrorF("-configdir dir specify a configuration directory, relative to the\n"); - ErrorF(" "__XCONFIGDIR__" search path, only root can use absolute\n"); - ErrorF("-verbose [n] verbose startup messages\n"); - ErrorF("-logverbose [n] verbose log messages\n"); - ErrorF("-quiet minimal startup messages\n"); - ErrorF("-pixmap24 use 24bpp pixmaps for depth 24\n"); - ErrorF("-pixmap32 use 32bpp pixmaps for depth 24\n"); - ErrorF("-fbbpp n set bpp for the framebuffer. Default: 8\n"); - ErrorF("-depth n set colour depth. Default: 8\n"); - ErrorF("-gamma f set gamma value (0.1 < f < 10.0) Default: 1.0\n"); - ErrorF("-rgamma f set gamma value for red phase\n"); - ErrorF("-ggamma f set gamma value for green phase\n"); - ErrorF("-bgamma f set gamma value for blue phase\n"); - ErrorF("-weight nnn set RGB weighting at 16 bpp. Default: 565\n"); - ErrorF("-layout name specify the ServerLayout section name\n"); - ErrorF("-screen name specify the Screen section name\n"); - ErrorF("-keyboard name specify the core keyboard InputDevice name\n"); - ErrorF("-pointer name specify the core pointer InputDevice name\n"); - ErrorF("-nosilk disable Silken Mouse\n"); - ErrorF("-flipPixels swap default black/white Pixel values\n"); -#ifdef XF86VIDMODE - ErrorF("-disableVidMode disable mode adjustments with xvidtune\n"); - ErrorF("-allowNonLocalXvidtune allow xvidtune to be run as a non-local client\n"); -#endif - ErrorF("-allowMouseOpenFail start server even if the mouse can't be initialized\n"); - ErrorF("-ignoreABI make module ABI mismatches non-fatal\n"); - ErrorF("-isolateDevice bus_id restrict device resets to bus_id (PCI only)\n"); - ErrorF("-version show the server version\n"); - ErrorF("-showDefaultModulePath show the server default module path\n"); - ErrorF("-showDefaultLibPath show the server default library path\n"); - /* OS-specific usage */ - xf86UseMsg(); - ErrorF("\n"); -} - - -/* - * xf86LoadModules iterates over a list that is being passed in. - */ -Bool -xf86LoadModules(char **list, pointer *optlist) -{ - int errmaj, errmin; - pointer opt; - int i; - char *name; - Bool failed = FALSE; - - if (!list) - return TRUE; - - for (i = 0; list[i] != NULL; i++) { - - /* Normalise the module name */ - name = xf86NormalizeName(list[i]); - - /* Skip empty names */ - if (name == NULL || *name == '\0') - continue; - - /* Replace obsolete keyboard driver with kbd */ - if (!xf86NameCmp(name, "keyboard")) { - strcpy(name, "kbd"); - } - - if (optlist) - opt = optlist[i]; - else - opt = NULL; - - if (!LoadModule(name, NULL, NULL, NULL, opt, NULL, &errmaj, &errmin)) { - LoaderErrorMsg(NULL, name, errmaj, errmin); - failed = TRUE; - } - free(name); - } - return !failed; -} - -/* Pixmap format stuff */ - -PixmapFormatPtr -xf86GetPixFormat(ScrnInfoPtr pScrn, int depth) -{ - int i; - static PixmapFormatRec format; /* XXX not reentrant */ - - /* - * When the formats[] list initialisation isn't complete, check the - * depth 24 pixmap config/cmdline options and screen-specified formats. - */ - - if (!formatsDone) { - if (depth == 24) { - Pix24Flags pix24 = Pix24DontCare; - - format.depth = 24; - format.scanlinePad = BITMAP_SCANLINE_PAD; - if (xf86Info.pixmap24 != Pix24DontCare) - pix24 = xf86Info.pixmap24; - else if (pScrn->pixmap24 != Pix24DontCare) - pix24 = pScrn->pixmap24; - if (pix24 == Pix24Use24) - format.bitsPerPixel = 24; - else - format.bitsPerPixel = 32; - return &format; - } - } - - for (i = 0; i < numFormats; i++) - if (formats[i].depth == depth) - break; - if (i != numFormats) - return &formats[i]; - else if (!formatsDone) { - /* Check for screen-specified formats */ - for (i = 0; i < pScrn->numFormats; i++) - if (pScrn->formats[i].depth == depth) - break; - if (i != pScrn->numFormats) - return &pScrn->formats[i]; - } - return NULL; -} - -int -xf86GetBppFromDepth(ScrnInfoPtr pScrn, int depth) -{ - PixmapFormatPtr format; - - - format = xf86GetPixFormat(pScrn, depth); - if (format) - return format->bitsPerPixel; - else - return 0; -} +/* + * Loosely based on code bearing the following copyright: + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + */ +/* + * Copyright (c) 1992-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). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#include +#include + +#undef HAS_UTSNAME +#if !defined(WIN32) +#define HAS_UTSNAME 1 +#include +#endif + +#include +#include +#include +#include +#include "input.h" +#include "servermd.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "site.h" +#include "mi.h" + +#include "compiler.h" + +#include "loaderProcs.h" +#ifdef XFreeXDGA +#include "dgaproc.h" +#endif + +#define XF86_OS_PRIVS +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86Config.h" +#include "xf86_OSlib.h" +#include "xf86cmap.h" +#include "xorgVersion.h" +#include "xf86Build.h" +#include "mipointer.h" +#include +#include +#include "xf86DDC.h" +#include "xf86Xinput.h" +#include "xf86InPriv.h" +#include "picturestr.h" + +#include "xf86Bus.h" +#include "xf86VGAarbiter.h" +#include "globals.h" + +#ifdef DPMSExtension +#include +#include "dpmsproc.h" +#endif +#include + + +#ifdef XF86PM +void (*xf86OSPMClose)(void) = NULL; +#endif +static Bool xorgHWOpenConsole = FALSE; + +/* Common pixmap formats */ + +static PixmapFormatRec formats[MAXFORMATS] = { + { 1, 1, BITMAP_SCANLINE_PAD }, + { 4, 8, BITMAP_SCANLINE_PAD }, + { 8, 8, BITMAP_SCANLINE_PAD }, + { 15, 16, BITMAP_SCANLINE_PAD }, + { 16, 16, BITMAP_SCANLINE_PAD }, + { 24, 32, BITMAP_SCANLINE_PAD }, + { 32, 32, BITMAP_SCANLINE_PAD }, +}; +static int numFormats = 7; +static Bool formatsDone = FALSE; + +#ifndef OSNAME +#define OSNAME " unknown" +#endif +#ifndef OSVENDOR +#define OSVENDOR "" +#endif +#ifndef PRE_RELEASE +#define PRE_RELEASE XORG_VERSION_SNAP +#endif + +static void +xf86PrintBanner(void) +{ +#if PRE_RELEASE + xf86ErrorFVerb(0, "\n" + "This is a pre-release version of the X server from " XVENDORNAME ".\n" + "It is not supported in any way.\n" + "Bugs may be filed in the bugzilla at http://bugs.freedesktop.org/.\n" + "Select the \"xorg\" product for bugs you find in this release.\n" + "Before reporting bugs in pre-release versions please check the\n" + "latest version in the X.Org Foundation git repository.\n" + "See http://wiki.x.org/wiki/GitPage for git access instructions.\n"); +#endif + xf86ErrorFVerb(0, "\nX.Org X Server %d.%d.%d", + XORG_VERSION_MAJOR, + XORG_VERSION_MINOR, + XORG_VERSION_PATCH); +#if XORG_VERSION_SNAP > 0 + xf86ErrorFVerb(0, ".%d", XORG_VERSION_SNAP); +#endif + +#if XORG_VERSION_SNAP >= 900 + /* When the minor number is 99, that signifies that the we are making + * a release candidate for a major version. (X.0.0) + * When the patch number is 99, that signifies that the we are making + * a release candidate for a minor version. (X.Y.0) + * When the patch number is < 99, then we are making a release + * candidate for the next point release. (X.Y.Z) + */ +#if XORG_VERSION_MINOR >= 99 + xf86ErrorFVerb(0, " (%d.0.0 RC %d)", XORG_VERSION_MAJOR+1, + XORG_VERSION_SNAP - 900); +#elif XORG_VERSION_PATCH == 99 + xf86ErrorFVerb(0, " (%d.%d.0 RC %d)", XORG_VERSION_MAJOR, + XORG_VERSION_MINOR + 1, XORG_VERSION_SNAP - 900); +#else + xf86ErrorFVerb(0, " (%d.%d.%d RC %d)", XORG_VERSION_MAJOR, + XORG_VERSION_MINOR, XORG_VERSION_PATCH + 1, + XORG_VERSION_SNAP - 900); +#endif +#endif + +#ifdef XORG_CUSTOM_VERSION + xf86ErrorFVerb(0, " (%s)", XORG_CUSTOM_VERSION); +#endif +#ifndef XORG_DATE +# define XORG_DATE "Unknown" +#endif + xf86ErrorFVerb(0, "\nRelease Date: %s\n", XORG_DATE); + xf86ErrorFVerb(0, "X Protocol Version %d, Revision %d\n", + X_PROTOCOL, X_PROTOCOL_REVISION); + xf86ErrorFVerb(0, "Build Operating System: %s %s\n", OSNAME, OSVENDOR); +#ifdef HAS_UTSNAME + { + struct utsname name; + + /* Linux & BSD state that 0 is success, SysV (including Solaris, HP-UX, + and Irix) and Single Unix Spec 3 just say that non-negative is success. + All agree that failure is represented by a negative number. + */ + if (uname(&name) >= 0) { + xf86ErrorFVerb(0, "Current Operating System: %s %s %s %s %s\n", + name.sysname, name.nodename, name.release, name.version, name.machine); +#ifdef linux + do { + char buf[80]; + int fd = open("/proc/cmdline", O_RDONLY); + if (fd != -1) { + xf86ErrorFVerb(0, "Kernel command line: "); + memset(buf, 0, 80); + while (read(fd, buf, 80) > 0) { + xf86ErrorFVerb(0, "%.80s", buf); + memset(buf, 0, 80); + } + close(fd); + } + } while (0); +#endif + } + } +#endif +#if defined(BUILD_DATE) && (BUILD_DATE > 19000000) + { + struct tm t; + char buf[100]; + + memset(&t, 0, sizeof(t)); + memset(buf, 0, sizeof(buf)); + t.tm_mday = BUILD_DATE % 100; + t.tm_mon = (BUILD_DATE / 100) % 100 - 1; + t.tm_year = BUILD_DATE / 10000 - 1900; +#if defined(BUILD_TIME) + t.tm_sec = BUILD_TIME % 100; + t.tm_min = (BUILD_TIME / 100) % 100; + t.tm_hour = (BUILD_TIME / 10000) % 100; + if (strftime(buf, sizeof(buf), "%d %B %Y %I:%M:%S%p", &t)) + xf86ErrorFVerb(0, "Build Date: %s\n", buf); +#else + if (strftime(buf, sizeof(buf), "%d %B %Y", &t)) + xf86ErrorFVerb(0, "Build Date: %s\n", buf); +#endif + } +#endif +#if defined(BUILDERSTRING) + xf86ErrorFVerb(0, "%s \n", BUILDERSTRING); +#endif + xf86ErrorFVerb(0, "Current version of pixman: %s\n", + pixman_version_string()); + xf86ErrorFVerb(0, "\tBefore reporting problems, check " + ""__VENDORDWEBSUPPORT__"\n" + "\tto make sure that you have the latest version.\n"); +} + +static void +xf86PrintMarkers(void) +{ + LogPrintMarkers(); +} + +static Bool +xf86CreateRootWindow(WindowPtr pWin) +{ + int ret = TRUE; + int err = Success; + ScreenPtr pScreen = pWin->drawable.pScreen; + RootWinPropPtr pProp; + CreateWindowProcPtr CreateWindow = (CreateWindowProcPtr) + dixLookupPrivate(&pScreen->devPrivates, xf86CreateRootWindowKey); + + DebugF("xf86CreateRootWindow(%p)\n", pWin); + + if ( pScreen->CreateWindow != xf86CreateRootWindow ) { + /* Can't find hook we are hung on */ + xf86DrvMsg(pScreen->myNum, X_WARNING /* X_ERROR */, + "xf86CreateRootWindow %p called when not in pScreen->CreateWindow %p n", + (void *)xf86CreateRootWindow, + (void *)pScreen->CreateWindow ); + } + + /* Unhook this function ... */ + pScreen->CreateWindow = CreateWindow; + dixSetPrivate(&pScreen->devPrivates, xf86CreateRootWindowKey, NULL); + + /* ... and call the previous CreateWindow fuction, if any */ + if (NULL!=pScreen->CreateWindow) { + ret = (*pScreen->CreateWindow)(pWin); + } + + /* Now do our stuff */ + if (xf86RegisteredPropertiesTable != NULL) { + if (pWin->parent == NULL && xf86RegisteredPropertiesTable != NULL) { + for (pProp = xf86RegisteredPropertiesTable[pScreen->myNum]; + pProp != NULL && err==Success; + pProp = pProp->next ) + { + Atom prop; + + prop = MakeAtom(pProp->name, strlen(pProp->name), TRUE); + err = dixChangeWindowProperty(serverClient, pWin, + prop, pProp->type, + pProp->format, PropModeReplace, + pProp->size, pProp->data, + FALSE); + } + + /* Look at err */ + ret &= (err==Success); + + } else { + xf86Msg(X_ERROR, "xf86CreateRootWindow unexpectedly called with " + "non-root window %p (parent %p)\n", + (void *)pWin, (void *)pWin->parent); + ret = FALSE; + } + } + + DebugF("xf86CreateRootWindow() returns %d\n", ret); + return ret; +} + + +static void +InstallSignalHandlers(void) +{ + /* + * Install signal handler for unexpected signals + */ + xf86Info.caughtSignal=FALSE; + if (!xf86Info.notrapSignals) { + OsRegisterSigWrapper(xf86SigWrapper); + } else { + signal(SIGSEGV, SIG_DFL); + signal(SIGILL, SIG_DFL); +#ifdef SIGEMT + signal(SIGEMT, SIG_DFL); +#endif + signal(SIGFPE, SIG_DFL); + signal(SIGBUS, SIG_DFL); + signal(SIGSYS, SIG_DFL); + signal(SIGXCPU, SIG_DFL); + signal(SIGXFSZ, SIG_DFL); + } +} + +/* + * InitOutput -- + * Initialize screenInfo for all actually accessible framebuffers. + * That includes vt-manager setup, querying all possible devices and + * collecting the pixmap formats. + */ +void +InitOutput(ScreenInfo *pScreenInfo, int argc, char **argv) +{ + int i, j, k, scr_index, was_blocked = 0; + char **modulelist; + pointer *optionlist; + Pix24Flags screenpix24, pix24; + MessageType pix24From = X_DEFAULT; + Bool pix24Fail = FALSE; + Bool autoconfig = FALSE; + GDevPtr configured_device; + + xf86Initialising = TRUE; + + if (serverGeneration == 1) { + if ((xf86ServerName = strrchr(argv[0], '/')) != 0) + xf86ServerName++; + else + xf86ServerName = argv[0]; + + xf86PrintBanner(); + xf86PrintMarkers(); + if (xf86LogFile) { + time_t t; + const char *ct; + t = time(NULL); + ct = ctime(&t); + xf86MsgVerb(xf86LogFileFrom, 0, "Log file: \"%s\", Time: %s", + xf86LogFile, ct); + } + + /* Read and parse the config file */ + if (!xf86DoConfigure && !xf86DoShowOptions) { + switch (xf86HandleConfigFile(FALSE)) { + case CONFIG_OK: + break; + case CONFIG_PARSE_ERROR: + xf86Msg(X_ERROR, "Error parsing the config file\n"); + return; + case CONFIG_NOFILE: + autoconfig = TRUE; + break; + } + } + + InstallSignalHandlers(); + + /* Initialise the loader */ + LoaderInit(); + + /* Tell the loader the default module search path */ + LoaderSetPath(xf86ModulePath); + + if (xf86Info.ignoreABI) { + LoaderSetOptions(LDR_OPT_ABI_MISMATCH_NONFATAL); + } + + if (xf86DoShowOptions) + DoShowOptions(); + + /* Do a general bus probe. This will be a PCI probe for x86 platforms */ + xf86BusProbe(); + + if (xf86DoConfigure) + DoConfigure(); + + if (autoconfig) { + if (!xf86AutoConfig()) { + xf86Msg(X_ERROR, "Auto configuration failed\n"); + return; + } + } + +#ifdef XF86PM + xf86OSPMClose = xf86OSPMOpen(); +#endif + + /* Load all modules specified explicitly in the config file */ + if ((modulelist = xf86ModulelistFromConfig(&optionlist))) { + xf86LoadModules(modulelist, optionlist); + free(modulelist); + free(optionlist); + } + + /* Load all driver modules specified in the config file */ + /* If there aren't any specified in the config file, autoconfig them */ + /* FIXME: Does not handle multiple active screen sections, but I'm not + * sure if we really want to handle that case*/ + configured_device = xf86ConfigLayout.screens->screen->device; + if ((!configured_device) || (!configured_device->driver)) { + if (!autoConfigDevice(configured_device)) { + xf86Msg(X_ERROR, "Automatic driver configuration failed\n"); + return ; + } + } + if ((modulelist = xf86DriverlistFromConfig())) { + xf86LoadModules(modulelist, NULL); + free(modulelist); + } + + /* Load all input driver modules specified in the config file. */ + if ((modulelist = xf86InputDriverlistFromConfig())) { + xf86LoadModules(modulelist, NULL); + free(modulelist); + } + + /* + * It is expected that xf86AddDriver()/xf86AddInputDriver will be + * called for each driver as it is loaded. Those functions save the + * module pointers for drivers. + * XXX Nothing keeps track of them for other modules. + */ + /* XXX What do we do if not all of these could be loaded? */ + + /* + * At this point, xf86DriverList[] is all filled in with entries for + * each of the drivers to try and xf86NumDrivers has the number of + * drivers. If there are none, return now. + */ + + if (xf86NumDrivers == 0) { + xf86Msg(X_ERROR, "No drivers available.\n"); + return; + } + + /* + * Call each of the Identify functions and call the driverFunc to check + * if HW access is required. The Identify functions print out some + * identifying information, and anything else that might be + * needed at this early stage. + */ + + for (i = 0; i < xf86NumDrivers; i++) { + if (xf86DriverList[i]->Identify != NULL) + xf86DriverList[i]->Identify(0); + + if (!xorgHWAccess || !xorgHWOpenConsole) { + xorgHWFlags flags; + if(!xf86DriverList[i]->driverFunc + || !xf86DriverList[i]->driverFunc(NULL, + GET_REQUIRED_HW_INTERFACES, + &flags)) + flags = HW_IO; + + if(NEED_IO_ENABLED(flags)) + xorgHWAccess = TRUE; + if(!(flags & HW_SKIP_CONSOLE)) + xorgHWOpenConsole = TRUE; + } + } + + if (xorgHWOpenConsole) + xf86OpenConsole(); + else + xf86Info.dontVTSwitch = TRUE; + + if (xf86BusConfig() == FALSE) + return; + + xf86PostProbe(); + + /* + * Sort the drivers to match the requested ording. Using a slow + * bubble sort. + */ + for (j = 0; j < xf86NumScreens - 1; j++) { + for (i = 0; i < xf86NumScreens - j - 1; i++) { + if (xf86Screens[i + 1]->confScreen->screennum < + xf86Screens[i]->confScreen->screennum) { + ScrnInfoPtr tmpScrn = xf86Screens[i + 1]; + xf86Screens[i + 1] = xf86Screens[i]; + xf86Screens[i] = tmpScrn; + } + } + } + /* Fix up the indexes */ + for (i = 0; i < xf86NumScreens; i++) { + xf86Screens[i]->scrnIndex = i; + } + + /* + * Call the driver's PreInit()'s to complete initialisation for the first + * generation. + */ + + for (i = 0; i < xf86NumScreens; i++) { + xf86VGAarbiterScrnInit(xf86Screens[i]); + xf86VGAarbiterLock(xf86Screens[i]); + if (xf86Screens[i]->PreInit && + xf86Screens[i]->PreInit(xf86Screens[i], 0)) + xf86Screens[i]->configured = TRUE; + xf86VGAarbiterUnlock(xf86Screens[i]); + } + for (i = 0; i < xf86NumScreens; i++) + if (!xf86Screens[i]->configured) + xf86DeleteScreen(i--, 0); + + /* + * If no screens left, return now. + */ + + if (xf86NumScreens == 0) { + xf86Msg(X_ERROR, + "Screen(s) found, but none have a usable configuration.\n"); + return; + } + + for (i = 0; i < xf86NumScreens; i++) { + if (xf86Screens[i]->name == NULL) { + XNFasprintf(&xf86Screens[i]->name, "screen%d", i); + xf86MsgVerb(X_WARNING, 0, + "Screen driver %d has no name set, using `%s'.\n", + i, xf86Screens[i]->name); + } + } + + /* Remove (unload) drivers that are not required */ + for (i = 0; i < xf86NumDrivers; i++) + if (xf86DriverList[i] && xf86DriverList[i]->refCount <= 0) + xf86DeleteDriver(i); + + /* + * At this stage we know how many screens there are. + */ + + for (i = 0; i < xf86NumScreens; i++) + xf86InitViewport(xf86Screens[i]); + + /* + * Collect all pixmap formats and check for conflicts at the display + * level. Should we die here? Or just delete the offending screens? + */ + screenpix24 = Pix24DontCare; + for (i = 0; i < xf86NumScreens; i++) { + if (xf86Screens[i]->imageByteOrder != + xf86Screens[0]->imageByteOrder) + FatalError("Inconsistent display bitmapBitOrder. Exiting\n"); + if (xf86Screens[i]->bitmapScanlinePad != + xf86Screens[0]->bitmapScanlinePad) + FatalError("Inconsistent display bitmapScanlinePad. Exiting\n"); + if (xf86Screens[i]->bitmapScanlineUnit != + xf86Screens[0]->bitmapScanlineUnit) + FatalError("Inconsistent display bitmapScanlineUnit. Exiting\n"); + if (xf86Screens[i]->bitmapBitOrder != + xf86Screens[0]->bitmapBitOrder) + FatalError("Inconsistent display bitmapBitOrder. Exiting\n"); + + /* Determine the depth 24 pixmap format the screens would like */ + if (xf86Screens[i]->pixmap24 != Pix24DontCare) { + if (screenpix24 == Pix24DontCare) + screenpix24 = xf86Screens[i]->pixmap24; + else if (screenpix24 != xf86Screens[i]->pixmap24) + FatalError("Inconsistent depth 24 pixmap format. Exiting\n"); + } + } + /* check if screenpix24 is consistent with the config/cmdline */ + if (xf86Info.pixmap24 != Pix24DontCare) { + pix24 = xf86Info.pixmap24; + pix24From = xf86Info.pix24From; + if (screenpix24 != Pix24DontCare && screenpix24 != xf86Info.pixmap24) + pix24Fail = TRUE; + } else if (screenpix24 != Pix24DontCare) { + pix24 = screenpix24; + pix24From = X_PROBED; + } else + pix24 = Pix24Use32; + + if (pix24Fail) + FatalError("Screen(s) can't use the required depth 24 pixmap format" + " (%d). Exiting\n", PIX24TOBPP(pix24)); + + /* Initialise the depth 24 format */ + for (j = 0; j < numFormats && formats[j].depth != 24; j++) + ; + formats[j].bitsPerPixel = PIX24TOBPP(pix24); + + /* Collect additional formats */ + for (i = 0; i < xf86NumScreens; i++) { + for (j = 0; j < xf86Screens[i]->numFormats; j++) { + for (k = 0; ; k++) { + if (k >= numFormats) { + if (k >= MAXFORMATS) + FatalError("Too many pixmap formats! Exiting\n"); + formats[k] = xf86Screens[i]->formats[j]; + numFormats++; + break; + } + if (formats[k].depth == xf86Screens[i]->formats[j].depth) { + if ((formats[k].bitsPerPixel == + xf86Screens[i]->formats[j].bitsPerPixel) && + (formats[k].scanlinePad == + xf86Screens[i]->formats[j].scanlinePad)) + break; + FatalError("Inconsistent pixmap format for depth %d." + " Exiting\n", formats[k].depth); + } + } + } + } + formatsDone = TRUE; + + if (xf86Info.vtno >= 0 ) { +#define VT_ATOM_NAME "XFree86_VT" + Atom VTAtom=-1; + CARD32 *VT = NULL; + int ret; + + /* This memory needs to stay available until the screen has been + initialized, and we can create the property for real. + */ + if ( (VT = malloc(sizeof(CARD32)))==NULL ) { + FatalError("Unable to make VT property - out of memory. Exiting...\n"); + } + *VT = xf86Info.vtno; + + VTAtom = MakeAtom(VT_ATOM_NAME, sizeof(VT_ATOM_NAME) - 1, TRUE); + + for (i = 0, ret = Success; i < xf86NumScreens && ret == Success; i++) { + ret = xf86RegisterRootWindowProperty(xf86Screens[i]->scrnIndex, + VTAtom, XA_INTEGER, 32, + 1, VT ); + if (ret != Success) + xf86DrvMsg(xf86Screens[i]->scrnIndex, X_WARNING, + "Failed to register VT property\n"); + } + } + + /* If a screen uses depth 24, show what the pixmap format is */ + for (i = 0; i < xf86NumScreens; i++) { + if (xf86Screens[i]->depth == 24) { + xf86Msg(pix24From, "Depth 24 pixmap format is %d bpp\n", + PIX24TOBPP(pix24)); + break; + } + } + } else { + /* + * serverGeneration != 1; some OSs have to do things here, too. + */ + if (xorgHWOpenConsole) + xf86OpenConsole(); + +#ifdef XF86PM + /* + should we reopen it here? We need to deal with an already opened + device. We could leave this to the OS layer. For now we simply + close it here + */ + if (xf86OSPMClose) + xf86OSPMClose(); + if ((xf86OSPMClose = xf86OSPMOpen()) != NULL) + xf86MsgVerb(X_INFO, 3, "APM registered successfully\n"); +#endif + + /* Make sure full I/O access is enabled */ + if (xorgHWAccess) + xf86EnableIO(); + } + + /* + * Use the previously collected parts to setup pScreenInfo + */ + + pScreenInfo->imageByteOrder = xf86Screens[0]->imageByteOrder; + pScreenInfo->bitmapScanlinePad = xf86Screens[0]->bitmapScanlinePad; + pScreenInfo->bitmapScanlineUnit = xf86Screens[0]->bitmapScanlineUnit; + pScreenInfo->bitmapBitOrder = xf86Screens[0]->bitmapBitOrder; + pScreenInfo->numPixmapFormats = numFormats; + for (i = 0; i < numFormats; i++) + pScreenInfo->formats[i] = formats[i]; + + /* Make sure the server's VT is active */ + + if (serverGeneration != 1) { + xf86Resetting = TRUE; + /* All screens are in the same state, so just check the first */ + if (!xf86Screens[0]->vtSema) { +#ifdef HAS_USL_VTS + ioctl(xf86Info.consoleFd, VT_RELDISP, VT_ACKACQ); +#endif + xf86AccessEnter(); + was_blocked = xf86BlockSIGIO(); + } + } + + for (i = 0; i < xf86NumScreens; i++) + if (!xf86ColormapAllocatePrivates(xf86Screens[i])) + FatalError("Cannot register DDX private keys"); + + if (!dixRegisterPrivateKey(&xf86ScreenKeyRec, PRIVATE_SCREEN, 0) || + !dixRegisterPrivateKey(&xf86CreateRootWindowKeyRec, PRIVATE_SCREEN, 0)) + FatalError("Cannot register DDX private keys"); + + for (i = 0; i < xf86NumScreens; i++) { + xf86VGAarbiterLock(xf86Screens[i]); + /* + * Almost everything uses these defaults, and many of those that + * don't, will wrap them. + */ + xf86Screens[i]->EnableDisableFBAccess = xf86EnableDisableFBAccess; +#ifdef XFreeXDGA + xf86Screens[i]->SetDGAMode = xf86SetDGAMode; +#endif + xf86Screens[i]->DPMSSet = NULL; + xf86Screens[i]->LoadPalette = NULL; + xf86Screens[i]->SetOverscan = NULL; + xf86Screens[i]->DriverFunc = NULL; + xf86Screens[i]->pScreen = NULL; + scr_index = AddScreen(xf86Screens[i]->ScreenInit, argc, argv); + xf86VGAarbiterUnlock(xf86Screens[i]); + if (scr_index == i) { + /* + * Hook in our ScrnInfoRec, and initialise some other pScreen + * fields. + */ + dixSetPrivate(&screenInfo.screens[scr_index]->devPrivates, + xf86ScreenKey, xf86Screens[i]); + xf86Screens[i]->pScreen = screenInfo.screens[scr_index]; + /* The driver should set this, but make sure it is set anyway */ + xf86Screens[i]->vtSema = TRUE; + } else { + /* This shouldn't normally happen */ + FatalError("AddScreen/ScreenInit failed for driver %d\n", i); + } + + DebugF("InitOutput - xf86Screens[%d]->pScreen = %p\n", + i, xf86Screens[i]->pScreen ); + DebugF("xf86Screens[%d]->pScreen->CreateWindow = %p\n", + i, xf86Screens[i]->pScreen->CreateWindow ); + + dixSetPrivate(&screenInfo.screens[scr_index]->devPrivates, + xf86CreateRootWindowKey, + xf86Screens[i]->pScreen->CreateWindow); + xf86Screens[i]->pScreen->CreateWindow = xf86CreateRootWindow; + + if (PictureGetSubpixelOrder (xf86Screens[i]->pScreen) == SubPixelUnknown) + { + xf86MonPtr DDC = (xf86MonPtr)(xf86Screens[i]->monitor->DDC); + PictureSetSubpixelOrder (xf86Screens[i]->pScreen, + DDC ? + (DDC->features.input_type ? + SubPixelHorizontalRGB : SubPixelNone) : + SubPixelUnknown); + } +#ifdef RANDR + if (!xf86Info.disableRandR) + xf86RandRInit (screenInfo.screens[scr_index]); + xf86Msg(xf86Info.randRFrom, "RandR %s\n", + xf86Info.disableRandR ? "disabled" : "enabled"); +#endif + } + + xf86VGAarbiterWrapFunctions(); + xf86UnblockSIGIO(was_blocked); + + xf86InitOrigins(); + + xf86Resetting = FALSE; + xf86Initialising = FALSE; + + RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, xf86Wakeup, + NULL); +} + +/* + * InitInput -- + * Initialize all supported input devices. + */ + +void +InitInput(int argc, char **argv) +{ + InputInfoPtr* pDev; + DeviceIntPtr dev; + + xf86Info.vtRequestsPending = FALSE; + + mieqInit(); + + GetEventList(&xf86Events); + + /* Initialize all configured input devices */ + for (pDev = xf86ConfigLayout.inputs; pDev && *pDev; pDev++) { + /* Replace obsolete keyboard driver with kbd */ + if (!xf86NameCmp((*pDev)->driver, "keyboard")) { + strcpy((*pDev)->driver, "kbd"); + } + + /* If one fails, the others will too */ + if (xf86NewInputDevice(*pDev, &dev, TRUE) == BadAlloc) + break; + } + + config_init(); +} + +void +CloseInput (void) +{ + config_fini(); +} + +/* + * OsVendorInit -- + * OS/Vendor-specific initialisations. Called from OsInit(), which + * is called by dix before establishing the well known sockets. + */ + +void +OsVendorInit(void) +{ + static Bool beenHere = FALSE; + + signal(SIGCHLD, SIG_DFL); /* Need to wait for child processes */ + + if (!beenHere) { + umask(022); + xf86LogInit(); + } + + /* Set stderr to non-blocking. */ +#ifndef O_NONBLOCK +#if defined(FNDELAY) +#define O_NONBLOCK FNDELAY +#elif defined(O_NDELAY) +#define O_NONBLOCK O_NDELAY +#endif + +#ifdef O_NONBLOCK + if (!beenHere) { + if (geteuid() == 0 && getuid() != geteuid()) + { + int status; + + status = fcntl(fileno(stderr), F_GETFL, 0); + if (status != -1) { + fcntl(fileno(stderr), F_SETFL, status | O_NONBLOCK); + } + } + } +#endif +#endif + + beenHere = TRUE; +} + +/* + * ddxGiveUp -- + * Device dependent cleanup. Called by by dix before normal server death. + * For SYSV386 we must switch the terminal back to normal mode. No error- + * checking here, since there should be restored as much as possible. + */ + +void +ddxGiveUp(void) +{ + int i; + + xf86VGAarbiterFini(); + +#ifdef XF86PM + if (xf86OSPMClose) + xf86OSPMClose(); + xf86OSPMClose = NULL; +#endif + + for (i = 0; i < xf86NumScreens; i++) { + /* + * zero all access functions to + * trap calls when switched away. + */ + xf86Screens[i]->vtSema = FALSE; + } + +#ifdef XFreeXDGA + DGAShutdown(); +#endif + + if (xorgHWOpenConsole) + xf86CloseConsole(); + + xf86CloseLog(); + + /* If an unexpected signal was caught, dump a core for debugging */ + if (xf86Info.caughtSignal) + OsAbort(); +} + + + +/* + * AbortDDX -- + * DDX - specific abort routine. Called by AbortServer(). The attempt is + * made to restore all original setting of the displays. Also all devices + * are closed. + */ + +void +AbortDDX(void) +{ + int i; + + xf86BlockSIGIO(); + + /* + * try to restore the original video state + */ +#ifdef DPMSExtension /* Turn screens back on */ + if (DPMSPowerLevel != DPMSModeOn) + DPMSSet(serverClient, DPMSModeOn); +#endif + if (xf86Screens) { + for (i = 0; i < xf86NumScreens; i++) + if (xf86Screens[i]->vtSema) { + /* + * if we are aborting before ScreenInit() has finished + * we might not have been wrapped yet. Therefore enable + * screen explicitely. + */ + xf86VGAarbiterLock(xf86Screens[i]); + (xf86Screens[i]->LeaveVT)(i, 0); + xf86VGAarbiterUnlock(xf86Screens[i]); + } + } + + xf86AccessLeave(); + + /* + * This is needed for an abnormal server exit, since the normal exit stuff + * MUST also be performed (i.e. the vt must be left in a defined state) + */ + ddxGiveUp(); +} + +void +OsVendorFatalError(void) +{ +#ifdef VENDORSUPPORT + ErrorF("\nPlease refer to your Operating System Vendor support pages\n" + "at %s for support on this crash.\n",VENDORSUPPORT); +#else + ErrorF("\nPlease consult the "XVENDORNAME" support \n" + "\t at "__VENDORDWEBSUPPORT__"\n for help. \n"); +#endif + if (xf86LogFile && xf86LogFileWasOpened) + ErrorF("Please also check the log file at \"%s\" for additional " + "information.\n", xf86LogFile); + ErrorF("\n"); +} + +int +xf86SetVerbosity(int verb) +{ + int save = xf86Verbose; + + xf86Verbose = verb; + LogSetParameter(XLOG_VERBOSITY, verb); + return save; +} + +int +xf86SetLogVerbosity(int verb) +{ + int save = xf86LogVerbose; + + xf86LogVerbose = verb; + LogSetParameter(XLOG_FILE_VERBOSITY, verb); + return save; +} + +static void +xf86PrintDefaultModulePath(void) +{ + ErrorF("%s\n", DEFAULT_MODULE_PATH); +} + +static void +xf86PrintDefaultLibraryPath(void) +{ + ErrorF("%s\n", DEFAULT_LIBRARY_PATH); +} + +/* + * ddxProcessArgument -- + * Process device-dependent command line args. Returns 0 if argument is + * not device dependent, otherwise Count of number of elements of argv + * that are part of a device dependent commandline option. + * + */ + +/* ARGSUSED */ +int +ddxProcessArgument(int argc, char **argv, int i) +{ +#define CHECK_FOR_REQUIRED_ARGUMENT() \ + if (((i + 1) >= argc) || (!argv[i + 1])) { \ + ErrorF("Required argument to %s not specified\n", argv[i]); \ + UseMsg(); \ + FatalError("Required argument to %s not specified\n", argv[i]); \ + } + + /* First the options that are only allowed for root */ + if (!strcmp(argv[i], "-modulepath") || !strcmp(argv[i], "-logfile")) { + if ( (geteuid() == 0) && (getuid() != 0) ) { + FatalError("The '%s' option can only be used by root.\n", argv[i]); + } + else if (!strcmp(argv[i], "-modulepath")) + { + char *mp; + CHECK_FOR_REQUIRED_ARGUMENT(); + mp = strdup(argv[i + 1]); + if (!mp) + FatalError("Can't allocate memory for ModulePath\n"); + xf86ModulePath = mp; + xf86ModPathFrom = X_CMDLINE; + return 2; + } + else if (!strcmp(argv[i], "-logfile")) + { + char *lf; + CHECK_FOR_REQUIRED_ARGUMENT(); + lf = strdup(argv[i + 1]); + if (!lf) + FatalError("Can't allocate memory for LogFile\n"); + xf86LogFile = lf; + xf86LogFileFrom = X_CMDLINE; + return 2; + } + } + if (!strcmp(argv[i], "-config") || !strcmp(argv[i], "-xf86config")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + if (getuid() != 0 && !xf86PathIsSafe(argv[i + 1])) { + FatalError("\nInvalid argument for %s\n" + "\tFor non-root users, the file specified with %s must be\n" + "\ta relative path and must not contain any \"..\" elements.\n" + "\tUsing default "__XCONFIGFILE__" search path.\n\n", + argv[i], argv[i]); + } + xf86ConfigFile = argv[i + 1]; + return 2; + } + if (!strcmp(argv[i], "-configdir")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + if (getuid() != 0 && !xf86PathIsSafe(argv[i + 1])) { + FatalError("\nInvalid argument for %s\n" + "\tFor non-root users, the file specified with %s must be\n" + "\ta relative path and must not contain any \"..\" elements.\n" + "\tUsing default "__XCONFIGDIR__" search path.\n\n", + argv[i], argv[i]); + } + xf86ConfigDir = argv[i + 1]; + return 2; + } + if (!strcmp(argv[i],"-flipPixels")) + { + xf86FlipPixels = TRUE; + return 1; + } +#ifdef XF86VIDMODE + if (!strcmp(argv[i],"-disableVidMode")) + { + xf86VidModeDisabled = TRUE; + return 1; + } + if (!strcmp(argv[i],"-allowNonLocalXvidtune")) + { + xf86VidModeAllowNonLocal = TRUE; + return 1; + } +#endif + if (!strcmp(argv[i],"-allowMouseOpenFail")) + { + xf86AllowMouseOpenFail = TRUE; + return 1; + } + if (!strcmp(argv[i],"-ignoreABI")) + { + LoaderSetOptions(LDR_OPT_ABI_MISMATCH_NONFATAL); + return 1; + } + if (!strcmp(argv[i],"-verbose")) + { + if (++i < argc && argv[i]) + { + char *end; + long val; + val = strtol(argv[i], &end, 0); + if (*end == '\0') + { + xf86SetVerbosity(val); + return 2; + } + } + xf86SetVerbosity(++xf86Verbose); + return 1; + } + if (!strcmp(argv[i],"-logverbose")) + { + if (++i < argc && argv[i]) + { + char *end; + long val; + val = strtol(argv[i], &end, 0); + if (*end == '\0') + { + xf86SetLogVerbosity(val); + return 2; + } + } + xf86SetLogVerbosity(++xf86LogVerbose); + return 1; + } + if (!strcmp(argv[i],"-quiet")) + { + xf86SetVerbosity(-1); + return 1; + } + if (!strcmp(argv[i],"-showconfig") || !strcmp(argv[i],"-version")) + { + xf86PrintBanner(); + exit(0); + } + if (!strcmp(argv[i],"-showDefaultModulePath")) + { + xf86PrintDefaultModulePath(); + exit(0); + } + if (!strcmp(argv[i],"-showDefaultLibPath")) + { + xf86PrintDefaultLibraryPath(); + exit(0); + } + /* Notice the -fp flag, but allow it to pass to the dix layer */ + if (!strcmp(argv[i], "-fp")) + { + xf86fpFlag = TRUE; + return 0; + } + /* Notice the -bs flag, but allow it to pass to the dix layer */ + if (!strcmp(argv[i], "-bs")) + { + xf86bsDisableFlag = TRUE; + return 0; + } + /* Notice the +bs flag, but allow it to pass to the dix layer */ + if (!strcmp(argv[i], "+bs")) + { + xf86bsEnableFlag = TRUE; + return 0; + } + /* Notice the -s flag, but allow it to pass to the dix layer */ + if (!strcmp(argv[i], "-s")) + { + xf86sFlag = TRUE; + return 0; + } + if (!strcmp(argv[i], "-pixmap24")) + { + xf86Pix24 = Pix24Use24; + return 1; + } + if (!strcmp(argv[i], "-pixmap32")) + { + xf86Pix24 = Pix24Use32; + return 1; + } + if (!strcmp(argv[i], "-fbbpp")) + { + int bpp; + CHECK_FOR_REQUIRED_ARGUMENT(); + if (sscanf(argv[++i], "%d", &bpp) == 1) + { + xf86FbBpp = bpp; + return 2; + } + else + { + ErrorF("Invalid fbbpp\n"); + return 0; + } + } + if (!strcmp(argv[i], "-depth")) + { + int depth; + CHECK_FOR_REQUIRED_ARGUMENT(); + if (sscanf(argv[++i], "%d", &depth) == 1) + { + xf86Depth = depth; + return 2; + } + else + { + ErrorF("Invalid depth\n"); + return 0; + } + } + if (!strcmp(argv[i], "-weight")) + { + int red, green, blue; + CHECK_FOR_REQUIRED_ARGUMENT(); + if (sscanf(argv[++i], "%1d%1d%1d", &red, &green, &blue) == 3) + { + xf86Weight.red = red; + xf86Weight.green = green; + xf86Weight.blue = blue; + return 2; + } + else + { + ErrorF("Invalid weighting\n"); + return 0; + } + } + if (!strcmp(argv[i], "-gamma") || !strcmp(argv[i], "-rgamma") || + !strcmp(argv[i], "-ggamma") || !strcmp(argv[i], "-bgamma")) + { + double gamma; + CHECK_FOR_REQUIRED_ARGUMENT(); + if (sscanf(argv[++i], "%lf", &gamma) == 1) { + if (gamma < GAMMA_MIN || gamma > GAMMA_MAX) { + ErrorF("gamma out of range, only %.2f <= gamma_value <= %.1f" + " is valid\n", GAMMA_MIN, GAMMA_MAX); + return 0; + } + if (!strcmp(argv[i-1], "-gamma")) + xf86Gamma.red = xf86Gamma.green = xf86Gamma.blue = gamma; + else if (!strcmp(argv[i-1], "-rgamma")) xf86Gamma.red = gamma; + else if (!strcmp(argv[i-1], "-ggamma")) xf86Gamma.green = gamma; + else if (!strcmp(argv[i-1], "-bgamma")) xf86Gamma.blue = gamma; + return 2; + } + } + if (!strcmp(argv[i], "-layout")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + xf86LayoutName = argv[++i]; + return 2; + } + if (!strcmp(argv[i], "-screen")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + xf86ScreenName = argv[++i]; + return 2; + } + if (!strcmp(argv[i], "-pointer")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + xf86PointerName = argv[++i]; + return 2; + } + if (!strcmp(argv[i], "-keyboard")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + xf86KeyboardName = argv[++i]; + return 2; + } + if (!strcmp(argv[i], "-nosilk")) + { + xf86silkenMouseDisableFlag = TRUE; + return 1; + } +#ifdef HAVE_ACPI + if (!strcmp(argv[i], "-noacpi")) + { + xf86acpiDisableFlag = TRUE; + return 1; + } +#endif + if (!strcmp(argv[i], "-configure")) + { + if (getuid() != 0 && geteuid() == 0) { + ErrorF("The '-configure' option can only be used by root.\n"); + exit(1); + } + xf86DoConfigure = TRUE; + xf86AllowMouseOpenFail = TRUE; + return 1; + } + if (!strcmp(argv[i], "-showopts")) + { + if (getuid() != 0 && geteuid() == 0) { + ErrorF("The '-showopts' option can only be used by root.\n"); + exit(1); + } + xf86DoShowOptions = TRUE; + return 1; + } + if (!strcmp(argv[i], "-isolateDevice")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + if (strncmp(argv[++i], "PCI:", 4)) { + FatalError("Bus types other than PCI not yet isolable\n"); + } + xf86PciIsolateDevice(argv[i]); + return 2; + } + /* Notice cmdline xkbdir, but pass to dix as well */ + if (!strcmp(argv[i], "-xkbdir")) + { + xf86xkbdirFlag = TRUE; + return 0; + } + + /* OS-specific processing */ + return xf86ProcessArgument(argc, argv, i); +} + +/* + * ddxUseMsg -- + * Print out correct use of device dependent commandline options. + * Maybe the user now knows what really to do ... + */ + +void +ddxUseMsg(void) +{ + ErrorF("\n"); + ErrorF("\n"); + ErrorF("Device Dependent Usage\n"); + if (getuid() == 0 || geteuid() != 0) + { + ErrorF("-modulepath paths specify the module search path\n"); + ErrorF("-logfile file specify a log file name\n"); + ErrorF("-configure probe for devices and write an "__XCONFIGFILE__"\n"); + ErrorF("-showopts print available options for all installed drivers\n"); + } + ErrorF("-config file specify a configuration file, relative to the\n"); + ErrorF(" "__XCONFIGFILE__" search path, only root can use absolute\n"); + ErrorF("-configdir dir specify a configuration directory, relative to the\n"); + ErrorF(" "__XCONFIGDIR__" search path, only root can use absolute\n"); + ErrorF("-verbose [n] verbose startup messages\n"); + ErrorF("-logverbose [n] verbose log messages\n"); + ErrorF("-quiet minimal startup messages\n"); + ErrorF("-pixmap24 use 24bpp pixmaps for depth 24\n"); + ErrorF("-pixmap32 use 32bpp pixmaps for depth 24\n"); + ErrorF("-fbbpp n set bpp for the framebuffer. Default: 8\n"); + ErrorF("-depth n set colour depth. Default: 8\n"); + ErrorF("-gamma f set gamma value (0.1 < f < 10.0) Default: 1.0\n"); + ErrorF("-rgamma f set gamma value for red phase\n"); + ErrorF("-ggamma f set gamma value for green phase\n"); + ErrorF("-bgamma f set gamma value for blue phase\n"); + ErrorF("-weight nnn set RGB weighting at 16 bpp. Default: 565\n"); + ErrorF("-layout name specify the ServerLayout section name\n"); + ErrorF("-screen name specify the Screen section name\n"); + ErrorF("-keyboard name specify the core keyboard InputDevice name\n"); + ErrorF("-pointer name specify the core pointer InputDevice name\n"); + ErrorF("-nosilk disable Silken Mouse\n"); + ErrorF("-flipPixels swap default black/white Pixel values\n"); +#ifdef XF86VIDMODE + ErrorF("-disableVidMode disable mode adjustments with xvidtune\n"); + ErrorF("-allowNonLocalXvidtune allow xvidtune to be run as a non-local client\n"); +#endif + ErrorF("-allowMouseOpenFail start server even if the mouse can't be initialized\n"); + ErrorF("-ignoreABI make module ABI mismatches non-fatal\n"); + ErrorF("-isolateDevice bus_id restrict device resets to bus_id (PCI only)\n"); + ErrorF("-version show the server version\n"); + ErrorF("-showDefaultModulePath show the server default module path\n"); + ErrorF("-showDefaultLibPath show the server default library path\n"); + /* OS-specific usage */ + xf86UseMsg(); + ErrorF("\n"); +} + + +/* + * xf86LoadModules iterates over a list that is being passed in. + */ +Bool +xf86LoadModules(char **list, pointer *optlist) +{ + int errmaj, errmin; + pointer opt; + int i; + char *name; + Bool failed = FALSE; + + if (!list) + return TRUE; + + for (i = 0; list[i] != NULL; i++) { + + /* Normalise the module name */ + name = xf86NormalizeName(list[i]); + + /* Skip empty names */ + if (name == NULL || *name == '\0') + continue; + + /* Replace obsolete keyboard driver with kbd */ + if (!xf86NameCmp(name, "keyboard")) { + strcpy(name, "kbd"); + } + + if (optlist) + opt = optlist[i]; + else + opt = NULL; + + if (!LoadModule(name, NULL, NULL, NULL, opt, NULL, &errmaj, &errmin)) { + LoaderErrorMsg(NULL, name, errmaj, errmin); + failed = TRUE; + } + free(name); + } + return !failed; +} + +/* Pixmap format stuff */ + +PixmapFormatPtr +xf86GetPixFormat(ScrnInfoPtr pScrn, int depth) +{ + int i; + static PixmapFormatRec format; /* XXX not reentrant */ + + /* + * When the formats[] list initialisation isn't complete, check the + * depth 24 pixmap config/cmdline options and screen-specified formats. + */ + + if (!formatsDone) { + if (depth == 24) { + Pix24Flags pix24 = Pix24DontCare; + + format.depth = 24; + format.scanlinePad = BITMAP_SCANLINE_PAD; + if (xf86Info.pixmap24 != Pix24DontCare) + pix24 = xf86Info.pixmap24; + else if (pScrn->pixmap24 != Pix24DontCare) + pix24 = pScrn->pixmap24; + if (pix24 == Pix24Use24) + format.bitsPerPixel = 24; + else + format.bitsPerPixel = 32; + return &format; + } + } + + for (i = 0; i < numFormats; i++) + if (formats[i].depth == depth) + break; + if (i != numFormats) + return &formats[i]; + else if (!formatsDone) { + /* Check for screen-specified formats */ + for (i = 0; i < pScrn->numFormats; i++) + if (pScrn->formats[i].depth == depth) + break; + if (i != pScrn->numFormats) + return &pScrn->formats[i]; + } + return NULL; +} + +int +xf86GetBppFromDepth(ScrnInfoPtr pScrn, int depth) +{ + PixmapFormatPtr format; + + + format = xf86GetPixFormat(pScrn, depth); + if (format) + return format->bitsPerPixel; + else + return 0; +} diff --git a/xorg-server/hw/xfree86/common/xf86VidMode.c b/xorg-server/hw/xfree86/common/xf86VidMode.c index 591c338b1..eb29fd09e 100644 --- a/xorg-server/hw/xfree86/common/xf86VidMode.c +++ b/xorg-server/hw/xfree86/common/xf86VidMode.c @@ -634,7 +634,7 @@ VidModeSetModeValue(pointer mode, int valtyp, int val) vidMonitorValue VidModeGetMonitorValue(pointer monitor, int valtyp, int indx) { - vidMonitorValue ret; + vidMonitorValue ret = { NULL, }; switch (valtyp) { case VIDMODE_MON_VENDOR: diff --git a/xorg-server/hw/xfree86/common/xf86xv.c b/xorg-server/hw/xfree86/common/xf86xv.c index 9f62a8397..8115075b3 100644 --- a/xorg-server/hw/xfree86/common/xf86xv.c +++ b/xorg-server/hw/xfree86/common/xf86xv.c @@ -97,8 +97,11 @@ static int xf86XVQueryImageAttributes(ClientPtr, XvPortPtr, XvImagePtr, static Bool xf86XVDestroyWindow(WindowPtr pWin); static void xf86XVWindowExposures(WindowPtr pWin, RegionPtr r1, RegionPtr r2); +static void xf86XVPostValidateTree(WindowPtr pWin, WindowPtr pLayerWin, VTKind kind); static void xf86XVClipNotify(WindowPtr pWin, int dx, int dy); +#define PostValidateTreeUndefined ((PostValidateTreeProcPtr)-1) + /* ScrnInfoRec functions */ static Bool xf86XVEnterVT(int, int); @@ -280,10 +283,9 @@ xf86XVScreenInit( pScrn = xf86Screens[pScreen->myNum]; - ScreenPriv->videoGC = NULL; /* for the helper */ - ScreenPriv->DestroyWindow = pScreen->DestroyWindow; ScreenPriv->WindowExposures = pScreen->WindowExposures; + ScreenPriv->PostValidateTree = PostValidateTreeUndefined; ScreenPriv->ClipNotify = pScreen->ClipNotify; ScreenPriv->EnterVT = pScrn->EnterVT; ScreenPriv->LeaveVT = pScrn->LeaveVT; @@ -333,6 +335,8 @@ xf86XVFreeAdaptor(XvAdaptorPtr pAdaptor) RegionDestroy(pPriv->clientClip); if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) RegionDestroy(pPriv->pCompositeClip); + if (pPriv->ckeyFilled) + RegionDestroy(pPriv->ckeyFilled); free(pPriv); } } @@ -1018,7 +1022,6 @@ static void xf86XVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) { XF86XVWindowPtr winPriv, prevPriv = NULL; - winPriv = GET_XF86XV_WINDOW(pWin); while(winPriv) { @@ -1035,6 +1038,11 @@ xf86XVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) winPriv = winPriv->next; } portPriv->pDraw = NULL; + if (portPriv->ckeyFilled) { + RegionDestroy(portPriv->ckeyFilled); + portPriv->ckeyFilled = NULL; + } + portPriv->clipChanged = FALSE; } static void @@ -1069,7 +1077,7 @@ xf86XVReputOrStopPort(XvPortRecPrivatePtr pPriv, } static void -xf86XVReputOrStopAllPorts(ScrnInfoPtr pScrn) +xf86XVReputOrStopAllPorts(ScrnInfoPtr pScrn, Bool onlyChanged) { ScreenPtr pScreen = pScrn->pScreen; XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); @@ -1087,6 +1095,9 @@ xf86XVReputOrStopAllPorts(ScrnInfoPtr pScrn) if (pPriv->isOn == XV_OFF || !pWin) continue; + if (onlyChanged && !pPriv->clipChanged) + continue; + visible = pWin->visibility == VisibilityUnobscured || pWin->visibility == VisibilityPartiallyObscured; @@ -1098,6 +1109,8 @@ xf86XVReputOrStopAllPorts(ScrnInfoPtr pScrn) visible = FALSE; xf86XVReputOrStopPort(pPriv, pWin, visible); + + pPriv->clipChanged = FALSE; } } } @@ -1123,9 +1136,6 @@ xf86XVDestroyWindow(WindowPtr pWin) pPriv->pDraw = NULL; tmp = WinPriv; - if(WinPriv->pGC) { - FreeGC(WinPriv->pGC, 0); - } WinPriv = WinPriv->next; free(tmp); } @@ -1139,6 +1149,29 @@ xf86XVDestroyWindow(WindowPtr pWin) return ret; } +static void +xf86XVPostValidateTree(WindowPtr pWin, WindowPtr pLayerWin, VTKind kind) +{ + ScreenPtr pScreen; + XF86XVScreenPtr ScreenPriv; + ScrnInfoPtr pScrn; + + if (pWin) + pScreen = pWin->drawable.pScreen; + else + pScreen = pLayerWin->drawable.pScreen; + + ScreenPriv = GET_XF86XV_SCREEN(pScreen); + pScrn = xf86Screens[pScreen->myNum]; + + xf86XVReputOrStopAllPorts(pScrn, TRUE); + + pScreen->PostValidateTree = ScreenPriv->PostValidateTree; + if (pScreen->PostValidateTree) { + (*pScreen->PostValidateTree)(pWin, pLayerWin, kind); + } + ScreenPriv->PostValidateTree = PostValidateTreeUndefined; +} static void xf86XVWindowExposures(WindowPtr pWin, RegionPtr reg1, RegionPtr reg2) @@ -1170,12 +1203,28 @@ xf86XVWindowExposures(WindowPtr pWin, RegionPtr reg1, RegionPtr reg2) if (!pPriv->type && !pPriv->AdaptorRec->ReputImage) visible = !AreasExposed; + /* + * Subtract exposed areas from overlaid image to match textured video + * behavior. + */ + if (!pPriv->type && pPriv->clientClip) + RegionSubtract(pPriv->clientClip, pPriv->clientClip, reg1); + + if (visible && pPriv->ckeyFilled) { + RegionRec tmp; + RegionNull(&tmp); + RegionCopy(&tmp, reg1); + RegionTranslate(&tmp, pWin->drawable.x, pWin->drawable.y); + RegionSubtract(pPriv->ckeyFilled, pPriv->ckeyFilled, &tmp); + } + WinPriv = WinPriv->next; xf86XVReputOrStopPort(pPriv, pWin, visible); + + pPriv->clipChanged = FALSE; } } - static void xf86XVClipNotify(WindowPtr pWin, int dx, int dy) { @@ -1185,9 +1234,6 @@ xf86XVClipNotify(WindowPtr pWin, int dx, int dy) XvPortRecPrivatePtr pPriv; while(WinPriv) { - Bool visible = pWin->visibility == VisibilityUnobscured || - pWin->visibility == VisibilityPartiallyObscured; - pPriv = WinPriv->PortRec; if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) @@ -1199,15 +1245,14 @@ xf86XVClipNotify(WindowPtr pWin, int dx, int dy) (*pPriv->AdaptorRec->ClipNotify)(pPriv->pScrn, pPriv->DevPriv.ptr, pWin, dx, dy); - /* - * Stop and remove still/images if - * ReputImage isn't supported. - */ - if (!pPriv->type && !pPriv->AdaptorRec->ReputImage) - visible = FALSE; + pPriv->clipChanged = TRUE; + + if (ScreenPriv->PostValidateTree == PostValidateTreeUndefined) { + ScreenPriv->PostValidateTree = pScreen->PostValidateTree; + pScreen->PostValidateTree = xf86XVPostValidateTree; + } WinPriv = WinPriv->next; - xf86XVReputOrStopPort(pPriv, pWin, visible); } if(ScreenPriv->ClipNotify) { @@ -1232,11 +1277,6 @@ xf86XVCloseScreen(int i, ScreenPtr pScreen) if(!ScreenPriv) return TRUE; - if(ScreenPriv->videoGC) { - FreeGC(ScreenPriv->videoGC, 0); - ScreenPriv->videoGC = NULL; - } - pScreen->DestroyWindow = ScreenPriv->DestroyWindow; pScreen->WindowExposures = ScreenPriv->WindowExposures; pScreen->ClipNotify = ScreenPriv->ClipNotify; @@ -1345,7 +1385,7 @@ xf86XVAdjustFrame(int index, int x, int y, int flags) pScrn->AdjustFrame = xf86XVAdjustFrame; } - xf86XVReputOrStopAllPorts(pScrn); + xf86XVReputOrStopAllPorts(pScrn, FALSE); } static void @@ -1366,7 +1406,7 @@ xf86XVModeSet(ScrnInfoPtr pScrn) pScrn->ModeSet = xf86XVModeSet; } - xf86XVReputOrStopAllPorts(pScrn); + xf86XVReputOrStopAllPorts(pScrn, FALSE); } /**** XvAdaptorRec fields ****/ @@ -1869,92 +1909,92 @@ xf86XVQueryImageAttributes( format->id, width, height, pitches, offsets); } - void -xf86XVFillKeyHelperDrawable (DrawablePtr pDraw, CARD32 key, RegionPtr clipboxes) +xf86XVFillKeyHelperDrawable (DrawablePtr pDraw, CARD32 key, RegionPtr fillboxes) { ScreenPtr pScreen = pDraw->pScreen; - WindowPtr pWin = (WindowPtr)pDraw; - XF86XVWindowPtr pPriv = GET_XF86XV_WINDOW(pWin); - GCPtr pGC = NULL; - BoxPtr pbox = RegionRects(clipboxes); - int i, nbox = RegionNumRects(clipboxes); - xRectangle *rects; - - if(!xf86Screens[pScreen->myNum]->vtSema) return; - - if(pPriv) - pGC = pPriv->pGC; - - if(!pGC) { - int status; - XID pval[2]; - pval[0] = key; - pval[1] = IncludeInferiors; - pGC = CreateGC(pDraw, GCForeground | GCSubwindowMode, pval, &status, - (XID)0, serverClient); - if(!pGC) return; - ValidateGC(pDraw, pGC); - if (pPriv) pPriv->pGC = pGC; - } else if (key != pGC->fgPixel){ - ChangeGCVal val; - val.val = key; - ChangeGC(NullClient, pGC, GCForeground, &val); - ValidateGC(pDraw, pGC); - } - - RegionTranslate(clipboxes, -pDraw->x, -pDraw->y); - - rects = malloc(nbox * sizeof(xRectangle)); - - for(i = 0; i < nbox; i++, pbox++) { - rects[i].x = pbox->x1; - rects[i].y = pbox->y1; - rects[i].width = pbox->x2 - pbox->x1; - rects[i].height = pbox->y2 - pbox->y1; - } - - (*pGC->ops->PolyFillRect)(pDraw, pGC, nbox, rects); - - if (!pPriv) FreeGC(pGC, 0); - - free(rects); -} - -void -xf86XVFillKeyHelper (ScreenPtr pScreen, CARD32 key, RegionPtr clipboxes) -{ - DrawablePtr root = &pScreen->root->drawable; ChangeGCVal pval[2]; - BoxPtr pbox = RegionRects(clipboxes); - int i, nbox = RegionNumRects(clipboxes); + BoxPtr pbox = RegionRects(fillboxes); + int i, nbox = RegionNumRects(fillboxes); xRectangle *rects; GCPtr gc; if(!xf86Screens[pScreen->myNum]->vtSema) return; - gc = GetScratchGC(root->depth, pScreen); + gc = GetScratchGC(pDraw->depth, pScreen); pval[0].val = key; pval[1].val = IncludeInferiors; (void) ChangeGC(NullClient, gc, GCForeground|GCSubwindowMode, pval); - ValidateGC(root, gc); + ValidateGC(pDraw, gc); rects = malloc(nbox * sizeof(xRectangle)); for(i = 0; i < nbox; i++, pbox++) { - rects[i].x = pbox->x1; - rects[i].y = pbox->y1; + rects[i].x = pbox->x1 - pDraw->x; + rects[i].y = pbox->y1 - pDraw->y; rects[i].width = pbox->x2 - pbox->x1; rects[i].height = pbox->y2 - pbox->y1; } - (*gc->ops->PolyFillRect)(root, gc, nbox, rects); + (*gc->ops->PolyFillRect)(pDraw, gc, nbox, rects); free(rects); FreeScratchGC (gc); } +void +xf86XVFillKeyHelper (ScreenPtr pScreen, CARD32 key, RegionPtr fillboxes) +{ + xf86XVFillKeyHelperDrawable (&pScreen->root->drawable, key, fillboxes); +} + +void +xf86XVFillKeyHelperPort (DrawablePtr pDraw, pointer data, CARD32 key, RegionPtr clipboxes, Bool fillEverything) +{ + WindowPtr pWin = (WindowPtr)pDraw; + XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin); + XvPortRecPrivatePtr portPriv = NULL; + RegionRec reg; + RegionPtr fillboxes; + + while (WinPriv) { + XvPortRecPrivatePtr pPriv = WinPriv->PortRec; + + if (data == pPriv->DevPriv.ptr) { + portPriv = pPriv; + break; + } + + WinPriv = WinPriv->next; + } + + if (!portPriv) + return; + + if (!portPriv->ckeyFilled) + portPriv->ckeyFilled = RegionCreate(NULL, 0); + + if (!fillEverything) { + RegionNull(®); + fillboxes = ® + RegionSubtract(fillboxes, clipboxes, portPriv->ckeyFilled); + + if (!RegionNotEmpty(fillboxes)) + goto out; + } else + fillboxes = clipboxes; + + + RegionCopy(portPriv->ckeyFilled, clipboxes); + + xf86XVFillKeyHelperDrawable(pDraw, key, fillboxes); +out: + if (!fillEverything) + RegionUninit(®); +} + + /* xf86XVClipVideoHelper - Takes the dst box in standard X BoxRec form (top and left diff --git a/xorg-server/hw/xfree86/common/xf86xv.h b/xorg-server/hw/xfree86/common/xf86xv.h index 25f3e4ad3..08e5c790d 100644 --- a/xorg-server/hw/xfree86/common/xf86xv.h +++ b/xorg-server/hw/xfree86/common/xf86xv.h @@ -244,6 +244,9 @@ xf86XVFillKeyHelper (ScreenPtr pScreen, CARD32 key, RegionPtr clipboxes); extern _X_EXPORT void xf86XVFillKeyHelperDrawable (DrawablePtr pDraw, CARD32 key, RegionPtr clipboxes); +extern _X_EXPORT void +xf86XVFillKeyHelperPort (DrawablePtr pDraw, pointer data, CARD32 key, RegionPtr clipboxes, Bool fillEverything); + extern _X_EXPORT Bool xf86XVClipVideoHelper( BoxPtr dst, diff --git a/xorg-server/hw/xfree86/common/xf86xvpriv.h b/xorg-server/hw/xfree86/common/xf86xvpriv.h index 35d72ca9c..7eb46e51f 100644 --- a/xorg-server/hw/xfree86/common/xf86xvpriv.h +++ b/xorg-server/hw/xfree86/common/xf86xvpriv.h @@ -40,10 +40,10 @@ typedef struct { DestroyWindowProcPtr DestroyWindow; ClipNotifyProcPtr ClipNotify; WindowExposuresProcPtr WindowExposures; + PostValidateTreeProcPtr PostValidateTree; void (*AdjustFrame)(int, int, int, int); Bool (*EnterVT)(int, int); void (*LeaveVT)(int, int); - GCPtr videoGC; xf86ModeSetProc *ModeSet; } XF86XVScreenRec, *XF86XVScreenPtr; @@ -69,11 +69,12 @@ typedef struct { unsigned char type; unsigned int subWindowMode; RegionPtr clientClip; + RegionPtr ckeyFilled; RegionPtr pCompositeClip; Bool FreeCompositeClip; XvAdaptorRecPrivatePtr AdaptorRec; XvStatus isOn; - Bool moved; + Bool clipChanged; int vid_x, vid_y, vid_w, vid_h; int drw_x, drw_y, drw_w, drw_h; DevUnion DevPriv; @@ -82,7 +83,6 @@ typedef struct { typedef struct _XF86XVWindowRec{ XvPortRecPrivatePtr PortRec; struct _XF86XVWindowRec *next; - GCPtr pGC; } XF86XVWindowRec, *XF86XVWindowPtr; #endif /* _XF86XVPRIV_H_ */ diff --git a/xorg-server/hw/xfree86/dri2/dri2.c b/xorg-server/hw/xfree86/dri2/dri2.c index aba2202d6..7d6f772d7 100644 --- a/xorg-server/hw/xfree86/dri2/dri2.c +++ b/xorg-server/hw/xfree86/dri2/dri2.c @@ -403,7 +403,7 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height, && (pDraw->height == pPriv->height) && (pPriv->serialNumber == DRI2DrawableSerial(pDraw)); - buffers = malloc((count + 1) * sizeof(buffers[0])); + buffers = calloc((count + 1), sizeof(buffers[0])); for (i = 0; i < count; i++) { const unsigned attachment = *(attachments++); diff --git a/xorg-server/hw/xfree86/fbdevhw/fbdevhw.c b/xorg-server/hw/xfree86/fbdevhw/fbdevhw.c index 49d0bd044..ef69d58bc 100644 --- a/xorg-server/hw/xfree86/fbdevhw/fbdevhw.c +++ b/xorg-server/hw/xfree86/fbdevhw/fbdevhw.c @@ -264,14 +264,7 @@ fbdev_open_pci(struct pci_device * pPci, char **namep) { struct fb_fix_screeninfo fix; char filename[256]; - int fd,i,j; - - - /* There are two ways to that we can determine which fb device is - * associated with this PCI device. The more modern way is to look in - * the sysfs directory for the PCI device for a file named - * "graphics/fb*" - */ + int fd, i; for (i = 0; i < 8; i++) { sprintf(filename, @@ -304,55 +297,10 @@ fbdev_open_pci(struct pci_device * pPci, char **namep) } } - - /* The other way is to examine the resources associated with each fb - * device and see if there is a match with the PCI device. This technique - * has some problems on certain mixed 64-bit / 32-bit architectures. - * There is a flaw in the fb_fix_screeninfo structure in that it only - * returns the low 32-bits of the address of the resources associated with - * a device. However, on a mixed architecture the base addresses of PCI - * devices, even for 32-bit applications, may be higher than 0x0f0000000. - */ - - for (i = 0; i < 8; i++) { - sprintf(filename,"/dev/fb%d",i); - if (-1 == (fd = open(filename,O_RDWR,0))) { - xf86DrvMsg(-1, X_WARNING, - "open %s: %s\n", filename, strerror(errno)); - continue; - } - if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,(void*)&fix)) { - close(fd); - continue; - } - for (j = 0; j < 6; j++) { - const pciaddr_t res_start = pPci->regions[j].base_addr; - const pciaddr_t res_end = res_start + pPci->regions[j].size; - - if ((0 != fix.smem_len && - (pciaddr_t) fix.smem_start >= res_start && - (pciaddr_t) fix.smem_start < res_end) || - (0 != fix.mmio_len && - (pciaddr_t) fix.mmio_start >= res_start && - (pciaddr_t) fix.mmio_start < res_end)) - break; - } - if (j == 6) { - close(fd); - continue; - } - if (namep) { - *namep = xnfalloc(16); - strncpy(*namep,fix.id,16); - } - return fd; - } - if (namep) *namep = NULL; - xf86DrvMsg(-1, X_ERROR, - "Unable to find a valid framebuffer device\n"); + xf86DrvMsg(-1, X_ERROR, "Unable to find a valid framebuffer device\n"); return -1; } diff --git a/xorg-server/hw/xfree86/int10/helper_exec.c b/xorg-server/hw/xfree86/int10/helper_exec.c index b9af473b1..1043fcde7 100644 --- a/xorg-server/hw/xfree86/int10/helper_exec.c +++ b/xorg-server/hw/xfree86/int10/helper_exec.c @@ -1,733 +1,733 @@ -/* - * XFree86 int10 module - * execute BIOS int 10h calls in x86 real mode environment - * Copyright 1999 Egbert Eich - * - * Part of this code was inspired by the VBIOS POSTing code in DOSEMU - * developed by the "DOSEMU-Development-Team" - */ - -/* - * To debug port accesses define PRINT_PORT to 1. - * Note! You also have to comment out ioperm() - * in xf86EnableIO(). Otherwise we won't trap - * on PIO. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include -#endif - -#define PRINT_PORT 0 - -#include - -#include -#include "xf86.h" -#include "xf86_OSproc.h" -#include "compiler.h" -#define _INT10_PRIVATE -#include "int10Defines.h" -#include "xf86int10.h" -#include "Pci.h" -#ifdef _X86EMU -#include "x86emu/x86emui.h" -#else -#define DEBUG_IO_TRACE() 0 -#endif -#include - -static int pciCfg1in(CARD16 addr, CARD32 *val); -static int pciCfg1out(CARD16 addr, CARD32 val); -static int pciCfg1inw(CARD16 addr, CARD16 *val); -static int pciCfg1outw(CARD16 addr, CARD16 val); -static int pciCfg1inb(CARD16 addr, CARD8 *val); -static int pciCfg1outb(CARD16 addr, CARD8 val); -#if defined (_PC) -static void SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set); -#endif - -#define REG pInt - -int -setup_int(xf86Int10InfoPtr pInt) -{ - if (pInt != Int10Current) { - if (!MapCurrentInt10(pInt)) - return -1; - Int10Current = pInt; - } - X86_EAX = (CARD32) pInt->ax; - X86_EBX = (CARD32) pInt->bx; - X86_ECX = (CARD32) pInt->cx; - X86_EDX = (CARD32) pInt->dx; - X86_ESI = (CARD32) pInt->si; - X86_EDI = (CARD32) pInt->di; - X86_EBP = (CARD32) pInt->bp; - X86_ESP = 0x1000; X86_SS = pInt->stackseg >> 4; - X86_EIP = 0x0600; X86_CS = 0x0; /* address of 'hlt' */ - X86_DS = 0x40; /* standard pc ds */ - X86_ES = pInt->es; - X86_FS = 0; - X86_GS = 0; - X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK; -#if defined (_PC) - if (pInt->Flags & SET_BIOS_SCRATCH) - SetResetBIOSVars(pInt, TRUE); -#endif - OsBlockSignals(); - return 0; -} - -void -finish_int(xf86Int10InfoPtr pInt, int sig) -{ - OsReleaseSignals(); - pInt->ax = (CARD32) X86_EAX; - pInt->bx = (CARD32) X86_EBX; - pInt->cx = (CARD32) X86_ECX; - pInt->dx = (CARD32) X86_EDX; - pInt->si = (CARD32) X86_ESI; - pInt->di = (CARD32) X86_EDI; - pInt->es = (CARD16) X86_ES; - pInt->bp = (CARD32) X86_EBP; - pInt->flags = (CARD32) X86_FLAGS; -#if defined (_PC) - if (pInt->Flags & RESTORE_BIOS_SCRATCH) - SetResetBIOSVars(pInt, FALSE); -#endif -} - -/* general software interrupt handler */ -CARD32 -getIntVect(xf86Int10InfoPtr pInt,int num) -{ - return MEM_RW(pInt, num << 2) + (MEM_RW(pInt, (num << 2) + 2) << 4); -} - -void -pushw(xf86Int10InfoPtr pInt, CARD16 val) -{ - X86_ESP -= 2; - MEM_WW(pInt, ((CARD32) X86_SS << 4) + X86_SP, val); -} - -int -run_bios_int(int num, xf86Int10InfoPtr pInt) -{ - CARD32 eflags; -#ifndef _PC - /* check if bios vector is initialized */ - if (MEM_RW(pInt, (num << 2) + 2) == (SYS_BIOS >> 4)) { /* SYS_BIOS_SEG ?*/ - - if (num == 21 && X86_AH == 0x4e) { - xf86DrvMsg(pInt->scrnIndex, X_NOTICE, - "Failing Find-Matching-File on non-PC" - " (int 21, func 4e)\n"); - X86_AX = 2; - SET_FLAG(F_CF); - return 1; - } else { - xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, - "Ignoring int 0x%02x call\n", num); - if (xf86GetVerbosity() > 3) { - dump_registers(pInt); - stack_trace(pInt); - } - return 1; - } - } -#endif -#ifdef PRINT_INT - ErrorF("calling card BIOS at: "); -#endif - eflags = X86_EFLAGS; -#if 0 - eflags = eflags | IF_MASK; - X86_EFLAGS = X86_EFLAGS & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK); -#endif - pushw(pInt, eflags); - pushw(pInt, X86_CS); - pushw(pInt, X86_IP); - X86_CS = MEM_RW(pInt, (num << 2) + 2); - X86_IP = MEM_RW(pInt, num << 2); -#ifdef PRINT_INT - ErrorF("0x%x:%lx\n", X86_CS, X86_EIP); -#endif - return 1; -} - -/* Debugging stuff */ -void -dump_code(xf86Int10InfoPtr pInt) -{ - int i; - unsigned long lina = SEG_ADR((CARD32), X86_CS, IP); - - xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, "code at 0x%8.8lx:\n", lina); - for (i=0; i<0x10; i++) - xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); - xf86ErrorFVerb(3, "\n"); - for (; i<0x20; i++) - xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); - xf86ErrorFVerb(3, "\n"); -} - -void -dump_registers(xf86Int10InfoPtr pInt) -{ - xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, - "EAX=0x%8.8lx, EBX=0x%8.8lx, ECX=0x%8.8lx, EDX=0x%8.8lx\n", - (unsigned long)X86_EAX, (unsigned long)X86_EBX, - (unsigned long)X86_ECX, (unsigned long)X86_EDX); - xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, - "ESP=0x%8.8lx, EBP=0x%8.8lx, ESI=0x%8.8lx, EDI=0x%8.8lx\n", - (unsigned long)X86_ESP, (unsigned long)X86_EBP, - (unsigned long)X86_ESI, (unsigned long)X86_EDI); - xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, - "CS=0x%4.4x, SS=0x%4.4x," - " DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n", - X86_CS, X86_SS, X86_DS, X86_ES, X86_FS, X86_GS); - xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, - "EIP=0x%8.8lx, EFLAGS=0x%8.8lx\n", - (unsigned long)X86_EIP, (unsigned long)X86_EFLAGS); -} - -void -stack_trace(xf86Int10InfoPtr pInt) -{ - int i = 0; - unsigned long stack = SEG_ADR((CARD32), X86_SS, SP); - unsigned long tail = (CARD32)((X86_SS << 4) + 0x1000); - - if (stack >= tail) return; - - xf86MsgVerb(X_INFO, 3, "stack at 0x%8.8lx:\n", stack); - for (; stack < tail; stack++) { - xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, stack)); - i = (i + 1) % 0x10; - if (!i) - xf86ErrorFVerb(3, "\n"); - } - if (i) - xf86ErrorFVerb(3, "\n"); -} - -int -port_rep_inb(xf86Int10InfoPtr pInt, - CARD16 port, CARD32 base, int d_f, CARD32 count) -{ - register int inc = d_f ? -1 : 1; - CARD32 dst = base; - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" rep_insb(%#x) %ld bytes at %8.8lx %s\n", - port, count, base, d_f ? "up" : "down"); - while (count--) { - MEM_WB(pInt, dst, x_inb(port)); - dst += inc; - } - return dst - base; -} - -int -port_rep_inw(xf86Int10InfoPtr pInt, - CARD16 port, CARD32 base, int d_f, CARD32 count) -{ - register int inc = d_f ? -2 : 2; - CARD32 dst = base; - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" rep_insw(%#x) %ld bytes at %8.8lx %s\n", - port, count, base, d_f ? "up" : "down"); - while (count--) { - MEM_WW(pInt, dst, x_inw(port)); - dst += inc; - } - return dst - base; -} - -int -port_rep_inl(xf86Int10InfoPtr pInt, - CARD16 port, CARD32 base, int d_f, CARD32 count) -{ - register int inc = d_f ? -4 : 4; - CARD32 dst = base; - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" rep_insl(%#x) %ld bytes at %8.8lx %s\n", - port, count, base, d_f ? "up" : "down"); - while (count--) { - MEM_WL(pInt, dst, x_inl(port)); - dst += inc; - } - return dst - base; -} - -int -port_rep_outb(xf86Int10InfoPtr pInt, - CARD16 port, CARD32 base, int d_f, CARD32 count) -{ - register int inc = d_f ? -1 : 1; - CARD32 dst = base; - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" rep_outb(%#x) %ld bytes at %8.8lx %s\n", - port, count, base, d_f ? "up" : "down"); - while (count--) { - x_outb(port, MEM_RB(pInt, dst)); - dst += inc; - } - return dst - base; -} - -int -port_rep_outw(xf86Int10InfoPtr pInt, - CARD16 port, CARD32 base, int d_f, CARD32 count) -{ - register int inc = d_f ? -2 : 2; - CARD32 dst = base; - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" rep_outw(%#x) %ld bytes at %8.8lx %s\n", - port, count, base, d_f ? "up" : "down"); - while (count--) { - x_outw(port, MEM_RW(pInt, dst)); - dst += inc; - } - return dst - base; -} - -int -port_rep_outl(xf86Int10InfoPtr pInt, - CARD16 port, CARD32 base, int d_f, CARD32 count) -{ - register int inc = d_f ? -4 : 4; - CARD32 dst = base; - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" rep_outl(%#x) %ld bytes at %8.8lx %s\n", - port, count, base, d_f ? "up" : "down"); - while (count--) { - x_outl(port, MEM_RL(pInt, dst)); - dst += inc; - } - return dst - base; -} - -CARD8 -x_inb(CARD16 port) -{ - CARD8 val; - - if (port == 0x40) { - Int10Current->inb40time++; - val = (CARD8)(Int10Current->inb40time >> - ((Int10Current->inb40time & 1) << 3)); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" inb(%#x) = %2.2x\n", port, val); -#ifdef __NOT_YET__ - } else if (port < 0x0100) { /* Don't interfere with mainboard */ - val = 0; - xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2, - "inb 0x%4.4x\n", port); - if (xf86GetVerbosity() > 3) { - dump_registers(Int10Current); - stack_trace(Int10Current); - } -#endif /* __NOT_YET__ */ - } else if (!pciCfg1inb(port, &val)) { - val = inb(Int10Current->ioBase + port); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" inb(%#x) = %2.2x\n", port, val); - } - return val; -} - -CARD16 -x_inw(CARD16 port) -{ - CARD16 val; - - if (port == 0x5c) { - struct timeval tv; - - /* - * Emulate a PC98's timer. Typical resolution is 3.26 usec. - * Approximate this by dividing by 3. - */ - X_GETTIMEOFDAY(&tv); - val = (CARD16)(tv.tv_usec / 3); - } else if (!pciCfg1inw(port, &val)) { - val = inw(Int10Current->ioBase + port); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" inw(%#x) = %4.4x\n", port, val); - } - return val; -} - -void -x_outb(CARD16 port, CARD8 val) -{ - if ((port == 0x43) && (val == 0)) { - struct timeval tv; - /* - * Emulate a PC's timer 0. Such timers typically have a resolution of - * some .838 usec per tick, but this can only provide 1 usec per tick. - * (Not that this matters much, given inherent emulation delays.) Use - * the bottom bit as a byte select. See inb(0x40) above. - */ - X_GETTIMEOFDAY(&tv); - Int10Current->inb40time = (CARD16)(tv.tv_usec | 1); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" outb(%#x, %2.2x)\n", port, val); -#ifdef __NOT_YET__ - } else if (port < 0x0100) { /* Don't interfere with mainboard */ - xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2, - "outb 0x%4.4x,0x%2.2x\n", port, val); - if (xf86GetVerbosity() > 3) { - dump_registers(Int10Current); - stack_trace(Int10Current); - } -#endif /* __NOT_YET__ */ - } else if (!pciCfg1outb(port, val)) { - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" outb(%#x, %2.2x)\n", port, val); - outb(Int10Current->ioBase + port, val); - } -} - -void -x_outw(CARD16 port, CARD16 val) -{ - - if (!pciCfg1outw(port, val)) { - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" outw(%#x, %4.4x)\n", port, val); - outw(Int10Current->ioBase + port, val); - } -} - -CARD32 -x_inl(CARD16 port) -{ - CARD32 val; - - if (!pciCfg1in(port, &val)) { - val = inl(Int10Current->ioBase + port); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" inl(%#x) = %8.8lx\n", port, val); - } - return val; -} - -void -x_outl(CARD16 port, CARD32 val) -{ - if (!pciCfg1out(port, val)) { - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" outl(%#x, %8.8lx)\n", port, val); - outl(Int10Current->ioBase + port, val); - } -} - -CARD8 -Mem_rb(CARD32 addr) -{ - return (*Int10Current->mem->rb)(Int10Current, addr); -} - -CARD16 -Mem_rw(CARD32 addr) -{ - return (*Int10Current->mem->rw)(Int10Current, addr); -} - -CARD32 -Mem_rl(CARD32 addr) -{ - return (*Int10Current->mem->rl)(Int10Current, addr); -} - -void -Mem_wb(CARD32 addr, CARD8 val) -{ - (*Int10Current->mem->wb)(Int10Current, addr, val); -} - -void -Mem_ww(CARD32 addr, CARD16 val) -{ - (*Int10Current->mem->ww)(Int10Current, addr, val); -} - -void -Mem_wl(CARD32 addr, CARD32 val) -{ - (*Int10Current->mem->wl)(Int10Current, addr, val); -} - -static CARD32 PciCfg1Addr = 0; - -#define PCI_DOM_FROM_TAG(tag) (((tag) >> 24) & (PCI_DOM_MASK)) -#define PCI_BUS_FROM_TAG(tag) (((tag) >> 16) & (PCI_DOMBUS_MASK)) -#define PCI_DEV_FROM_TAG(tag) (((tag) & 0x0000f800u) >> 11) -#define PCI_FUNC_FROM_TAG(tag) (((tag) & 0x00000700u) >> 8) - -#define PCI_OFFSET(x) ((x) & 0x000000ff) -#define PCI_TAG(x) ((x) & 0x7fffff00) - -static struct pci_device* -pci_device_for_cfg_address (CARD32 addr) -{ - struct pci_device *dev = NULL; - PCITAG tag = PCI_TAG(addr); - struct pci_slot_match slot_match = { - .domain = PCI_DOM_FROM_TAG(tag), - .bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(tag)), - .dev = PCI_DEV_FROM_TAG(tag), - .func = PCI_FUNC_FROM_TAG(tag), - .match_data = 0 - }; - - struct pci_device_iterator *iter = - pci_slot_match_iterator_create (&slot_match); - - if (iter) - dev = pci_device_next(iter); - - pci_iterator_destroy(iter); - - return dev; -} - -static int -pciCfg1in(CARD16 addr, CARD32 *val) -{ - if (addr == 0xCF8) { - *val = PciCfg1Addr; - return 1; - } - if (addr == 0xCFC) { - pci_device_cfg_read_u32(pci_device_for_cfg_address(PciCfg1Addr), - val, PCI_OFFSET(PciCfg1Addr)); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" cfg_inl(%#lx) = %8.8lx\n", PciCfg1Addr, *val); - return 1; - } - return 0; -} - -static int -pciCfg1out(CARD16 addr, CARD32 val) -{ - if (addr == 0xCF8) { - PciCfg1Addr = val; - return 1; - } - if (addr == 0xCFC) { - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" cfg_outl(%#lx, %8.8lx)\n", PciCfg1Addr, val); - pci_device_cfg_write_u32(pci_device_for_cfg_address(PciCfg1Addr), - val, PCI_OFFSET(PciCfg1Addr)); - return 1; - } - return 0; -} - -static int -pciCfg1inw(CARD16 addr, CARD16 *val) -{ - int shift; - - if ((addr >= 0xCF8) && (addr <= 0xCFB)) { - shift = (addr - 0xCF8) * 8; - *val = (PciCfg1Addr >> shift) & 0xffff; - return 1; - } - if ((addr >= 0xCFC) && (addr <= 0xCFF)) { - const unsigned offset = addr - 0xCFC; - - pci_device_cfg_read_u16(pci_device_for_cfg_address(PciCfg1Addr), - val, PCI_OFFSET(PciCfg1Addr) + offset); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" cfg_inw(%#lx) = %4.4x\n", PciCfg1Addr + offset, *val); - return 1; - } - return 0; -} - -static int -pciCfg1outw(CARD16 addr, CARD16 val) -{ - int shift; - - if ((addr >= 0xCF8) && (addr <= 0xCFB)) { - shift = (addr - 0xCF8) * 8; - PciCfg1Addr &= ~(0xffff << shift); - PciCfg1Addr |= ((CARD32) val) << shift; - return 1; - } - if ((addr >= 0xCFC) && (addr <= 0xCFF)) { - const unsigned offset = addr - 0xCFC; - - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" cfg_outw(%#lx, %4.4x)\n", PciCfg1Addr + offset, val); - pci_device_cfg_write_u16(pci_device_for_cfg_address(PciCfg1Addr), - val, PCI_OFFSET(PciCfg1Addr) + offset); - return 1; - } - return 0; -} - -static int -pciCfg1inb(CARD16 addr, CARD8 *val) -{ - int shift; - - if ((addr >= 0xCF8) && (addr <= 0xCFB)) { - shift = (addr - 0xCF8) * 8; - *val = (PciCfg1Addr >> shift) & 0xff; - return 1; - } - if ((addr >= 0xCFC) && (addr <= 0xCFF)) { - const unsigned offset = addr - 0xCFC; - - pci_device_cfg_read_u8(pci_device_for_cfg_address(PciCfg1Addr), - val, PCI_OFFSET(PciCfg1Addr) + offset); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" cfg_inb(%#lx) = %2.2x\n", PciCfg1Addr + offset, *val); - return 1; - } - return 0; -} - -static int -pciCfg1outb(CARD16 addr, CARD8 val) -{ - int shift; - - if ((addr >= 0xCF8) && (addr <= 0xCFB)) { - shift = (addr - 0xCF8) * 8; - PciCfg1Addr &= ~(0xff << shift); - PciCfg1Addr |= ((CARD32) val) << shift; - return 1; - } - if ((addr >= 0xCFC) && (addr <= 0xCFF)) { - const unsigned offset = addr - 0xCFC; - - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" cfg_outb(%#lx, %2.2x)\n", PciCfg1Addr + offset, val); - pci_device_cfg_write_u8(pci_device_for_cfg_address(PciCfg1Addr), - val, PCI_OFFSET(PciCfg1Addr) + offset); - return 1; - } - return 0; -} - -CARD8 -bios_checksum(const CARD8 *start, int size) -{ - CARD8 sum = 0; - - while (size-- > 0) - sum += *start++; - return sum; -} - -/* - * Lock/Unlock legacy VGA. Some Bioses try to be very clever and make - * an attempt to detect a legacy ISA card. If they find one they might - * act very strange: for example they might configure the card as a - * monochrome card. This might cause some drivers to choke. - * To avoid this we attempt legacy VGA by writing to all know VGA - * disable registers before we call the BIOS initialization and - * restore the original values afterwards. In beween we hold our - * breath. To get to a (possibly exising) ISA card need to disable - * our current PCI card. - */ -/* - * This is just for booting: we just want to catch pure - * legacy vga therefore we don't worry about mmio etc. - * This stuff should really go into vgaHW.c. However then - * the driver would have to load the vga-module prior to - * doing int10. - */ -void -LockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) -{ - vga->save_msr = inb(pInt->ioBase + 0x03CC); - vga->save_vse = inb(pInt->ioBase + 0x03C3); -#ifndef __ia64__ - vga->save_46e8 = inb(pInt->ioBase + 0x46E8); -#endif - vga->save_pos102 = inb(pInt->ioBase + 0x0102); - outb(pInt->ioBase + 0x03C2, ~(CARD8)0x03 & vga->save_msr); - outb(pInt->ioBase + 0x03C3, ~(CARD8)0x01 & vga->save_vse); -#ifndef __ia64__ - outb(pInt->ioBase + 0x46E8, ~(CARD8)0x08 & vga->save_46e8); -#endif - outb(pInt->ioBase + 0x0102, ~(CARD8)0x01 & vga->save_pos102); -} - -void -UnlockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) -{ - outb(pInt->ioBase + 0x0102, vga->save_pos102); -#ifndef __ia64__ - outb(pInt->ioBase + 0x46E8, vga->save_46e8); -#endif - outb(pInt->ioBase + 0x03C3, vga->save_vse); - outb(pInt->ioBase + 0x03C2, vga->save_msr); -} - -#if defined (_PC) -static void -SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set) -{ - int pagesize = getpagesize(); - unsigned char* base = xf86MapVidMem(pInt->scrnIndex, - VIDMEM_MMIO, 0, pagesize); - int i; - - if (set) { - for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) - MEM_WW(pInt, i, *(base + i)); - } else { - for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) - *(base + i) = MEM_RW(pInt, i); - } - - xf86UnMapVidMem(pInt->scrnIndex,base,pagesize); -} - -void -xf86Int10SaveRestoreBIOSVars(xf86Int10InfoPtr pInt, Bool save) -{ - int pagesize = getpagesize(); - unsigned char* base; - int i; - - if (!xf86IsEntityPrimary(pInt->entityIndex) - || (!save && !pInt->BIOSScratch)) - return; - - base = xf86MapVidMem(pInt->scrnIndex, VIDMEM_MMIO, 0, pagesize); - base += BIOS_SCRATCH_OFF; - if (save) { - if ((pInt->BIOSScratch - = xnfalloc(BIOS_SCRATCH_LEN))) - for (i = 0; i < BIOS_SCRATCH_LEN; i++) - *(((char*)pInt->BIOSScratch + i)) = *(base + i); - } else { - if (pInt->BIOSScratch) { - for (i = 0; i < BIOS_SCRATCH_LEN; i++) - *(base + i) = *(pInt->BIOSScratch + i); - free(pInt->BIOSScratch); - pInt->BIOSScratch = NULL; - } - } - - xf86UnMapVidMem(pInt->scrnIndex,base - BIOS_SCRATCH_OFF ,pagesize); -} -#endif - -xf86Int10InfoPtr -xf86InitInt10(int entityIndex) -{ - return xf86ExtendedInitInt10(entityIndex, 0); -} +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + * + * Part of this code was inspired by the VBIOS POSTing code in DOSEMU + * developed by the "DOSEMU-Development-Team" + */ + +/* + * To debug port accesses define PRINT_PORT to 1. + * Note! You also have to comment out ioperm() + * in xf86EnableIO(). Otherwise we won't trap + * on PIO. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#define PRINT_PORT 0 + +#include + +#include +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" +#define _INT10_PRIVATE +#include "int10Defines.h" +#include "xf86int10.h" +#include "Pci.h" +#ifdef _X86EMU +#include "x86emu/x86emui.h" +#else +#define DEBUG_IO_TRACE() 0 +#endif +#include + +static int pciCfg1in(CARD16 addr, CARD32 *val); +static int pciCfg1out(CARD16 addr, CARD32 val); +static int pciCfg1inw(CARD16 addr, CARD16 *val); +static int pciCfg1outw(CARD16 addr, CARD16 val); +static int pciCfg1inb(CARD16 addr, CARD8 *val); +static int pciCfg1outb(CARD16 addr, CARD8 val); +#if defined (_PC) +static void SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set); +#endif + +#define REG pInt + +int +setup_int(xf86Int10InfoPtr pInt) +{ + if (pInt != Int10Current) { + if (!MapCurrentInt10(pInt)) + return -1; + Int10Current = pInt; + } + X86_EAX = (CARD32) pInt->ax; + X86_EBX = (CARD32) pInt->bx; + X86_ECX = (CARD32) pInt->cx; + X86_EDX = (CARD32) pInt->dx; + X86_ESI = (CARD32) pInt->si; + X86_EDI = (CARD32) pInt->di; + X86_EBP = (CARD32) pInt->bp; + X86_ESP = 0x1000; X86_SS = pInt->stackseg >> 4; + X86_EIP = 0x0600; X86_CS = 0x0; /* address of 'hlt' */ + X86_DS = 0x40; /* standard pc ds */ + X86_ES = pInt->es; + X86_FS = 0; + X86_GS = 0; + X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK; +#if defined (_PC) + if (pInt->Flags & SET_BIOS_SCRATCH) + SetResetBIOSVars(pInt, TRUE); +#endif + OsBlockSignals(); + return 0; +} + +void +finish_int(xf86Int10InfoPtr pInt, int sig) +{ + OsReleaseSignals(); + pInt->ax = (CARD32) X86_EAX; + pInt->bx = (CARD32) X86_EBX; + pInt->cx = (CARD32) X86_ECX; + pInt->dx = (CARD32) X86_EDX; + pInt->si = (CARD32) X86_ESI; + pInt->di = (CARD32) X86_EDI; + pInt->es = (CARD16) X86_ES; + pInt->bp = (CARD32) X86_EBP; + pInt->flags = (CARD32) X86_FLAGS; +#if defined (_PC) + if (pInt->Flags & RESTORE_BIOS_SCRATCH) + SetResetBIOSVars(pInt, FALSE); +#endif +} + +/* general software interrupt handler */ +CARD32 +getIntVect(xf86Int10InfoPtr pInt,int num) +{ + return MEM_RW(pInt, num << 2) + (MEM_RW(pInt, (num << 2) + 2) << 4); +} + +void +pushw(xf86Int10InfoPtr pInt, CARD16 val) +{ + X86_ESP -= 2; + MEM_WW(pInt, ((CARD32) X86_SS << 4) + X86_SP, val); +} + +int +run_bios_int(int num, xf86Int10InfoPtr pInt) +{ + CARD32 eflags; +#ifndef _PC + /* check if bios vector is initialized */ + if (MEM_RW(pInt, (num << 2) + 2) == (SYS_BIOS >> 4)) { /* SYS_BIOS_SEG ?*/ + + if (num == 21 && X86_AH == 0x4e) { + xf86DrvMsg(pInt->scrnIndex, X_NOTICE, + "Failing Find-Matching-File on non-PC" + " (int 21, func 4e)\n"); + X86_AX = 2; + SET_FLAG(F_CF); + return 1; + } else { + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "Ignoring int 0x%02x call\n", num); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + return 1; + } + } +#endif +#ifdef PRINT_INT + ErrorF("calling card BIOS at: "); +#endif + eflags = X86_EFLAGS; +#if 0 + eflags = eflags | IF_MASK; + X86_EFLAGS = X86_EFLAGS & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK); +#endif + pushw(pInt, eflags); + pushw(pInt, X86_CS); + pushw(pInt, X86_IP); + X86_CS = MEM_RW(pInt, (num << 2) + 2); + X86_IP = MEM_RW(pInt, num << 2); +#ifdef PRINT_INT + ErrorF("0x%x:%lx\n", X86_CS, X86_EIP); +#endif + return 1; +} + +/* Debugging stuff */ +void +dump_code(xf86Int10InfoPtr pInt) +{ + int i; + unsigned long lina = SEG_ADR((CARD32), X86_CS, IP); + + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, "code at 0x%8.8lx:\n", lina); + for (i=0; i<0x10; i++) + xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); + xf86ErrorFVerb(3, "\n"); + for (; i<0x20; i++) + xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); + xf86ErrorFVerb(3, "\n"); +} + +void +dump_registers(xf86Int10InfoPtr pInt) +{ + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, + "EAX=0x%8.8lx, EBX=0x%8.8lx, ECX=0x%8.8lx, EDX=0x%8.8lx\n", + (unsigned long)X86_EAX, (unsigned long)X86_EBX, + (unsigned long)X86_ECX, (unsigned long)X86_EDX); + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, + "ESP=0x%8.8lx, EBP=0x%8.8lx, ESI=0x%8.8lx, EDI=0x%8.8lx\n", + (unsigned long)X86_ESP, (unsigned long)X86_EBP, + (unsigned long)X86_ESI, (unsigned long)X86_EDI); + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, + "CS=0x%4.4x, SS=0x%4.4x," + " DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n", + X86_CS, X86_SS, X86_DS, X86_ES, X86_FS, X86_GS); + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, + "EIP=0x%8.8lx, EFLAGS=0x%8.8lx\n", + (unsigned long)X86_EIP, (unsigned long)X86_EFLAGS); +} + +void +stack_trace(xf86Int10InfoPtr pInt) +{ + int i = 0; + unsigned long stack = SEG_ADR((CARD32), X86_SS, SP); + unsigned long tail = (CARD32)((X86_SS << 4) + 0x1000); + + if (stack >= tail) return; + + xf86MsgVerb(X_INFO, 3, "stack at 0x%8.8lx:\n", stack); + for (; stack < tail; stack++) { + xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, stack)); + i = (i + 1) % 0x10; + if (!i) + xf86ErrorFVerb(3, "\n"); + } + if (i) + xf86ErrorFVerb(3, "\n"); +} + +int +port_rep_inb(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -1 : 1; + CARD32 dst = base; + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" rep_insb(%#x) %ld bytes at %8.8lx %s\n", + port, count, base, d_f ? "up" : "down"); + while (count--) { + MEM_WB(pInt, dst, x_inb(port)); + dst += inc; + } + return dst - base; +} + +int +port_rep_inw(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -2 : 2; + CARD32 dst = base; + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" rep_insw(%#x) %ld bytes at %8.8lx %s\n", + port, count, base, d_f ? "up" : "down"); + while (count--) { + MEM_WW(pInt, dst, x_inw(port)); + dst += inc; + } + return dst - base; +} + +int +port_rep_inl(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -4 : 4; + CARD32 dst = base; + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" rep_insl(%#x) %ld bytes at %8.8lx %s\n", + port, count, base, d_f ? "up" : "down"); + while (count--) { + MEM_WL(pInt, dst, x_inl(port)); + dst += inc; + } + return dst - base; +} + +int +port_rep_outb(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -1 : 1; + CARD32 dst = base; + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" rep_outb(%#x) %ld bytes at %8.8lx %s\n", + port, count, base, d_f ? "up" : "down"); + while (count--) { + x_outb(port, MEM_RB(pInt, dst)); + dst += inc; + } + return dst - base; +} + +int +port_rep_outw(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -2 : 2; + CARD32 dst = base; + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" rep_outw(%#x) %ld bytes at %8.8lx %s\n", + port, count, base, d_f ? "up" : "down"); + while (count--) { + x_outw(port, MEM_RW(pInt, dst)); + dst += inc; + } + return dst - base; +} + +int +port_rep_outl(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -4 : 4; + CARD32 dst = base; + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" rep_outl(%#x) %ld bytes at %8.8lx %s\n", + port, count, base, d_f ? "up" : "down"); + while (count--) { + x_outl(port, MEM_RL(pInt, dst)); + dst += inc; + } + return dst - base; +} + +CARD8 +x_inb(CARD16 port) +{ + CARD8 val; + + if (port == 0x40) { + Int10Current->inb40time++; + val = (CARD8)(Int10Current->inb40time >> + ((Int10Current->inb40time & 1) << 3)); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" inb(%#x) = %2.2x\n", port, val); +#ifdef __NOT_YET__ + } else if (port < 0x0100) { /* Don't interfere with mainboard */ + val = 0; + xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2, + "inb 0x%4.4x\n", port); + if (xf86GetVerbosity() > 3) { + dump_registers(Int10Current); + stack_trace(Int10Current); + } +#endif /* __NOT_YET__ */ + } else if (!pciCfg1inb(port, &val)) { + val = inb(Int10Current->ioBase + port); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" inb(%#x) = %2.2x\n", port, val); + } + return val; +} + +CARD16 +x_inw(CARD16 port) +{ + CARD16 val; + + if (port == 0x5c) { + struct timeval tv; + + /* + * Emulate a PC98's timer. Typical resolution is 3.26 usec. + * Approximate this by dividing by 3. + */ + X_GETTIMEOFDAY(&tv); + val = (CARD16)(tv.tv_usec / 3); + } else if (!pciCfg1inw(port, &val)) { + val = inw(Int10Current->ioBase + port); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" inw(%#x) = %4.4x\n", port, val); + } + return val; +} + +void +x_outb(CARD16 port, CARD8 val) +{ + if ((port == 0x43) && (val == 0)) { + struct timeval tv; + /* + * Emulate a PC's timer 0. Such timers typically have a resolution of + * some .838 usec per tick, but this can only provide 1 usec per tick. + * (Not that this matters much, given inherent emulation delays.) Use + * the bottom bit as a byte select. See inb(0x40) above. + */ + X_GETTIMEOFDAY(&tv); + Int10Current->inb40time = (CARD16)(tv.tv_usec | 1); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" outb(%#x, %2.2x)\n", port, val); +#ifdef __NOT_YET__ + } else if (port < 0x0100) { /* Don't interfere with mainboard */ + xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2, + "outb 0x%4.4x,0x%2.2x\n", port, val); + if (xf86GetVerbosity() > 3) { + dump_registers(Int10Current); + stack_trace(Int10Current); + } +#endif /* __NOT_YET__ */ + } else if (!pciCfg1outb(port, val)) { + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" outb(%#x, %2.2x)\n", port, val); + outb(Int10Current->ioBase + port, val); + } +} + +void +x_outw(CARD16 port, CARD16 val) +{ + + if (!pciCfg1outw(port, val)) { + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" outw(%#x, %4.4x)\n", port, val); + outw(Int10Current->ioBase + port, val); + } +} + +CARD32 +x_inl(CARD16 port) +{ + CARD32 val; + + if (!pciCfg1in(port, &val)) { + val = inl(Int10Current->ioBase + port); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" inl(%#x) = %8.8lx\n", port, val); + } + return val; +} + +void +x_outl(CARD16 port, CARD32 val) +{ + if (!pciCfg1out(port, val)) { + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" outl(%#x, %8.8lx)\n", port, val); + outl(Int10Current->ioBase + port, val); + } +} + +CARD8 +Mem_rb(CARD32 addr) +{ + return (*Int10Current->mem->rb)(Int10Current, addr); +} + +CARD16 +Mem_rw(CARD32 addr) +{ + return (*Int10Current->mem->rw)(Int10Current, addr); +} + +CARD32 +Mem_rl(CARD32 addr) +{ + return (*Int10Current->mem->rl)(Int10Current, addr); +} + +void +Mem_wb(CARD32 addr, CARD8 val) +{ + (*Int10Current->mem->wb)(Int10Current, addr, val); +} + +void +Mem_ww(CARD32 addr, CARD16 val) +{ + (*Int10Current->mem->ww)(Int10Current, addr, val); +} + +void +Mem_wl(CARD32 addr, CARD32 val) +{ + (*Int10Current->mem->wl)(Int10Current, addr, val); +} + +static CARD32 PciCfg1Addr = 0; + +#define PCI_DOM_FROM_TAG(tag) (((tag) >> 24) & (PCI_DOM_MASK)) +#define PCI_BUS_FROM_TAG(tag) (((tag) >> 16) & (PCI_DOMBUS_MASK)) +#define PCI_DEV_FROM_TAG(tag) (((tag) & 0x0000f800u) >> 11) +#define PCI_FUNC_FROM_TAG(tag) (((tag) & 0x00000700u) >> 8) + +#define PCI_OFFSET(x) ((x) & 0x000000ff) +#define PCI_TAG(x) ((x) & 0x7fffff00) + +static struct pci_device* +pci_device_for_cfg_address (CARD32 addr) +{ + struct pci_device *dev = NULL; + PCITAG tag = PCI_TAG(addr); + struct pci_slot_match slot_match = { + .domain = PCI_DOM_FROM_TAG(tag), + .bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(tag)), + .dev = PCI_DEV_FROM_TAG(tag), + .func = PCI_FUNC_FROM_TAG(tag), + .match_data = 0 + }; + + struct pci_device_iterator *iter = + pci_slot_match_iterator_create (&slot_match); + + if (iter) + dev = pci_device_next(iter); + + pci_iterator_destroy(iter); + + return dev; +} + +static int +pciCfg1in(CARD16 addr, CARD32 *val) +{ + if (addr == 0xCF8) { + *val = PciCfg1Addr; + return 1; + } + if (addr == 0xCFC) { + pci_device_cfg_read_u32(pci_device_for_cfg_address(PciCfg1Addr), + (uint32_t *)val, PCI_OFFSET(PciCfg1Addr)); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" cfg_inl(%#lx) = %8.8lx\n", PciCfg1Addr, *val); + return 1; + } + return 0; +} + +static int +pciCfg1out(CARD16 addr, CARD32 val) +{ + if (addr == 0xCF8) { + PciCfg1Addr = val; + return 1; + } + if (addr == 0xCFC) { + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" cfg_outl(%#lx, %8.8lx)\n", PciCfg1Addr, val); + pci_device_cfg_write_u32(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr)); + return 1; + } + return 0; +} + +static int +pciCfg1inw(CARD16 addr, CARD16 *val) +{ + int shift; + + if ((addr >= 0xCF8) && (addr <= 0xCFB)) { + shift = (addr - 0xCF8) * 8; + *val = (PciCfg1Addr >> shift) & 0xffff; + return 1; + } + if ((addr >= 0xCFC) && (addr <= 0xCFF)) { + const unsigned offset = addr - 0xCFC; + + pci_device_cfg_read_u16(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr) + offset); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" cfg_inw(%#lx) = %4.4x\n", PciCfg1Addr + offset, *val); + return 1; + } + return 0; +} + +static int +pciCfg1outw(CARD16 addr, CARD16 val) +{ + int shift; + + if ((addr >= 0xCF8) && (addr <= 0xCFB)) { + shift = (addr - 0xCF8) * 8; + PciCfg1Addr &= ~(0xffff << shift); + PciCfg1Addr |= ((CARD32) val) << shift; + return 1; + } + if ((addr >= 0xCFC) && (addr <= 0xCFF)) { + const unsigned offset = addr - 0xCFC; + + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" cfg_outw(%#lx, %4.4x)\n", PciCfg1Addr + offset, val); + pci_device_cfg_write_u16(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr) + offset); + return 1; + } + return 0; +} + +static int +pciCfg1inb(CARD16 addr, CARD8 *val) +{ + int shift; + + if ((addr >= 0xCF8) && (addr <= 0xCFB)) { + shift = (addr - 0xCF8) * 8; + *val = (PciCfg1Addr >> shift) & 0xff; + return 1; + } + if ((addr >= 0xCFC) && (addr <= 0xCFF)) { + const unsigned offset = addr - 0xCFC; + + pci_device_cfg_read_u8(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr) + offset); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" cfg_inb(%#lx) = %2.2x\n", PciCfg1Addr + offset, *val); + return 1; + } + return 0; +} + +static int +pciCfg1outb(CARD16 addr, CARD8 val) +{ + int shift; + + if ((addr >= 0xCF8) && (addr <= 0xCFB)) { + shift = (addr - 0xCF8) * 8; + PciCfg1Addr &= ~(0xff << shift); + PciCfg1Addr |= ((CARD32) val) << shift; + return 1; + } + if ((addr >= 0xCFC) && (addr <= 0xCFF)) { + const unsigned offset = addr - 0xCFC; + + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" cfg_outb(%#lx, %2.2x)\n", PciCfg1Addr + offset, val); + pci_device_cfg_write_u8(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr) + offset); + return 1; + } + return 0; +} + +CARD8 +bios_checksum(const CARD8 *start, int size) +{ + CARD8 sum = 0; + + while (size-- > 0) + sum += *start++; + return sum; +} + +/* + * Lock/Unlock legacy VGA. Some Bioses try to be very clever and make + * an attempt to detect a legacy ISA card. If they find one they might + * act very strange: for example they might configure the card as a + * monochrome card. This might cause some drivers to choke. + * To avoid this we attempt legacy VGA by writing to all know VGA + * disable registers before we call the BIOS initialization and + * restore the original values afterwards. In beween we hold our + * breath. To get to a (possibly exising) ISA card need to disable + * our current PCI card. + */ +/* + * This is just for booting: we just want to catch pure + * legacy vga therefore we don't worry about mmio etc. + * This stuff should really go into vgaHW.c. However then + * the driver would have to load the vga-module prior to + * doing int10. + */ +void +LockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) +{ + vga->save_msr = inb(pInt->ioBase + 0x03CC); + vga->save_vse = inb(pInt->ioBase + 0x03C3); +#ifndef __ia64__ + vga->save_46e8 = inb(pInt->ioBase + 0x46E8); +#endif + vga->save_pos102 = inb(pInt->ioBase + 0x0102); + outb(pInt->ioBase + 0x03C2, ~(CARD8)0x03 & vga->save_msr); + outb(pInt->ioBase + 0x03C3, ~(CARD8)0x01 & vga->save_vse); +#ifndef __ia64__ + outb(pInt->ioBase + 0x46E8, ~(CARD8)0x08 & vga->save_46e8); +#endif + outb(pInt->ioBase + 0x0102, ~(CARD8)0x01 & vga->save_pos102); +} + +void +UnlockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) +{ + outb(pInt->ioBase + 0x0102, vga->save_pos102); +#ifndef __ia64__ + outb(pInt->ioBase + 0x46E8, vga->save_46e8); +#endif + outb(pInt->ioBase + 0x03C3, vga->save_vse); + outb(pInt->ioBase + 0x03C2, vga->save_msr); +} + +#if defined (_PC) +static void +SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set) +{ + int pagesize = getpagesize(); + unsigned char* base = xf86MapVidMem(pInt->scrnIndex, + VIDMEM_MMIO, 0, pagesize); + int i; + + if (set) { + for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) + MEM_WW(pInt, i, *(base + i)); + } else { + for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) + *(base + i) = MEM_RW(pInt, i); + } + + xf86UnMapVidMem(pInt->scrnIndex,base,pagesize); +} + +void +xf86Int10SaveRestoreBIOSVars(xf86Int10InfoPtr pInt, Bool save) +{ + int pagesize = getpagesize(); + unsigned char* base; + int i; + + if (!xf86IsEntityPrimary(pInt->entityIndex) + || (!save && !pInt->BIOSScratch)) + return; + + base = xf86MapVidMem(pInt->scrnIndex, VIDMEM_MMIO, 0, pagesize); + base += BIOS_SCRATCH_OFF; + if (save) { + if ((pInt->BIOSScratch + = xnfalloc(BIOS_SCRATCH_LEN))) + for (i = 0; i < BIOS_SCRATCH_LEN; i++) + *(((char*)pInt->BIOSScratch + i)) = *(base + i); + } else { + if (pInt->BIOSScratch) { + for (i = 0; i < BIOS_SCRATCH_LEN; i++) + *(base + i) = *(pInt->BIOSScratch + i); + free(pInt->BIOSScratch); + pInt->BIOSScratch = NULL; + } + } + + xf86UnMapVidMem(pInt->scrnIndex,base - BIOS_SCRATCH_OFF ,pagesize); +} +#endif + +xf86Int10InfoPtr +xf86InitInt10(int entityIndex) +{ + return xf86ExtendedInitInt10(entityIndex, 0); +} diff --git a/xorg-server/hw/xfree86/modes/xf86Crtc.c b/xorg-server/hw/xfree86/modes/xf86Crtc.c index 47d3ad14c..d721b131f 100644 --- a/xorg-server/hw/xfree86/modes/xf86Crtc.c +++ b/xorg-server/hw/xfree86/modes/xf86Crtc.c @@ -1,3282 +1,3281 @@ -/* - * Copyright © 2006 Keith Packard - * Copyright © 2008 Red Hat, Inc. - * - * 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include -#else -#ifdef HAVE_CONFIG_H -#include -#endif -#endif - -#include -#include -#include - -#include "xf86.h" -#include "xf86DDC.h" -#include "xf86Crtc.h" -#include "xf86Modes.h" -#include "xf86Priv.h" -#include "xf86RandR12.h" -#include "X11/extensions/render.h" -#include "X11/extensions/dpmsconst.h" -#include "X11/Xatom.h" -#include "picturestr.h" - -#include "xf86xv.h" - -#define NO_OUTPUT_DEFAULT_WIDTH 1024 -#define NO_OUTPUT_DEFAULT_HEIGHT 768 -/* - * Initialize xf86CrtcConfig structure - */ - -int xf86CrtcConfigPrivateIndex = -1; - -void -xf86CrtcConfigInit (ScrnInfoPtr scrn, - const xf86CrtcConfigFuncsRec *funcs) -{ - xf86CrtcConfigPtr config; - - if (xf86CrtcConfigPrivateIndex == -1) - xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); - config = xnfcalloc (1, sizeof (xf86CrtcConfigRec)); - - config->funcs = funcs; - - scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config; -} - -void -xf86CrtcSetSizeRange (ScrnInfoPtr scrn, - int minWidth, int minHeight, - int maxWidth, int maxHeight) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - - config->minWidth = minWidth; - config->minHeight = minHeight; - config->maxWidth = maxWidth; - config->maxHeight = maxHeight; -} - -void -xf86CrtcSetScanoutFormats(ScrnInfoPtr scrn, - int num_formats, - xf86CrtcScanoutFormat *formats) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - - config->num_scanout_formats = num_formats; - config->scanout_formats = formats; -} - -/* - * Crtc functions - */ -xf86CrtcPtr -xf86CrtcCreate (ScrnInfoPtr scrn, - const xf86CrtcFuncsRec *funcs) -{ - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - xf86CrtcPtr crtc, *crtcs; - - crtc = calloc(sizeof (xf86CrtcRec), 1); - if (!crtc) - return NULL; - crtc->version = XF86_CRTC_VERSION; - crtc->scrn = scrn; - crtc->funcs = funcs; -#ifdef RANDR_12_INTERFACE - crtc->randr_crtc = NULL; -#endif - crtc->rotation = RR_Rotate_0; - crtc->desiredRotation = RR_Rotate_0; - pixman_transform_init_identity (&crtc->crtc_to_framebuffer); - pixman_f_transform_init_identity (&crtc->f_crtc_to_framebuffer); - pixman_f_transform_init_identity (&crtc->f_framebuffer_to_crtc); - pixman_f_transform_init_identity (&crtc->f_screen_to_crtc); - pixman_f_transform_init_identity (&crtc->user_sprite_position_transform); - pixman_f_transform_init_identity (&crtc->f_crtc_to_cursor); - pixman_f_transform_init_identity (&crtc->user_sprite_image_transform); - crtc->filter = NULL; - crtc->params = NULL; - crtc->nparams = 0; - crtc->filter_width = 0; - crtc->filter_height = 0; - crtc->transform_in_use = FALSE; - crtc->sprite_transform_in_use = FALSE; - crtc->transformPresent = FALSE; - crtc->desiredTransformPresent = FALSE; - memset (&crtc->bounds, '\0', sizeof (crtc->bounds)); - - /* Preallocate gamma at a sensible size. */ - crtc->gamma_size = 256; - crtc->gamma_red = malloc(3 * crtc->gamma_size * sizeof (CARD16)); - if (!crtc->gamma_red) { - free(crtc); - return NULL; - } - crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; - crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; - - if (xf86_config->crtc) - crtcs = realloc(xf86_config->crtc, - (xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); - else - crtcs = malloc((xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); - if (!crtcs) - { - free(crtc); - return NULL; - } - xf86_config->crtc = crtcs; - xf86_config->crtc[xf86_config->num_crtc++] = crtc; - return crtc; -} - -void -xf86CrtcDestroy (xf86CrtcPtr crtc) -{ - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); - int c; - - (*crtc->funcs->destroy) (crtc); - for (c = 0; c < xf86_config->num_crtc; c++) - if (xf86_config->crtc[c] == crtc) - { - memmove (&xf86_config->crtc[c], - &xf86_config->crtc[c+1], - ((xf86_config->num_crtc - (c + 1)) * sizeof(void*))); - xf86_config->num_crtc--; - break; - } - free(crtc->params); - free(crtc->gamma_red); - free(crtc); -} - - -/** - * Return whether any outputs are connected to the specified pipe - */ - -Bool -xf86CrtcInUse (xf86CrtcPtr crtc) -{ - ScrnInfoPtr pScrn = crtc->scrn; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - int o; - - for (o = 0; o < xf86_config->num_output; o++) - if (xf86_config->output[o]->crtc == crtc) - return TRUE; - return FALSE; -} - -void -xf86CrtcSetScreenSubpixelOrder (ScreenPtr pScreen) -{ - int subpixel_order = SubPixelUnknown; - Bool has_none = FALSE; - ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - int c, o; - - for (c = 0; c < xf86_config->num_crtc; c++) - { - xf86CrtcPtr crtc = xf86_config->crtc[c]; - - for (o = 0; o < xf86_config->num_output; o++) - { - xf86OutputPtr output = xf86_config->output[o]; - - if (output->crtc == crtc) - { - switch (output->subpixel_order) { - case SubPixelNone: - has_none = TRUE; - break; - case SubPixelUnknown: - break; - default: - subpixel_order = output->subpixel_order; - break; - } - } - if (subpixel_order != SubPixelUnknown) - break; - } - if (subpixel_order != SubPixelUnknown) - { - static const int circle[4] = { - SubPixelHorizontalRGB, - SubPixelVerticalRGB, - SubPixelHorizontalBGR, - SubPixelVerticalBGR, - }; - int rotate; - int c; - for (rotate = 0; rotate < 4; rotate++) - if (crtc->rotation & (1 << rotate)) - break; - for (c = 0; c < 4; c++) - if (circle[c] == subpixel_order) - break; - c = (c + rotate) & 0x3; - if ((crtc->rotation & RR_Reflect_X) && !(c & 1)) - c ^= 2; - if ((crtc->rotation & RR_Reflect_Y) && (c & 1)) - c ^= 2; - subpixel_order = circle[c]; - break; - } - } - if (subpixel_order == SubPixelUnknown && has_none) - subpixel_order = SubPixelNone; - PictureSetSubpixelOrder (pScreen, subpixel_order); -} - -/** - * Sets the given video mode on the given crtc - */ -Bool -xf86CrtcSet(xf86CrtcPtr crtc, xf86CrtcSetRec *set) -{ - ScrnInfoPtr scrn = crtc->scrn; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - int i; - Bool ret = FALSE; - Bool didLock = FALSE; - DisplayModePtr adjusted_mode = NULL; - DisplayModeRec saved_mode; - int saved_x, saved_y; - Rotation saved_rotation; - RRTransformRec saved_transform; - Bool saved_transform_present; - PixmapPtr saved_scanout_pixmap; - - crtc->enabled = xf86CrtcInUse (crtc); - - /* We only hit this if someone explicitly sends a "disabled" modeset. */ - if (!crtc->enabled) - { - /* Check everything for stuff that should be off. */ - xf86DisableUnusedFunctions(scrn); - return TRUE; - } - - /* See if nothing has changed */ - if (!set->flags) - return TRUE; - - saved_mode = crtc->mode; - saved_x = crtc->x; - saved_y = crtc->y; - saved_rotation = crtc->rotation; - saved_scanout_pixmap = crtc->scanoutPixmap; - if (crtc->transformPresent) { - RRTransformInit (&saved_transform); - RRTransformCopy (&saved_transform, &crtc->transform); - } - saved_transform_present = crtc->transformPresent; - - /* Update crtc values up front so the driver can rely on them for mode - * setting. - */ - if (set->flags & XF86CrtcSetMode) - crtc->mode = *set->mode; - if (set->flags & XF86CrtcSetOrigin) { - crtc->x = set->x; - crtc->y = set->y; - } - if (set->flags & XF86CrtcSetRotation) - crtc->rotation = set->rotation; - if (set->flags & XF86CrtcSetScanoutPixmap) - crtc->scanoutPixmap = set->scanout_pixmap; - - if (set->flags & XF86CrtcSetTransform) { - if (set->transform) { - RRTransformCopy (&crtc->transform, set->transform); - crtc->transformPresent = TRUE; - } else - crtc->transformPresent = FALSE; - } - - if (crtc->funcs->set) { - ret = crtc->funcs->set(crtc, set->flags); - goto done; - } - - if (set->flags == XF86CrtcSetOrigin && crtc->funcs->set_origin) { - ret = xf86CrtcRotate(crtc); - if (ret) - crtc->funcs->set_origin(crtc, crtc->x, crtc->y); - goto done; - } - - if (crtc->funcs->set_mode_major) { - ret = crtc->funcs->set_mode_major(crtc, &crtc->mode, - crtc->rotation, - crtc->x, crtc->y); - goto done; - } - - adjusted_mode = xf86DuplicateMode(&crtc->mode); - - didLock = crtc->funcs->lock (crtc); - /* Pass our mode to the outputs and the CRTC to give them a chance to - * adjust it according to limitations or output properties, and also - * a chance to reject the mode entirely. - */ - for (i = 0; i < xf86_config->num_output; i++) { - xf86OutputPtr output = xf86_config->output[i]; - - if (output->crtc != crtc) - continue; - - if (!output->funcs->mode_fixup(output, &crtc->mode, adjusted_mode)) { - goto done; - } - } - - if (!crtc->funcs->mode_fixup(crtc, &crtc->mode, adjusted_mode)) { - goto done; - } - - if (!xf86CrtcRotate (crtc)) - goto done; - - /* Prepare the outputs and CRTCs before setting the mode. */ - for (i = 0; i < xf86_config->num_output; i++) { - xf86OutputPtr output = xf86_config->output[i]; - - if (output->crtc != crtc) - continue; - - /* Disable the output as the first thing we do. */ - output->funcs->prepare(output); - } - - crtc->funcs->prepare(crtc); - - /* Set up the DPLL and any output state that needs to adjust or depend - * on the DPLL. - */ - crtc->funcs->mode_set(crtc, &crtc->mode, adjusted_mode, crtc->x, crtc->y); - for (i = 0; i < xf86_config->num_output; i++) - { - xf86OutputPtr output = xf86_config->output[i]; - if (output->crtc == crtc) - output->funcs->mode_set(output, &crtc->mode, adjusted_mode); - } - - /* Only upload when needed, to avoid unneeded delays. */ - if (!crtc->active && crtc->funcs->gamma_set) - crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, - crtc->gamma_blue, crtc->gamma_size); - - /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ - crtc->funcs->commit(crtc); - for (i = 0; i < xf86_config->num_output; i++) - { - xf86OutputPtr output = xf86_config->output[i]; - if (output->crtc == crtc) - output->funcs->commit(output); - } - - ret = TRUE; - -done: - if (ret) { - crtc->active = TRUE; - if (scrn->pScreen) - xf86CrtcSetScreenSubpixelOrder (scrn->pScreen); - if (scrn->ModeSet) - scrn->ModeSet(scrn); - } else { - crtc->x = saved_x; - crtc->y = saved_y; - crtc->rotation = saved_rotation; - crtc->mode = saved_mode; - if (saved_transform_present) - RRTransformCopy (&crtc->transform, &saved_transform); - crtc->transformPresent = saved_transform_present; - crtc->scanoutPixmap = saved_scanout_pixmap; - } - - if (adjusted_mode) { - free(adjusted_mode->name); - free(adjusted_mode); - } - - if (didLock) - crtc->funcs->unlock (crtc); - - return ret; -} - -/** - * Pans the screen, does not change the mode - */ -void -xf86CrtcSetOrigin (xf86CrtcPtr crtc, int x, int y) -{ - xf86CrtcSetRec set; - - if (x != crtc->x || y != crtc->y) { - set.x = x; - set.y = y; - set.flags = XF86CrtcSetOrigin; - (void) xf86CrtcSet(crtc, &set); - } -} - -/* - * Output functions - */ - -extern XF86ConfigPtr xf86configptr; - -typedef enum { - OPTION_PREFERRED_MODE, - OPTION_POSITION, - OPTION_BELOW, - OPTION_RIGHT_OF, - OPTION_ABOVE, - OPTION_LEFT_OF, - OPTION_ENABLE, - OPTION_DISABLE, - OPTION_MIN_CLOCK, - OPTION_MAX_CLOCK, - OPTION_IGNORE, - OPTION_ROTATE, - OPTION_PANNING, - OPTION_PRIMARY, - OPTION_DEFAULT_MODES, -} OutputOpts; - -static OptionInfoRec xf86OutputOptions[] = { - {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE }, - {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE }, - {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE }, - {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE }, - {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE }, - {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE }, - {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE }, - {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE }, - {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE }, - {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE }, - {OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE }, - {OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE }, - {OPTION_PANNING, "Panning", OPTV_STRING, {0}, FALSE }, - {OPTION_PRIMARY, "Primary", OPTV_BOOLEAN, {0}, FALSE }, - {OPTION_DEFAULT_MODES, "DefaultModes", OPTV_BOOLEAN, {0}, FALSE }, - {-1, NULL, OPTV_NONE, {0}, FALSE }, -}; - -enum { - OPTION_MODEDEBUG, -}; - -static OptionInfoRec xf86DeviceOptions[] = { - {OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE }, - {-1, NULL, OPTV_NONE, {0}, FALSE }, -}; - -static void -xf86OutputSetMonitor (xf86OutputPtr output) -{ - char *option_name; - char *monitor; - - if (!output->name) - return; - - free(output->options); - - output->options = xnfalloc (sizeof (xf86OutputOptions)); - memcpy (output->options, xf86OutputOptions, sizeof (xf86OutputOptions)); - - XNFasprintf(&option_name, "monitor-%s", output->name); - monitor = xf86findOptionValue (output->scrn->options, option_name); - if (!monitor) - monitor = output->name; - else - xf86MarkOptionUsedByName (output->scrn->options, option_name); - free(option_name); - output->conf_monitor = xf86findMonitor (monitor, - xf86configptr->conf_monitor_lst); - /* - * Find the monitor section of the screen and use that - */ - if (!output->conf_monitor && output->use_screen_monitor) - output->conf_monitor = xf86findMonitor (output->scrn->monitor->id, - xf86configptr->conf_monitor_lst); - if (output->conf_monitor) - { - xf86DrvMsg (output->scrn->scrnIndex, X_INFO, - "Output %s using monitor section %s\n", - output->name, output->conf_monitor->mon_identifier); - xf86ProcessOptions (output->scrn->scrnIndex, - output->conf_monitor->mon_option_lst, - output->options); - } - else - xf86DrvMsg (output->scrn->scrnIndex, X_INFO, - "Output %s has no monitor section\n", - output->name); -} - -static Bool -xf86OutputEnabled (xf86OutputPtr output, Bool strict) -{ - Bool enable, disable; - - /* check to see if this output was enabled in the config file */ - if (xf86GetOptValBool (output->options, OPTION_ENABLE, &enable) && enable) - { - xf86DrvMsg (output->scrn->scrnIndex, X_INFO, - "Output %s enabled by config file\n", output->name); - return TRUE; - } - /* or if this output was disabled in the config file */ - if (xf86GetOptValBool (output->options, OPTION_DISABLE, &disable) && disable) - { - xf86DrvMsg (output->scrn->scrnIndex, X_INFO, - "Output %s disabled by config file\n", output->name); - return FALSE; - } - - /* If not, try to only light up the ones we know are connected */ - if (strict) { - enable = output->status == XF86OutputStatusConnected; - } - /* But if that fails, try to light up even outputs we're unsure of */ - else { - enable = output->status != XF86OutputStatusDisconnected; - } - - xf86DrvMsg (output->scrn->scrnIndex, X_INFO, - "Output %s %sconnected\n", output->name, enable ? "" : "dis"); - return enable; -} - -static Bool -xf86OutputIgnored (xf86OutputPtr output) -{ - return xf86ReturnOptValBool (output->options, OPTION_IGNORE, FALSE); -} - -static char *direction[4] = { - "normal", - "left", - "inverted", - "right" -}; - -static Rotation -xf86OutputInitialRotation (xf86OutputPtr output) -{ - char *rotate_name = xf86GetOptValString (output->options, - OPTION_ROTATE); - int i; - - if (!rotate_name) { - if (output->initial_rotation) - return output->initial_rotation; - return RR_Rotate_0; - } - - for (i = 0; i < 4; i++) - if (xf86nameCompare (direction[i], rotate_name) == 0) - return 1 << i; - return RR_Rotate_0; -} - -xf86OutputPtr -xf86OutputCreate (ScrnInfoPtr scrn, - const xf86OutputFuncsRec *funcs, - const char *name) -{ - xf86OutputPtr output, *outputs; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - int len; - Bool primary; - - if (name) - len = strlen (name) + 1; - else - len = 0; - - output = calloc(sizeof (xf86OutputRec) + len, 1); - if (!output) - return NULL; - output->scrn = scrn; - output->funcs = funcs; - if (name) - { - output->name = (char *) (output + 1); - strcpy (output->name, name); - } - output->subpixel_order = SubPixelUnknown; - /* - * Use the old per-screen monitor section for the first output - */ - output->use_screen_monitor = (xf86_config->num_output == 0); -#ifdef RANDR_12_INTERFACE - output->randr_output = NULL; -#endif - if (name) - { - xf86OutputSetMonitor (output); - if (xf86OutputIgnored (output)) - { - free(output); - return FALSE; - } - } - - - if (xf86_config->output) - outputs = realloc(xf86_config->output, - (xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); - else - outputs = malloc((xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); - if (!outputs) - { - free(output); - return NULL; - } - - xf86_config->output = outputs; - - if (xf86GetOptValBool (output->options, OPTION_PRIMARY, &primary) && primary) - { - memmove(xf86_config->output + 1, xf86_config->output, - xf86_config->num_output * sizeof (xf86OutputPtr)); - xf86_config->output[0] = output; - } - else - { - xf86_config->output[xf86_config->num_output] = output; - } - - xf86_config->num_output++; - - return output; -} - -Bool -xf86OutputRename (xf86OutputPtr output, const char *name) -{ - char *newname = strdup(name); - - if (!newname) - return FALSE; /* so sorry... */ - - if (output->name && output->name != (char *) (output + 1)) - free(output->name); - output->name = newname; - xf86OutputSetMonitor (output); - if (xf86OutputIgnored (output)) - return FALSE; - return TRUE; -} - -void -xf86OutputUseScreenMonitor (xf86OutputPtr output, Bool use_screen_monitor) -{ - if (use_screen_monitor != output->use_screen_monitor) - { - output->use_screen_monitor = use_screen_monitor; - xf86OutputSetMonitor (output); - } -} - -void -xf86OutputDestroy (xf86OutputPtr output) -{ - ScrnInfoPtr scrn = output->scrn; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - int o; - - (*output->funcs->destroy) (output); - while (output->probed_modes) - xf86DeleteMode (&output->probed_modes, output->probed_modes); - for (o = 0; o < xf86_config->num_output; o++) - if (xf86_config->output[o] == output) - { - memmove (&xf86_config->output[o], - &xf86_config->output[o+1], - ((xf86_config->num_output - (o + 1)) * sizeof(void*))); - xf86_config->num_output--; - break; - } - if (output->name && output->name != (char *) (output + 1)) - free(output->name); - free(output); -} - -/* - * Called during CreateScreenResources to hook up RandR - */ -static Bool -xf86CrtcCreateScreenResources (ScreenPtr screen) -{ - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - - screen->CreateScreenResources = config->CreateScreenResources; - - if (!(*screen->CreateScreenResources)(screen)) - return FALSE; - - if (!xf86RandR12CreateScreenResources (screen)) - return FALSE; - - return TRUE; -} - -/* - * Clean up config on server reset - */ -static Bool -xf86CrtcCloseScreen (int index, ScreenPtr screen) -{ - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o, c; - - screen->CloseScreen = config->CloseScreen; - - xf86RotateCloseScreen (screen); - - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - - output->randr_output = NULL; - } - for (c = 0; c < config->num_crtc; c++) - { - xf86CrtcPtr crtc = config->crtc[c]; - - crtc->randr_crtc = NULL; - } - xf86RandR12CloseScreen (screen); - - return screen->CloseScreen (index, screen); -} - -/* - * Called at ScreenInit time to set up - */ -#ifdef RANDR_13_INTERFACE -int -#else -Bool -#endif -xf86CrtcScreenInit (ScreenPtr screen) -{ - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int c; - - /* Rotation */ - xf86DrvMsg(scrn->scrnIndex, X_INFO, "RandR 1.2 enabled, ignore the following RandR disabled message.\n"); - xf86DisableRandR(); /* Disable old RandR extension support */ - xf86RandR12Init (screen); - - /* support all rotations if every crtc has the shadow alloc funcs */ - for (c = 0; c < config->num_crtc; c++) - { - xf86CrtcPtr crtc = config->crtc[c]; - if (!crtc->funcs->shadow_allocate || !crtc->funcs->shadow_create) - break; - } - if (c == config->num_crtc) - { - xf86RandR12SetRotations (screen, RR_Rotate_0 | RR_Rotate_90 | - RR_Rotate_180 | RR_Rotate_270 | - RR_Reflect_X | RR_Reflect_Y); - xf86RandR12SetTransformSupport (screen, TRUE); - } - else - { - xf86RandR12SetRotations (screen, RR_Rotate_0); - xf86RandR12SetTransformSupport (screen, FALSE); - } - - /* Wrap CreateScreenResources so we can initialize the RandR code */ - config->CreateScreenResources = screen->CreateScreenResources; - screen->CreateScreenResources = xf86CrtcCreateScreenResources; - - config->CloseScreen = screen->CloseScreen; - screen->CloseScreen = xf86CrtcCloseScreen; - -#ifdef XFreeXDGA - _xf86_di_dga_init_internal(screen); -#endif -#ifdef RANDR_13_INTERFACE - return RANDR_INTERFACE_VERSION; -#else - return TRUE; -#endif -} - -static DisplayModePtr -xf86DefaultMode (xf86OutputPtr output, int width, int height) -{ - DisplayModePtr target_mode = NULL; - DisplayModePtr mode; - int target_diff = 0; - int target_preferred = 0; - int mm_height; - - mm_height = output->mm_height; - if (!mm_height) - mm_height = (768 * 25.4) / DEFAULT_DPI; - /* - * Pick a mode closest to DEFAULT_DPI - */ - for (mode = output->probed_modes; mode; mode = mode->next) - { - int dpi; - int preferred = (((mode->type & M_T_PREFERRED) != 0) + - ((mode->type & M_T_USERPREF) != 0)); - int diff; - - if (xf86ModeWidth (mode, output->initial_rotation) > width || - xf86ModeHeight (mode, output->initial_rotation) > height) - continue; - - /* yes, use VDisplay here, not xf86ModeHeight */ - dpi = (mode->VDisplay * 254) / (mm_height * 10); - diff = dpi - DEFAULT_DPI; - diff = diff < 0 ? -diff : diff; - if (target_mode == NULL || (preferred > target_preferred) || - (preferred == target_preferred && diff < target_diff)) - { - target_mode = mode; - target_diff = diff; - target_preferred = preferred; - } - } - return target_mode; -} - -static DisplayModePtr -xf86ClosestMode (xf86OutputPtr output, - DisplayModePtr match, Rotation match_rotation, - int width, int height) -{ - DisplayModePtr target_mode = NULL; - DisplayModePtr mode; - int target_diff = 0; - - /* - * Pick a mode closest to the specified mode - */ - for (mode = output->probed_modes; mode; mode = mode->next) - { - int dx, dy; - int diff; - - if (xf86ModeWidth (mode, output->initial_rotation) > width || - xf86ModeHeight (mode, output->initial_rotation) > height) - continue; - - /* exact matches are preferred */ - if (output->initial_rotation == match_rotation && - xf86ModesEqual (mode, match)) - return mode; - - dx = xf86ModeWidth (match, match_rotation) - xf86ModeWidth (mode, output->initial_rotation); - dy = xf86ModeHeight (match, match_rotation) - xf86ModeHeight (mode, output->initial_rotation); - diff = dx * dx + dy * dy; - if (target_mode == NULL || diff < target_diff) - { - target_mode = mode; - target_diff = diff; - } - } - return target_mode; -} - -static DisplayModePtr -xf86OutputHasPreferredMode (xf86OutputPtr output, int width, int height) -{ - DisplayModePtr mode; - - for (mode = output->probed_modes; mode; mode = mode->next) - { - if (xf86ModeWidth (mode, output->initial_rotation) > width || - xf86ModeHeight (mode, output->initial_rotation) > height) - continue; - - if (mode->type & M_T_PREFERRED) - return mode; - } - return NULL; -} - -static DisplayModePtr -xf86OutputHasUserPreferredMode (xf86OutputPtr output) -{ - DisplayModePtr mode, first = output->probed_modes; - - for (mode = first; mode && mode->next != first; mode = mode->next) - if (mode->type & M_T_USERPREF) - return mode; - - return NULL; -} - -static int -xf86PickCrtcs (ScrnInfoPtr scrn, - xf86CrtcPtr *best_crtcs, - DisplayModePtr *modes, - int n, - int width, - int height) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int c, o; - xf86OutputPtr output; - xf86CrtcPtr crtc; - xf86CrtcPtr *crtcs; - xf86CrtcPtr best_crtc; - int best_score; - int score; - int my_score; - - if (n == config->num_output) - return 0; - output = config->output[n]; - - /* - * Compute score with this output disabled - */ - best_crtcs[n] = NULL; - best_crtc = NULL; - best_score = xf86PickCrtcs (scrn, best_crtcs, modes, n+1, width, height); - if (modes[n] == NULL) - return best_score; - - crtcs = malloc(config->num_output * sizeof (xf86CrtcPtr)); - if (!crtcs) - return best_score; - - my_score = 1; - /* Score outputs that are known to be connected higher */ - if (output->status == XF86OutputStatusConnected) - my_score++; - /* Score outputs with preferred modes higher */ - if (xf86OutputHasPreferredMode (output, width, height)) - my_score++; - /* - * Select a crtc for this output and - * then attempt to configure the remaining - * outputs - */ - for (c = 0; c < config->num_crtc; c++) - { - if ((output->possible_crtcs & (1 << c)) == 0) - continue; - - crtc = config->crtc[c]; - /* - * Check to see if some other output is - * using this crtc - */ - for (o = 0; o < n; o++) - if (best_crtcs[o] == crtc) - break; - if (o < n) - { - /* - * If the two outputs desire the same mode, - * see if they can be cloned - */ - if (xf86ModesEqual (modes[o], modes[n]) && - config->output[o]->initial_rotation == config->output[n]->initial_rotation && - config->output[o]->initial_x == config->output[n]->initial_x && - config->output[o]->initial_y == config->output[n]->initial_y) - { - if ((output->possible_clones & (1 << o)) == 0) - continue; /* nope, try next CRTC */ - } - else - continue; /* different modes, can't clone */ - } - crtcs[n] = crtc; - memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr)); - score = my_score + xf86PickCrtcs (scrn, crtcs, modes, n+1, width, height); - if (score > best_score) - { - best_crtc = crtc; - best_score = score; - memcpy (best_crtcs, crtcs, config->num_output * sizeof (xf86CrtcPtr)); - } - } - free(crtcs); - return best_score; -} - - -/* - * Compute the virtual size necessary to place all of the available - * crtcs in the specified configuration. - * - * canGrow indicates that the driver can make the screen larger than its initial - * configuration. If FALSE, this function will enlarge the screen to include - * the largest available mode. - */ - -static void -xf86DefaultScreenLimits (ScrnInfoPtr scrn, int *widthp, int *heightp, - Bool canGrow) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int width = 0, height = 0; - int o; - int c; - int s; - - for (c = 0; c < config->num_crtc; c++) - { - int crtc_width = 0, crtc_height = 0; - xf86CrtcPtr crtc = config->crtc[c]; - - if (crtc->enabled) - { - crtc_width = crtc->desiredX + xf86ModeWidth (&crtc->desiredMode, crtc->desiredRotation); - crtc_height = crtc->desiredY + xf86ModeHeight (&crtc->desiredMode, crtc->desiredRotation); - } - if (!canGrow) { - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - - for (s = 0; s < config->num_crtc; s++) - if (output->possible_crtcs & (1 << s)) - { - DisplayModePtr mode; - for (mode = output->probed_modes; mode; mode = mode->next) - { - if (mode->HDisplay > crtc_width) - crtc_width = mode->HDisplay; - if (mode->VDisplay > crtc_width) - crtc_width = mode->VDisplay; - if (mode->VDisplay > crtc_height) - crtc_height = mode->VDisplay; - if (mode->HDisplay > crtc_height) - crtc_height = mode->HDisplay; - } - } - } - } - if (crtc_width > width) - width = crtc_width; - if (crtc_height > height) - height = crtc_height; - } - if (config->maxWidth && width > config->maxWidth) width = config->maxWidth; - if (config->maxHeight && height > config->maxHeight) height = config->maxHeight; - if (config->minWidth && width < config->minWidth) width = config->minWidth; - if (config->minHeight && height < config->minHeight) height = config->minHeight; - *widthp = width; - *heightp = height; -} - -#define POSITION_UNSET -100000 - -/* - * check if the user configured any outputs at all - * with either a position or a relative setting or a mode. - */ -static Bool -xf86UserConfiguredOutputs(ScrnInfoPtr scrn, DisplayModePtr *modes) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o; - Bool user_conf = FALSE; - - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - char *position; - char *relative_name; - OutputOpts relation; - int r; - static const OutputOpts relations[] = { - OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF - }; - - position = xf86GetOptValString (output->options, - OPTION_POSITION); - if (position) - user_conf = TRUE; - - relation = 0; - relative_name = NULL; - for (r = 0; r < 4; r++) - { - relation = relations[r]; - relative_name = xf86GetOptValString (output->options, - relation); - if (relative_name) - break; - } - if (relative_name) - user_conf = TRUE; - - modes[o] = xf86OutputHasUserPreferredMode(output); - if (modes[o]) - user_conf = TRUE; - } - - return user_conf; -} - -static Bool -xf86InitialOutputPositions (ScrnInfoPtr scrn, DisplayModePtr *modes) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o; - int min_x, min_y; - - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - - output->initial_x = output->initial_y = POSITION_UNSET; - } - - /* - * Loop until all outputs are set - */ - for (;;) - { - Bool any_set = FALSE; - Bool keep_going = FALSE; - - for (o = 0; o < config->num_output; o++) - { - static const OutputOpts relations[] = { - OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF - }; - xf86OutputPtr output = config->output[o]; - xf86OutputPtr relative; - char *relative_name; - char *position; - OutputOpts relation; - int r; - - if (output->initial_x != POSITION_UNSET) - continue; - position = xf86GetOptValString (output->options, - OPTION_POSITION); - /* - * Absolute position wins - */ - if (position) - { - int x, y; - if (sscanf (position, "%d %d", &x, &y) == 2) - { - output->initial_x = x; - output->initial_y = y; - } - else - { - xf86DrvMsg (scrn->scrnIndex, X_ERROR, - "Output %s position not of form \"x y\"\n", - output->name); - output->initial_x = output->initial_y = 0; - } - any_set = TRUE; - continue; - } - /* - * Next comes relative positions - */ - relation = 0; - relative_name = NULL; - for (r = 0; r < 4; r++) - { - relation = relations[r]; - relative_name = xf86GetOptValString (output->options, - relation); - if (relative_name) - break; - } - if (relative_name) - { - int or; - relative = NULL; - for (or = 0; or < config->num_output; or++) - { - xf86OutputPtr out_rel = config->output[or]; - XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor; - - if (rel_mon) - { - if (xf86nameCompare (rel_mon->mon_identifier, - relative_name) == 0) - { - relative = config->output[or]; - break; - } - } - if (strcmp (out_rel->name, relative_name) == 0) - { - relative = config->output[or]; - break; - } - } - if (!relative) - { - xf86DrvMsg (scrn->scrnIndex, X_ERROR, - "Cannot position output %s relative to unknown output %s\n", - output->name, relative_name); - output->initial_x = 0; - output->initial_y = 0; - any_set = TRUE; - continue; - } - if (!modes[or]) - { - xf86DrvMsg (scrn->scrnIndex, X_ERROR, - "Cannot position output %s relative to output %s without modes\n", - output->name, relative_name); - output->initial_x = 0; - output->initial_y = 0; - any_set = TRUE; - continue; - } - if (relative->initial_x == POSITION_UNSET) - { - keep_going = TRUE; - continue; - } - output->initial_x = relative->initial_x; - output->initial_y = relative->initial_y; - switch (relation) { - case OPTION_BELOW: - output->initial_y += xf86ModeHeight (modes[or], relative->initial_rotation); - break; - case OPTION_RIGHT_OF: - output->initial_x += xf86ModeWidth (modes[or], relative->initial_rotation); - break; - case OPTION_ABOVE: - if (modes[o]) - output->initial_y -= xf86ModeHeight (modes[o], output->initial_rotation); - break; - case OPTION_LEFT_OF: - if (modes[o]) - output->initial_x -= xf86ModeWidth (modes[o], output->initial_rotation); - break; - default: - break; - } - any_set = TRUE; - continue; - } - - /* Nothing set, just stick them at 0,0 */ - output->initial_x = 0; - output->initial_y = 0; - any_set = TRUE; - } - if (!keep_going) - break; - if (!any_set) - { - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - if (output->initial_x == POSITION_UNSET) - { - xf86DrvMsg (scrn->scrnIndex, X_ERROR, - "Output position loop. Moving %s to 0,0\n", - output->name); - output->initial_x = output->initial_y = 0; - break; - } - } - } - } - - /* - * normalize positions - */ - min_x = 1000000; - min_y = 1000000; - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - - if (output->initial_x < min_x) - min_x = output->initial_x; - if (output->initial_y < min_y) - min_y = output->initial_y; - } - - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - - output->initial_x -= min_x; - output->initial_y -= min_y; - } - return TRUE; -} - -static void -xf86InitialPanning (ScrnInfoPtr scrn) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o; - - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - char *panning = xf86GetOptValString (output->options, OPTION_PANNING); - int width, height, left, top; - int track_width, track_height, track_left, track_top; - int brdr[4]; - - memset (&output->initialTotalArea, 0, sizeof(BoxRec)); - memset (&output->initialTrackingArea, 0, sizeof(BoxRec)); - memset (output->initialBorder, 0, 4*sizeof(INT16)); - - if (! panning) - continue; - - switch (sscanf (panning, "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d", - &width, &height, &left, &top, - &track_width, &track_height, &track_left, &track_top, - &brdr[0], &brdr[1], &brdr[2], &brdr[3])) { - case 12: - output->initialBorder[0] = brdr[0]; - output->initialBorder[1] = brdr[1]; - output->initialBorder[2] = brdr[2]; - output->initialBorder[3] = brdr[3]; - /* fall through */ - case 8: - output->initialTrackingArea.x1 = track_left; - output->initialTrackingArea.y1 = track_top; - output->initialTrackingArea.x2 = track_left + track_width; - output->initialTrackingArea.y2 = track_top + track_height; - /* fall through */ - case 4: - output->initialTotalArea.x1 = left; - output->initialTotalArea.y1 = top; - /* fall through */ - case 2: - output->initialTotalArea.x2 = output->initialTotalArea.x1 + width; - output->initialTotalArea.y2 = output->initialTotalArea.y1 + height; - break; - default: - xf86DrvMsg (scrn->scrnIndex, X_ERROR, - "Broken panning specification '%s' for output %s in config file\n", - panning, output->name); - } - } -} - -/** Return - 0 + if a should be earlier, same or later than b in list - */ -static int -xf86ModeCompare (DisplayModePtr a, DisplayModePtr b) -{ - int diff; - - diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0); - if (diff) - return diff; - diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay; - if (diff) - return diff; - diff = b->Clock - a->Clock; - return diff; -} - -/** - * Insertion sort input in-place and return the resulting head - */ -static DisplayModePtr -xf86SortModes (DisplayModePtr input) -{ - DisplayModePtr output = NULL, i, o, n, *op, prev; - - /* sort by preferred status and pixel area */ - while (input) - { - i = input; - input = input->next; - for (op = &output; (o = *op); op = &o->next) - if (xf86ModeCompare (o, i) > 0) - break; - i->next = *op; - *op = i; - } - /* prune identical modes */ - for (o = output; o && (n = o->next); o = n) - { - if (!strcmp (o->name, n->name) && xf86ModesEqual (o, n)) - { - o->next = n->next; - free(n->name); - free(n); - n = o; - } - } - /* hook up backward links */ - prev = NULL; - for (o = output; o; o = o->next) - { - o->prev = prev; - prev = o; - } - return output; -} - -static char * -preferredMode(ScrnInfoPtr pScrn, xf86OutputPtr output) -{ - char *preferred_mode = NULL; - - /* Check for a configured preference for a particular mode */ - preferred_mode = xf86GetOptValString (output->options, - OPTION_PREFERRED_MODE); - if (preferred_mode) - return preferred_mode; - - if (pScrn->display->modes && *pScrn->display->modes) - preferred_mode = *pScrn->display->modes; - - return preferred_mode; -} - -static void -GuessRangeFromModes(MonPtr mon, DisplayModePtr mode) -{ - if (!mon || !mode) - return; - - mon->nHsync = 1; - mon->hsync[0].lo = 1024.0; - mon->hsync[0].hi = 0.0; - - mon->nVrefresh = 1; - mon->vrefresh[0].lo = 1024.0; - mon->vrefresh[0].hi = 0.0; - - while (mode) { - if (!mode->HSync) - mode->HSync = ((float) mode->Clock ) / ((float) mode->HTotal); - - if (!mode->VRefresh) - mode->VRefresh = (1000.0 * ((float) mode->Clock)) / - ((float) (mode->HTotal * mode->VTotal)); - - if (mode->HSync < mon->hsync[0].lo) - mon->hsync[0].lo = mode->HSync; - - if (mode->HSync > mon->hsync[0].hi) - mon->hsync[0].hi = mode->HSync; - - if (mode->VRefresh < mon->vrefresh[0].lo) - mon->vrefresh[0].lo = mode->VRefresh; - - if (mode->VRefresh > mon->vrefresh[0].hi) - mon->vrefresh[0].hi = mode->VRefresh; - - mode = mode->next; - } - - /* stretch out the bottom to fit 640x480@60 */ - if (mon->hsync[0].lo > 31.0) - mon->hsync[0].lo = 31.0; - if (mon->vrefresh[0].lo > 58.0) - mon->vrefresh[0].lo = 58.0; -} - -enum det_monrec_source { - sync_config, sync_edid, sync_default -}; - -struct det_monrec_parameter { - MonRec *mon_rec; - int *max_clock; - Bool set_hsync; - Bool set_vrefresh; - enum det_monrec_source *sync_source; -}; - -static void handle_detailed_monrec(struct detailed_monitor_section *det_mon, - void *data) -{ - enum { sync_config, sync_edid, sync_default }; - struct det_monrec_parameter *p; - p = (struct det_monrec_parameter *)data; - - if (det_mon->type == DS_RANGES) { - struct monitor_ranges *ranges = &det_mon->section.ranges; - if (p->set_hsync && ranges->max_h) { - p->mon_rec->hsync[p->mon_rec->nHsync].lo = ranges->min_h; - p->mon_rec->hsync[p->mon_rec->nHsync].hi = ranges->max_h; - p->mon_rec->nHsync++; - if (*p->sync_source == sync_default) - *p->sync_source = sync_edid; - } - if (p->set_vrefresh && ranges->max_v) { - p->mon_rec->vrefresh[p->mon_rec->nVrefresh].lo = ranges->min_v; - p->mon_rec->vrefresh[p->mon_rec->nVrefresh].hi = ranges->max_v; - p->mon_rec->nVrefresh++; - if (*p->sync_source == sync_default) - *p->sync_source = sync_edid; - } - if (ranges->max_clock * 1000 > *p->max_clock) - *p->max_clock = ranges->max_clock * 1000; - } -} - -void -xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o; - - /* When canGrow was TRUE in the initial configuration we have to - * compare against the maximum values so that we don't drop modes. - * When canGrow was FALSE, the maximum values would have been clamped - * anyway. - */ - if (maxX == 0 || maxY == 0) { - maxX = config->maxWidth; - maxY = config->maxHeight; - } - - /* Probe the list of modes for each output. */ - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - DisplayModePtr mode; - DisplayModePtr config_modes = NULL, output_modes, default_modes = NULL; - char *preferred_mode; - xf86MonPtr edid_monitor; - XF86ConfMonitorPtr conf_monitor; - MonRec mon_rec; - int min_clock = 0; - int max_clock = 0; - double clock; - Bool add_default_modes = xf86ReturnOptValBool(output->options, OPTION_DEFAULT_MODES, TRUE); - Bool debug_modes = config->debug_modes || - xf86Initialising; - enum det_monrec_source sync_source = sync_default; - - while (output->probed_modes != NULL) - xf86DeleteMode(&output->probed_modes, output->probed_modes); - - /* - * Check connection status - */ - output->status = (*output->funcs->detect)(output); - - if (output->status == XF86OutputStatusDisconnected && - !xf86ReturnOptValBool(output->options, OPTION_ENABLE, FALSE)) - { - xf86OutputSetEDID (output, NULL); - continue; - } - - memset (&mon_rec, '\0', sizeof (mon_rec)); - - conf_monitor = output->conf_monitor; - - if (conf_monitor) - { - int i; - - for (i = 0; i < conf_monitor->mon_n_hsync; i++) - { - mon_rec.hsync[mon_rec.nHsync].lo = conf_monitor->mon_hsync[i].lo; - mon_rec.hsync[mon_rec.nHsync].hi = conf_monitor->mon_hsync[i].hi; - mon_rec.nHsync++; - sync_source = sync_config; - } - for (i = 0; i < conf_monitor->mon_n_vrefresh; i++) - { - mon_rec.vrefresh[mon_rec.nVrefresh].lo = conf_monitor->mon_vrefresh[i].lo; - mon_rec.vrefresh[mon_rec.nVrefresh].hi = conf_monitor->mon_vrefresh[i].hi; - mon_rec.nVrefresh++; - sync_source = sync_config; - } - config_modes = xf86GetMonitorModes (scrn, conf_monitor); - } - - output_modes = (*output->funcs->get_modes) (output); - - edid_monitor = output->MonInfo; - - if (edid_monitor) - { - struct det_monrec_parameter p; - struct disp_features *features = &edid_monitor->features; - - /* if display is not continuous-frequency, don't add default modes */ - if (!GTF_SUPPORTED(features->msc)) - add_default_modes = FALSE; - - p.mon_rec = &mon_rec; - p.max_clock = &max_clock; - p.set_hsync = mon_rec.nHsync == 0; - p.set_vrefresh = mon_rec.nVrefresh == 0; - p.sync_source = &sync_source; - - xf86ForEachDetailedBlock(edid_monitor, - handle_detailed_monrec, - &p); - } - - if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK, - OPTUNITS_KHZ, &clock)) - min_clock = (int) clock; - if (xf86GetOptValFreq (output->options, OPTION_MAX_CLOCK, - OPTUNITS_KHZ, &clock)) - max_clock = (int) clock; - - /* If we still don't have a sync range, guess wildly */ - if (!mon_rec.nHsync || !mon_rec.nVrefresh) - GuessRangeFromModes(&mon_rec, output_modes); - - /* - * These limits will end up setting a 1024x768@60Hz mode by default, - * which seems like a fairly good mode to use when nothing else is - * specified - */ - if (mon_rec.nHsync == 0) - { - mon_rec.hsync[0].lo = 31.0; - mon_rec.hsync[0].hi = 55.0; - mon_rec.nHsync = 1; - } - if (mon_rec.nVrefresh == 0) - { - mon_rec.vrefresh[0].lo = 58.0; - mon_rec.vrefresh[0].hi = 62.0; - mon_rec.nVrefresh = 1; - } - - if (add_default_modes) - default_modes = xf86GetDefaultModes (); - - /* - * If this is not an RB monitor, remove RB modes from the default - * pool. RB modes from the config or the monitor itself are fine. - */ - if (!mon_rec.reducedblanking) - xf86ValidateModesReducedBlanking (scrn, default_modes); - - if (sync_source == sync_config) - { - /* - * Check output and config modes against sync range from config file - */ - xf86ValidateModesSync (scrn, output_modes, &mon_rec); - xf86ValidateModesSync (scrn, config_modes, &mon_rec); - } - /* - * Check default modes against sync range - */ - xf86ValidateModesSync (scrn, default_modes, &mon_rec); - /* - * Check default modes against monitor max clock - */ - if (max_clock) { - xf86ValidateModesClocks(scrn, default_modes, - &min_clock, &max_clock, 1); - xf86ValidateModesClocks(scrn, output_modes, - &min_clock, &max_clock, 1); - } - - output->probed_modes = NULL; - output->probed_modes = xf86ModesAdd (output->probed_modes, config_modes); - output->probed_modes = xf86ModesAdd (output->probed_modes, output_modes); - output->probed_modes = xf86ModesAdd (output->probed_modes, default_modes); - - /* - * Check all modes against max size, interlace, and doublescan - */ - if (maxX && maxY) - xf86ValidateModesSize (scrn, output->probed_modes, - maxX, maxY, 0); - - { - int flags = (output->interlaceAllowed ? V_INTERLACE : 0) | - (output->doubleScanAllowed ? V_DBLSCAN : 0); - xf86ValidateModesFlags (scrn, output->probed_modes, flags); - } - - /* - * Check all modes against output - */ - for (mode = output->probed_modes; mode != NULL; mode = mode->next) - if (mode->status == MODE_OK) - mode->status = (*output->funcs->mode_valid)(output, mode); - - xf86PruneInvalidModes(scrn, &output->probed_modes, debug_modes); - - output->probed_modes = xf86SortModes (output->probed_modes); - - /* Check for a configured preference for a particular mode */ - preferred_mode = preferredMode(scrn, output); - - if (preferred_mode) - { - for (mode = output->probed_modes; mode; mode = mode->next) - { - if (!strcmp (preferred_mode, mode->name)) - { - if (mode != output->probed_modes) - { - if (mode->prev) - mode->prev->next = mode->next; - if (mode->next) - mode->next->prev = mode->prev; - mode->next = output->probed_modes; - output->probed_modes->prev = mode; - mode->prev = NULL; - output->probed_modes = mode; - } - mode->type |= (M_T_PREFERRED|M_T_USERPREF); - break; - } - } - } - - output->initial_rotation = xf86OutputInitialRotation (output); - - if (debug_modes) { - if (output->probed_modes != NULL) { - xf86DrvMsg(scrn->scrnIndex, X_INFO, - "Printing probed modes for output %s\n", - output->name); - } else { - xf86DrvMsg(scrn->scrnIndex, X_INFO, - "No remaining probed modes for output %s\n", - output->name); - } - } - for (mode = output->probed_modes; mode != NULL; mode = mode->next) - { - /* The code to choose the best mode per pipe later on will require - * VRefresh to be set. - */ - mode->VRefresh = xf86ModeVRefresh(mode); - xf86SetModeCrtc(mode, INTERLACE_HALVE_V); - - if (debug_modes) - xf86PrintModeline(scrn->scrnIndex, mode); - } - } -} - - -/** - * Copy one of the output mode lists to the ScrnInfo record - */ - -/* XXX where does this function belong? Here? */ -void -xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr scrn, int *x, int *y); - -static DisplayModePtr -biggestMode(DisplayModePtr a, DisplayModePtr b) -{ - int A, B; - - if (!a) - return b; - if (!b) - return a; - - A = a->HDisplay * a->VDisplay; - B = b->HDisplay * b->VDisplay; - - if (A > B) - return a; - - return b; -} - -static xf86OutputPtr -SetCompatOutput(xf86CrtcConfigPtr config) -{ - xf86OutputPtr output = NULL, test = NULL; - DisplayModePtr maxmode = NULL, testmode, mode; - int o, compat = -1, count, mincount = 0; - - /* Look for one that's definitely connected */ - for (o = 0; o < config->num_output; o++) - { - test = config->output[o]; - if (!test->crtc) - continue; - if (test->status != XF86OutputStatusConnected) - continue; - if (!test->probed_modes) - continue; - - testmode = mode = test->probed_modes; - for (count = 0; mode; mode = mode->next, count++) - testmode = biggestMode(testmode, mode); - - if (!output) { - output = test; - compat = o; - maxmode = testmode; - mincount = count; - } else if (maxmode == biggestMode(maxmode, testmode)) { - output = test; - compat = o; - maxmode = testmode; - mincount = count; - } else if ((maxmode->HDisplay == testmode->HDisplay) && - (maxmode->VDisplay == testmode->VDisplay) && - count <= mincount) { - output = test; - compat = o; - maxmode = testmode; - mincount = count; - } - } - - /* If we didn't find one, take anything we can get */ - if (!output) - { - for (o = 0; o < config->num_output; o++) - { - test = config->output[o]; - if (!test->crtc) - continue; - if (!test->probed_modes) - continue; - - if (!output) { - output = test; - compat = o; - } else if (test->probed_modes->HDisplay < output->probed_modes->HDisplay) { - output = test; - compat = o; - } - } - } - - if (compat >= 0) { - config->compat_output = compat; - } else { - /* Don't change the compat output when no valid outputs found */ - output = config->output[config->compat_output]; - } - - return output; -} - -void -xf86SetScrnInfoModes (ScrnInfoPtr scrn) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - xf86OutputPtr output; - xf86CrtcPtr crtc; - DisplayModePtr last, mode = NULL; - - output = SetCompatOutput(config); - - if (!output) - return; /* punt */ - - crtc = output->crtc; - - /* Clear any existing modes from scrn->modes */ - while (scrn->modes != NULL) - xf86DeleteMode(&scrn->modes, scrn->modes); - - /* Set scrn->modes to the mode list for the 'compat' output */ - scrn->modes = xf86DuplicateModes(scrn, output->probed_modes); - - if (crtc) { - for (mode = scrn->modes; mode; mode = mode->next) - if (xf86ModesEqual (mode, &crtc->desiredMode)) - break; - } - - if (scrn->modes != NULL) { - /* For some reason, scrn->modes is circular, unlike the other mode - * lists. How great is that? - */ - for (last = scrn->modes; last && last->next; last = last->next) - ; - last->next = scrn->modes; - scrn->modes->prev = last; - if (mode) { - while (scrn->modes != mode) - scrn->modes = scrn->modes->next; - } - } - scrn->currentMode = scrn->modes; -#ifdef XFreeXDGA - if (scrn->pScreen) - _xf86_di_dga_reinit_internal(scrn->pScreen); -#endif -} - -static Bool -xf86CollectEnabledOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, - Bool *enabled) -{ - Bool any_enabled = FALSE; - int o; - - for (o = 0; o < config->num_output; o++) - any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE); - - if (!any_enabled) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "No outputs definitely connected, trying again...\n"); - - for (o = 0; o < config->num_output; o++) - any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], FALSE); - } - - return any_enabled; -} - -static Bool -nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index) -{ - int o = *index; - - for (o++; o < config->num_output; o++) { - if (enabled[o]) { - *index = o; - return TRUE; - } - } - - return FALSE; -} - -static Bool -aspectMatch(float a, float b) -{ - return fabs(1 - (a / b)) < 0.05; -} - -static DisplayModePtr -nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect) -{ - DisplayModePtr m = NULL; - - if (!o) - return NULL; - - if (!last) - m = o->probed_modes; - else - m = last->next; - - for (; m; m = m->next) - if (aspectMatch(aspect, (float)m->HDisplay / (float)m->VDisplay)) - return m; - - return NULL; -} - -static DisplayModePtr -bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect) -{ - int o = -1, p; - DisplayModePtr mode = NULL, test = NULL, match = NULL; - - if (!nextEnabledOutput(config, enabled, &o)) - return NULL; - while ((mode = nextAspectMode(config->output[o], mode, aspect))) { - test = mode; - for (p = o; nextEnabledOutput(config, enabled, &p); ) { - test = xf86OutputFindClosestMode(config->output[p], mode); - if (!test) - break; - if (test->HDisplay != mode->HDisplay || - test->VDisplay != mode->VDisplay) { - test = NULL; - break; - } - } - - /* if we didn't match it on all outputs, try the next one */ - if (!test) - continue; - - /* if it's bigger than the last one, save it */ - if (!match || (test->HDisplay > match->HDisplay)) - match = test; - } - - /* return the biggest one found */ - return match; -} - -static Bool -xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, - DisplayModePtr *modes, Bool *enabled, - int width, int height) -{ - int o, p; - int max_pref_width = 0, max_pref_height = 0; - DisplayModePtr *preferred, *preferred_match; - Bool ret = FALSE; - - preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); - preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); - - /* Check if the preferred mode is available on all outputs */ - for (p = -1; nextEnabledOutput(config, enabled, &p); ) { - Rotation r = config->output[p]->initial_rotation; - DisplayModePtr mode; - if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p], - width, height))) { - int pref_width = xf86ModeWidth(preferred[p], r); - int pref_height = xf86ModeHeight(preferred[p], r); - Bool all_match = TRUE; - - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - Bool match = FALSE; - xf86OutputPtr output = config->output[o]; - if (o == p) - continue; - - for (mode = output->probed_modes; mode; mode = mode->next) { - Rotation r = output->initial_rotation; - if (xf86ModeWidth(mode, r) == pref_width && - xf86ModeHeight(mode, r) == pref_height) { - preferred[o] = mode; - match = TRUE; - } - } - - all_match &= match; - } - - if (all_match && - (pref_width*pref_height > max_pref_width*max_pref_height)) { - for (o = -1; nextEnabledOutput(config, enabled, &o); ) - preferred_match[o] = preferred[o]; - max_pref_width = pref_width; - max_pref_height = pref_height; - ret = TRUE; - } - } - } - - /* - * If there's no preferred mode, but only one monitor, pick the - * biggest mode for its aspect ratio, assuming one exists. - */ - if (!ret) do { - int i = 0; - float aspect = 0.0; - - /* count the number of enabled outputs */ - for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ; - - if (i != 1) - break; - - p = -1; - nextEnabledOutput(config, enabled, &p); - if (config->output[p]->mm_height) - aspect = (float)config->output[p]->mm_width / - (float)config->output[p]->mm_height; - - if (aspect) - preferred_match[p] = bestModeForAspect(config, enabled, aspect); - - if (preferred_match[p]) - ret = TRUE; - - } while (0); - - if (ret) { - /* oh good, there is a match. stash the selected modes and return. */ - memcpy(modes, preferred_match, - config->num_output * sizeof(DisplayModePtr)); - } - - free(preferred); - free(preferred_match); - return ret; -} - -static Bool -xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, - DisplayModePtr *modes, Bool *enabled, - int width, int height) -{ - int o; - float aspect = 0.0, *aspects; - xf86OutputPtr output; - Bool ret = FALSE; - DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL; - - aspects = xnfcalloc(config->num_output, sizeof(float)); - - /* collect the aspect ratios */ - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - output = config->output[o]; - if (output->mm_height) - aspects[o] = (float)output->mm_width / (float)output->mm_height; - else - aspects[o] = 4.0 / 3.0; - } - - /* check that they're all the same */ - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - output = config->output[o]; - if (!aspect) { - aspect = aspects[o]; - } else if (!aspectMatch(aspect, aspects[o])) { - goto no_aspect_match; - } - } - - /* if they're all 4:3, just skip ahead and save effort */ - if (!aspectMatch(aspect, 4.0/3.0)) - aspect_guess = bestModeForAspect(config, enabled, aspect); - -no_aspect_match: - base_guess = bestModeForAspect(config, enabled, 4.0/3.0); - - guess = biggestMode(base_guess, aspect_guess); - - if (!guess) - goto out; - - /* found a mode that works everywhere, now apply it */ - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - modes[o] = xf86OutputFindClosestMode(config->output[o], guess); - } - ret = TRUE; - -out: - free(aspects); - return ret; -} - -static Bool -xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, - DisplayModePtr *modes, Bool *enabled, - int width, int height) -{ - DisplayModePtr target_mode = NULL; - Rotation target_rotation = RR_Rotate_0; - DisplayModePtr default_mode; - int default_preferred, target_preferred = 0, o; - - /* User preferred > preferred > other modes */ - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - default_mode = xf86DefaultMode (config->output[o], width, height); - if (!default_mode) - continue; - - default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) + - ((default_mode->type & M_T_USERPREF) != 0)); - - if (default_preferred > target_preferred || !target_mode) { - target_mode = default_mode; - target_preferred = default_preferred; - target_rotation = config->output[o]->initial_rotation; - config->compat_output = o; - } - } - - if (target_mode) - modes[config->compat_output] = target_mode; - - /* Fill in other output modes */ - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - if (!modes[o]) - modes[o] = xf86ClosestMode(config->output[o], target_mode, - target_rotation, width, height); - } - - return target_mode != NULL; -} - -static Bool -xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, - DisplayModePtr *modes, Bool *enabled, - int width, int height) -{ - int o; - - if (xf86UserConfiguredOutputs(scrn, modes)) - return xf86TargetFallback(scrn, config, modes, enabled, width, height); - - for (o = -1; nextEnabledOutput(config, enabled, &o); ) - if (xf86OutputHasUserPreferredMode(config->output[o])) - return - xf86TargetFallback(scrn, config, modes, enabled, width, height); - - return FALSE; -} - -static Bool -xf86CrtcSetInitialGamma(xf86CrtcPtr crtc, float gamma_red, float gamma_green, - float gamma_blue) -{ - int i, size = 256; - CARD16 *red, *green, *blue; - - red = malloc(3 * size * sizeof(CARD16)); - green = red + size; - blue = green + size; - - /* Only cause warning if user wanted gamma to be set. */ - if (!crtc->funcs->gamma_set && (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0)) { - free(red); - return FALSE; - } else if (!crtc->funcs->gamma_set) { - free(red); - return TRUE; - } - - /* At this early stage none of the randr-interface stuff is up. - * So take the default gamma size for lack of something better. - */ - for (i = 0; i < size; i++) { - if (gamma_red == 1.0) - red[i] = i << 8; - else - red[i] = (CARD16)(pow((double)i/(double)(size - 1), - 1. / (double)gamma_red) * (double)(size - 1) * 256); - - if (gamma_green == 1.0) - green[i] = i << 8; - else - green[i] = (CARD16)(pow((double)i/(double)(size - 1), - 1. / (double)gamma_green) * (double)(size - 1) * 256); - - if (gamma_blue == 1.0) - blue[i] = i << 8; - else - blue[i] = (CARD16)(pow((double)i/(double)(size - 1), - 1. / (double)gamma_blue) * (double)(size - 1) * 256); - } - - /* Default size is 256, so anything else is failure. */ - if (size != crtc->gamma_size) { - free(red); - return FALSE; - } - - crtc->gamma_size = size; - memcpy (crtc->gamma_red, red, crtc->gamma_size * sizeof (CARD16)); - memcpy (crtc->gamma_green, green, crtc->gamma_size * sizeof (CARD16)); - memcpy (crtc->gamma_blue, blue, crtc->gamma_size * sizeof (CARD16)); - - /* Do not set gamma now, delay until the crtc is activated. */ - - free(red); - - return TRUE; -} - -static Bool -xf86OutputSetInitialGamma(xf86OutputPtr output) -{ - XF86ConfMonitorPtr mon = output->conf_monitor; - float gamma_red = 1.0, gamma_green = 1.0, gamma_blue = 1.0; - - if (!mon) - return TRUE; - - if (!output->crtc) - return FALSE; - - /* Get configured values, where they exist. */ - if (mon->mon_gamma_red >= GAMMA_MIN && - mon->mon_gamma_red <= GAMMA_MAX) - gamma_red = mon->mon_gamma_red; - - if (mon->mon_gamma_green >= GAMMA_MIN && - mon->mon_gamma_green <= GAMMA_MAX) - gamma_green = mon->mon_gamma_green; - - if (mon->mon_gamma_blue >= GAMMA_MIN && - mon->mon_gamma_blue <= GAMMA_MAX) - gamma_blue = mon->mon_gamma_blue; - - /* This avoids setting gamma 1.0 in case another cloned output on this crtc has a specific gamma. */ - if (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0) { - xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Output %s wants gamma correction (%.1f, %.1f, %.1f)\n", output->name, gamma_red, gamma_green, gamma_blue); - return xf86CrtcSetInitialGamma(output->crtc, gamma_red, gamma_green, gamma_blue); - }else - return TRUE; -} - -/** - * Construct default screen configuration - * - * Given auto-detected (and, eventually, configured) values, - * construct a usable configuration for the system - * - * canGrow indicates that the driver can resize the screen to larger than its - * initially configured size via the config->funcs->resize hook. If TRUE, this - * function will set virtualX and virtualY to match the initial configuration - * and leave config->max{Width,Height} alone. If FALSE, it will bloat - * virtual[XY] to include the largest modes and set config->max{Width,Height} - * accordingly. - */ - -Bool -xf86InitialConfiguration (ScrnInfoPtr scrn, Bool canGrow) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o, c; - xf86CrtcPtr *crtcs; - DisplayModePtr *modes; - Bool *enabled; - int width, height; - int i = scrn->scrnIndex; - Bool have_outputs = TRUE; - Bool ret; - - /* Set up the device options */ - config->options = xnfalloc (sizeof (xf86DeviceOptions)); - memcpy (config->options, xf86DeviceOptions, sizeof (xf86DeviceOptions)); - xf86ProcessOptions (scrn->scrnIndex, - scrn->options, - config->options); - config->debug_modes = xf86ReturnOptValBool (config->options, - OPTION_MODEDEBUG, FALSE); - - if (scrn->display->virtualX) - width = scrn->display->virtualX; - else - width = config->maxWidth; - if (scrn->display->virtualY) - height = scrn->display->virtualY; - else - height = config->maxHeight; - - xf86ProbeOutputModes (scrn, width, height); - - crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr)); - modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr)); - enabled = xnfcalloc (config->num_output, sizeof (Bool)); - - ret = xf86CollectEnabledOutputs(scrn, config, enabled); - if (ret == FALSE && canGrow) { - xf86DrvMsg(i, X_WARNING, "Unable to find connected outputs - setting %dx%d initial framebuffer\n", - NO_OUTPUT_DEFAULT_WIDTH, NO_OUTPUT_DEFAULT_HEIGHT); - have_outputs = FALSE; - } else { - if (xf86TargetUserpref(scrn, config, modes, enabled, width, height)) - xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n"); - else if (xf86TargetPreferred(scrn, config, modes, enabled, width, height)) - xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n"); - else if (xf86TargetAspect(scrn, config, modes, enabled, width, height)) - xf86DrvMsg(i, X_INFO, "Using fuzzy aspect match for initial modes\n"); - else if (xf86TargetFallback(scrn, config, modes, enabled, width, height)) - xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n"); - else - xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n"); - } - - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - if (!modes[o]) - xf86DrvMsg (scrn->scrnIndex, X_ERROR, - "Output %s enabled but has no modes\n", - config->output[o]->name); - else - xf86DrvMsg (scrn->scrnIndex, X_INFO, - "Output %s using initial mode %s\n", - config->output[o]->name, modes[o]->name); - } - - /* - * Set the position of each output - */ - if (!xf86InitialOutputPositions (scrn, modes)) - { - free(crtcs); - free(modes); - return FALSE; - } - - /* - * Set initial panning of each output - */ - xf86InitialPanning (scrn); - - /* - * Assign CRTCs to fit output configuration - */ - if (have_outputs && !xf86PickCrtcs (scrn, crtcs, modes, 0, width, height)) - { - free(crtcs); - free(modes); - return FALSE; - } - - /* XXX override xf86 common frame computation code */ - - scrn->display->frameX0 = 0; - scrn->display->frameY0 = 0; - - for (c = 0; c < config->num_crtc; c++) - { - xf86CrtcPtr crtc = config->crtc[c]; - - crtc->enabled = FALSE; - memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode)); - /* Set default gamma for all crtc's. */ - /* This is done to avoid problems later on with cloned outputs. */ - xf86CrtcSetInitialGamma(crtc, 1.0, 1.0, 1.0); - } - - if (xf86_crtc_supports_gamma(scrn)) - xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using default gamma of (1.0, 1.0, 1.0) unless otherwise stated.\n"); - - /* - * Set initial configuration - */ - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - DisplayModePtr mode = modes[o]; - xf86CrtcPtr crtc = crtcs[o]; - - if (mode && crtc) - { - crtc->desiredMode = *mode; - crtc->desiredRotation = output->initial_rotation; - crtc->desiredX = output->initial_x; - crtc->desiredY = output->initial_y; - crtc->desiredTransformPresent = FALSE; - crtc->enabled = TRUE; - memcpy (&crtc->panningTotalArea, &output->initialTotalArea, sizeof(BoxRec)); - memcpy (&crtc->panningTrackingArea, &output->initialTrackingArea, sizeof(BoxRec)); - memcpy (crtc->panningBorder, output->initialBorder, 4*sizeof(INT16)); - output->crtc = crtc; - if (!xf86OutputSetInitialGamma(output)) - xf86DrvMsg (scrn->scrnIndex, X_WARNING, "Initial gamma correction for output %s: failed.\n", output->name); - } else { - output->crtc = NULL; - } - } - - if (scrn->display->virtualX == 0) - { - /* - * Expand virtual size to cover the current config and potential mode - * switches, if the driver can't enlarge the screen later. - */ - xf86DefaultScreenLimits (scrn, &width, &height, canGrow); - - if (have_outputs == FALSE) { - if (width < NO_OUTPUT_DEFAULT_WIDTH && height < NO_OUTPUT_DEFAULT_HEIGHT) { - width = NO_OUTPUT_DEFAULT_WIDTH; - height = NO_OUTPUT_DEFAULT_HEIGHT; - } - } - - scrn->display->virtualX = width; - scrn->display->virtualY = height; - } - - if (width > scrn->virtualX) - scrn->virtualX = width; - if (height > scrn->virtualY) - scrn->virtualY = height; - - /* - * Make sure the configuration isn't too small. - */ - if (width < config->minWidth || height < config->minHeight) - return FALSE; - - /* - * Limit the crtc config to virtual[XY] if the driver can't grow the - * desktop. - */ - if (!canGrow) - { - xf86CrtcSetSizeRange (scrn, config->minWidth, config->minHeight, - width, height); - } - - if (have_outputs) { - /* Mirror output modes to scrn mode list */ - xf86SetScrnInfoModes (scrn); - } else { - /* Clear any existing modes from scrn->modes */ - while (scrn->modes != NULL) - xf86DeleteMode(&scrn->modes, scrn->modes); - scrn->modes = xf86ModesAdd(scrn->modes, - xf86CVTMode(width, height, 60, 0, 0)); - } - - - free(crtcs); - free(modes); - return TRUE; -} - -/* - * Check the CRTC we're going to map each output to vs. it's current - * CRTC. If they don't match, we have to disable the output and the CRTC - * since the driver will have to re-route things. - */ -static void -xf86PrepareOutputs (ScrnInfoPtr scrn) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o; - - for (o = 0; o < config->num_output; o++) { - xf86OutputPtr output = config->output[o]; -#if RANDR_GET_CRTC_INTERFACE - /* Disable outputs that are unused or will be re-routed */ - if (!output->funcs->get_crtc || - output->crtc != (*output->funcs->get_crtc)(output) || - output->crtc == NULL) -#endif - (*output->funcs->dpms)(output, DPMSModeOff); - } -} - -static void -xf86PrepareCrtcs (ScrnInfoPtr scrn) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int c; - - for (c = 0; c < config->num_crtc; c++) { -#if RANDR_GET_CRTC_INTERFACE - xf86CrtcPtr crtc = config->crtc[c]; - xf86OutputPtr output = NULL; - uint32_t desired_outputs = 0, current_outputs = 0; - int o; - - for (o = 0; o < config->num_output; o++) { - output = config->output[o]; - if (output->crtc == crtc) - desired_outputs |= (1<funcs->get_crtc) { - desired_outputs = 0; - break; - } - if ((*output->funcs->get_crtc)(output) == crtc) - current_outputs |= (1<funcs->dpms)(crtc, DPMSModeOff); -#else - (*crtc->funcs->dpms)(crtc, DPMSModeOff); -#endif - } -} - -/* - * Using the desired mode information in each crtc, set - * modes (used in EnterVT functions, or at server startup) - */ - -Bool -xf86SetDesiredModes (ScrnInfoPtr scrn) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - xf86CrtcPtr crtc = config->crtc[0]; - int c; - - /* A driver with this hook will take care of this */ - if (!crtc->funcs->set_mode_major) { - xf86PrepareOutputs(scrn); - xf86PrepareCrtcs(scrn); - } - - for (c = 0; c < config->num_crtc; c++) - { - xf86OutputPtr output = NULL; - xf86CrtcSetRec set; - int o; - RRTransformPtr transform; - - crtc = config->crtc[c]; - - /* Skip disabled CRTCs */ - if (!crtc->enabled) - continue; - - if (xf86CompatOutput(scrn) && xf86CompatCrtc(scrn) == crtc) - output = xf86CompatOutput(scrn); - else - { - for (o = 0; o < config->num_output; o++) - if (config->output[o]->crtc == crtc) - { - output = config->output[o]; - break; - } - } - /* paranoia */ - if (!output) - continue; - - /* Mark that we'll need to re-set the mode for sure */ - memset(&crtc->mode, 0, sizeof(crtc->mode)); - if (!crtc->desiredMode.CrtcHDisplay) - { - DisplayModePtr mode = xf86OutputFindClosestMode (output, scrn->currentMode); - - if (!mode) - return FALSE; - crtc->desiredMode = *mode; - crtc->desiredRotation = RR_Rotate_0; - crtc->desiredTransformPresent = FALSE; - crtc->desiredX = 0; - crtc->desiredY = 0; - } - - if (crtc->desiredTransformPresent) - transform = &crtc->desiredTransform; - else - transform = NULL; - set.mode = &crtc->desiredMode; - set.rotation = crtc->desiredRotation; - set.transform = transform; - set.x = crtc->desiredX; - set.y = crtc->desiredY; - set.flags = (XF86CrtcSetMode | XF86CrtcSetOutput | - XF86CrtcSetOrigin | XF86CrtcSetTransform | - XF86CrtcSetRotation); - if (!xf86CrtcSet(crtc, &set)) - return FALSE; - } - - xf86DisableUnusedFunctions(scrn); - return TRUE; -} - -/** - * In the current world order, there are lists of modes per output, which may - * or may not include the mode that was asked to be set by XFree86's mode - * selection. Find the closest one, in the following preference order: - * - * - Equality - * - Closer in size to the requested mode, but no larger - * - Closer in refresh rate to the requested mode. - */ - -DisplayModePtr -xf86OutputFindClosestMode (xf86OutputPtr output, DisplayModePtr desired) -{ - DisplayModePtr best = NULL, scan = NULL; - - for (scan = output->probed_modes; scan != NULL; scan = scan->next) - { - /* If there's an exact match, we're done. */ - if (xf86ModesEqual(scan, desired)) { - best = desired; - break; - } - - /* Reject if it's larger than the desired mode. */ - if (scan->HDisplay > desired->HDisplay || - scan->VDisplay > desired->VDisplay) - { - continue; - } - - /* - * If we haven't picked a best mode yet, use the first - * one in the size range - */ - if (best == NULL) - { - best = scan; - continue; - } - - /* Find if it's closer to the right size than the current best - * option. - */ - if ((scan->HDisplay > best->HDisplay && - scan->VDisplay >= best->VDisplay) || - (scan->HDisplay >= best->HDisplay && - scan->VDisplay > best->VDisplay)) - { - best = scan; - continue; - } - - /* Find if it's still closer to the right refresh than the current - * best resolution. - */ - if (scan->HDisplay == best->HDisplay && - scan->VDisplay == best->VDisplay && - (fabs(scan->VRefresh - desired->VRefresh) < - fabs(best->VRefresh - desired->VRefresh))) { - best = scan; - } - } - return best; -} - -/** - * When setting a mode through XFree86-VidModeExtension or XFree86-DGA, - * take the specified mode and apply it to the crtc connected to the compat - * output. Then, find similar modes for the other outputs, as with the - * InitialConfiguration code above. The goal is to clone the desired - * mode across all outputs that are currently active. - */ - -Bool -xf86SetSingleMode (ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); - Bool ok = TRUE; - xf86OutputPtr compat_output; - DisplayModePtr compat_mode = NULL; - int c; - - /* - * Let the compat output drive the final mode selection - */ - compat_output = xf86CompatOutput(pScrn); - if (compat_output) - compat_mode = xf86OutputFindClosestMode (compat_output, desired); - if (compat_mode) - desired = compat_mode; - - for (c = 0; c < config->num_crtc; c++) - { - xf86CrtcPtr crtc = config->crtc[c]; - DisplayModePtr crtc_mode = NULL; - int o; - xf86CrtcSetRec set; - - if (!crtc->enabled) - continue; - - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - DisplayModePtr output_mode; - - /* skip outputs not on this crtc */ - if (output->crtc != crtc) - continue; - - if (crtc_mode) - { - output_mode = xf86OutputFindClosestMode (output, crtc_mode); - if (output_mode != crtc_mode) - output->crtc = NULL; - } - else - crtc_mode = xf86OutputFindClosestMode (output, desired); - } - if (!crtc_mode) - { - crtc->enabled = FALSE; - continue; - } - set.mode = crtc_mode; - set.rotation = rotation; - set.transform = NULL; - set.x = 0; - set.y = 0; - set.flags = (XF86CrtcSetMode | XF86CrtcSetOutput | - XF86CrtcSetOrigin | XF86CrtcSetTransform | - XF86CrtcSetRotation); - if (!xf86CrtcSet (crtc, &set)) - ok = FALSE; - else - { - crtc->desiredMode = *crtc_mode; - crtc->desiredRotation = rotation; - crtc->desiredTransformPresent = FALSE; - crtc->desiredX = 0; - crtc->desiredY = 0; - } - } - xf86DisableUnusedFunctions(pScrn); -#ifdef RANDR_12_INTERFACE - xf86RandR12TellChanged (pScrn->pScreen); -#endif - return ok; -} - - -/** - * Set the DPMS power mode of all outputs and CRTCs. - * - * If the new mode is off, it will turn off outputs and then CRTCs. - * Otherwise, it will affect CRTCs before outputs. - */ -void -xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int i; - - if (!scrn->vtSema) - return; - - if (mode == DPMSModeOff) { - for (i = 0; i < config->num_output; i++) { - xf86OutputPtr output = config->output[i]; - if (output->crtc != NULL) - (*output->funcs->dpms) (output, mode); - } - } - - for (i = 0; i < config->num_crtc; i++) { - xf86CrtcPtr crtc = config->crtc[i]; - if (crtc->enabled) - (*crtc->funcs->dpms) (crtc, mode); - } - - if (mode != DPMSModeOff) { - for (i = 0; i < config->num_output; i++) { - xf86OutputPtr output = config->output[i]; - if (output->crtc != NULL) - (*output->funcs->dpms) (output, mode); - } - } -} - -/** - * Implement the screensaver by just calling down into the driver DPMS hooks. - * - * Even for monitors with no DPMS support, by the definition of our DPMS hooks, - * the outputs will still get disabled (blanked). - */ -Bool -xf86SaveScreen(ScreenPtr pScreen, int mode) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - - if (xf86IsUnblank(mode)) - xf86DPMSSet(pScrn, DPMSModeOn, 0); - else - xf86DPMSSet(pScrn, DPMSModeOff, 0); - - return TRUE; -} - -/** - * Disable all inactive crtcs and outputs - */ -void -xf86DisableUnusedFunctions(ScrnInfoPtr pScrn) -{ - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - int o, c; - - for (o = 0; o < xf86_config->num_output; o++) - { - xf86OutputPtr output = xf86_config->output[o]; - if (!output->crtc) - (*output->funcs->dpms)(output, DPMSModeOff); - } - - for (c = 0; c < xf86_config->num_crtc; c++) - { - xf86CrtcPtr crtc = xf86_config->crtc[c]; - - if (!crtc->enabled) - { - crtc->funcs->dpms(crtc, DPMSModeOff); - memset(&crtc->mode, 0, sizeof(crtc->mode)); - xf86RotateDestroy(crtc); - crtc->active = FALSE; - } - } - if (pScrn->pScreen) - xf86_crtc_notify(pScrn->pScreen); - if (pScrn->ModeSet) - pScrn->ModeSet(pScrn); -} - -#ifdef RANDR_12_INTERFACE - -#define EDID_ATOM_NAME "EDID" - -/** - * Set the RandR EDID property - */ -static void -xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len) -{ - Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE); - - /* This may get called before the RandR resources have been created */ - if (output->randr_output == NULL) - return; - - if (data_len != 0) { - RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, - PropModeReplace, data_len, data, FALSE, TRUE); - } else { - RRDeleteOutputProperty(output->randr_output, edid_atom); - } -} - -#endif - -/* Pull out a phyiscal size from a detailed timing if available. */ -struct det_phySize_parameter { - xf86OutputPtr output; - ddc_quirk_t quirks; - Bool ret; -}; - -static void handle_detailed_physical_size(struct detailed_monitor_section - *det_mon, void *data) -{ - struct det_phySize_parameter *p; - p = (struct det_phySize_parameter *)data; - - if (p->ret == TRUE ) - return ; - - xf86DetTimingApplyQuirks(det_mon, p->quirks, - p->output->MonInfo->features.hsize, - p->output->MonInfo->features.vsize); - if (det_mon->type == DT && - det_mon->section.d_timings.h_size != 0 && - det_mon->section.d_timings.v_size != 0) { - - p->output->mm_width = det_mon->section.d_timings.h_size; - p->output->mm_height = det_mon->section.d_timings.v_size; - p->ret = TRUE; - } -} - -/** - * Set the EDID information for the specified output - */ -void -xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon) -{ - ScrnInfoPtr scrn = output->scrn; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - Bool debug_modes = config->debug_modes || xf86Initialising; -#ifdef RANDR_12_INTERFACE - int size; -#endif - - free(output->MonInfo); - - output->MonInfo = edid_mon; - output->mm_width = 0; - output->mm_height = 0; - - if (debug_modes) { - xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n", - output->name); - xf86PrintEDID(edid_mon); - } - - /* Set the DDC properties for the 'compat' output */ - if (output == xf86CompatOutput(scrn)) - xf86SetDDCproperties(scrn, edid_mon); - -#ifdef RANDR_12_INTERFACE - /* Set the RandR output properties */ - size = 0; - if (edid_mon) - { - if (edid_mon->ver.version == 1) { - size = 128; - if (edid_mon->flags & EDID_COMPLETE_RAWDATA) - size += edid_mon->no_sections * 128; - } else if (edid_mon->ver.version == 2) - size = 256; - } - xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size); -#endif - - if (edid_mon) { - - struct det_phySize_parameter p; - p.output = output; - p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex,edid_mon, FALSE); - p.ret = FALSE; - xf86ForEachDetailedBlock(edid_mon, - handle_detailed_physical_size, &p); - - /* if no mm size is available from a detailed timing, check the max size field */ - if ((!output->mm_width || !output->mm_height) && - (edid_mon->features.hsize && edid_mon->features.vsize)) - { - output->mm_width = edid_mon->features.hsize * 10; - output->mm_height = edid_mon->features.vsize * 10; - } - } -} - -/** - * Return the list of modes supported by the EDID information - * stored in 'output' - */ -DisplayModePtr -xf86OutputGetEDIDModes (xf86OutputPtr output) -{ - ScrnInfoPtr scrn = output->scrn; - xf86MonPtr edid_mon = output->MonInfo; - - if (!edid_mon) - return NULL; - return xf86DDCGetModes(scrn->scrnIndex, edid_mon); -} - -/* maybe we should care about DDC1? meh. */ -xf86MonPtr -xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus) -{ - ScrnInfoPtr scrn = output->scrn; - xf86MonPtr mon; - - mon = xf86DoEEDID(scrn->scrnIndex, pDDCBus, TRUE); - if (mon) - xf86DDCApplyQuirks(scrn->scrnIndex, mon); - - return mon; -} - -static char *_xf86ConnectorNames[] = { - "None", "VGA", "DVI-I", "DVI-D", - "DVI-A", "Composite", "S-Video", - "Component", "LFP", "Proprietary", - "HDMI", "DisplayPort", - }; -char * -xf86ConnectorGetName(xf86ConnectorType connector) -{ - return _xf86ConnectorNames[connector]; -} - -static void -x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) -{ - dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; - dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; - dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; - dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; - - if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) - dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; -} - -static void -x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) -{ - if (crtc->enabled) { - crtc_box->x1 = crtc->x; - crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); - crtc_box->y1 = crtc->y; - crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); - } else - crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; -} - -static int -xf86_crtc_box_area(BoxPtr box) -{ - return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); -} - -/* - * Return the crtc covering 'box'. If two crtcs cover a portion of - * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc - * with greater coverage - */ - -static xf86CrtcPtr -xf86_covering_crtc(ScrnInfoPtr pScrn, - BoxPtr box, - xf86CrtcPtr desired, - BoxPtr crtc_box_ret) -{ - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - xf86CrtcPtr crtc, best_crtc; - int coverage, best_coverage; - int c; - BoxRec crtc_box, cover_box; - - best_crtc = NULL; - best_coverage = 0; - crtc_box_ret->x1 = 0; - crtc_box_ret->x2 = 0; - crtc_box_ret->y1 = 0; - crtc_box_ret->y2 = 0; - for (c = 0; c < xf86_config->num_crtc; c++) { - crtc = xf86_config->crtc[c]; - x86_crtc_box(crtc, &crtc_box); - x86_crtc_box_intersect(&cover_box, &crtc_box, box); - coverage = xf86_crtc_box_area(&cover_box); - if (coverage && crtc == desired) { - *crtc_box_ret = crtc_box; - return crtc; - } else if (coverage > best_coverage) { - *crtc_box_ret = crtc_box; - best_crtc = crtc; - best_coverage = coverage; - } - } - return best_crtc; -} - -/* - * For overlay video, compute the relevant CRTC and - * clip video to that. - * - * returning FALSE means there was a memory failure of some kind, - * not that the video shouldn't be displayed - */ - -Bool -xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, - xf86CrtcPtr *crtc_ret, - xf86CrtcPtr desired_crtc, - BoxPtr dst, - INT32 *xa, - INT32 *xb, - INT32 *ya, - INT32 *yb, - RegionPtr reg, - INT32 width, - INT32 height) -{ - Bool ret; - RegionRec crtc_region_local; - RegionPtr crtc_region = reg; - - if (crtc_ret) { - BoxRec crtc_box; - xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst, - desired_crtc, - &crtc_box); - - if (crtc) { - RegionInit(&crtc_region_local, &crtc_box, 1); - crtc_region = &crtc_region_local; - RegionIntersect(crtc_region, crtc_region, reg); - } - *crtc_ret = crtc; - } - - ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, - crtc_region, width, height); - - if (crtc_region != reg) - RegionUninit(&crtc_region_local); - - return ret; -} - -xf86_crtc_notify_proc_ptr -xf86_wrap_crtc_notify (ScreenPtr screen, xf86_crtc_notify_proc_ptr new) -{ - if (xf86CrtcConfigPrivateIndex != -1) - { - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - xf86_crtc_notify_proc_ptr old; - - old = config->xf86_crtc_notify; - config->xf86_crtc_notify = new; - return old; - } - return NULL; -} - -void -xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old) -{ - if (xf86CrtcConfigPrivateIndex != -1) - { - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - - config->xf86_crtc_notify = old; - } -} - -void -xf86_crtc_notify(ScreenPtr screen) -{ - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - - if (config->xf86_crtc_notify) - config->xf86_crtc_notify(screen); -} - -Bool -xf86_crtc_supports_gamma(ScrnInfoPtr pScrn) -{ - if (xf86CrtcConfigPrivateIndex != -1) { - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - xf86CrtcPtr crtc; - - /* for multiple drivers loaded we need this */ - if (!xf86_config) - return FALSE; - if (xf86_config->num_crtc == 0) - return FALSE; - crtc = xf86_config->crtc[0]; - - return crtc->funcs->gamma_set != NULL; - } - - return FALSE; -} +/* + * Copyright © 2006 Keith Packard + * Copyright © 2008 Red Hat, Inc. + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#else +#ifdef HAVE_CONFIG_H +#include +#endif +#endif + +#include +#include +#include + +#include "xf86.h" +#include "xf86DDC.h" +#include "xf86Crtc.h" +#include "xf86Modes.h" +#include "xf86Priv.h" +#include "xf86RandR12.h" +#include "X11/extensions/render.h" +#include "X11/extensions/dpmsconst.h" +#include "X11/Xatom.h" +#include "picturestr.h" + +#include "xf86xv.h" + +#define NO_OUTPUT_DEFAULT_WIDTH 1024 +#define NO_OUTPUT_DEFAULT_HEIGHT 768 +/* + * Initialize xf86CrtcConfig structure + */ + +int xf86CrtcConfigPrivateIndex = -1; + +void +xf86CrtcConfigInit (ScrnInfoPtr scrn, + const xf86CrtcConfigFuncsRec *funcs) +{ + xf86CrtcConfigPtr config; + + if (xf86CrtcConfigPrivateIndex == -1) + xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); + config = xnfcalloc (1, sizeof (xf86CrtcConfigRec)); + + config->funcs = funcs; + + scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config; +} + +void +xf86CrtcSetSizeRange (ScrnInfoPtr scrn, + int minWidth, int minHeight, + int maxWidth, int maxHeight) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + config->minWidth = minWidth; + config->minHeight = minHeight; + config->maxWidth = maxWidth; + config->maxHeight = maxHeight; +} + +void +xf86CrtcSetScanoutFormats(ScrnInfoPtr scrn, + int num_formats, + xf86CrtcScanoutFormat *formats) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + config->num_scanout_formats = num_formats; + config->scanout_formats = formats; +} + +/* + * Crtc functions + */ +xf86CrtcPtr +xf86CrtcCreate (ScrnInfoPtr scrn, + const xf86CrtcFuncsRec *funcs) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CrtcPtr crtc, *crtcs; + + crtc = calloc(sizeof (xf86CrtcRec), 1); + if (!crtc) + return NULL; + crtc->version = XF86_CRTC_VERSION; + crtc->scrn = scrn; + crtc->funcs = funcs; +#ifdef RANDR_12_INTERFACE + crtc->randr_crtc = NULL; +#endif + crtc->rotation = RR_Rotate_0; + crtc->desiredRotation = RR_Rotate_0; + pixman_transform_init_identity (&crtc->crtc_to_framebuffer); + pixman_f_transform_init_identity (&crtc->f_crtc_to_framebuffer); + pixman_f_transform_init_identity (&crtc->f_framebuffer_to_crtc); + pixman_f_transform_init_identity (&crtc->f_screen_to_crtc); + pixman_f_transform_init_identity (&crtc->user_sprite_position_transform); + pixman_f_transform_init_identity (&crtc->f_crtc_to_cursor); + pixman_f_transform_init_identity (&crtc->user_sprite_image_transform); + crtc->filter = NULL; + crtc->params = NULL; + crtc->nparams = 0; + crtc->filter_width = 0; + crtc->filter_height = 0; + crtc->transform_in_use = FALSE; + crtc->sprite_transform_in_use = FALSE; + crtc->transformPresent = FALSE; + crtc->desiredTransformPresent = FALSE; + memset (&crtc->bounds, '\0', sizeof (crtc->bounds)); + + /* Preallocate gamma at a sensible size. */ + crtc->gamma_size = 256; + crtc->gamma_red = malloc(3 * crtc->gamma_size * sizeof (CARD16)); + if (!crtc->gamma_red) { + free(crtc); + return NULL; + } + crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; + crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; + + if (xf86_config->crtc) + crtcs = realloc(xf86_config->crtc, + (xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); + else + crtcs = malloc((xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); + if (!crtcs) + { + free(crtc); + return NULL; + } + xf86_config->crtc = crtcs; + xf86_config->crtc[xf86_config->num_crtc++] = crtc; + return crtc; +} + +void +xf86CrtcDestroy (xf86CrtcPtr crtc) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + int c; + + (*crtc->funcs->destroy) (crtc); + for (c = 0; c < xf86_config->num_crtc; c++) + if (xf86_config->crtc[c] == crtc) + { + memmove (&xf86_config->crtc[c], + &xf86_config->crtc[c+1], + ((xf86_config->num_crtc - (c + 1)) * sizeof(void*))); + xf86_config->num_crtc--; + break; + } + free(crtc->params); + free(crtc->gamma_red); + free(crtc); +} + + +/** + * Return whether any outputs are connected to the specified pipe + */ + +Bool +xf86CrtcInUse (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int o; + + for (o = 0; o < xf86_config->num_output; o++) + if (xf86_config->output[o]->crtc == crtc) + return TRUE; + return FALSE; +} + +void +xf86CrtcSetScreenSubpixelOrder (ScreenPtr pScreen) +{ + int subpixel_order = SubPixelUnknown; + Bool has_none = FALSE; + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c, o; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + for (o = 0; o < xf86_config->num_output; o++) + { + xf86OutputPtr output = xf86_config->output[o]; + + if (output->crtc == crtc) + { + switch (output->subpixel_order) { + case SubPixelNone: + has_none = TRUE; + break; + case SubPixelUnknown: + break; + default: + subpixel_order = output->subpixel_order; + break; + } + } + if (subpixel_order != SubPixelUnknown) + break; + } + if (subpixel_order != SubPixelUnknown) + { + static const int circle[4] = { + SubPixelHorizontalRGB, + SubPixelVerticalRGB, + SubPixelHorizontalBGR, + SubPixelVerticalBGR, + }; + int rotate; + int c; + for (rotate = 0; rotate < 4; rotate++) + if (crtc->rotation & (1 << rotate)) + break; + for (c = 0; c < 4; c++) + if (circle[c] == subpixel_order) + break; + c = (c + rotate) & 0x3; + if ((crtc->rotation & RR_Reflect_X) && !(c & 1)) + c ^= 2; + if ((crtc->rotation & RR_Reflect_Y) && (c & 1)) + c ^= 2; + subpixel_order = circle[c]; + break; + } + } + if (subpixel_order == SubPixelUnknown && has_none) + subpixel_order = SubPixelNone; + PictureSetSubpixelOrder (pScreen, subpixel_order); +} + +/** + * Sets the given video mode on the given crtc + */ +Bool +xf86CrtcSet(xf86CrtcPtr crtc, xf86CrtcSetRec *set) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int i; + Bool ret = FALSE; + Bool didLock = FALSE; + DisplayModePtr adjusted_mode = NULL; + DisplayModeRec saved_mode; + int saved_x, saved_y; + Rotation saved_rotation; + RRTransformRec saved_transform; + Bool saved_transform_present; + PixmapPtr saved_scanout_pixmap; + + crtc->enabled = xf86CrtcInUse (crtc); + + /* We only hit this if someone explicitly sends a "disabled" modeset. */ + if (!crtc->enabled) + { + /* Check everything for stuff that should be off. */ + xf86DisableUnusedFunctions(scrn); + return TRUE; + } + + /* See if nothing has changed */ + if (!set->flags) + return TRUE; + + saved_mode = crtc->mode; + saved_x = crtc->x; + saved_y = crtc->y; + saved_rotation = crtc->rotation; + saved_scanout_pixmap = crtc->scanoutPixmap; + if (crtc->transformPresent) { + RRTransformInit (&saved_transform); + RRTransformCopy (&saved_transform, &crtc->transform); + } + saved_transform_present = crtc->transformPresent; + + /* Update crtc values up front so the driver can rely on them for mode + * setting. + */ + if (set->flags & XF86CrtcSetMode) + crtc->mode = *set->mode; + if (set->flags & XF86CrtcSetOrigin) { + crtc->x = set->x; + crtc->y = set->y; + } + if (set->flags & XF86CrtcSetRotation) + crtc->rotation = set->rotation; + if (set->flags & XF86CrtcSetScanoutPixmap) + crtc->scanoutPixmap = set->scanout_pixmap; + + if (set->flags & XF86CrtcSetTransform) { + if (set->transform) { + RRTransformCopy (&crtc->transform, set->transform); + crtc->transformPresent = TRUE; + } else + crtc->transformPresent = FALSE; + } + + if (crtc->funcs->set) { + ret = crtc->funcs->set(crtc, set->flags); + goto done; + } + + if (set->flags == XF86CrtcSetOrigin && crtc->funcs->set_origin) { + ret = xf86CrtcRotate(crtc); + if (ret) + crtc->funcs->set_origin(crtc, crtc->x, crtc->y); + goto done; + } + + if (crtc->funcs->set_mode_major) { + ret = crtc->funcs->set_mode_major(crtc, &crtc->mode, + crtc->rotation, + crtc->x, crtc->y); + goto done; + } + + adjusted_mode = xf86DuplicateMode(&crtc->mode); + + didLock = crtc->funcs->lock (crtc); + /* Pass our mode to the outputs and the CRTC to give them a chance to + * adjust it according to limitations or output properties, and also + * a chance to reject the mode entirely. + */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + if (output->crtc != crtc) + continue; + + if (!output->funcs->mode_fixup(output, &crtc->mode, adjusted_mode)) { + goto done; + } + } + + if (!crtc->funcs->mode_fixup(crtc, &crtc->mode, adjusted_mode)) { + goto done; + } + + if (!xf86CrtcRotate (crtc)) + goto done; + + /* Prepare the outputs and CRTCs before setting the mode. */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + if (output->crtc != crtc) + continue; + + /* Disable the output as the first thing we do. */ + output->funcs->prepare(output); + } + + crtc->funcs->prepare(crtc); + + /* Set up the DPLL and any output state that needs to adjust or depend + * on the DPLL. + */ + crtc->funcs->mode_set(crtc, &crtc->mode, adjusted_mode, crtc->x, crtc->y); + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr output = xf86_config->output[i]; + if (output->crtc == crtc) + output->funcs->mode_set(output, &crtc->mode, adjusted_mode); + } + + /* Only upload when needed, to avoid unneeded delays. */ + if (!crtc->active && crtc->funcs->gamma_set) + crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, + crtc->gamma_blue, crtc->gamma_size); + + /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ + crtc->funcs->commit(crtc); + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr output = xf86_config->output[i]; + if (output->crtc == crtc) + output->funcs->commit(output); + } + + ret = TRUE; + +done: + if (ret) { + crtc->active = TRUE; + if (scrn->pScreen) + xf86CrtcSetScreenSubpixelOrder (scrn->pScreen); + if (scrn->ModeSet) + scrn->ModeSet(scrn); + } else { + crtc->x = saved_x; + crtc->y = saved_y; + crtc->rotation = saved_rotation; + crtc->mode = saved_mode; + if (saved_transform_present) + RRTransformCopy (&crtc->transform, &saved_transform); + crtc->transformPresent = saved_transform_present; + crtc->scanoutPixmap = saved_scanout_pixmap; + } + + if (adjusted_mode) { + free(adjusted_mode->name); + free(adjusted_mode); + } + + if (didLock) + crtc->funcs->unlock (crtc); + + return ret; +} + +/** + * Pans the screen, does not change the mode + */ +void +xf86CrtcSetOrigin (xf86CrtcPtr crtc, int x, int y) +{ + xf86CrtcSetRec set; + + if (x != crtc->x || y != crtc->y) { + set.x = x; + set.y = y; + set.flags = XF86CrtcSetOrigin; + (void) xf86CrtcSet(crtc, &set); + } +} + +/* + * Output functions + */ + +extern XF86ConfigPtr xf86configptr; + +typedef enum { + OPTION_PREFERRED_MODE, + OPTION_POSITION, + OPTION_BELOW, + OPTION_RIGHT_OF, + OPTION_ABOVE, + OPTION_LEFT_OF, + OPTION_ENABLE, + OPTION_DISABLE, + OPTION_MIN_CLOCK, + OPTION_MAX_CLOCK, + OPTION_IGNORE, + OPTION_ROTATE, + OPTION_PANNING, + OPTION_PRIMARY, + OPTION_DEFAULT_MODES, +} OutputOpts; + +static OptionInfoRec xf86OutputOptions[] = { + {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE }, + {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE }, + {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE }, + {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE }, + {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE }, + {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE }, + {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE }, + {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE }, + {OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE }, + {OPTION_PANNING, "Panning", OPTV_STRING, {0}, FALSE }, + {OPTION_PRIMARY, "Primary", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_DEFAULT_MODES, "DefaultModes", OPTV_BOOLEAN, {0}, FALSE }, + {-1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +enum { + OPTION_MODEDEBUG, +}; + +static OptionInfoRec xf86DeviceOptions[] = { + {OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE }, + {-1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +static void +xf86OutputSetMonitor (xf86OutputPtr output) +{ + char *option_name; + char *monitor; + + if (!output->name) + return; + + free(output->options); + + output->options = xnfalloc (sizeof (xf86OutputOptions)); + memcpy (output->options, xf86OutputOptions, sizeof (xf86OutputOptions)); + + XNFasprintf(&option_name, "monitor-%s", output->name); + monitor = xf86findOptionValue (output->scrn->options, option_name); + if (!monitor) + monitor = output->name; + else + xf86MarkOptionUsedByName (output->scrn->options, option_name); + free(option_name); + output->conf_monitor = xf86findMonitor (monitor, + xf86configptr->conf_monitor_lst); + /* + * Find the monitor section of the screen and use that + */ + if (!output->conf_monitor && output->use_screen_monitor) + output->conf_monitor = xf86findMonitor (output->scrn->monitor->id, + xf86configptr->conf_monitor_lst); + if (output->conf_monitor) + { + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s using monitor section %s\n", + output->name, output->conf_monitor->mon_identifier); + xf86ProcessOptions (output->scrn->scrnIndex, + output->conf_monitor->mon_option_lst, + output->options); + } + else + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s has no monitor section\n", + output->name); +} + +static Bool +xf86OutputEnabled (xf86OutputPtr output, Bool strict) +{ + Bool enable, disable; + + /* check to see if this output was enabled in the config file */ + if (xf86GetOptValBool (output->options, OPTION_ENABLE, &enable) && enable) + { + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s enabled by config file\n", output->name); + return TRUE; + } + /* or if this output was disabled in the config file */ + if (xf86GetOptValBool (output->options, OPTION_DISABLE, &disable) && disable) + { + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s disabled by config file\n", output->name); + return FALSE; + } + + /* If not, try to only light up the ones we know are connected */ + if (strict) { + enable = output->status == XF86OutputStatusConnected; + } + /* But if that fails, try to light up even outputs we're unsure of */ + else { + enable = output->status != XF86OutputStatusDisconnected; + } + + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s %sconnected\n", output->name, enable ? "" : "dis"); + return enable; +} + +static Bool +xf86OutputIgnored (xf86OutputPtr output) +{ + return xf86ReturnOptValBool (output->options, OPTION_IGNORE, FALSE); +} + +static char *direction[4] = { + "normal", + "left", + "inverted", + "right" +}; + +static Rotation +xf86OutputInitialRotation (xf86OutputPtr output) +{ + char *rotate_name = xf86GetOptValString (output->options, + OPTION_ROTATE); + int i; + + if (!rotate_name) { + if (output->initial_rotation) + return output->initial_rotation; + return RR_Rotate_0; + } + + for (i = 0; i < 4; i++) + if (xf86nameCompare (direction[i], rotate_name) == 0) + return 1 << i; + return RR_Rotate_0; +} + +xf86OutputPtr +xf86OutputCreate (ScrnInfoPtr scrn, + const xf86OutputFuncsRec *funcs, + const char *name) +{ + xf86OutputPtr output, *outputs; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int len; + Bool primary; + + if (name) + len = strlen (name) + 1; + else + len = 0; + + output = calloc(sizeof (xf86OutputRec) + len, 1); + if (!output) + return NULL; + output->scrn = scrn; + output->funcs = funcs; + if (name) + { + output->name = (char *) (output + 1); + strcpy (output->name, name); + } + output->subpixel_order = SubPixelUnknown; + /* + * Use the old per-screen monitor section for the first output + */ + output->use_screen_monitor = (xf86_config->num_output == 0); +#ifdef RANDR_12_INTERFACE + output->randr_output = NULL; +#endif + if (name) + { + xf86OutputSetMonitor (output); + if (xf86OutputIgnored (output)) + { + free(output); + return FALSE; + } + } + + + if (xf86_config->output) + outputs = realloc(xf86_config->output, + (xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); + else + outputs = malloc((xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); + if (!outputs) + { + free(output); + return NULL; + } + + xf86_config->output = outputs; + + if (xf86GetOptValBool (output->options, OPTION_PRIMARY, &primary) && primary) + { + memmove(xf86_config->output + 1, xf86_config->output, + xf86_config->num_output * sizeof (xf86OutputPtr)); + xf86_config->output[0] = output; + } + else + { + xf86_config->output[xf86_config->num_output] = output; + } + + xf86_config->num_output++; + + return output; +} + +Bool +xf86OutputRename (xf86OutputPtr output, const char *name) +{ + char *newname = strdup(name); + + if (!newname) + return FALSE; /* so sorry... */ + + if (output->name && output->name != (char *) (output + 1)) + free(output->name); + output->name = newname; + xf86OutputSetMonitor (output); + if (xf86OutputIgnored (output)) + return FALSE; + return TRUE; +} + +void +xf86OutputUseScreenMonitor (xf86OutputPtr output, Bool use_screen_monitor) +{ + if (use_screen_monitor != output->use_screen_monitor) + { + output->use_screen_monitor = use_screen_monitor; + xf86OutputSetMonitor (output); + } +} + +void +xf86OutputDestroy (xf86OutputPtr output) +{ + ScrnInfoPtr scrn = output->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + (*output->funcs->destroy) (output); + while (output->probed_modes) + xf86DeleteMode (&output->probed_modes, output->probed_modes); + for (o = 0; o < xf86_config->num_output; o++) + if (xf86_config->output[o] == output) + { + memmove (&xf86_config->output[o], + &xf86_config->output[o+1], + ((xf86_config->num_output - (o + 1)) * sizeof(void*))); + xf86_config->num_output--; + break; + } + if (output->name && output->name != (char *) (output + 1)) + free(output->name); + free(output); +} + +/* + * Called during CreateScreenResources to hook up RandR + */ +static Bool +xf86CrtcCreateScreenResources (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + screen->CreateScreenResources = config->CreateScreenResources; + + if (!(*screen->CreateScreenResources)(screen)) + return FALSE; + + if (!xf86RandR12CreateScreenResources (screen)) + return FALSE; + + return TRUE; +} + +/* + * Clean up config on server reset + */ +static Bool +xf86CrtcCloseScreen (int index, ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o, c; + + screen->CloseScreen = config->CloseScreen; + + xf86RotateCloseScreen (screen); + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->randr_output = NULL; + } + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->randr_crtc = NULL; + } + xf86RandR12CloseScreen (screen); + + return screen->CloseScreen (index, screen); +} + +/* + * Called at ScreenInit time to set up + */ +#ifdef RANDR_13_INTERFACE +int +#else +Bool +#endif +xf86CrtcScreenInit (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + /* Rotation */ + xf86DrvMsg(scrn->scrnIndex, X_INFO, "RandR 1.2 enabled, ignore the following RandR disabled message.\n"); + xf86DisableRandR(); /* Disable old RandR extension support */ + xf86RandR12Init (screen); + + /* support all rotations if every crtc has the shadow alloc funcs */ + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + if (!crtc->funcs->shadow_allocate || !crtc->funcs->shadow_create) + break; + } + if (c == config->num_crtc) + { + xf86RandR12SetRotations (screen, RR_Rotate_0 | RR_Rotate_90 | + RR_Rotate_180 | RR_Rotate_270 | + RR_Reflect_X | RR_Reflect_Y); + xf86RandR12SetTransformSupport (screen, TRUE); + } + else + { + xf86RandR12SetRotations (screen, RR_Rotate_0); + xf86RandR12SetTransformSupport (screen, FALSE); + } + + /* Wrap CreateScreenResources so we can initialize the RandR code */ + config->CreateScreenResources = screen->CreateScreenResources; + screen->CreateScreenResources = xf86CrtcCreateScreenResources; + + config->CloseScreen = screen->CloseScreen; + screen->CloseScreen = xf86CrtcCloseScreen; + +#ifdef XFreeXDGA + _xf86_di_dga_init_internal(screen); +#endif +#ifdef RANDR_13_INTERFACE + return RANDR_INTERFACE_VERSION; +#else + return TRUE; +#endif +} + +static DisplayModePtr +xf86DefaultMode (xf86OutputPtr output, int width, int height) +{ + DisplayModePtr target_mode = NULL; + DisplayModePtr mode; + int target_diff = 0; + int target_preferred = 0; + int mm_height; + + mm_height = output->mm_height; + if (!mm_height) + mm_height = (768 * 25.4) / DEFAULT_DPI; + /* + * Pick a mode closest to DEFAULT_DPI + */ + for (mode = output->probed_modes; mode; mode = mode->next) + { + int dpi; + int preferred = (((mode->type & M_T_PREFERRED) != 0) + + ((mode->type & M_T_USERPREF) != 0)); + int diff; + + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + /* yes, use VDisplay here, not xf86ModeHeight */ + dpi = (mode->VDisplay * 254) / (mm_height * 10); + diff = dpi - DEFAULT_DPI; + diff = diff < 0 ? -diff : diff; + if (target_mode == NULL || (preferred > target_preferred) || + (preferred == target_preferred && diff < target_diff)) + { + target_mode = mode; + target_diff = diff; + target_preferred = preferred; + } + } + return target_mode; +} + +static DisplayModePtr +xf86ClosestMode (xf86OutputPtr output, + DisplayModePtr match, Rotation match_rotation, + int width, int height) +{ + DisplayModePtr target_mode = NULL; + DisplayModePtr mode; + int target_diff = 0; + + /* + * Pick a mode closest to the specified mode + */ + for (mode = output->probed_modes; mode; mode = mode->next) + { + int dx, dy; + int diff; + + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + /* exact matches are preferred */ + if (output->initial_rotation == match_rotation && + xf86ModesEqual (mode, match)) + return mode; + + dx = xf86ModeWidth (match, match_rotation) - xf86ModeWidth (mode, output->initial_rotation); + dy = xf86ModeHeight (match, match_rotation) - xf86ModeHeight (mode, output->initial_rotation); + diff = dx * dx + dy * dy; + if (target_mode == NULL || diff < target_diff) + { + target_mode = mode; + target_diff = diff; + } + } + return target_mode; +} + +static DisplayModePtr +xf86OutputHasPreferredMode (xf86OutputPtr output, int width, int height) +{ + DisplayModePtr mode; + + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + if (mode->type & M_T_PREFERRED) + return mode; + } + return NULL; +} + +static DisplayModePtr +xf86OutputHasUserPreferredMode (xf86OutputPtr output) +{ + DisplayModePtr mode, first = output->probed_modes; + + for (mode = first; mode && mode->next != first; mode = mode->next) + if (mode->type & M_T_USERPREF) + return mode; + + return NULL; +} + +static int +xf86PickCrtcs (ScrnInfoPtr scrn, + xf86CrtcPtr *best_crtcs, + DisplayModePtr *modes, + int n, + int width, + int height) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int c, o; + xf86OutputPtr output; + xf86CrtcPtr crtc; + xf86CrtcPtr *crtcs; + xf86CrtcPtr best_crtc; + int best_score; + int score; + int my_score; + + if (n == config->num_output) + return 0; + output = config->output[n]; + + /* + * Compute score with this output disabled + */ + best_crtcs[n] = NULL; + best_crtc = NULL; + best_score = xf86PickCrtcs (scrn, best_crtcs, modes, n+1, width, height); + if (modes[n] == NULL) + return best_score; + + crtcs = malloc(config->num_output * sizeof (xf86CrtcPtr)); + if (!crtcs) + return best_score; + + my_score = 1; + /* Score outputs that are known to be connected higher */ + if (output->status == XF86OutputStatusConnected) + my_score++; + /* Score outputs with preferred modes higher */ + if (xf86OutputHasPreferredMode (output, width, height)) + my_score++; + /* + * Select a crtc for this output and + * then attempt to configure the remaining + * outputs + */ + for (c = 0; c < config->num_crtc; c++) + { + if ((output->possible_crtcs & (1 << c)) == 0) + continue; + + crtc = config->crtc[c]; + /* + * Check to see if some other output is + * using this crtc + */ + for (o = 0; o < n; o++) + if (best_crtcs[o] == crtc) + break; + if (o < n) + { + /* + * If the two outputs desire the same mode, + * see if they can be cloned + */ + if (xf86ModesEqual (modes[o], modes[n]) && + config->output[o]->initial_rotation == config->output[n]->initial_rotation && + config->output[o]->initial_x == config->output[n]->initial_x && + config->output[o]->initial_y == config->output[n]->initial_y) + { + if ((output->possible_clones & (1 << o)) == 0) + continue; /* nope, try next CRTC */ + } + else + continue; /* different modes, can't clone */ + } + crtcs[n] = crtc; + memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr)); + score = my_score + xf86PickCrtcs (scrn, crtcs, modes, n+1, width, height); + if (score > best_score) + { + best_crtc = crtc; + best_score = score; + memcpy (best_crtcs, crtcs, config->num_output * sizeof (xf86CrtcPtr)); + } + } + free(crtcs); + return best_score; +} + + +/* + * Compute the virtual size necessary to place all of the available + * crtcs in the specified configuration. + * + * canGrow indicates that the driver can make the screen larger than its initial + * configuration. If FALSE, this function will enlarge the screen to include + * the largest available mode. + */ + +static void +xf86DefaultScreenLimits (ScrnInfoPtr scrn, int *widthp, int *heightp, + Bool canGrow) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int width = 0, height = 0; + int o; + int c; + int s; + + for (c = 0; c < config->num_crtc; c++) + { + int crtc_width = 0, crtc_height = 0; + xf86CrtcPtr crtc = config->crtc[c]; + + if (crtc->enabled) + { + crtc_width = crtc->desiredX + xf86ModeWidth (&crtc->desiredMode, crtc->desiredRotation); + crtc_height = crtc->desiredY + xf86ModeHeight (&crtc->desiredMode, crtc->desiredRotation); + } + if (!canGrow) { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + for (s = 0; s < config->num_crtc; s++) + if (output->possible_crtcs & (1 << s)) + { + DisplayModePtr mode; + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (mode->HDisplay > crtc_width) + crtc_width = mode->HDisplay; + if (mode->VDisplay > crtc_width) + crtc_width = mode->VDisplay; + if (mode->VDisplay > crtc_height) + crtc_height = mode->VDisplay; + if (mode->HDisplay > crtc_height) + crtc_height = mode->HDisplay; + } + } + } + } + if (crtc_width > width) + width = crtc_width; + if (crtc_height > height) + height = crtc_height; + } + if (config->maxWidth && width > config->maxWidth) width = config->maxWidth; + if (config->maxHeight && height > config->maxHeight) height = config->maxHeight; + if (config->minWidth && width < config->minWidth) width = config->minWidth; + if (config->minHeight && height < config->minHeight) height = config->minHeight; + *widthp = width; + *heightp = height; +} + +#define POSITION_UNSET -100000 + +/* + * check if the user configured any outputs at all + * with either a position or a relative setting or a mode. + */ +static Bool +xf86UserConfiguredOutputs(ScrnInfoPtr scrn, DisplayModePtr *modes) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + Bool user_conf = FALSE; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + char *position; + char *relative_name; + OutputOpts relation; + int r; + static const OutputOpts relations[] = { + OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF + }; + + position = xf86GetOptValString (output->options, + OPTION_POSITION); + if (position) + user_conf = TRUE; + + relation = 0; + relative_name = NULL; + for (r = 0; r < 4; r++) + { + relation = relations[r]; + relative_name = xf86GetOptValString (output->options, + relation); + if (relative_name) + break; + } + if (relative_name) + user_conf = TRUE; + + modes[o] = xf86OutputHasUserPreferredMode(output); + if (modes[o]) + user_conf = TRUE; + } + + return user_conf; +} + +static Bool +xf86InitialOutputPositions (ScrnInfoPtr scrn, DisplayModePtr *modes) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + int min_x, min_y; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->initial_x = output->initial_y = POSITION_UNSET; + } + + /* + * Loop until all outputs are set + */ + for (;;) + { + Bool any_set = FALSE; + Bool keep_going = FALSE; + + for (o = 0; o < config->num_output; o++) + { + static const OutputOpts relations[] = { + OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF + }; + xf86OutputPtr output = config->output[o]; + xf86OutputPtr relative; + char *relative_name; + char *position; + OutputOpts relation; + int r; + + if (output->initial_x != POSITION_UNSET) + continue; + position = xf86GetOptValString (output->options, + OPTION_POSITION); + /* + * Absolute position wins + */ + if (position) + { + int x, y; + if (sscanf (position, "%d %d", &x, &y) == 2) + { + output->initial_x = x; + output->initial_y = y; + } + else + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Output %s position not of form \"x y\"\n", + output->name); + output->initial_x = output->initial_y = 0; + } + any_set = TRUE; + continue; + } + /* + * Next comes relative positions + */ + relation = 0; + relative_name = NULL; + for (r = 0; r < 4; r++) + { + relation = relations[r]; + relative_name = xf86GetOptValString (output->options, + relation); + if (relative_name) + break; + } + if (relative_name) + { + int or; + relative = NULL; + for (or = 0; or < config->num_output; or++) + { + xf86OutputPtr out_rel = config->output[or]; + XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor; + + if (rel_mon) + { + if (xf86nameCompare (rel_mon->mon_identifier, + relative_name) == 0) + { + relative = config->output[or]; + break; + } + } + if (strcmp (out_rel->name, relative_name) == 0) + { + relative = config->output[or]; + break; + } + } + if (!relative) + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Cannot position output %s relative to unknown output %s\n", + output->name, relative_name); + output->initial_x = 0; + output->initial_y = 0; + any_set = TRUE; + continue; + } + if (!modes[or]) + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Cannot position output %s relative to output %s without modes\n", + output->name, relative_name); + output->initial_x = 0; + output->initial_y = 0; + any_set = TRUE; + continue; + } + if (relative->initial_x == POSITION_UNSET) + { + keep_going = TRUE; + continue; + } + output->initial_x = relative->initial_x; + output->initial_y = relative->initial_y; + switch (relation) { + case OPTION_BELOW: + output->initial_y += xf86ModeHeight (modes[or], relative->initial_rotation); + break; + case OPTION_RIGHT_OF: + output->initial_x += xf86ModeWidth (modes[or], relative->initial_rotation); + break; + case OPTION_ABOVE: + if (modes[o]) + output->initial_y -= xf86ModeHeight (modes[o], output->initial_rotation); + break; + case OPTION_LEFT_OF: + if (modes[o]) + output->initial_x -= xf86ModeWidth (modes[o], output->initial_rotation); + break; + default: + break; + } + any_set = TRUE; + continue; + } + + /* Nothing set, just stick them at 0,0 */ + output->initial_x = 0; + output->initial_y = 0; + any_set = TRUE; + } + if (!keep_going) + break; + if (!any_set) + { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + if (output->initial_x == POSITION_UNSET) + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Output position loop. Moving %s to 0,0\n", + output->name); + output->initial_x = output->initial_y = 0; + break; + } + } + } + } + + /* + * normalize positions + */ + min_x = 1000000; + min_y = 1000000; + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (output->initial_x < min_x) + min_x = output->initial_x; + if (output->initial_y < min_y) + min_y = output->initial_y; + } + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->initial_x -= min_x; + output->initial_y -= min_y; + } + return TRUE; +} + +static void +xf86InitialPanning (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + char *panning = xf86GetOptValString (output->options, OPTION_PANNING); + int width, height, left, top; + int track_width, track_height, track_left, track_top; + int brdr[4]; + + memset (&output->initialTotalArea, 0, sizeof(BoxRec)); + memset (&output->initialTrackingArea, 0, sizeof(BoxRec)); + memset (output->initialBorder, 0, 4*sizeof(INT16)); + + if (! panning) + continue; + + switch (sscanf (panning, "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d", + &width, &height, &left, &top, + &track_width, &track_height, &track_left, &track_top, + &brdr[0], &brdr[1], &brdr[2], &brdr[3])) { + case 12: + output->initialBorder[0] = brdr[0]; + output->initialBorder[1] = brdr[1]; + output->initialBorder[2] = brdr[2]; + output->initialBorder[3] = brdr[3]; + /* fall through */ + case 8: + output->initialTrackingArea.x1 = track_left; + output->initialTrackingArea.y1 = track_top; + output->initialTrackingArea.x2 = track_left + track_width; + output->initialTrackingArea.y2 = track_top + track_height; + /* fall through */ + case 4: + output->initialTotalArea.x1 = left; + output->initialTotalArea.y1 = top; + /* fall through */ + case 2: + output->initialTotalArea.x2 = output->initialTotalArea.x1 + width; + output->initialTotalArea.y2 = output->initialTotalArea.y1 + height; + break; + default: + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Broken panning specification '%s' for output %s in config file\n", + panning, output->name); + } + } +} + +/** Return - 0 + if a should be earlier, same or later than b in list + */ +static int +xf86ModeCompare (DisplayModePtr a, DisplayModePtr b) +{ + int diff; + + diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0); + if (diff) + return diff; + diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay; + if (diff) + return diff; + diff = b->Clock - a->Clock; + return diff; +} + +/** + * Insertion sort input in-place and return the resulting head + */ +static DisplayModePtr +xf86SortModes (DisplayModePtr input) +{ + DisplayModePtr output = NULL, i, o, n, *op, prev; + + /* sort by preferred status and pixel area */ + while (input) + { + i = input; + input = input->next; + for (op = &output; (o = *op); op = &o->next) + if (xf86ModeCompare (o, i) > 0) + break; + i->next = *op; + *op = i; + } + /* prune identical modes */ + for (o = output; o && (n = o->next); o = n) + { + if (!strcmp (o->name, n->name) && xf86ModesEqual (o, n)) + { + o->next = n->next; + free(n->name); + free(n); + n = o; + } + } + /* hook up backward links */ + prev = NULL; + for (o = output; o; o = o->next) + { + o->prev = prev; + prev = o; + } + return output; +} + +static char * +preferredMode(ScrnInfoPtr pScrn, xf86OutputPtr output) +{ + char *preferred_mode = NULL; + + /* Check for a configured preference for a particular mode */ + preferred_mode = xf86GetOptValString (output->options, + OPTION_PREFERRED_MODE); + if (preferred_mode) + return preferred_mode; + + if (pScrn->display->modes && *pScrn->display->modes) + preferred_mode = *pScrn->display->modes; + + return preferred_mode; +} + +static void +GuessRangeFromModes(MonPtr mon, DisplayModePtr mode) +{ + if (!mon || !mode) + return; + + mon->nHsync = 1; + mon->hsync[0].lo = 1024.0; + mon->hsync[0].hi = 0.0; + + mon->nVrefresh = 1; + mon->vrefresh[0].lo = 1024.0; + mon->vrefresh[0].hi = 0.0; + + while (mode) { + if (!mode->HSync) + mode->HSync = ((float) mode->Clock ) / ((float) mode->HTotal); + + if (!mode->VRefresh) + mode->VRefresh = (1000.0 * ((float) mode->Clock)) / + ((float) (mode->HTotal * mode->VTotal)); + + if (mode->HSync < mon->hsync[0].lo) + mon->hsync[0].lo = mode->HSync; + + if (mode->HSync > mon->hsync[0].hi) + mon->hsync[0].hi = mode->HSync; + + if (mode->VRefresh < mon->vrefresh[0].lo) + mon->vrefresh[0].lo = mode->VRefresh; + + if (mode->VRefresh > mon->vrefresh[0].hi) + mon->vrefresh[0].hi = mode->VRefresh; + + mode = mode->next; + } + + /* stretch out the bottom to fit 640x480@60 */ + if (mon->hsync[0].lo > 31.0) + mon->hsync[0].lo = 31.0; + if (mon->vrefresh[0].lo > 58.0) + mon->vrefresh[0].lo = 58.0; +} + +enum det_monrec_source { + sync_config, sync_edid, sync_default +}; + +struct det_monrec_parameter { + MonRec *mon_rec; + int *max_clock; + Bool set_hsync; + Bool set_vrefresh; + enum det_monrec_source *sync_source; +}; + +static void handle_detailed_monrec(struct detailed_monitor_section *det_mon, + void *data) +{ + struct det_monrec_parameter *p; + p = (struct det_monrec_parameter *)data; + + if (det_mon->type == DS_RANGES) { + struct monitor_ranges *ranges = &det_mon->section.ranges; + if (p->set_hsync && ranges->max_h) { + p->mon_rec->hsync[p->mon_rec->nHsync].lo = ranges->min_h; + p->mon_rec->hsync[p->mon_rec->nHsync].hi = ranges->max_h; + p->mon_rec->nHsync++; + if (*p->sync_source == sync_default) + *p->sync_source = sync_edid; + } + if (p->set_vrefresh && ranges->max_v) { + p->mon_rec->vrefresh[p->mon_rec->nVrefresh].lo = ranges->min_v; + p->mon_rec->vrefresh[p->mon_rec->nVrefresh].hi = ranges->max_v; + p->mon_rec->nVrefresh++; + if (*p->sync_source == sync_default) + *p->sync_source = sync_edid; + } + if (ranges->max_clock * 1000 > *p->max_clock) + *p->max_clock = ranges->max_clock * 1000; + } +} + +void +xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + /* When canGrow was TRUE in the initial configuration we have to + * compare against the maximum values so that we don't drop modes. + * When canGrow was FALSE, the maximum values would have been clamped + * anyway. + */ + if (maxX == 0 || maxY == 0) { + maxX = config->maxWidth; + maxY = config->maxHeight; + } + + /* Probe the list of modes for each output. */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode; + DisplayModePtr config_modes = NULL, output_modes, default_modes = NULL; + char *preferred_mode; + xf86MonPtr edid_monitor; + XF86ConfMonitorPtr conf_monitor; + MonRec mon_rec; + int min_clock = 0; + int max_clock = 0; + double clock; + Bool add_default_modes = xf86ReturnOptValBool(output->options, OPTION_DEFAULT_MODES, TRUE); + Bool debug_modes = config->debug_modes || + xf86Initialising; + enum det_monrec_source sync_source = sync_default; + + while (output->probed_modes != NULL) + xf86DeleteMode(&output->probed_modes, output->probed_modes); + + /* + * Check connection status + */ + output->status = (*output->funcs->detect)(output); + + if (output->status == XF86OutputStatusDisconnected && + !xf86ReturnOptValBool(output->options, OPTION_ENABLE, FALSE)) + { + xf86OutputSetEDID (output, NULL); + continue; + } + + memset (&mon_rec, '\0', sizeof (mon_rec)); + + conf_monitor = output->conf_monitor; + + if (conf_monitor) + { + int i; + + for (i = 0; i < conf_monitor->mon_n_hsync; i++) + { + mon_rec.hsync[mon_rec.nHsync].lo = conf_monitor->mon_hsync[i].lo; + mon_rec.hsync[mon_rec.nHsync].hi = conf_monitor->mon_hsync[i].hi; + mon_rec.nHsync++; + sync_source = sync_config; + } + for (i = 0; i < conf_monitor->mon_n_vrefresh; i++) + { + mon_rec.vrefresh[mon_rec.nVrefresh].lo = conf_monitor->mon_vrefresh[i].lo; + mon_rec.vrefresh[mon_rec.nVrefresh].hi = conf_monitor->mon_vrefresh[i].hi; + mon_rec.nVrefresh++; + sync_source = sync_config; + } + config_modes = xf86GetMonitorModes (scrn, conf_monitor); + } + + output_modes = (*output->funcs->get_modes) (output); + + edid_monitor = output->MonInfo; + + if (edid_monitor) + { + struct det_monrec_parameter p; + struct disp_features *features = &edid_monitor->features; + + /* if display is not continuous-frequency, don't add default modes */ + if (!GTF_SUPPORTED(features->msc)) + add_default_modes = FALSE; + + p.mon_rec = &mon_rec; + p.max_clock = &max_clock; + p.set_hsync = mon_rec.nHsync == 0; + p.set_vrefresh = mon_rec.nVrefresh == 0; + p.sync_source = &sync_source; + + xf86ForEachDetailedBlock(edid_monitor, + handle_detailed_monrec, + &p); + } + + if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK, + OPTUNITS_KHZ, &clock)) + min_clock = (int) clock; + if (xf86GetOptValFreq (output->options, OPTION_MAX_CLOCK, + OPTUNITS_KHZ, &clock)) + max_clock = (int) clock; + + /* If we still don't have a sync range, guess wildly */ + if (!mon_rec.nHsync || !mon_rec.nVrefresh) + GuessRangeFromModes(&mon_rec, output_modes); + + /* + * These limits will end up setting a 1024x768@60Hz mode by default, + * which seems like a fairly good mode to use when nothing else is + * specified + */ + if (mon_rec.nHsync == 0) + { + mon_rec.hsync[0].lo = 31.0; + mon_rec.hsync[0].hi = 55.0; + mon_rec.nHsync = 1; + } + if (mon_rec.nVrefresh == 0) + { + mon_rec.vrefresh[0].lo = 58.0; + mon_rec.vrefresh[0].hi = 62.0; + mon_rec.nVrefresh = 1; + } + + if (add_default_modes) + default_modes = xf86GetDefaultModes (); + + /* + * If this is not an RB monitor, remove RB modes from the default + * pool. RB modes from the config or the monitor itself are fine. + */ + if (!mon_rec.reducedblanking) + xf86ValidateModesReducedBlanking (scrn, default_modes); + + if (sync_source == sync_config) + { + /* + * Check output and config modes against sync range from config file + */ + xf86ValidateModesSync (scrn, output_modes, &mon_rec); + xf86ValidateModesSync (scrn, config_modes, &mon_rec); + } + /* + * Check default modes against sync range + */ + xf86ValidateModesSync (scrn, default_modes, &mon_rec); + /* + * Check default modes against monitor max clock + */ + if (max_clock) { + xf86ValidateModesClocks(scrn, default_modes, + &min_clock, &max_clock, 1); + xf86ValidateModesClocks(scrn, output_modes, + &min_clock, &max_clock, 1); + } + + output->probed_modes = NULL; + output->probed_modes = xf86ModesAdd (output->probed_modes, config_modes); + output->probed_modes = xf86ModesAdd (output->probed_modes, output_modes); + output->probed_modes = xf86ModesAdd (output->probed_modes, default_modes); + + /* + * Check all modes against max size, interlace, and doublescan + */ + if (maxX && maxY) + xf86ValidateModesSize (scrn, output->probed_modes, + maxX, maxY, 0); + + { + int flags = (output->interlaceAllowed ? V_INTERLACE : 0) | + (output->doubleScanAllowed ? V_DBLSCAN : 0); + xf86ValidateModesFlags (scrn, output->probed_modes, flags); + } + + /* + * Check all modes against output + */ + for (mode = output->probed_modes; mode != NULL; mode = mode->next) + if (mode->status == MODE_OK) + mode->status = (*output->funcs->mode_valid)(output, mode); + + xf86PruneInvalidModes(scrn, &output->probed_modes, debug_modes); + + output->probed_modes = xf86SortModes (output->probed_modes); + + /* Check for a configured preference for a particular mode */ + preferred_mode = preferredMode(scrn, output); + + if (preferred_mode) + { + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (!strcmp (preferred_mode, mode->name)) + { + if (mode != output->probed_modes) + { + if (mode->prev) + mode->prev->next = mode->next; + if (mode->next) + mode->next->prev = mode->prev; + mode->next = output->probed_modes; + output->probed_modes->prev = mode; + mode->prev = NULL; + output->probed_modes = mode; + } + mode->type |= (M_T_PREFERRED|M_T_USERPREF); + break; + } + } + } + + output->initial_rotation = xf86OutputInitialRotation (output); + + if (debug_modes) { + if (output->probed_modes != NULL) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "Printing probed modes for output %s\n", + output->name); + } else { + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "No remaining probed modes for output %s\n", + output->name); + } + } + for (mode = output->probed_modes; mode != NULL; mode = mode->next) + { + /* The code to choose the best mode per pipe later on will require + * VRefresh to be set. + */ + mode->VRefresh = xf86ModeVRefresh(mode); + xf86SetModeCrtc(mode, INTERLACE_HALVE_V); + + if (debug_modes) + xf86PrintModeline(scrn->scrnIndex, mode); + } + } +} + + +/** + * Copy one of the output mode lists to the ScrnInfo record + */ + +/* XXX where does this function belong? Here? */ +void +xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr scrn, int *x, int *y); + +static DisplayModePtr +biggestMode(DisplayModePtr a, DisplayModePtr b) +{ + int A, B; + + if (!a) + return b; + if (!b) + return a; + + A = a->HDisplay * a->VDisplay; + B = b->HDisplay * b->VDisplay; + + if (A > B) + return a; + + return b; +} + +static xf86OutputPtr +SetCompatOutput(xf86CrtcConfigPtr config) +{ + xf86OutputPtr output = NULL, test = NULL; + DisplayModePtr maxmode = NULL, testmode, mode; + int o, compat = -1, count, mincount = 0; + + /* Look for one that's definitely connected */ + for (o = 0; o < config->num_output; o++) + { + test = config->output[o]; + if (!test->crtc) + continue; + if (test->status != XF86OutputStatusConnected) + continue; + if (!test->probed_modes) + continue; + + testmode = mode = test->probed_modes; + for (count = 0; mode; mode = mode->next, count++) + testmode = biggestMode(testmode, mode); + + if (!output) { + output = test; + compat = o; + maxmode = testmode; + mincount = count; + } else if (maxmode == biggestMode(maxmode, testmode)) { + output = test; + compat = o; + maxmode = testmode; + mincount = count; + } else if ((maxmode->HDisplay == testmode->HDisplay) && + (maxmode->VDisplay == testmode->VDisplay) && + count <= mincount) { + output = test; + compat = o; + maxmode = testmode; + mincount = count; + } + } + + /* If we didn't find one, take anything we can get */ + if (!output) + { + for (o = 0; o < config->num_output; o++) + { + test = config->output[o]; + if (!test->crtc) + continue; + if (!test->probed_modes) + continue; + + if (!output) { + output = test; + compat = o; + } else if (test->probed_modes->HDisplay < output->probed_modes->HDisplay) { + output = test; + compat = o; + } + } + } + + if (compat >= 0) { + config->compat_output = compat; + } else { + /* Don't change the compat output when no valid outputs found */ + output = config->output[config->compat_output]; + } + + return output; +} + +void +xf86SetScrnInfoModes (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + xf86OutputPtr output; + xf86CrtcPtr crtc; + DisplayModePtr last, mode = NULL; + + output = SetCompatOutput(config); + + if (!output) + return; /* punt */ + + crtc = output->crtc; + + /* Clear any existing modes from scrn->modes */ + while (scrn->modes != NULL) + xf86DeleteMode(&scrn->modes, scrn->modes); + + /* Set scrn->modes to the mode list for the 'compat' output */ + scrn->modes = xf86DuplicateModes(scrn, output->probed_modes); + + if (crtc) { + for (mode = scrn->modes; mode; mode = mode->next) + if (xf86ModesEqual (mode, &crtc->desiredMode)) + break; + } + + if (scrn->modes != NULL) { + /* For some reason, scrn->modes is circular, unlike the other mode + * lists. How great is that? + */ + for (last = scrn->modes; last && last->next; last = last->next) + ; + last->next = scrn->modes; + scrn->modes->prev = last; + if (mode) { + while (scrn->modes != mode) + scrn->modes = scrn->modes->next; + } + } + scrn->currentMode = scrn->modes; +#ifdef XFreeXDGA + if (scrn->pScreen) + _xf86_di_dga_reinit_internal(scrn->pScreen); +#endif +} + +static Bool +xf86CollectEnabledOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, + Bool *enabled) +{ + Bool any_enabled = FALSE; + int o; + + for (o = 0; o < config->num_output; o++) + any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE); + + if (!any_enabled) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "No outputs definitely connected, trying again...\n"); + + for (o = 0; o < config->num_output; o++) + any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], FALSE); + } + + return any_enabled; +} + +static Bool +nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index) +{ + int o = *index; + + for (o++; o < config->num_output; o++) { + if (enabled[o]) { + *index = o; + return TRUE; + } + } + + return FALSE; +} + +static Bool +aspectMatch(float a, float b) +{ + return fabs(1 - (a / b)) < 0.05; +} + +static DisplayModePtr +nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect) +{ + DisplayModePtr m = NULL; + + if (!o) + return NULL; + + if (!last) + m = o->probed_modes; + else + m = last->next; + + for (; m; m = m->next) + if (aspectMatch(aspect, (float)m->HDisplay / (float)m->VDisplay)) + return m; + + return NULL; +} + +static DisplayModePtr +bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect) +{ + int o = -1, p; + DisplayModePtr mode = NULL, test = NULL, match = NULL; + + if (!nextEnabledOutput(config, enabled, &o)) + return NULL; + while ((mode = nextAspectMode(config->output[o], mode, aspect))) { + test = mode; + for (p = o; nextEnabledOutput(config, enabled, &p); ) { + test = xf86OutputFindClosestMode(config->output[p], mode); + if (!test) + break; + if (test->HDisplay != mode->HDisplay || + test->VDisplay != mode->VDisplay) { + test = NULL; + break; + } + } + + /* if we didn't match it on all outputs, try the next one */ + if (!test) + continue; + + /* if it's bigger than the last one, save it */ + if (!match || (test->HDisplay > match->HDisplay)) + match = test; + } + + /* return the biggest one found */ + return match; +} + +static Bool +xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, + DisplayModePtr *modes, Bool *enabled, + int width, int height) +{ + int o, p; + int max_pref_width = 0, max_pref_height = 0; + DisplayModePtr *preferred, *preferred_match; + Bool ret = FALSE; + + preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); + preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); + + /* Check if the preferred mode is available on all outputs */ + for (p = -1; nextEnabledOutput(config, enabled, &p); ) { + Rotation r = config->output[p]->initial_rotation; + DisplayModePtr mode; + if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p], + width, height))) { + int pref_width = xf86ModeWidth(preferred[p], r); + int pref_height = xf86ModeHeight(preferred[p], r); + Bool all_match = TRUE; + + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + Bool match = FALSE; + xf86OutputPtr output = config->output[o]; + if (o == p) + continue; + + for (mode = output->probed_modes; mode; mode = mode->next) { + Rotation r = output->initial_rotation; + if (xf86ModeWidth(mode, r) == pref_width && + xf86ModeHeight(mode, r) == pref_height) { + preferred[o] = mode; + match = TRUE; + } + } + + all_match &= match; + } + + if (all_match && + (pref_width*pref_height > max_pref_width*max_pref_height)) { + for (o = -1; nextEnabledOutput(config, enabled, &o); ) + preferred_match[o] = preferred[o]; + max_pref_width = pref_width; + max_pref_height = pref_height; + ret = TRUE; + } + } + } + + /* + * If there's no preferred mode, but only one monitor, pick the + * biggest mode for its aspect ratio, assuming one exists. + */ + if (!ret) do { + int i = 0; + float aspect = 0.0; + + /* count the number of enabled outputs */ + for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ; + + if (i != 1) + break; + + p = -1; + nextEnabledOutput(config, enabled, &p); + if (config->output[p]->mm_height) + aspect = (float)config->output[p]->mm_width / + (float)config->output[p]->mm_height; + + if (aspect) + preferred_match[p] = bestModeForAspect(config, enabled, aspect); + + if (preferred_match[p]) + ret = TRUE; + + } while (0); + + if (ret) { + /* oh good, there is a match. stash the selected modes and return. */ + memcpy(modes, preferred_match, + config->num_output * sizeof(DisplayModePtr)); + } + + free(preferred); + free(preferred_match); + return ret; +} + +static Bool +xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, + DisplayModePtr *modes, Bool *enabled, + int width, int height) +{ + int o; + float aspect = 0.0, *aspects; + xf86OutputPtr output; + Bool ret = FALSE; + DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL; + + aspects = xnfcalloc(config->num_output, sizeof(float)); + + /* collect the aspect ratios */ + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + output = config->output[o]; + if (output->mm_height) + aspects[o] = (float)output->mm_width / (float)output->mm_height; + else + aspects[o] = 4.0 / 3.0; + } + + /* check that they're all the same */ + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + output = config->output[o]; + if (!aspect) { + aspect = aspects[o]; + } else if (!aspectMatch(aspect, aspects[o])) { + goto no_aspect_match; + } + } + + /* if they're all 4:3, just skip ahead and save effort */ + if (!aspectMatch(aspect, 4.0/3.0)) + aspect_guess = bestModeForAspect(config, enabled, aspect); + +no_aspect_match: + base_guess = bestModeForAspect(config, enabled, 4.0/3.0); + + guess = biggestMode(base_guess, aspect_guess); + + if (!guess) + goto out; + + /* found a mode that works everywhere, now apply it */ + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + modes[o] = xf86OutputFindClosestMode(config->output[o], guess); + } + ret = TRUE; + +out: + free(aspects); + return ret; +} + +static Bool +xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, + DisplayModePtr *modes, Bool *enabled, + int width, int height) +{ + DisplayModePtr target_mode = NULL; + Rotation target_rotation = RR_Rotate_0; + DisplayModePtr default_mode; + int default_preferred, target_preferred = 0, o; + + /* User preferred > preferred > other modes */ + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + default_mode = xf86DefaultMode (config->output[o], width, height); + if (!default_mode) + continue; + + default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) + + ((default_mode->type & M_T_USERPREF) != 0)); + + if (default_preferred > target_preferred || !target_mode) { + target_mode = default_mode; + target_preferred = default_preferred; + target_rotation = config->output[o]->initial_rotation; + config->compat_output = o; + } + } + + if (target_mode) + modes[config->compat_output] = target_mode; + + /* Fill in other output modes */ + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + if (!modes[o]) + modes[o] = xf86ClosestMode(config->output[o], target_mode, + target_rotation, width, height); + } + + return target_mode != NULL; +} + +static Bool +xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, + DisplayModePtr *modes, Bool *enabled, + int width, int height) +{ + int o; + + if (xf86UserConfiguredOutputs(scrn, modes)) + return xf86TargetFallback(scrn, config, modes, enabled, width, height); + + for (o = -1; nextEnabledOutput(config, enabled, &o); ) + if (xf86OutputHasUserPreferredMode(config->output[o])) + return + xf86TargetFallback(scrn, config, modes, enabled, width, height); + + return FALSE; +} + +static Bool +xf86CrtcSetInitialGamma(xf86CrtcPtr crtc, float gamma_red, float gamma_green, + float gamma_blue) +{ + int i, size = 256; + CARD16 *red, *green, *blue; + + red = malloc(3 * size * sizeof(CARD16)); + green = red + size; + blue = green + size; + + /* Only cause warning if user wanted gamma to be set. */ + if (!crtc->funcs->gamma_set && (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0)) { + free(red); + return FALSE; + } else if (!crtc->funcs->gamma_set) { + free(red); + return TRUE; + } + + /* At this early stage none of the randr-interface stuff is up. + * So take the default gamma size for lack of something better. + */ + for (i = 0; i < size; i++) { + if (gamma_red == 1.0) + red[i] = i << 8; + else + red[i] = (CARD16)(pow((double)i/(double)(size - 1), + 1. / (double)gamma_red) * (double)(size - 1) * 256); + + if (gamma_green == 1.0) + green[i] = i << 8; + else + green[i] = (CARD16)(pow((double)i/(double)(size - 1), + 1. / (double)gamma_green) * (double)(size - 1) * 256); + + if (gamma_blue == 1.0) + blue[i] = i << 8; + else + blue[i] = (CARD16)(pow((double)i/(double)(size - 1), + 1. / (double)gamma_blue) * (double)(size - 1) * 256); + } + + /* Default size is 256, so anything else is failure. */ + if (size != crtc->gamma_size) { + free(red); + return FALSE; + } + + crtc->gamma_size = size; + memcpy (crtc->gamma_red, red, crtc->gamma_size * sizeof (CARD16)); + memcpy (crtc->gamma_green, green, crtc->gamma_size * sizeof (CARD16)); + memcpy (crtc->gamma_blue, blue, crtc->gamma_size * sizeof (CARD16)); + + /* Do not set gamma now, delay until the crtc is activated. */ + + free(red); + + return TRUE; +} + +static Bool +xf86OutputSetInitialGamma(xf86OutputPtr output) +{ + XF86ConfMonitorPtr mon = output->conf_monitor; + float gamma_red = 1.0, gamma_green = 1.0, gamma_blue = 1.0; + + if (!mon) + return TRUE; + + if (!output->crtc) + return FALSE; + + /* Get configured values, where they exist. */ + if (mon->mon_gamma_red >= GAMMA_MIN && + mon->mon_gamma_red <= GAMMA_MAX) + gamma_red = mon->mon_gamma_red; + + if (mon->mon_gamma_green >= GAMMA_MIN && + mon->mon_gamma_green <= GAMMA_MAX) + gamma_green = mon->mon_gamma_green; + + if (mon->mon_gamma_blue >= GAMMA_MIN && + mon->mon_gamma_blue <= GAMMA_MAX) + gamma_blue = mon->mon_gamma_blue; + + /* This avoids setting gamma 1.0 in case another cloned output on this crtc has a specific gamma. */ + if (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0) { + xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Output %s wants gamma correction (%.1f, %.1f, %.1f)\n", output->name, gamma_red, gamma_green, gamma_blue); + return xf86CrtcSetInitialGamma(output->crtc, gamma_red, gamma_green, gamma_blue); + }else + return TRUE; +} + +/** + * Construct default screen configuration + * + * Given auto-detected (and, eventually, configured) values, + * construct a usable configuration for the system + * + * canGrow indicates that the driver can resize the screen to larger than its + * initially configured size via the config->funcs->resize hook. If TRUE, this + * function will set virtualX and virtualY to match the initial configuration + * and leave config->max{Width,Height} alone. If FALSE, it will bloat + * virtual[XY] to include the largest modes and set config->max{Width,Height} + * accordingly. + */ + +Bool +xf86InitialConfiguration (ScrnInfoPtr scrn, Bool canGrow) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o, c; + xf86CrtcPtr *crtcs; + DisplayModePtr *modes; + Bool *enabled; + int width, height; + int i = scrn->scrnIndex; + Bool have_outputs = TRUE; + Bool ret; + + /* Set up the device options */ + config->options = xnfalloc (sizeof (xf86DeviceOptions)); + memcpy (config->options, xf86DeviceOptions, sizeof (xf86DeviceOptions)); + xf86ProcessOptions (scrn->scrnIndex, + scrn->options, + config->options); + config->debug_modes = xf86ReturnOptValBool (config->options, + OPTION_MODEDEBUG, FALSE); + + if (scrn->display->virtualX) + width = scrn->display->virtualX; + else + width = config->maxWidth; + if (scrn->display->virtualY) + height = scrn->display->virtualY; + else + height = config->maxHeight; + + xf86ProbeOutputModes (scrn, width, height); + + crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr)); + modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr)); + enabled = xnfcalloc (config->num_output, sizeof (Bool)); + + ret = xf86CollectEnabledOutputs(scrn, config, enabled); + if (ret == FALSE && canGrow) { + xf86DrvMsg(i, X_WARNING, "Unable to find connected outputs - setting %dx%d initial framebuffer\n", + NO_OUTPUT_DEFAULT_WIDTH, NO_OUTPUT_DEFAULT_HEIGHT); + have_outputs = FALSE; + } else { + if (xf86TargetUserpref(scrn, config, modes, enabled, width, height)) + xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n"); + else if (xf86TargetPreferred(scrn, config, modes, enabled, width, height)) + xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n"); + else if (xf86TargetAspect(scrn, config, modes, enabled, width, height)) + xf86DrvMsg(i, X_INFO, "Using fuzzy aspect match for initial modes\n"); + else if (xf86TargetFallback(scrn, config, modes, enabled, width, height)) + xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n"); + else + xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n"); + } + + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + if (!modes[o]) + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Output %s enabled but has no modes\n", + config->output[o]->name); + else + xf86DrvMsg (scrn->scrnIndex, X_INFO, + "Output %s using initial mode %s\n", + config->output[o]->name, modes[o]->name); + } + + /* + * Set the position of each output + */ + if (!xf86InitialOutputPositions (scrn, modes)) + { + free(crtcs); + free(modes); + return FALSE; + } + + /* + * Set initial panning of each output + */ + xf86InitialPanning (scrn); + + /* + * Assign CRTCs to fit output configuration + */ + if (have_outputs && !xf86PickCrtcs (scrn, crtcs, modes, 0, width, height)) + { + free(crtcs); + free(modes); + return FALSE; + } + + /* XXX override xf86 common frame computation code */ + + scrn->display->frameX0 = 0; + scrn->display->frameY0 = 0; + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->enabled = FALSE; + memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode)); + /* Set default gamma for all crtc's. */ + /* This is done to avoid problems later on with cloned outputs. */ + xf86CrtcSetInitialGamma(crtc, 1.0, 1.0, 1.0); + } + + if (xf86_crtc_supports_gamma(scrn)) + xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using default gamma of (1.0, 1.0, 1.0) unless otherwise stated.\n"); + + /* + * Set initial configuration + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode = modes[o]; + xf86CrtcPtr crtc = crtcs[o]; + + if (mode && crtc) + { + crtc->desiredMode = *mode; + crtc->desiredRotation = output->initial_rotation; + crtc->desiredX = output->initial_x; + crtc->desiredY = output->initial_y; + crtc->desiredTransformPresent = FALSE; + crtc->enabled = TRUE; + memcpy (&crtc->panningTotalArea, &output->initialTotalArea, sizeof(BoxRec)); + memcpy (&crtc->panningTrackingArea, &output->initialTrackingArea, sizeof(BoxRec)); + memcpy (crtc->panningBorder, output->initialBorder, 4*sizeof(INT16)); + output->crtc = crtc; + if (!xf86OutputSetInitialGamma(output)) + xf86DrvMsg (scrn->scrnIndex, X_WARNING, "Initial gamma correction for output %s: failed.\n", output->name); + } else { + output->crtc = NULL; + } + } + + if (scrn->display->virtualX == 0) + { + /* + * Expand virtual size to cover the current config and potential mode + * switches, if the driver can't enlarge the screen later. + */ + xf86DefaultScreenLimits (scrn, &width, &height, canGrow); + + if (have_outputs == FALSE) { + if (width < NO_OUTPUT_DEFAULT_WIDTH && height < NO_OUTPUT_DEFAULT_HEIGHT) { + width = NO_OUTPUT_DEFAULT_WIDTH; + height = NO_OUTPUT_DEFAULT_HEIGHT; + } + } + + scrn->display->virtualX = width; + scrn->display->virtualY = height; + } + + if (width > scrn->virtualX) + scrn->virtualX = width; + if (height > scrn->virtualY) + scrn->virtualY = height; + + /* + * Make sure the configuration isn't too small. + */ + if (width < config->minWidth || height < config->minHeight) + return FALSE; + + /* + * Limit the crtc config to virtual[XY] if the driver can't grow the + * desktop. + */ + if (!canGrow) + { + xf86CrtcSetSizeRange (scrn, config->minWidth, config->minHeight, + width, height); + } + + if (have_outputs) { + /* Mirror output modes to scrn mode list */ + xf86SetScrnInfoModes (scrn); + } else { + /* Clear any existing modes from scrn->modes */ + while (scrn->modes != NULL) + xf86DeleteMode(&scrn->modes, scrn->modes); + scrn->modes = xf86ModesAdd(scrn->modes, + xf86CVTMode(width, height, 60, 0, 0)); + } + + + free(crtcs); + free(modes); + return TRUE; +} + +/* + * Check the CRTC we're going to map each output to vs. it's current + * CRTC. If they don't match, we have to disable the output and the CRTC + * since the driver will have to re-route things. + */ +static void +xf86PrepareOutputs (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + for (o = 0; o < config->num_output; o++) { + xf86OutputPtr output = config->output[o]; +#if RANDR_GET_CRTC_INTERFACE + /* Disable outputs that are unused or will be re-routed */ + if (!output->funcs->get_crtc || + output->crtc != (*output->funcs->get_crtc)(output) || + output->crtc == NULL) +#endif + (*output->funcs->dpms)(output, DPMSModeOff); + } +} + +static void +xf86PrepareCrtcs (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + for (c = 0; c < config->num_crtc; c++) { +#if RANDR_GET_CRTC_INTERFACE + xf86CrtcPtr crtc = config->crtc[c]; + xf86OutputPtr output = NULL; + uint32_t desired_outputs = 0, current_outputs = 0; + int o; + + for (o = 0; o < config->num_output; o++) { + output = config->output[o]; + if (output->crtc == crtc) + desired_outputs |= (1<funcs->get_crtc) { + desired_outputs = 0; + break; + } + if ((*output->funcs->get_crtc)(output) == crtc) + current_outputs |= (1<funcs->dpms)(crtc, DPMSModeOff); +#else + (*crtc->funcs->dpms)(crtc, DPMSModeOff); +#endif + } +} + +/* + * Using the desired mode information in each crtc, set + * modes (used in EnterVT functions, or at server startup) + */ + +Bool +xf86SetDesiredModes (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CrtcPtr crtc = config->crtc[0]; + int c; + + /* A driver with this hook will take care of this */ + if (!crtc->funcs->set_mode_major) { + xf86PrepareOutputs(scrn); + xf86PrepareCrtcs(scrn); + } + + for (c = 0; c < config->num_crtc; c++) + { + xf86OutputPtr output = NULL; + xf86CrtcSetRec set; + int o; + RRTransformPtr transform; + + crtc = config->crtc[c]; + + /* Skip disabled CRTCs */ + if (!crtc->enabled) + continue; + + if (xf86CompatOutput(scrn) && xf86CompatCrtc(scrn) == crtc) + output = xf86CompatOutput(scrn); + else + { + for (o = 0; o < config->num_output; o++) + if (config->output[o]->crtc == crtc) + { + output = config->output[o]; + break; + } + } + /* paranoia */ + if (!output) + continue; + + /* Mark that we'll need to re-set the mode for sure */ + memset(&crtc->mode, 0, sizeof(crtc->mode)); + if (!crtc->desiredMode.CrtcHDisplay) + { + DisplayModePtr mode = xf86OutputFindClosestMode (output, scrn->currentMode); + + if (!mode) + return FALSE; + crtc->desiredMode = *mode; + crtc->desiredRotation = RR_Rotate_0; + crtc->desiredTransformPresent = FALSE; + crtc->desiredX = 0; + crtc->desiredY = 0; + } + + if (crtc->desiredTransformPresent) + transform = &crtc->desiredTransform; + else + transform = NULL; + set.mode = &crtc->desiredMode; + set.rotation = crtc->desiredRotation; + set.transform = transform; + set.x = crtc->desiredX; + set.y = crtc->desiredY; + set.flags = (XF86CrtcSetMode | XF86CrtcSetOutput | + XF86CrtcSetOrigin | XF86CrtcSetTransform | + XF86CrtcSetRotation); + if (!xf86CrtcSet(crtc, &set)) + return FALSE; + } + + xf86DisableUnusedFunctions(scrn); + return TRUE; +} + +/** + * In the current world order, there are lists of modes per output, which may + * or may not include the mode that was asked to be set by XFree86's mode + * selection. Find the closest one, in the following preference order: + * + * - Equality + * - Closer in size to the requested mode, but no larger + * - Closer in refresh rate to the requested mode. + */ + +DisplayModePtr +xf86OutputFindClosestMode (xf86OutputPtr output, DisplayModePtr desired) +{ + DisplayModePtr best = NULL, scan = NULL; + + for (scan = output->probed_modes; scan != NULL; scan = scan->next) + { + /* If there's an exact match, we're done. */ + if (xf86ModesEqual(scan, desired)) { + best = desired; + break; + } + + /* Reject if it's larger than the desired mode. */ + if (scan->HDisplay > desired->HDisplay || + scan->VDisplay > desired->VDisplay) + { + continue; + } + + /* + * If we haven't picked a best mode yet, use the first + * one in the size range + */ + if (best == NULL) + { + best = scan; + continue; + } + + /* Find if it's closer to the right size than the current best + * option. + */ + if ((scan->HDisplay > best->HDisplay && + scan->VDisplay >= best->VDisplay) || + (scan->HDisplay >= best->HDisplay && + scan->VDisplay > best->VDisplay)) + { + best = scan; + continue; + } + + /* Find if it's still closer to the right refresh than the current + * best resolution. + */ + if (scan->HDisplay == best->HDisplay && + scan->VDisplay == best->VDisplay && + (fabs(scan->VRefresh - desired->VRefresh) < + fabs(best->VRefresh - desired->VRefresh))) { + best = scan; + } + } + return best; +} + +/** + * When setting a mode through XFree86-VidModeExtension or XFree86-DGA, + * take the specified mode and apply it to the crtc connected to the compat + * output. Then, find similar modes for the other outputs, as with the + * InitialConfiguration code above. The goal is to clone the desired + * mode across all outputs that are currently active. + */ + +Bool +xf86SetSingleMode (ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + Bool ok = TRUE; + xf86OutputPtr compat_output; + DisplayModePtr compat_mode = NULL; + int c; + + /* + * Let the compat output drive the final mode selection + */ + compat_output = xf86CompatOutput(pScrn); + if (compat_output) + compat_mode = xf86OutputFindClosestMode (compat_output, desired); + if (compat_mode) + desired = compat_mode; + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + DisplayModePtr crtc_mode = NULL; + int o; + xf86CrtcSetRec set; + + if (!crtc->enabled) + continue; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr output_mode; + + /* skip outputs not on this crtc */ + if (output->crtc != crtc) + continue; + + if (crtc_mode) + { + output_mode = xf86OutputFindClosestMode (output, crtc_mode); + if (output_mode != crtc_mode) + output->crtc = NULL; + } + else + crtc_mode = xf86OutputFindClosestMode (output, desired); + } + if (!crtc_mode) + { + crtc->enabled = FALSE; + continue; + } + set.mode = crtc_mode; + set.rotation = rotation; + set.transform = NULL; + set.x = 0; + set.y = 0; + set.flags = (XF86CrtcSetMode | XF86CrtcSetOutput | + XF86CrtcSetOrigin | XF86CrtcSetTransform | + XF86CrtcSetRotation); + if (!xf86CrtcSet (crtc, &set)) + ok = FALSE; + else + { + crtc->desiredMode = *crtc_mode; + crtc->desiredRotation = rotation; + crtc->desiredTransformPresent = FALSE; + crtc->desiredX = 0; + crtc->desiredY = 0; + } + } + xf86DisableUnusedFunctions(pScrn); +#ifdef RANDR_12_INTERFACE + xf86RandR12TellChanged (pScrn->pScreen); +#endif + return ok; +} + + +/** + * Set the DPMS power mode of all outputs and CRTCs. + * + * If the new mode is off, it will turn off outputs and then CRTCs. + * Otherwise, it will affect CRTCs before outputs. + */ +void +xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int i; + + if (!scrn->vtSema) + return; + + if (mode == DPMSModeOff) { + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + if (output->crtc != NULL) + (*output->funcs->dpms) (output, mode); + } + } + + for (i = 0; i < config->num_crtc; i++) { + xf86CrtcPtr crtc = config->crtc[i]; + if (crtc->enabled) + (*crtc->funcs->dpms) (crtc, mode); + } + + if (mode != DPMSModeOff) { + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + if (output->crtc != NULL) + (*output->funcs->dpms) (output, mode); + } + } +} + +/** + * Implement the screensaver by just calling down into the driver DPMS hooks. + * + * Even for monitors with no DPMS support, by the definition of our DPMS hooks, + * the outputs will still get disabled (blanked). + */ +Bool +xf86SaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (xf86IsUnblank(mode)) + xf86DPMSSet(pScrn, DPMSModeOn, 0); + else + xf86DPMSSet(pScrn, DPMSModeOff, 0); + + return TRUE; +} + +/** + * Disable all inactive crtcs and outputs + */ +void +xf86DisableUnusedFunctions(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int o, c; + + for (o = 0; o < xf86_config->num_output; o++) + { + xf86OutputPtr output = xf86_config->output[o]; + if (!output->crtc) + (*output->funcs->dpms)(output, DPMSModeOff); + } + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (!crtc->enabled) + { + crtc->funcs->dpms(crtc, DPMSModeOff); + memset(&crtc->mode, 0, sizeof(crtc->mode)); + xf86RotateDestroy(crtc); + crtc->active = FALSE; + } + } + if (pScrn->pScreen) + xf86_crtc_notify(pScrn->pScreen); + if (pScrn->ModeSet) + pScrn->ModeSet(pScrn); +} + +#ifdef RANDR_12_INTERFACE + +#define EDID_ATOM_NAME "EDID" + +/** + * Set the RandR EDID property + */ +static void +xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len) +{ + Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE); + + /* This may get called before the RandR resources have been created */ + if (output->randr_output == NULL) + return; + + if (data_len != 0) { + RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, + PropModeReplace, data_len, data, FALSE, TRUE); + } else { + RRDeleteOutputProperty(output->randr_output, edid_atom); + } +} + +#endif + +/* Pull out a phyiscal size from a detailed timing if available. */ +struct det_phySize_parameter { + xf86OutputPtr output; + ddc_quirk_t quirks; + Bool ret; +}; + +static void handle_detailed_physical_size(struct detailed_monitor_section + *det_mon, void *data) +{ + struct det_phySize_parameter *p; + p = (struct det_phySize_parameter *)data; + + if (p->ret == TRUE ) + return ; + + xf86DetTimingApplyQuirks(det_mon, p->quirks, + p->output->MonInfo->features.hsize, + p->output->MonInfo->features.vsize); + if (det_mon->type == DT && + det_mon->section.d_timings.h_size != 0 && + det_mon->section.d_timings.v_size != 0) { + + p->output->mm_width = det_mon->section.d_timings.h_size; + p->output->mm_height = det_mon->section.d_timings.v_size; + p->ret = TRUE; + } +} + +/** + * Set the EDID information for the specified output + */ +void +xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon) +{ + ScrnInfoPtr scrn = output->scrn; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + Bool debug_modes = config->debug_modes || xf86Initialising; +#ifdef RANDR_12_INTERFACE + int size; +#endif + + free(output->MonInfo); + + output->MonInfo = edid_mon; + output->mm_width = 0; + output->mm_height = 0; + + if (debug_modes) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n", + output->name); + xf86PrintEDID(edid_mon); + } + + /* Set the DDC properties for the 'compat' output */ + if (output == xf86CompatOutput(scrn)) + xf86SetDDCproperties(scrn, edid_mon); + +#ifdef RANDR_12_INTERFACE + /* Set the RandR output properties */ + size = 0; + if (edid_mon) + { + if (edid_mon->ver.version == 1) { + size = 128; + if (edid_mon->flags & EDID_COMPLETE_RAWDATA) + size += edid_mon->no_sections * 128; + } else if (edid_mon->ver.version == 2) + size = 256; + } + xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size); +#endif + + if (edid_mon) { + + struct det_phySize_parameter p; + p.output = output; + p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex,edid_mon, FALSE); + p.ret = FALSE; + xf86ForEachDetailedBlock(edid_mon, + handle_detailed_physical_size, &p); + + /* if no mm size is available from a detailed timing, check the max size field */ + if ((!output->mm_width || !output->mm_height) && + (edid_mon->features.hsize && edid_mon->features.vsize)) + { + output->mm_width = edid_mon->features.hsize * 10; + output->mm_height = edid_mon->features.vsize * 10; + } + } +} + +/** + * Return the list of modes supported by the EDID information + * stored in 'output' + */ +DisplayModePtr +xf86OutputGetEDIDModes (xf86OutputPtr output) +{ + ScrnInfoPtr scrn = output->scrn; + xf86MonPtr edid_mon = output->MonInfo; + + if (!edid_mon) + return NULL; + return xf86DDCGetModes(scrn->scrnIndex, edid_mon); +} + +/* maybe we should care about DDC1? meh. */ +xf86MonPtr +xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus) +{ + ScrnInfoPtr scrn = output->scrn; + xf86MonPtr mon; + + mon = xf86DoEEDID(scrn->scrnIndex, pDDCBus, TRUE); + if (mon) + xf86DDCApplyQuirks(scrn->scrnIndex, mon); + + return mon; +} + +static char *_xf86ConnectorNames[] = { + "None", "VGA", "DVI-I", "DVI-D", + "DVI-A", "Composite", "S-Video", + "Component", "LFP", "Proprietary", + "HDMI", "DisplayPort", + }; +char * +xf86ConnectorGetName(xf86ConnectorType connector) +{ + return _xf86ConnectorNames[connector]; +} + +static void +x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) +{ + dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; + dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; + dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; + dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; + + if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) + dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; +} + +static void +x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) +{ + if (crtc->enabled) { + crtc_box->x1 = crtc->x; + crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); + crtc_box->y1 = crtc->y; + crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); + } else + crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; +} + +static int +xf86_crtc_box_area(BoxPtr box) +{ + return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); +} + +/* + * Return the crtc covering 'box'. If two crtcs cover a portion of + * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc + * with greater coverage + */ + +static xf86CrtcPtr +xf86_covering_crtc(ScrnInfoPtr pScrn, + BoxPtr box, + xf86CrtcPtr desired, + BoxPtr crtc_box_ret) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc, best_crtc; + int coverage, best_coverage; + int c; + BoxRec crtc_box, cover_box; + + best_crtc = NULL; + best_coverage = 0; + crtc_box_ret->x1 = 0; + crtc_box_ret->x2 = 0; + crtc_box_ret->y1 = 0; + crtc_box_ret->y2 = 0; + for (c = 0; c < xf86_config->num_crtc; c++) { + crtc = xf86_config->crtc[c]; + x86_crtc_box(crtc, &crtc_box); + x86_crtc_box_intersect(&cover_box, &crtc_box, box); + coverage = xf86_crtc_box_area(&cover_box); + if (coverage && crtc == desired) { + *crtc_box_ret = crtc_box; + return crtc; + } else if (coverage > best_coverage) { + *crtc_box_ret = crtc_box; + best_crtc = crtc; + best_coverage = coverage; + } + } + return best_crtc; +} + +/* + * For overlay video, compute the relevant CRTC and + * clip video to that. + * + * returning FALSE means there was a memory failure of some kind, + * not that the video shouldn't be displayed + */ + +Bool +xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, + xf86CrtcPtr *crtc_ret, + xf86CrtcPtr desired_crtc, + BoxPtr dst, + INT32 *xa, + INT32 *xb, + INT32 *ya, + INT32 *yb, + RegionPtr reg, + INT32 width, + INT32 height) +{ + Bool ret; + RegionRec crtc_region_local; + RegionPtr crtc_region = reg; + + if (crtc_ret) { + BoxRec crtc_box; + xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst, + desired_crtc, + &crtc_box); + + if (crtc) { + RegionInit(&crtc_region_local, &crtc_box, 1); + crtc_region = &crtc_region_local; + RegionIntersect(crtc_region, crtc_region, reg); + } + *crtc_ret = crtc; + } + + ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, + crtc_region, width, height); + + if (crtc_region != reg) + RegionUninit(&crtc_region_local); + + return ret; +} + +xf86_crtc_notify_proc_ptr +xf86_wrap_crtc_notify (ScreenPtr screen, xf86_crtc_notify_proc_ptr new) +{ + if (xf86CrtcConfigPrivateIndex != -1) + { + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + xf86_crtc_notify_proc_ptr old; + + old = config->xf86_crtc_notify; + config->xf86_crtc_notify = new; + return old; + } + return NULL; +} + +void +xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old) +{ + if (xf86CrtcConfigPrivateIndex != -1) + { + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + config->xf86_crtc_notify = old; + } +} + +void +xf86_crtc_notify(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + if (config->xf86_crtc_notify) + config->xf86_crtc_notify(screen); +} + +Bool +xf86_crtc_supports_gamma(ScrnInfoPtr pScrn) +{ + if (xf86CrtcConfigPrivateIndex != -1) { + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc; + + /* for multiple drivers loaded we need this */ + if (!xf86_config) + return FALSE; + if (xf86_config->num_crtc == 0) + return FALSE; + crtc = xf86_config->crtc[0]; + + return crtc->funcs->gamma_set != NULL; + } + + return FALSE; +} -- cgit v1.2.3