smi_driver.c revision 09885543
109885543Smrg/* Header:   //Mercury/Projects/archives/XFree86/4.0/smi_driver.c-arc   1.42   03 Jan 2001 13:52:16   Frido  $ */
209885543Smrg
309885543Smrg/*
409885543SmrgCopyright (C) 1994-1999 The XFree86 Project, Inc.  All Rights Reserved.
509885543SmrgCopyright (C) 2000 Silicon Motion, Inc.  All Rights Reserved.
609885543Smrg
709885543SmrgPermission is hereby granted, free of charge, to any person obtaining a copy of
809885543Smrgthis software and associated documentation files (the "Software"), to deal in
909885543Smrgthe Software without restriction, including without limitation the rights to
1009885543Smrguse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
1109885543Smrgof the Software, and to permit persons to whom the Software is furnished to do
1209885543Smrgso, subject to the following conditions:
1309885543Smrg
1409885543SmrgThe above copyright notice and this permission notice shall be included in all
1509885543Smrgcopies or substantial portions of the Software.
1609885543Smrg
1709885543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1809885543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
1909885543SmrgNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
2009885543SmrgXFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2109885543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2209885543SmrgWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2309885543Smrg
2409885543SmrgExcept as contained in this notice, the names of The XFree86 Project and
2509885543SmrgSilicon Motion shall not be used in advertising or otherwise to promote the
2609885543Smrgsale, use or other dealings in this Software without prior written
2709885543Smrgauthorization from The XFree86 Project or Silicon Motion.
2809885543Smrg*/
2909885543Smrg/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_driver.c,v 1.36tsi Exp $ */
3009885543Smrg
3109885543Smrg#ifdef HAVE_CONFIG_H
3209885543Smrg#include "config.h"
3309885543Smrg#endif
3409885543Smrg
3509885543Smrg#include "xf86Resources.h"
3609885543Smrg#include "xf86RAC.h"
3709885543Smrg#include "xf86DDC.h"
3809885543Smrg#include "xf86int10.h"
3909885543Smrg#include "vbe.h"
4009885543Smrg#include "shadowfb.h"
4109885543Smrg
4209885543Smrg#include "smi.h"
4309885543Smrg
4409885543Smrg#include "globals.h"
4509885543Smrg#define DPMS_SERVER
4609885543Smrg#include <X11/extensions/dpms.h>
4709885543Smrg
4809885543Smrg/*
4909885543Smrg * Internals
5009885543Smrg */
5109885543Smrgstatic void SMI_EnableMmio(ScrnInfoPtr pScrn);
5209885543Smrgstatic void SMI_DisableMmio(ScrnInfoPtr pScrn);
5309885543Smrg
5409885543Smrg/*
5509885543Smrg * Forward definitions for the functions that make up the driver.
5609885543Smrg */
5709885543Smrg
5809885543Smrgstatic const OptionInfoRec * SMI_AvailableOptions(int chipid, int busid);
5909885543Smrgstatic void SMI_Identify(int flags);
6009885543Smrgstatic Bool SMI_Probe(DriverPtr drv, int flags);
6109885543Smrgstatic Bool SMI_PreInit(ScrnInfoPtr pScrn, int flags);
6209885543Smrgstatic Bool SMI_EnterVT(int scrnIndex, int flags);
6309885543Smrgstatic void SMI_LeaveVT(int scrnIndex, int flags);
6409885543Smrgstatic void SMI_Save (ScrnInfoPtr pScrn);
6509885543Smrgstatic void SMI_WriteMode (ScrnInfoPtr pScrn, vgaRegPtr, SMIRegPtr);
6609885543Smrgstatic Bool SMI_ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
6709885543Smrg                           char **argv);
6809885543Smrgstatic int SMI_InternalScreenInit(int scrnIndex, ScreenPtr pScreen);
6909885543Smrgstatic void SMI_PrintRegs(ScrnInfoPtr);
7009885543Smrgstatic ModeStatus SMI_ValidMode(int scrnIndex, DisplayModePtr mode,
7109885543Smrg                                Bool verbose, int flags);
7209885543Smrgstatic void SMI_DisableVideo(ScrnInfoPtr pScrn);
7309885543Smrgstatic void SMI_EnableVideo(ScrnInfoPtr pScrn);
7409885543Smrgstatic Bool SMI_MapMem(ScrnInfoPtr pScrn);
7509885543Smrgstatic void SMI_UnmapMem(ScrnInfoPtr pScrn);
7609885543Smrgstatic Bool SMI_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
7709885543Smrgstatic Bool SMI_CloseScreen(int scrnIndex, ScreenPtr pScreen);
7809885543Smrgstatic Bool SMI_SaveScreen(ScreenPtr pScreen, int mode);
7909885543Smrgstatic void SMI_LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies,
8009885543Smrg                            LOCO *colors, VisualPtr pVisual);
8109885543Smrgstatic void SMI_DisplayPowerManagementSet(ScrnInfoPtr pScrn,
8209885543Smrg                                          int PowerManagementMode, int flags);
8309885543Smrgstatic Bool SMI_ddc1(int scrnIndex);
8409885543Smrgstatic unsigned int SMI_ddc1Read(ScrnInfoPtr pScrn);
8509885543Smrgstatic void SMI_FreeScreen(int ScrnIndex, int flags);
8609885543Smrgstatic void SMI_ProbeDDC(ScrnInfoPtr pScrn, int index);
8709885543Smrgstatic void SMI_DetectPanelSize(ScrnInfoPtr pScrn);
8809885543Smrg
8909885543Smrg
9009885543Smrg#define SILICONMOTION_NAME          "Silicon Motion"
9109885543Smrg#define SILICONMOTION_DRIVER_NAME   "siliconmotion"
9209885543Smrg#define SILICONMOTION_VERSION_NAME  "1.4.1"
9309885543Smrg#define SILICONMOTION_VERSION_MAJOR 1
9409885543Smrg#define SILICONMOTION_VERSION_MINOR 4
9509885543Smrg#define SILICONMOTION_PATCHLEVEL    1
9609885543Smrg#define SILICONMOTION_DRIVER_VERSION ((SILICONMOTION_VERSION_MAJOR << 24) | \
9709885543Smrg                                      (SILICONMOTION_VERSION_MINOR << 16) | \
9809885543Smrg                                      (SILICONMOTION_PATCHLEVEL))
9909885543Smrg
10009885543Smrg/*
10109885543Smrg * This contains the functions needed by the server after loading the
10209885543Smrg * driver module.  It must be supplied, and gets added the driver list by
10309885543Smrg * the Module Setup funtion in the dynamic case.  In the static case a
10409885543Smrg * reference to this is compiled in, and this requires that the name of
10509885543Smrg * this DriverRec be an upper-case version of the driver name.
10609885543Smrg */
10709885543Smrg
10809885543Smrg_X_EXPORT DriverRec SILICONMOTION =
10909885543Smrg{
11009885543Smrg    SILICONMOTION_DRIVER_VERSION,
11109885543Smrg    SILICONMOTION_DRIVER_NAME,
11209885543Smrg    SMI_Identify,
11309885543Smrg    SMI_Probe,
11409885543Smrg    SMI_AvailableOptions,
11509885543Smrg    NULL,
11609885543Smrg    0
11709885543Smrg};
11809885543Smrg
11909885543Smrg/* Supported chipsets */
12009885543Smrgstatic SymTabRec SMIChipsets[] =
12109885543Smrg{
12209885543Smrg    { PCI_CHIP_SMI910, "Lynx"    },
12309885543Smrg    { PCI_CHIP_SMI810, "LynxE"   },
12409885543Smrg    { PCI_CHIP_SMI820, "Lynx3D"  },
12509885543Smrg    { PCI_CHIP_SMI710, "LynxEM"  },
12609885543Smrg    { PCI_CHIP_SMI712, "LynxEM+" },
12709885543Smrg    { PCI_CHIP_SMI720, "Lynx3DM" },
12809885543Smrg    { PCI_CHIP_SMI731, "Cougar3DR" },
12909885543Smrg    { -1,             NULL      }
13009885543Smrg};
13109885543Smrg
13209885543Smrgstatic PciChipsets SMIPciChipsets[] =
13309885543Smrg{
13409885543Smrg    /* numChipset,		PciID,				Resource */
13509885543Smrg    { PCI_CHIP_SMI910,	PCI_CHIP_SMI910,	RES_SHARED_VGA },
13609885543Smrg    { PCI_CHIP_SMI810,	PCI_CHIP_SMI810,	RES_SHARED_VGA },
13709885543Smrg    { PCI_CHIP_SMI820,	PCI_CHIP_SMI820,	RES_SHARED_VGA },
13809885543Smrg    { PCI_CHIP_SMI710,	PCI_CHIP_SMI710,	RES_SHARED_VGA },
13909885543Smrg    { PCI_CHIP_SMI712,	PCI_CHIP_SMI712,	RES_SHARED_VGA },
14009885543Smrg    { PCI_CHIP_SMI720,	PCI_CHIP_SMI720,	RES_SHARED_VGA },
14109885543Smrg    { PCI_CHIP_SMI731,	PCI_CHIP_SMI731,	RES_SHARED_VGA },
14209885543Smrg    { -1,				-1,					RES_UNDEFINED  }
14309885543Smrg};
14409885543Smrg
14509885543Smrgtypedef enum
14609885543Smrg{
14709885543Smrg    OPTION_PCI_BURST,
14809885543Smrg    OPTION_FIFO_CONSERV,
14909885543Smrg    OPTION_FIFO_MODERATE,
15009885543Smrg    OPTION_FIFO_AGGRESSIVE,
15109885543Smrg    OPTION_PCI_RETRY,
15209885543Smrg    OPTION_NOACCEL,
15309885543Smrg    OPTION_MCLK,
15409885543Smrg    OPTION_SHOWCACHE,
15509885543Smrg    OPTION_SWCURSOR,
15609885543Smrg    OPTION_HWCURSOR,
15709885543Smrg    OPTION_SHADOW_FB,
15809885543Smrg    OPTION_ROTATE,
15909885543Smrg    OPTION_VIDEOKEY,
16009885543Smrg    OPTION_BYTESWAP,
16109885543Smrg    /* CZ 26.10.2001: interlaced video */
16209885543Smrg    OPTION_INTERLACED,
16309885543Smrg    /* end CZ */
16409885543Smrg    OPTION_USEBIOS,
16509885543Smrg    OPTION_ZOOMONLCD,
16609885543Smrg    OPTION_DUALHEAD,
16709885543Smrg    OPTION_ACCELMETHOD,
16809885543Smrg    NUMBER_OF_OPTIONS
16909885543Smrg} SMIOpts;
17009885543Smrg
17109885543Smrgstatic const OptionInfoRec SMIOptions[] =
17209885543Smrg{
17309885543Smrg    { OPTION_PCI_BURST,	     "pci_burst",	  OPTV_BOOLEAN, {0}, FALSE },
17409885543Smrg    { OPTION_FIFO_CONSERV,    "fifo_conservative", OPTV_BOOLEAN, {0}, FALSE },
17509885543Smrg    { OPTION_FIFO_MODERATE,   "fifo_moderate",	  OPTV_BOOLEAN, {0}, FALSE },
17609885543Smrg    { OPTION_FIFO_AGGRESSIVE, "fifo_aggressive",	  OPTV_BOOLEAN, {0}, FALSE },
17709885543Smrg    { OPTION_PCI_RETRY,	     "pci_retry",	  OPTV_BOOLEAN, {0}, FALSE },
17809885543Smrg    { OPTION_NOACCEL,	     "NoAccel",		  OPTV_BOOLEAN, {0}, FALSE },
17909885543Smrg    { OPTION_MCLK,	     "set_mclk",	  OPTV_FREQ,	{0}, FALSE },
18009885543Smrg    { OPTION_SHOWCACHE,	     "show_cache",	  OPTV_BOOLEAN, {0}, FALSE },
18109885543Smrg    { OPTION_HWCURSOR,	     "HWCursor",	  OPTV_BOOLEAN, {0}, FALSE },
18209885543Smrg    { OPTION_SWCURSOR,	     "SWCursor",	  OPTV_BOOLEAN, {0}, FALSE },
18309885543Smrg    { OPTION_SHADOW_FB,	     "ShadowFB",	  OPTV_BOOLEAN, {0}, FALSE },
18409885543Smrg    { OPTION_ROTATE,	     "Rotate",		  OPTV_ANYSTR,  {0}, FALSE },
18509885543Smrg    { OPTION_VIDEOKEY,	     "VideoKey",	  OPTV_INTEGER, {0}, FALSE },
18609885543Smrg    { OPTION_BYTESWAP,	     "ByteSwap",	  OPTV_BOOLEAN, {0}, FALSE },
18709885543Smrg    /* CZ 26.10.2001: interlaced video */
18809885543Smrg    { OPTION_INTERLACED,	     "Interlaced",        OPTV_BOOLEAN, {0}, FALSE },
18909885543Smrg    /* end CZ */
19009885543Smrg    { OPTION_USEBIOS,	     "UseBIOS",		  OPTV_BOOLEAN,	{0}, FALSE },
19109885543Smrg    { OPTION_ZOOMONLCD,	     "ZoomOnLCD",	  OPTV_BOOLEAN,	{0}, FALSE },
19209885543Smrg    { OPTION_DUALHEAD,	     "Dualhead",	  OPTV_BOOLEAN,	{0}, FALSE },
19309885543Smrg    { OPTION_ACCELMETHOD,    "AccelMethod",       OPTV_STRING,  {0}, FALSE },
19409885543Smrg    { -1,		     NULL,		  OPTV_NONE,	{0}, FALSE }
19509885543Smrg};
19609885543Smrg
19709885543Smrg/*
19809885543Smrg * Lists of symbols that may/may not be required by this driver.
19909885543Smrg * This allows the loader to know which ones to issue warnings for.
20009885543Smrg *
20109885543Smrg * Note that vgahwSymbols and xaaSymbols are referenced outside the
20209885543Smrg * XFree86LOADER define in later code, so are defined outside of that
20309885543Smrg * define here also.
20409885543Smrg */
20509885543Smrg
20609885543Smrgstatic const char *vgahwSymbols[] =
20709885543Smrg{
20809885543Smrg    "vgaHWCopyReg",
20909885543Smrg    "vgaHWGetHWRec",
21009885543Smrg    "vgaHWGetIOBase",
21109885543Smrg    "vgaHWGetIndex",
21209885543Smrg    "vgaHWInit",
21309885543Smrg    "vgaHWLock",
21409885543Smrg    "vgaHWMapMem",
21509885543Smrg    "vgaHWProtect",
21609885543Smrg    "vgaHWRestore",
21709885543Smrg    "vgaHWSave",
21809885543Smrg    "vgaHWSaveScreen",
21909885543Smrg    "vgaHWSetMmioFuncs",
22009885543Smrg    "vgaHWSetStdFuncs",
22109885543Smrg    "vgaHWUnmapMem",
22209885543Smrg    "vgaHWddc1SetSpeedWeak",
22309885543Smrg    NULL
22409885543Smrg};
22509885543Smrg
22609885543Smrgstatic const char *xaaSymbols[] =
22709885543Smrg{
22809885543Smrg    "XAAGetCopyROP",
22909885543Smrg    "XAACreateInfoRec",
23009885543Smrg    "XAADestroyInfoRec",
23109885543Smrg    "XAAGetFallbackOps",
23209885543Smrg    "XAAInit",
23309885543Smrg    "XAAGetPatternROP",
23409885543Smrg    NULL
23509885543Smrg};
23609885543Smrg
23709885543Smrgstatic const char *exaSymbols[] =
23809885543Smrg{
23909885543Smrg    "exaDriverAlloc",
24009885543Smrg    "exaDriverInit",
24109885543Smrg    "exaDriverFini",
24209885543Smrg    "exaOffscreenAlloc",
24309885543Smrg    "exaOffscreenFree",
24409885543Smrg    "exaGetPixmapPitch",
24509885543Smrg    "exaGetPixmapOffset",
24609885543Smrg    "exaGetPixmapSize",
24709885543Smrg    NULL
24809885543Smrg};
24909885543Smrg
25009885543Smrgstatic const char *ramdacSymbols[] =
25109885543Smrg{
25209885543Smrg    "xf86CreateCursorInfoRec",
25309885543Smrg    "xf86DestroyCursorInfoRec",
25409885543Smrg    "xf86InitCursor",
25509885543Smrg    NULL
25609885543Smrg};
25709885543Smrg
25809885543Smrgstatic const char *ddcSymbols[] =
25909885543Smrg{
26009885543Smrg    "xf86PrintEDID",
26109885543Smrg    "xf86DoEDID_DDC1",
26209885543Smrg    "xf86DoEDID_DDC2",
26309885543Smrg    "xf86SetDDCproperties",
26409885543Smrg    NULL
26509885543Smrg};
26609885543Smrg
26709885543Smrgstatic const char *i2cSymbols[] =
26809885543Smrg{
26909885543Smrg    "xf86CreateI2CBusRec",
27009885543Smrg    "xf86CreateI2CDevRec",
27109885543Smrg    "xf86DestroyI2CBusRec",
27209885543Smrg    "xf86DestroyI2CDevRec",
27309885543Smrg    "xf86I2CBusInit",
27409885543Smrg    "xf86I2CDevInit",
27509885543Smrg    "xf86I2CReadBytes",
27609885543Smrg    "xf86I2CWriteByte",
27709885543Smrg    NULL
27809885543Smrg};
27909885543Smrg
28009885543Smrgstatic const char *shadowSymbols[] =
28109885543Smrg{
28209885543Smrg    "ShadowFBInit",
28309885543Smrg    NULL
28409885543Smrg};
28509885543Smrg
28609885543Smrgstatic const char *int10Symbols[] =
28709885543Smrg{
28809885543Smrg    "xf86ExecX86int10",
28909885543Smrg    "xf86FreeInt10",
29009885543Smrg    "xf86InitInt10",
29109885543Smrg    NULL
29209885543Smrg};
29309885543Smrg
29409885543Smrgstatic const char *vbeSymbols[] =
29509885543Smrg{
29609885543Smrg    "VBEInit",
29709885543Smrg    "vbeDoEDID",
29809885543Smrg    "vbeFree",
29909885543Smrg    NULL
30009885543Smrg};
30109885543Smrg
30209885543Smrgstatic const char *fbSymbols[] =
30309885543Smrg{
30409885543Smrg    "fbPictureInit",
30509885543Smrg    "fbScreenInit",
30609885543Smrg    NULL
30709885543Smrg};
30809885543Smrg
30909885543Smrg#ifdef XFree86LOADER
31009885543Smrg
31109885543Smrgstatic MODULESETUPPROTO(siliconmotionSetup);
31209885543Smrg
31309885543Smrgstatic XF86ModuleVersionInfo SMIVersRec =
31409885543Smrg{
31509885543Smrg    "siliconmotion",
31609885543Smrg    MODULEVENDORSTRING,
31709885543Smrg    MODINFOSTRING1,
31809885543Smrg    MODINFOSTRING2,
31909885543Smrg    XORG_VERSION_CURRENT,
32009885543Smrg    SILICONMOTION_VERSION_MAJOR,
32109885543Smrg    SILICONMOTION_VERSION_MINOR,
32209885543Smrg    SILICONMOTION_PATCHLEVEL,
32309885543Smrg    ABI_CLASS_VIDEODRV,
32409885543Smrg    ABI_VIDEODRV_VERSION,
32509885543Smrg    MOD_CLASS_VIDEODRV,
32609885543Smrg    {0, 0, 0, 0}
32709885543Smrg};
32809885543Smrg
32909885543Smrg/*
33009885543Smrg * This is the module init data for XFree86 modules.
33109885543Smrg *
33209885543Smrg * Its name has to be the driver name followed by ModuleData.
33309885543Smrg */
33409885543Smrg_X_EXPORT XF86ModuleData siliconmotionModuleData =
33509885543Smrg{
33609885543Smrg    &SMIVersRec,
33709885543Smrg    siliconmotionSetup,
33809885543Smrg    NULL
33909885543Smrg};
34009885543Smrg
34109885543Smrgstatic pointer
34209885543SmrgsiliconmotionSetup(pointer module, pointer opts, int *errmaj, int *errmin)
34309885543Smrg{
34409885543Smrg    static Bool setupDone = FALSE;
34509885543Smrg
34609885543Smrg    if (!setupDone) {
34709885543Smrg	setupDone = TRUE;
34809885543Smrg	xf86AddDriver(&SILICONMOTION, module, 0);
34909885543Smrg
35009885543Smrg	/*
35109885543Smrg	 * Modules that this driver always requires can be loaded here
35209885543Smrg	 * by calling LoadSubModule().
35309885543Smrg	 */
35409885543Smrg
35509885543Smrg	/*
35609885543Smrg	 * Tell the loader about symbols from other modules that this module
35709885543Smrg	 * might refer to.
35809885543Smrg	 */
35909885543Smrg	LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols, exaSymbols, ramdacSymbols,
36009885543Smrg					  ddcSymbols, i2cSymbols, int10Symbols, vbeSymbols,
36109885543Smrg					  shadowSymbols, NULL);
36209885543Smrg
36309885543Smrg	/*
36409885543Smrg	 * The return value must be non-NULL on success even though there
36509885543Smrg	 * is no TearDownProc.
36609885543Smrg	 */
36709885543Smrg	return (pointer) 1;
36809885543Smrg
36909885543Smrg    } else {
37009885543Smrg	if (errmaj) {
37109885543Smrg	    *errmaj = LDR_ONCEONLY;
37209885543Smrg	}
37309885543Smrg	return NULL;
37409885543Smrg    }
37509885543Smrg}
37609885543Smrg
37709885543Smrg#endif /* XFree86LOADER */
37809885543Smrg
37909885543Smrgstatic Bool
38009885543SmrgSMI_GetRec(ScrnInfoPtr pScrn)
38109885543Smrg{
38209885543Smrg    ENTER_PROC("SMI_GetRec");
38309885543Smrg
38409885543Smrg    /*
38509885543Smrg     * Allocate an 'Chip'Rec, and hook it into pScrn->driverPrivate.
38609885543Smrg     * pScrn->driverPrivate is initialised to NULL, so we can check if
38709885543Smrg     * the allocation has already been done.
38809885543Smrg     */
38909885543Smrg    if (pScrn->driverPrivate == NULL) {
39009885543Smrg	pScrn->driverPrivate = xnfcalloc(sizeof(SMIRec), 1);
39109885543Smrg    }
39209885543Smrg
39309885543Smrg    LEAVE_PROC("SMI_GetRec");
39409885543Smrg    return TRUE;
39509885543Smrg}
39609885543Smrg
39709885543Smrgstatic void
39809885543SmrgSMI_FreeRec(ScrnInfoPtr pScrn)
39909885543Smrg{
40009885543Smrg    ENTER_PROC("SMI_FreeRec");
40109885543Smrg
40209885543Smrg    if (pScrn->driverPrivate != NULL) {
40309885543Smrg	xfree(pScrn->driverPrivate);
40409885543Smrg	pScrn->driverPrivate = NULL;
40509885543Smrg    }
40609885543Smrg
40709885543Smrg    LEAVE_PROC("SMI_FreeRec");
40809885543Smrg}
40909885543Smrg
41009885543Smrgstatic const OptionInfoRec *
41109885543SmrgSMI_AvailableOptions(int chipid, int busid)
41209885543Smrg{
41309885543Smrg    ENTER_PROC("SMI_AvailableOptions");
41409885543Smrg    LEAVE_PROC("SMI_AvailableOptions");
41509885543Smrg    return SMIOptions;
41609885543Smrg}
41709885543Smrg
41809885543Smrgstatic void
41909885543SmrgSMI_Identify(int flags)
42009885543Smrg{
42109885543Smrg    ENTER_PROC("SMI_Identify");
42209885543Smrg
42309885543Smrg    xf86PrintChipsets(SILICONMOTION_NAME, "driver (version "
42409885543Smrg		SILICONMOTION_VERSION_NAME ") for Silicon Motion Lynx chipsets",
42509885543Smrg		SMIChipsets);
42609885543Smrg
42709885543Smrg    LEAVE_PROC("SMI_Identify");
42809885543Smrg}
42909885543Smrg
43009885543Smrgstatic Bool
43109885543SmrgSMI_Probe(DriverPtr drv, int flags)
43209885543Smrg{
43309885543Smrg    int i;
43409885543Smrg    GDevPtr *devSections;
43509885543Smrg    int *usedChips;
43609885543Smrg    int numDevSections;
43709885543Smrg    int numUsed;
43809885543Smrg    Bool foundScreen = FALSE;
43909885543Smrg
44009885543Smrg    ENTER_PROC("SMI_Probe");
44109885543Smrg
44209885543Smrg    numDevSections = xf86MatchDevice(SILICONMOTION_DRIVER_NAME, &devSections);
44309885543Smrg
44409885543Smrg    if (numDevSections <= 0) {
44509885543Smrg	/* There's no matching device section in the config file, so quit now. */
44609885543Smrg	LEAVE_PROC("SMI_Probe");
44709885543Smrg	return FALSE;
44809885543Smrg    }
44909885543Smrg
45009885543Smrg    if (xf86GetPciVideoInfo() == NULL) {
45109885543Smrg	LEAVE_PROC("SMI_Probe");
45209885543Smrg	return FALSE;
45309885543Smrg    }
45409885543Smrg
45509885543Smrg    numUsed = xf86MatchPciInstances(SILICONMOTION_NAME, PCI_SMI_VENDOR_ID,
45609885543Smrg				    SMIChipsets, SMIPciChipsets, devSections,
45709885543Smrg				    numDevSections, drv, &usedChips);
45809885543Smrg
45909885543Smrg    /* Free it since we don't need that list after this */
46009885543Smrg    xfree(devSections);
46109885543Smrg    if (numUsed <= 0) {
46209885543Smrg	LEAVE_PROC("SMI_Probe");
46309885543Smrg	return FALSE;
46409885543Smrg    }
46509885543Smrg
46609885543Smrg    if (flags & PROBE_DETECT) {
46709885543Smrg		foundScreen = TRUE;
46809885543Smrg    } else {
46909885543Smrg	for (i = 0; i < numUsed; i++) {
47009885543Smrg	    /* Allocate a ScrnInfoRec and claim the slot */
47109885543Smrg	    ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0);
47209885543Smrg
47309885543Smrg	    /* Fill in what we can of the ScrnInfoRec */
47409885543Smrg	    pScrn->driverVersion = SILICONMOTION_DRIVER_VERSION;
47509885543Smrg	    pScrn->driverName	 = SILICONMOTION_DRIVER_NAME;
47609885543Smrg	    pScrn->name		 = SILICONMOTION_NAME;
47709885543Smrg	    pScrn->Probe	 = SMI_Probe;
47809885543Smrg	    pScrn->PreInit	 = SMI_PreInit;
47909885543Smrg	    pScrn->ScreenInit	 = SMI_ScreenInit;
48009885543Smrg	    pScrn->SwitchMode	 = SMI_SwitchMode;
48109885543Smrg	    pScrn->AdjustFrame	 = SMI_AdjustFrame;
48209885543Smrg	    pScrn->EnterVT	 = SMI_EnterVT;
48309885543Smrg	    pScrn->LeaveVT	 = SMI_LeaveVT;
48409885543Smrg	    pScrn->FreeScreen	 = SMI_FreeScreen;
48509885543Smrg	    pScrn->ValidMode	 = SMI_ValidMode;
48609885543Smrg	    foundScreen		 = TRUE;
48709885543Smrg
48809885543Smrg	    xf86ConfigActivePciEntity(pScrn, usedChips[i], SMIPciChipsets, NULL,
48909885543Smrg				      NULL, NULL, NULL, NULL);
49009885543Smrg	}
49109885543Smrg    }
49209885543Smrg    xfree(usedChips);
49309885543Smrg
49409885543Smrg    LEAVE_PROC("SMI_Probe");
49509885543Smrg    return foundScreen;
49609885543Smrg}
49709885543Smrg
49809885543Smrgstatic Bool
49909885543SmrgSMI_PreInit(ScrnInfoPtr pScrn, int flags)
50009885543Smrg{
50109885543Smrg    EntityInfoPtr pEnt;
50209885543Smrg    SMIPtr pSmi;
50309885543Smrg    MessageType from;
50409885543Smrg    int i;
50509885543Smrg    double real;
50609885543Smrg    ClockRangePtr clockRanges;
50709885543Smrg    char *s;
50809885543Smrg    unsigned char config, m, n, shift;
50909885543Smrg    int mclk;
51009885543Smrg    vgaHWPtr hwp;
51109885543Smrg    int vgaCRIndex, vgaIOBase;
51209885543Smrg    vbeInfoPtr pVbe = NULL;
51309885543Smrg
51409885543Smrg    ENTER_PROC("SMI_PreInit");
51509885543Smrg
51609885543Smrg    if (flags & PROBE_DETECT) {
51709885543Smrg	SMI_ProbeDDC(pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index);
51809885543Smrg	LEAVE_PROC("SMI_PreInit");
51909885543Smrg	return TRUE;
52009885543Smrg    }
52109885543Smrg
52209885543Smrg    /* Ignoring the Type list for now.  It might be needed when multiple cards
52309885543Smrg     * are supported.
52409885543Smrg     */
52509885543Smrg    if (pScrn->numEntities > 1) {
52609885543Smrg	LEAVE_PROC("SMI_PreInit");
52709885543Smrg	return FALSE;
52809885543Smrg    }
52909885543Smrg
53009885543Smrg    /* The vgahw module should be loaded here when needed */
53109885543Smrg    if (!xf86LoadSubModule(pScrn, "vgahw")) {
53209885543Smrg	LEAVE_PROC("SMI_PreInit");
53309885543Smrg	return FALSE;
53409885543Smrg    }
53509885543Smrg
53609885543Smrg    xf86LoaderReqSymLists(vgahwSymbols, NULL);
53709885543Smrg
53809885543Smrg    /*
53909885543Smrg     * Allocate a vgaHWRec
54009885543Smrg     */
54109885543Smrg    if (!vgaHWGetHWRec(pScrn)) {
54209885543Smrg	LEAVE_PROC("SMI_PreInit");
54309885543Smrg	return FALSE;
54409885543Smrg    }
54509885543Smrg
54609885543Smrg    /* Allocate the SMIRec driverPrivate */
54709885543Smrg    if (!SMI_GetRec(pScrn)) {
54809885543Smrg	LEAVE_PROC("SMI_PreInit");
54909885543Smrg	return FALSE;
55009885543Smrg    }
55109885543Smrg    pSmi = SMIPTR(pScrn);
55209885543Smrg
55309885543Smrg    /* Set pScrn->monitor */
55409885543Smrg    pScrn->monitor = pScrn->confScreen->monitor;
55509885543Smrg
55609885543Smrg    /*
55709885543Smrg     * The first thing we should figure out is the depth, bpp, etc.
55809885543Smrg     */
55909885543Smrg    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb)) {
56009885543Smrg	LEAVE_PROC("SMI_PreInit");
56109885543Smrg	return FALSE;
56209885543Smrg    }
56309885543Smrg
56409885543Smrg    /* Check that the returned depth is one we support */
56509885543Smrg    switch (pScrn->depth) {
56609885543Smrg    case 8:
56709885543Smrg    case 16:
56809885543Smrg    case 24:
56909885543Smrg	/* OK */
57009885543Smrg	break;
57109885543Smrg
57209885543Smrg    default:
57309885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
57409885543Smrg		   "Given depth (%d) is not supported by this driver\n",
57509885543Smrg		   pScrn->depth);
57609885543Smrg	LEAVE_PROC("SMI_PreInit");
57709885543Smrg	return FALSE;
57809885543Smrg    }
57909885543Smrg
58009885543Smrg    xf86PrintDepthBpp(pScrn);
58109885543Smrg
58209885543Smrg    /*
58309885543Smrg     * This must happen after pScrn->display has been set because
58409885543Smrg     * xf86SetWeight references it.
58509885543Smrg     */
58609885543Smrg    if (pScrn->depth > 8) {
58709885543Smrg	/* The defaults are OK for us */
58809885543Smrg	rgb zeros = {0, 0, 0};
58909885543Smrg
59009885543Smrg	if (!xf86SetWeight(pScrn, zeros, zeros)) {
59109885543Smrg	    LEAVE_PROC("SMI_PreInit");
59209885543Smrg	    return FALSE;
59309885543Smrg	}
59409885543Smrg    }
59509885543Smrg
59609885543Smrg    if (!xf86SetDefaultVisual(pScrn, -1)) {
59709885543Smrg	LEAVE_PROC("SMI_PreInit");
59809885543Smrg	return FALSE;
59909885543Smrg    }
60009885543Smrg
60109885543Smrg    /* We don't currently support DirectColor at > 8bpp */
60209885543Smrg    if ((pScrn->depth > 8) && (pScrn->defaultVisual != TrueColor)) {
60309885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual (%s) "
60409885543Smrg		   "is not supported at depth %d\n",
60509885543Smrg		   xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
60609885543Smrg	LEAVE_PROC("SMI_PreInit");
60709885543Smrg	return FALSE;
60809885543Smrg    }
60909885543Smrg
61009885543Smrg    /* We use a programmable clock */
61109885543Smrg    pScrn->progClock = TRUE;
61209885543Smrg
61309885543Smrg    /* Collect all of the relevant option flags (fill in pScrn->options) */
61409885543Smrg    xf86CollectOptions(pScrn, NULL);
61509885543Smrg
61609885543Smrg    /* Set the bits per RGB for 8bpp mode */
61709885543Smrg    if (pScrn->depth == 8) {
61809885543Smrg	pScrn->rgbBits = 6;
61909885543Smrg    }
62009885543Smrg
62109885543Smrg    /* Process the options */
62209885543Smrg    if (!(pSmi->Options = xalloc(sizeof(SMIOptions))))
62309885543Smrg	return FALSE;
62409885543Smrg    memcpy(pSmi->Options, SMIOptions, sizeof(SMIOptions));
62509885543Smrg    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pSmi->Options);
62609885543Smrg
62709885543Smrg    if (xf86ReturnOptValBool(pSmi->Options, OPTION_PCI_BURST, FALSE)) {
62809885543Smrg	pSmi->pci_burst = TRUE;
62909885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_burst - PCI burst "
63009885543Smrg		   "read enabled\n");
63109885543Smrg    } else {
63209885543Smrg	pSmi->pci_burst = FALSE;
63309885543Smrg    }
63409885543Smrg
63509885543Smrg    pSmi->NoPCIRetry = TRUE;
63609885543Smrg    if (xf86ReturnOptValBool(pSmi->Options, OPTION_PCI_RETRY, FALSE)) {
63709885543Smrg	if (xf86ReturnOptValBool(pSmi->Options, OPTION_PCI_BURST, FALSE)) {
63809885543Smrg	    pSmi->NoPCIRetry = FALSE;
63909885543Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_retry\n");
64009885543Smrg	} else {
64109885543Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option "
64209885543Smrg		       "requires \"pci_burst\".\n");
64309885543Smrg	}
64409885543Smrg    }
64509885543Smrg
64609885543Smrg    if (xf86IsOptionSet(pSmi->Options, OPTION_FIFO_CONSERV)) {
64709885543Smrg	pSmi->fifo_conservative = TRUE;
64809885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_conservative "
64909885543Smrg		   "set\n");
65009885543Smrg    } else {
65109885543Smrg	pSmi->fifo_conservative = FALSE;
65209885543Smrg    }
65309885543Smrg
65409885543Smrg    if (xf86IsOptionSet(pSmi->Options, OPTION_FIFO_MODERATE)) {
65509885543Smrg	pSmi->fifo_moderate = TRUE;
65609885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_moderate set\n");
65709885543Smrg    } else {
65809885543Smrg	pSmi->fifo_moderate = FALSE;
65909885543Smrg    }
66009885543Smrg
66109885543Smrg    if (xf86IsOptionSet(pSmi->Options, OPTION_FIFO_AGGRESSIVE)) {
66209885543Smrg	pSmi->fifo_aggressive = TRUE;
66309885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_aggressive set\n");
66409885543Smrg    } else {
66509885543Smrg	pSmi->fifo_aggressive = FALSE;
66609885543Smrg    }
66709885543Smrg
66809885543Smrg    if (xf86ReturnOptValBool(pSmi->Options, OPTION_NOACCEL, FALSE)) {
66909885543Smrg	pSmi->NoAccel = TRUE;
67009885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: NoAccel - Acceleration "
67109885543Smrg		   "disabled\n");
67209885543Smrg    } else {
67309885543Smrg	pSmi->NoAccel = FALSE;
67409885543Smrg    }
67509885543Smrg
67609885543Smrg    if (xf86ReturnOptValBool(pSmi->Options, OPTION_SHOWCACHE, FALSE)) {
67709885543Smrg	pSmi->ShowCache = TRUE;
67809885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: show_cache set\n");
67909885543Smrg    } else {
68009885543Smrg	pSmi->ShowCache = FALSE;
68109885543Smrg    }
68209885543Smrg
68309885543Smrg    if (xf86GetOptValFreq(pSmi->Options, OPTION_MCLK, OPTUNITS_MHZ, &real)) {
68409885543Smrg	pSmi->MCLK = (int)(real * 1000.0);
68509885543Smrg	if (pSmi->MCLK <= 120000) {
68609885543Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: set_mclk set to "
68709885543Smrg		       "%1.3f MHz\n", pSmi->MCLK / 1000.0);
68809885543Smrg	} else {
68909885543Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Memory Clock value of "
69009885543Smrg		       "%1.3f MHz is larger than limit of 120 MHz\n",
69109885543Smrg		       pSmi->MCLK / 1000.0);
69209885543Smrg	    pSmi->MCLK = 0;
69309885543Smrg	}
69409885543Smrg    } else {
69509885543Smrg	pSmi->MCLK = 0;
69609885543Smrg    }
69709885543Smrg
69809885543Smrg    from = X_DEFAULT;
69909885543Smrg    pSmi->hwcursor = TRUE;
70009885543Smrg    if (xf86GetOptValBool(pSmi->Options, OPTION_HWCURSOR, &pSmi->hwcursor)) {
70109885543Smrg	from = X_CONFIG;
70209885543Smrg    }
70309885543Smrg    if (xf86ReturnOptValBool(pSmi->Options, OPTION_SWCURSOR, FALSE)) {
70409885543Smrg	pSmi->hwcursor = FALSE;
70509885543Smrg	from = X_CONFIG;
70609885543Smrg    }
70709885543Smrg    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s Cursor\n",
70809885543Smrg	       pSmi->hwcursor ? "Hardware" : "Software");
70909885543Smrg
71009885543Smrg    if (xf86GetOptValBool(pSmi->Options, OPTION_SHADOW_FB, &pSmi->shadowFB)) {
71109885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n",
71209885543Smrg		   pSmi->shadowFB ? "enabled" : "disabled");
71309885543Smrg    }
71409885543Smrg
71509885543Smrg#if 1 /* PDR#932 */
71609885543Smrg    if ((pScrn->depth == 8) || (pScrn->depth == 16))
71709885543Smrg#endif /* PDR#932 */
71809885543Smrg	if ((s = xf86GetOptValString(pSmi->Options, OPTION_ROTATE))) {
71909885543Smrg	    if (!xf86NameCmp(s, "CW")) {
72009885543Smrg		pSmi->shadowFB = TRUE;
72109885543Smrg		pSmi->rotate = SMI_ROTATE_CCW;
72209885543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen "
72309885543Smrg			   "clockwise\n");
72409885543Smrg	    } else if (!xf86NameCmp(s, "CCW")) {
72509885543Smrg		pSmi->shadowFB = TRUE;
72609885543Smrg		pSmi->rotate = SMI_ROTATE_CW;
72709885543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen counter "
72809885543Smrg			   "clockwise\n");
72909885543Smrg	    } else {
73009885543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid "
73109885543Smrg			   "value for Option \"Rotate\"\n", s);
73209885543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid options are \"CW\" or "
73309885543Smrg			   "\"CCW\"\n");
73409885543Smrg	    }
73509885543Smrg	}
73609885543Smrg
73709885543Smrg    if (pSmi->rotate) {
73809885543Smrg	/* Disable the RandR extension, it messes up the internal rotation stuff */
73909885543Smrg	xf86DisableRandR();
74009885543Smrg    }
74109885543Smrg
74209885543Smrg    if (xf86GetOptValInteger(pSmi->Options, OPTION_VIDEOKEY, &pSmi->videoKey)) {
74309885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: Video key set to "
74409885543Smrg		   "0x%08X\n", pSmi->videoKey);
74509885543Smrg    } else {
74609885543Smrg	pSmi->videoKey = (1 << pScrn->offset.red) |
74709885543Smrg			 (1 << pScrn->offset.green) |
74809885543Smrg			 (((pScrn->mask.blue >> pScrn->offset.blue) - 1)
74909885543Smrg			 << pScrn->offset.blue);
75009885543Smrg    }
75109885543Smrg
75209885543Smrg    if (xf86ReturnOptValBool(pSmi->Options, OPTION_BYTESWAP, FALSE)) {
75309885543Smrg	pSmi->ByteSwap = TRUE;
75409885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: ByteSwap enabled.\n");
75509885543Smrg    } else {
75609885543Smrg	pSmi->ByteSwap = FALSE;
75709885543Smrg    }
75809885543Smrg
75909885543Smrg    /* CZ 26.10.2001: interlaced video */
76009885543Smrg    if (xf86ReturnOptValBool(pSmi->Options, OPTION_INTERLACED, FALSE)) {
76109885543Smrg	pSmi->interlaced = TRUE;
76209885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: Interlaced enabled.\n");
76309885543Smrg    } else {
76409885543Smrg	pSmi->interlaced = FALSE;
76509885543Smrg    }
76609885543Smrg    /* end CZ */
76709885543Smrg
76809885543Smrg    if (xf86GetOptValBool(pSmi->Options, OPTION_USEBIOS, &pSmi->useBIOS)) {
76909885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: UseBIOS %s.\n",
77009885543Smrg		   pSmi->useBIOS ? "enabled" : "disabled");
77109885543Smrg    } else {
77209885543Smrg	/* Default to UseBIOS enabled. */
77309885543Smrg	pSmi->useBIOS = TRUE;
77409885543Smrg    }
77509885543Smrg
77609885543Smrg    if (xf86GetOptValBool(pSmi->Options, OPTION_ZOOMONLCD, &pSmi->zoomOnLCD)) {
77709885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: ZoomOnLCD %s.\n",
77809885543Smrg		   pSmi->zoomOnLCD ? "enabled" : "disabled");
77909885543Smrg    } else {
78009885543Smrg	/* Default to ZoomOnLCD enabled. */
78109885543Smrg	pSmi->zoomOnLCD = TRUE;
78209885543Smrg    }
78309885543Smrg
78409885543Smrg    /* Find the PCI slot for this screen */
78509885543Smrg    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
78609885543Smrg    if ((pEnt->location.type != BUS_PCI) || (pEnt->resources)) {
78709885543Smrg	xfree(pEnt);
78809885543Smrg	SMI_FreeRec(pScrn);
78909885543Smrg	LEAVE_PROC("SMI_PreInit");
79009885543Smrg	return FALSE;
79109885543Smrg    }
79209885543Smrg
79309885543Smrg    if (xf86LoadSubModule(pScrn,"int10")) {
79409885543Smrg	xf86LoaderReqSymLists(int10Symbols,NULL);
79509885543Smrg	pSmi->pInt10 = xf86InitInt10(pEnt->index);
79609885543Smrg    }
79709885543Smrg
79809885543Smrg    if (pSmi->pInt10 && xf86LoadSubModule(pScrn, "vbe")) {
79909885543Smrg	xf86LoaderReqSymLists(vbeSymbols, NULL);
80009885543Smrg	pVbe = VBEInit(pSmi->pInt10, pEnt->index);
80109885543Smrg    }
80209885543Smrg
80309885543Smrg    pSmi->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
80409885543Smrg    xf86RegisterResources(pEnt->index, NULL, ResExclusive);
80509885543Smrg/*  xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr); */
80609885543Smrg/*  xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr); */
80709885543Smrg
80809885543Smrg    /*
80909885543Smrg     * Set the Chipset and ChipRev, allowing config file entries to
81009885543Smrg     * override.
81109885543Smrg     */
81209885543Smrg    if (pEnt->device->chipset && *pEnt->device->chipset) {
81309885543Smrg	pScrn->chipset = pEnt->device->chipset;
81409885543Smrg	pSmi->Chipset = xf86StringToToken(SMIChipsets, pScrn->chipset);
81509885543Smrg	from = X_CONFIG;
81609885543Smrg    } else if (pEnt->device->chipID >= 0) {
81709885543Smrg	pSmi->Chipset = pEnt->device->chipID;
81809885543Smrg	pScrn->chipset = (char *) xf86TokenToString(SMIChipsets, pSmi->Chipset);
81909885543Smrg	from = X_CONFIG;
82009885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
82109885543Smrg		   pSmi->Chipset);
82209885543Smrg    } else {
82309885543Smrg	from = X_PROBED;
82409885543Smrg	pSmi->Chipset = pSmi->PciInfo->chipType;
82509885543Smrg	pScrn->chipset = (char *) xf86TokenToString(SMIChipsets, pSmi->Chipset);
82609885543Smrg    }
82709885543Smrg
82809885543Smrg    if (pEnt->device->chipRev >= 0) {
82909885543Smrg	pSmi->ChipRev = pEnt->device->chipRev;
83009885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
83109885543Smrg		   pSmi->ChipRev);
83209885543Smrg    } else {
83309885543Smrg	pSmi->ChipRev = pSmi->PciInfo->chipRev;
83409885543Smrg    }
83509885543Smrg    xfree(pEnt);
83609885543Smrg
83709885543Smrg    /*
83809885543Smrg     * This shouldn't happen because such problems should be caught in
83909885543Smrg     * SMI_Probe(), but check it just in case.
84009885543Smrg     */
84109885543Smrg    if (pScrn->chipset == NULL) {
84209885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ChipID 0x%04X is not "
84309885543Smrg				"recognised\n", pSmi->Chipset);
84409885543Smrg	LEAVE_PROC("SMI_PreInit");
84509885543Smrg	return FALSE;
84609885543Smrg    }
84709885543Smrg
84809885543Smrg    if (pSmi->Chipset < 0) {
84909885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Chipset \"%s\" is not "
85009885543Smrg		   "recognised\n", pScrn->chipset);
85109885543Smrg	LEAVE_PROC("SMI_PreInit");
85209885543Smrg	return FALSE;
85309885543Smrg    }
85409885543Smrg
85509885543Smrg    xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset);
85609885543Smrg
85709885543Smrg    pSmi->PciTag = pciTag(pSmi->PciInfo->bus, pSmi->PciInfo->device,
85809885543Smrg		   	  pSmi->PciInfo->func);
85909885543Smrg
86009885543Smrg    pSmi->Dualhead = FALSE;
86109885543Smrg    if (xf86ReturnOptValBool(pSmi->Options, OPTION_DUALHEAD, FALSE) &&
86209885543Smrg	SMI_LYNXM_SERIES(pSmi->Chipset)) {
86309885543Smrg	pSmi->Dualhead = TRUE;
86409885543Smrg    }
86509885543Smrg
86609885543Smrg    /* tweak options for dualhead */
86709885543Smrg    if (pSmi->Dualhead) {
86809885543Smrg	pSmi->useBIOS = FALSE;
86909885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "UseBIOS disabled in dualhead mode\n");
87009885543Smrg	pSmi->hwcursor = FALSE;
87109885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No hardware cursor in dualhead mode\n");
87209885543Smrg	if (pScrn->bitsPerPixel != 16) {
87309885543Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Dualhead only supported at "
87409885543Smrg		       "depth 16\n");
87509885543Smrg	    return FALSE;
87609885543Smrg	}
87709885543Smrg    }
87809885543Smrg
87909885543Smrg    SMI_MapMem(pScrn);
88009885543Smrg    SMI_DisableVideo(pScrn);
88109885543Smrg
88209885543Smrg    hwp = VGAHWPTR(pScrn);
88309885543Smrg    vgaIOBase  = hwp->IOBase;
88409885543Smrg    vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
88509885543Smrg    pSmi->PIOBase = hwp->PIOOffset;
88609885543Smrg
88709885543Smrg    xf86ErrorFVerb(VERBLEV, "\tSMI_PreInit vgaCRIndex=%x, vgaIOBase=%x, "
88809885543Smrg		   "MMIOBase=%p\n", vgaCRIndex, vgaIOBase, hwp->MMIOBase);
88909885543Smrg
89009885543Smrg    /* detect the panel size */
89109885543Smrg    SMI_DetectPanelSize(pScrn);
89209885543Smrg
89309885543Smrg    if (xf86LoadSubModule(pScrn, "i2c")) {
89409885543Smrg	xf86LoaderReqSymLists(i2cSymbols, NULL);
89509885543Smrg	SMI_I2CInit(pScrn);
89609885543Smrg    }
89709885543Smrg
89809885543Smrg    if (xf86LoadSubModule(pScrn, "ddc")) {
89909885543Smrg	xf86MonPtr pMon = NULL;
90009885543Smrg
90109885543Smrg	xf86LoaderReqSymLists(ddcSymbols, NULL);
90209885543Smrg#if 1 /* PDR#579 */
90309885543Smrg	if (pVbe) {
90409885543Smrg	    pMon = vbeDoEDID(pVbe, NULL);
90509885543Smrg	    if (pMon != NULL) {
90609885543Smrg		if ((pMon->rawData[0] == 0x00) &&
90709885543Smrg		    (pMon->rawData[1] == 0xFF) &&
90809885543Smrg		    (pMon->rawData[2] == 0xFF) &&
90909885543Smrg		    (pMon->rawData[3] == 0xFF) &&
91009885543Smrg		    (pMon->rawData[4] == 0xFF) &&
91109885543Smrg		    (pMon->rawData[5] == 0xFF) &&
91209885543Smrg		    (pMon->rawData[6] == 0xFF) &&
91309885543Smrg		    (pMon->rawData[7] == 0x00)) {
91409885543Smrg		    pMon = xf86PrintEDID(pMon);
91509885543Smrg		    if (pMon != NULL) {
91609885543Smrg			xf86SetDDCproperties(pScrn, pMon);
91709885543Smrg		    }
91809885543Smrg		}
91909885543Smrg	    }
92009885543Smrg#else
92109885543Smrg	if ((pVbe) &&
92209885543Smrg	    ((pMon = xf86PrintEDID(vbeDoEDID(pVbe, NULL))) != NULL)) {
92309885543Smrg	    xf86SetDDCproperties(pScrn, pMon);
92409885543Smrg#endif
92509885543Smrg    	} else if (!SMI_ddc1(pScrn->scrnIndex)) {
92609885543Smrg	    if (pSmi->I2C) {
92709885543Smrg	    	xf86SetDDCproperties(pScrn,
92809885543Smrg			xf86PrintEDID(xf86DoEDID_DDC2(pScrn->scrnIndex,
92909885543Smrg			pSmi->I2C)));
93009885543Smrg	    }
93109885543Smrg    	}
93209885543Smrg    }
93309885543Smrg
93409885543Smrg    vbeFree(pVbe);
93509885543Smrg    xf86FreeInt10(pSmi->pInt10);
93609885543Smrg    pSmi->pInt10 = NULL;
93709885543Smrg
93809885543Smrg    /*
93909885543Smrg     * If the driver can do gamma correction, it should call xf86SetGamma()
94009885543Smrg     * here. (from MGA, no ViRGE gamma support yet, but needed for
94109885543Smrg     * xf86HandleColormaps support.)
94209885543Smrg     */
94309885543Smrg    {
94409885543Smrg	Gamma zeros = { 0.0, 0.0, 0.0 };
94509885543Smrg
94609885543Smrg	if (!xf86SetGamma(pScrn, zeros)) {
94709885543Smrg	    LEAVE_PROC("SMI_PreInit");
94809885543Smrg	    SMI_EnableVideo(pScrn);
94909885543Smrg	    SMI_UnmapMem(pScrn);
95009885543Smrg	    return FALSE;
95109885543Smrg	}
95209885543Smrg    }
95309885543Smrg
95409885543Smrg
95509885543Smrg    /* Next go on to detect amount of installed ram */
95609885543Smrg    config = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x71);
95709885543Smrg
95809885543Smrg    /* And compute the amount of video memory and offscreen memory */
95909885543Smrg    pSmi->videoRAMKBytes = 0;
96009885543Smrg
96109885543Smrg    if (!pScrn->videoRam) {
96209885543Smrg	switch (pSmi->Chipset) {
96309885543Smrg	default:
96409885543Smrg	{
96509885543Smrg	    int mem_table[4] = { 1, 2, 4, 0 };
96609885543Smrg	    pSmi->videoRAMKBytes = mem_table[(config >> 6)] * 1024;
96709885543Smrg	    break;
96809885543Smrg	}
96909885543Smrg	case SMI_LYNX3D:
97009885543Smrg	{
97109885543Smrg	    int mem_table[4] = { 0, 2, 4, 6 };
97209885543Smrg	    pSmi->videoRAMKBytes = mem_table[(config >> 6)] * 1024 + 512;
97309885543Smrg	    break;
97409885543Smrg	}
97509885543Smrg	case SMI_LYNX3DM:
97609885543Smrg	{
97709885543Smrg	    int mem_table[4] = { 16, 2, 4, 8 };
97809885543Smrg	    pSmi->videoRAMKBytes = mem_table[(config >> 6)] * 1024;
97909885543Smrg	    break;
98009885543Smrg	}
98109885543Smrg	case SMI_COUGAR3DR:
98209885543Smrg	{
98309885543Smrg	    /* DANGER - Cougar3DR BIOS is broken - hardcode video ram size */
98409885543Smrg	    /* per instructions from Silicon Motion engineers */
98509885543Smrg	    pSmi->videoRAMKBytes = 16 * 1024;
98609885543Smrg	    break;
98709885543Smrg        }
98809885543Smrg	}
98909885543Smrg	pSmi->videoRAMBytes = pSmi->videoRAMKBytes * 1024;
99009885543Smrg	pScrn->videoRam     = pSmi->videoRAMKBytes;
99109885543Smrg
99209885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "videoram: %dkB\n",
99309885543Smrg		   pSmi->videoRAMKBytes);
99409885543Smrg    } else {
99509885543Smrg	pSmi->videoRAMKBytes = pScrn->videoRam;
99609885543Smrg	pSmi->videoRAMBytes  = pScrn->videoRam * 1024;
99709885543Smrg
99809885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "videoram: %dk\n",
99909885543Smrg		   pSmi->videoRAMKBytes);
100009885543Smrg    }
100109885543Smrg
100209885543Smrg    /* Detect current MCLK and print it for user */
100309885543Smrg    m = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A);
100409885543Smrg    n = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B);
100509885543Smrg    switch (n >> 6) {
100609885543Smrg    default:
100709885543Smrg	shift = 1;
100809885543Smrg	break;
100909885543Smrg    case 1:
101009885543Smrg	shift = 4;
101109885543Smrg	break;
101209885543Smrg    case 2:
101309885543Smrg	shift = 2;
101409885543Smrg	break;
101509885543Smrg    }
101609885543Smrg    n &= 0x3F;
101709885543Smrg    mclk = ((1431818 * m) / n / shift + 50) / 100;
101809885543Smrg    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected current MCLK value of "
101909885543Smrg	       "%1.3f MHz\n", mclk / 1000.0);
102009885543Smrg
102109885543Smrg    SMI_EnableVideo(pScrn);
102209885543Smrg    SMI_UnmapMem(pScrn);
102309885543Smrg
102409885543Smrg    pSmi->IsSwitching = FALSE;
102509885543Smrg
102609885543Smrg    if (pSmi->Dualhead) {
102709885543Smrg	pScrn->display->virtualX = 2 * pSmi->lcdWidth;
102809885543Smrg	pScrn->display->virtualY = pSmi->lcdHeight;
102909885543Smrg    }
103009885543Smrg
103109885543Smrg    pScrn->virtualX = pScrn->display->virtualX;
103209885543Smrg
103309885543Smrg    /*
103409885543Smrg     * Setup the ClockRanges, which describe what clock ranges are available,
103509885543Smrg     * and what sort of modes they can be used for.
103609885543Smrg     */
103709885543Smrg    clockRanges = xnfcalloc(sizeof(ClockRange),1);
103809885543Smrg    clockRanges->next = NULL;
103909885543Smrg    clockRanges->minClock = 20000;
104009885543Smrg
104109885543Smrg    if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR))
104209885543Smrg	clockRanges->maxClock = 200000;
104309885543Smrg    else
104409885543Smrg        clockRanges->maxClock = 135000;
104509885543Smrg
104609885543Smrg    clockRanges->clockIndex = -1;
104709885543Smrg    clockRanges->interlaceAllowed = FALSE;
104809885543Smrg    clockRanges->doubleScanAllowed = FALSE;
104909885543Smrg
105009885543Smrg    i = xf86ValidateModes(
105109885543Smrg		pScrn,				/* Screen pointer			  */
105209885543Smrg		pScrn->monitor->Modes,		/* Available monitor modes		  */
105309885543Smrg		pScrn->display->modes,		/* req mode names for screen		  */
105409885543Smrg		clockRanges,			/* list of clock ranges allowed		  */
105509885543Smrg		NULL,				/* use min/max below			  */
105609885543Smrg		128,				/* min line pitch (width)		  */
105709885543Smrg		4096,				/* maximum line pitch (width)		  */
105809885543Smrg		128,				/* bits of granularity for line pitch     */
105909885543Smrg						/* (width) above			  */
106009885543Smrg		128,				/* min virtual height			  */
106109885543Smrg		4096,				/* max virtual height			  */
106209885543Smrg		pScrn->display->virtualX,	/* force virtual x			  */
106309885543Smrg		pScrn->display->virtualY,	/* force virtual Y			  */
106409885543Smrg		pSmi->videoRAMBytes,		/* size of aperture used to access	  */
106509885543Smrg						/* video memory				  */
106609885543Smrg		LOOKUP_BEST_REFRESH);		/* how to pick modes			  */
106709885543Smrg
106809885543Smrg    if (i == -1) {
106909885543Smrg	SMI_FreeRec(pScrn);
107009885543Smrg	LEAVE_PROC("SMI_PreInit");
107109885543Smrg	return FALSE;
107209885543Smrg    }
107309885543Smrg
107409885543Smrg    /* Prune the modes marked as invalid */
107509885543Smrg    xf86PruneDriverModes(pScrn);
107609885543Smrg
107709885543Smrg    if ((i == 0) || (pScrn->modes == NULL)) {
107809885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
107909885543Smrg	SMI_FreeRec(pScrn);
108009885543Smrg	LEAVE_PROC("SMI_PreInit");
108109885543Smrg	return FALSE;
108209885543Smrg    }
108309885543Smrg    xf86SetCrtcForModes(pScrn, 0);
108409885543Smrg
108509885543Smrg    /* Set the current mode to the first in the list */
108609885543Smrg    pScrn->currentMode = pScrn->modes;
108709885543Smrg
108809885543Smrg    /* Print the list of modes being used */
108909885543Smrg    xf86PrintModes(pScrn);
109009885543Smrg
109109885543Smrg    /* Set display resolution */
109209885543Smrg    xf86SetDpi(pScrn, 0, 0);
109309885543Smrg
109409885543Smrg    if ((xf86LoadSubModule(pScrn, "fb") == NULL)) {
109509885543Smrg	SMI_FreeRec(pScrn);
109609885543Smrg	LEAVE_PROC("SMI_PreInit");
109709885543Smrg	return FALSE;
109809885543Smrg    }
109909885543Smrg
110009885543Smrg    if (!pSmi->NoAccel) {
110109885543Smrg	from = X_DEFAULT;
110209885543Smrg	char *strptr;
110309885543Smrg
110409885543Smrg	if ((strptr = (char *)xf86GetOptValString(pSmi->Options, OPTION_ACCELMETHOD))) {
110509885543Smrg	    if (!xf86NameCmp(strptr,"XAA")) {
110609885543Smrg		from = X_CONFIG;
110709885543Smrg		pSmi->useEXA = FALSE;
110809885543Smrg	    } else if(!xf86NameCmp(strptr,"EXA")) {
110909885543Smrg		from = X_CONFIG;
111009885543Smrg		pSmi->useEXA = TRUE;
111109885543Smrg	    }
111209885543Smrg	}
111309885543Smrg
111409885543Smrg	xf86DrvMsg(pScrn->scrnIndex, from, "Using %s acceleration architecture\n",
111509885543Smrg        	pSmi->useEXA ? "EXA" : "XAA");
111609885543Smrg    }
111709885543Smrg
111809885543Smrg    xf86LoaderReqSymLists(fbSymbols, NULL);
111909885543Smrg
112009885543Smrg    /* Load XAA or EXA if needed */
112109885543Smrg    if (!pSmi->NoAccel) {
112209885543Smrg	if (!pSmi->useEXA) {
112309885543Smrg	    if (!xf86LoadSubModule(pScrn, "xaa")) {
112409885543Smrg		SMI_FreeRec(pScrn);
112509885543Smrg		LEAVE_PROC("SMI_PreInit");
112609885543Smrg		return FALSE;
112709885543Smrg	    }
112809885543Smrg	    xf86LoaderReqSymLists(xaaSymbols, NULL);
112909885543Smrg	} else {
113009885543Smrg	    XF86ModReqInfo req;
113109885543Smrg	    int errmaj, errmin;
113209885543Smrg
113309885543Smrg	    memset(&req, 0, sizeof(XF86ModReqInfo));
113409885543Smrg	    req.majorversion = 2;
113509885543Smrg	    req.minorversion = 0;
113609885543Smrg
113709885543Smrg	    if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL,
113809885543Smrg				&req, &errmaj, &errmin)) {
113909885543Smrg		LoaderErrorMsg(NULL, "exa", errmaj, errmin);
114009885543Smrg		SMI_FreeRec(pScrn);
114109885543Smrg		LEAVE_PROC("SMI_PreInit");
114209885543Smrg		return FALSE;
114309885543Smrg	    }
114409885543Smrg	    xf86LoaderReqSymLists(exaSymbols, NULL);
114509885543Smrg	}
114609885543Smrg    }
114709885543Smrg
114809885543Smrg    /* Load ramdac if needed */
114909885543Smrg    if (pSmi->hwcursor) {
115009885543Smrg	if (!xf86LoadSubModule(pScrn, "ramdac")) {
115109885543Smrg	    SMI_FreeRec(pScrn);
115209885543Smrg	    LEAVE_PROC("SMI_PreInit");
115309885543Smrg	    return FALSE;
115409885543Smrg	}
115509885543Smrg	xf86LoaderReqSymLists(ramdacSymbols, NULL);
115609885543Smrg    }
115709885543Smrg
115809885543Smrg    if (pSmi->shadowFB) {
115909885543Smrg	if (!xf86LoadSubModule(pScrn, "shadowfb")) {
116009885543Smrg	    SMI_FreeRec(pScrn);
116109885543Smrg	    LEAVE_PROC("SMI_PreInit");
116209885543Smrg	    return FALSE;
116309885543Smrg	}
116409885543Smrg	xf86LoaderReqSymLists(shadowSymbols, NULL);
116509885543Smrg    }
116609885543Smrg
116709885543Smrg    LEAVE_PROC("SMI_PreInit");
116809885543Smrg    return TRUE;
116909885543Smrg}
117009885543Smrg
117109885543Smrg/*
117209885543Smrg * This is called when VT switching back to the X server.  Its job is to
117309885543Smrg * reinitialise the video mode. We may wish to unmap video/MMIO memory too.
117409885543Smrg */
117509885543Smrg
117609885543Smrgstatic Bool
117709885543SmrgSMI_EnterVT(int scrnIndex, int flags)
117809885543Smrg{
117909885543Smrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
118009885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
118109885543Smrg    Bool ret;
118209885543Smrg
118309885543Smrg    ENTER_PROC("SMI_EnterVT");
118409885543Smrg
118509885543Smrg    /* Enable MMIO and map memory */
118609885543Smrg    SMI_MapMem(pScrn);
118709885543Smrg    SMI_Save(pScrn);
118809885543Smrg
118909885543Smrg    /* #670 */
119009885543Smrg    if (pSmi->shadowFB) {
119109885543Smrg	pSmi->FBOffset = pSmi->savedFBOffset;
119209885543Smrg	pSmi->FBReserved = pSmi->savedFBReserved;
119309885543Smrg    }
119409885543Smrg
119509885543Smrg    ret = SMI_ModeInit(pScrn, pScrn->currentMode);
119609885543Smrg
119709885543Smrg    /* #670 */
119809885543Smrg    if (ret && pSmi->shadowFB) {
119909885543Smrg	BoxRec box;
120009885543Smrg
120109885543Smrg	/* #920 */
120209885543Smrg	if (pSmi->paletteBuffer) {
120309885543Smrg	    int i;
120409885543Smrg
120509885543Smrg	    VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, 0);
120609885543Smrg	    for (i = 0; i < 256 * 3; i++) {
120709885543Smrg		VGAOUT8(pSmi, VGA_DAC_DATA, pSmi->paletteBuffer[i]);
120809885543Smrg	    }
120909885543Smrg	    xfree(pSmi->paletteBuffer);
121009885543Smrg	    pSmi->paletteBuffer = NULL;
121109885543Smrg	}
121209885543Smrg
121309885543Smrg	if (pSmi->pSaveBuffer) {
121409885543Smrg	    memcpy(pSmi->FBBase, pSmi->pSaveBuffer, pSmi->saveBufferSize);
121509885543Smrg	    xfree(pSmi->pSaveBuffer);
121609885543Smrg	    pSmi->pSaveBuffer = NULL;
121709885543Smrg	}
121809885543Smrg
121909885543Smrg	box.x1 = 0;
122009885543Smrg	box.y1 = 0;
122109885543Smrg	box.x2 = pScrn->virtualY;
122209885543Smrg	box.y2 = pScrn->virtualX;
122309885543Smrg	if (pSmi->Chipset == SMI_COUGAR3DR) {
122409885543Smrg	    SMI_RefreshArea730(pScrn, 1, &box);
122509885543Smrg	} else {
122609885543Smrg	    SMI_RefreshArea(pScrn, 1, &box);
122709885543Smrg	}
122809885543Smrg    }
122909885543Smrg
123009885543Smrg    /* Reset the grapics engine */
123109885543Smrg    if (!pSmi->NoAccel)
123209885543Smrg	SMI_EngineReset(pScrn);
123309885543Smrg
123409885543Smrg    LEAVE_PROC("SMI_EnterVT");
123509885543Smrg    return ret;
123609885543Smrg}
123709885543Smrg
123809885543Smrg/*
123909885543Smrg * This is called when VT switching away from the X server.  Its job is to
124009885543Smrg * restore the previous (text) mode. We may wish to remap video/MMIO memory
124109885543Smrg * too.
124209885543Smrg */
124309885543Smrg
124409885543Smrgstatic void
124509885543SmrgSMI_LeaveVT(int scrnIndex, int flags)
124609885543Smrg{
124709885543Smrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
124809885543Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
124909885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
125009885543Smrg    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
125109885543Smrg    SMIRegPtr SMISavePtr = &pSmi->SavedReg;
125209885543Smrg
125309885543Smrg    ENTER_PROC("SMI_LeaveVT");
125409885543Smrg
125509885543Smrg    /* #670 */
125609885543Smrg    if (pSmi->shadowFB) {
125709885543Smrg	pSmi->pSaveBuffer = xnfalloc(pSmi->saveBufferSize);
125809885543Smrg	if (pSmi->pSaveBuffer) {
125909885543Smrg	    memcpy(pSmi->pSaveBuffer, pSmi->FBBase, pSmi->saveBufferSize);
126009885543Smrg	}
126109885543Smrg
126209885543Smrg	pSmi->savedFBOffset = pSmi->FBOffset;
126309885543Smrg	pSmi->savedFBReserved = pSmi->FBReserved;
126409885543Smrg
126509885543Smrg	/* #920 */
126609885543Smrg	if (pSmi->Bpp == 1) {
126709885543Smrg	    pSmi->paletteBuffer = xnfalloc(256 * 3);
126809885543Smrg	    if (pSmi->paletteBuffer) {
126909885543Smrg		int i;
127009885543Smrg
127109885543Smrg		VGAOUT8(pSmi, VGA_DAC_READ_ADDR, 0);
127209885543Smrg		for (i = 0; i < 256 * 3; i++) {
127309885543Smrg		    pSmi->paletteBuffer[i] = VGAIN8(pSmi, VGA_DAC_DATA);
127409885543Smrg		}
127509885543Smrg	    }
127609885543Smrg	}
127709885543Smrg    }
127809885543Smrg
127909885543Smrg    memset(pSmi->FBBase, 0, 256 * 1024);	/* #689 */
128009885543Smrg    SMI_WriteMode(pScrn, vgaSavePtr, SMISavePtr);
128109885543Smrg    SMI_UnmapMem(pScrn);
128209885543Smrg
128309885543Smrg    LEAVE_PROC("SMI_LeaveVT");
128409885543Smrg}
128509885543Smrg
128609885543Smrg/*
128709885543Smrg * This function performs the inverse of the restore function: It saves all the
128809885543Smrg * standard and extended registers that we are going to modify to set up a video
128909885543Smrg * mode.
129009885543Smrg */
129109885543Smrg
129209885543Smrgstatic void
129309885543SmrgSMI_Save(ScrnInfoPtr pScrn)
129409885543Smrg{
129509885543Smrg    int i;
129609885543Smrg    CARD32 offset;
129709885543Smrg
129809885543Smrg    vgaHWPtr hwp         = VGAHWPTR(pScrn);
129909885543Smrg    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
130009885543Smrg    SMIPtr pSmi          = SMIPTR(pScrn);
130109885543Smrg    SMIRegPtr save       = &pSmi->SavedReg;
130209885543Smrg
130309885543Smrg    int vgaIOBase  = hwp->IOBase;
130409885543Smrg    int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
130509885543Smrg    int vgaCRData  = vgaIOBase + VGA_CRTC_DATA_OFFSET;
130609885543Smrg
130709885543Smrg    ENTER_PROC("SMI_Save");
130809885543Smrg
130909885543Smrg    /* Save the standard VGA registers */
131009885543Smrg    vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL);
131109885543Smrg    save->smiDACMask = VGAIN8(pSmi, VGA_DAC_MASK);
131209885543Smrg    VGAOUT8(pSmi, VGA_DAC_READ_ADDR, 0);
131309885543Smrg    for (i = 0; i < 256; i++) {
131409885543Smrg	save->smiDacRegs[i][0] = VGAIN8(pSmi, VGA_DAC_DATA);
131509885543Smrg	save->smiDacRegs[i][1] = VGAIN8(pSmi, VGA_DAC_DATA);
131609885543Smrg	save->smiDacRegs[i][2] = VGAIN8(pSmi, VGA_DAC_DATA);
131709885543Smrg    }
131809885543Smrg    for (i = 0, offset = 2; i < 8192; i++, offset += 8) {
131909885543Smrg	save->smiFont[i] = *(pSmi->FBBase + offset);
132009885543Smrg    }
132109885543Smrg
132209885543Smrg    /* Now we save all the extended registers we need. */
132309885543Smrg    save->SR17 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17);
132409885543Smrg    save->SR18 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18);
132509885543Smrg    save->SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
132609885543Smrg    save->SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31);
132709885543Smrg    save->SR32 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32);
132809885543Smrg    save->SR6A = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A);
132909885543Smrg    save->SR6B = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B);
133009885543Smrg    save->SR81 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81);
133109885543Smrg    save->SRA0 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0);
133209885543Smrg
133309885543Smrg    /* vclk1 */
133409885543Smrg    save->SR6C = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C);
133509885543Smrg    save->SR6D = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D);
133609885543Smrg    /* vclk1 control */
133709885543Smrg    save->SR68 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x68);
133809885543Smrg
133909885543Smrg    if (pSmi->Dualhead) {
134009885543Smrg	/* dualhead stuff */
134109885543Smrg	save->SR22 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22);
134209885543Smrg	save->SR40 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x40);
134309885543Smrg	save->SR41 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x41);
134409885543Smrg	save->SR42 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x42);
134509885543Smrg	save->SR43 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x43);
134609885543Smrg	save->SR44 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x44);
134709885543Smrg	save->SR45 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x45);
134809885543Smrg	save->SR48 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x48);
134909885543Smrg	save->SR49 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49);
135009885543Smrg	save->SR4A = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4A);
135109885543Smrg	save->SR4B = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4B);
135209885543Smrg	save->SR4C = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4C);
135309885543Smrg	/* PLL2 stuff */
135409885543Smrg	save->SR69 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x69);
135509885543Smrg	save->SR6E = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6E);
135609885543Smrg	save->SR6F = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6F);
135709885543Smrg    }
135809885543Smrg
135909885543Smrg    if (SMI_LYNXM_SERIES(pSmi->Chipset)) {
136009885543Smrg	/* Save primary registers */
136109885543Smrg	save->CR90[14] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E);
136209885543Smrg	VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14] & ~0x20);
136309885543Smrg
136409885543Smrg	for (i = 0; i < 16; i++) {
136509885543Smrg	    save->CR90[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x90 + i);
136609885543Smrg	}
136709885543Smrg	save->CR33 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33);
136809885543Smrg	save->CR3A = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A);
136909885543Smrg	for (i = 0; i < 14; i++) {
137009885543Smrg	    save->CR40[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i);
137109885543Smrg	}
137209885543Smrg
137309885543Smrg	/* Save secondary registers */
137409885543Smrg	VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14] | 0x20);
137509885543Smrg	save->CR33_2 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33);
137609885543Smrg	for (i = 0; i < 14; i++) {
137709885543Smrg	    save->CR40_2[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i);
137809885543Smrg	}
137909885543Smrg	save->CR9F_2 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9F);
138009885543Smrg
138109885543Smrg	/* Save common registers */
138209885543Smrg	for (i = 0; i < 14; i++) {
138309885543Smrg	    save->CRA0[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0xA0 + i);
138409885543Smrg	}
138509885543Smrg
138609885543Smrg	/* PDR#1069 */
138709885543Smrg	VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14]);
138809885543Smrg    } else {
138909885543Smrg	save->CR33 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33);
139009885543Smrg	save->CR3A = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A);
139109885543Smrg	for (i = 0; i < 14; i++) {
139209885543Smrg	    save->CR40[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i);
139309885543Smrg	}
139409885543Smrg    }
139509885543Smrg
139609885543Smrg    /* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */
139709885543Smrg    if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR)) {
139809885543Smrg	save->CCR66 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66);
139909885543Smrg    }
140009885543Smrg    /* end CZ */
140109885543Smrg
140209885543Smrg    save->DPR10 = READ_DPR(pSmi, 0x10);
140309885543Smrg    save->DPR1C = READ_DPR(pSmi, 0x1C);
140409885543Smrg    save->DPR20 = READ_DPR(pSmi, 0x20);
140509885543Smrg    save->DPR24 = READ_DPR(pSmi, 0x24);
140609885543Smrg    save->DPR28 = READ_DPR(pSmi, 0x28);
140709885543Smrg    save->DPR2C = READ_DPR(pSmi, 0x2C);
140809885543Smrg    save->DPR30 = READ_DPR(pSmi, 0x30);
140909885543Smrg    save->DPR3C = READ_DPR(pSmi, 0x3C);
141009885543Smrg    save->DPR40 = READ_DPR(pSmi, 0x40);
141109885543Smrg    save->DPR44 = READ_DPR(pSmi, 0x44);
141209885543Smrg
141309885543Smrg    save->VPR00 = READ_VPR(pSmi, 0x00);
141409885543Smrg    save->VPR0C = READ_VPR(pSmi, 0x0C);
141509885543Smrg    save->VPR10 = READ_VPR(pSmi, 0x10);
141609885543Smrg
141709885543Smrg    if (pSmi->Chipset == SMI_COUGAR3DR) {
141809885543Smrg	save->FPR00_ = READ_FPR(pSmi, FPR00);
141909885543Smrg	save->FPR0C_ = READ_FPR(pSmi, FPR0C);
142009885543Smrg	save->FPR10_ = READ_FPR(pSmi, FPR10);
142109885543Smrg    }
142209885543Smrg
142309885543Smrg    save->CPR00 = READ_CPR(pSmi, 0x00);
142409885543Smrg
142509885543Smrg    if (!pSmi->ModeStructInit) {
142609885543Smrg	/* XXX Should check the return value of vgaHWCopyReg() */
142709885543Smrg	vgaHWCopyReg(&hwp->ModeReg, vgaSavePtr);
142809885543Smrg	memcpy(&pSmi->ModeReg, save, sizeof(SMIRegRec));
142909885543Smrg	pSmi->ModeStructInit = TRUE;
143009885543Smrg    }
143109885543Smrg
143209885543Smrg    if (pSmi->useBIOS && (pSmi->pInt10 != NULL)) {
143309885543Smrg	pSmi->pInt10->num = 0x10;
143409885543Smrg	pSmi->pInt10->ax = 0x0F00;
143509885543Smrg	xf86ExecX86int10(pSmi->pInt10);
143609885543Smrg	save->mode = pSmi->pInt10->ax & 0x007F;
143709885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Current mode 0x%02X.\n",
143809885543Smrg		   save->mode);
143909885543Smrg    }
144009885543Smrg
144109885543Smrg    if (xf86GetVerbosity() > 1) {
144209885543Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
144309885543Smrg		       "Saved current video mode.  Register dump:\n");
144409885543Smrg	SMI_PrintRegs(pScrn);
144509885543Smrg    }
144609885543Smrg
144709885543Smrg    LEAVE_PROC("SMI_Save");
144809885543Smrg}
144909885543Smrg
145009885543Smrg/*
145109885543Smrg * This function is used to restore a video mode. It writes out all of the
145209885543Smrg * standard VGA and extended registers needed to setup a video mode.
145309885543Smrg */
145409885543Smrg
145509885543Smrgstatic void
145609885543SmrgSMI_WriteMode(ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr, SMIRegPtr restore)
145709885543Smrg{
145809885543Smrg    int i;
145909885543Smrg    CARD8 tmp;
146009885543Smrg    CARD32 offset;
146109885543Smrg
146209885543Smrg    vgaHWPtr hwp   = VGAHWPTR(pScrn);
146309885543Smrg    SMIPtr pSmi    = SMIPTR(pScrn);
146409885543Smrg    int vgaIOBase  = hwp->IOBase;
146509885543Smrg    int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
146609885543Smrg    int vgaCRData  = vgaIOBase + VGA_CRTC_DATA_OFFSET;
146709885543Smrg
146809885543Smrg    ENTER_PROC("SMI_WriteMode");
146909885543Smrg
147009885543Smrg    vgaHWProtect(pScrn, TRUE);
147109885543Smrg
147209885543Smrg    /* Wait for engine to become idle */
147309885543Smrg    if (pSmi->IsSwitching)
147409885543Smrg	WaitIdle();
147509885543Smrg
147609885543Smrg    if (pSmi->useBIOS && (pSmi->pInt10 != NULL) && (restore->mode != 0)) {
147709885543Smrg	pSmi->pInt10->num = 0x10;
147809885543Smrg	pSmi->pInt10->ax = restore->mode | 0x80;
147909885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%02X\n",
148009885543Smrg		   restore->mode);
148109885543Smrg	xf86ExecX86int10(pSmi->pInt10);
148209885543Smrg
148309885543Smrg	/* Enable linear mode. */
148409885543Smrg	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
148509885543Smrg	tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
148609885543Smrg	outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x01);
148709885543Smrg
148809885543Smrg	/* Enable DPR/VPR registers. */
148909885543Smrg	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
149009885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03);
149109885543Smrg    } else {
149209885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17, restore->SR17);
149309885543Smrg	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18) & ~0x1F;
149409885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18, tmp |
149509885543Smrg		      (restore->SR18 & 0x1F));
149609885543Smrg	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
149709885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03);
149809885543Smrg	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31) & ~0xC0;
149909885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, tmp |
150009885543Smrg		      (restore->SR31 & 0xC0));
150109885543Smrg	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32) & ~0x07;
150209885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32, tmp |
150309885543Smrg		      (restore->SR32 & 0x07));
150409885543Smrg	if (restore->SR6B != 0xFF) {
150509885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A, restore->SR6A);
150609885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B, restore->SR6B);
150709885543Smrg	}
150809885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, restore->SR81);
150909885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0, restore->SRA0);
151009885543Smrg
151109885543Smrg	/* Restore the standard VGA registers */
151209885543Smrg	vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
151309885543Smrg	if (restore->smiDACMask) {
151409885543Smrg	    VGAOUT8(pSmi, VGA_DAC_MASK, restore->smiDACMask);
151509885543Smrg	} else {
151609885543Smrg	    VGAOUT8(pSmi, VGA_DAC_MASK, 0xFF);
151709885543Smrg	}
151809885543Smrg	VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, 0);
151909885543Smrg	for (i = 0; i < 256; i++) {
152009885543Smrg	    VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][0]);
152109885543Smrg	    VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][1]);
152209885543Smrg	    VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][2]);
152309885543Smrg	}
152409885543Smrg	for (i = 0, offset = 2; i < 8192; i++, offset += 8) {
152509885543Smrg	    *(pSmi->FBBase + offset) = restore->smiFont[i];
152609885543Smrg	}
152709885543Smrg
152809885543Smrg	if (SMI_LYNXM_SERIES(pSmi->Chipset)) {
152909885543Smrg	    /* Restore secondary registers */
153009885543Smrg	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E,
153109885543Smrg			  restore->CR90[14] | 0x20);
153209885543Smrg
153309885543Smrg	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33_2);
153409885543Smrg	    for (i = 0; i < 14; i++) {
153509885543Smrg		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i,
153609885543Smrg			      restore->CR40_2[i]);
153709885543Smrg	    }
153809885543Smrg	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9F, restore->CR9F_2);
153909885543Smrg
154009885543Smrg	    /* Restore primary registers */
154109885543Smrg	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E,
154209885543Smrg			  restore->CR90[14] & ~0x20);
154309885543Smrg
154409885543Smrg	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33);
154509885543Smrg	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A, restore->CR3A);
154609885543Smrg	    for (i = 0; i < 14; i++) {
154709885543Smrg		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i,
154809885543Smrg			      restore->CR40[i]);
154909885543Smrg	    }
155009885543Smrg	    for (i = 0; i < 16; i++) {
155109885543Smrg		if (i != 14) {
155209885543Smrg		    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x90 + i,
155309885543Smrg				  restore->CR90[i]);
155409885543Smrg		}
155509885543Smrg	    }
155609885543Smrg	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, restore->CR90[14]);
155709885543Smrg
155809885543Smrg	    /* Restore common registers */
155909885543Smrg	    for (i = 0; i < 14; i++) {
156009885543Smrg		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0xA0 + i,
156109885543Smrg			      restore->CRA0[i]);
156209885543Smrg	    }
156309885543Smrg	}
156409885543Smrg
156509885543Smrg	/* Restore the standard VGA registers */
156609885543Smrg	if (xf86IsPrimaryPci(pSmi->PciInfo)) {
156709885543Smrg	    vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_CMAP | VGA_SR_FONTS);
156809885543Smrg	}
156909885543Smrg
157009885543Smrg	if (restore->modeInit)
157109885543Smrg	    vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
157209885543Smrg
157309885543Smrg	if (!SMI_LYNXM_SERIES(pSmi->Chipset)) {
157409885543Smrg	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33);
157509885543Smrg	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A, restore->CR3A);
157609885543Smrg	    for (i = 0; i < 14; i++) {
157709885543Smrg		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i,
157809885543Smrg			      restore->CR40[i]);
157909885543Smrg	    }
158009885543Smrg	}
158109885543Smrg
158209885543Smrg	/* vclk1 */
158309885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x68, restore->SR68);
158409885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C, restore->SR6C);
158509885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D, restore->SR6D);
158609885543Smrg
158709885543Smrg	if (pSmi->Dualhead) {
158809885543Smrg
158909885543Smrg	/* TFT panel uses FIFO1, DSTN panel uses FIFO1 for upper panel and
159009885543Smrg	 * FIFO2 for lower panel.  I don't have a DSTN panel, so it's untested.
159109885543Smrg	 * -- AGD
159209885543Smrg	 */
159309885543Smrg
159409885543Smrg	    /* PLL2 regs */
159509885543Smrg
159609885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x69, restore->SR69);
159709885543Smrg
159809885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6E, restore->SR6E);
159909885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6F, restore->SR6F);
160009885543Smrg
160109885543Smrg	    /* setting SR21 bit 2 disables ZV circuitry,
160209885543Smrg	     * if ZV is needed, SR21 = 0x20
160309885543Smrg	     */
160409885543Smrg	    /* enable DAC, PLL, etc. */
160509885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, restore->SR21);
160609885543Smrg
160709885543Smrg	    /* clear DPMS state */
160809885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22, restore->SR22);
160909885543Smrg
161009885543Smrg	    /* enable virtual refresh and LCD and CRT outputs */
161109885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, restore->SR31);
161209885543Smrg
161309885543Smrg	    /* FIFO1 Read Offset */
161409885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x44, restore->SR44);
161509885543Smrg	    /* FIFO2 Read Offset */
161609885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4B, restore->SR4B);
161709885543Smrg	    /* FIFO1/2 Read Offset overflow */
161809885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4C, restore->SR4C);
161909885543Smrg
162009885543Smrg	    /* FIFO Write Offset */
162109885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x48, restore->SR48);
162209885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49, restore->SR49);
162309885543Smrg
162409885543Smrg	    /* set FIFO levels */
162509885543Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4A, restore->SR4A);
162609885543Smrg
162709885543Smrg	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33);
162809885543Smrg
162909885543Smrg	}
163009885543Smrg    }
163109885543Smrg
163209885543Smrg    /* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */
163309885543Smrg    if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR)) {
163409885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66, restore->CCR66);
163509885543Smrg    }
163609885543Smrg    /* end CZ */
163709885543Smrg
163809885543Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, 0x00);
163909885543Smrg
164009885543Smrg    /* Reset the graphics engine */
164109885543Smrg    WRITE_DPR(pSmi, 0x10, restore->DPR10);
164209885543Smrg    WRITE_DPR(pSmi, 0x1C, restore->DPR1C);
164309885543Smrg    WRITE_DPR(pSmi, 0x20, restore->DPR20);
164409885543Smrg    WRITE_DPR(pSmi, 0x24, restore->DPR24);
164509885543Smrg    WRITE_DPR(pSmi, 0x28, restore->DPR28);
164609885543Smrg    WRITE_DPR(pSmi, 0x2C, restore->DPR2C);
164709885543Smrg    WRITE_DPR(pSmi, 0x30, restore->DPR30);
164809885543Smrg    WRITE_DPR(pSmi, 0x3C, restore->DPR3C);
164909885543Smrg    WRITE_DPR(pSmi, 0x40, restore->DPR40);
165009885543Smrg    WRITE_DPR(pSmi, 0x44, restore->DPR44);
165109885543Smrg
165209885543Smrg    /* write video controller regs */
165309885543Smrg    WRITE_VPR(pSmi, 0x00, restore->VPR00);
165409885543Smrg    WRITE_VPR(pSmi, 0x0C, restore->VPR0C);
165509885543Smrg    WRITE_VPR(pSmi, 0x10, restore->VPR10);
165609885543Smrg
165709885543Smrg    if(pSmi->Chipset == SMI_COUGAR3DR) {
165809885543Smrg	WRITE_FPR(pSmi, FPR00, restore->FPR00_);
165909885543Smrg	WRITE_FPR(pSmi, FPR0C, restore->FPR0C_);
166009885543Smrg	WRITE_FPR(pSmi, FPR10, restore->FPR10_);
166109885543Smrg    }
166209885543Smrg
166309885543Smrg    WRITE_CPR(pSmi, 0x00, restore->CPR00);
166409885543Smrg
166509885543Smrg    if (xf86GetVerbosity() > 1) {
166609885543Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
166709885543Smrg		       "Done restoring mode.  Register dump:\n");
166809885543Smrg	SMI_PrintRegs(pScrn);
166909885543Smrg    }
167009885543Smrg
167109885543Smrg    vgaHWProtect(pScrn, FALSE);
167209885543Smrg
167309885543Smrg    LEAVE_PROC("SMI_WriteMode");
167409885543Smrg}
167509885543Smrg
167609885543Smrgstatic void
167709885543SmrgSMI_DetectPanelSize(ScrnInfoPtr pScrn)
167809885543Smrg{
167909885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
168009885543Smrg
168109885543Smrg    /* panel size detection ... requires BIOS call on 730 hardware */
168209885543Smrg    if (pSmi->Chipset == SMI_COUGAR3DR) {
168309885543Smrg	if (pSmi->pInt10 != NULL) {
168409885543Smrg	    pSmi->pInt10->num = 0x10;
168509885543Smrg	    pSmi->pInt10->ax  = 0x5F00;
168609885543Smrg	    pSmi->pInt10->bx  = 0;
168709885543Smrg	    pSmi->pInt10->cx  = 0;
168809885543Smrg	    pSmi->pInt10->dx  = 0;
168909885543Smrg	    xf86ExecX86int10(pSmi->pInt10);
169009885543Smrg	    if (pSmi->pInt10->ax == 0x005F) {
169109885543Smrg		switch (pSmi->pInt10->cx & 0x0F) {
169209885543Smrg		case PANEL_640x480:
169309885543Smrg		    pSmi->lcdWidth  = 640;
169409885543Smrg		    pSmi->lcdHeight = 480;
169509885543Smrg		    break;
169609885543Smrg		case PANEL_800x600:
169709885543Smrg		    pSmi->lcdWidth  = 800;
169809885543Smrg		    pSmi->lcdHeight = 600;
169909885543Smrg		    break;
170009885543Smrg		case PANEL_1024x768:
170109885543Smrg		    pSmi->lcdWidth  = 1024;
170209885543Smrg		    pSmi->lcdHeight = 768;
170309885543Smrg		    break;
170409885543Smrg		case PANEL_1280x1024:
170509885543Smrg		    pSmi->lcdWidth  = 1280;
170609885543Smrg		    pSmi->lcdHeight = 1024;
170709885543Smrg		    break;
170809885543Smrg		case PANEL_1600x1200:
170909885543Smrg		    pSmi->lcdWidth  = 1600;
171009885543Smrg		    pSmi->lcdHeight = 1200;
171109885543Smrg		    break;
171209885543Smrg		case PANEL_1400x1050:
171309885543Smrg		    pSmi->lcdWidth  = 1400;
171409885543Smrg		    pSmi->lcdHeight = 1050;
171509885543Smrg		    break;
171609885543Smrg		}
171709885543Smrg
171809885543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Detected panel size via BIOS: %d x %d\n",
171909885543Smrg			   pSmi->lcdWidth, pSmi->lcdHeight);
172009885543Smrg	    } else {
172109885543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS error during 730 panel detection!\n");
172209885543Smrg			   pSmi->lcdWidth  = pScrn->virtualX;
172309885543Smrg		pSmi->lcdHeight = pScrn->virtualY;
172409885543Smrg	    }
172509885543Smrg	} else  {
172609885543Smrg	    /* int10 support isn't setup on the second call to this function,
172709885543Smrg	       so if this is the second call, don't do detection again */
172809885543Smrg	    if (pSmi->lcd == 0) {
172909885543Smrg		/* If we get here, int10 support is not loaded or not working */
173009885543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No BIOS support for 730 panel detection!\n");
173109885543Smrg		pSmi->lcdWidth  = pScrn->virtualX;
173209885543Smrg		pSmi->lcdHeight = pScrn->virtualY;
173309885543Smrg	    }
173409885543Smrg	}
173509885543Smrg
173609885543Smrg	/* Set this to indicate that we've done the detection */
173709885543Smrg	pSmi->lcd = 1;
173809885543Smrg    } else {
173909885543Smrg	/* panel size detection for hardware other than 730 */
174009885543Smrg	pSmi->lcd = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31) & 0x01;
174109885543Smrg
174209885543Smrg	if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x01) {
174309885543Smrg	    pSmi->lcd <<= 1;
174409885543Smrg	}
174509885543Smrg	switch (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x0C) {
174609885543Smrg	case 0x00:
174709885543Smrg	    pSmi->lcdWidth  = 640;
174809885543Smrg	    pSmi->lcdHeight = 480;
174909885543Smrg	    break;
175009885543Smrg	case 0x04:
175109885543Smrg	    pSmi->lcdWidth  = 800;
175209885543Smrg	    pSmi->lcdHeight = 600;
175309885543Smrg	    break;
175409885543Smrg	case 0x08:
175509885543Smrg	    if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x74) & 0x02) {
175609885543Smrg		pSmi->lcdWidth  = 1024;
175709885543Smrg		pSmi->lcdHeight = 600;
175809885543Smrg	    } else {
175909885543Smrg		pSmi->lcdWidth  = 1024;
176009885543Smrg		pSmi->lcdHeight = 768;
176109885543Smrg	    }
176209885543Smrg	    break;
176309885543Smrg	case 0x0C:
176409885543Smrg	    pSmi->lcdWidth  = 1280;
176509885543Smrg	    pSmi->lcdHeight = 1024;
176609885543Smrg	    break;
176709885543Smrg	}
176809885543Smrg    }
176909885543Smrg
177009885543Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Panel Size = %dx%d\n",
177109885543Smrg	       (pSmi->lcd == 0) ? "OFF" : (pSmi->lcd == 1) ? "TFT" : "DSTN",
177209885543Smrg	       pSmi->lcdWidth, pSmi->lcdHeight);
177309885543Smrg
177409885543Smrg}
177509885543Smrg
177609885543Smrgstatic Bool
177709885543SmrgSMI_MapMem(ScrnInfoPtr pScrn)
177809885543Smrg{
177909885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
178009885543Smrg    vgaHWPtr hwp;
178109885543Smrg    CARD32 memBase;
178209885543Smrg
178309885543Smrg    ENTER_PROC("SMI_MapMem");
178409885543Smrg
178509885543Smrg    /* Map the Lynx register space */
178609885543Smrg    switch (pSmi->Chipset) {
178709885543Smrg    default:
178809885543Smrg	memBase = pSmi->PciInfo->memBase[0] + 0x400000;
178909885543Smrg	pSmi->MapSize = 0x10000;
179009885543Smrg	break;
179109885543Smrg    case SMI_COUGAR3DR:
179209885543Smrg	memBase = pSmi->PciInfo->memBase[1];
179309885543Smrg	pSmi->MapSize = 0x200000;
179409885543Smrg	break;
179509885543Smrg    case SMI_LYNX3D:
179609885543Smrg	memBase = pSmi->PciInfo->memBase[0] + 0x680000;
179709885543Smrg	pSmi->MapSize = 0x180000;
179809885543Smrg	break;
179909885543Smrg    case SMI_LYNXEM:
180009885543Smrg    case SMI_LYNXEMplus:
180109885543Smrg	memBase = pSmi->PciInfo->memBase[0] + 0x400000;
180209885543Smrg	pSmi->MapSize = 0x400000;
180309885543Smrg	break;
180409885543Smrg    case SMI_LYNX3DM:
180509885543Smrg	memBase = pSmi->PciInfo->memBase[0];
180609885543Smrg	pSmi->MapSize = 0x200000;
180709885543Smrg	break;
180809885543Smrg    }
180909885543Smrg    pSmi->MapBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pSmi->PciTag,
181009885543Smrg				  memBase, pSmi->MapSize);
181109885543Smrg
181209885543Smrg    if (pSmi->MapBase == NULL) {
181309885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Internal error: could not map "
181409885543Smrg		   "MMIO registers.\n");
181509885543Smrg	LEAVE_PROC("SMI_MapMem");
181609885543Smrg	return FALSE;
181709885543Smrg    }
181809885543Smrg
181909885543Smrg    switch (pSmi->Chipset) {
182009885543Smrg    default:
182109885543Smrg	pSmi->DPRBase = pSmi->MapBase + 0x8000;
182209885543Smrg	pSmi->VPRBase = pSmi->MapBase + 0xC000;
182309885543Smrg	pSmi->CPRBase = pSmi->MapBase + 0xE000;
182409885543Smrg	pSmi->IOBase  = NULL;
182509885543Smrg	pSmi->DataPortBase = pSmi->MapBase;
182609885543Smrg	pSmi->DataPortSize = 0x8000;
182709885543Smrg	break;
182809885543Smrg    case SMI_COUGAR3DR:
182909885543Smrg	pSmi->DPRBase = pSmi->MapBase + 0x000000;
183009885543Smrg	pSmi->VPRBase = pSmi->MapBase + 0x000800;
183109885543Smrg	pSmi->CPRBase = pSmi->MapBase + 0x001000;
183209885543Smrg	pSmi->FPRBase = pSmi->MapBase + 0x005800;
183309885543Smrg	pSmi->IOBase  = pSmi->MapBase + 0x0C0000;
183409885543Smrg	pSmi->DataPortBase = pSmi->MapBase + 0x100000;
183509885543Smrg	pSmi->DataPortSize = 0x100000;
183609885543Smrg	break;
183709885543Smrg    case SMI_LYNX3D:
183809885543Smrg	pSmi->DPRBase = pSmi->MapBase + 0x000000;
183909885543Smrg	pSmi->VPRBase = pSmi->MapBase + 0x000800;
184009885543Smrg	pSmi->CPRBase = pSmi->MapBase + 0x001000;
184109885543Smrg	pSmi->IOBase  = pSmi->MapBase + 0x040000;
184209885543Smrg	pSmi->DataPortBase = pSmi->MapBase + 0x080000;
184309885543Smrg	pSmi->DataPortSize = 0x100000;
184409885543Smrg	break;
184509885543Smrg    case SMI_LYNXEM:
184609885543Smrg    case SMI_LYNXEMplus:
184709885543Smrg	pSmi->DPRBase = pSmi->MapBase + 0x008000;
184809885543Smrg	pSmi->VPRBase = pSmi->MapBase + 0x00C000;
184909885543Smrg	pSmi->CPRBase = pSmi->MapBase + 0x00E000;
185009885543Smrg	pSmi->IOBase  = pSmi->MapBase + 0x300000;
185109885543Smrg	pSmi->DataPortBase = pSmi->MapBase /*+ 0x100000*/;
185209885543Smrg	pSmi->DataPortSize = 0x8000 /*0x200000*/;
185309885543Smrg	break;
185409885543Smrg    case SMI_LYNX3DM:
185509885543Smrg	pSmi->DPRBase = pSmi->MapBase + 0x000000;
185609885543Smrg	pSmi->VPRBase = pSmi->MapBase + 0x000800;
185709885543Smrg	pSmi->CPRBase = pSmi->MapBase + 0x001000;
185809885543Smrg	pSmi->IOBase  = pSmi->MapBase + 0x0C0000;
185909885543Smrg	pSmi->DataPortBase = pSmi->MapBase + 0x100000;
186009885543Smrg	pSmi->DataPortSize = 0x100000;
186109885543Smrg	break;
186209885543Smrg    }
186309885543Smrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
186409885543Smrg		   "Physical MMIO at 0x%08lX\n", (unsigned long)memBase);
186509885543Smrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
186609885543Smrg		   "Logical MMIO at %p - %p\n", pSmi->MapBase,
186709885543Smrg		   pSmi->MapBase + pSmi->MapSize - 1);
186809885543Smrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
186909885543Smrg		   "DPR=%p, VPR=%p, IOBase=%p\n",
187009885543Smrg		   pSmi->DPRBase, pSmi->VPRBase, pSmi->IOBase);
187109885543Smrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
187209885543Smrg		   "DataPort=%p - %p\n", pSmi->DataPortBase,
187309885543Smrg		   pSmi->DataPortBase + pSmi->DataPortSize - 1);
187409885543Smrg
187509885543Smrg    pScrn->memPhysBase = pSmi->PciInfo->memBase[0];
187609885543Smrg
187709885543Smrg    SMI_EnableMmio(pScrn);
187809885543Smrg
187909885543Smrg    if (pSmi->videoRAMBytes) {
188009885543Smrg	/* Map the frame buffer */
188109885543Smrg	if (pSmi->Chipset == SMI_LYNX3DM)
188209885543Smrg	    pSmi->fbMapOffset = 0x200000;
188309885543Smrg	else
188409885543Smrg	    pSmi->fbMapOffset = 0x0;
188509885543Smrg
188609885543Smrg	pSmi->FBOffset = 0;
188709885543Smrg
188809885543Smrg	pScrn->fbOffset = pSmi->FBOffset + pSmi->fbMapOffset;
188909885543Smrg
189009885543Smrg	pSmi->FBBase = xf86MapPciMem(pScrn->scrnIndex,
189109885543Smrg				     VIDMEM_FRAMEBUFFER,
189209885543Smrg				     pSmi->PciTag,
189309885543Smrg				     pScrn->memPhysBase + pSmi->fbMapOffset,
189409885543Smrg				     pSmi->videoRAMBytes);
189509885543Smrg
189609885543Smrg	if (pSmi->FBBase == NULL) {
189709885543Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Internal error: could not "
189809885543Smrg		       "map framebuffer.\n");
189909885543Smrg	    LEAVE_PROC("SMI_MapMem");
190009885543Smrg	    return FALSE;
190109885543Smrg	}
190209885543Smrg
190309885543Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
190409885543Smrg		       "Physical frame buffer at 0x%08lX offset: 0x%08lX\n",
190509885543Smrg		       pScrn->memPhysBase, pScrn->fbOffset);
190609885543Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
190709885543Smrg		       "Logical frame buffer at %p - %p\n", pSmi->FBBase,
190809885543Smrg		       pSmi->FBBase + pSmi->videoRAMBytes - 1);
190909885543Smrg
191009885543Smrg	/* Set up offset to hwcursor memory area.  It's a 1K chunk at the end of
191109885543Smrg	 * the frame buffer.
191209885543Smrg	 */
191309885543Smrg	pSmi->FBCursorOffset = pSmi->videoRAMBytes - 1024;
191409885543Smrg
191509885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
191609885543Smrg		   "Cursor Offset: %08lX\n",
191709885543Smrg		   (unsigned long)pSmi->FBCursorOffset);
191809885543Smrg
191909885543Smrg	/* set up the fifo reserved space */
192009885543Smrg	if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x01)/* #1074 */ {
192109885543Smrg	    CARD32 fifoOffset = 0;
192209885543Smrg	    fifoOffset |= VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x46) << 3;
192309885543Smrg	    fifoOffset |= VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x47) << 11;
192409885543Smrg	    fifoOffset |= (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49)
192509885543Smrg			& 0x1C) << 17;
192609885543Smrg	    pSmi->FBReserved = fifoOffset;	/* PDR#1074 */
192709885543Smrg	} else {
192809885543Smrg	    pSmi->FBReserved = pSmi->videoRAMBytes - 2048;
192909885543Smrg	}
193009885543Smrg
193109885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Reserved: %08lX\n",
193209885543Smrg		   (unsigned long)pSmi->FBReserved);
193309885543Smrg
193409885543Smrg    }
193509885543Smrg
193609885543Smrg    /* Assign hwp->MemBase & IOBase here */
193709885543Smrg    hwp = VGAHWPTR(pScrn);
193809885543Smrg    if (pSmi->IOBase != NULL) {
193909885543Smrg	vgaHWSetMmioFuncs(hwp, pSmi->MapBase, pSmi->IOBase - pSmi->MapBase);
194009885543Smrg    }
194109885543Smrg    vgaHWGetIOBase(hwp);
194209885543Smrg
194309885543Smrg    /* Map the VGA memory when the primary video */
194409885543Smrg    if (xf86IsPrimaryPci(pSmi->PciInfo)) {
194509885543Smrg	hwp->MapSize = 0x10000;
194609885543Smrg	if (!vgaHWMapMem(pScrn)) {
194709885543Smrg	    LEAVE_PROC("SMI_MapMem");
194809885543Smrg	    return FALSE;
194909885543Smrg	}
195009885543Smrg	pSmi->PrimaryVidMapped = TRUE;
195109885543Smrg    }
195209885543Smrg
195309885543Smrg    LEAVE_PROC("SMI_MapMem");
195409885543Smrg    return TRUE;
195509885543Smrg}
195609885543Smrg
195709885543Smrg/* UnMapMem - contains half of pre-4.0 EnterLeave function.  The EnterLeave
195809885543Smrg * function which en/disable access to IO ports and ext. regs
195909885543Smrg */
196009885543Smrg
196109885543Smrgstatic void
196209885543SmrgSMI_UnmapMem(ScrnInfoPtr pScrn)
196309885543Smrg{
196409885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
196509885543Smrg
196609885543Smrg    ENTER_PROC("SMI_UnmapMem");
196709885543Smrg
196809885543Smrg    /* Unmap VGA mem if mapped. */
196909885543Smrg    if (pSmi->PrimaryVidMapped) {
197009885543Smrg	vgaHWUnmapMem(pScrn);
197109885543Smrg	pSmi->PrimaryVidMapped = FALSE;
197209885543Smrg    }
197309885543Smrg
197409885543Smrg    SMI_DisableMmio(pScrn);
197509885543Smrg
197609885543Smrg    xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pSmi->MapBase, pSmi->MapSize);
197709885543Smrg    if (pSmi->FBBase != NULL) {
197809885543Smrg	xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pSmi->FBBase,
197909885543Smrg			pSmi->videoRAMBytes);
198009885543Smrg    }
198109885543Smrg
198209885543Smrg    LEAVE_PROC("SMI_UnmapMem");
198309885543Smrg}
198409885543Smrg
198509885543Smrg/* This gets called at the start of each server generation. */
198609885543Smrg
198709885543Smrgstatic Bool
198809885543SmrgSMI_ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
198909885543Smrg{
199009885543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
199109885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
199209885543Smrg    EntityInfoPtr pEnt;
199309885543Smrg
199409885543Smrg    ENTER_PROC("SMI_ScreenInit");
199509885543Smrg
199609885543Smrg    /* Map MMIO regs and framebuffer */
199709885543Smrg    if (!SMI_MapMem(pScrn)) {
199809885543Smrg	LEAVE_PROC("SMI_ScreenInit");
199909885543Smrg	return FALSE;
200009885543Smrg    }
200109885543Smrg
200209885543Smrg    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
200309885543Smrg
200409885543Smrg    if (!pSmi->pInt10) {
200509885543Smrg	pSmi->pInt10 = xf86InitInt10(pEnt->index);
200609885543Smrg    }
200709885543Smrg
200809885543Smrg    /* Save the chip/graphics state */
200909885543Smrg    SMI_Save(pScrn);
201009885543Smrg
201109885543Smrg    /* Zero the frame buffer, #258 */
201209885543Smrg    memset(pSmi->FBBase, 0, pSmi->videoRAMBytes);
201309885543Smrg
201409885543Smrg    /* Initialize the first mode */
201509885543Smrg    if (!SMI_ModeInit(pScrn, pScrn->currentMode)) {
201609885543Smrg	LEAVE_PROC("SMI_ScreenInit");
201709885543Smrg	return FALSE;
201809885543Smrg    }
201909885543Smrg
202009885543Smrg    /*
202109885543Smrg     * The next step is to setup the screen's visuals, and initialise the
202209885543Smrg     * framebuffer code.  In cases where the framebuffer's default choises for
202309885543Smrg     * things like visual layouts and bits per RGB are OK, this may be as simple
202409885543Smrg     * as calling the framebuffer's ScreenInit() function.  If not, the visuals
202509885543Smrg     * will need to be setup before calling a fb ScreenInit() function and fixed
202609885543Smrg     * up after.
202709885543Smrg     */
202809885543Smrg
202909885543Smrg    /*
203009885543Smrg     * Reset the visual list.
203109885543Smrg     */
203209885543Smrg    miClearVisualTypes();
203309885543Smrg
203409885543Smrg    /* Setup the visuals we support. */
203509885543Smrg
203609885543Smrg    if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
203709885543Smrg			  pScrn->rgbBits, pScrn->defaultVisual)) {
203809885543Smrg	LEAVE_PROC("SMI_ScreenInit");
203909885543Smrg	return FALSE;
204009885543Smrg    }
204109885543Smrg    if (!miSetPixmapDepths ()) return FALSE;
204209885543Smrg
204309885543Smrg    if (!SMI_InternalScreenInit(scrnIndex, pScreen)) {
204409885543Smrg	LEAVE_PROC("SMI_ScreenInit");
204509885543Smrg	return FALSE;
204609885543Smrg    }
204709885543Smrg
204809885543Smrg    xf86SetBlackWhitePixels(pScreen);
204909885543Smrg
205009885543Smrg    if (pScrn->bitsPerPixel > 8) {
205109885543Smrg	VisualPtr visual;
205209885543Smrg	/* Fixup RGB ordering */
205309885543Smrg	visual = pScreen->visuals + pScreen->numVisuals;
205409885543Smrg	while (--visual >= pScreen->visuals) {
205509885543Smrg	    if ((visual->class | DynamicClass) == DirectColor) {
205609885543Smrg		visual->offsetRed   = pScrn->offset.red;
205709885543Smrg		visual->offsetGreen = pScrn->offset.green;
205809885543Smrg		visual->offsetBlue  = pScrn->offset.blue;
205909885543Smrg		visual->redMask     = pScrn->mask.red;
206009885543Smrg		visual->greenMask   = pScrn->mask.green;
206109885543Smrg		visual->blueMask    = pScrn->mask.blue;
206209885543Smrg	    }
206309885543Smrg	}
206409885543Smrg    }
206509885543Smrg
206609885543Smrg    /* must be after RGB ordering fixed */
206709885543Smrg    fbPictureInit(pScreen, 0, 0);
206809885543Smrg
206909885543Smrg    /* CZ 18.06.2001: moved here from smi_accel.c to have offscreen
207009885543Smrg       framebuffer in NoAccel mode */
207109885543Smrg    if (!pSmi->useEXA) {
207209885543Smrg	int numLines, maxLines;
207309885543Smrg	BoxRec AvailFBArea;
207409885543Smrg
207509885543Smrg	maxLines = pSmi->FBReserved / (pSmi->width * pSmi->Bpp);
207609885543Smrg	if (pSmi->rotate) {
207709885543Smrg	    numLines = maxLines;
207809885543Smrg	} else {
207909885543Smrg	    /* CZ 3.11.2001: What does the following code? see also smi_video.c aaa line 1226 */
208009885543Smrg/*#if SMI_USE_VIDEO */
208109885543Smrg#if 0
208209885543Smrg	    numLines = ((pSmi->FBReserved - pSmi->width * pSmi->Bpp
208309885543Smrg			* pSmi->height) * 25 / 100 + pSmi->width
208409885543Smrg			* pSmi->Bpp - 1) / (pSmi->width * pSmi->Bpp);
208509885543Smrg	    numLines += pSmi->height;
208609885543Smrg#else
208709885543Smrg	    numLines = maxLines;
208809885543Smrg#endif
208909885543Smrg	}
209009885543Smrg
209109885543Smrg	AvailFBArea.x1 = 0;
209209885543Smrg	AvailFBArea.y1 = 0;
209309885543Smrg	AvailFBArea.x2 = pSmi->width;
209409885543Smrg	AvailFBArea.y2 = numLines;
209509885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
209609885543Smrg		   "FrameBuffer Box: %d,%d - %d,%d\n",
209709885543Smrg		   AvailFBArea.x1, AvailFBArea.y1, AvailFBArea.x2,
209809885543Smrg		   AvailFBArea.y2);
209909885543Smrg	xf86InitFBManager(pScreen, &AvailFBArea);
210009885543Smrg    }
210109885543Smrg    /* end CZ */
210209885543Smrg
210309885543Smrg
210409885543Smrg    /* Initialize acceleration layer */
210509885543Smrg    if (!pSmi->NoAccel) {
210609885543Smrg	if (!pSmi->useEXA) {
210709885543Smrg	    if (!SMI_XAAInit(pScreen)) {
210809885543Smrg		LEAVE_PROC("SMI_ScreenInit");
210909885543Smrg		return FALSE;
211009885543Smrg	    }
211109885543Smrg	} else {
211209885543Smrg	    if (!SMI_EXAInit(pScreen)) {
211309885543Smrg		LEAVE_PROC("SMI_ScreenInit");
211409885543Smrg		return FALSE;
211509885543Smrg	    }
211609885543Smrg	}
211709885543Smrg    }
211809885543Smrg
211909885543Smrg    miInitializeBackingStore(pScreen);
212009885543Smrg
212109885543Smrg    /* hardware cursor needs to wrap this layer */
212209885543Smrg    if(!pSmi->NoAccel && !pSmi->useEXA)
212309885543Smrg	SMI_DGAInit(pScreen);
212409885543Smrg
212509885543Smrg    /* Initialise cursor functions */
212609885543Smrg    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
212709885543Smrg
212809885543Smrg    /* Initialize HW cursor layer.  Must follow software cursor
212909885543Smrg     * initialization.
213009885543Smrg     */
213109885543Smrg    if (pSmi->hwcursor) {
213209885543Smrg	if (!SMI_HWCursorInit(pScreen)) {
213309885543Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Hardware cursor "
213409885543Smrg		       "initialization failed\n");
213509885543Smrg	}
213609885543Smrg    }
213709885543Smrg
213809885543Smrg    if (pSmi->shadowFB) {
213909885543Smrg	RefreshAreaFuncPtr refreshArea;
214009885543Smrg
214109885543Smrg	if (pSmi->Chipset == SMI_COUGAR3DR) {
214209885543Smrg	    refreshArea = SMI_RefreshArea730;
214309885543Smrg	} else {
214409885543Smrg	    refreshArea = SMI_RefreshArea;
214509885543Smrg	}
214609885543Smrg
214709885543Smrg	if (pSmi->rotate) {
214809885543Smrg	    if (pSmi->PointerMoved == NULL) {
214909885543Smrg		pSmi->PointerMoved  = pScrn->PointerMoved;
215009885543Smrg		pScrn->PointerMoved = SMI_PointerMoved;
215109885543Smrg	    }
215209885543Smrg	}
215309885543Smrg
215409885543Smrg	ShadowFBInit(pScreen, refreshArea);
215509885543Smrg    }
215609885543Smrg
215709885543Smrg    /* Initialise default colormap */
215809885543Smrg    if (!miCreateDefColormap(pScreen)) {
215909885543Smrg	LEAVE_PROC("SMI_ScreenInit");
216009885543Smrg	return FALSE;
216109885543Smrg    }
216209885543Smrg
216309885543Smrg    /* Initialize colormap layer.  Must follow initialization of the default
216409885543Smrg     * colormap.  And SetGamma call, else it will load palette with solid white.
216509885543Smrg     */
216609885543Smrg    /* CZ 2.11.2001: CMAP_PALETTED_TRUECOLOR for gamma correction */
216709885543Smrg    if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, SMI_LoadPalette, NULL,
216809885543Smrg            CMAP_RELOAD_ON_MODE_SWITCH | CMAP_PALETTED_TRUECOLOR)) {
216909885543Smrg	LEAVE_PROC("SMI_ScreenInit");
217009885543Smrg	return FALSE;
217109885543Smrg    }
217209885543Smrg
217309885543Smrg    pScreen->SaveScreen = SMI_SaveScreen;
217409885543Smrg    pSmi->CloseScreen = pScreen->CloseScreen;
217509885543Smrg    pScreen->CloseScreen = SMI_CloseScreen;
217609885543Smrg
217709885543Smrg    if (!xf86DPMSInit(pScreen, SMI_DisplayPowerManagementSet, 0)) {
217809885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed!\n");
217909885543Smrg    }
218009885543Smrg
218109885543Smrg    if (!pSmi->Dualhead)
218209885543Smrg  	SMI_InitVideo(pScreen);
218309885543Smrg    else
218409885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No overlay in dualhead mode\n");
218509885543Smrg
218609885543Smrg    /* Report any unused options (only for the first generation) */
218709885543Smrg    if (serverGeneration == 1) {
218809885543Smrg	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
218909885543Smrg    }
219009885543Smrg
219109885543Smrg    LEAVE_PROC("SMI_ScreenInit");
219209885543Smrg    return TRUE;
219309885543Smrg}
219409885543Smrg
219509885543Smrg/* Common init routines needed in EnterVT and ScreenInit */
219609885543Smrg
219709885543Smrgstatic int
219809885543SmrgSMI_InternalScreenInit(int scrnIndex, ScreenPtr pScreen)
219909885543Smrg{
220009885543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
220109885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
220209885543Smrg    int width, height, displayWidth;
220309885543Smrg    int bytesPerPixel = pScrn->bitsPerPixel / 8;
220409885543Smrg    int xDpi, yDpi;
220509885543Smrg    int ret;
220609885543Smrg
220709885543Smrg    ENTER_PROC("SMI_InternalScreenInit");
220809885543Smrg
220909885543Smrg    if (pSmi->rotate) {
221009885543Smrg	width        = pScrn->virtualY;
221109885543Smrg	height       = pScrn->virtualX;
221209885543Smrg	xDpi         = pScrn->yDpi;
221309885543Smrg	yDpi         = pScrn->xDpi;
221409885543Smrg	displayWidth = ((width * bytesPerPixel + 15) & ~15) / bytesPerPixel;
221509885543Smrg    } else {
221609885543Smrg	width        = pScrn->virtualX;
221709885543Smrg	height       = pScrn->virtualY;
221809885543Smrg	xDpi		 = pScrn->xDpi;
221909885543Smrg	yDpi		 = pScrn->yDpi;
222009885543Smrg	displayWidth = pScrn->displayWidth;
222109885543Smrg    }
222209885543Smrg
222309885543Smrg    if (pSmi->shadowFB) {
222409885543Smrg	pSmi->ShadowWidth      = width;
222509885543Smrg	pSmi->ShadowHeight     = height;
222609885543Smrg	pSmi->ShadowWidthBytes = (width * bytesPerPixel + 15) & ~15;
222709885543Smrg	if (bytesPerPixel == 3) {
222809885543Smrg	    pSmi->ShadowPitch = ((height * 3) << 16)
222909885543Smrg			      | pSmi->ShadowWidthBytes;
223009885543Smrg	} else {
223109885543Smrg	    pSmi->ShadowPitch = (height << 16)
223209885543Smrg			      | (pSmi->ShadowWidthBytes / bytesPerPixel);
223309885543Smrg	}
223409885543Smrg
223509885543Smrg	pSmi->saveBufferSize = pSmi->ShadowWidthBytes * pSmi->ShadowHeight;
223609885543Smrg	pSmi->FBReserved -= pSmi->saveBufferSize;
223709885543Smrg	pSmi->FBReserved &= ~0x15;
223809885543Smrg	WRITE_VPR(pSmi, 0x0C, (pSmi->FBOffset = pSmi->FBReserved) >> 3);
223909885543Smrg	if (pSmi->Chipset == SMI_COUGAR3DR) {
224009885543Smrg	    WRITE_FPR(pSmi, FPR0C, (pSmi->FBOffset = pSmi->FBReserved) >> 3);
224109885543Smrg	}
224209885543Smrg	pScrn->fbOffset = pSmi->FBOffset + pSmi->fbMapOffset;
224309885543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
224409885543Smrg		   "Shadow: width=%d height=%d "
224509885543Smrg		   "offset=0x%08lX pitch=0x%08X\n",
224609885543Smrg		   pSmi->ShadowWidth, pSmi->ShadowHeight,
224709885543Smrg		   (unsigned long)pSmi->FBOffset,
224809885543Smrg		   pSmi->ShadowPitch);
224909885543Smrg    } else {
225009885543Smrg	pSmi->FBOffset = 0;
225109885543Smrg	pScrn->fbOffset = pSmi->FBOffset + pSmi->fbMapOffset;
225209885543Smrg    }
225309885543Smrg
225409885543Smrg    /*
225509885543Smrg     * Call the framebuffer layer's ScreenInit function, and fill in other
225609885543Smrg     * pScreen fields.
225709885543Smrg     */
225809885543Smrg
225909885543Smrg    DEBUG((VERBLEV, "\tInitializing FB @ 0x%08X for %dx%d (%d)\n",
226009885543Smrg	   pSmi->FBBase, width, height, displayWidth));
226109885543Smrg    switch (pScrn->bitsPerPixel) {
226209885543Smrg    case 8:
226309885543Smrg    case 16:
226409885543Smrg    case 24:
226509885543Smrg    case 32:
226609885543Smrg	ret = fbScreenInit(pScreen, pSmi->FBBase, width, height, xDpi,
226709885543Smrg			   yDpi, displayWidth, pScrn->bitsPerPixel);
226809885543Smrg	break;
226909885543Smrg    default:
227009885543Smrg	xf86DrvMsg(scrnIndex, X_ERROR, "Internal error: invalid bpp (%d) "
227109885543Smrg		   "in SMI_InternalScreenInit\n", pScrn->bitsPerPixel);
227209885543Smrg	LEAVE_PROC("SMI_InternalScreenInit");
227309885543Smrg	return FALSE;
227409885543Smrg    }
227509885543Smrg
227609885543Smrg    LEAVE_PROC("SMI_InternalScreenInit");
227709885543Smrg    return ret;
227809885543Smrg}
227909885543Smrg
228009885543Smrg/* Checks if a mode is suitable for the selected configuration. */
228109885543Smrgstatic ModeStatus
228209885543SmrgSMI_ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
228309885543Smrg{
228409885543Smrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
228509885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
228609885543Smrg    float refresh;
228709885543Smrg
228809885543Smrg    ENTER_PROC("SMI_ValidMode");
228909885543Smrg    refresh = (mode->VRefresh > 0) ? mode->VRefresh
229009885543Smrg	    : mode->Clock * 1000.0 / mode->VTotal / mode->HTotal;
229109885543Smrg    xf86DrvMsg(scrnIndex, X_INFO, "Mode: %dx%d %d-bpp, %fHz\n", mode->HDisplay,
229209885543Smrg	       mode->VDisplay, pScrn->bitsPerPixel, refresh);
229309885543Smrg
229409885543Smrg    if (pSmi->shadowFB) {
229509885543Smrg	int mem;
229609885543Smrg
229709885543Smrg	if (pScrn->bitsPerPixel == 24) {
229809885543Smrg	    LEAVE_PROC("SMI_ValidMode");
229909885543Smrg	    return MODE_BAD;
230009885543Smrg	}
230109885543Smrg
230209885543Smrg	mem  = (pScrn->virtualX * pScrn->bitsPerPixel / 8 + 15) & ~15;
230309885543Smrg	mem *= pScrn->virtualY * 2;
230409885543Smrg
230509885543Smrg	if (mem > pSmi->FBReserved) /* PDR#1074 */ {
230609885543Smrg	    LEAVE_PROC("SMI_ValidMode");
230709885543Smrg	    return MODE_MEM;
230809885543Smrg	}
230909885543Smrg    }
231009885543Smrg
231109885543Smrg    if (!pSmi->useBIOS || pSmi->lcd) {
231209885543Smrg#if 1 /* PDR#983 */
231309885543Smrg	if (pSmi->zoomOnLCD) {
231409885543Smrg	    if ((mode->HDisplay > pSmi->lcdWidth) ||
231509885543Smrg		(mode->VDisplay > pSmi->lcdHeight)) {
231609885543Smrg		LEAVE_PROC("SMI_ValidMode");
231709885543Smrg		return MODE_PANEL;
231809885543Smrg	    }
231909885543Smrg	} else
232009885543Smrg#endif
232109885543Smrg	{
232209885543Smrg	    if ((mode->HDisplay != pSmi->lcdWidth) ||
232309885543Smrg		(mode->VDisplay != pSmi->lcdHeight)) {
232409885543Smrg		LEAVE_PROC("SMI_ValidMode");
232509885543Smrg		return MODE_PANEL;
232609885543Smrg	    }
232709885543Smrg	}
232809885543Smrg    }
232909885543Smrg
233009885543Smrg#if 1 /* PDR#944 */
233109885543Smrg    if (pSmi->rotate) {
233209885543Smrg	if ((mode->HDisplay != pSmi->lcdWidth) ||
233309885543Smrg	    (mode->VDisplay != pSmi->lcdHeight)) {
233409885543Smrg	    LEAVE_PROC("SMI_ValidMode");
233509885543Smrg	    return MODE_PANEL;
233609885543Smrg	}
233709885543Smrg    }
233809885543Smrg#endif
233909885543Smrg
234009885543Smrg    LEAVE_PROC("SMI_ValidMode");
234109885543Smrg    return MODE_OK;
234209885543Smrg}
234309885543Smrg
234409885543Smrgstatic void
234509885543SmrgSMI_DPRInit(ScrnInfoPtr pScrn)
234609885543Smrg{
234709885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
234809885543Smrg    int i;
234909885543Smrg    int xyAddress[] = { 320, 400, 512, 640, 800, 1024, 1280, 1600, 2048 };
235009885543Smrg    CARD32 DEDataFormat = 0;
235109885543Smrg
235209885543Smrg    /* Store values to current mode register structs */
235309885543Smrg    SMIRegPtr new = &pSmi->ModeReg;
235409885543Smrg
235509885543Smrg    /* Set DPR registers */
235609885543Smrg    pSmi->Stride = (pSmi->width * pSmi->Bpp + 15) & ~15;
235709885543Smrg    switch (pScrn->bitsPerPixel) {
235809885543Smrg    case 8:
235909885543Smrg	DEDataFormat = 0x00000000;
236009885543Smrg	break;
236109885543Smrg    case 16:
236209885543Smrg	pSmi->Stride >>= 1;
236309885543Smrg	DEDataFormat = 0x00100000;
236409885543Smrg	break;
236509885543Smrg    case 24:
236609885543Smrg	DEDataFormat = 0x00300000;
236709885543Smrg	break;
236809885543Smrg    case 32:
236909885543Smrg	pSmi->Stride >>= 2;
237009885543Smrg	DEDataFormat = 0x00200000;
237109885543Smrg	break;
237209885543Smrg    }
237309885543Smrg
237409885543Smrg    for (i = 0; i < sizeof(xyAddress) / sizeof(xyAddress[0]); i++) {
237509885543Smrg	if (pSmi->rotate) {
237609885543Smrg	    if (xyAddress[i] == pSmi->height) {
237709885543Smrg		DEDataFormat |= i << 16;
237809885543Smrg		break;
237909885543Smrg	    }
238009885543Smrg	} else {
238109885543Smrg	    if (xyAddress[i] == pSmi->width) {
238209885543Smrg		DEDataFormat |= i << 16;
238309885543Smrg		break;
238409885543Smrg	    }
238509885543Smrg	}
238609885543Smrg    }
238709885543Smrg
238809885543Smrg    new->DPR10 = (pSmi->Stride << 16) | pSmi->Stride;
238909885543Smrg    new->DPR1C = DEDataFormat;
239009885543Smrg    new->DPR20 = 0;
239109885543Smrg    new->DPR24 = 0xFFFFFFFF;
239209885543Smrg    new->DPR28 = 0xFFFFFFFF;
239309885543Smrg    new->DPR2C = 0;
239409885543Smrg    new->DPR30 = 0;
239509885543Smrg    new->DPR3C = (pSmi->Stride << 16) | pSmi->Stride;
239609885543Smrg    new->DPR40 = pSmi->FBOffset >> 3;
239709885543Smrg    new->DPR44 = pSmi->FBOffset >> 3;
239809885543Smrg
239909885543Smrg}
240009885543Smrg
240109885543Smrgstatic Bool
240209885543SmrgSMI_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
240309885543Smrg{
240409885543Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
240509885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
240609885543Smrg    unsigned char tmp;
240709885543Smrg    int panelIndex, modeIndex, i, vclk;
240809885543Smrg
240909885543Smrg    /* Store values to current mode register structs */
241009885543Smrg    SMIRegPtr new = &pSmi->ModeReg;
241109885543Smrg    vgaRegPtr vganew = &hwp->ModeReg;
241209885543Smrg
241309885543Smrg    ENTER_PROC("SMI_ModeInit");
241409885543Smrg
241509885543Smrg    if (!vgaHWInit(pScrn, mode)) {
241609885543Smrg	LEAVE_PROC("SMI_ModeInit");
241709885543Smrg	return FALSE;
241809885543Smrg    }
241909885543Smrg
242009885543Smrg    new->modeInit = TRUE;
242109885543Smrg
242209885543Smrg    if (pSmi->rotate) {
242309885543Smrg	pSmi->width  = pScrn->virtualY;
242409885543Smrg	pSmi->height = pScrn->virtualX;
242509885543Smrg    } else {
242609885543Smrg	pSmi->width  = pScrn->virtualX;
242709885543Smrg	pSmi->height = pScrn->virtualY;
242809885543Smrg    }
242909885543Smrg    pSmi->Bpp    = pScrn->bitsPerPixel / 8;
243009885543Smrg
243109885543Smrg    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x17);
243209885543Smrg    tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
243309885543Smrg    if (pSmi->pci_burst) {
243409885543Smrg	new->SR17 = tmp | 0x20;
243509885543Smrg    } else {
243609885543Smrg	new->SR17 = tmp & ~0x20;
243709885543Smrg    }
243809885543Smrg
243909885543Smrg    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
244009885543Smrg    new->SR18 = inb(pSmi->PIOBase + VGA_SEQ_DATA) | 0x11;
244109885543Smrg
244209885543Smrg    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21);
244309885543Smrg    new->SR21 = inb(pSmi->PIOBase + VGA_SEQ_DATA) & ~0x03;
244409885543Smrg
244509885543Smrg    if (pSmi->Chipset != SMI_COUGAR3DR) {
244609885543Smrg	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x31);
244709885543Smrg	new->SR31 = inb(pSmi->PIOBase + VGA_SEQ_DATA) & ~0xC0;
244809885543Smrg
244909885543Smrg	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x32);
245009885543Smrg	new->SR32 = inb(pSmi->PIOBase + VGA_SEQ_DATA) & ~0x07;
245109885543Smrg
245209885543Smrg	if (SMI_LYNXM_SERIES(pSmi->Chipset)) {
245309885543Smrg	    new->SR32 |= 0x04;
245409885543Smrg	}
245509885543Smrg    }
245609885543Smrg
245709885543Smrg    new->SRA0 = new->CR33 = new->CR3A = 0x00;
245809885543Smrg
245909885543Smrg    if (pSmi->lcdWidth == 640) {
246009885543Smrg	panelIndex = 0;
246109885543Smrg    } else if (pSmi->lcdWidth == 800) {
246209885543Smrg	panelIndex = 1;
246309885543Smrg    } else {
246409885543Smrg	panelIndex = 2;
246509885543Smrg    }
246609885543Smrg
246709885543Smrg    if (mode->HDisplay == 640) {
246809885543Smrg	modeIndex = 0;
246909885543Smrg    } else if (mode->HDisplay == 800) {
247009885543Smrg	modeIndex = 1;
247109885543Smrg    } else {
247209885543Smrg	modeIndex = 2;
247309885543Smrg    }
247409885543Smrg
247509885543Smrg    if (SMI_LYNXM_SERIES(pSmi->Chipset)) {
247609885543Smrg	static unsigned char PanelTable[3][14] =
247709885543Smrg	    {
247809885543Smrg		{ 0x5F, 0x4F, 0x00, 0x52, 0x1E, 0x0B, 0xDF, 0x00, 0xE9, 0x0B, 0x2E,
247909885543Smrg		  0x00, 0x4F, 0xDF },
248009885543Smrg		{ 0x7F, 0x63, 0x00, 0x69, 0x19, 0x72, 0x57, 0x00, 0x58, 0x0C, 0xA2,
248109885543Smrg		  0x20, 0x4F, 0xDF },
248209885543Smrg		{ 0xA3, 0x7F, 0x00, 0x83, 0x14, 0x24, 0xFF, 0x00, 0x02, 0x08, 0xA7,
248309885543Smrg		  0xE0, 0x4F, 0xDF },
248409885543Smrg	    };
248509885543Smrg
248609885543Smrg	for (i = 0; i < 14; i++) {
248709885543Smrg	    new->CR40[i] = PanelTable[panelIndex][i];
248809885543Smrg	}
248909885543Smrg	new->CR90[14] = 0x03;
249009885543Smrg	new->CR90[15] = 0x00;
249109885543Smrg	if (mode->VDisplay < pSmi->lcdHeight) {
249209885543Smrg	    new->CRA0[6] = (pSmi->lcdHeight - mode->VDisplay) / 8;
249309885543Smrg	} else {
249409885543Smrg	    new->CRA0[6] = 0;
249509885543Smrg	}
249609885543Smrg
249709885543Smrg	if (mode->HDisplay < pSmi->lcdWidth) {
249809885543Smrg	    new->CRA0[7] = (pSmi->lcdWidth - mode->HDisplay) / 16;
249909885543Smrg	} else {
250009885543Smrg	    new->CRA0[7] = 0;
250109885543Smrg	}
250209885543Smrg    } else {
250309885543Smrg	static unsigned char PanelTable[3][3][14] =
250409885543Smrg	    {
250509885543Smrg		{ /* 640x480 panel */
250609885543Smrg		    { 0x5F, 0x4F, 0x00, 0x53, 0x00, 0x0B, 0xDF, 0x00, 0xEA, 0x0C,
250709885543Smrg		      0x2E, 0x00, 0x4F, 0xDF },
250809885543Smrg		    { 0x5F, 0x4F, 0x00, 0x53, 0x00, 0x0B, 0xDF, 0x00, 0xEA, 0x0C,
250909885543Smrg		      0x2E, 0x00, 0x4F, 0xDF },
251009885543Smrg		    { 0x5F, 0x4F, 0x00, 0x53, 0x00, 0x0B, 0xDF, 0x00, 0xEA, 0x0C,
251109885543Smrg		      0x2E, 0x00, 0x4F, 0xDF },
251209885543Smrg		},
251309885543Smrg		{ /* 800x600 panel */
251409885543Smrg		    { 0x7F, 0x59, 0x19, 0x5E, 0x8E, 0x72, 0x1C, 0x37, 0x1D, 0x00,
251509885543Smrg		      0xA2, 0x20, 0x4F, 0xDF },
251609885543Smrg		    { 0x7F, 0x63, 0x00, 0x68, 0x18, 0x72, 0x58, 0x00, 0x59, 0x0C,
251709885543Smrg		      0xE0, 0x20, 0x63, 0x57 },
251809885543Smrg		    { 0x7F, 0x63, 0x00, 0x68, 0x18, 0x72, 0x58, 0x00, 0x59, 0x0C,
251909885543Smrg		      0xE0, 0x20, 0x63, 0x57 },
252009885543Smrg		},
252109885543Smrg		{ /* 1024x768 panel */
252209885543Smrg		    { 0xA3, 0x67, 0x0F, 0x6D, 0x1D, 0x24, 0x70, 0x95, 0x72, 0x07,
252309885543Smrg		      0xA3, 0x20, 0x4F, 0xDF },
252409885543Smrg		    { 0xA3, 0x71, 0x19, 0x77, 0x07, 0x24, 0xAC, 0xD1, 0xAE, 0x03,
252509885543Smrg		      0xE1, 0x20, 0x63, 0x57 },
252609885543Smrg		    { 0xA3, 0x7F, 0x00, 0x85, 0x15, 0x24, 0xFF, 0x00, 0x01, 0x07,
252709885543Smrg		      0xE5, 0x20, 0x7F, 0xFF },
252809885543Smrg		},
252909885543Smrg	    };
253009885543Smrg
253109885543Smrg	for (i = 0; i < 14; i++) {
253209885543Smrg	    new->CR40[i] = PanelTable[panelIndex][modeIndex][i];
253309885543Smrg	}
253409885543Smrg    }
253509885543Smrg
253609885543Smrg    /* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */
253709885543Smrg    new->CCR66 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66);
253809885543Smrg    if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR)) {
253909885543Smrg	switch (pScrn->bitsPerPixel) {
254009885543Smrg	case 8:
254109885543Smrg	    new->CCR66 = (new->CCR66 & 0xF3) | 0x00; /* 6 bits-RAM */
254209885543Smrg	    break;
254309885543Smrg	case 16:
254409885543Smrg	    new->CCR66 = (new->CCR66 & 0xF3) | 0x00; /* 6 bits-RAM */
254509885543Smrg	    /* no Gamma correction in 16 Bit mode (s. Release.txt 1.3.1) */
254609885543Smrg	    break;
254709885543Smrg	case 24:
254809885543Smrg	case 32:
254909885543Smrg	    new->CCR66 = (new->CCR66 & 0xF3) | 0x04; /* Gamma correct ON */
255009885543Smrg	    break;
255109885543Smrg	default:
255209885543Smrg	    LEAVE_PROC("SMI_ModeInit");
255309885543Smrg	    return FALSE;
255409885543Smrg	}
255509885543Smrg    }
255609885543Smrg
255709885543Smrg    if (pSmi->Chipset != SMI_COUGAR3DR) {
255809885543Smrg	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x30);
255909885543Smrg	if (inb(pSmi->PIOBase + VGA_SEQ_DATA) & 0x01) {
256009885543Smrg	    new->SR21 = 0x00;
256109885543Smrg	}
256209885543Smrg    }
256309885543Smrg
256409885543Smrg    if (pSmi->MCLK > 0) {
256509885543Smrg	SMI_CommonCalcClock(pScrn->scrnIndex, pSmi->MCLK,
256609885543Smrg			    1, 1, 63, 0, 2,
256709885543Smrg                            pScrn->clockRanges->minClock,
256809885543Smrg                            pScrn->clockRanges->maxClock,
256909885543Smrg                            &new->SR6A, &new->SR6B);
257009885543Smrg    } else {
257109885543Smrg	new->SR6B = 0xFF;
257209885543Smrg    }
257309885543Smrg
257409885543Smrg    if ((mode->HDisplay == 640) && SMI_LYNXM_SERIES(pSmi->Chipset)) {
257509885543Smrg	vganew->MiscOutReg &= ~0x0C;
257609885543Smrg    } else {
257709885543Smrg	vganew->MiscOutReg |= 0x0C;
257809885543Smrg    }
257909885543Smrg    vganew->MiscOutReg |= 0xE0;
258009885543Smrg    if (mode->HDisplay == 800) {
258109885543Smrg	vganew->MiscOutReg &= ~0xC0;
258209885543Smrg    }
258309885543Smrg    if ((mode->HDisplay == 1024) && SMI_LYNXM_SERIES(pSmi->Chipset)) {
258409885543Smrg	vganew->MiscOutReg &= ~0xC0;
258509885543Smrg    }
258609885543Smrg
258709885543Smrg    /* calculate vclk1 */
258809885543Smrg    vclk = mode->Clock;
258909885543Smrg    if (SMI_LYNX_SERIES(pSmi->Chipset)) {
259009885543Smrg        SMI_CommonCalcClock(pScrn->scrnIndex, vclk,
259109885543Smrg			1, 1, 63, 0, 2,
259209885543Smrg                        pScrn->clockRanges->minClock,
259309885543Smrg                        pScrn->clockRanges->maxClock,
259409885543Smrg                        &new->SR6C, &new->SR6D);
259509885543Smrg    } else {
259609885543Smrg        SMI_CommonCalcClock(pScrn->scrnIndex, vclk,
259709885543Smrg			1, 1, 63, 0, 1,
259809885543Smrg                        pScrn->clockRanges->minClock,
259909885543Smrg                        pScrn->clockRanges->maxClock,
260009885543Smrg                        &new->SR6C, &new->SR6D);
260109885543Smrg    }
260209885543Smrg
260309885543Smrg    /* use vclk1 */
260409885543Smrg    new->SR68 = 0x54;
260509885543Smrg
260609885543Smrg    /* dualhead */
260709885543Smrg    if (pSmi->Dualhead) {
260809885543Smrg	/* PLL controls */
260909885543Smrg	/* set LCD to vclk2 */
261009885543Smrg	new->SR69 = 0x04;
261109885543Smrg
261209885543Smrg	if (pSmi->lcdWidth == 640) {
261309885543Smrg	    /* vclk */
261409885543Smrg	    new->SR6C = 0x07;
261509885543Smrg	    new->SR6D = 0x04;
261609885543Smrg
261709885543Smrg	    /* vclk2 */
261809885543Smrg	    new->SR6E = 0x07;
261909885543Smrg	    new->SR6F = 0x04;
262009885543Smrg	} else if (pSmi->lcdWidth == 800) {
262109885543Smrg	    /* vclk */
262209885543Smrg	    new->SR6C = 0x0B;
262309885543Smrg	    new->SR6D = 0x82;
262409885543Smrg
262509885543Smrg	    /* vclk2 */
262609885543Smrg	    new->SR6E = 0x0B;
262709885543Smrg	    new->SR6F = 0x82;
262809885543Smrg	} else {
262909885543Smrg	    /* vclk */
263009885543Smrg	    new->SR6C = 0x52;
263109885543Smrg	    new->SR6D = 0x89;
263209885543Smrg
263309885543Smrg	    /* vclk2 */
263409885543Smrg	    new->SR6E = 0x52;
263509885543Smrg	    new->SR6F = 0x89;
263609885543Smrg	}
263709885543Smrg
263809885543Smrg	/* TFT panel uses FIFO1, DSTN panel uses FIFO1 for upper panel and
263909885543Smrg	 * FIFO2 for lower panel.  I don't have a DSTN panel, so it's untested.
264009885543Smrg	 * -- AGD
264109885543Smrg	 */
264209885543Smrg	CARD32 fifo1_readoffset, fifo2_readoffset, fifo_writeoffset;
264309885543Smrg
264409885543Smrg	/* setting SR21 bit 2 disables ZV circuitry,
264509885543Smrg	 * if ZV is needed, SR21 = 0x20
264609885543Smrg	 */
264709885543Smrg	/* enable DAC, PLL, etc. */
264809885543Smrg	new->SR21 = 0x24;
264909885543Smrg
265009885543Smrg	/* clear DPMS state */
265109885543Smrg	new->SR22 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22) & ~0x30;
265209885543Smrg
265309885543Smrg	/* enable virtual refresh and LCD and CRT outputs */
265409885543Smrg	if (pScrn->bitsPerPixel > 8)
265509885543Smrg	    new->SR31 = /*0xCB*/ 0xC3; /* 16 bpp */
265609885543Smrg	else
265709885543Smrg	    new->SR31 = /*0x8B*/ 0x83; /* 8 bpp */
265809885543Smrg
265909885543Smrg	/* FIFO1 Read Offset */
266009885543Smrg	fifo1_readoffset = pSmi->lcdWidth / 2;
266109885543Smrg	fifo2_readoffset = pSmi->lcdWidth / 2;
266209885543Smrg	new->SR44 = fifo1_readoffset & 0x000000FF;
266309885543Smrg	/* FIFO2 Read Offset */
266409885543Smrg	new->SR4B = fifo2_readoffset & 0x000000FF;
266509885543Smrg	/* FIFO1/2 Read Offset overflow */
266609885543Smrg	new->SR4C = (((fifo1_readoffset & 0x00000300) >> 8) << 2) |
266709885543Smrg		    (((fifo2_readoffset & 0x00000300) >> 8) << 6);
266809885543Smrg
266909885543Smrg	/* FIFO Write Offset */
267009885543Smrg	fifo_writeoffset = pSmi->lcdWidth / 4;
267109885543Smrg	new->SR48 = fifo_writeoffset & 0x000000FF;
267209885543Smrg	new->SR49 = (fifo_writeoffset & 0x00000300) >> 8;
267309885543Smrg
267409885543Smrg	/* set FIFO levels */
267509885543Smrg	new->SR4A = 0x41;
267609885543Smrg
267709885543Smrg	/* something related to tv... */
267809885543Smrg	new->CR33 |= 0x07;
267909885543Smrg
268009885543Smrg    }
268109885543Smrg
268209885543Smrg    /* init graphics engine regs */
268309885543Smrg    SMI_DPRInit(pScrn);
268409885543Smrg
268509885543Smrg    /* Set VPR registers (and FPR registers for SM731) */
268609885543Smrg    switch (pScrn->bitsPerPixel) {
268709885543Smrg    case 8:
268809885543Smrg	new->VPR00 = 0x00000000;
268909885543Smrg	new->FPR00_= 0x00080000;
269009885543Smrg	break;
269109885543Smrg    case 16:
269209885543Smrg	new->VPR00 = 0x00020000;
269309885543Smrg	new->FPR00_= 0x000A0000;
269409885543Smrg	break;
269509885543Smrg    case 24:
269609885543Smrg	new->VPR00 = 0x00040000;
269709885543Smrg	new->FPR00_= 0x000C0000;
269809885543Smrg	break;
269909885543Smrg    case 32:
270009885543Smrg	new->VPR00 = 0x00030000;
270109885543Smrg	new->FPR00_= 0x000B0000;
270209885543Smrg	break;
270309885543Smrg    }
270409885543Smrg    new->VPR0C = pSmi->FBOffset >> 3;
270509885543Smrg    if (pSmi->rotate) {
270609885543Smrg	new->VPR10 = (((( pSmi->height * pSmi->Bpp) >> 3) + 2) << 16) |
270709885543Smrg		     ((pSmi->height * pSmi->Bpp) >> 3);
270809885543Smrg    } else {
270909885543Smrg	new->VPR10 = ((((pSmi->width * pSmi->Bpp) >> 3) + 2) << 16) |
271009885543Smrg		     ((pSmi->width * pSmi->Bpp) >> 3);
271109885543Smrg    }
271209885543Smrg
271309885543Smrg    new->FPR0C_ = new->VPR0C;
271409885543Smrg    new->FPR10_ = new->VPR10;
271509885543Smrg
271609885543Smrg    /* Set CPR registers */
271709885543Smrg    new->CPR00 = 0x00000000;
271809885543Smrg
271909885543Smrg    pScrn->vtSema = TRUE;
272009885543Smrg
272109885543Smrg    /* Find the INT 10 mode number */
272209885543Smrg    {
272309885543Smrg	static struct {
272409885543Smrg	    int x, y, bpp;
272509885543Smrg	    CARD16 mode;
272609885543Smrg	} modeTable[] =
272709885543Smrg	    {
272809885543Smrg		{  640,  480,  8, 0x50 },
272909885543Smrg		{  640,  480, 16, 0x52 },
273009885543Smrg		{  640,  480, 24, 0x53 },
273109885543Smrg		{  640,  480, 32, 0x54 },
273209885543Smrg		{  800,  480,  8, 0x4A },
273309885543Smrg		{  800,  480, 16, 0x4C },
273409885543Smrg		{  800,  480, 24, 0x4D },
273509885543Smrg		{  800,  600,  8, 0x55 },
273609885543Smrg		{  800,  600, 16, 0x57 },
273709885543Smrg		{  800,  600, 24, 0x58 },
273809885543Smrg		{  800,  600, 32, 0x59 },
273909885543Smrg		{ 1024,  768,  8, 0x60 },
274009885543Smrg		{ 1024,  768, 16, 0x62 },
274109885543Smrg		{ 1024,  768, 24, 0x63 },
274209885543Smrg		{ 1024,  768, 32, 0x64 },
274309885543Smrg		{ 1280, 1024,  8, 0x65 },
274409885543Smrg		{ 1280, 1024, 16, 0x67 },
274509885543Smrg		{ 1280, 1024, 24, 0x68 },
274609885543Smrg		{ 1280, 1024, 32, 0x69 },
274709885543Smrg	    };
274809885543Smrg
274909885543Smrg	new->mode = 0;
275009885543Smrg	for (i = 0; i < sizeof(modeTable) / sizeof(modeTable[0]); i++) {
275109885543Smrg	    if ((modeTable[i].x == mode->HDisplay) &&
275209885543Smrg		(modeTable[i].y == mode->VDisplay) &&
275309885543Smrg		(modeTable[i].bpp == pScrn->bitsPerPixel)) {
275409885543Smrg		new->mode = modeTable[i].mode;
275509885543Smrg		break;
275609885543Smrg	    }
275709885543Smrg	}
275809885543Smrg    }
275909885543Smrg
276009885543Smrg    /* Zero the font memory */
276109885543Smrg    memset(new->smiFont, 0, sizeof(new->smiFont));
276209885543Smrg
276309885543Smrg    /* Write the mode registers to hardware */
276409885543Smrg    SMI_WriteMode(pScrn, vganew, new);
276509885543Smrg
276609885543Smrg    /* Adjust the viewport */
276709885543Smrg    SMI_AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
276809885543Smrg
276909885543Smrg    LEAVE_PROC("SMI_ModeInit");
277009885543Smrg    return TRUE;
277109885543Smrg}
277209885543Smrg
277309885543Smrg/*
277409885543Smrg * This is called at the end of each server generation.  It restores the
277509885543Smrg * original (text) mode.  It should also unmap the video memory, and free any
277609885543Smrg * per-generation data allocated by the driver.  It should finish by unwrapping
277709885543Smrg * and calling the saved CloseScreen function.
277809885543Smrg */
277909885543Smrg
278009885543Smrgstatic Bool
278109885543SmrgSMI_CloseScreen(int scrnIndex, ScreenPtr pScreen)
278209885543Smrg{
278309885543Smrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
278409885543Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
278509885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
278609885543Smrg    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
278709885543Smrg    SMIRegPtr SMISavePtr = &pSmi->SavedReg;
278809885543Smrg    Bool ret;
278909885543Smrg
279009885543Smrg    ENTER_PROC("SMI_CloseScreen");
279109885543Smrg
279209885543Smrg    if (pScrn->vtSema) {
279309885543Smrg	SMI_WriteMode(pScrn, vgaSavePtr, SMISavePtr);
279409885543Smrg	vgaHWLock(hwp);
279509885543Smrg	SMI_UnmapMem(pScrn);
279609885543Smrg    }
279709885543Smrg
279809885543Smrg    if (pSmi->XAAInfoRec != NULL) {
279909885543Smrg	XAADestroyInfoRec(pSmi->XAAInfoRec);
280009885543Smrg    }
280109885543Smrg    if (pSmi->EXADriverPtr) {
280209885543Smrg	exaDriverFini(pScreen);
280309885543Smrg	pSmi->EXADriverPtr = NULL;
280409885543Smrg    }
280509885543Smrg    if (pSmi->CursorInfoRec != NULL) {
280609885543Smrg	xf86DestroyCursorInfoRec(pSmi->CursorInfoRec);
280709885543Smrg    }
280809885543Smrg    if (pSmi->DGAModes != NULL) {
280909885543Smrg	xfree(pSmi->DGAModes);
281009885543Smrg    }
281109885543Smrg    if (pSmi->pInt10 != NULL) {
281209885543Smrg	xf86FreeInt10(pSmi->pInt10);
281309885543Smrg	pSmi->pInt10 = NULL;
281409885543Smrg    }
281509885543Smrg    if (pSmi->ptrAdaptor != NULL) {
281609885543Smrg	xfree(pSmi->ptrAdaptor);
281709885543Smrg    }
281809885543Smrg    if (pSmi->BlockHandler != NULL) {
281909885543Smrg	pScreen->BlockHandler = pSmi->BlockHandler;
282009885543Smrg    }
282109885543Smrg    /* #670 */
282209885543Smrg    if (pSmi->pSaveBuffer) {
282309885543Smrg	xfree(pSmi->pSaveBuffer);
282409885543Smrg    }
282509885543Smrg/* #920 */
282609885543Smrg    if (pSmi->paletteBuffer) {
282709885543Smrg	xfree(pSmi->paletteBuffer);
282809885543Smrg    }
282909885543Smrg
283009885543Smrg    pScrn->vtSema = FALSE;
283109885543Smrg    pScreen->CloseScreen = pSmi->CloseScreen;
283209885543Smrg    ret = (*pScreen->CloseScreen)(scrnIndex, pScreen);
283309885543Smrg
283409885543Smrg    LEAVE_PROC("SMI_CloseScreen");
283509885543Smrg    return ret;
283609885543Smrg}
283709885543Smrg
283809885543Smrgstatic void
283909885543SmrgSMI_FreeScreen(int scrnIndex, int flags)
284009885543Smrg{
284109885543Smrg    SMI_FreeRec(xf86Screens[scrnIndex]);
284209885543Smrg}
284309885543Smrg
284409885543Smrgstatic Bool
284509885543SmrgSMI_SaveScreen(ScreenPtr pScreen, int mode)
284609885543Smrg{
284709885543Smrg    Bool ret;
284809885543Smrg
284909885543Smrg    ENTER_PROC("SMI_SaveScreen");
285009885543Smrg
285109885543Smrg    ret = vgaHWSaveScreen(pScreen, mode);
285209885543Smrg
285309885543Smrg    LEAVE_PROC("SMI_SaveScreen");
285409885543Smrg    return ret;
285509885543Smrg}
285609885543Smrg
285709885543Smrgvoid
285809885543SmrgSMI_AdjustFrame(int scrnIndex, int x, int y, int flags)
285909885543Smrg{
286009885543Smrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
286109885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
286209885543Smrg    CARD32 Base, lcdBase;
286309885543Smrg
286409885543Smrg    ENTER_PROC("SMI_AdjustFrame");
286509885543Smrg
286609885543Smrg    if (pSmi->ShowCache && y) {
286709885543Smrg	y += pScrn->virtualY - 1;
286809885543Smrg    }
286909885543Smrg
287009885543Smrg    if (pSmi->Dualhead) {
287109885543Smrg	lcdBase = 0;
287209885543Smrg	x = pSmi->lcdWidth;
287309885543Smrg	y = 0;
287409885543Smrg    }
287509885543Smrg
287609885543Smrg    Base = pSmi->FBOffset + (x + y * pScrn->virtualX) * pSmi->Bpp;
287709885543Smrg    if (SMI_LYNX3D_SERIES(pSmi->Chipset) ||
287809885543Smrg	SMI_COUGAR_SERIES(pSmi->Chipset)) {
287909885543Smrg	Base = (Base + 15) & ~15;
288009885543Smrg#if 1 /* PDR#1058 */
288109885543Smrg	while ((Base % pSmi->Bpp) > 0) {
288209885543Smrg	    Base -= 16;
288309885543Smrg	}
288409885543Smrg#endif
288509885543Smrg    } else {
288609885543Smrg	Base = (Base + 7) & ~7;
288709885543Smrg#if 1 /* PDR#1058 */
288809885543Smrg	while ((Base % pSmi->Bpp) > 0) {
288909885543Smrg	    Base -= 8;
289009885543Smrg	}
289109885543Smrg#endif
289209885543Smrg    }
289309885543Smrg
289409885543Smrg    if (pSmi->Dualhead) {
289509885543Smrg
289609885543Smrg	/* FIFO1 read start address */
289709885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x40,
289809885543Smrg			 (lcdBase & 0x000000FF));
289909885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x41,
290009885543Smrg			 ((lcdBase & 0x0000FF00) >> 8));
290109885543Smrg
290209885543Smrg	/* FIFO2 read start address */
290309885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x42,
290409885543Smrg			 (lcdBase & 0x000000FF));
290509885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x43,
290609885543Smrg			 ((lcdBase & 0x0000FF00) >> 8));
290709885543Smrg
290809885543Smrg	/* FIFO1/2 read start address overflow */
290909885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x45,
291009885543Smrg		((lcdBase & 0x000F0000) >> 12) | (((lcdBase & 0x000F0000) >> 12) << 4));
291109885543Smrg
291209885543Smrg    }
291309885543Smrg
291409885543Smrg    WRITE_VPR(pSmi, 0x0C, Base >> 3);
291509885543Smrg    if (pSmi->Chipset == SMI_COUGAR3DR) {
291609885543Smrg	WRITE_FPR(pSmi, FPR0C, Base >> 3);
291709885543Smrg    }
291809885543Smrg
291909885543Smrg    LEAVE_PROC("SMI_AdjustFrame");
292009885543Smrg}
292109885543Smrg
292209885543SmrgBool
292309885543SmrgSMI_SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
292409885543Smrg{
292509885543Smrg    Bool ret;
292609885543Smrg    SMIPtr pSmi = SMIPTR(xf86Screens[scrnIndex]);
292709885543Smrg
292809885543Smrg    ENTER_PROC("SMI_SwitchMode");
292909885543Smrg
293009885543Smrg    pSmi->IsSwitching = TRUE;
293109885543Smrg    ret = SMI_ModeInit(xf86Screens[scrnIndex], mode);
293209885543Smrg    pSmi->IsSwitching = FALSE;
293309885543Smrg
293409885543Smrg    LEAVE_PROC("SMI_SwitchMode");
293509885543Smrg    return ret;
293609885543Smrg}
293709885543Smrg
293809885543Smrgvoid
293909885543SmrgSMI_LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies, LOCO *colors,
294009885543Smrg				VisualPtr pVisual)
294109885543Smrg{
294209885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
294309885543Smrg    int i;
294409885543Smrg
294509885543Smrg    ENTER_PROC("SMI_LoadPalette");
294609885543Smrg
294709885543Smrg    /* Enable both the CRT and LCD DAC RAM paths, so both palettes are updated */
294809885543Smrg    if ((pSmi->Chipset == SMI_LYNX3DM) ||
294909885543Smrg	(pSmi->Chipset == SMI_COUGAR3DR)) {
295009885543Smrg	CARD8 ccr66;
295109885543Smrg
295209885543Smrg	ccr66  = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66);
295309885543Smrg	ccr66 &= 0x0f;
295409885543Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66, ccr66);
295509885543Smrg    }
295609885543Smrg
295709885543Smrg    for(i = 0; i < numColors; i++) {
295809885543Smrg        DEBUG((VERBLEV, "pal[%d] = %d %d %d\n", indicies[i],
295909885543Smrg        colors[indicies[i]].red, colors[indicies[i]].green, colors[indicies[i]].blue));
296009885543Smrg	VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, indicies[i]);
296109885543Smrg	VGAOUT8(pSmi, VGA_DAC_DATA, colors[indicies[i]].red);
296209885543Smrg	VGAOUT8(pSmi, VGA_DAC_DATA, colors[indicies[i]].green);
296309885543Smrg	VGAOUT8(pSmi, VGA_DAC_DATA, colors[indicies[i]].blue);
296409885543Smrg    }
296509885543Smrg
296609885543Smrg    LEAVE_PROC("SMI_LoadPalette");
296709885543Smrg}
296809885543Smrg
296909885543Smrgstatic void
297009885543SmrgSMI_DisableVideo(ScrnInfoPtr pScrn)
297109885543Smrg{
297209885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
297309885543Smrg    CARD8 tmp;
297409885543Smrg
297509885543Smrg    if (!(tmp = VGAIN8(pSmi, VGA_DAC_MASK)))
297609885543Smrg	return;
297709885543Smrg    pSmi->DACmask = tmp;
297809885543Smrg    VGAOUT8(pSmi, VGA_DAC_MASK, 0);
297909885543Smrg}
298009885543Smrg
298109885543Smrgstatic void
298209885543SmrgSMI_EnableVideo(ScrnInfoPtr pScrn)
298309885543Smrg{
298409885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
298509885543Smrg
298609885543Smrg    VGAOUT8(pSmi, VGA_DAC_MASK, pSmi->DACmask);
298709885543Smrg}
298809885543Smrg
298909885543Smrg
299009885543Smrgvoid
299109885543SmrgSMI_EnableMmio(ScrnInfoPtr pScrn)
299209885543Smrg{
299309885543Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
299409885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
299509885543Smrg    CARD8 tmp;
299609885543Smrg
299709885543Smrg    ENTER_PROC("SMI_EnableMmio");
299809885543Smrg
299909885543Smrg    /*
300009885543Smrg     * Enable chipset (seen on uninitialized secondary cards) might not be
300109885543Smrg     * needed once we use the VGA softbooter
300209885543Smrg     */
300309885543Smrg    vgaHWSetStdFuncs(hwp);
300409885543Smrg
300509885543Smrg    /* Enable linear mode */
300609885543Smrg    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
300709885543Smrg    tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
300809885543Smrg    pSmi->SR18Value = tmp;					/* PDR#521 */
300909885543Smrg    outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x11);
301009885543Smrg
301109885543Smrg    /* Enable 2D/3D Engine and Video Processor */
301209885543Smrg    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21);
301309885543Smrg    tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
301409885543Smrg    pSmi->SR21Value = tmp;					/* PDR#521 */
301509885543Smrg    outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp & ~0x03);
301609885543Smrg
301709885543Smrg    LEAVE_PROC("SMI_EnableMmio");
301809885543Smrg}
301909885543Smrg
302009885543Smrgvoid
302109885543SmrgSMI_DisableMmio(ScrnInfoPtr pScrn)
302209885543Smrg{
302309885543Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
302409885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
302509885543Smrg
302609885543Smrg    ENTER_PROC("SMI_DisableMmio");
302709885543Smrg
302809885543Smrg    vgaHWSetStdFuncs(hwp);
302909885543Smrg
303009885543Smrg    /* Disable 2D/3D Engine and Video Processor */
303109885543Smrg    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21);
303209885543Smrg    outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR21Value);	/* PDR#521 */
303309885543Smrg
303409885543Smrg    /* Disable linear mode */
303509885543Smrg    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
303609885543Smrg    outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR18Value);	/* PDR#521 */
303709885543Smrg
303809885543Smrg    LEAVE_PROC("SMI_DisableMmio");
303909885543Smrg}
304009885543Smrg
304109885543Smrg/* This function is used to debug, it prints out the contents of Lynx regs */
304209885543Smrgstatic void
304309885543SmrgSMI_PrintRegs(ScrnInfoPtr pScrn)
304409885543Smrg{
304509885543Smrg    unsigned char i;
304609885543Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
304709885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
304809885543Smrg    int vgaCRIndex = hwp->IOBase + VGA_CRTC_INDEX_OFFSET;
304909885543Smrg    int vgaCRReg   = hwp->IOBase + VGA_CRTC_DATA_OFFSET;
305009885543Smrg    int vgaStatus  = hwp->IOBase + VGA_IN_STAT_1_OFFSET;
305109885543Smrg
305209885543Smrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
305309885543Smrg		"START register dump ------------------\n");
305409885543Smrg
305509885543Smrg    xf86ErrorFVerb(VERBLEV, "MISCELLANEOUS OUTPUT\n    %02X\n",
305609885543Smrg		VGAIN8(pSmi, VGA_MISC_OUT_R));
305709885543Smrg
305809885543Smrg    xf86ErrorFVerb(VERBLEV, "\nSEQUENCER\n"
305909885543Smrg		"    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
306009885543Smrg    for (i = 0x00; i <= 0xAF; i++) {
306109885543Smrg	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
306209885543Smrg	if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " ");
306309885543Smrg	xf86ErrorFVerb(VERBLEV, "%02X ",
306409885543Smrg	    VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, i));
306509885543Smrg    }
306609885543Smrg
306709885543Smrg    xf86ErrorFVerb(VERBLEV, "\n\nCRT CONTROLLER\n"
306809885543Smrg		"    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
306909885543Smrg    for (i = 0x00; i <= 0xAD; i++) {
307009885543Smrg	if (i == 0x20) i = 0x30;
307109885543Smrg	if (i == 0x50) i = 0x90;
307209885543Smrg	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
307309885543Smrg	if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " ");
307409885543Smrg	xf86ErrorFVerb(VERBLEV, "%02X ",
307509885543Smrg	    VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRReg, i));
307609885543Smrg    }
307709885543Smrg
307809885543Smrg    xf86ErrorFVerb(VERBLEV, "\n\nGRAPHICS CONTROLLER\n"
307909885543Smrg		"    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
308009885543Smrg    for (i = 0x00; i <= 0x08; i++) {
308109885543Smrg	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
308209885543Smrg	if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " ");
308309885543Smrg	xf86ErrorFVerb(VERBLEV, "%02X ",
308409885543Smrg	    VGAIN8_INDEX(pSmi, VGA_GRAPH_INDEX, VGA_GRAPH_DATA, i));
308509885543Smrg    }
308609885543Smrg
308709885543Smrg    xf86ErrorFVerb(VERBLEV, "\n\nATTRIBUTE 0CONTROLLER\n"
308809885543Smrg		"    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
308909885543Smrg    for (i = 0x00; i <= 0x14; i++) {
309009885543Smrg	(void) VGAIN8(pSmi, vgaStatus);
309109885543Smrg	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
309209885543Smrg	if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " ");
309309885543Smrg	xf86ErrorFVerb(VERBLEV, "%02X ",
309409885543Smrg	    VGAIN8_INDEX(pSmi, VGA_ATTR_INDEX, VGA_ATTR_DATA_R, i));
309509885543Smrg    }
309609885543Smrg    (void) VGAIN8(pSmi, vgaStatus);
309709885543Smrg    VGAOUT8(pSmi, VGA_ATTR_INDEX, 0x20);
309809885543Smrg
309909885543Smrg    xf86ErrorFVerb(VERBLEV, "\n\nDPR    x0       x4       x8       xC");
310009885543Smrg    for (i = 0x00; i <= 0x44; i += 4) {
310109885543Smrg	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
310209885543Smrg	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_DPR(pSmi, i));
310309885543Smrg    }
310409885543Smrg
310509885543Smrg    xf86ErrorFVerb(VERBLEV, "\n\nVPR    x0       x4       x8       xC");
310609885543Smrg    for (i = 0x00; i <= 0x60; i += 4) {
310709885543Smrg	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
310809885543Smrg	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_VPR(pSmi, i));
310909885543Smrg    }
311009885543Smrg
311109885543Smrg    xf86ErrorFVerb(VERBLEV, "\n\nCPR    x0       x4       x8       xC");
311209885543Smrg    for (i = 0x00; i <= 0x18; i += 4) {
311309885543Smrg	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
311409885543Smrg	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_CPR(pSmi, i));
311509885543Smrg    }
311609885543Smrg
311709885543Smrg    xf86ErrorFVerb(VERBLEV, "\n\n");
311809885543Smrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
311909885543Smrg		"END register dump --------------------\n");
312009885543Smrg}
312109885543Smrg
312209885543Smrg/*
312309885543Smrg * SMI_DisplayPowerManagementSet -- Sets VESA Display Power Management
312409885543Smrg * Signaling (DPMS) Mode.
312509885543Smrg */
312609885543Smrgstatic void
312709885543SmrgSMI_DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
312809885543Smrg							  int flags)
312909885543Smrg{
313009885543Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
313109885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
313209885543Smrg    CARD8 SR01, SR20, SR21, SR22, SR23, SR24, SR31, SR34;
313309885543Smrg
313409885543Smrg    ENTER_PROC("SMI_DisplayPowerManagementSet");
313509885543Smrg
313609885543Smrg    /* If we already are in the requested DPMS mode, just return */
313709885543Smrg    if (pSmi->CurrentDPMS == PowerManagementMode) {
313809885543Smrg	LEAVE_PROC("SMI_DisplayPowerManagementSet");
313909885543Smrg	return;
314009885543Smrg    }
314109885543Smrg
314209885543Smrg#if 1 /* PDR#735 */
314309885543Smrg    if (pSmi->useBIOS && pSmi->pInt10 != NULL) {
314409885543Smrg	pSmi->pInt10->ax = 0x4F10;
314509885543Smrg	switch (PowerManagementMode) {
314609885543Smrg	case DPMSModeOn:
314709885543Smrg	    pSmi->pInt10->bx = 0x0001;
314809885543Smrg	    break;
314909885543Smrg	case DPMSModeStandby:
315009885543Smrg	    pSmi->pInt10->bx = 0x0101;
315109885543Smrg	    break;
315209885543Smrg	case DPMSModeSuspend:
315309885543Smrg	    pSmi->pInt10->bx = 0x0201;
315409885543Smrg	    break;
315509885543Smrg	case DPMSModeOff:
315609885543Smrg	    pSmi->pInt10->bx = 0x0401;
315709885543Smrg	    break;
315809885543Smrg	}
315909885543Smrg	pSmi->pInt10->cx = 0x0000;
316009885543Smrg	pSmi->pInt10->num = 0x10;
316109885543Smrg	xf86ExecX86int10(pSmi->pInt10);
316209885543Smrg	if (pSmi->pInt10->ax == 0x004F) {
316309885543Smrg	    pSmi->CurrentDPMS = PowerManagementMode;
316409885543Smrg#if 1 /* PDR#835 */
316509885543Smrg	    if (PowerManagementMode == DPMSModeOn) {
316609885543Smrg		SR01 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01);
316709885543Smrg		VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01,
316809885543Smrg				SR01 & ~0x20);
316909885543Smrg	    }
317009885543Smrg#endif
317109885543Smrg	    LEAVE_PROC("SMI_DisplayPowerManagementSet");
317209885543Smrg	    return;
317309885543Smrg	}
317409885543Smrg    }
317509885543Smrg#endif
317609885543Smrg
317709885543Smrg    /* Save the current SR registers */
317809885543Smrg    if (pSmi->CurrentDPMS == DPMSModeOn) {
317909885543Smrg	pSmi->DPMS_SR20 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20);
318009885543Smrg	pSmi->DPMS_SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
318109885543Smrg	pSmi->DPMS_SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31);
318209885543Smrg	pSmi->DPMS_SR34 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34);
318309885543Smrg    }
318409885543Smrg
318509885543Smrg    /* Read the required SR registers for the DPMS handler */
318609885543Smrg    SR01 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01);
318709885543Smrg    SR20 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20);
318809885543Smrg    SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
318909885543Smrg    SR22 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22);
319009885543Smrg    SR23 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23);
319109885543Smrg    SR24 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x24);
319209885543Smrg    SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31);
319309885543Smrg    SR34 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34);
319409885543Smrg
319509885543Smrg    switch (PowerManagementMode) {
319609885543Smrg    case DPMSModeOn:
319709885543Smrg	/* Screen On: HSync: On, VSync : On */
319809885543Smrg	SR01 &= ~0x20;
319909885543Smrg	SR20  = pSmi->DPMS_SR20;
320009885543Smrg	SR21  = pSmi->DPMS_SR21;
320109885543Smrg	SR22 &= ~0x30;
320209885543Smrg	SR23 &= ~0xC0;
320309885543Smrg	SR24 |= 0x01;
320409885543Smrg	SR31  = pSmi->DPMS_SR31;
320509885543Smrg	SR34  = pSmi->DPMS_SR34;
320609885543Smrg	break;
320709885543Smrg    case DPMSModeStandby:
320809885543Smrg	/* Screen: Off; HSync: Off, VSync: On */
320909885543Smrg	SR01 |= 0x20;
321009885543Smrg	SR20  = (SR20 & ~0xB0) | 0x10;
321109885543Smrg	SR21 |= 0x88;
321209885543Smrg	SR22  = (SR22 & ~0x30) | 0x10;
321309885543Smrg	SR23  = (SR23 & ~0x07) | 0xD8;
321409885543Smrg	SR24 &= ~0x01;
321509885543Smrg	SR31  = (SR31 & ~0x07) | 0x00;
321609885543Smrg	SR34 |= 0x80;
321709885543Smrg	break;
321809885543Smrg    case DPMSModeSuspend:
321909885543Smrg	/* Screen: Off; HSync: On, VSync: Off */
322009885543Smrg	SR01 |= 0x20;
322109885543Smrg	SR20  = (SR20 & ~0xB0) | 0x10;
322209885543Smrg	SR21 |= 0x88;
322309885543Smrg	SR22  = (SR22 & ~0x30) | 0x20;
322409885543Smrg	SR23  = (SR23 & ~0x07) | 0xD8;
322509885543Smrg	SR24 &= ~0x01;
322609885543Smrg	SR31  = (SR31 & ~0x07) | 0x00;
322709885543Smrg	SR34 |= 0x80;
322809885543Smrg	break;
322909885543Smrg    case DPMSModeOff:
323009885543Smrg	/* Screen: Off; HSync: Off, VSync: Off */
323109885543Smrg	SR01 |= 0x20;
323209885543Smrg	SR20  = (SR20 & ~0xB0) | 0x10;
323309885543Smrg	SR21 |= 0x88;
323409885543Smrg	SR22  = (SR22 & ~0x30) | 0x30;
323509885543Smrg	SR23  = (SR23 & ~0x07) | 0xD8;
323609885543Smrg	SR24 &= ~0x01;
323709885543Smrg	SR31  = (SR31 & ~0x07) | 0x00;
323809885543Smrg	SR34 |= 0x80;
323909885543Smrg	break;
324009885543Smrg    default:
324109885543Smrg	xf86ErrorFVerb(VERBLEV, "Invalid PowerManagementMode %d passed to "
324209885543Smrg		"SMI_DisplayPowerManagementSet\n", PowerManagementMode);
324309885543Smrg	LEAVE_PROC("SMI_DisplayPowerManagementSet");
324409885543Smrg	return;
324509885543Smrg    }
324609885543Smrg
324709885543Smrg    /* Wait for vertical retrace */
324809885543Smrg    while (hwp->readST01(hwp) & 0x8) ;
324909885543Smrg    while (!(hwp->readST01(hwp) & 0x8)) ;
325009885543Smrg
325109885543Smrg    /* Write the registers */
325209885543Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01, SR01);
325309885543Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34, SR34);
325409885543Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, SR31);
325509885543Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20, SR20);
325609885543Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22, SR22);
325709885543Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23, SR23);
325809885543Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, SR21);
325909885543Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x24, SR24);
326009885543Smrg
326109885543Smrg    /* Save the current power state */
326209885543Smrg    pSmi->CurrentDPMS = PowerManagementMode;
326309885543Smrg
326409885543Smrg    LEAVE_PROC("SMI_DisplayPowerManagementSet");
326509885543Smrg}
326609885543Smrg
326709885543Smrgstatic void
326809885543SmrgSMI_ProbeDDC(ScrnInfoPtr pScrn, int index)
326909885543Smrg{
327009885543Smrg    vbeInfoPtr pVbe;
327109885543Smrg    if (xf86LoadSubModule(pScrn, "vbe")) {
327209885543Smrg	pVbe = VBEInit(NULL, index);
327309885543Smrg	ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
327409885543Smrg	vbeFree(pVbe);
327509885543Smrg    }
327609885543Smrg}
327709885543Smrg
327809885543Smrgstatic unsigned int
327909885543SmrgSMI_ddc1Read(ScrnInfoPtr pScrn)
328009885543Smrg{
328109885543Smrg    register vgaHWPtr hwp = VGAHWPTR(pScrn);
328209885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
328309885543Smrg    unsigned int ret;
328409885543Smrg
328509885543Smrg    ENTER_PROC("SMI_ddc1Read");
328609885543Smrg
328709885543Smrg    while (hwp->readST01(hwp) & 0x8) ;
328809885543Smrg    while (!(hwp->readST01(hwp) & 0x8)) ;
328909885543Smrg
329009885543Smrg    ret = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72) & 0x08;
329109885543Smrg
329209885543Smrg    LEAVE_PROC("SMI_ddc1Read");
329309885543Smrg    return ret;
329409885543Smrg}
329509885543Smrg
329609885543Smrgstatic Bool
329709885543SmrgSMI_ddc1(int scrnIndex)
329809885543Smrg{
329909885543Smrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
330009885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
330109885543Smrg    Bool success = FALSE;
330209885543Smrg    xf86MonPtr pMon;
330309885543Smrg    unsigned char tmp;
330409885543Smrg
330509885543Smrg    ENTER_PROC("SMI_ddc1");
330609885543Smrg
330709885543Smrg    tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72);
330809885543Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, tmp | 0x20);
330909885543Smrg
331009885543Smrg    pMon = xf86PrintEDID(xf86DoEDID_DDC1(scrnIndex,
331109885543Smrg					 vgaHWddc1SetSpeedWeak(),
331209885543Smrg					 SMI_ddc1Read));
331309885543Smrg    if (pMon != NULL) {
331409885543Smrg	success = TRUE;
331509885543Smrg    }
331609885543Smrg    xf86SetDDCproperties(pScrn, pMon);
331709885543Smrg
331809885543Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, tmp);
331909885543Smrg
332009885543Smrg    LEAVE_PROC("SMI_ddc1");
332109885543Smrg    return success;
332209885543Smrg}
332309885543Smrg
3324