From 78af703cb019a60cc93843efcd4889ccb15abd13 Mon Sep 17 00:00:00 2001 From: Kaleb Keithley Date: Fri, 14 Nov 2003 16:48:55 +0000 Subject: Initial revision --- src/smi_driver.c | 3294 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3294 insertions(+) create mode 100644 src/smi_driver.c (limited to 'src/smi_driver.c') diff --git a/src/smi_driver.c b/src/smi_driver.c new file mode 100644 index 0000000..ffd946e --- /dev/null +++ b/src/smi_driver.c @@ -0,0 +1,3294 @@ +/* Header: //Mercury/Projects/archives/XFree86/4.0/smi_driver.c-arc 1.42 03 Jan 2001 13:52:16 Frido $ */ + +/* +Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. +Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. + +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, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT 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 names of The XFree86 Project and +Silicon Motion 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 XFree86 Project or Silicon Motion. +*/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_driver.c,v 1.28.2.1 2003/05/09 02:22:00 dawes Exp $ */ + +#include "xf86Resources.h" +#include "xf86RAC.h" +#include "xf86DDC.h" +#include "xf86int10.h" +#include "vbe.h" +#include "shadowfb.h" + +#include "smi.h" + +#include "globals.h" +#define DPMS_SERVER +#include "extensions/dpms.h" + +/* + * Internals + */ +static void SMI_EnableMmio(ScrnInfoPtr pScrn); +static void SMI_DisableMmio(ScrnInfoPtr pScrn); + +/* + * Forward definitions for the functions that make up the driver. + */ + +static const OptionInfoRec * SMI_AvailableOptions(int chipid, int busid); +static void SMI_Identify(int flags); +static Bool SMI_Probe(DriverPtr drv, int flags); +static Bool SMI_PreInit(ScrnInfoPtr pScrn, int flags); +static Bool SMI_EnterVT(int scrnIndex, int flags); +static void SMI_LeaveVT(int scrnIndex, int flags); +static void SMI_Save (ScrnInfoPtr pScrn); +static void SMI_WriteMode (ScrnInfoPtr pScrn, vgaRegPtr, SMIRegPtr); +static Bool SMI_ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, + char **argv); +static int SMI_InternalScreenInit(int scrnIndex, ScreenPtr pScreen); +static void SMI_PrintRegs(ScrnInfoPtr); +static ModeStatus SMI_ValidMode(int scrnIndex, DisplayModePtr mode, + Bool verbose, int flags); +static void SMI_DisableVideo(ScrnInfoPtr pScrn); +static void SMI_EnableVideo(ScrnInfoPtr pScrn); +static Bool SMI_MapMem(ScrnInfoPtr pScrn); +static void SMI_UnmapMem(ScrnInfoPtr pScrn); +static Bool SMI_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode); +static Bool SMI_CloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool SMI_SaveScreen(ScreenPtr pScreen, int mode); +static void SMI_LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies, + LOCO *colors, VisualPtr pVisual); +static void SMI_DisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagementMode, int flags); +static Bool SMI_ddc1(int scrnIndex); +static unsigned int SMI_ddc1Read(ScrnInfoPtr pScrn); +static void SMI_FreeScreen(int ScrnIndex, int flags); +static void SMI_ProbeDDC(ScrnInfoPtr pScrn, int index); + + +#define SILICONMOTION_NAME "Silicon Motion" +#define SILICONMOTION_DRIVER_NAME "siliconmotion" +#define SILICONMOTION_VERSION_NAME "1.3.1" +#define SILICONMOTION_VERSION_MAJOR 1 +#define SILICONMOTION_VERSION_MINOR 3 +#define SILICONMOTION_PATCHLEVEL 1 +#define SILICONMOTION_DRIVER_VERSION ((SILICONMOTION_VERSION_MAJOR << 24) | \ + (SILICONMOTION_VERSION_MINOR << 16) | \ + (SILICONMOTION_PATCHLEVEL)) + +/* + * This contains the functions needed by the server after loading the + * driver module. It must be supplied, and gets added the driver list by + * the Module Setup funtion in the dynamic case. In the static case a + * reference to this is compiled in, and this requires that the name of + * this DriverRec be an upper-case version of the driver name. + */ + +DriverRec SILICONMOTION = +{ + SILICONMOTION_DRIVER_VERSION, + SILICONMOTION_DRIVER_NAME, + SMI_Identify, + SMI_Probe, + SMI_AvailableOptions, + NULL, + 0 +}; + +/* Supported chipsets */ +static SymTabRec SMIChipsets[] = +{ + { PCI_CHIP_SMI910, "Lynx" }, + { PCI_CHIP_SMI810, "LynxE" }, + { PCI_CHIP_SMI820, "Lynx3D" }, + { PCI_CHIP_SMI710, "LynxEM" }, + { PCI_CHIP_SMI712, "LynxEM+" }, + { PCI_CHIP_SMI720, "Lynx3DM" }, + { -1, NULL } +}; + +static PciChipsets SMIPciChipsets[] = +{ + /* numChipset, PciID, Resource */ + { PCI_CHIP_SMI910, PCI_CHIP_SMI910, RES_SHARED_VGA }, + { PCI_CHIP_SMI810, PCI_CHIP_SMI810, RES_SHARED_VGA }, + { PCI_CHIP_SMI820, PCI_CHIP_SMI820, RES_SHARED_VGA }, + { PCI_CHIP_SMI710, PCI_CHIP_SMI710, RES_SHARED_VGA }, + { PCI_CHIP_SMI712, PCI_CHIP_SMI712, RES_SHARED_VGA }, + { PCI_CHIP_SMI720, PCI_CHIP_SMI720, RES_SHARED_VGA }, + { -1, -1, RES_UNDEFINED } +}; + +typedef enum +{ + OPTION_PCI_BURST, + OPTION_FIFO_CONSERV, + OPTION_FIFO_MODERATE, + OPTION_FIFO_AGGRESSIVE, + OPTION_PCI_RETRY, + OPTION_NOACCEL, + OPTION_MCLK, + OPTION_SHOWCACHE, + OPTION_SWCURSOR, + OPTION_HWCURSOR, + OPTION_SHADOW_FB, + OPTION_ROTATE, +#ifdef XvExtension + OPTION_VIDEOKEY, + OPTION_BYTESWAP, + /* CZ 26.10.2001: interlaced video */ + OPTION_INTERLACED, + /* end CZ */ +#endif + OPTION_USEBIOS, + OPTION_ZOOMONLCD, + NUMBER_OF_OPTIONS + +} SMIOpts; + +static const OptionInfoRec SMIOptions[] = +{ + { OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_FIFO_CONSERV, "fifo_conservative", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_FIFO_MODERATE, "fifo_moderate", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_FIFO_AGGRESSIVE, "fifo_aggressive", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_PCI_RETRY, "pci_retry", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_MCLK, "set_mclk", OPTV_FREQ, {0}, FALSE }, + { OPTION_SHOWCACHE, "show_cache", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_HWCURSOR, "HWCursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SWCURSOR, "SWCursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE }, +#ifdef XvExtension + { OPTION_VIDEOKEY, "VideoKey", OPTV_INTEGER, {0}, FALSE }, + { OPTION_BYTESWAP, "ByteSwap", OPTV_BOOLEAN, {0}, FALSE }, + /* CZ 26.10.2001: interlaced video */ + { OPTION_INTERLACED, "Interlaced", OPTV_BOOLEAN, {0}, FALSE }, + /* end CZ */ +#endif + { OPTION_USEBIOS, "UseBIOS", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_ZOOMONLCD, "ZoomOnLCD", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +/* + * Lists of symbols that may/may not be required by this driver. + * This allows the loader to know which ones to issue warnings for. + * + * Note that vgahwSymbols and xaaSymbols are referenced outside the + * XFree86LOADER define in later code, so are defined outside of that + * define here also. + */ + +static const char *vgahwSymbols[] = +{ + "vgaHWCopyReg", + "vgaHWGetHWRec", + "vgaHWGetIOBase", + "vgaHWGetIndex", + "vgaHWInit", + "vgaHWLock", + "vgaHWMapMem", + "vgaHWProtect", + "vgaHWRestore", + "vgaHWSave", + "vgaHWSaveScreen", + "vgaHWSetMmioFuncs", + "vgaHWSetStdFuncs", + "vgaHWUnmapMem", + "vgaHWddc1SetSpeed", + NULL +}; + +static const char *xaaSymbols[] = +{ + "XAACopyROP", + "XAACreateInfoRec", + "XAADestroyInfoRec", + "XAAFallbackOps", + "XAAFillSolidRects", + "XAAInit", + "XAAPatternROP", + "XAAScreenIndex", + NULL +}; + +static const char *ramdacSymbols[] = +{ + "xf86CreateCursorInfoRec", + "xf86DestroyCursorInfoRec", + "xf86InitCursor", + NULL +}; + +static const char *ddcSymbols[] = +{ + "xf86PrintEDID", + "xf86DoEDID_DDC1", + "xf86DoEDID_DDC2", + "xf86SetDDCproperties", + NULL +}; + +static const char *i2cSymbols[] = +{ + "xf86CreateI2CBusRec", + "xf86CreateI2CDevRec", + "xf86DestroyI2CBusRec", + "xf86DestroyI2CDevRec", + "xf86I2CBusInit", + "xf86I2CDevInit", + "xf86I2CReadBytes", + "xf86I2CWriteByte", + NULL +}; + +static const char *shadowSymbols[] = +{ + "ShadowFBInit", + NULL +}; + +static const char *int10Symbols[] = +{ + "xf86ExecX86int10", + "xf86FreeInt10", + "xf86InitInt10", + NULL +}; + +static const char *vbeSymbols[] = +{ + "VBEInit", + "vbeDoEDID", + "vbeFree", + NULL +}; + +static const char *fbSymbols[] = +{ +#ifdef USE_FB + "fbPictureInit", + "fbScreenInit", +#else + "cfbScreenInit", + "cfb16ScreenInit", + "cfb24ScreenInit", + "cfb32ScreenInit", + "cfb16BresS", + "cfb24BresS", +#endif + NULL +}; + +#ifdef XFree86LOADER + +static MODULESETUPPROTO(siliconmotionSetup); + +static XF86ModuleVersionInfo SMIVersRec = +{ + "siliconmotion", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + SILICONMOTION_VERSION_MAJOR, + SILICONMOTION_VERSION_MINOR, + SILICONMOTION_PATCHLEVEL, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0, 0, 0, 0} +}; + +/* + * This is the module init data for XFree86 modules. + * + * Its name has to be the driver name followed by ModuleData. + */ +XF86ModuleData siliconmotionModuleData = +{ + &SMIVersRec, + siliconmotionSetup, + NULL +}; + +static pointer +siliconmotionSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + if (!setupDone) + { + setupDone = TRUE; + xf86AddDriver(&SILICONMOTION, module, 0); + + /* + * Modules that this driver always requires can be loaded here + * by calling LoadSubModule(). + */ + + /* + * Tell the loader about symbols from other modules that this module + * might refer to. + */ + LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols, ramdacSymbols, + ddcSymbols, i2cSymbols, int10Symbols, vbeSymbols, + shadowSymbols, NULL); + + /* + * The return value must be non-NULL on success even though there + * is no TearDownProc. + */ + return (pointer) 1; + } + else + { + if (errmaj) + { + *errmaj = LDR_ONCEONLY; + } + return(NULL); + } +} + +#endif /* XFree86LOADER */ + +static Bool +SMI_GetRec(ScrnInfoPtr pScrn) +{ + ENTER_PROC("SMI_GetRec"); + + /* + * Allocate an 'Chip'Rec, and hook it into pScrn->driverPrivate. + * pScrn->driverPrivate is initialised to NULL, so we can check if + * the allocation has already been done. + */ + if (pScrn->driverPrivate == NULL) + { + pScrn->driverPrivate = xnfcalloc(sizeof(SMIRec), 1); + } + + LEAVE_PROC("SMI_GetRec"); + return(TRUE); +} + +static void +SMI_FreeRec(ScrnInfoPtr pScrn) +{ + ENTER_PROC("SMI_FreeRec"); + + if (pScrn->driverPrivate != NULL) + { + xfree(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; + } + + LEAVE_PROC("SMI_FreeRec"); +} + +static const OptionInfoRec * +SMI_AvailableOptions(int chipid, int busid) +{ + ENTER_PROC("SMI_AvailableOptions"); + LEAVE_PROC("SMI_AvailableOptions"); + return(SMIOptions); +} + +static void +SMI_Identify(int flags) +{ + ENTER_PROC("SMI_Identify"); + + xf86PrintChipsets(SILICONMOTION_NAME, "driver (version " + SILICONMOTION_VERSION_NAME ") for Silicon Motion Lynx chipsets", + SMIChipsets); + + LEAVE_PROC("SMI_Identify"); +} + +static Bool +SMI_Probe(DriverPtr drv, int flags) +{ + int i; + GDevPtr *devSections; + int *usedChips; + int numDevSections; + int numUsed; + Bool foundScreen = FALSE; + + ENTER_PROC("SMI_Probe"); + + numDevSections = xf86MatchDevice(SILICONMOTION_DRIVER_NAME, &devSections); + if (numDevSections <= 0) + { + /* There's no matching device section in the config file, so quit now. + */ + LEAVE_PROC("SMI_Probe"); + return(FALSE); + } + + if (xf86GetPciVideoInfo() == NULL) + { + LEAVE_PROC("SMI_Probe"); + return(FALSE); + } + + numUsed = xf86MatchPciInstances(SILICONMOTION_NAME, PCI_SMI_VENDOR_ID, + SMIChipsets, SMIPciChipsets, devSections, + numDevSections, drv, &usedChips); + + /* Free it since we don't need that list after this */ + xfree(devSections); + if (numUsed <= 0) + { + LEAVE_PROC("SMI_Probe"); + return(FALSE); + } + + if (flags & PROBE_DETECT) + { + foundScreen = TRUE; + } + else + { + for (i = 0; i < numUsed; i++) + { + /* Allocate a ScrnInfoRec and claim the slot */ + ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0); + + /* Fill in what we can of the ScrnInfoRec */ + pScrn->driverVersion = SILICONMOTION_DRIVER_VERSION; + pScrn->driverName = SILICONMOTION_DRIVER_NAME; + pScrn->name = SILICONMOTION_NAME; + pScrn->Probe = SMI_Probe; + pScrn->PreInit = SMI_PreInit; + pScrn->ScreenInit = SMI_ScreenInit; + pScrn->SwitchMode = SMI_SwitchMode; + pScrn->AdjustFrame = SMI_AdjustFrame; + pScrn->EnterVT = SMI_EnterVT; + pScrn->LeaveVT = SMI_LeaveVT; + pScrn->FreeScreen = SMI_FreeScreen; + pScrn->ValidMode = SMI_ValidMode; + foundScreen = TRUE; + + xf86ConfigActivePciEntity(pScrn, usedChips[i], SMIPciChipsets, NULL, + NULL, NULL, NULL, NULL); + } + } + xfree(usedChips); + + LEAVE_PROC("SMI_Probe"); + return(foundScreen); +} + +static Bool +SMI_PreInit(ScrnInfoPtr pScrn, int flags) +{ + EntityInfoPtr pEnt; + SMIPtr pSmi; + MessageType from; + int i; + double real; + ClockRangePtr clockRanges; +#ifndef USE_FB + char *mod = NULL; + const char *reqSym = NULL; +#endif + char *s; + unsigned char config, m, n, shift; + int mclk; + vgaHWPtr hwp; + int vgaCRIndex, vgaCRReg, vgaIOBase; + vbeInfoPtr pVbe = NULL; + + ENTER_PROC("SMI_PreInit"); + + if (flags & PROBE_DETECT) + { + SMI_ProbeDDC(pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index); + LEAVE_PROC("SMI_PreInit"); + return(TRUE); + } + + /* Ignoring the Type list for now. It might be needed when multiple cards + * are supported. + */ + if (pScrn->numEntities > 1) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + /* The vgahw module should be loaded here when needed */ + if (!xf86LoadSubModule(pScrn, "vgahw")) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + xf86LoaderReqSymLists(vgahwSymbols, NULL); + + /* + * Allocate a vgaHWRec + */ + if (!vgaHWGetHWRec(pScrn)) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + /* Allocate the SMIRec driverPrivate */ + if (!SMI_GetRec(pScrn)) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + pSmi = SMIPTR(pScrn); + + /* Set pScrn->monitor */ + pScrn->monitor = pScrn->confScreen->monitor; + + /* + * The first thing we should figure out is the depth, bpp, etc. Our + * default depth is 8, so pass it to the helper function. We support + * only 24bpp layouts, so indicate that. + */ + if (!xf86SetDepthBpp(pScrn, 8, 8, 8, Support24bppFb)) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + /* Check that the returned depth is one we support */ + switch (pScrn->depth) + { + case 8: + case 16: + case 24: + /* OK */ + break; + + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported by this driver\n", + pScrn->depth); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + xf86PrintDepthBpp(pScrn); + + /* + * This must happen after pScrn->display has been set because + * xf86SetWeight references it. + */ + if (pScrn->depth > 8) + { + /* The defaults are OK for us */ + rgb zeros = {0, 0, 0}; + + if (!xf86SetWeight(pScrn, zeros, zeros)) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + } + + if (!xf86SetDefaultVisual(pScrn, -1)) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + /* We don't currently support DirectColor at > 8bpp */ + if ((pScrn->depth > 8) && (pScrn->defaultVisual != TrueColor)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual (%s) " + "is not supported at depth %d\n", + xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + /* We use a programmable clock */ + pScrn->progClock = TRUE; + + /* Collect all of the relevant option flags (fill in pScrn->options) */ + xf86CollectOptions(pScrn, NULL); + + /* Set the bits per RGB for 8bpp mode */ + if (pScrn->depth == 8) + { + pScrn->rgbBits = 6; + } + + /* Process the options */ + if (!(pSmi->Options = xalloc(sizeof(SMIOptions)))) + return FALSE; + memcpy(pSmi->Options, SMIOptions, sizeof(SMIOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pSmi->Options); + + if (xf86ReturnOptValBool(pSmi->Options, OPTION_PCI_BURST, FALSE)) + { + pSmi->pci_burst = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_burst - PCI burst " + "read enabled\n"); + } + else + { + pSmi->pci_burst = FALSE; + } + + pSmi->NoPCIRetry = TRUE; + if (xf86ReturnOptValBool(pSmi->Options, OPTION_PCI_RETRY, FALSE)) + { + if (xf86ReturnOptValBool(pSmi->Options, OPTION_PCI_BURST, FALSE)) + { + pSmi->NoPCIRetry = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_retry\n"); + } + else + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option " + "requires \"pci_burst\".\n"); + } + } + + if (xf86IsOptionSet(pSmi->Options, OPTION_FIFO_CONSERV)) + { + pSmi->fifo_conservative = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_conservative " + "set\n"); + } + else + { + pSmi->fifo_conservative = FALSE; + } + + if (xf86IsOptionSet(pSmi->Options, OPTION_FIFO_MODERATE)) + { + pSmi->fifo_moderate = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_moderate set\n"); + } + else + { + pSmi->fifo_moderate = FALSE; + } + + if (xf86IsOptionSet(pSmi->Options, OPTION_FIFO_AGGRESSIVE)) + { + pSmi->fifo_aggressive = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_aggressive set\n"); + } + else + { + pSmi->fifo_aggressive = FALSE; + } + + if (xf86ReturnOptValBool(pSmi->Options, OPTION_NOACCEL, FALSE)) + { + pSmi->NoAccel = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: NoAccel - Acceleration " + "disabled\n"); + } + else + { + pSmi->NoAccel = FALSE; + } + + if (xf86ReturnOptValBool(pSmi->Options, OPTION_SHOWCACHE, FALSE)) + { + pSmi->ShowCache = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: show_cache set\n"); + } + else + { + pSmi->ShowCache = FALSE; + } + + if (xf86GetOptValFreq(pSmi->Options, OPTION_MCLK, OPTUNITS_MHZ, &real)) + { + pSmi->MCLK = (int)(real * 1000.0); + if (pSmi->MCLK <= 120000) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: set_mclk set to " + "%1.3f MHz\n", pSmi->MCLK / 1000.0); + } + else + { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Memory Clock value of " + "%1.3f MHz is larger than limit of 120 MHz\n", + pSmi->MCLK / 1000.0); + pSmi->MCLK = 0; + } + } + else + { + pSmi->MCLK = 0; + } + + from = X_DEFAULT; + pSmi->hwcursor = TRUE; + if (xf86GetOptValBool(pSmi->Options, OPTION_HWCURSOR, &pSmi->hwcursor)) + { + from = X_CONFIG; + } + if (xf86ReturnOptValBool(pSmi->Options, OPTION_SWCURSOR, FALSE)) + { + pSmi->hwcursor = FALSE; + from = X_CONFIG; + } + xf86DrvMsg(pScrn->scrnIndex, from, "Using %s Cursor\n", + pSmi->hwcursor ? "Hardware" : "Software"); + + if (xf86GetOptValBool(pSmi->Options, OPTION_SHADOW_FB, &pSmi->shadowFB)) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n", + pSmi->shadowFB ? "enabled" : "disabled"); + } + +#if 1 /* PDR#932 */ + if ((pScrn->depth == 8) || (pScrn->depth == 16)) +#endif /* PDR#932 */ + if ((s = xf86GetOptValString(pSmi->Options, OPTION_ROTATE))) + { + if(!xf86NameCmp(s, "CW")) + { + pSmi->shadowFB = TRUE; + pSmi->rotate = SMI_ROTATE_CCW; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen " + "clockwise\n"); + } + else if (!xf86NameCmp(s, "CCW")) + { + pSmi->shadowFB = TRUE; + pSmi->rotate = SMI_ROTATE_CW; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen counter " + "clockwise\n"); + } + else + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid " + "value for Option \"Rotate\"\n", s); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid options are \"CW\" or " + "\"CCW\"\n"); + } + } + +#ifdef XvExtension + if (xf86GetOptValInteger(pSmi->Options, OPTION_VIDEOKEY, &pSmi->videoKey)) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: Video key set to " + "0x%08X\n", pSmi->videoKey); + } + else + { + pSmi->videoKey = (1 << pScrn->offset.red) | (1 << pScrn->offset.green) + | (((pScrn->mask.blue >> pScrn->offset.blue) - 1) + << pScrn->offset.blue); + } + + if (xf86ReturnOptValBool(pSmi->Options, OPTION_BYTESWAP, FALSE)) + { + pSmi->ByteSwap = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: ByteSwap enabled.\n"); + } + else + { + pSmi->ByteSwap = FALSE; + } + + /* CZ 26.10.2001: interlaced video */ + if (xf86ReturnOptValBool(pSmi->Options, OPTION_INTERLACED, FALSE)) + { + pSmi->interlaced = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: Interlaced enabled.\n"); + } + else + { + pSmi->interlaced = FALSE; + } + /* end CZ */ +#endif + + if (xf86GetOptValBool(pSmi->Options, OPTION_USEBIOS, &pSmi->useBIOS)) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: UseBIOS %s.\n", + pSmi->useBIOS ? "enabled" : "disabled"); + } + else + { + /* Default to UseBIOS enabled. */ + pSmi->useBIOS = TRUE; + } + + if (xf86GetOptValBool(pSmi->Options, OPTION_ZOOMONLCD, &pSmi->zoomOnLCD)) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: ZoomOnLCD %s.\n", + pSmi->zoomOnLCD ? "enabled" : "disabled"); + } + else + { + /* Default to ZoomOnLCD enabled. */ + pSmi->zoomOnLCD = TRUE; + } + + /* Find the PCI slot for this screen */ + pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + if ((pEnt->location.type != BUS_PCI) || (pEnt->resources)) + { + xfree(pEnt); + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + if (xf86LoadSubModule(pScrn,"int10")) { + xf86LoaderReqSymLists(int10Symbols,NULL); + pSmi->pInt10 = xf86InitInt10(pEnt->index); + } + + if (pSmi->pInt10 && xf86LoadSubModule(pScrn, "vbe")) + { + xf86LoaderReqSymLists(vbeSymbols, NULL); + pVbe = VBEInit(pSmi->pInt10, pEnt->index); + } + + pSmi->PciInfo = xf86GetPciInfoForEntity(pEnt->index); + xf86RegisterResources(pEnt->index, NULL, ResExclusive); +/* xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr); */ +/* xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr); */ + + /* + * Set the Chipset and ChipRev, allowing config file entries to + * override. + */ + if (pEnt->device->chipset && *pEnt->device->chipset) + { + pScrn->chipset = pEnt->device->chipset; + pSmi->Chipset = xf86StringToToken(SMIChipsets, pScrn->chipset); + from = X_CONFIG; + } + else if (pEnt->device->chipID >= 0) + { + pSmi->Chipset = pEnt->device->chipID; + pScrn->chipset = (char *) xf86TokenToString(SMIChipsets, pSmi->Chipset); + from = X_CONFIG; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", + pSmi->Chipset); + } + else + { + from = X_PROBED; + pSmi->Chipset = pSmi->PciInfo->chipType; + pScrn->chipset = (char *) xf86TokenToString(SMIChipsets, pSmi->Chipset); + } + + if (pEnt->device->chipRev >= 0) + { + pSmi->ChipRev = pEnt->device->chipRev; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", + pSmi->ChipRev); + } + else + { + pSmi->ChipRev = pSmi->PciInfo->chipRev; + } + xfree(pEnt); + + /* + * This shouldn't happen because such problems should be caught in + * SMI_Probe(), but check it just in case. + */ + if (pScrn->chipset == NULL) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ChipID 0x%04X is not " + "recognised\n", pSmi->Chipset); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + if (pSmi->Chipset < 0) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Chipset \"%s\" is not " + "recognised\n", pScrn->chipset); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset); + + pSmi->PciTag = pciTag(pSmi->PciInfo->bus, pSmi->PciInfo->device, + pSmi->PciInfo->func); + + SMI_MapMem(pScrn); + SMI_DisableVideo(pScrn); + + hwp = VGAHWPTR(pScrn); + vgaIOBase = hwp->IOBase; + vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET; + vgaCRReg = vgaIOBase + VGA_CRTC_DATA_OFFSET; + pSmi->PIOBase = hwp->PIOOffset; + + xf86ErrorFVerb(VERBLEV, "\tSMI_PreInit vgaCRIndex=%x, vgaIOBase=%x, " + "MMIOBase=%x\n", vgaCRIndex, vgaIOBase, hwp->MMIOBase); + + /* Next go on to detect amount of installed ram */ + config = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x71); + + if (xf86LoadSubModule(pScrn, "i2c")) + { + xf86LoaderReqSymLists(i2cSymbols, NULL); + SMI_I2CInit(pScrn); + } + if (xf86LoadSubModule(pScrn, "ddc")) + { + xf86MonPtr pMon = NULL; + + xf86LoaderReqSymLists(ddcSymbols, NULL); +#if 1 /* PDR#579 */ + if (pVbe) + { + pMon = vbeDoEDID(pVbe, NULL); + if (pMon != NULL) + { + if ( (pMon->rawData[0] == 0x00) + && (pMon->rawData[1] == 0xFF) + && (pMon->rawData[2] == 0xFF) + && (pMon->rawData[3] == 0xFF) + && (pMon->rawData[4] == 0xFF) + && (pMon->rawData[5] == 0xFF) + && (pMon->rawData[6] == 0xFF) + && (pMon->rawData[7] == 0x00) + ) + { + pMon = xf86PrintEDID(pMon); + if (pMon != NULL) + { + xf86SetDDCproperties(pScrn, pMon); + } + } + } + } +#else + if ( (pVbe) + && ((pMon = xf86PrintEDID(vbeDoEDID(pVbe, NULL))) != NULL) + ) + { + xf86SetDDCproperties(pScrn, pMon); + } +#endif + else if (!SMI_ddc1(pScrn->scrnIndex)) + { + if (pSmi->I2C) + { + xf86SetDDCproperties(pScrn, + xf86PrintEDID(xf86DoEDID_DDC2(pScrn->scrnIndex, + pSmi->I2C))); + } + } + } + + vbeFree(pVbe); + xf86FreeInt10(pSmi->pInt10); + pSmi->pInt10 = NULL; + + /* + * If the driver can do gamma correction, it should call xf86SetGamma() + * here. (from MGA, no ViRGE gamma support yet, but needed for + * xf86HandleColormaps support.) + */ + { + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) + { + LEAVE_PROC("SMI_PreInit"); + SMI_EnableVideo(pScrn); + SMI_UnmapMem(pScrn); + return(FALSE); + } + } + + /* And compute the amount of video memory and offscreen memory */ + pSmi->videoRAMKBytes = 0; + + if (!pScrn->videoRam) + { + switch (pSmi->Chipset) + { + default: + { + int mem_table[4] = { 1, 2, 4, 0 }; + pSmi->videoRAMKBytes = mem_table[(config >> 6)] * 1024; + break; + } + + case SMI_LYNX3D: + { + int mem_table[4] = { 0, 2, 4, 6 }; + pSmi->videoRAMKBytes = mem_table[(config >> 6)] * 1024 + 512; + break; + } + + case SMI_LYNX3DM: + { + int mem_table[4] = { 16, 2, 4, 8 }; + pSmi->videoRAMKBytes = mem_table[(config >> 6)] * 1024; + break; + } + } + pSmi->videoRAMBytes = pSmi->videoRAMKBytes * 1024; + pScrn->videoRam = pSmi->videoRAMKBytes; + + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "videoram: %dkB\n", + pSmi->videoRAMKBytes); + } + else + { + pSmi->videoRAMKBytes = pScrn->videoRam; + pSmi->videoRAMBytes = pScrn->videoRam * 1024; + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "videoram: %dk\n", + pSmi->videoRAMKBytes); + } + + /* Lynx built-in ramdac speeds */ + pScrn->numClocks = 4; + + if ((pScrn->clock[3] <= 0) && (pScrn->clock[2] > 0)) + { + pScrn->clock[3] = pScrn->clock[2]; + } + + if (pSmi->Chipset == SMI_LYNX3DM) + { + if (pScrn->clock[0] <= 0) pScrn->clock[0] = 200000; + if (pScrn->clock[1] <= 0) pScrn->clock[1] = 200000; + if (pScrn->clock[2] <= 0) pScrn->clock[2] = 200000; + if (pScrn->clock[3] <= 0) pScrn->clock[3] = 200000; + } + else + { + if (pScrn->clock[0] <= 0) pScrn->clock[0] = 135000; + if (pScrn->clock[1] <= 0) pScrn->clock[1] = 135000; + if (pScrn->clock[2] <= 0) pScrn->clock[2] = 135000; + if (pScrn->clock[3] <= 0) pScrn->clock[3] = 135000; + } + + /* Now set RAMDAC limits */ + switch (pSmi->Chipset) + { + default: + pSmi->minClock = 20000; + pSmi->maxClock = 135000; + break; + } + xf86ErrorFVerb(VERBLEV, "\tSMI_PreInit minClock=%d, maxClock=%d\n", + pSmi->minClock, pSmi->maxClock); + + /* Detect current MCLK and print it for user */ + m = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A); + n = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B); + switch (n >> 6) + { + default: + shift = 1; + break; + + case 1: + shift = 4; + break; + + case 2: + shift = 2; + break; + } + n &= 0x3F; + mclk = ((1431818 * m) / n / shift + 50) / 100; + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected current MCLK value of " + "%1.3f MHz\n", mclk / 1000.0); + + SMI_EnableVideo(pScrn); + SMI_UnmapMem(pScrn); + + pScrn->virtualX = pScrn->display->virtualX; + + /* + * Setup the ClockRanges, which describe what clock ranges are available, + * and what sort of modes they can be used for. + */ + clockRanges = xnfcalloc(sizeof(ClockRange),1); + clockRanges->next = NULL; + clockRanges->minClock = pSmi->minClock; + clockRanges->maxClock = pSmi->maxClock; + clockRanges->clockIndex = -1; + clockRanges->interlaceAllowed = FALSE; + clockRanges->doubleScanAllowed = FALSE; + + i = xf86ValidateModes( + pScrn, /* Screen pointer */ + pScrn->monitor->Modes, /* Available monitor modes */ + pScrn->display->modes, /* req mode names for screen */ + clockRanges, /* list of clock ranges allowed */ + NULL, /* use min/max below */ + 128, /* min line pitch (width) */ + 4096, /* maximum line pitch (width) */ + 128, /* bits of granularity for line pitch */ + /* (width) above */ + 128, /* min virtual height */ + 4096, /* max virtual height */ + pScrn->display->virtualX, /* force virtual x */ + pScrn->display->virtualY, /* force virtual Y */ + pSmi->videoRAMBytes, /* size of aperture used to access */ + /* video memory */ + LOOKUP_BEST_REFRESH); /* how to pick modes */ + + if (i == -1) + { + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + /* Prune the modes marked as invalid */ + xf86PruneDriverModes(pScrn); + + if ((i == 0) || (pScrn->modes == NULL)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + xf86SetCrtcForModes(pScrn, 0); + + /* Set the current mode to the first in the list */ + pScrn->currentMode = pScrn->modes; + + /* Print the list of modes being used */ + xf86PrintModes(pScrn); + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + +#ifdef USE_FB + if ((xf86LoadSubModule(pScrn, "fb") == NULL)) + { + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + xf86LoaderReqSymLists(fbSymbols, NULL); +#else + /* Load bpp-specific modules */ + switch (pScrn->bitsPerPixel) + { + case 8: + mod = "cfb"; + reqSym = "cfbScreenInit"; + break; + + case 16: + mod = "cfb16"; + reqSym = "cfb16ScreenInit"; + break; + + case 24: + mod = "cfb24"; + reqSym = "cfb24ScreenInit"; + break; + } + + if (mod && (xf86LoadSubModule(pScrn, mod) == NULL)) + { + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + xf86LoaderReqSymbols(reqSym, NULL); +#endif + /* Load XAA if needed */ + if (!pSmi->NoAccel || pSmi->hwcursor) + { + if (!xf86LoadSubModule(pScrn, "xaa")) + { + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + xf86LoaderReqSymLists(xaaSymbols, NULL); + } + + /* Load ramdac if needed */ + if (pSmi->hwcursor) + { + if (!xf86LoadSubModule(pScrn, "ramdac")) + { + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + xf86LoaderReqSymLists(ramdacSymbols, NULL); + } + + if (pSmi->shadowFB) + { + if (!xf86LoadSubModule(pScrn, "shadowfb")) + { + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + xf86LoaderReqSymLists(shadowSymbols, NULL); + } + + LEAVE_PROC("SMI_PreInit"); + return(TRUE); +} + +/* + * This is called when VT switching back to the X server. Its job is to + * reinitialise the video mode. We may wish to unmap video/MMIO memory too. + */ + +static Bool +SMI_EnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + SMIPtr pSmi = SMIPTR(pScrn); + Bool ret; + + ENTER_PROC("SMI_EnterVT"); + + /* Enable MMIO and map memory */ + SMI_MapMem(pScrn); + SMI_Save(pScrn); + + /* #670 */ + if (pSmi->shadowFB) + { + pSmi->FBOffset = pSmi->savedFBOffset; + pSmi->FBReserved = pSmi->savedFBReserved; + } + + ret = SMI_ModeInit(pScrn, pScrn->currentMode); + + /* #670 */ + if (ret && pSmi->shadowFB) + { + BoxRec box; + + /* #920 */ + if (pSmi->paletteBuffer) + { + int i; + + VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, 0); + for(i = 0; i < 256 * 3; i++) + { + VGAOUT8(pSmi, VGA_DAC_DATA, pSmi->paletteBuffer[i]); + } + xfree(pSmi->paletteBuffer); + pSmi->paletteBuffer = NULL; + } + + if (pSmi->pSaveBuffer) + { + memcpy(pSmi->FBBase, pSmi->pSaveBuffer, pSmi->saveBufferSize); + xfree(pSmi->pSaveBuffer); + pSmi->pSaveBuffer = NULL; + } + + box.x1 = 0; + box.y1 = 0; + box.x2 = pScrn->virtualY; + box.y2 = pScrn->virtualX; + SMI_RefreshArea(pScrn, 1, &box); + } + + /* Reset the grapics engine */ + if (!pSmi->NoAccel) + SMI_EngineReset(pScrn); + + LEAVE_PROC("SMI_EnterVT"); + return(ret); +} + +/* + * This is called when VT switching away from the X server. Its job is to + * restore the previous (text) mode. We may wish to remap video/MMIO memory + * too. + */ + +static void +SMI_LeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + vgaRegPtr vgaSavePtr = &hwp->SavedReg; + SMIRegPtr SMISavePtr = &pSmi->SavedReg; + + ENTER_PROC("SMI_LeaveVT"); + + /* #670 */ + if (pSmi->shadowFB) + { + pSmi->pSaveBuffer = xnfalloc(pSmi->saveBufferSize); + if (pSmi->pSaveBuffer) + { + memcpy(pSmi->pSaveBuffer, pSmi->FBBase, pSmi->saveBufferSize); + } + + pSmi->savedFBOffset = pSmi->FBOffset; + pSmi->savedFBReserved = pSmi->FBReserved; + + /* #920 */ + if (pSmi->Bpp == 1) + { + pSmi->paletteBuffer = xnfalloc(256 * 3); + if (pSmi->paletteBuffer) + { + int i; + + VGAOUT8(pSmi, VGA_DAC_READ_ADDR, 0); + for (i = 0; i < 256 * 3; i++) + { + pSmi->paletteBuffer[i] = VGAIN8(pSmi, VGA_DAC_DATA); + } + } + } + } + + memset(pSmi->FBBase, 0, 256 * 1024); /* #689 */ + SMI_WriteMode(pScrn, vgaSavePtr, SMISavePtr); + SMI_UnmapMem(pScrn); + + LEAVE_PROC("SMI_LeaveVT"); +} + +/* + * This function performs the inverse of the restore function: It saves all the + * standard and extended registers that we are going to modify to set up a video + * mode. + */ + +static void +SMI_Save(ScrnInfoPtr pScrn) +{ + int i; + CARD32 offset; + + vgaHWPtr hwp = VGAHWPTR(pScrn); + vgaRegPtr vgaSavePtr = &hwp->SavedReg; + SMIPtr pSmi = SMIPTR(pScrn); + SMIRegPtr save = &pSmi->SavedReg; + + int vgaIOBase = hwp->IOBase; + int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET; + int vgaCRData = vgaIOBase + VGA_CRTC_DATA_OFFSET; + + ENTER_PROC("SMI_Save"); + + /* Save the standard VGA registers */ + vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL); + save->smiDACMask = VGAIN8(pSmi, VGA_DAC_MASK); + VGAOUT8(pSmi, VGA_DAC_READ_ADDR, 0); + for (i = 0; i < 256; i++) + { + save->smiDacRegs[i][0] = VGAIN8(pSmi, VGA_DAC_DATA); + save->smiDacRegs[i][1] = VGAIN8(pSmi, VGA_DAC_DATA); + save->smiDacRegs[i][2] = VGAIN8(pSmi, VGA_DAC_DATA); + } + for (i = 0, offset = 2; i < 8192; i++, offset += 8) + { + save->smiFont[i] = *(pSmi->FBBase + offset); + } + + /* Now we save all the extended registers we need. */ + save->SR17 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17); + save->SR18 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18); + save->SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21); + save->SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31); + save->SR32 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32); + save->SR6A = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A); + save->SR6B = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B); + save->SR81 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81); + save->SRA0 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0); + + if (SMI_LYNXM_SERIES(pSmi->Chipset)) + { + /* Save primary registers */ + save->CR90[14] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E); + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, + save->CR90[14] & ~0x20); + + for (i = 0; i < 16; i++) + { + save->CR90[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x90 + i); + } + save->CR33 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33); + save->CR3A = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A); + for (i = 0; i < 14; i++) + { + save->CR40[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i); + } + + /* Save secondary registers */ + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14] | 0x20); + save->CR33_2 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33); + for (i = 0; i < 14; i++) + { + save->CR40_2[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, + 0x40 + i); + } + save->CR9F_2 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9F); + + /* Save common registers */ + for (i = 0; i < 14; i++) + { + save->CRA0[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0xA0 + i); + } + + /* PDR#1069 */ + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14]); + } + else + { + save->CR33 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33); + save->CR3A = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A); + for (i = 0; i < 14; i++) + { + save->CR40[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i); + } + } + + /* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */ + if (pSmi->Chipset == SMI_LYNX3DM) { + save->CCR66 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66); + } + /* end CZ */ + + save->DPR10 = READ_DPR(pSmi, 0x10); + save->DPR1C = READ_DPR(pSmi, 0x1C); + save->DPR20 = READ_DPR(pSmi, 0x20); + save->DPR24 = READ_DPR(pSmi, 0x24); + save->DPR28 = READ_DPR(pSmi, 0x28); + save->DPR2C = READ_DPR(pSmi, 0x2C); + save->DPR30 = READ_DPR(pSmi, 0x30); + save->DPR3C = READ_DPR(pSmi, 0x3C); + save->DPR40 = READ_DPR(pSmi, 0x40); + save->DPR44 = READ_DPR(pSmi, 0x44); + + save->VPR00 = READ_VPR(pSmi, 0x00); + save->VPR0C = READ_VPR(pSmi, 0x0C); + save->VPR10 = READ_VPR(pSmi, 0x10); + + save->CPR00 = READ_CPR(pSmi, 0x00); + + if (!pSmi->ModeStructInit) + { + /* XXX Should check the return value of vgaHWCopyReg() */ + vgaHWCopyReg(&hwp->ModeReg, vgaSavePtr); + memcpy(&pSmi->ModeReg, save, sizeof(SMIRegRec)); + pSmi->ModeStructInit = TRUE; + } + + if (pSmi->useBIOS && (pSmi->pInt10 != NULL)) + { + pSmi->pInt10->num = 0x10; + pSmi->pInt10->ax = 0x0F00; + xf86ExecX86int10(pSmi->pInt10); + save->mode = pSmi->pInt10->ax & 0x007F; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Current mode 0x%02X.\n", + save->mode); + } + + if (xf86GetVerbosity() > 1) + { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "Saved current video mode. Register dump:\n"); + SMI_PrintRegs(pScrn); + } + + LEAVE_PROC("SMI_Save"); +} + +/* + * This function is used to restore a video mode. It writes out all of the + * standard VGA and extended registers needed to setup a video mode. + */ + +static void +SMI_WriteMode(ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr, SMIRegPtr restore) +{ + int i; + CARD8 tmp; + CARD32 offset; + + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + int vgaIOBase = hwp->IOBase; + int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET; + int vgaCRData = vgaIOBase + VGA_CRTC_DATA_OFFSET; + + ENTER_PROC("SMI_WriteMode"); + + vgaHWProtect(pScrn, TRUE); + + /* Wait for engine to become idle */ + WaitIdle(); + + if (pSmi->useBIOS && (pSmi->pInt10 != NULL) + && (restore->mode != 0)) + { + pSmi->pInt10->num = 0x10; + pSmi->pInt10->ax = restore->mode | 0x80; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%02X\n", + restore->mode); + xf86ExecX86int10(pSmi->pInt10); + + /* Enable linear mode. */ + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18); + tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA); + outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x01); + + /* Enable DPR/VPR registers. */ + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03); + } + else + { + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17, restore->SR17); + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18) & ~0x1F; + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18, tmp | + (restore->SR18 & 0x1F)); + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03); + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31) & ~0xC0; + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, tmp | + (restore->SR31 & 0xC0)); + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32) & ~0x07; + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32, tmp | + (restore->SR32 & 0x07)); + if (restore->SR6B != 0xFF) + { + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A, + restore->SR6A); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B, + restore->SR6B); + } + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, restore->SR81); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0, restore->SRA0); + + /* Restore the standard VGA registers */ + vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL); + if (restore->smiDACMask) + { + VGAOUT8(pSmi, VGA_DAC_MASK, restore->smiDACMask); + } + else + { + VGAOUT8(pSmi, VGA_DAC_MASK, 0xFF); + } + VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, 0); + for (i = 0; i < 256; i++) + { + VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][0]); + VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][1]); + VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][2]); + } + for (i = 0, offset = 2; i < 8192; i++, offset += 8) + { + *(pSmi->FBBase + offset) = restore->smiFont[i]; + } + + if (SMI_LYNXM_SERIES(pSmi->Chipset)) + { + /* Restore secondary registers */ + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, + restore->CR90[14] | 0x20); + + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33_2); + for (i = 0; i < 14; i++) + { + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i, + restore->CR40_2[i]); + } + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9F, restore->CR9F_2); + + /* Restore primary registers */ + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, + restore->CR90[14] & ~0x20); + + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33); + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A, restore->CR3A); + for (i = 0; i < 14; i++) + { + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i, + restore->CR40[i]); + } + for (i = 0; i < 16; i++) + { + if (i != 14) + { + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x90 + i, + restore->CR90[i]); + } + } + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, restore->CR90[14]); + + /* Restore common registers */ + for (i = 0; i < 14; i++) + { + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0xA0 + i, + restore->CRA0[i]); + } + } + + /* Restore the standard VGA registers */ + if (xf86IsPrimaryPci(pSmi->PciInfo)) { + vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_CMAP + | VGA_SR_FONTS); + } + + if (restore->modeInit) + vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL); + + if (!SMI_LYNXM_SERIES(pSmi->Chipset)) + { + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33); + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A, restore->CR3A); + for (i = 0; i < 14; i++) + { + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i, + restore->CR40[i]); + } + } + } + + /* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */ + if (pSmi->Chipset == SMI_LYNX3DM) { + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66, restore->CCR66); + } + /* end CZ */ + + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, 0x00); + + WRITE_DPR(pSmi, 0x10, restore->DPR10); + WRITE_DPR(pSmi, 0x1C, restore->DPR1C); + WRITE_DPR(pSmi, 0x20, restore->DPR20); + WRITE_DPR(pSmi, 0x24, restore->DPR24); + WRITE_DPR(pSmi, 0x28, restore->DPR28); + WRITE_DPR(pSmi, 0x2C, restore->DPR2C); + WRITE_DPR(pSmi, 0x30, restore->DPR30); + WRITE_DPR(pSmi, 0x3C, restore->DPR3C); + WRITE_DPR(pSmi, 0x40, restore->DPR40); + WRITE_DPR(pSmi, 0x44, restore->DPR44); + + WRITE_VPR(pSmi, 0x00, restore->VPR00); + WRITE_VPR(pSmi, 0x0C, restore->VPR0C); + WRITE_VPR(pSmi, 0x10, restore->VPR10); + + WRITE_CPR(pSmi, 0x00, restore->CPR00); + + if (xf86GetVerbosity() > 1) + { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "Done restoring mode. Register dump:\n"); + SMI_PrintRegs(pScrn); + } + + vgaHWProtect(pScrn, FALSE); + + LEAVE_PROC("SMI_WriteMode"); +} + +static Bool +SMI_MapMem(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + vgaHWPtr hwp; + CARD32 memBase; + + ENTER_PROC("SMI_MapMem"); + + /* Map the Lynx register space */ + switch (pSmi->Chipset) + { + default: + memBase = pSmi->PciInfo->memBase[0] + 0x400000; + pSmi->MapSize = 0x10000; + break; + + case SMI_LYNX3D: + memBase = pSmi->PciInfo->memBase[0] + 0x680000; + pSmi->MapSize = 0x180000; + break; + + case SMI_LYNXEM: + case SMI_LYNXEMplus: + memBase = pSmi->PciInfo->memBase[0] + 0x400000; + pSmi->MapSize = 0x400000; + break; + + case SMI_LYNX3DM: + memBase = pSmi->PciInfo->memBase[0]; + pSmi->MapSize = 0x200000; + break; + } + pSmi->MapBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pSmi->PciTag, + memBase, pSmi->MapSize); + + if (pSmi->MapBase == NULL) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Internal error: could not map " + "MMIO registers.\n"); + LEAVE_PROC("SMI_MapMem"); + return(FALSE); + } + + switch (pSmi->Chipset) + { + default: + pSmi->DPRBase = pSmi->MapBase + 0x8000; + pSmi->VPRBase = pSmi->MapBase + 0xC000; + pSmi->CPRBase = pSmi->MapBase + 0xE000; + pSmi->IOBase = NULL; + pSmi->DataPortBase = pSmi->MapBase; + pSmi->DataPortSize = 0x8000; + break; + + case SMI_LYNX3D: + pSmi->DPRBase = pSmi->MapBase + 0x000000; + pSmi->VPRBase = pSmi->MapBase + 0x000800; + pSmi->CPRBase = pSmi->MapBase + 0x001000; + pSmi->IOBase = pSmi->MapBase + 0x040000; + pSmi->DataPortBase = pSmi->MapBase + 0x080000; + pSmi->DataPortSize = 0x100000; + break; + + case SMI_LYNXEM: + case SMI_LYNXEMplus: + pSmi->DPRBase = pSmi->MapBase + 0x008000; + pSmi->VPRBase = pSmi->MapBase + 0x00C000; + pSmi->CPRBase = pSmi->MapBase + 0x00E000; + pSmi->IOBase = pSmi->MapBase + 0x300000; + pSmi->DataPortBase = pSmi->MapBase /*+ 0x100000*/; + pSmi->DataPortSize = 0x8000 /*0x200000*/; + break; + + case SMI_LYNX3DM: + pSmi->DPRBase = pSmi->MapBase + 0x000000; + pSmi->VPRBase = pSmi->MapBase + 0x000800; + pSmi->CPRBase = pSmi->MapBase + 0x001000; + pSmi->IOBase = pSmi->MapBase + 0x0C0000; + pSmi->DataPortBase = pSmi->MapBase + 0x100000; + pSmi->DataPortSize = 0x100000; + break; + } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "Physical MMIO at 0x%08X\n", memBase); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "Logical MMIO at 0x%08X - 0x%08X\n", pSmi->MapBase, + pSmi->MapBase + pSmi->MapSize - 1); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "DPR=0x%08X, VPR=0x%08X, IOBase=0x%08X\n", pSmi->DPRBase, + pSmi->VPRBase, pSmi->IOBase); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "DataPort=0x%08X - 0x%08X\n", pSmi->DataPortBase, + pSmi->DataPortBase + pSmi->DataPortSize - 1); + + /* Map the frame buffer */ + if (pSmi->Chipset == SMI_LYNX3DM) + { + pScrn->memPhysBase = pSmi->PciInfo->memBase[0] + 0x200000; + } + else + { + pScrn->memPhysBase = pSmi->PciInfo->memBase[0]; + } + if (pSmi->videoRAMBytes) + { + pSmi->FBBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, + pSmi->PciTag, pScrn->memPhysBase, pSmi->videoRAMBytes); + + if (pSmi->FBBase == NULL) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Internal error: could not " + "map framebuffer.\n"); + LEAVE_PROC("SMI_MapMem"); + return(FALSE); + } + } + pSmi->FBOffset = pScrn->fbOffset = 0; + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "Physical frame buffer at 0x%08X\n", pScrn->memPhysBase); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "Logical frame buffer at 0x%08X - 0x%08X\n", pSmi->FBBase, + pSmi->FBBase + pSmi->videoRAMBytes - 1); + + SMI_EnableMmio(pScrn); + + /* Set up offset to hwcursor memory area. It's a 1K chunk at the end of + * the frame buffer. Also set up the reserved memory space. + */ + pSmi->FBCursorOffset = pSmi->videoRAMBytes - 1024; + if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x01)/* #1074 */ + { + CARD32 fifoOffset = 0; + fifoOffset |= VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x46) + << 3; + fifoOffset |= VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x47) + << 11; + fifoOffset |= (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49) + & 0x1C) << 17; + pSmi->FBReserved = fifoOffset; /* PDR#1074 */ + } + else + { + pSmi->FBReserved = pSmi->videoRAMBytes - 2048; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Cursor Offset: %08X Reserved: %08X\n", + pSmi->FBCursorOffset, pSmi->FBReserved); + + pSmi->lcd = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31) & 0x01; + if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x01) + { + pSmi->lcd <<= 1; + } + switch (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x0C) + { + case 0x00: + pSmi->lcdWidth = 640; + pSmi->lcdHeight = 480; + break; + + case 0x04: + pSmi->lcdWidth = 800; + pSmi->lcdHeight = 600; + break; + + case 0x08: + if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x74) & 0x02) + { + pSmi->lcdWidth = 1024; + pSmi->lcdHeight = 600; + } + else + { + pSmi->lcdWidth = 1024; + pSmi->lcdHeight = 768; + } + break; + + case 0x0C: + pSmi->lcdWidth = 1280; + pSmi->lcdHeight = 1024; + break; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Panel Size = %dx%d\n", + (pSmi->lcd == 0) ? "OFF" : (pSmi->lcd == 1) ? "TFT" : "DSTN", + pSmi->lcdWidth, pSmi->lcdHeight); + + /* Assign hwp->MemBase & IOBase here */ + hwp = VGAHWPTR(pScrn); + if (pSmi->IOBase != NULL) + { + vgaHWSetMmioFuncs(hwp, pSmi->MapBase, pSmi->IOBase - pSmi->MapBase); + } + vgaHWGetIOBase(hwp); + + /* Map the VGA memory when the primary video */ + if (xf86IsPrimaryPci(pSmi->PciInfo)) + { + hwp->MapSize = 0x10000; + if (!vgaHWMapMem(pScrn)) + { + LEAVE_PROC("SMI_MapMem"); + return(FALSE); + } + pSmi->PrimaryVidMapped = TRUE; + } + + LEAVE_PROC("SMI_MapMem"); + return(TRUE); +} + +/* UnMapMem - contains half of pre-4.0 EnterLeave function. The EnterLeave + * function which en/disable access to IO ports and ext. regs + */ + +static void +SMI_UnmapMem(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_UnmapMem"); + + /* Unmap VGA mem if mapped. */ + if (pSmi->PrimaryVidMapped) + { + vgaHWUnmapMem(pScrn); + pSmi->PrimaryVidMapped = FALSE; + } + + SMI_DisableMmio(pScrn); + + xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pSmi->MapBase, pSmi->MapSize); + if (pSmi->FBBase != NULL) + { + xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pSmi->FBBase, + pSmi->videoRAMBytes); + } + + LEAVE_PROC("SMI_UnmapMem"); +} + +/* This gets called at the start of each server generation. */ + +static Bool +SMI_ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SMIPtr pSmi = SMIPTR(pScrn); + EntityInfoPtr pEnt; + + ENTER_PROC("SMI_ScreenInit"); + + /* Map MMIO regs and framebuffer */ + if (!SMI_MapMem(pScrn)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + + pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + + if (!pSmi->pInt10) { + pSmi->pInt10 = xf86InitInt10(pEnt->index); + } + + /* Save the chip/graphics state */ + SMI_Save(pScrn); + + /* Zero the frame buffer, #258 */ + memset(pSmi->FBBase, 0, pSmi->videoRAMBytes); + + /* Initialize the first mode */ + if (!SMI_ModeInit(pScrn, pScrn->currentMode)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + + /* + * The next step is to setup the screen's visuals, and initialise the + * framebuffer code. In cases where the framebuffer's default choises for + * things like visual layouts and bits per RGB are OK, this may be as simple + * as calling the framebuffer's ScreenInit() function. If not, the visuals + * will need to be setup before calling a fb ScreenInit() function and fixed + * up after. + * + * For most PC hardware at depths >= 8, the defaults that cfb uses are not + * appropriate. In this driver, we fixup the visuals after. + */ + + /* + * Reset the visual list. + */ + miClearVisualTypes(); + + /* Setup the visuals we support. */ + + /* + * For bpp > 8, the default visuals are not acceptable because we only + * support TrueColor and not DirectColor. To deal with this, call + * miSetVisualTypes with the appropriate visual mask. + */ +#ifndef USE_FB + if (pScrn->bitsPerPixel > 8) + { + if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits, + pScrn->defaultVisual)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + } + else +#endif + { + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, + pScrn->defaultVisual)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + } +#ifdef USE_FB + if (!miSetPixmapDepths ()) return FALSE; +#endif + + if (!SMI_InternalScreenInit(scrnIndex, pScreen)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + + xf86SetBlackWhitePixels(pScreen); + + if (pScrn->bitsPerPixel > 8) + { + VisualPtr visual; + /* Fixup RGB ordering */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) + { + if ((visual->class | DynamicClass) == DirectColor) + { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + +#ifdef USE_FB + /* must be after RGB ordering fixed */ + fbPictureInit(pScreen, 0, 0); +#endif + + /* CZ 18.06.2001: moved here from smi_accel.c to have offscreen + framebuffer in NoAccel mode */ + { + int numLines, maxLines; + BoxRec AvailFBArea; + + maxLines = pSmi->FBReserved / (pSmi->width * pSmi->Bpp); + if (pSmi->rotate) { + numLines = maxLines; + } else { + /* CZ 3.11.2001: What does the following code? see also smi_video.c aaa line 1226 */ +/*#if defined(XvExtension) && SMI_USE_VIDEO */ +#if 0 + numLines = ((pSmi->FBReserved - pSmi->width * pSmi->Bpp + * pSmi->height) * 25 / 100 + pSmi->width + * pSmi->Bpp - 1) / (pSmi->width * pSmi->Bpp); + numLines += pSmi->height; +#else + numLines = maxLines; +#endif + } + + AvailFBArea.x1 = 0; + AvailFBArea.y1 = 0; + AvailFBArea.x2 = pSmi->width; + AvailFBArea.y2 = numLines; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "FrameBuffer Box: %d,%d - %d,%d\n", + AvailFBArea.x1, AvailFBArea.y1, AvailFBArea.x2, + AvailFBArea.y2); + xf86InitFBManager(pScreen, &AvailFBArea); + } + /* end CZ */ + + + /* Initialize acceleration layer */ + if (!pSmi->NoAccel) { + if (!SMI_AccelInit(pScreen)) { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + } + + miInitializeBackingStore(pScreen); + + /* hardware cursor needs to wrap this layer */ + SMI_DGAInit(pScreen); + + /* Initialise cursor functions */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* Initialize HW cursor layer. Must follow software cursor + * initialization. + */ + if (pSmi->hwcursor) + { + if (!SMI_HWCursorInit(pScreen)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Hardware cursor " + "initialization failed\n"); + } + } + + if (pSmi->shadowFB) + { + RefreshAreaFuncPtr refreshArea = SMI_RefreshArea; + + if (pSmi->rotate) + { + if (pSmi->PointerMoved == NULL) + { + pSmi->PointerMoved = pScrn->PointerMoved; + pScrn->PointerMoved = SMI_PointerMoved; + } + } + + ShadowFBInit(pScreen, refreshArea); + } + + /* Initialise default colormap */ + if (!miCreateDefColormap(pScreen)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + + /* Initialize colormap layer. Must follow initialization of the default + * colormap. And SetGamma call, else it will load palette with solid white. + */ + /* CZ 2.11.2001: CMAP_PALETTED_TRUECOLOR for gamma correction */ + if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, SMI_LoadPalette, NULL, + CMAP_RELOAD_ON_MODE_SWITCH | CMAP_PALETTED_TRUECOLOR)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + + pScreen->SaveScreen = SMI_SaveScreen; + pSmi->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = SMI_CloseScreen; + + if (!xf86DPMSInit(pScreen, SMI_DisplayPowerManagementSet, 0)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed!\n"); + } + + SMI_InitVideo(pScreen); + + /* Report any unused options (only for the first generation) */ + if (serverGeneration == 1) + { + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + } + + LEAVE_PROC("SMI_ScreenInit"); + return(TRUE); +} + +/* Common init routines needed in EnterVT and ScreenInit */ + +static int +SMI_InternalScreenInit(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SMIPtr pSmi = SMIPTR(pScrn); + int width, height, displayWidth; + int bytesPerPixel = pScrn->bitsPerPixel / 8; + int xDpi, yDpi; + int ret; + + ENTER_PROC("SMI_InternalScreenInit"); + + if (pSmi->rotate) + { + width = pScrn->virtualY; + height = pScrn->virtualX; + xDpi = pScrn->yDpi; + yDpi = pScrn->xDpi; + displayWidth = ((width * bytesPerPixel + 15) & ~15) / bytesPerPixel; + } + else + { + width = pScrn->virtualX; + height = pScrn->virtualY; + xDpi = pScrn->xDpi; + yDpi = pScrn->yDpi; + displayWidth = pScrn->displayWidth; + } + + if (pSmi->shadowFB) + { + pSmi->ShadowWidth = width; + pSmi->ShadowHeight = height; + pSmi->ShadowWidthBytes = (width * bytesPerPixel + 15) & ~15; + if (bytesPerPixel == 3) + { + pSmi->ShadowPitch = ((height * 3) << 16) + | pSmi->ShadowWidthBytes; + } + else + { + pSmi->ShadowPitch = (height << 16) + | (pSmi->ShadowWidthBytes / bytesPerPixel); + } + + pSmi->saveBufferSize = pSmi->ShadowWidthBytes * pSmi->ShadowHeight; + pSmi->FBReserved -= pSmi->saveBufferSize; + pSmi->FBReserved &= ~0x15; + WRITE_VPR(pSmi, 0x0C, (pSmi->FBOffset = pSmi->FBReserved) >> 3); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Shadow: width=%d height=%d " + "offset=0x%08X pitch=0x%08X\n", pSmi->ShadowWidth, + pSmi->ShadowHeight, pSmi->FBOffset, pSmi->ShadowPitch); + } + else + { + pSmi->FBOffset = 0; + } + + /* + * Call the framebuffer layer's ScreenInit function, and fill in other + * pScreen fields. + */ + + DEBUG((VERBLEV, "\tInitializing FB @ 0x%08X for %dx%d (%d)\n", + pSmi->FBBase, width, height, displayWidth)); + switch (pScrn->bitsPerPixel) + { +#ifdef USE_FB + case 8: + case 16: + case 24: + ret = fbScreenInit(pScreen, pSmi->FBBase, width, height, xDpi, + yDpi, displayWidth,pScrn->bitsPerPixel); + break; +#else + case 8: + ret = cfbScreenInit(pScreen, pSmi->FBBase, width, height, xDpi, + yDpi, displayWidth); + break; + + case 16: + ret = cfb16ScreenInit(pScreen, pSmi->FBBase, width, height, xDpi, + yDpi, displayWidth); + break; + + case 24: + ret = cfb24ScreenInit(pScreen, pSmi->FBBase, width, height, xDpi, + yDpi, displayWidth); + break; +#endif + default: + xf86DrvMsg(scrnIndex, X_ERROR, "Internal error: invalid bpp (%d) " + "in SMI_InternalScreenInit\n", pScrn->bitsPerPixel); + LEAVE_PROC("SMI_InternalScreenInit"); + return(FALSE); + } + + LEAVE_PROC("SMI_InternalScreenInit"); + return(ret); +} + +/* Checks if a mode is suitable for the selected configuration. */ +static ModeStatus +SMI_ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + SMIPtr pSmi = SMIPTR(pScrn); + float refresh; + + ENTER_PROC("SMI_ValidMode"); + refresh = (mode->VRefresh > 0) ? mode->VRefresh + : mode->Clock * 1000.0 / mode->VTotal / mode->HTotal; + xf86DrvMsg(scrnIndex, X_INFO, "Mode: %dx%d %d-bpp, %fHz\n", mode->HDisplay, + mode->VDisplay, pScrn->bitsPerPixel, refresh); + + if (pSmi->shadowFB) + { + int mem; + + if (pScrn->bitsPerPixel == 24) + { + LEAVE_PROC("SMI_ValidMode"); + return(MODE_BAD); + } + + mem = (pScrn->virtualX * pScrn->bitsPerPixel / 8 + 15) & ~15; + mem *= pScrn->virtualY * 2; + + if (mem > pSmi->FBReserved) /* PDR#1074 */ + { + LEAVE_PROC("SMI_ValidMode"); + return(MODE_MEM); + } + } + + if (!pSmi->useBIOS || pSmi->lcd) + { +#if 1 /* PDR#983 */ + if (pSmi->zoomOnLCD) + { + if ( (mode->HDisplay > pSmi->lcdWidth) + || (mode->VDisplay > pSmi->lcdHeight) + ) + { + LEAVE_PROC("SMI_ValidMode"); + return(MODE_PANEL); + } + } + else +#endif + { + if ( (mode->HDisplay != pSmi->lcdWidth) + || (mode->VDisplay != pSmi->lcdHeight) + ) + { + LEAVE_PROC("SMI_ValidMode"); + return(MODE_PANEL); + } + } + + } + +#if 1 /* PDR#944 */ + if (pSmi->rotate) + { + if ( (mode->HDisplay != pSmi->lcdWidth) + || (mode->VDisplay != pSmi->lcdHeight) + ) + { + LEAVE_PROC("SMI_ValidMode"); + return(MODE_PANEL); + } + } +#endif + + LEAVE_PROC("SMI_ValidMode"); + return(MODE_OK); +} + +static Bool +SMI_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + unsigned char tmp; + int panelIndex, modeIndex, i; + int xyAddress[] = { 320, 400, 512, 640, 800, 1024, 1280, 1600, 2048 }; + CARD32 DEDataFormat = 0; + + /* Store values to current mode register structs */ + SMIRegPtr new = &pSmi->ModeReg; + vgaRegPtr vganew = &hwp->ModeReg; + + ENTER_PROC("SMI_ModeInit"); + + if(!vgaHWInit(pScrn, mode)) + { + LEAVE_PROC("SMI_ModeInit"); + return(FALSE); + } + + new->modeInit = TRUE; + + if (pSmi->rotate) + { + pSmi->width = pScrn->virtualY; + pSmi->height = pScrn->virtualX; + } + else + { + pSmi->width = pScrn->virtualX; + pSmi->height = pScrn->virtualY; + } + pSmi->Bpp = pScrn->bitsPerPixel / 8; + + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x17); + tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA); + if (pSmi->pci_burst) + { + new->SR17 = tmp | 0x20; + } + else + { + new->SR17 = tmp & ~0x20; + } + + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18); + new->SR18 = inb(pSmi->PIOBase + VGA_SEQ_DATA) | 0x11; + + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21); + new->SR21 = inb(pSmi->PIOBase + VGA_SEQ_DATA) & ~0x03; + + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x31); + new->SR31 = inb(pSmi->PIOBase + VGA_SEQ_DATA) & ~0xC0; + + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x32); + new->SR32 = inb(pSmi->PIOBase + VGA_SEQ_DATA) & ~0x07; + if (SMI_LYNXM_SERIES(pSmi->Chipset)) + { + new->SR32 |= 0x04; + } + + new->SRA0 = new->CR33 = new->CR3A = 0x00; + + if (pSmi->lcdWidth == 640) + { + panelIndex = 0; + } + else if (pSmi->lcdWidth == 800) + { + panelIndex = 1; + } + else + { + panelIndex = 2; + } + + if (mode->HDisplay == 640) + { + modeIndex = 0; + } + else if (mode->HDisplay == 800) + { + modeIndex = 1; + } + else + { + modeIndex = 2; + } + + if (SMI_LYNXM_SERIES(pSmi->Chipset)) + { + static unsigned char PanelTable[3][14] = + { + { 0x5F, 0x4F, 0x00, 0x52, 0x1E, 0x0B, 0xDF, 0x00, 0xE9, 0x0B, 0x2E, + 0x00, 0x4F, 0xDF }, + { 0x7F, 0x63, 0x00, 0x69, 0x19, 0x72, 0x57, 0x00, 0x58, 0x0C, 0xA2, + 0x20, 0x4F, 0xDF }, + { 0xA3, 0x7F, 0x00, 0x83, 0x14, 0x24, 0xFF, 0x00, 0x02, 0x08, 0xA7, + 0xE0, 0x4F, 0xDF }, + }; + + for (i = 0; i < 14; i++) + { + new->CR40[i] = PanelTable[panelIndex][i]; + } + new->CR90[14] = 0x03; + new->CR90[15] = 0x00; + if (mode->VDisplay < pSmi->lcdHeight) + { + new->CRA0[6] = (pSmi->lcdHeight - mode->VDisplay) / 8; + } + else + { + new->CRA0[6] = 0; + } + + if (mode->HDisplay < pSmi->lcdWidth) + { + new->CRA0[7] = (pSmi->lcdWidth - mode->HDisplay) / 16; + } + else + { + new->CRA0[7] = 0; + } + } + else + { + static unsigned char PanelTable[3][3][14] = + { + { /* 640x480 panel */ + { 0x5F, 0x4F, 0x00, 0x53, 0x00, 0x0B, 0xDF, 0x00, 0xEA, 0x0C, + 0x2E, 0x00, 0x4F, 0xDF }, + { 0x5F, 0x4F, 0x00, 0x53, 0x00, 0x0B, 0xDF, 0x00, 0xEA, 0x0C, + 0x2E, 0x00, 0x4F, 0xDF }, + { 0x5F, 0x4F, 0x00, 0x53, 0x00, 0x0B, 0xDF, 0x00, 0xEA, 0x0C, + 0x2E, 0x00, 0x4F, 0xDF }, + }, + { /* 800x600 panel */ + { 0x7F, 0x59, 0x19, 0x5E, 0x8E, 0x72, 0x1C, 0x37, 0x1D, 0x00, + 0xA2, 0x20, 0x4F, 0xDF }, + { 0x7F, 0x63, 0x00, 0x68, 0x18, 0x72, 0x58, 0x00, 0x59, 0x0C, + 0xE0, 0x20, 0x63, 0x57 }, + { 0x7F, 0x63, 0x00, 0x68, 0x18, 0x72, 0x58, 0x00, 0x59, 0x0C, + 0xE0, 0x20, 0x63, 0x57 }, + }, + { /* 1024x768 panel */ + { 0xA3, 0x67, 0x0F, 0x6D, 0x1D, 0x24, 0x70, 0x95, 0x72, 0x07, + 0xA3, 0x20, 0x4F, 0xDF }, + { 0xA3, 0x71, 0x19, 0x77, 0x07, 0x24, 0xAC, 0xD1, 0xAE, 0x03, + 0xE1, 0x20, 0x63, 0x57 }, + { 0xA3, 0x7F, 0x00, 0x85, 0x15, 0x24, 0xFF, 0x00, 0x01, 0x07, + 0xE5, 0x20, 0x7F, 0xFF }, + }, + }; + + for (i = 0; i < 14; i++) + { + new->CR40[i] = PanelTable[panelIndex][modeIndex][i]; + } + } + + /* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */ + new->CCR66 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66); + if (pSmi->Chipset == SMI_LYNX3DM) { + switch (pScrn->bitsPerPixel) { + case 8: + new->CCR66 = (new->CCR66 & 0xF3) | 0x00; /* 6 bits-RAM */ + break; + case 16: + new->CCR66 = (new->CCR66 & 0xF3) | 0x00; /* 6 bits-RAM */ + /* no Gamma correction in 16 Bit mode (s. Release.txt 1.3.1) */ + break; + case 24: + case 32: + new->CCR66 = (new->CCR66 & 0xF3) | 0x04; /* Gamma correct ON */ + break; + default: + LEAVE_PROC("SMI_ModeInit"); + return(FALSE); + } + } + + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x30); + if (inb(pSmi->PIOBase + VGA_SEQ_DATA) & 0x01) + { + new->SR21 = 0x00; + } + + if (pSmi->MCLK > 0) + { + SMI_CommonCalcClock(pScrn->scrnIndex,pSmi->MCLK, + 1, 1, 31, 0, 2, pSmi->minClock, + pSmi->maxClock, &new->SR6A, &new->SR6B); + } + else + { + new->SR6B = 0xFF; + } + + if ((mode->HDisplay == 640) && SMI_LYNXM_SERIES(pSmi->Chipset)) + { + vganew->MiscOutReg &= ~0x0C; + } + else + { + vganew->MiscOutReg |= 0x0C; + } + vganew->MiscOutReg |= 0xE0; + if (mode->HDisplay == 800) + { + vganew->MiscOutReg &= ~0xC0; + } + if ((mode->HDisplay == 1024) && SMI_LYNXM_SERIES(pSmi->Chipset)) + { + vganew->MiscOutReg &= ~0xC0; + } + + /* Set DPR registers */ + pSmi->Stride = (pSmi->width * pSmi->Bpp + 15) & ~15; + switch (pScrn->bitsPerPixel) + { + case 8: + DEDataFormat = 0x00000000; + break; + + case 16: + pSmi->Stride >>= 1; + DEDataFormat = 0x00100000; + break; + + case 24: + DEDataFormat = 0x00300000; + break; + + case 32: + pSmi->Stride >>= 2; + DEDataFormat = 0x00200000; + break; + } + for (i = 0; i < sizeof(xyAddress) / sizeof(xyAddress[0]); i++) + { + if (pSmi->rotate) + { + if (xyAddress[i] == pSmi->height) + { + DEDataFormat |= i << 16; + break; + } + } + else + { + if (xyAddress[i] == pSmi->width) + { + DEDataFormat |= i << 16; + break; + } + } + } + new->DPR10 = (pSmi->Stride << 16) | pSmi->Stride; + new->DPR1C = DEDataFormat; + new->DPR20 = 0; + new->DPR24 = 0xFFFFFFFF; + new->DPR28 = 0xFFFFFFFF; + new->DPR2C = 0; + new->DPR30 = 0; + new->DPR3C = (pSmi->Stride << 16) | pSmi->Stride; + new->DPR40 = 0; + new->DPR44 = 0; + + /* Set VPR registers */ + switch (pScrn->bitsPerPixel) + { + case 8: + new->VPR00 = 0x00000000; + break; + + case 16: + new->VPR00 = 0x00020000; + break; + + case 24: + new->VPR00 = 0x00040000; + break; + + case 32: + new->VPR00 = 0x00030000; + break; + } + new->VPR0C = pSmi->FBOffset >> 3; + if (pSmi->rotate) + { + new->VPR10 = ((((min(pSmi->lcdWidth, pSmi->height) * pSmi->Bpp) >> 3) + + 2) << 16) | ((pSmi->height * pSmi->Bpp) >> 3); + } + else + { + new->VPR10 = ((((min(pSmi->lcdWidth, pSmi->width) * pSmi->Bpp) >> 3) + + 2) << 16) | ((pSmi->width * pSmi->Bpp) >> 3); + } + + /* Set CPR registers */ + new->CPR00 = 0x00000000; + + pScrn->vtSema = TRUE; + + /* Find the INT 10 mode number */ + { + static struct + { + int x, y, bpp; + CARD16 mode; + + } modeTable[] = + { + { 640, 480, 8, 0x50 }, + { 640, 480, 16, 0x52 }, + { 640, 480, 24, 0x53 }, + { 640, 480, 32, 0x54 }, + { 800, 600, 8, 0x55 }, + { 800, 600, 16, 0x57 }, + { 800, 600, 24, 0x58 }, + { 800, 600, 32, 0x59 }, + { 1024, 768, 8, 0x60 }, + { 1024, 768, 16, 0x62 }, + { 1024, 768, 24, 0x63 }, + { 1024, 768, 32, 0x64 }, + { 1280, 1024, 8, 0x65 }, + { 1280, 1024, 16, 0x67 }, + { 1280, 1024, 24, 0x68 }, + { 1280, 1024, 32, 0x69 }, + }; + + new->mode = 0; + for (i = 0; i < sizeof(modeTable) / sizeof(modeTable[0]); i++) + { + if ( (modeTable[i].x == mode->HDisplay) + && (modeTable[i].y == mode->VDisplay) + && (modeTable[i].bpp == pScrn->bitsPerPixel) + ) + { + new->mode = modeTable[i].mode; + break; + } + } + } + + /* Zero the font memory */ + memset(new->smiFont, 0, sizeof(new->smiFont)); + + /* Write the mode registers to hardware */ + SMI_WriteMode(pScrn, vganew, new); + + /* Adjust the viewport */ + SMI_AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + + LEAVE_PROC("SMI_ModeInit"); + return(TRUE); +} + +/* + * This is called at the end of each server generation. It restores the + * original (text) mode. It should also unmap the video memory, and free any + * per-generation data allocated by the driver. It should finish by unwrapping + * and calling the saved CloseScreen function. + */ + +static Bool +SMI_CloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + vgaRegPtr vgaSavePtr = &hwp->SavedReg; + SMIRegPtr SMISavePtr = &pSmi->SavedReg; + Bool ret; + + ENTER_PROC("SMI_CloseScreen"); + + if (pScrn->vtSema) + { + SMI_WriteMode(pScrn, vgaSavePtr, SMISavePtr); + vgaHWLock(hwp); + SMI_UnmapMem(pScrn); + } + + if (pSmi->AccelInfoRec != NULL) + { + XAADestroyInfoRec(pSmi->AccelInfoRec); + } + if (pSmi->CursorInfoRec != NULL) + { + xf86DestroyCursorInfoRec(pSmi->CursorInfoRec); + } + if (pSmi->DGAModes != NULL) + { + xfree(pSmi->DGAModes); + } + if (pSmi->pInt10 != NULL) + { + xf86FreeInt10(pSmi->pInt10); + pSmi->pInt10 = NULL; + } +#ifdef XvExtension + if (pSmi->ptrAdaptor != NULL) + { + xfree(pSmi->ptrAdaptor); + } + if (pSmi->BlockHandler != NULL) + { + pScreen->BlockHandler = pSmi->BlockHandler; + } +#endif + if (pSmi->I2C != NULL) + { + xf86DestroyI2CBusRec(pSmi->I2C, FALSE, TRUE); + xfree(pSmi->I2C); + pSmi->I2C = NULL; + } + /* #670 */ + if (pSmi->pSaveBuffer) + { + xfree(pSmi->pSaveBuffer); + } + /* #920 */ + if (pSmi->paletteBuffer) + { + xfree(pSmi->paletteBuffer); + } + + pScrn->vtSema = FALSE; + pScreen->CloseScreen = pSmi->CloseScreen; + ret = (*pScreen->CloseScreen)(scrnIndex, pScreen); + + LEAVE_PROC("SMI_CloseScreen"); + return(ret); +} + +static void +SMI_FreeScreen(int scrnIndex, int flags) +{ + SMI_FreeRec(xf86Screens[scrnIndex]); +} + +static Bool +SMI_SaveScreen(ScreenPtr pScreen, int mode) +{ + Bool ret; + + ENTER_PROC("SMI_SaveScreen"); + + ret = vgaHWSaveScreen(pScreen, mode); + + LEAVE_PROC("SMI_SaveScreen"); + return(ret); +} + +void +SMI_AdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + SMIPtr pSmi = SMIPTR(pScrn); + CARD32 Base; + + ENTER_PROC("SMI_AdjustFrame"); + + if (pSmi->ShowCache && y) + { + y += pScrn->virtualY - 1; + } + + Base = pSmi->FBOffset + (x + y * pScrn->virtualX) * pSmi->Bpp; + if (SMI_LYNX3D_SERIES(pSmi->Chipset)) + { + Base = (Base + 15) & ~15; +#if 1 /* PDR#1058 */ + while ((Base % pSmi->Bpp) > 0) + { + Base -= 16; + } +#endif + } + else + { + Base = (Base + 7) & ~7; +#if 1 /* PDR#1058 */ + while ((Base % pSmi->Bpp) > 0) + { + Base -= 8; + } +#endif + } + + WRITE_VPR(pSmi, 0x0C, Base >> 3); + + LEAVE_PROC("SMI_AdjustFrame"); +} + +Bool +SMI_SwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + Bool ret; + + ENTER_PROC("SMI_SwitchMode"); + + ret = SMI_ModeInit(xf86Screens[scrnIndex], mode); + + LEAVE_PROC("SMI_SwitchMode"); + return(ret); +} + +void +SMI_LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies, LOCO *colors, + VisualPtr pVisual) +{ + SMIPtr pSmi = SMIPTR(pScrn); + int i; + + ENTER_PROC("SMI_LoadPalette"); + + for(i = 0; i < numColors; i++) + { + DEBUG((VERBLEV, "pal[%d] = %d %d %d\n", indicies[i], + colors[indicies[i]].red, colors[indicies[i]].green, colors[indicies[i]].blue)); + VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, indicies[i]); + VGAOUT8(pSmi, VGA_DAC_DATA, colors[indicies[i]].red); + VGAOUT8(pSmi, VGA_DAC_DATA, colors[indicies[i]].green); + VGAOUT8(pSmi, VGA_DAC_DATA, colors[indicies[i]].blue); + } + + LEAVE_PROC("SMI_LoadPalette"); +} + +static void +SMI_DisableVideo(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + CARD8 tmp; + + if (!(tmp = VGAIN8(pSmi, VGA_DAC_MASK))) + return; + pSmi->DACmask = tmp; + VGAOUT8(pSmi, VGA_DAC_MASK, 0); +} + +static void +SMI_EnableVideo(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + VGAOUT8(pSmi, VGA_DAC_MASK, pSmi->DACmask); +} + + +void +SMI_EnableMmio(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + CARD8 tmp; + + ENTER_PROC("SMI_EnableMmio"); + + /* + * Enable chipset (seen on uninitialized secondary cards) might not be + * needed once we use the VGA softbooter + */ + vgaHWSetStdFuncs(hwp); + + /* Enable linear mode */ + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18); + tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA); + pSmi->SR18Value = tmp; /* PDR#521 */ + outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x11); + + /* Enable 2D/3D Engine and Video Processor */ + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21); + tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA); + pSmi->SR21Value = tmp; /* PDR#521 */ + outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp & ~0x03); + + LEAVE_PROC("SMI_EnableMmio"); +} + +void +SMI_DisableMmio(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_DisableMmio"); + + vgaHWSetStdFuncs(hwp); + + /* Disable 2D/3D Engine and Video Processor */ + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21); + outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR21Value); /* PDR#521 */ + + /* Disable linear mode */ + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18); + outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR18Value); /* PDR#521 */ + + LEAVE_PROC("SMI_DisableMmio"); +} + +/* This function is used to debug, it prints out the contents of Lynx regs */ +static void +SMI_PrintRegs(ScrnInfoPtr pScrn) +{ + unsigned char i, tmp; + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + int vgaCRIndex = hwp->IOBase + VGA_CRTC_INDEX_OFFSET; + int vgaCRReg = hwp->IOBase + VGA_CRTC_DATA_OFFSET; + int vgaStatus = hwp->IOBase + VGA_IN_STAT_1_OFFSET; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "START register dump ------------------\n"); + + xf86ErrorFVerb(VERBLEV, "MISCELLANEOUS OUTPUT\n %02X\n", + VGAIN8(pSmi, VGA_MISC_OUT_R)); + + xf86ErrorFVerb(VERBLEV, "\nSEQUENCER\n" + " x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF"); + for (i = 0x00; i <= 0xAF; i++) + { + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " "); + xf86ErrorFVerb(VERBLEV, "%02X ", + VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, i)); + } + + xf86ErrorFVerb(VERBLEV, "\n\nCRT CONTROLLER\n" + " x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF"); + for (i = 0x00; i <= 0xAD; i++) + { + if (i == 0x20) i = 0x30; + if (i == 0x50) i = 0x90; + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " "); + xf86ErrorFVerb(VERBLEV, "%02X ", + VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRReg, i)); + } + + xf86ErrorFVerb(VERBLEV, "\n\nGRAPHICS CONTROLLER\n" + " x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF"); + for (i = 0x00; i <= 0x08; i++) + { + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " "); + xf86ErrorFVerb(VERBLEV, "%02X ", + VGAIN8_INDEX(pSmi, VGA_GRAPH_INDEX, VGA_GRAPH_DATA, i)); + } + + xf86ErrorFVerb(VERBLEV, "\n\nATTRIBUTE 0CONTROLLER\n" + " x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF"); + for (i = 0x00; i <= 0x14; i++) + { + tmp = VGAIN8(pSmi, vgaStatus); + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " "); + xf86ErrorFVerb(VERBLEV, "%02X ", + VGAIN8_INDEX(pSmi, VGA_ATTR_INDEX, VGA_ATTR_DATA_R, i)); + } + tmp = VGAIN8(pSmi, vgaStatus); + VGAOUT8(pSmi, VGA_ATTR_INDEX, 0x20); + + xf86ErrorFVerb(VERBLEV, "\n\nDPR x0 x4 x8 xC"); + for (i = 0x00; i <= 0x44; i += 4) + { + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + xf86ErrorFVerb(VERBLEV, " %08X", READ_DPR(pSmi, i)); + } + + xf86ErrorFVerb(VERBLEV, "\n\nVPR x0 x4 x8 xC"); + for (i = 0x00; i <= 0x60; i += 4) + { + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + xf86ErrorFVerb(VERBLEV, " %08X", READ_VPR(pSmi, i)); + } + + xf86ErrorFVerb(VERBLEV, "\n\nCPR x0 x4 x8 xC"); + for (i = 0x00; i <= 0x18; i += 4) + { + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + xf86ErrorFVerb(VERBLEV, " %08X", READ_CPR(pSmi, i)); + } + + xf86ErrorFVerb(VERBLEV, "\n\n"); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "END register dump --------------------\n"); +} + +/* + * SMI_DisplayPowerManagementSet -- Sets VESA Display Power Management + * Signaling (DPMS) Mode. + */ +static void +SMI_DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, + int flags) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + CARD8 SR01, SR20, SR21, SR22, SR23, SR24, SR31, SR34; + + ENTER_PROC("SMI_DisplayPowerManagementSet"); + + /* If we already are in the requested DPMS mode, just return */ + if (pSmi->CurrentDPMS == PowerManagementMode) + { + LEAVE_PROC("SMI_DisplayPowerManagementSet"); + return; + } + +#if 1 /* PDR#735 */ + if (pSmi->pInt10 != NULL) + { + pSmi->pInt10->ax = 0x4F10; + switch (PowerManagementMode) + { + case DPMSModeOn: + pSmi->pInt10->bx = 0x0001; + break; + + case DPMSModeStandby: + pSmi->pInt10->bx = 0x0101; + break; + + case DPMSModeSuspend: + pSmi->pInt10->bx = 0x0201; + break; + + case DPMSModeOff: + pSmi->pInt10->bx = 0x0401; + break; + } + pSmi->pInt10->cx = 0x0000; + pSmi->pInt10->num = 0x10; + xf86ExecX86int10(pSmi->pInt10); + if (pSmi->pInt10->ax == 0x004F) + { + pSmi->CurrentDPMS = PowerManagementMode; +#if 1 /* PDR#835 */ + if (PowerManagementMode == DPMSModeOn) + { + SR01 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01, + SR01 & ~0x20); + } +#endif + LEAVE_PROC("SMI_DisplayPowerManagementSet"); + return; + } + } +#endif + + /* Save the current SR registers */ + if (pSmi->CurrentDPMS == DPMSModeOn) + { + pSmi->DPMS_SR20 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20); + pSmi->DPMS_SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21); + pSmi->DPMS_SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31); + pSmi->DPMS_SR34 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34); + } + + /* Read the required SR registers for the DPMS handler */ + SR01 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01); + SR20 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20); + SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21); + SR22 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22); + SR23 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23); + SR24 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x24); + SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31); + SR34 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34); + + switch (PowerManagementMode) + { + case DPMSModeOn: + /* Screen On: HSync: On, VSync : On */ + SR01 &= ~0x20; + SR20 = pSmi->DPMS_SR20; + SR21 = pSmi->DPMS_SR21; + SR22 &= ~0x30; + SR23 &= ~0xC0; + SR24 |= 0x01; + SR31 = pSmi->DPMS_SR31; + SR34 = pSmi->DPMS_SR34; + break; + + case DPMSModeStandby: + /* Screen: Off; HSync: Off, VSync: On */ + SR01 |= 0x20; + SR20 = (SR20 & ~0xB0) | 0x10; + SR21 |= 0x88; + SR22 = (SR22 & ~0x30) | 0x10; + SR23 = (SR23 & ~0x07) | 0xD8; + SR24 &= ~0x01; + SR31 = (SR31 & ~0x07) | 0x00; + SR34 |= 0x80; + break; + + case DPMSModeSuspend: + /* Screen: Off; HSync: On, VSync: Off */ + SR01 |= 0x20; + SR20 = (SR20 & ~0xB0) | 0x10; + SR21 |= 0x88; + SR22 = (SR22 & ~0x30) | 0x20; + SR23 = (SR23 & ~0x07) | 0xD8; + SR24 &= ~0x01; + SR31 = (SR31 & ~0x07) | 0x00; + SR34 |= 0x80; + break; + + case DPMSModeOff: + /* Screen: Off; HSync: Off, VSync: Off */ + SR01 |= 0x20; + SR20 = (SR20 & ~0xB0) | 0x10; + SR21 |= 0x88; + SR22 = (SR22 & ~0x30) | 0x30; + SR23 = (SR23 & ~0x07) | 0xD8; + SR24 &= ~0x01; + SR31 = (SR31 & ~0x07) | 0x00; + SR34 |= 0x80; + break; + + default: + xf86ErrorFVerb(VERBLEV, "Invalid PowerManagementMode %d passed to " + "SMI_DisplayPowerManagementSet\n", PowerManagementMode); + LEAVE_PROC("SMI_DisplayPowerManagementSet"); + return; + } + + /* Wait for vertical retrace */ + while (hwp->readST01(hwp) & 0x8) ; + while (!(hwp->readST01(hwp) & 0x8)) ; + + /* Write the registers */ + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01, SR01); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34, SR34); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, SR31); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20, SR20); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22, SR22); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23, SR23); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, SR21); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x24, SR24); + + /* Save the current power state */ + pSmi->CurrentDPMS = PowerManagementMode; + + LEAVE_PROC("SMI_DisplayPowerManagementSet"); +} + +static void +SMI_ProbeDDC(ScrnInfoPtr pScrn, int index) +{ + vbeInfoPtr pVbe; + if (xf86LoadSubModule(pScrn, "vbe")) + { + pVbe = VBEInit(NULL, index); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); + vbeFree(pVbe); + } +} + +static unsigned int +SMI_ddc1Read(ScrnInfoPtr pScrn) +{ + register vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + unsigned int ret; + + ENTER_PROC("SMI_ddc1Read"); + + while (hwp->readST01(hwp) & 0x8) ; + while (!(hwp->readST01(hwp) & 0x8)) ; + + ret = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72) & 0x08; + + LEAVE_PROC("SMI_ddc1Read"); + return(ret); +} + +static Bool +SMI_ddc1(int scrnIndex) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + SMIPtr pSmi = SMIPTR(pScrn); + Bool success = FALSE; + xf86MonPtr pMon; + unsigned char tmp; + + ENTER_PROC("SMI_ddc1"); + + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, tmp | 0x20); + + pMon = xf86PrintEDID(xf86DoEDID_DDC1(scrnIndex, vgaHWddc1SetSpeed, + SMI_ddc1Read)); + if (pMon != NULL) + { + success = TRUE; + } + xf86SetDDCproperties(pScrn, pMon); + + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, tmp); + + LEAVE_PROC("SMI_ddc1"); + return(success); +} -- cgit v1.2.3