/* Header:   //Mercury/Projects/archives/XFree86/4.0/smi_driver.c-arc   1.42   03 Jan 2001 13:52:16   Frido  $ */

/*
   Copyright (C) 1994-1999 The XFree86 Project, Inc.  All Rights Reserved.
   Copyright (C) 2000 Silicon Motion, Inc.  All Rights Reserved.

   Permission is hereby granted, free of charge, to any person obtaining a copy of
   this software and associated documentation files (the "Software"), to deal in
   the Software without restriction, including without limitation the rights to
   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
   of the Software, and to permit persons to whom the Software is furnished to do
   so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
   NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
   XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
   AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the names of The XFree86 Project and
   Silicon Motion shall not be used in advertising or otherwise to promote the
   sale, use or other dealings in this Software without prior written
   authorization from The XFree86 Project or Silicon Motion.
   */
/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_driver.c,v 1.30 2003/04/23 21:51:44 tsi Exp $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif


#include "xf86Resources.h"
#include "xf86RAC.h"
#include "xf86DDC.h"
#include "xf86int10.h"
#include "vbe.h"
#include "shadowfb.h"
#include "smi.h"




#include "globals.h"
#define DPMS_SERVER
#include <X11/extensions/dpms.h>

#ifdef RANDR
static Bool    SMI_DriverFunc(ScrnInfoPtr pScrnInfo, xorgDriverFuncOp op,
		pointer data);
#endif

#define	FIXUP_89INCH_BUG
 
/*#include "smi_501.h"*/
extern void setPower (SMIPtr pSmi, unsigned int nGates, unsigned int nClock,
		int control_value);
extern void setDPMS (SMIPtr pSmi, int state);
extern void crtSetMode (SMIPtr pSmi, int nWidth, int nHeight,
		unsigned int fMode, int nHertz, int fbPitch, int bpp);
extern void panelSetMode (SMIPtr pSmi, int nWidth, int nHeight,
		unsigned int fMode, int nHertz, int fbPitch,
		int bpp);
extern void panelUseCRT (SMIPtr pSmi, BOOL bEnable);
extern Bool entity_init_501(ScrnInfoPtr pScrn, int entity);

void SMI_PrintMode(DisplayModePtr mode);

/*
 * Internals
 */
void SMI_EnableMmio (ScrnInfoPtr pScrn);
static void SMI_DisableMmio (ScrnInfoPtr pScrn);

/*
 * Forward definitions for the functions that make up the driver.
 */

static const OptionInfoRec *SMI_AvailableOptions (int chipid, int busid);
static void SMI_Identify (int flags);
static Bool SMI_Probe (DriverPtr drv, int flags);
static Bool SMI_PreInit (ScrnInfoPtr pScrn, int flags);
static Bool SMI_EnterVT (int scrnIndex, int flags);
static void SMI_LeaveVT (int scrnIndex, int flags);
static void SMI_Save (ScrnInfoPtr pScrn);
static void SMI_BiosWriteMode (ScrnInfoPtr pScrn, DisplayModePtr mode, SMIRegPtr restore);
static void SMI_WriteMode (ScrnInfoPtr pScrn, vgaRegPtr, SMIRegPtr);
static Bool SMI_ScreenInit (int scrnIndex, ScreenPtr pScreen, int argc,
		char **argv);
static int SMI_InternalScreenInit (int scrnIndex, ScreenPtr pScreen);
static void SMI_PrintRegs (ScrnInfoPtr);
static ModeStatus SMI_ValidMode (int scrnIndex, DisplayModePtr mode,
		Bool verbose, int flags);
static void SMI_DisableVideo (ScrnInfoPtr pScrn);
static void SMI_EnableVideo (ScrnInfoPtr pScrn);
static Bool SMI_MapMem (ScrnInfoPtr pScrn);
static void SMI_UnmapMem (ScrnInfoPtr pScrn);
static Bool SMI_ModeInit (ScrnInfoPtr pScrn, DisplayModePtr mode);
static Bool SMI_CloseScreen (int scrnIndex, ScreenPtr pScreen);
static Bool SMI_SaveScreen (ScreenPtr pScreen, int mode);
static void SMI_LoadPalette (ScrnInfoPtr pScrn, int numColors, int *indicies,
		LOCO * colors, VisualPtr pVisual);
static void SMI_DisplayPowerManagementSet (ScrnInfoPtr pScrn,
		int PowerManagementMode,
		int flags);
static Bool SMI_ddc1 (int scrnIndex);
static unsigned int SMI_ddc1Read (ScrnInfoPtr pScrn);
static void SMI_FreeScreen (int ScrnIndex, int flags);
static void SMI_ProbeDDC (ScrnInfoPtr pScrn, int index);

static Bool SMI_MSOCSetMode (ScrnInfoPtr pScrn, DisplayModePtr mode);

static void SMI_SaveReg(ScrnInfoPtr pScrn );

static void SMI_RestoreReg(ScrnInfoPtr pScrn );

void SMI_SaveReg_502(ScrnInfoPtr pScrn );
void SMI_RestoreReg_502(ScrnInfoPtr pScrn );
void EnableOverlay(SMIPtr pSmi);
#define SILICONMOTION_NAME          "Silicon Motion"
#define SILICONMOTION_DRIVER_NAME   "siliconmotion"
#define SILICONMOTION_VERSION_NAME  "2.2.8"
#define SILICONMOTION_VERSION_MAJOR 2
#define SILICONMOTION_VERSION_MINOR 2
#define SILICONMOTION_PATCHLEVEL    8
#define SILICONMOTION_DRIVER_VERSION ((SILICONMOTION_VERSION_MAJOR << 24) | \
		(SILICONMOTION_VERSION_MINOR << 16) | \
		(SILICONMOTION_PATCHLEVEL))

#define FB_RESERVE4USB	128*1024		// 128K

extern int	free_video_memory;
int	entity_index[MAX_ENTITIES] = {-1, -1, -1, -1, -1, -1, -1, -1,
	-1, -1, -1, -1, -1, -1, -1, -1};
int	pci_tag = 0x0;
static int	saved_console_reg = -1;

/*
 * This contains the functions needed by the server after loading the
 * driver module.  It must be supplied, and gets added the driver list by
 * the Module Setup funtion in the dynamic case.  In the static case a
 * reference to this is compiled in, and this requires that the name of
 * this DriverRec be an upper-case version of the driver name.
 */

/* #if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(6,9,0,0,0) */
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(6,9,0,0,0)
	_X_EXPORT DriverRec SILICONMOTION =
#elif XORG_VERSION_CURRENT == XORG_VERSION_NUMERIC(1,3,0,0,0)
	_X_EXPORT DriverRec SILICONMOTION =
#else
	DriverRec SILICONMOTION =
#endif
{
	SILICONMOTION_DRIVER_VERSION,
	SILICONMOTION_DRIVER_NAME,
	SMI_Identify,
	SMI_Probe,
	SMI_AvailableOptions,
	NULL,
	0
};

/* Supported chipsets */
static SymTabRec SMIChipsets[] = {
	{PCI_CHIP_SMI910, "Lynx"},
	{PCI_CHIP_SMI810, "LynxE"},
	{PCI_CHIP_SMI820, "Lynx3D"},
	{PCI_CHIP_SMI710, "LynxEM"},
	{PCI_CHIP_SMI712, "LynxEM+"},
	{PCI_CHIP_SMI720, "Lynx3DM"},
	{PCI_CHIP_SMI731, "Cougar3DR"},
	{PCI_CHIP_SMI501, "MSOC"},
	{-1, NULL}
};

static PciChipsets SMIPciChipsets[] = {
	/* numChipset,          PciID,                          Resource */
	{PCI_CHIP_SMI910, PCI_CHIP_SMI910, RES_SHARED_VGA},
	{PCI_CHIP_SMI810, PCI_CHIP_SMI810, RES_SHARED_VGA},
	{PCI_CHIP_SMI820, PCI_CHIP_SMI820, RES_SHARED_VGA},
	{PCI_CHIP_SMI710, PCI_CHIP_SMI710, RES_SHARED_VGA},
	{PCI_CHIP_SMI712, PCI_CHIP_SMI712, resVgaIo},
	{PCI_CHIP_SMI720, PCI_CHIP_SMI720, RES_SHARED_VGA},
	{PCI_CHIP_SMI731, PCI_CHIP_SMI731, RES_SHARED_VGA},
	{PCI_CHIP_SMI501, PCI_CHIP_SMI501, RES_SHARED_VGA},
	{-1, -1, RES_UNDEFINED}
};

typedef enum
{
	OPTION_PCI_BURST,
	OPTION_FIFO_CONSERV,
	OPTION_FIFO_MODERATE,
	OPTION_FIFO_AGGRESSIVE,
	OPTION_PCI_RETRY,
	OPTION_NOACCEL,
	OPTION_MCLK,
	OPTION_SHOWCACHE,
	OPTION_SWCURSOR,
	OPTION_HWCURSOR,
	OPTION_SHADOW_FB,
	OPTION_ROTATE,
	OPTION_VIDEOKEY,
	OPTION_BYTESWAP,
	/* CZ 26.10.2001: interlaced video */
	OPTION_INTERLACED,
	/* end CZ */
	OPTION_USEBIOS,
	OPTION_ZOOMONLCD,
	OPTION_PANELWIDTH,
	OPTION_PANELHEIGHT,
	NUMBER_OF_OPTIONS,
	/*Add for CSC Video*/
	OPTION_CSCVIDEO
} SMIOpts;

static const OptionInfoRec SMIOptions[] = {
	{OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN, {0}, TRUE},
	{OPTION_FIFO_CONSERV, "fifo_conservative", OPTV_BOOLEAN, {0}, FALSE},
	{OPTION_FIFO_MODERATE, "fifo_moderate", OPTV_BOOLEAN, {0}, FALSE},
	{OPTION_FIFO_AGGRESSIVE, "fifo_aggressive", OPTV_BOOLEAN, {0}, FALSE},
	{OPTION_PCI_RETRY, "pci_retry", OPTV_BOOLEAN, {0}, FALSE},
	{OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE},
	{OPTION_MCLK, "set_mclk", OPTV_FREQ, {0}, FALSE},
	{OPTION_SHOWCACHE, "show_cache", OPTV_BOOLEAN, {0}, FALSE},
	{OPTION_HWCURSOR, "HWCursor", OPTV_BOOLEAN, {0}, FALSE},
	{OPTION_SWCURSOR, "SWCursor", OPTV_BOOLEAN, {0}, FALSE},
	{OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE},
	{OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE},
	{OPTION_VIDEOKEY, "VideoKey", OPTV_INTEGER, {0}, FALSE},
	{OPTION_BYTESWAP, "ByteSwap", OPTV_BOOLEAN, {0}, FALSE},
	/* CZ 26.10.2001: interlaced video */
	{OPTION_INTERLACED, "Interlaced", OPTV_BOOLEAN, {0}, FALSE},
	/* end CZ */
	{OPTION_USEBIOS, "UseBIOS", OPTV_BOOLEAN, {0}, FALSE},
	{OPTION_ZOOMONLCD, "ZoomOnLCD", OPTV_BOOLEAN, {0}, FALSE},
	/* Added by Belcon */
	{OPTION_PANELHEIGHT, "LCDHeight", OPTV_INTEGER, {0}, FALSE},
	{OPTION_PANELWIDTH, "LCDWidth", OPTV_INTEGER, {0}, FALSE},
	/*Add for CSC Video*/
	{OPTION_CSCVIDEO, "CSCVideo",OPTV_BOOLEAN, {0}, FALSE},
	{-1, NULL, OPTV_NONE, {0}, FALSE}
};

/*
 * Lists of symbols that may/may not be required by this driver.
 * This allows the loader to know which ones to issue warnings for.
 *
 * Note that vgahwSymbols and xaaSymbols are referenced outside the
 * XFree86LOADER define in later code, so are defined outside of that
 * define here also.
 */

static const char *vgahwSymbols[] = {
	"vgaHWCopyReg",
	"vgaHWGetHWRec",
	"vgaHWGetIOBase",
	"vgaHWGetIndex",
	"vgaHWInit",
	"vgaHWLock",
	"vgaHWUnLock",
	"vgaHWMapMem",
	"vgaHWProtect",
	"vgaHWRestore",
	"vgaHWSave",
	"vgaHWSaveScreen",
	"vgaHWSetMmioFuncs",
	"vgaHWSetStdFuncs",
	"vgaHWUnmapMem",
	/* #if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(6,9,0,0,0) */
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(6,9,0,0,0)
	"vgaHWddc1SetSpeedWeak",
#elif XORG_VERSION_CURRENT == XORG_VERSION_NUMERIC(1,3,0,0,0)
	"vgaHWddc1SetSpeedWeak", 
#endif
	NULL
};

static const char *xaaSymbols[] = {
	// #if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(6,9,0,0,0)
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(6,9,0,0,0)
	"XAAGetCopyROP",
#elif XORG_VERSION_CURRENT == XORG_VERSION_NUMERIC(1,3,0,0,0)
	"XAAGetCopyROP",
#else
	"XAACopyROP",
#endif
	"XAACreateInfoRec",
	"XAADestroyInfoRec",
	// #if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(6,9,0,0,0)
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(6,9,0,0,0)
	"XAAGetFallbackOps",
#elif XORG_VERSION_CURRENT == XORG_VERSION_NUMERIC(1,3,0,0,0)
	"XAAGetFallbackOps",
#else
	"XAAFallbackOps",
	"XAAScreenIndex",
#endif
	"XAAInit",
	// #if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(6,9,0,0,0)
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(6,9,0,0,0)
	"XAAGetPatternROP",
#elif XORG_VERSION_CURRENT == XORG_VERSION_NUMERIC(1,3,0,0,0)
	"XAAGetPatternROP",
#else
	"XAAPatternROP",
#endif
	NULL
};

static const char *ramdacSymbols[] = {
	"xf86CreateCursorInfoRec",
	"xf86DestroyCursorInfoRec",
	"xf86InitCursor",
	NULL
};

static const char *ddcSymbols[] = {
	"xf86PrintEDID",
	"xf86DoEDID_DDC1",
	"xf86InterpretEDID",
	"xf86DoEDID_DDC2",
	"xf86SetDDCproperties",
	NULL
};

static const char *i2cSymbols[] = {
	"xf86CreateI2CBusRec",
	"xf86CreateI2CDevRec",
	"xf86DestroyI2CBusRec",
	"xf86DestroyI2CDevRec",
	"xf86I2CBusInit",
	"xf86I2CDevInit",
	"xf86I2CReadBytes",
	"xf86I2CWriteByte",
	NULL
};

static const char *shadowSymbols[] = {
	"ShadowFBInit",
	NULL
};

static const char *int10Symbols[] = {
	"xf86ExecX86int10",
	"xf86FreeInt10",
	"xf86InitInt10",
	NULL
};

static const char *vbeSymbols[] = {
	"VBEInit",
	"vbeDoEDID",
	"vbeFree",
	NULL
};

static const char *fbSymbols[] = {

	"fbPictureInit",
	"fbScreenInit",
	NULL
};


static unsigned char SeqTable[144];
static unsigned char CrtTable[168];
static unsigned char DprIndexTable[27]={
	0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 
	0x10, 0x12, 0x14, 0x18, 0x1c, 0x1e, 0x20, 0x24,
	0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x38,
	0x3c, 0x40, 0x44,
};
static unsigned int DprTable[27];
static unsigned char VprIndexTable[23]={
	0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c, 
	0x20, 0x24, 0x2c, 0x30, 0x34, 0x38, 0x3c, 0x40, 
	0x54, 0x58, 0x5c, 0x60, 0x64, 0x68, 0x6c
};
static unsigned int VprTable[23];

#ifdef XFree86LOADER

static MODULESETUPPROTO (siliconmotionSetup);

static XF86ModuleVersionInfo SMIVersRec = {
	"siliconmotion",
	MODULEVENDORSTRING,
	MODINFOSTRING1,
	MODINFOSTRING2,
	// #if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(6,9,0,0,0)
#ifdef XORG_VERSION_CURRENT
	XORG_VERSION_CURRENT,
#else
	XF86_VERSION_CURRENT,
#endif
	SILICONMOTION_VERSION_MAJOR,
	SILICONMOTION_VERSION_MINOR,
	SILICONMOTION_PATCHLEVEL,
	ABI_CLASS_VIDEODRV,
	ABI_VIDEODRV_VERSION,
	MOD_CLASS_VIDEODRV,
	{0, 0, 0, 0}
};

/*
 * This is the module init data for XFree86 modules.
 *
 * Its name has to be the driver name followed by ModuleData.
 */

// #if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(6,9,0,0,0)
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(6,9,0,0,0)
	_X_EXPORT XF86ModuleData siliconmotionModuleData =
#elif XORG_VERSION_CURRENT == XORG_VERSION_NUMERIC(1,3,0,0,0)
	_X_EXPORT XF86ModuleData siliconmotionModuleData =
#else
	XF86ModuleData siliconmotionModuleData =
#endif
{
	&SMIVersRec,
	siliconmotionSetup,
	NULL
};

	static pointer
siliconmotionSetup (pointer module, pointer opts, int *errmaj, int *errmin)
{
	static Bool setupDone = FALSE;

	ENTER_PROC("siliconmotionSetup");
	if (!setupDone)
	{
		setupDone = TRUE;
		xf86AddDriver (&SILICONMOTION, module, 0);

		/*
		 * Modules that this driver always requires can be loaded here
		 * by calling LoadSubModule().
		 */

		/*
		 * Tell the loader about symbols from other modules that this module
		 * might refer to.
		 */
		LoaderRefSymLists (vgahwSymbols, fbSymbols, xaaSymbols, ramdacSymbols,
				ddcSymbols, i2cSymbols, int10Symbols, vbeSymbols,
				shadowSymbols, NULL);

		/*
		 * The return value must be non-NULL on success even though there
		 * is no TearDownProc.
		 */
		LEAVE_PROC("siliconmotionSetup");
		return (pointer) 1;
	}
	else
	{
		if (errmaj)
		{
			*errmaj = LDR_ONCEONLY;
		}
		LEAVE_PROC("siliconmotionSetup");
		return (NULL);
	}
}

#endif /* XFree86LOADER */



	SMIRegPtr
SMIEntPriv (ScrnInfoPtr pScrn)
{
	DevUnion *pPriv;
	ENTER_PROC ("SMIEntPriv");

	//  pPriv = xf86GetEntityPrivate (pScrn->entityList[0], gSMIEntityIndex);
	pPriv = xf86GetEntityPrivate (pScrn->entityList[0], entity_index[pScrn->entityList[0]]);

	LEAVE_PROC ("SMIEntPriv");
	return pPriv->ptr;
}



	static Bool
SMI_GetRec (ScrnInfoPtr pScrn)
{
	ENTER_PROC ("SMI_GetRec");

	/*
	 * Allocate an 'Chip'Rec, and hook it into pScrn->driverPrivate.
	 * pScrn->driverPrivate is initialised to NULL, so we can check if
	 * the allocation has already been done.
	 */
	if (pScrn->driverPrivate == NULL)
	{
		pScrn->driverPrivate = xnfcalloc (sizeof (SMIRec), 1);
#if SMI_DEBUG
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "For screen %d, allocate an 'chip' rec (0x%x)\n", pScrn->scrnIndex, pScrn->driverPrivate);
#endif
	}

	LEAVE_PROC ("SMI_GetRec");
	return (pScrn->driverPrivate ? TRUE : FALSE);
}

	static void
SMI_FreeRec (ScrnInfoPtr pScrn)
{
	ENTER_PROC ("SMI_FreeRec");

	if (pScrn->driverPrivate != NULL)
	{
		xfree (pScrn->driverPrivate);
		pScrn->driverPrivate = NULL;
	}

	LEAVE_PROC ("SMI_FreeRec");
}

	static const OptionInfoRec *
SMI_AvailableOptions (int chipid, int busid)
{
	ENTER_PROC ("SMI_AvailableOptions");
	LEAVE_PROC ("SMI_AvailableOptions");
	return (SMIOptions);
}

	static void
SMI_Identify (int flags)
{
	ENTER_PROC ("SMI_Identify");

	xf86PrintChipsets (SILICONMOTION_NAME, "driver (version "
			SILICONMOTION_VERSION_NAME
			") for Silicon Motion Lynx chipsets", SMIChipsets);

	LEAVE_PROC ("SMI_Identify");
}

	static Bool
SMI_Probe (DriverPtr drv, int flags)
{
	int i;
	GDevPtr *devSections;
	int *usedChips;
	int numDevSections;
	int numUsed;
	Bool foundScreen = FALSE;

	ENTER_PROC ("SMI_Probe");


	numDevSections = xf86MatchDevice (SILICONMOTION_DRIVER_NAME, &devSections);

	if (numDevSections <= 0)
	{
		/* There's no matching device section in the config file, so quit now.
		*/
		LEAVE_PROC ("SMI_Probe");
		return (FALSE);
	}
	ENTER_PROC ("SMI_Probe");

	if (xf86GetPciVideoInfo () == NULL)
	{
		LEAVE_PROC ("SMI_Probe");
		return (FALSE);
	}
	ENTER_PROC ("SMI_Probe");


	numUsed = xf86MatchPciInstances (SILICONMOTION_NAME, PCI_SMI_VENDOR_ID,
			SMIChipsets, SMIPciChipsets, devSections,
			numDevSections, drv, &usedChips);
	ENTER_PROC ("SMI_Probe");
	/* Free it since we don't need that list after this */
	xfree (devSections);
	ENTER_PROC ("SMI_Probe");

	if (numUsed <= 0)
	{
		LEAVE_PROC ("SMI_Probe");
		return (FALSE);
	}

	if (flags & PROBE_DETECT)
	{
		foundScreen = TRUE;
	}
	else
	{
		for (i = 0; i < numUsed; i++)
		{
			EntityInfoPtr pEnt;
			ScrnInfoPtr pScrn = NULL;
			pScrn = NULL;

			if ((pScrn = xf86ConfigPciEntity (pScrn, 0, usedChips[i],
							SMIPciChipsets, 0, 0, 0, 0, 0)))
			{
				if (pScrn->display != NULL) {
				} else {
				}
				/* Fill in what we can of the ScrnInfoRec */
				pScrn->driverVersion = SILICONMOTION_DRIVER_VERSION;
				pScrn->driverName = SILICONMOTION_DRIVER_NAME;
				pScrn->name = SILICONMOTION_NAME;
				pScrn->Probe = SMI_Probe;
				pScrn->PreInit = SMI_PreInit;
				pScrn->ScreenInit = SMI_ScreenInit;
				pScrn->SwitchMode = SMI_SwitchMode;
				pScrn->AdjustFrame = SMI_AdjustFrame;
				pScrn->EnterVT = SMI_EnterVT;
				pScrn->LeaveVT = SMI_LeaveVT;
				pScrn->FreeScreen = SMI_FreeScreen;
				pScrn->ValidMode = SMI_ValidMode;
				foundScreen = TRUE;
			}

			pEnt = xf86GetEntityInfo (usedChips[i]);

			switch(pEnt->chipset) {
				case PCI_CHIP_SMI501:
					xf86DrvMsg(0, X_INFO, "501 found\n");
					entity_init_501(pScrn, usedChips[i]);
					break;

				default:
					break;
			}

			xfree (pEnt);
		}

	}

	xfree (usedChips);
	LEAVE_PROC ("SMI_Probe");
	return (foundScreen);
}

	static Bool
SMI_PreInit (ScrnInfoPtr pScrn, int flags)
{
	EntityInfoPtr pEnt;
	SMIPtr pSmi;
	MessageType from;
	int i;
	double real;
	ClockRangePtr clockRanges;
	char *s;
	unsigned char config, m, n, shift;
	int mclk;
	vgaHWPtr hwp;
	int vgaCRIndex, vgaIOBase;
	vbeInfoPtr pVbe = NULL;


#ifdef _XSERVER64
	unsigned char Generic_EDID[] =
	{ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x22, 0x64, 0x91, 0x89,
		0xE4, 0x12, 0x00, 0x00,
		0x16, 0x10, 0x01, 0x03, 0x80, 0x29, 0x1A, 0x78, 0x2A, 0x9B, 0xB6, 0xA4,
		0x53, 0x4B, 0x9D, 0x24,
		0x14, 0x4F, 0x54, 0xBF, 0xEF, 0x00, 0x31, 0x46, 0x61, 0x46, 0x71, 0x4F,
		0x81, 0x40, 0x81, 0x80,
		0x95, 0x00, 0x95, 0x0F, 0x01, 0x01, 0x9A, 0x29, 0xA0, 0xD0, 0x51, 0x84,
		0x22, 0x30, 0x50, 0x98,
		0x36, 0x00, 0x98, 0xFF, 0x10, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xFD,
		0x00, 0x31, 0x4B, 0x1E,
		0x50, 0x0E, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00,
		0x00, 0xFC, 0x00, 0x48,
		0x57, 0x31, 0x39, 0x31, 0x44, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x00, 0x00, 0x00, 0xFF,
		0x00, 0x36, 0x32, 0x32, 0x47, 0x48, 0x33, 0x32, 0x43, 0x41, 0x34, 0x38,
		0x33, 0x36, 0x00, 0x29
	};
#endif


	int chipType;

	ENTER_PROC ("SMI_PreInit");
#if SMI_DEBUG
	xf86EnableAccess(pScrn);
	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "pScrn is %p, screen index is %d, resource type is %d\n", pScrn, pScrn->scrnIndex, pScrn->resourceType);
#endif

	if (pScrn->numEntities > 1)
	{
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}

	/* Allocate the SMIRec driverPrivate */
	if (!SMI_GetRec (pScrn))
	{
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}

	pSmi = SMIPTR (pScrn);
	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "pScrn is %p, pSmi is %p, flags is 0x%x\n", pScrn, pSmi, flags);

	pEnt = xf86GetEntityInfo (pScrn->entityList[0]);

	/* Get the entity, and make sure it is PCI. */
	if (pEnt->location.type != BUS_PCI) {
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}
	pSmi->pEnt = pEnt;
	pSmi->PciInfo = xf86GetPciInfoForEntity (pEnt->index);

	chipType = pSmi->PciInfo->chipType;
	if (flags & PROBE_DETECT)
	{
		if (SMI_MSOC != chipType) {
			SMI_ProbeDDC (pScrn, xf86GetEntityInfo (pScrn->entityList[0])->index);
			LEAVE_PROC ("SMI_PreInit");
		}
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SM502\n");
		return (TRUE);
	}

	/* The vgahw module should be loaded here when needed */
	if (!xf86LoadSubModule (pScrn, "vgahw"))
	{
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}

	xf86LoaderReqSymLists (vgahwSymbols, NULL);
	/*
	 * Allocate a vgaHWRec
	 */
	if (!vgaHWGetHWRec (pScrn))
	{
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}


	/* Set pScrn->monitor */
	pScrn->monitor = pScrn->confScreen->monitor;

	/*
	 * The first thing we should figure out is the depth, bpp, etc.  Our
	 * default depth is 8, so pass it to the helper function.  We support
	 * only 24bpp layouts, so indicate that.
	 */
	switch (chipType) {
		case SMI_MSOC:
			if (smi_setdepbpp_501(pScrn) == FALSE) {
				LEAVE_PROC("SMI_PreInit");
				return FALSE;
			}
			break;

		default:
			if (smi_setdepbpp(pScrn) == FALSE) {
				LEAVE_PROC("SMI_PreInit");
				return FALSE;
			}
			break;
	}

	xf86PrintDepthBpp (pScrn);

	/*
	 * This must happen after pScrn->display has been set because
	 * xf86SetWeight references it.
	 */
	if ((pScrn->depth > 8))	/*&&(pScrn->depth <= 24)) */
	{
		/* The defaults are OK for us */
		rgb BitsPerComponent = { 0, 0, 0 };
		rgb BitMask = { 0, 0, 0 };

		if (!xf86SetWeight (pScrn, BitsPerComponent, BitMask))
		{
			LEAVE_PROC ("SMI_PreInit");
			return (FALSE);
		}
	}
	if (!xf86SetDefaultVisual (pScrn, -1))
	{
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}

	/* We don't currently support DirectColor at > 8bpp */
	if ((pScrn->depth > 8) && (pScrn->defaultVisual != TrueColor))
	{
		xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "Given default visual (%s) "
				"is not supported at depth %d\n",
				xf86GetVisualName (pScrn->defaultVisual), pScrn->depth);
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}

	/* We use a programmable clock */
	pScrn->progClock = TRUE;

	/* Collect all of the relevant option flags (fill in pScrn->options) */
	xf86CollectOptions (pScrn, NULL);


	/* Set the bits per RGB for 8bpp mode */
	if (pScrn->depth == 8)
	{
		if (SMI_MSOC == chipType)
		{
			pScrn->rgbBits = 8;
		}
		else
		{
			pScrn->rgbBits = 6;
		}
	}

	/* Process the options */
	if (!(pSmi->Options = xalloc (sizeof (SMIOptions))))
		return FALSE;
	memcpy (pSmi->Options, SMIOptions, sizeof (SMIOptions));
	xf86ProcessOptions (pScrn->scrnIndex, pScrn->options, pSmi->Options);

	if (xf86ReturnOptValBool (pSmi->Options, OPTION_PCI_BURST, FALSE))
	{
		pSmi->pci_burst = TRUE;
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Option: pci_burst - PCI burst "
				"read enabled\n");
	}
	else
	{
		pSmi->pci_burst = FALSE;
	}

	pSmi->NoPCIRetry = TRUE;
	if (xf86ReturnOptValBool (pSmi->Options, OPTION_PCI_RETRY, FALSE))
	{
		if (xf86ReturnOptValBool (pSmi->Options, OPTION_PCI_BURST, FALSE))
		{
			pSmi->NoPCIRetry = FALSE;
			xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Option: pci_retry\n");
		}
		else
		{
			xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option "
					"requires \"pci_burst\".\n");
		}
	}

	if (xf86IsOptionSet (pSmi->Options, OPTION_FIFO_CONSERV))
	{
		pSmi->fifo_conservative = TRUE;
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Option: fifo_conservative "
				"set\n");
	}
	else
	{
		pSmi->fifo_conservative = FALSE;
	}

	if (xf86IsOptionSet (pSmi->Options, OPTION_FIFO_MODERATE))
	{
		pSmi->fifo_moderate = TRUE;
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Option: fifo_moderate set\n");
	}
	else
	{
		pSmi->fifo_moderate = FALSE;
	}

	if (xf86IsOptionSet (pSmi->Options, OPTION_FIFO_AGGRESSIVE))
	{
		pSmi->fifo_aggressive = TRUE;
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG,
				"Option: fifo_aggressive set\n");
	}
	else
	{
		pSmi->fifo_aggressive = FALSE;
	}

	if (xf86ReturnOptValBool (pSmi->Options, OPTION_NOACCEL, FALSE))
	{
		pSmi->NoAccel = TRUE;
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG,
				"Option: NoAccel - Acceleration " "disabled\n");
	}
	else
	{
		pSmi->NoAccel = FALSE;
	}

	if (xf86ReturnOptValBool (pSmi->Options, OPTION_SHOWCACHE, FALSE))
	{
		pSmi->ShowCache = TRUE;
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Option: show_cache set\n");
	}
	else
	{
		pSmi->ShowCache = FALSE;
	}

	if (xf86GetOptValFreq (pSmi->Options, OPTION_MCLK, OPTUNITS_MHZ, &real))
	{
		pSmi->MCLK = (int) (real * 1000.0);
		if (chipType != SMI_MSOC) {
			if (pSmi->MCLK <= 120000)
			{
				xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Option: set_mclk set to "
						"%1.3f MHz\n", pSmi->MCLK / 1000.0);
			}
			else
			{
				xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "Memory Clock value of "
						"%1.3f MHz is larger than limit of 120 MHz\n",
						pSmi->MCLK / 1000.0);
				pSmi->MCLK = 0;
			}
		}
	}
	else
	{
		pSmi->MCLK = 0;
#ifdef	FIXUP_89INCH_BUG
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A, 0x16);
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B, 0x02);
#endif
	}

	from = X_DEFAULT;
	pSmi->hwcursor = TRUE;
	if (xf86GetOptValBool (pSmi->Options, OPTION_HWCURSOR, &pSmi->hwcursor))
	{
		from = X_CONFIG;
	}
	if (xf86ReturnOptValBool (pSmi->Options, OPTION_SWCURSOR, FALSE))
	{
		pSmi->hwcursor = FALSE;
		from = X_CONFIG;
	}

	xf86DrvMsg (pScrn->scrnIndex, from, "Using %s Cursor\n",
			pSmi->hwcursor ? "Hardware" : "Software");

	if (xf86GetOptValBool (pSmi->Options, OPTION_SHADOW_FB, &pSmi->shadowFB))
	{
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n",
				pSmi->shadowFB ? "enabled" : "disabled");
	}

	if ((s = xf86GetOptValString (pSmi->Options, OPTION_ROTATE)))
	{
		if (!xf86NameCmp (s, "CCW"))
		{
			pSmi->shadowFB = TRUE;
			pSmi->rotate = SMI_ROTATE_CCW;
			xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Rotating screen "
					"clockwise\n");
		}
		else if (!xf86NameCmp (s, "CW"))
		{
			pSmi->shadowFB = TRUE;
			pSmi->rotate = SMI_ROTATE_CW;
			xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Rotating screen counter "
					"clockwise\n");
		}
		else if (!xf86NameCmp (s, "UD"))
		{
			pSmi->shadowFB = TRUE;
			pSmi->rotate = SMI_ROTATE_UD;
			xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Rotating screen half "
					"clockwise\n");
		}	
		else if(!xf86NameCmp(s, "RandR")) 
		{
#ifdef RANDR
			pSmi->shadowFB = TRUE;
			pSmi->RandRRotation = TRUE;
			pSmi->rotate = SMI_ROTATE_ZERO;	
			//		pSmi->rotate = SMI_ROTATE_CW;
			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
					"Using RandR rotation - acceleration disabled\n");
#else
			xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
					"This driver was not compiled with support for the Resize and "
					"Rotate extension.  Cannot honor 'Option \"Rotate\" "
					"\"RandR\"'.\n");
#endif
		}
		else
		{
			xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid "
					"value for Option \"Rotate\"\n", s);
			xf86DrvMsg (pScrn->scrnIndex, X_INFO,
					"Valid options are \"CW\" or " "\"CCW\" or " "\"UD\" or " "\"RandR\"\n");
		}
	}

	if (pSmi->rotate)
	{
		/* Disable XF86 rotation, it hoses up SMI rotation */
		xf86DisableRandR ();
	}

	if (xf86GetOptValInteger (pSmi->Options, OPTION_VIDEOKEY, &pSmi->videoKey))
	{
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Option: Video key set to "
				"0x%08X\n", pSmi->videoKey);
	}
	else
	{
		pSmi->videoKey = (1 << pScrn->offset.red) | (1 << pScrn->offset.green)
			| (((pScrn->mask.blue >> pScrn->offset.blue) - 1)
					<< pScrn->offset.blue);
	}

	if (xf86ReturnOptValBool (pSmi->Options, OPTION_BYTESWAP, FALSE))
	{
		pSmi->ByteSwap = TRUE;
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Option: ByteSwap enabled.\n");
	}
	else
	{
		pSmi->ByteSwap = FALSE;
	}

	/* CZ 26.10.2001: interlaced video */
	if (xf86ReturnOptValBool (pSmi->Options, OPTION_INTERLACED, FALSE))
	{
		pSmi->interlaced = TRUE;
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG,
				"Option: Interlaced enabled.\n");
	}
	else
	{
		pSmi->interlaced = FALSE;
	}
	/* end CZ */

	if (xf86GetOptValBool (pSmi->Options, OPTION_USEBIOS, &pSmi->useBIOS))
	{
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Option: UseBIOS %s.\n",
				pSmi->useBIOS ? "enabled" : "disabled");
	}
	else
	{
		/* Default to UseBIOS enabled. */
		pSmi->useBIOS = FALSE;
	}

	if (xf86GetOptValBool (pSmi->Options, OPTION_ZOOMONLCD, &pSmi->zoomOnLCD))
	{
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Option: ZoomOnLCD %s.\n",
				pSmi->zoomOnLCD ? "enabled" : "disabled");
	}
	else
	{
		/* Default to ZoomOnLCD enabled. */
		pSmi->zoomOnLCD = TRUE;
	}
	if (xf86GetOptValBool (pSmi->Options, OPTION_PANELHEIGHT, &pSmi->lcdHeight))
	{
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Option: LCDHeight %d.\n",
				pSmi->lcdHeight);
	}
	else
	{
		/* Default to ZoomOnLCD enabled. */
		pSmi->lcdHeight = 0;
	}
	if (xf86GetOptValBool (pSmi->Options, OPTION_PANELWIDTH, &pSmi->lcdWidth))
	{
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Option: LCDWidth %d.\n",
				pSmi->lcdWidth);
	}
	else
	{
		/* Default to ZoomOnLCD enabled. */
		pSmi->lcdWidth = 0;
	}

	/* Find the PCI slot for this screen */
	pEnt = xf86GetEntityInfo (pScrn->entityList[0]);
	if ((pEnt->location.type != BUS_PCI) || (pEnt->resources))
	{
		xfree (pEnt);
		SMI_FreeRec (pScrn);
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}

	if (chipType != SMI_MSOC)	/* IGX -- NO vga on 501 */
	{

		if (xf86LoadSubModule (pScrn, "int10"))
		{
			xf86LoaderReqSymLists (int10Symbols, NULL);
			pSmi->pInt10 = xf86InitInt10 (pEnt->index);
		}

		if (pSmi->pInt10 && xf86LoadSubModule (pScrn, "vbe"))
		{
			xf86LoaderReqSymLists (vbeSymbols, NULL);
			pVbe = VBEInit (pSmi->pInt10, pEnt->index);
		}
	}

	xf86RegisterResources (pEnt->index, NULL, ResExclusive);

	/*
	 * Set the Chipset and ChipRev, allowing config file entries to
	 * override.
	 */
	if (pEnt->device->chipset && *pEnt->device->chipset)
	{
		pScrn->chipset = pEnt->device->chipset;
		pSmi->Chipset = xf86StringToToken (SMIChipsets, pScrn->chipset);
		from = X_CONFIG;
	}
	else if (pEnt->device->chipID >= 0)
	{
		pSmi->Chipset = pEnt->device->chipID;
		pScrn->chipset =
			(char *) xf86TokenToString (SMIChipsets, pSmi->Chipset);
		from = X_CONFIG;
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
				pSmi->Chipset);
	}
	else
	{
		from = X_PROBED;
		pSmi->Chipset = pSmi->PciInfo->chipType;
		pScrn->chipset =
			(char *) xf86TokenToString (SMIChipsets, pSmi->Chipset);
	}

	if (pEnt->device->chipRev >= 0)
	{
		pSmi->ChipRev = pEnt->device->chipRev;
		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
				pSmi->ChipRev);
	}
	else
	{
		pSmi->ChipRev = pSmi->PciInfo->chipRev;
	}
	xfree (pEnt);

	/*
	 * This shouldn't happen because such problems should be caught in
	 * SMI_Probe(), but check it just in case.
	 */
	if (pScrn->chipset == NULL)
	{
		xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "ChipID 0x%04X is not "
				"recognised\n", pSmi->Chipset);
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}
	if (pSmi->Chipset < 0)
	{
		xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "Chipset \"%s\" is not "
				"recognised\n", pScrn->chipset);
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}

	xf86DrvMsg (pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset);

	pSmi->PciTag = pciTag (pSmi->PciInfo->bus, pSmi->PciInfo->device,
			pSmi->PciInfo->func);
	pci_tag = pSmi->PciTag;
	config = pciReadByte(pSmi->PciTag, PCI_CMD_STAT_REG);
	pciWriteByte(pSmi->PciTag, PCI_CMD_STAT_REG, config | PCI_CMD_MEM_ENABLE);

	/*boyod */

	pSmi->IsSecondary = FALSE;
	pSmi->IsPrimary = TRUE;
	pSmi->IsLCD = TRUE;
	pSmi->IsCRT = FALSE;

	switch (chipType) {
		case SMI_MSOC:
			smi_set_dualhead_501(pScrn, pSmi);
			break;

		default:
			break;
	}

	/* Map memory should execute ahead any vga io operation */
	SMI_MapMem (pScrn);

	/* And compute the amount of video memory and offscreen memory */
	pSmi->videoRAMKBytes = 0;

	/* Added by Belcon according to driver of sm712 */
	// Detect amount of installed ram */
	config = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x71);
	if(pSmi->Chipset == SMI_LYNXEMplus){
		config = (0x2 << 6);
	}
	if (!pScrn->videoRam) {
		switch(pSmi->Chipset) {
			case SMI_LYNX3D:
				smi_setvideomem_820(config, pScrn, pSmi);
				break;

			case SMI_LYNX3DM:
				smi_setvideomem_720(config, pScrn, pSmi);
				break;

			case SMI_COUGAR3DR:
				smi_setvideomem_730(config, pScrn, pSmi);
				break;

			case SMI_MSOC:
				smi_setvideomem_501(config, pScrn, pSmi);
				break;
			case SMI_LYNXEM:
			case SMI_LYNXEMplus:
				smi_setvideomem_712(config, pScrn, pSmi);
				break;
			default:
				smi_setvideomem(config, pScrn, pSmi);
				break;
		}
	} else {
		pSmi->videoRAMKBytes = pScrn->videoRam;
		pSmi->videoRAMBytes = pScrn->videoRam * 1024;

		xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "videoram: %dk\n",
				pSmi->videoRAMKBytes);
	}
#if SMI_DEBUG
	xf86DrvMsg (pScrn->scrnIndex, X_PROBED, " videoram: %dkB\n",
			pSmi->videoRAMKBytes);
#endif

	if (chipType != SMI_MSOC)	/* IGX */
	{
		SMI_DisableVideo (pScrn);

		hwp = VGAHWPTR (pScrn);
		vgaIOBase = hwp->IOBase;
		vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
		pSmi->PIOBase = hwp->PIOOffset;

		xf86ErrorFVerb (VERBLEV, "\tSMI_PreInit vgaCRIndex=%x, vgaIOBase=%x, "
				"MMIOBase=%x\n", vgaCRIndex, (unsigned int)vgaIOBase, (unsigned int)(hwp->MMIOBase));

		/* Next go on to detect amount of installed ram */
		//  config = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x71);


#ifdef _XSERVER64

		/*  Fake the reading of a valid EDID block to allow the population of the
		    default configuration file upon startup. */

		if (xf86LoadSubModule (pScrn, "i2c"))
		{
			xf86LoaderReqSymLists (i2cSymbols, NULL);
			SMI_I2CInit (pScrn);	/* IGXMAL DEBUG */
			xf86ErrorFVerb (VERBLEV, "\tSMI_I2CInit ");
		}


		if (xf86LoadSubModule (pScrn, "ddc"))
		{
			xf86MonPtr pMon = NULL;

			xf86LoaderReqSymLists (ddcSymbols, NULL);
			{

				unsigned char *EDID_Block = Generic_EDID;
				pMon = xf86InterpretEDID (pScrn, EDID_Block);

				if (pMon != NULL)
				{
					pMon = xf86PrintEDID (pMon);
					if (pMon != NULL)
					{
						xf86SetDDCproperties (pScrn, pMon);
					}
				}
			}
		}

#else


		if (xf86LoadSubModule (pScrn, "i2c"))
		{
			xf86LoaderReqSymLists (i2cSymbols, NULL);
			SMI_I2CInit (pScrn);
		}

		if (xf86LoadSubModule (pScrn, "ddc"))
		{
			xf86MonPtr pMon = NULL;

			xf86LoaderReqSymLists (ddcSymbols, NULL);
#if 1				/* PDR#579 */
			if (pVbe)
			{
				pMon = vbeDoEDID (pVbe, NULL);
				if (pMon != NULL)
				{
					if ((pMon->rawData[0] == 0x00)
							&& (pMon->rawData[1] == 0xFF)
							&& (pMon->rawData[2] == 0xFF)
							&& (pMon->rawData[3] == 0xFF)
							&& (pMon->rawData[4] == 0xFF)
							&& (pMon->rawData[5] == 0xFF)
							&& (pMon->rawData[6] == 0xFF)
							&& (pMon->rawData[7] == 0x00))
					{
						pMon = xf86PrintEDID (pMon);
						if (pMon != NULL)
						{
							xf86SetDDCproperties (pScrn, pMon);
						}
					}
				}
			}
#else
			if ((pVbe)
					&& ((pMon = xf86PrintEDID (vbeDoEDID (pVbe, NULL))) != NULL))
			{
				xf86SetDDCproperties (pScrn, pMon);
			}
#endif
			else if (!SMI_ddc1 (pScrn->scrnIndex))
			{
				if (pSmi->I2C)
				{
					xf86SetDDCproperties (pScrn,
							xf86PrintEDID (xf86DoEDID_DDC2
								(pScrn->scrnIndex,
								 pSmi->I2C)));
				}
			}
		}

		vbeFree (pVbe);
		xf86FreeInt10 (pSmi->pInt10);




		pSmi->pInt10 = NULL;

#endif
	}				/* End !SMI_MSOC */

	/*
	 * If the driver can do gamma correction, it should call xf86SetGamma()
	 * here. (from MGA, no ViRGE gamma support yet, but needed for
	 * xf86HandleColormaps support.)
	 */
	{
		Gamma zeros = { 0.0, 0.0, 0.0 };

		if (!xf86SetGamma (pScrn, zeros))
		{
			LEAVE_PROC ("SMI_PreInit");
			SMI_EnableVideo (pScrn);
			SMI_UnmapMem (pScrn);
			return (FALSE);
		}
	}


	/* Lynx built-in ramdac speeds */
	pScrn->numClocks = 4;

	if ((pScrn->clock[3] <= 0) && (pScrn->clock[2] > 0))
	{
		pScrn->clock[3] = pScrn->clock[2];
	}

	switch (pSmi->Chipset) {
		case SMI_LYNX3DM:
		case SMI_COUGAR3DR:
		case SMI_MSOC:
			smi_setclk(pScrn, 200000, 200000, 200000, 200000);
			break;

		default:
			smi_setclk(pScrn, 135000, 135000, 135000, 135000);
			break;
	}

	/* Now set RAMDAC limits */
	switch (pSmi->Chipset)
	{
		default:
			pSmi->minClock = 12000;
			pSmi->maxClock = 270000;

			break;
	}
	xf86ErrorFVerb (VERBLEV, "\tSMI_PreInit minClock=%d, maxClock=%d\n",
			pSmi->minClock, pSmi->maxClock);

	if (SMI_MSOC != pSmi->Chipset)
	{

		/* Detect current MCLK and print it for user */
		m = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A);
		n = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B);
		switch (n >> 6)
		{
			default:
				shift = 1;
				break;

			case 1:
				shift = 4;
				break;

			case 2:
				shift = 2;
				break;
		}
		n &= 0x3F;
		mclk = ((1431818 * m) / n / shift + 50) / 100;
		xf86DrvMsg (pScrn->scrnIndex, X_PROBED,
				"Detected current MCLK value of " "%1.3f MHz\n",
				mclk / 1000.0);
	}

	SMI_EnableVideo (pScrn);
	SMI_UnmapMem (pScrn);
	xf86DrvMsg(0, X_INFO, "pScrn->virtualX is %d, pScrn->display->virtualX is %d\n",
			(unsigned int)pScrn->virtualX, (unsigned int)pScrn->display->virtualX);
	pScrn->virtualX = pScrn->display->virtualX;

	/*
	 * Setup the ClockRanges, which describe what clock ranges are available,
	 * and what sort of modes they can be used for.
	 */
	clockRanges = xnfcalloc (sizeof (ClockRange), 1);
	clockRanges->next = NULL;

	clockRanges->minClock = pSmi->minClock;
	clockRanges->maxClock = pSmi->maxClock;
	clockRanges->clockIndex = -1;
	clockRanges->interlaceAllowed = FALSE;
	clockRanges->doubleScanAllowed = FALSE;


	/*boyod */

	i = xf86ValidateModes (pScrn,	/* Screen pointer                                         */
			pScrn->monitor->Modes,	/* Available monitor modes                        */
			pScrn->display->modes,	/* req mode names for screen              */
			clockRanges,	/* list of clock ranges allowed           */
			NULL,	/* use min/max below                              */
			128,	/* min line pitch (width)                         */
			4096,	/* maximum line pitch (width)             */
			128,	/* bits of granularity for line pitch */
			/* (width) above                                          */
			128,	/* min virtual height                             */
			4096,	/* max virtual height                             */
			pScrn->display->virtualX,	/* force virtual x                                        */
			pScrn->display->virtualY,	/* force virtual Y                                        */
			pSmi->videoRAMBytes,	/* size of aperture used to access        */
			/* video memory                                           */
			LOOKUP_BEST_REFRESH);	/* how to pick modes                              */

	if (i == -1)
	{
		SMI_FreeRec (pScrn);
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}

	/* Prune the modes marked as invalid */
	xf86PruneDriverModes (pScrn);
	if ((i == 0) || (pScrn->modes == NULL))
	{
		xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
		SMI_FreeRec (pScrn);
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}

	/* Don't need this for 501 */
	if (SMI_MSOC != pSmi->Chipset)
	{
		xf86SetCrtcForModes (pScrn, 0);
	}

	/* Set the current mode to the first in the list */
	pScrn->currentMode = pScrn->modes;

	/* Print the list of modes being used */
	xf86PrintModes (pScrn);

	/* Set display resolution */
	xf86SetDpi (pScrn, 0, 0);


	if ((xf86LoadSubModule (pScrn, "fb") == NULL))
	{
		SMI_FreeRec (pScrn);
		LEAVE_PROC ("SMI_PreInit");
		return (FALSE);
	}

	xf86LoaderReqSymLists (fbSymbols, NULL);

	/* Load XAA if needed */
	if (!pSmi->NoAccel || pSmi->hwcursor)
	{
		if (!xf86LoadSubModule (pScrn, "xaa"))
		{
			SMI_FreeRec (pScrn);
			LEAVE_PROC ("SMI_PreInit");
			return (FALSE);
		}
		xf86LoaderReqSymLists (xaaSymbols, NULL);
	}

	/* Load ramdac if needed */
	if (pSmi->hwcursor)
	{
		if (!xf86LoadSubModule (pScrn, "ramdac"))
		{
			SMI_FreeRec (pScrn);
			LEAVE_PROC ("SMI_PreInit");
			return (FALSE);
		}
		xf86LoaderReqSymLists (ramdacSymbols, NULL);
	}

	if (pSmi->shadowFB)
	{
		if (!xf86LoadSubModule (pScrn, "shadowfb"))
		{
			SMI_FreeRec (pScrn);
			LEAVE_PROC ("SMI_PreInit");
			return (FALSE);
		}
		xf86LoaderReqSymLists (shadowSymbols, NULL);
	}

	LEAVE_PROC ("SMI_PreInit");
	xf86DrvMsg(0, X_INFO, "PCI: command is 0x%x, line %d\n", pciReadByte(pSmi->PciTag, PCI_CMD_STAT_REG), __LINE__);
	read_cmd_reg(4);
	return (TRUE);
}

/*
 * This is called when VT switching back to the X server.  Its job is to
 * reinitialise the video mode. We may wish to unmap video/MMIO memory too.
 */

	static Bool
SMI_EnterVT (int scrnIndex, int flags)
{
	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
	SMIPtr pSmi = SMIPTR (pScrn);
	Bool ret;

	ENTER_PROC ("SMI_EnterVT");

	/* Enable MMIO and map memory */
	/*
	   SMI_MapMem(pScrn);
	   SMI_Save(pScrn);
	   */

	if (!SMI_MapMem (pScrn))
	{
		LEAVE_PROC ("SMI_EnterVT");
		return (FALSE);
	}

	SMI_RestoreReg(pScrn);
	/* #670 */
	if (pSmi->shadowFB)
	{
		pSmi->FBOffset = pSmi->savedFBOffset;
		pSmi->FBReserved = pSmi->savedFBReserved;
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "line %d: pSmi->FBReserved is 0x%x\n", 
				__LINE__, (unsigned int)pSmi->FBReserved);
	}

	ret = SMI_ModeInit (pScrn, pScrn->currentMode);

	/* #670 */
	if (ret && pSmi->shadowFB)
	{
		BoxRec box;

		/* #920 */
		if (pSmi->paletteBuffer)
		{
			int i;

			VGAOUT8 (pSmi, VGA_DAC_WRITE_ADDR, 0);
			for (i = 0; i < 256 * 3; i++)
			{
				VGAOUT8 (pSmi, VGA_DAC_DATA, pSmi->paletteBuffer[i]);
			}
			xfree (pSmi->paletteBuffer);
			pSmi->paletteBuffer = NULL;
		}

		if (pSmi->pSaveBuffer)
		{
			memcpy (pSmi->FBBase, pSmi->pSaveBuffer, pSmi->saveBufferSize);
			xfree (pSmi->pSaveBuffer);
			pSmi->pSaveBuffer = NULL;
		}

		box.x1 = 0;
		box.y1 = 0;
		box.x2 = pScrn->virtualY;
		box.y2 = pScrn->virtualX;

		if (pSmi->Chipset == SMI_COUGAR3DR)
		{
			SMI_RefreshArea730 (pScrn, 1, &box);
		}
		else
		{
			SMI_RefreshArea (pScrn, 1, &box);
		}

	}

	/* Reset the grapics engine */
	if (!pSmi->NoAccel)
		SMI_EngineReset (pScrn);

	LEAVE_PROC ("SMI_EnterVT");
	return (ret);
}

/*
 * This is called when VT switching away from the X server.  Its job is to
 * restore the previous (text) mode. We may wish to remap video/MMIO memory
 * too.
 */

	static void
SMI_LeaveVT (int scrnIndex, int flags)
{
	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
	vgaHWPtr hwp = VGAHWPTR (pScrn);
	SMIPtr pSmi = SMIPTR (pScrn);
	vgaRegPtr vgaSavePtr = &hwp->SavedReg;
	SMIRegPtr SMISavePtr = &pSmi->SavedReg;

	ENTER_PROC ("SMI_LeaveVT");

	SMI_SaveReg(pScrn );
	/* #670 */
	if (pSmi->shadowFB)
	{
		pSmi->pSaveBuffer = xnfalloc (pSmi->saveBufferSize);
		if (pSmi->pSaveBuffer)
		{
			memcpy (pSmi->pSaveBuffer, pSmi->FBBase, pSmi->saveBufferSize);
		}

		pSmi->savedFBOffset = pSmi->FBOffset;
		pSmi->savedFBReserved = pSmi->FBReserved;

		/* #920 */
		if (pSmi->Bpp == 1)
		{
			pSmi->paletteBuffer = xnfalloc (256 * 3);
			if (pSmi->paletteBuffer)
			{
				int i;

				VGAOUT8 (pSmi, VGA_DAC_READ_ADDR, 0);
				for (i = 0; i < 256 * 3; i++)
				{
					pSmi->paletteBuffer[i] = VGAIN8 (pSmi, VGA_DAC_DATA);
				}
			}
		}
	}

	memset (pSmi->FBBase, 0, 256 * 1024);	/* #689 */
	SMI_WriteMode (pScrn, vgaSavePtr, SMISavePtr);
	/*
	 * Belcon: Fix #001
	 * 	Restore hardware cursor register
	 */
	if (pSmi->dcrF0)
		WRITE_DCR(pSmi, DCRF0, pSmi->dcrF0);
	if (pSmi->dcr230)
		WRITE_DCR(pSmi, DCR230, pSmi->dcr230);
	/* #001 ended */
	SMI_UnmapMem (pScrn);

	LEAVE_PROC ("SMI_LeaveVT");
}

/*
 * This function performs the inverse of the restore function: It saves all the
 * standard and extended registers that we are going to modify to set up a video
 * mode.
 */

	static void
SMI_Save (ScrnInfoPtr pScrn)
{
	int i;
	CARD32 offset;

	vgaHWPtr hwp = VGAHWPTR (pScrn);
	vgaRegPtr vgaSavePtr = &hwp->SavedReg;
	SMIPtr pSmi = SMIPTR (pScrn);
	SMIRegPtr save = &pSmi->SavedReg;

	int vgaIOBase = hwp->IOBase;
	int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
	int vgaCRData = vgaIOBase + VGA_CRTC_DATA_OFFSET;

	ENTER_PROC ("SMI_Save");

	if (SMI_MSOC != pSmi->Chipset)
	{

		/* Save the standard VGA registers */
		SMI_vgaHWSave (pSmi, (SMI_vgaRegPtr)vgaSavePtr, VGA_SR_ALL);
		save->smiDACMask = VGAIN8 (pSmi, VGA_DAC_MASK);
		VGAOUT8 (pSmi, VGA_DAC_READ_ADDR, 0);
		for (i = 0; i < 256; i++)
		{
			save->smiDacRegs[i][0] = VGAIN8 (pSmi, VGA_DAC_DATA);
			save->smiDacRegs[i][1] = VGAIN8 (pSmi, VGA_DAC_DATA);
			save->smiDacRegs[i][2] = VGAIN8 (pSmi, VGA_DAC_DATA);
		}
		for (i = 0, offset = 2; i < 8192; i++, offset += 8)
		{
			save->smiFont[i] = *(pSmi->FBBase + offset);
		}

		/* Now we save all the extended registers we need. */
		save->SR17 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17);
		if (-1 == saved_console_reg) {
			save->SR18 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18);
			saved_console_reg = 0x0;
		} else {
			save->SR18 = (pSmi->SavedReg).SR18;
		}
		save->SR21 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
		save->SR31 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31);
		save->SR32 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32);
		save->SR6A = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A);
		save->SR6B = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B);
		/*Add for 64bit */
		save->SR6C = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C);
		save->SR6D = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D);

		save->SR81 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81);
		save->SRA0 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0);

		if (SMI_LYNXM_SERIES (pSmi->Chipset))
		{
			/* Save primary registers */
			save->CR90[14] = VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x9E);
			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x9E,
					save->CR90[14] & ~0x20);

			for (i = 0; i < 16; i++)
			{
				save->CR90[i] =
					VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x90 + i);
			}
			save->CR30 = VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x30);
			save->CR33 = VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x33);
			save->CR3A = VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x3A);
			for (i = 0; i < 14; i++)
			{
				save->CR40[i] =
					VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x40 + i);
			}

			/* Save secondary registers */
			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x9E,
					save->CR90[14] | 0x20);
			save->CR33_2 = VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x33);
			for (i = 0; i < 14; i++)
			{
				save->CR40_2[i] = VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData,
						0x40 + i);
			}
			save->CR9F_2 = VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x9F);

			/* Save common registers */
			for (i = 0; i < 14; i++)
			{
				save->CRA0[i] =
					VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0xA0 + i);
			}

			/* PDR#1069 */
			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14]);
		}
		else
		{
			save->CR30 = VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x30);
			save->CR33 = VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x33);
			save->CR3A = VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x3A);
			for (i = 0; i < 14; i++)
			{
				save->CR40[i] =
					VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x40 + i);
			}
		}

		/* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */
		if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR))
		{
			save->CCR66 =
				VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66);
		}
		/* end CZ */
	}


	save->DPR10 = READ_DPR (pSmi, 0x10);
	save->DPR1C = READ_DPR (pSmi, 0x1C);
	save->DPR20 = READ_DPR (pSmi, 0x20);
	save->DPR24 = READ_DPR (pSmi, 0x24);
	save->DPR28 = READ_DPR (pSmi, 0x28);
	save->DPR2C = READ_DPR (pSmi, 0x2C);
	save->DPR30 = READ_DPR (pSmi, 0x30);
	save->DPR3C = READ_DPR (pSmi, 0x3C);
	save->DPR40 = READ_DPR (pSmi, 0x40);
	save->DPR44 = READ_DPR (pSmi, 0x44);

	save->VPR00 = READ_VPR (pSmi, 0x00);
	save->VPR0C = READ_VPR (pSmi, 0x0C);
	save->VPR10 = READ_VPR (pSmi, 0x10);

	if (pSmi->Chipset == SMI_COUGAR3DR)
	{
		save->FPR00_ = READ_FPR (pSmi, FPR00);
		save->FPR0C_ = READ_FPR (pSmi, FPR0C);
		save->FPR10_ = READ_FPR (pSmi, FPR10);
	}

	save->CPR00 = READ_CPR (pSmi, 0x00);

	if (SMI_MSOC != pSmi->Chipset)
	{
		if (!pSmi->ModeStructInit)
		{
			/* XXX Should check the return value of vgaHWCopyReg() */
			vgaHWCopyReg (&hwp->ModeReg, vgaSavePtr);
			memcpy (&pSmi->ModeReg, save, sizeof (SMIRegRec));
			pSmi->ModeStructInit = TRUE;
		}
	}

	if (xf86GetVerbosity () > 1)
	{
		xf86DrvMsgVerb (pScrn->scrnIndex, X_INFO, VERBLEV,
				"Saved current video mode.  Register dump:\n");
		SMI_PrintRegs (pScrn);
	}

	LEAVE_PROC ("SMI_Save");
}

int GetFreshRate(DisplayModePtr mode)
{
	char *pString = mode->name;
	float Refresh;

	while(((*pString) != '\0'))
	{
		if(*pString == '@')
			break;

		pString++;
	}


	if((*pString) == '\0')
	{
		Refresh = mode->VRefresh;
		if(Refresh > 85 * (1.0 - SYNC_TOLERANCE)) return 85;
		if(Refresh > 75 * (1.0 - SYNC_TOLERANCE)) return 75;
		if(Refresh > 60 * (1.0 - SYNC_TOLERANCE)) return 60;

		return 60;

	}
	else
	{

		pString++;
		if((*pString == '6')&&(*(pString+1) == '0')) return 60;
		if((*pString == '7')&&(*(pString+1) == '5')) return 75;
		if((*pString == '8')&&(*(pString+1) == '5')) return 85;

		return 60;
	}

}




	static void
SMI_BiosWriteMode (ScrnInfoPtr pScrn, DisplayModePtr mode, SMIRegPtr restore)
{
	int i;
	CARD8 tmp;
	EntityInfoPtr pEnt;

	SMIPtr pSmi     = SMIPTR (pScrn);

	//if not use bios call, return
	if(!pSmi->useBIOS) return;	

	int modeindex = 0; 
	int VsyncBits = 0x0;        //00 -- 43Hz
	//01 -- 60Hz 
	//10 -- 75Hz
	//11 -- 85Hz
	/* Find the INT 10 mode number */
	static struct
	{
		int x, y, bpp, freshrate;
		CARD16 mode;
	} 
	modeTable[] =
	{
		{640, 480, 8, 60,0x50},
		{640, 480, 16, 60,0x52},
		{640, 480, 24, 60,0x53},
		{640, 480, 32, 60,0x54},
		{640, 480, 8, 75,0x50},
		{640, 480, 16, 75,0x52},
		{640, 480, 24, 75,0x53},
		{640, 480, 32, 75,0x54},
		{640, 480, 8, 85,0x50},
		{640, 480, 16, 85,0x52},
		{640, 480, 24, 85,0x53},
		{640, 480, 32, 85,0x54},

		{800, 480, 8, 60,0x4A},
		{800, 480, 16, 60,0x4C},
		{800, 480, 24, 60,0x4D},
		{800, 480, 8, 75,0x4A},
		{800, 480, 16, 75,0x4C},
		{800, 480, 24, 75,0x4D},
		{800, 480, 8, 85,0x4A},
		{800, 480, 16, 85,0x4C},
		{800, 480, 24, 85,0x4D},


		{800, 600, 8, 60,0x55},
		{800, 600, 16,60, 0x57},
		{800, 600, 24, 60,0x58},
		{800, 600, 32, 60,0x59},
		{800, 600, 8, 75,0x55},
		{800, 600, 16,75, 0x57},
		{800, 600, 24, 75,0x58},
		{800, 600, 32, 75,0x59},
		{800, 600, 8, 85,0x55},
		{800, 600, 16,85, 0x57},
		{800, 600, 24, 85,0x58},
		{800, 600, 32, 85,0x59},


		{1024, 768, 8, 60,0x60},
		{1024, 768, 16, 60,0x62},
		{1024, 768, 24, 60,0x63},
		{1024, 768, 32, 60,0x64},
		{1024, 768, 8, 75,0x60},
		{1024, 768, 16, 75,0x62},
		{1024, 768, 24, 75,0x63},
		{1024, 768, 32, 75,0x64},
		{1024, 768, 8, 85,0x60},
		{1024, 768, 16, 85,0x62},
		{1024, 768, 24, 85,0x63},
		{1024, 768, 32, 85,0x64},


		{1280, 1024, 8, 60,0x65},
		{1280, 1024, 16, 60,0x67},
		{1280, 1024, 24, 60,0x68},
		{1280, 1024, 32, 60,0x69},
		{1280, 1024, 8, 75,0x65},
		{1280, 1024, 16, 75,0x67},
		{1280, 1024, 24, 75,0x68},
		{1280, 1024, 32, 75,0x69},
	};

	ENTER_PROC ("SMI_BiosWriteMode");
	//check mode width, height, freshrate
	for (i = 0; i < sizeof (modeTable) / sizeof (modeTable[0]); i++)
	{
		if ((modeTable[i].x == mode->HDisplay)
				&& (modeTable[i].y == mode->VDisplay)
				&& (modeTable[i].bpp == pScrn->bitsPerPixel)
				&&(modeTable[i].freshrate == GetFreshRate(mode)))
		{
			modeindex = i;
			break;
		}
	}

	vgaHWProtect (pScrn, TRUE);

	/* Wait for engine to become idle */
	WaitIdle ();


	//if no use int10 function, load it    - = - mill.chen
	if(pSmi->pInt10 == NULL)
	{
		pEnt = xf86GetEntityInfo (pScrn->entityList[0]);
		pSmi->pInt10 = xf86InitInt10 (pEnt->index);
	}

	//begin to use bios call
	if (pSmi->pInt10 != NULL) 
	{
		pSmi->pInt10->num = 0x10;
		pSmi->pInt10->ax = modeTable[modeindex].mode | 0x80;

		switch(modeTable[modeindex].freshrate)
		{
			case 60: 	VsyncBits = 0x1; break;
			case 75:		VsyncBits = 0x2; break;
			case 85:		VsyncBits = 0x3; break;
			default:		VsyncBits = 0x0; 		
		}


		tmp = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x71);   // only use in our bios -- mill added
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x71, (tmp & 0xFC) | VsyncBits);

		SMI_DisableMmio (pScrn);
		xf86ExecX86int10 (pSmi->pInt10);

		/* Enable linear mode. */
		tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18);
		VGAOUT8(pSmi, VGA_SEQ_DATA, tmp | 0x01);

		/* Enable DPR/VPR registers. */
		tmp = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03);


		//////////////////////////////////mill added
		xf86FreeInt10 (pSmi->pInt10);
		pSmi->pInt10 = NULL;
	}

	//old code
	/* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */
	if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR))
	{
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66, restore->CCR66);
	}
	/* end CZ */

	VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C, restore->SR6C);
	VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D, restore->SR6D);
	VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, 0x00);

	WRITE_DPR (pSmi, 0x10, restore->DPR10);
	WRITE_DPR (pSmi, 0x1C, restore->DPR1C);
	WRITE_DPR (pSmi, 0x20, restore->DPR20);
	WRITE_DPR (pSmi, 0x24, restore->DPR24);
	WRITE_DPR (pSmi, 0x28, restore->DPR28);
	WRITE_DPR (pSmi, 0x2C, restore->DPR2C);
	WRITE_DPR (pSmi, 0x30, restore->DPR30);
	WRITE_DPR (pSmi, 0x3C, restore->DPR3C);
	WRITE_DPR (pSmi, 0x40, restore->DPR40);
	WRITE_DPR (pSmi, 0x44, restore->DPR44);

	WRITE_VPR (pSmi, 0x00, restore->VPR00);
	WRITE_VPR (pSmi, 0x0C, restore->VPR0C);
	WRITE_VPR (pSmi, 0x10, restore->VPR10);

	if (pSmi->Chipset == SMI_COUGAR3DR)
	{
		WRITE_FPR (pSmi, FPR00, restore->FPR00_);
		WRITE_FPR (pSmi, FPR0C, restore->FPR0C_);
		WRITE_FPR (pSmi, FPR10, restore->FPR10_);
	}

	WRITE_CPR (pSmi, 0x00, restore->CPR00);


	//old code 
	if (xf86GetVerbosity () > 1)
	{
		xf86DrvMsgVerb (pScrn->scrnIndex, X_INFO, VERBLEV,
				"Done restoring mode.  Register dump:\n");
		SMI_PrintRegs (pScrn);
	}

	vgaHWProtect (pScrn, FALSE);

	LEAVE_PROC ("SMI_BiosWriteMode");


}
/*
 * This function is used to restore a video mode. It writes out all of the
 * standard VGA and extended registers needed to setup a video mode.
 */

	static void
SMI_WriteMode (ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr, SMIRegPtr restore)
{
	int i;
	CARD8 tmp;
	CARD32 offset;

	vgaHWPtr hwp = VGAHWPTR (pScrn);
	SMIPtr pSmi = SMIPTR (pScrn);
	int vgaIOBase = hwp->IOBase;
	int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
	int vgaCRData = vgaIOBase + VGA_CRTC_DATA_OFFSET;

	ENTER_PROC ("SMI_WriteMode");

	vgaHWProtect (pScrn, TRUE);

	/* Wait for engine to become idle */
	WaitIdle ();


	if (pSmi->useBIOS && (pSmi->pInt10 != NULL) && (restore->mode != 0))
	{
		pSmi->pInt10->num = 0x10;
		pSmi->pInt10->ax = restore->mode | 0x80;
		xf86DrvMsg (pScrn->scrnIndex, X_INFO, "Setting mode 0x%02X\n",
				restore->mode);

		SMI_DisableMmio (pScrn);
		xf86ExecX86int10 (pSmi->pInt10);

		/* Enable linear mode. */
		tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18);
		VGAOUT8(pSmi, VGA_SEQ_DATA, tmp | 0x01);

		/* Enable DPR/VPR registers. */
		tmp = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03);
	}
	else
	{

		xf86DrvMsg (pScrn->scrnIndex, X_INFO, " Restore mode 0x%02X\n",
				restore->mode);

		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17, restore->SR17);

		tmp = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18) & ~0x1F;
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18, tmp | (restore->SR18 & 0x1F) | 0x11);

		tmp = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
		/* changed by Belcon to enable CRT output */
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03 & ~0x80);


		tmp = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31) & ~0xC0;
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, tmp |
				(restore->SR31 & 0xC0));
		tmp = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32) & ~0x07;
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32, tmp |
				(restore->SR32 & 0x07));
		if (restore->SR6B != 0xFF)
		{
			VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A,
					restore->SR6A);
			VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B,
					restore->SR6B);
		}
		xf86DrvMsg (pScrn->scrnIndex, X_INFO, " Mode Pclock 0x%02X 0x%02X\n",
				restore->SR6C, restore->SR6D);
		/*boyod add */
		if (restore->SR6D != 0x0)
		{
			VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C,
					restore->SR6C);
			VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D,
					restore->SR6D);
		}


		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, restore->SR81);
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0, restore->SRA0);

		/* Restore the standard VGA registers */
		SMI_vgaHWRestore (pSmi, (SMI_vgaRegPtr)vgaSavePtr, VGA_SR_ALL);
		if (restore->smiDACMask)
		{
			VGAOUT8 (pSmi, VGA_DAC_MASK, restore->smiDACMask);
		}
		else
		{
			VGAOUT8 (pSmi, VGA_DAC_MASK, 0xFF);
		}
		VGAOUT8 (pSmi, VGA_DAC_WRITE_ADDR, 0);
		for (i = 0; i < 256; i++)
		{
			VGAOUT8 (pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][0]);
			VGAOUT8 (pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][1]);
			VGAOUT8 (pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][2]);
		}
		for (i = 0, offset = 2; i < 8192; i++, offset += 8)
		{
			*(pSmi->FBBase + offset) = restore->smiFont[i];
		}

		if (SMI_LYNXM_SERIES (pSmi->Chipset))
		{
			/*
			 * FIXME:: hardcode here
			 */

			/* Restore secondary registers */
			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x9E,
					restore->CR90[14] | 0x20);

			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x30, restore->CR30);
			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33_2);

			for (i = 0; i < 14; i++)
			{
				VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x40 + i,
						restore->CR40_2[i]);
			}
			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x9F, restore->CR9F_2);

			/* Restore primary registers */
			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x9E,
					restore->CR90[14] & ~0x20);

			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33);
			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x3A, restore->CR3A);
			for (i = 0; i < 14; i++)
			{
				VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x40 + i,
						restore->CR40[i]);
			}

			for (i = 0; i < 16; i++)
			{
				if (i != 14)
				{
					VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x90 + i,
							restore->CR90[i]);
				}

			}
			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x9E,
					restore->CR90[14]);

			/* Restore common registers */
			for (i = 0; i < 14; i++)
			{
				VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0xA0 + i,
						restore->CRA0[i]);
			}
		}

		/* Restore the standard VGA registers */
		if (xf86IsPrimaryPci (pSmi->PciInfo))
		{
			SMI_vgaHWRestore (pSmi, (SMI_vgaRegPtr)vgaSavePtr, VGA_SR_CMAP | VGA_SR_FONTS);
		}

		if (restore->modeInit) {
			SMI_vgaHWRestore (pSmi, (SMI_vgaRegPtr)vgaSavePtr, VGA_SR_ALL);
		}

		if (!SMI_LYNXM_SERIES (pSmi->Chipset))
		{
			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x30, restore->CR30);
			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33);
			VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x3A, restore->CR3A);
			for (i = 0; i < 14; i++)
			{
				VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x40 + i,
						restore->CR40[i]);
			}
		}
	}

	/* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */
	if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR))
	{
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66, restore->CCR66);
	}
	/* end CZ */

	VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, 0x00);

	WRITE_DPR (pSmi, 0x10, restore->DPR10);
	WRITE_DPR (pSmi, 0x1C, restore->DPR1C);
	WRITE_DPR (pSmi, 0x20, restore->DPR20);
	WRITE_DPR (pSmi, 0x24, restore->DPR24);
	WRITE_DPR (pSmi, 0x28, restore->DPR28);
	WRITE_DPR (pSmi, 0x2C, restore->DPR2C);
	WRITE_DPR (pSmi, 0x30, restore->DPR30);
	WRITE_DPR (pSmi, 0x3C, restore->DPR3C);
	WRITE_DPR (pSmi, 0x40, restore->DPR40);
	WRITE_DPR (pSmi, 0x44, restore->DPR44);

	WRITE_VPR (pSmi, 0x00, restore->VPR00);
	WRITE_VPR (pSmi, 0x0C, restore->VPR0C);
	WRITE_VPR (pSmi, 0x10, restore->VPR10);

	if (pSmi->Chipset == SMI_COUGAR3DR)
	{
		WRITE_FPR (pSmi, FPR00, restore->FPR00_);
		WRITE_FPR (pSmi, FPR0C, restore->FPR0C_);
		WRITE_FPR (pSmi, FPR10, restore->FPR10_);
	}

	WRITE_CPR (pSmi, 0x00, restore->CPR00);




#ifdef  _EXPERIMENTAL_XSERVER64	/*  IGXMAL -- Manage Simultaneous (virtual refresh) mode */
	{

		/* Get Hres, Vres for this mode */
		int iHres;
		int iVres;

		if (restore->mode >= 0x65)
		{
			iHres = 1280;
			iVres = 1024;
		}
		else if (restore->mode >= 0x60)
		{
			iHres = 1024;
			iVres = 768;
		}
		else if ((restore->mode >= 0x50) && (restore->mode <= 0x54))
		{
			iHres = 640;
			iVres = 480;
		}
		else
		{
			iHres = 800;
			iVres = 600;
		}

		if (restore->mode > 0)
		{
			int iVertAdjust;
			int iHorzAdjust;

			/*boyod */
			/* Set VR bit for hi-res modes */
			tmp = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31) & ~0x07;
			VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, tmp | 0x80);

			/* Handle centering here */
			/* If (res < panelsize) then set 3d4.9e and 3d4.a6 */
			if ((iHres < pSmi->lcdWidth) || (iVres < pSmi->lcdHeight))
			{
				tmp = VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x9E);
				VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0x9E, 0x00);

				iVertAdjust = min (63, (pSmi->lcdHeight - iVres) / 2 / 4);
				iHorzAdjust = min (127, (pSmi->lcdWidth - iHres) / 2 / 8);

				VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0xA7, iHorzAdjust);
				VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, 0xA6, iVertAdjust);
			}
		}
		else
		{
			/* Clear virtual refresh bit for text modes */
			tmp = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31) & ~0x80;
			VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, tmp);
		}
	}
#endif

	if (xf86GetVerbosity () > 1)
	{
		xf86DrvMsgVerb (pScrn->scrnIndex, X_INFO, VERBLEV,
				"Done restoring mode.  Register dump:\n");
		SMI_PrintRegs (pScrn);
	}

	vgaHWProtect (pScrn, FALSE);

	LEAVE_PROC ("SMI_WriteMode");
}

	static Bool
SMI_MapMem (ScrnInfoPtr pScrn)
{
	SMIPtr pSmi = SMIPTR (pScrn);
	vgaHWPtr hwp;
	int	ret;

	ENTER_PROC ("SMI_MapMem");
	switch (pSmi->Chipset)
	{
		default:
			ret = smi_mapmemory(pScrn, pSmi);
			break;

		case SMI_COUGAR3DR:
			ret = smi_mapmemory_730(pScrn, pSmi);
			break;

		case SMI_LYNX3D:
			ret = smi_mapmemory_820(pScrn, pSmi);
			break;

		case SMI_LYNXEM:
		case SMI_LYNXEMplus:
			ret = smi_mapmemory_712(pScrn, pSmi);
			break;

		case SMI_LYNX3DM:
			ret = smi_mapmemory_720(pScrn, pSmi);
			break;

		case SMI_MSOC:
			ret = smi_mapmemory_501(pScrn, pSmi);
			break;
	}
	if (ret == FALSE)
		return (ret);

	xf86DrvMsg (pScrn->scrnIndex, X_INFO, "%s Panel Size = %dx%d\n",
			(pSmi->lcd == 0) ? "OFF" : (pSmi->lcd == 1) ? "TFT" : "DSTN",
			pSmi->lcdWidth, pSmi->lcdHeight);
	xf86DrvMsg (pScrn->scrnIndex, X_INFO, " SiliconMotion Driver\n");

	if (SMI_MSOC != pSmi->Chipset)	/* 501?  No VGA!  */
	{
		/* Assign hwp->MemBase & IOBase here */
		hwp = VGAHWPTR (pScrn);
		if (pSmi->IOBase != NULL)
		{
			vgaHWSetMmioFuncs (hwp, pSmi->MapBase,
					pSmi->IOBase - pSmi->MapBase);
		}
		vgaHWGetIOBase (hwp);

		/* Map the VGA memory when the primary video */
		if (xf86IsPrimaryPci (pSmi->PciInfo))
		{
			hwp->MapSize = 0x10000;
			if (!vgaHWMapMem (pScrn))
			{
				LEAVE_PROC ("SMI_MapMem");
				return (FALSE);
			}
			pSmi->PrimaryVidMapped = TRUE;
		}
	}

	LEAVE_PROC ("SMI_MapMem");
	return (TRUE);
}

/* UnMapMem - contains half of pre-4.0 EnterLeave function.  The EnterLeave
 * function which en/disable access to IO ports and ext. regs
 */

	static void
SMI_UnmapMem (ScrnInfoPtr pScrn)
{
	SMIPtr pSmi = SMIPTR (pScrn);

	ENTER_PROC ("SMI_UnmapMem");

	/* Unmap VGA mem if mapped. */
	if (pSmi->PrimaryVidMapped)
	{
		vgaHWUnmapMem (pScrn);
		pSmi->PrimaryVidMapped = FALSE;
	}

	SMI_DisableMmio (pScrn);

	xf86UnMapVidMem (pScrn->scrnIndex, (pointer) pSmi->MapBase, pSmi->MapSize);
	if (pSmi->FBBase != NULL)
	{
		xf86UnMapVidMem (pScrn->scrnIndex, (pointer) pSmi->FBBase,
				pSmi->videoRAMBytes);
	}
	pSmi->IOBase = NULL;

	LEAVE_PROC ("SMI_UnmapMem");
}

/* This gets called at the start of each server generation. */

	static Bool
SMI_ScreenInit (int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
{
	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
	SMIPtr pSmi = SMIPTR (pScrn);
	EntityInfoPtr pEnt;

	ENTER_PROC ("SMI_ScreenInit");

	/* Map MMIO regs and framebuffer */
	if (!SMI_MapMem (pScrn))
	{
		LEAVE_PROC ("SMI_ScreenInit");
		return (FALSE);
	}

	pEnt = xf86GetEntityInfo (pScrn->entityList[0]);

#ifdef _XSERVER64
	if (!pSmi->pInt10 && !(SMI_MSOC == pSmi->Chipset))
	{
		pSmi->pInt10 = xf86InitInt10 (pEnt->index);
	}
#endif

	/* Save the chip/graphics state */
	SMI_Save (pScrn);

	/* Zero the frame buffer, #258 */
	memset (pSmi->FBBase, 0, pSmi->videoRAMBytes);

	/* Initialize the first mode */
	xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "lcdWidth = %d\n", pSmi->lcdWidth);
	if (!SMI_ModeInit (pScrn, pScrn->currentMode))
	{
		LEAVE_PROC ("SMI_ScreenInit");
		return (FALSE);
	}

	/*
	 * The next step is to setup the screen's visuals, and initialise the
	 * framebuffer code.  In cases where the framebuffer's default choises for
	 * things like visual layouts and bits per RGB are OK, this may be as simple
	 * as calling the framebuffer's ScreenInit() function.  If not, the visuals
	 * will need to be setup before calling a fb ScreenInit() function and fixed
	 * up after.
	 *
	 * For most PC hardware at depths >= 8, the defaults that cfb uses are not
	 * appropriate.  In this driver, we fixup the visuals after.
	 */

	/*
	 * Reset the visual list.
	 */
	miClearVisualTypes ();

	/* Setup the visuals we support. */

	/*
	 * For bpp > 8, the default visuals are not acceptable because we only
	 * support TrueColor and not DirectColor.  To deal with this, call
	 * miSetVisualTypes with the appropriate visual mask.
	 */

	if (!miSetVisualTypes (pScrn->depth, TrueColorMask, pScrn->rgbBits,
				pScrn->defaultVisual))
	{
		LEAVE_PROC ("SMI_ScreenInit");
		return (FALSE);
	}
	if (!miSetPixmapDepths ())
	{
		LEAVE_PROC ("SMI_ScreenInit");
		return FALSE;
	}

	if (!SMI_InternalScreenInit (scrnIndex, pScreen))
	{
		LEAVE_PROC ("SMI_ScreenInit");
		return (FALSE);
	}

	xf86SetBlackWhitePixels (pScreen);

	if (pScrn->bitsPerPixel > 8)
	{
		VisualPtr visual;
		/* Fixup RGB ordering */
		visual = pScreen->visuals + pScreen->numVisuals;
		while (--visual >= pScreen->visuals)
		{
			if ((visual->class | DynamicClass) == DirectColor)
			{
				visual->offsetRed = pScrn->offset.red;
				visual->offsetGreen = pScrn->offset.green;
				visual->offsetBlue = pScrn->offset.blue;
				visual->redMask = pScrn->mask.red;
				visual->greenMask = pScrn->mask.green;
				visual->blueMask = pScrn->mask.blue;
			}
		}
	}

	/* must be after RGB ordering fixed */

	fbPictureInit (pScreen, 0, 0);

/* CZ 18.06.2001: moved here from smi_accel.c to have offscreen
   framebuffer in NoAccel mode */
	{
		int numLines, maxLines;
		BoxRec AvailFBArea;

		maxLines = pSmi->FBReserved / (pScrn->displayWidth * pSmi->Bpp);
		if (pSmi->rotate)
		{
			numLines = maxLines;
		}
		else
		{
			/* CZ 3.11.2001: What does the following code? see also smi_video.c aaa line 1226 */
			numLines = maxLines;
		}

		AvailFBArea.x1 = 0;
		AvailFBArea.y1 = 0;
		AvailFBArea.x2 = (pSmi->width + 15) & ~15;;
		AvailFBArea.y2 = numLines;
		xf86DrvMsg (pScrn->scrnIndex, X_INFO,
				"FrameBuffer Box: %d,%d - %d,%d\n",
				AvailFBArea.x1, AvailFBArea.y1, AvailFBArea.x2,
				AvailFBArea.y2);

		xf86InitFBManager (pScreen, &AvailFBArea);

	}
/* end CZ */

	/* Initialize acceleration layer */
	if (!pSmi->NoAccel)
	{
		if (!SMI_AccelInit (pScreen))
		{
			LEAVE_PROC ("SMI_ScreenInit");
			return (FALSE);
		}
	}

	miInitializeBackingStore (pScreen);

	/* hardware cursor needs to wrap this layer */

	SMI_DGAInit (pScreen);

	/* Initialise cursor functions */
	miDCInitialize (pScreen, xf86GetPointerScreenFuncs ());

	/* Initialize HW cursor layer.  Must follow software cursor
	 * initialization.
	 */
	if (pSmi->hwcursor)
	{
		if (!SMI_HWCursorInit (pScreen))
		{
			xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "Hardware cursor "
					"initialization failed\n");
		}
	}

	if (pSmi->shadowFB)
	{
		Bool bRetCode;

		RefreshAreaFuncPtr refreshArea;

		if (pSmi->Chipset == SMI_COUGAR3DR)
		{
			refreshArea = SMI_RefreshArea730;
		}
		else
		{
			refreshArea = SMI_RefreshArea;
		}


		if (pSmi->rotate || pSmi->RandRRotation) //caesar modify
		{
			if (pSmi->PointerMoved == NULL)
			{
				pSmi->PointerMoved = pScrn->PointerMoved;
				pScrn->PointerMoved = SMI_PointerMoved;
			}
			xf86DisableRandR();
		}

		bRetCode = ShadowFBInit (pScreen, refreshArea);
	}

	/* Initialise default colormap */
	if (!miCreateDefColormap (pScreen))
	{
		LEAVE_PROC ("SMI_ScreenInit");
		return (FALSE);
	}

	/* Initialize colormap layer.  Must follow initialization of the default
	 * colormap.  And SetGamma call, else it will load palette with solid white.
	 */
	/* CZ 2.11.2001: CMAP_PALETTED_TRUECOLOR for gamma correction */
	if (!xf86HandleColormaps
			(pScreen, 256, pScrn->rgbBits, SMI_LoadPalette, NULL,
			 CMAP_RELOAD_ON_MODE_SWITCH | CMAP_PALETTED_TRUECOLOR))
	{
		LEAVE_PROC ("SMI_ScreenInit");
		return (FALSE);
	}

	pScreen->SaveScreen = SMI_SaveScreen;
	pSmi->CloseScreen = pScreen->CloseScreen;
	pScreen->CloseScreen = SMI_CloseScreen;

	/* Added by Belcon to enable LCD Panel Control Select */
	if (pSmi->Chipset == SMI_LYNXEMplus)
	{
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22, 2);
	}

	if (!xf86DPMSInit (pScreen, SMI_DisplayPowerManagementSet, 0))
	{
		xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "DPMS initialization failed!\n");
	}

	SMI_InitVideo (pScreen);

#ifdef RANDR
	/* Install our DriverFunc.  We have to do it this way instead of using the
	 * HaveDriverFuncs argument to xf86AddDriver, because InitOutput clobbers
	 * pScrn->DriverFunc */
	pScrn->DriverFunc = SMI_DriverFunc;
#endif
	/* Report any unused options (only for the first generation) */
	if (serverGeneration == 1)
	{
		xf86ShowUnusedOptions (pScrn->scrnIndex, pScrn->options);
	}

	LEAVE_PROC ("SMI_ScreenInit");
	{
		volatile CARD8	config;
		config = pciReadByte(pSmi->PciTag, PCI_CMD_STAT_REG);
		//  pciWriteByte(pSmi->PciTag, PCI_CMD_STAT_REG, config | PCI_CMD_MEM_ENABLE);

	}
	LEAVE_PROC ("SMI_ScreenInit");
	return (TRUE);
}

/* Common init routines needed in EnterVT and ScreenInit */

	static int
SMI_InternalScreenInit (int scrnIndex, ScreenPtr pScreen)
{
	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
	SMIPtr pSmi = SMIPTR (pScrn);
	int width, height, displayWidth;
	int bytesPerPixel = pScrn->bitsPerPixel / 8;
	int xDpi, yDpi;
	int ret;

	ENTER_PROC ("SMI_InternalScreenInit");

	if (pSmi->rotate && pSmi->rotate != SMI_ROTATE_UD)
	{
		width = pScrn->virtualY;
		height = pScrn->virtualX;
		xDpi = pScrn->yDpi;
		yDpi = pScrn->xDpi;
		displayWidth = ((width * bytesPerPixel + 15) & ~15) / bytesPerPixel;
	}
	else
	{
		width = pScrn->virtualX;
		height = pScrn->virtualY;
		xDpi = pScrn->xDpi;
		yDpi = pScrn->yDpi;
		displayWidth = pScrn->displayWidth;
	}

	if (pSmi->shadowFB)
	{
		pSmi->ShadowWidth = width;
		pSmi->ShadowHeight = height;
		pSmi->ShadowWidthBytes = ((width + 15) & ~15) * bytesPerPixel ;			
		if (bytesPerPixel == 3)
		{
			if(pSmi->rotate == SMI_ROTATE_CW || pSmi->rotate == SMI_ROTATE_CCW)	
			{
				pSmi->ShadowPitch = ((height * 3) << 16) | pSmi->ShadowWidthBytes;
			}
			else
			{
				pSmi->ShadowPitch = ((width * 3) << 16) | pSmi->ShadowWidthBytes;
			}
		}
		else
		{
			if(pSmi->rotate == SMI_ROTATE_CW || pSmi->rotate == SMI_ROTATE_CCW)	
			{
				pSmi->ShadowPitch = (((height + 15) & ~15)<< 16) |(pSmi->ShadowWidthBytes / bytesPerPixel);				
			}
			else
			{
				pSmi->ShadowPitch = (((width + 15) & ~15)<< 16) |(pSmi->ShadowWidthBytes / bytesPerPixel);	
			}
		}

		pSmi->saveBufferSize = pSmi->ShadowWidthBytes * pSmi->ShadowHeight;
		pSmi->FBReserved -= pSmi->saveBufferSize;
		pSmi->FBReserved &= ~0x15;
		WRITE_VPR (pSmi, 0x0C, (pSmi->FBOffset = pSmi->FBReserved) >> 3);

		if (pSmi->Chipset == SMI_COUGAR3DR)
		{
			WRITE_FPR (pSmi, FPR0C, pSmi->FBOffset >> 3);
		}


		if (SMI_MSOC == pSmi->Chipset)
		{
			if (!pSmi->IsSecondary) {
				WRITE_DCR (pSmi, DCR0C, pSmi->FBOffset);
			} else {
				WRITE_DCR (pSmi, DCR204, pSmi->FBOffset);
			}
		}

		pScrn->fbOffset = pSmi->FBOffset + pSmi->fbMapOffset;
		xf86DrvMsg (pScrn->scrnIndex, X_INFO, "Shadow: width=%d height=%d "
				"offset=0x%08X pitch=0x%08X\n", pSmi->ShadowWidth,
				pSmi->ShadowHeight, (unsigned int)pSmi->FBOffset, pSmi->ShadowPitch);
	}
	else
	{
		pSmi->FBOffset = 0;
		pScrn->fbOffset = pSmi->FBOffset + pSmi->fbMapOffset;
	}

	/*
	 * Call the framebuffer layer's ScreenInit function, and fill in other
	 * pScreen fields.
	 */


	DEBUG ((VERBLEV, "\tInitializing FB @ 0x%08X for %dx%d (%d)\n",
				pSmi->FBBase, width, height, displayWidth));
	switch (pScrn->bitsPerPixel)
	{
		case 8:
		case 16:
		case 24:
		case 32:

#ifdef XORG_VERSION_CURRENT
#if XORG_VERSION_CURRENT == XORG_VERSION_NUMERIC(1,3,0,0,0)
			if (SMI_MSOC != pSmi->Chipset && pScrn->bitsPerPixel == 32)
				ret = fbScreenInit (pScreen, pSmi->FBBase, width, height, xDpi,
						yDpi, displayWidth, pScrn->bitsPerPixel);
#endif
#endif
			if ((SMI_MSOC == pSmi->Chipset && pScrn->bitsPerPixel != 24) ||
					(SMI_MSOC != pSmi->Chipset && pScrn->bitsPerPixel != 32))

			{
				ret = fbScreenInit (pScreen, pSmi->FBBase, width, height, xDpi,
						yDpi, displayWidth, pScrn->bitsPerPixel);
			}
			break;

		default:
			xf86DrvMsg (scrnIndex, X_ERROR, "Internal error: invalid bpp (%d) "
					"in SMI_InternalScreenInit\n", pScrn->bitsPerPixel);
			LEAVE_PROC ("SMI_InternalScreenInit");
			return (FALSE);
	}

	if ((SMI_MSOC == pSmi->Chipset) && (pScrn->bitsPerPixel == 8))
	{
		/* Initialize Palette entries 0 and 1, they don't seem to get hit */
		if (!pSmi->IsSecondary)
		{
			WRITE_DCR (pSmi, DCR400 + 0, 0x00000000);	/* CRT Palette       */
			WRITE_DCR (pSmi, DCR400 + 4, 0x00FFFFFF);	/* CRT Palette       */
		}
		else
		{
			WRITE_DCR (pSmi, DCR800 + 0, 0x00000000);	/* Panel Palette */
			WRITE_DCR (pSmi, DCR800 + 4, 0x00FFFFFF);	/* Panel Palette */
		}

	}

	LEAVE_PROC ("SMI_InternalScreenInit");
	return (ret);
}

/* Checks if a mode is suitable for the selected configuration. */
	static ModeStatus
SMI_ValidMode (int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
{
	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
	SMIPtr pSmi = SMIPTR (pScrn);
	float refresh;

	ENTER_PROC ("SMI_ValidMode");
	refresh = (mode->VRefresh > 0) ? mode->VRefresh
		: mode->Clock * 1000.0 / mode->VTotal / mode->HTotal;
	xf86DrvMsg (scrnIndex, X_INFO, " Mode: %dx%d %d-bpp, %fHz\n",
			mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel, refresh);

	if (pSmi->shadowFB)
	{
		int mem;

		/*		if (pScrn->bitsPerPixel > 16)
				{
				LEAVE_PROC("SMI_ValidMode");
				return(MODE_BAD);
				}
				*/
		mem = (pScrn->virtualX * pScrn->bitsPerPixel / 8 + 15) & ~15;
		mem *= pScrn->virtualY * 2;

		if (mem > pSmi->FBReserved)	/* PDR#1074 */
		{
			LEAVE_PROC ("SMI_ValidMode");
			return (MODE_MEM);
		}
	}

	// Mode added by Belcon according new mode table
	if (!(((mode->HDisplay == 1280) && (mode->VDisplay == 1024)) ||
				((mode->HDisplay == 1024) && (mode->VDisplay == 768)) ||
				((mode->HDisplay == 800) && (mode->VDisplay == 600)) ||
				((mode->HDisplay == 640) && (mode->VDisplay == 480)) ||
				((mode->HDisplay == 320) && (mode->VDisplay == 240)) ||
				((mode->HDisplay == 400) && (mode->VDisplay == 300)) ||
				((mode->HDisplay == 1280) && (mode->VDisplay == 960)) ||
				((mode->HDisplay == 1280) && (mode->VDisplay == 768)) ||
				((mode->HDisplay == 1366) && (mode->VDisplay == 768)) ||
				((mode->HDisplay == 1024) && (mode->VDisplay == 600)) ||
				((mode->HDisplay == 800) && (mode->VDisplay == 480)) ||
				((mode->HDisplay == 720) && (mode->VDisplay == 540)) ||
				((mode->HDisplay == 720) && (mode->VDisplay == 480))))
	{
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "HDisplay %d, VDisplay %d\n", mode->HDisplay, mode->VDisplay);
		return (MODE_BAD_WIDTH);
	}


#if 1				/* PDR#944 */
	if ((pSmi->rotate && pSmi->rotate != SMI_ROTATE_UD) && (SMI_MSOC != pSmi->Chipset))
	{
		if ((mode->HDisplay != pSmi->lcdWidth)
				|| (mode->VDisplay != pSmi->lcdHeight))
		{
			LEAVE_PROC ("SMI_ValidMode");
			return (MODE_PANEL);
		}
	}
#endif

	LEAVE_PROC ("SMI_ValidMode");
	return (MODE_OK);
}
static void SMI_SaveReg(ScrnInfoPtr pScrn )
{
	int i;
	vgaHWPtr hwp = VGAHWPTR (pScrn);
	SMIPtr pSmi = SMIPTR (pScrn);
	int vgaIOBase = hwp->IOBase;
	int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
	int vgaCRData = vgaIOBase + VGA_CRTC_DATA_OFFSET;
	ENTER_PROC ("SMI_SaveReg");

	/*save seq registers*/
	for(i = 0; i < (sizeof(SeqTable) / sizeof(unsigned char)); i++)
	{
		SeqTable[i] = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, i);	
	}

	/*save crt registers*/
	for(i = 0; i < (sizeof(CrtTable) / sizeof(unsigned char)); i++)
	{
		CrtTable[i] = VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRData, i);
	}

	/*save dpr registers*/
	for(i = 0; i < (sizeof(DprTable) / sizeof(unsigned int)); i++)
	{
		DprTable[i] = READ_DPR(pSmi, DprIndexTable[i]);
	}
	for(i = 0; i < (sizeof(VprTable) / sizeof(unsigned int)); i++)
	{
		VprTable[i] = READ_VPR(pSmi, VprIndexTable[i]);
	}

	LEAVE_PROC ("SMI_SaveReg");
	return;
}

static void SMI_RestoreReg(ScrnInfoPtr pScrn )
{
	int i;
	vgaHWPtr hwp = VGAHWPTR (pScrn);
	SMIPtr pSmi = SMIPTR (pScrn);
	int vgaIOBase = hwp->IOBase;
	int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
	int vgaCRData = vgaIOBase + VGA_CRTC_DATA_OFFSET;
	ENTER_PROC ("SMI_RestoreReg");

	/*restore seq registers*/
	for(i = 0; i < (sizeof(SeqTable) / sizeof(unsigned char)); i++)
	{
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, i, SeqTable[i]);	
	}

	/*restore crt registers*/
	for(i = 0; i < (sizeof(CrtTable) / sizeof(unsigned char)); i++)
	{	
		VGAOUT8_INDEX (pSmi, vgaCRIndex, vgaCRData, i, CrtTable[i]);	
	}

	/*restore dpr registers*/
	for(i = 0; i < (sizeof(DprTable) / sizeof(unsigned int)); i++)
	{
		WRITE_DPR(pSmi, DprIndexTable[i], DprTable[i]); 
	}
	for(i = 0; i < (sizeof(VprTable) / sizeof(unsigned int)); i++)
	{
		WRITE_VPR(pSmi, VprIndexTable[i], VprTable[i]); 
	}

	LEAVE_PROC ("SMI_RestoreReg");
	return;
}

	static Bool
SMI_ModeInit (ScrnInfoPtr pScrn, DisplayModePtr mode)
{
	vgaHWPtr hwp = VGAHWPTR (pScrn);
	SMIPtr pSmi = SMIPTR (pScrn);
	unsigned char tmp;
	int panelIndex, modeIndex, i;
	int xyAddress[] = { 320, 400, 512, 640, 800, 1024, 1280, 1600, 2048 };
	CARD32 DEDataFormat = 0;

	/* Store values to current mode register structs */
	SMIRegPtr new = &pSmi->ModeReg;
	vgaRegPtr vganew = &hwp->ModeReg;

	ENTER_PROC ("SMI_ModeInit");

	if (SMI_MSOC == pSmi->Chipset)
	{
		pSmi->Bpp = pScrn->bitsPerPixel / 8;


		if (pSmi->rotate && pSmi->rotate != SMI_ROTATE_UD)
		{
			pSmi->width = pScrn->virtualY;
			pSmi->height = pScrn->virtualX;
			pSmi->Stride = (pSmi->height * pSmi->Bpp + 15) & ~15;
		}
		else
		{
			pSmi->width = pScrn->virtualX;
			pSmi->height = pScrn->virtualY;
			pSmi->Stride = (pSmi->width * pSmi->Bpp + 15) & ~15;
		}



		/* Set mode on Voyager */
		SMI_MSOCSetMode (pScrn, mode);

		/* Adjust the viewport */
		SMI_AdjustFrame (pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);

		SMI_PrintRegs (pScrn);

		LEAVE_PROC ("SMI_ModeInit");
		return (TRUE);
	}

	if (!vgaHWInit (pScrn, mode))
	{
		LEAVE_PROC ("SMI_ModeInit");
		return (FALSE);
	}

	new->modeInit = TRUE;

	if (pSmi->rotate && pSmi->rotate != SMI_ROTATE_UD)
	{
		pSmi->width = pScrn->virtualY;
		pSmi->height = pScrn->virtualX;
	}
	else
	{
		pSmi->width = pScrn->virtualX;
		pSmi->height = pScrn->virtualY;
	}


	pSmi->Bpp = pScrn->bitsPerPixel / 8;

	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17);

	if (pSmi->pci_burst)
	{
		new->SR17 = tmp | 0x20;
	}
	else
	{
		new->SR17 = tmp & ~0x20;
	}

	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18);
	new->SR18 = tmp | 0x11;

	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
	new->SR21 = tmp & ~0x03;

	if (pSmi->Chipset != SMI_COUGAR3DR)
	{
		new->SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31) & 0xC0;

		new->SR32 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32) & ~0x07;

		if (SMI_LYNXM_SERIES (pSmi->Chipset))
		{
			new->SR32 |= 0x04;
		}
	}

	new->SRA0 = new->CR33 = new->CR3A = 0x00;

	xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "lcdWidth = %d HDisplay = %d\n",
			pSmi->lcdWidth, mode->HDisplay);

	/*boyod*/

	if (pSmi->lcdWidth == 640)
	{
		panelIndex = 0;
	}
	else if (pSmi->lcdWidth == 800)
	{
		panelIndex = 1;
	}
	else if (pSmi->lcdWidth == 1024)
	{
		panelIndex = 2;
	}
	else
	{
		panelIndex = 3;
	}



	if (mode->HDisplay == 640)
	{
		modeIndex = 0;
	}
	else if (mode->HDisplay == 800)
	{
		if (mode->VDisplay == 480)
			modeIndex = 1;
		else
			modeIndex = 2;
	}
	else if (mode->HDisplay == 1024)
	{
		modeIndex = 3;
	}
	else
	{
		modeIndex = 4;
	}

	xf86DrvMsg (pScrn->scrnIndex, X_INFO, "HDisplay %d, VDisplay %d\n",
			mode->HDisplay, mode->VDisplay);
	xf86DrvMsg (pScrn->scrnIndex, X_INFO, "panelIndex = %d modeIndex = %d\n",
			panelIndex, modeIndex);
	if (SMI_LYNXM_SERIES (pSmi->Chipset))
#ifdef LCD_SIZE_DETECT
	{
		static unsigned char PanelTable[4][16] = {
			/*              640x480         */
			{0x5F, 0x4F, 0x00, 0x52, 0x1E, 0x0B, 0xDF, 0x00, 0xE9, 0x0B, 0x2E,
				0x00, 0x4F, 0xDF, 0x07, 0x82},
			/*              8000x600                */
			{0x7F, 0x63, 0x00, 0x69, 0x19, 0x72, 0x57, 0x00, 0x58, 0x0C, 0xA2,
				0x20, 0x4F, 0xDF, 0x1C, 0x85},
			/*              1024x768                */
			{0xA3, 0x7F, 0x00, 0x83, 0x14, 0x24, 0xFF, 0x00, 0x02, 0x08, 0xA7,
				0xE0, 0x4F, 0xDF, 0x52, 0x89},
			/*              other           */
			{0xCE, 0x9F, 0x00, 0xA7, 0x15, 0x28, 0xFF, 0x28, 0x00, 0xA3, 0x5A,
				0x20, 0x9F, 0xFF, 0x53, 0x0B},
		};
		xf86DrvMsg (pScrn->scrnIndex, X_INFO, "LCD_SIZE_DETECT\n");

		for (i = 0; i < 14; i++)
		{
			new->CR40[i] = PanelTable[panelIndex][i];
		}
		new->SR6C = PanelTable[panelIndex][14];
		new->SR6D = PanelTable[panelIndex][15];


		if (panelIndex == 3)
		{
			new->CR90[14] = 0x18;
		}
		else
		{
			new->CR90[14] = 0x00;
		}

		if (mode->VDisplay < pSmi->lcdHeight)
		{
			new->CRA0[6] = (pSmi->lcdHeight - mode->VDisplay) / 8;
		}
		else
		{
			new->CRA0[6] = 0;
		}

		if (mode->HDisplay < pSmi->lcdWidth)
		{
			new->CRA0[7] = (pSmi->lcdWidth - mode->HDisplay) / 16;
		}
		else
		{
			new->CRA0[7] = 0;
		}
	}
	else
#else

	{
		/*
		 * Belcon Added
		 */
		/*
		   if (pSmi->lcdWidth == 0) {
		   */
		static unsigned char ModeTable[5][3][16] = {
			/* 640x480 */
			{
				/* 60 Hz */
				{
					0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
					0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, 0x07, 0x82,
				},
				/* 75 Hz */
				{
					0x64, 0x4F, 0x00, 0x52, 0x1A, 0xF2, 0xDF, 0x00,
					0xE0, 0x03, 0x0F, 0xC0, 0x4F, 0xDF, 0x16, 0x85,
				},
				/* 85 Hz */
				{
					0x63, 0x4F, 0x00, 0x57, 0x1E, 0xFB, 0xDF, 0x00,
					0xE0, 0x03, 0x0F, 0xC0, 0x4F, 0xDF, 0x88, 0x9B,
				},
			},

			/* 800x480 */
			{
				/* 60 Hz */
				{
					0x6B, 0x63, 0x00, 0x69, 0x1B, 0xF2, 0xDF, 0x00,
					0xE2, 0xE4, 0x1F, 0xC0, 0x63, 0xDF, 0x2C, 0x17,
				},
				/* 75 Hz */
				{
					0x6B, 0x63, 0x00, 0x69, 0x1B, 0xF2, 0xDF, 0x00,
					0xE2, 0xE4, 0x1F, 0xC0, 0x63, 0xDF, 0x2C, 0x17,
				},
				/* 85 Hz */
				{
					0x6B, 0x63, 0x00, 0x69, 0x1B, 0xF2, 0xDF, 0x00,
					0xE2, 0xE4, 0x1F, 0xC0, 0x63, 0xDF, 0x2C, 0x17,
				},
			},

			/* 800x600 */
			{
				/* 60 Hz */
				{
					0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
					0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, 0x1C, 0x85,
				},
				/* 75 Hz */
				{
					0x7F, 0x63, 0x00, 0x66, 0x10, 0x6F, 0x57, 0x00,
					0x58, 0x0B, 0xE0, 0x20, 0x63, 0x57, 0x4C, 0x8B,
				},
				/* 85 Hz */
				{
					0x7E, 0x63, 0x00, 0x68, 0x10, 0x75, 0x57, 0x00,
					0x58, 0x0B, 0xE0, 0x20, 0x63, 0x57, 0x37, 0x87,
				},
			},

			/* 1024x768 */
			{
				/* 60 Hz */
				{
					0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
#ifdef	FIXUP_89INCH_BUG
					0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, 0x0e, 0x82, //Teddy modify for 1024x600
#else
					0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, 0x52, 0x89,
#endif
				},
				/* 75 Hz */
				{
					0x9F, 0x7F, 0x00, 0x82, 0x0E, 0x1E, 0xFF, 0x00,
					0x00, 0x03, 0xE5, 0x20, 0x7F, 0xFF, 0x0B, 0x02,
				},
				/* 85 Hz */
				{
					0xA7, 0x7F, 0x00, 0x86, 0x12, 0x26, 0xFF, 0x00,
					0x00, 0x03, 0xE5, 0x20, 0x7F, 0xFF, 0x70, 0x11,
				},
			},

			/* 1280x1024 */
			{
				/* 60 Hz */
				{
					0xCE, 0x9F, 0x00, 0xA7, 0x15, 0x28, 0xFF, 0x00,
					0x00, 0x03, 0x4A, 0x20, 0x9F, 0xFF, 0x53, 0x0B,
				},
				/* 75 Hz */
				{
					0xCE, 0x9F, 0x00, 0xA2, 0x14, 0x28, 0xFF, 0x00,
					0x00, 0x03, 0x4A, 0x20, 0x9F, 0xFF, 0x42, 0x07,           
				},
				/* 85 Hz */
				{
					0xD3, 0x9F, 0x00, 0xA8, 0x1C, 0x2E, 0xFF, 0x00,
					0x00, 0x03, 0x4A, 0x20, 0x9F, 0xFF, 0x0b, 0x01,           
				},
			},
		};
		int	refresh_rate_index = -1;

		if (abs(mode->VRefresh - 60.0) < 5) {
			refresh_rate_index = 0;
		} else if (abs(mode->VRefresh - 75.0) < 5 ){
			refresh_rate_index = 1;
		} else if (abs(mode->VRefresh - 85.0) < 5) {
			refresh_rate_index = 2;
		} else {
			xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "Refresh Rate %fHz is not supported\n", mode->VRefresh);
			return (FALSE);
		}
		xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "Refresh Rate %fHz , index is %d\n", mode->VRefresh, refresh_rate_index);
		for (i = 0; i < 14; i++) {
			new->CR40[i] = ModeTable[modeIndex][refresh_rate_index][i];
		}
		new->SR6A = 0x16;
		new->SR6B = 0x02;
		new->SR6C = ModeTable[modeIndex][refresh_rate_index][14];
		new->SR6D = ModeTable[modeIndex][refresh_rate_index][15];
		if (panelIndex == 3) {
			new->CR90[14] = 0x18;
		} else {
			new->CR90[14] = 0x00;
		}
		if (modeIndex < 4) {
			new->CR30 &= ~0x09;
		} else {
			new->CR30 |= 0x09;
		}

		if (mode->VDisplay < pSmi->lcdHeight) {
			new->CRA0[6] = (pSmi->lcdHeight - mode->VDisplay) / 8;
		} else {
			new->CRA0[6] = 0;
		}
		if (mode->HDisplay < pSmi->lcdWidth) {
			new->CRA0[7] = (pSmi->lcdWidth - mode->HDisplay) / 16;
		} else {
			new->CRA0[7] = 0;
		}
		/*
		   }
		   */

	}
#endif

	/* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */
	new->CCR66 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66);
	if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR))
	{
		switch (pScrn->bitsPerPixel)
		{
			case 8:
				new->CCR66 = (new->CCR66 & 0xF3) | 0x00;	/* 6 bits-RAM */
				break;
			case 16:
				new->CCR66 = (new->CCR66 & 0xF3) | 0x00;	/* 6 bits-RAM */
				/* no Gamma correction in 16 Bit mode (s. Release.txt 1.3.1) */
				break;
			case 24:
			case 32:
				new->CCR66 = (new->CCR66 & 0xF3) | 0x04;	/* Gamma correct ON */
				break;
			default:
				LEAVE_PROC ("SMI_ModeInit");
				return (FALSE);
		}
	}

	if (pSmi->Chipset != SMI_COUGAR3DR)
	{
		if (VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x01)
		{
			new->SR21 = 0x00;
		}
	}

	if (pSmi->MCLK > 0)
	{
		SMI_CommonCalcClock (pScrn->scrnIndex, pSmi->MCLK,
				1, 1, 31, 0, 2, pSmi->minClock,
				pSmi->maxClock, &new->SR6A, &new->SR6B);
	}
	else
	{
		new->SR6B = 0xFF;
	}

	if ((mode->HDisplay == 640) && SMI_LYNXM_SERIES (pSmi->Chipset))
	{
		vganew->MiscOutReg &= ~0x0C;
	}
	else
	{
		vganew->MiscOutReg |= 0x0C;
	}
	vganew->MiscOutReg |= 0xE0;
	if (mode->HDisplay == 800)
	{
		vganew->MiscOutReg &= ~0xC0;
	}

	if ((mode->HDisplay == 1024) && SMI_LYNXM_SERIES (pSmi->Chipset))
	{
		vganew->MiscOutReg &= ~0xC0;
	}

	/* Set DPR registers */
	pSmi->Stride = (pSmi->lcdWidth * pSmi->Bpp + 15) & ~15;
	switch (pScrn->bitsPerPixel)
	{
		case 8:
			DEDataFormat = 0x00000000;
			break;

		case 16:
			pSmi->Stride >>= 1;
			DEDataFormat = 0x00100000;
			break;

		case 24:
			DEDataFormat = 0x00300000;
			break;

		case 32:
			pSmi->Stride >>= 2;
			DEDataFormat = 0x00200000;
			break;
	}
	for (i = 0; i < sizeof (xyAddress) / sizeof (xyAddress[0]); i++)
	{
		if (pSmi->rotate && pSmi->rotate != SMI_ROTATE_UD)
		{
			if (xyAddress[i] == pSmi->lcdHeight)
			{
				DEDataFormat |= i << 16;
				break;
			}
		}
		else
		{
			if (xyAddress[i] == pSmi->lcdWidth)
			{
				DEDataFormat |= i << 16;
				break;
			}
		}
	}
	new->DPR10 = (pSmi->Stride << 16) | pSmi->Stride;
	new->DPR1C = DEDataFormat;
	new->DPR20 = 0;
	new->DPR24 = 0xFFFFFFFF;
	new->DPR28 = 0xFFFFFFFF;
	new->DPR2C = 0;
	new->DPR30 = 0;
	new->DPR3C = (pSmi->Stride << 16) | pSmi->Stride;
	new->DPR40 = 0;
	new->DPR44 = 0;

	/* Set VPR registers (and FPR registers for SM731) */
	switch (pScrn->bitsPerPixel)
	{
		case 8:
			new->VPR00 = 0x00000000;
			new->FPR00_ = 0x00080000;
			break;

		case 16:
			new->VPR00 = 0x00020000;
			new->FPR00_ = 0x000A0000;
			break;

		case 24:
			new->VPR00 = 0x00040000;
			new->FPR00_ = 0x000C0000;
			break;

		case 32:
			new->VPR00 = 0x00030000;
			new->FPR00_ = 0x000B0000;
			break;
	}
	new->VPR0C = pSmi->FBOffset >> 3;
	if (pSmi->rotate && pSmi->rotate != SMI_ROTATE_UD)
	{
		new->VPR10 = ((((pSmi->lcdHeight * pSmi->Bpp) >> 3)
					+ 2) << 16) | ((pSmi->lcdHeight * pSmi->Bpp) >> 3);
	}
	else
	{
		new->VPR10 = ((((pSmi->lcdWidth * pSmi->Bpp) >> 3)
					+ 2) << 16) | ((pSmi->lcdWidth * pSmi->Bpp) >> 3);
	}

	new->FPR0C_ = new->VPR0C;
	new->FPR10_ = new->VPR10;

	/* Set CPR registers */
	new->CPR00 = 0x00000000;

	pScrn->vtSema = TRUE;

	/* Find the INT 10 mode number */
	{
		static struct
		{
			int x, y, bpp;
			CARD16 mode;

		} modeTable[] =
		{
			{
				640, 480, 8, 0x50},
			{
				640, 480, 16, 0x52},
			{
				640, 480, 24, 0x53},
			{
				640, 480, 32, 0x54},
			{
				800, 480, 8, 0x4A},
			{
				800, 480, 16, 0x4C},
			{
				800, 480, 24, 0x4D},
			{
				800, 600, 8, 0x55},
			{
				800, 600, 16, 0x57},
			{
				800, 600, 24, 0x58},
			{
				800, 600, 32, 0x59},
			{
				1024, 768, 8, 0x60},
			{
				1024, 768, 16, 0x62},
			{
				1024, 768, 24, 0x63},
			{
				1024, 768, 32, 0x64},
			{
				1280, 1024, 8, 0x65},
			{
				1280, 1024, 16, 0x67},
			{
				1280, 1024, 24, 0x68},
			{
				1280, 1024, 32, 0x69},};

				new->mode = 0;
				for (i = 0; i < sizeof (modeTable) / sizeof (modeTable[0]); i++)
				{
					if ((modeTable[i].x == mode->HDisplay)
							&& (modeTable[i].y == mode->VDisplay)
							&& (modeTable[i].bpp == pScrn->bitsPerPixel))
					{
						new->mode = modeTable[i].mode;
						break;
					}
				}
	}

	/* Zero the font memory */
	memset (new->smiFont, 0, sizeof (new->smiFont));

	/* Write the mode registers to hardware */
	if (pSmi->useBIOS)	// Use bios call -- by mill.chen
		SMI_BiosWriteMode(pScrn, mode, new);
	else
		SMI_WriteMode (pScrn, vganew, new);

	/* Adjust the viewport */
	SMI_AdjustFrame (pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);

	LEAVE_PROC ("SMI_ModeInit");
#if 1
	SMI_PrintRegs(pScrn);
#endif
	return (TRUE);
}

/*
 * This is called at the end of each server generation.  It restores the
 * original (text) mode.  It should also unmap the video memory, and free any
 * per-generation data allocated by the driver.  It should finish by unwrapping
 * and calling the saved CloseScreen function.
 */

	static Bool
SMI_CloseScreen (int scrnIndex, ScreenPtr pScreen)
{
	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
	vgaHWPtr hwp = VGAHWPTR (pScrn);
	SMIPtr pSmi = SMIPTR (pScrn);
	vgaRegPtr vgaSavePtr = &hwp->SavedReg;
	SMIRegPtr SMISavePtr = &pSmi->SavedReg;
	Bool ret;

	/*
	 * Belcon: Fix #001
	 * 	Restore hardware cursor register
	 */
	if (pSmi->dcrF0)
		WRITE_DCR(pSmi, DCRF0, pSmi->dcrF0);
	if (pSmi->dcr230)
		WRITE_DCR(pSmi, DCR230, pSmi->dcr230);
	/* #001 ended */

	ENTER_PROC ("SMI_CloseScreen");

	if (pScrn->vtSema)
	{
		SMI_WriteMode (pScrn, vgaSavePtr, SMISavePtr);
		vgaHWLock (hwp);
		SMI_UnmapMem (pScrn);
	}

	if (pSmi->AccelInfoRec != NULL)
	{
		XAADestroyInfoRec (pSmi->AccelInfoRec);
	}
	if (pSmi->CursorInfoRec != NULL)
	{
		xf86DestroyCursorInfoRec (pSmi->CursorInfoRec);
	}
	if (pSmi->DGAModes != NULL)
	{
		xfree (pSmi->DGAModes);
	}
	if (pSmi->pInt10 != NULL)
	{
		xf86FreeInt10 (pSmi->pInt10);
		pSmi->pInt10 = NULL;
	}
	if (pSmi->ptrAdaptor != NULL)
	{
		xfree (pSmi->ptrAdaptor);
	}
	if (pSmi->BlockHandler != NULL)
	{
		pScreen->BlockHandler = pSmi->BlockHandler;
	}
	if (pSmi->I2C != NULL)
	{
		xf86DestroyI2CBusRec (pSmi->I2C, FALSE, TRUE);
		xfree (pSmi->I2C);
		pSmi->I2C = NULL;
	}
	/* #670 */
	if (pSmi->pSaveBuffer)
	{
		xfree (pSmi->pSaveBuffer);
	}
	/* #920 */
	if (pSmi->paletteBuffer)
	{
		xfree (pSmi->paletteBuffer);
	}

	pScrn->vtSema = FALSE;
	pScreen->CloseScreen = pSmi->CloseScreen;
	ret = (*pScreen->CloseScreen) (scrnIndex, pScreen);

	LEAVE_PROC ("SMI_CloseScreen");
	return (ret);
}

	static void
SMI_FreeScreen (int scrnIndex, int flags)
{
	SMI_FreeRec (xf86Screens[scrnIndex]);
}

	static Bool
SMI_SaveScreen (ScreenPtr pScreen, int mode)
{
	Bool ret;

	ENTER_PROC ("SMI_SaveScreen");

	ret = vgaHWSaveScreen (pScreen, mode);

	LEAVE_PROC ("SMI_SaveScreen");
	return (ret);
}

	void
SMI_AdjustFrame (int scrnIndex, int x, int y, int flags)
{
	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
	SMIPtr pSmi = SMIPTR (pScrn);
	CARD32 Base;

	ENTER_PROC ("SMI_AdjustFrame");

	if (pSmi->ShowCache && y)
	{
		y += pScrn->virtualY - 1;
	}

	Base = pSmi->FBOffset + (x + y * pScrn->displayWidth) * pSmi->Bpp;

	if (SMI_LYNX3D_SERIES (pSmi->Chipset) || SMI_COUGAR_SERIES (pSmi->Chipset))
	{
		Base = (Base + 15) & ~15;
#if 1				/* PDR#1058 */
		while ((Base % pSmi->Bpp) > 0)
		{
			Base -= 16;
		}
#endif
	}
	else if (SMI_MSOC != pSmi->Chipset)
	{
		Base = (Base + 7) & ~7;
#if 1				/* PDR#1058 */
		while ((Base % pSmi->Bpp) > 0)
		{
			Base -= 8;
		}
#endif
	}

	if (pSmi->Chipset != SMI_MSOC)
	{
		WRITE_VPR (pSmi, 0x0C, Base >> 3);
	}
	else
	{

		if (!pSmi->IsSecondary)
		{
			WRITE_DCR (pSmi, DCR0C, Base);
#if SMI_DEBUG
			ErrorF ("LCD Base = %8X\n", 0);
#endif
		}
		else
		{
			/* changed by Belcon */
			//	  Base = pSmi->videoRAMBytes / 16 << 4;
			//  Base = pSmi->FBOffset / 16 << 4;
#if SMI_DEBUG
			ErrorF ("CRT Base = %8X\n", Base);
#endif
			WRITE_DCR (pSmi, DCR204, Base);
		}
#if SMI_DEBUG
		ErrorF ("FBOffset is 0x%x\n", pSmi->FBOffset);
#endif

	}


	if (pSmi->Chipset == SMI_COUGAR3DR)
	{
		WRITE_FPR (pSmi, FPR0C, Base >> 3);
	}

	LEAVE_PROC ("SMI_AdjustFrame");
}


	Bool
SMI_SwitchMode (int scrnIndex, DisplayModePtr mode, int flags)
{
	Bool ret;
	SMIPtr pSmi = SMIPTR (xf86Screens[scrnIndex]);

	ENTER_PROC ("SMI_SwitchMode");

	ret = SMI_ModeInit (xf86Screens[scrnIndex], mode);

	if (!pSmi->NoAccel)
		SMI_EngineReset (xf86Screens[scrnIndex]);
	LEAVE_PROC ("SMI_SwitchMode");
	return (ret);
}

	void
SMI_LoadPalette (ScrnInfoPtr pScrn, int numColors, int *indicies,
		LOCO * colors, VisualPtr pVisual)
{
	SMIPtr pSmi = SMIPTR (pScrn);
	int i;
	int iRGB;

	ENTER_PROC ("SMI_LoadPalette");



	/* Enable both the CRT and LCD DAC RAM paths, so both palettes are updated */
	if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR))
	{
		CARD8 ccr66;

		ccr66 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66);
		ccr66 &= 0x0f;
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66, ccr66);
	}

	if (SMI_MSOC != pSmi->Chipset)
	{
		for (i = 0; i < numColors; i++)
		{
			DEBUG ((VERBLEV, "pal[%d] = %d %d %d\n", indicies[i],
						colors[indicies[i]].red, colors[indicies[i]].green,
						colors[indicies[i]].blue));
			VGAOUT8 (pSmi, VGA_DAC_WRITE_ADDR, indicies[i]);
			VGAOUT8 (pSmi, VGA_DAC_DATA, colors[indicies[i]].red);
			VGAOUT8 (pSmi, VGA_DAC_DATA, colors[indicies[i]].green);
			VGAOUT8 (pSmi, VGA_DAC_DATA, colors[indicies[i]].blue);
		}
	}
	else				/* For SMI 501 Palette control */
	{
		for (i = 0; i < numColors; i++)
		{
			DEBUG ((VERBLEV, "pal[%d] = %d %d %d\n", indicies[i],
						colors[indicies[i]].red, colors[indicies[i]].green,
						colors[indicies[i]].blue));

			iRGB = (colors[indicies[i]].red << 16) |
				(colors[indicies[i]].green << 8) | (colors[indicies[i]].blue);

			if (!pSmi->IsSecondary)
			{
				WRITE_DCR (pSmi, DCR400 + (4 * (indicies[i])), iRGB);	/* CRT Palette   */
			}
			else
				WRITE_DCR (pSmi, DCR800 + (4 * (indicies[i])), iRGB);	/* Panel Palette */
		}

	}


	LEAVE_PROC ("SMI_LoadPalette");
}

	static void
SMI_DisableVideo (ScrnInfoPtr pScrn)
{
	SMIPtr pSmi = SMIPTR (pScrn);
	CARD8 tmp;
	int rVal;

	if (SMI_MSOC != pSmi->Chipset)
	{
		if (!(tmp = VGAIN8 (pSmi, VGA_DAC_MASK)))
			return;
		pSmi->DACmask = tmp;
		VGAOUT8 (pSmi, VGA_DAC_MASK, 0);
	}
	else
	{
		rVal = READ_DCR (pSmi, DCR200);
		rVal |= DCR200_CRT_BLANK;
		WRITE_DCR (pSmi, DCR200, rVal);
	}
}

	static void
SMI_EnableVideo (ScrnInfoPtr pScrn)
{
	SMIPtr pSmi = SMIPTR (pScrn);
	int rVal;

	if (SMI_MSOC != pSmi->Chipset)
	{
		VGAOUT8 (pSmi, VGA_DAC_MASK, pSmi->DACmask);
	}
	else
	{
		rVal = READ_DCR (pSmi, DCR200);
		rVal &= ~DCR200_CRT_BLANK;
		WRITE_DCR (pSmi, DCR200, rVal);
	}
}


	void
SMI_EnableMmio (ScrnInfoPtr pScrn)
{
	vgaHWPtr hwp = VGAHWPTR (pScrn);
	SMIPtr pSmi = SMIPTR (pScrn);
	CARD8 tmp;

	ENTER_PROC ("SMI_EnableMmio");

	if (SMI_MSOC != pSmi->Chipset)
	{
		/*
		 * Enable chipset (seen on uninitialized secondary cards) might not be
		 * needed once we use the VGA softbooter
		 */
		if (pSmi->IOBase != NULL)
		{
			vgaHWSetMmioFuncs (hwp, pSmi->MapBase,
					pSmi->IOBase - pSmi->MapBase);
		}

		/* Enable linear mode */
		tmp = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18);
		pSmi->SR18Value = tmp;	/* PDR#521 */
		if (-1 == saved_console_reg) {
			(pSmi->SavedReg).SR18 = tmp;
			saved_console_reg = 0;
		}
		VGAOUT8(pSmi, VGA_SEQ_DATA, tmp | 0x11);

		/* Enable 2D/3D Engine and Video Processor */
		tmp = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
		pSmi->SR21Value = tmp;	/* PDR#521 */
		VGAOUT8(pSmi, VGA_SEQ_DATA, tmp & ~0x03);

	}

	LEAVE_PROC ("SMI_EnableMmio");
}

	void
SMI_DisableMmio (ScrnInfoPtr pScrn)
{
	vgaHWPtr hwp = VGAHWPTR (pScrn);
	SMIPtr pSmi = SMIPTR (pScrn);

	ENTER_PROC ("SMI_DisableMmio");

	if (SMI_MSOC != pSmi->Chipset)
	{
		vgaHWSetStdFuncs (hwp);

		/* Disable 2D/3D Engine and Video Processor */
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, pSmi->SR21Value & (~0x80));

		/* Disable linear mode */
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18, (pSmi->SavedReg).SR18);
	}

	LEAVE_PROC ("SMI_DisableMmio");
}

/* This function is used to debug, it prints out the contents of Lynx regs */
	static void
SMI_PrintRegs (ScrnInfoPtr pScrn)
{
	unsigned char i;
	unsigned int j;
	vgaHWPtr hwp = VGAHWPTR (pScrn);
	SMIPtr pSmi = SMIPTR (pScrn);
	int vgaCRIndex = hwp->IOBase + VGA_CRTC_INDEX_OFFSET;
	int vgaCRReg = hwp->IOBase + VGA_CRTC_DATA_OFFSET;
	int vgaStatus = hwp->IOBase + VGA_IN_STAT_1_OFFSET;

	xf86DrvMsgVerb (pScrn->scrnIndex, X_INFO, VERBLEV,
			"START register dump ------------------\nEntitlyList is %d",
			pScrn->entityList[0]);

	if (SMI_MSOC != pSmi->Chipset)
	{
		xf86ErrorFVerb (VERBLEV, "MISCELLANEOUS OUTPUT\n    %02X\n",
				VGAIN8 (pSmi, VGA_MISC_OUT_R));

		xf86ErrorFVerb (VERBLEV, "\nSEQUENCER\n"
				"    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
		for (i = 0x00; i <= 0xAF; i++)
		{
			if ((i & 0xF) == 0x0)
				xf86ErrorFVerb (VERBLEV, "\n%02X|", i);
			if ((i & 0x3) == 0x0)
				xf86ErrorFVerb (VERBLEV, " ");
			xf86ErrorFVerb (VERBLEV, "%02X ",
					VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
						i));
		}

		xf86ErrorFVerb (VERBLEV, "\n\nCRT CONTROLLER\n"
				"    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
		for (i = 0x00; i <= 0xAD; i++)
		{
			if (i == 0x20)
				i = 0x30;
			if (i == 0x50)
#if SMI_DEBUG
				i = 0x70;
			if (i == 0x80)
#endif
				i = 0x90;
			if ((i & 0xF) == 0x0)
				xf86ErrorFVerb (VERBLEV, "\n%02X|", i);
			if ((i & 0x3) == 0x0)
				xf86ErrorFVerb (VERBLEV, " ");
			xf86ErrorFVerb (VERBLEV, "%02X ",
					VGAIN8_INDEX (pSmi, vgaCRIndex, vgaCRReg, i));
		}

		xf86ErrorFVerb (VERBLEV, "\n\nGRAPHICS CONTROLLER\n"
				"    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
		for (i = 0x00; i <= 0x08; i++)
		{
			if ((i & 0xF) == 0x0)
				xf86ErrorFVerb (VERBLEV, "\n%02X|", i);
			if ((i & 0x3) == 0x0)
				xf86ErrorFVerb (VERBLEV, " ");
			xf86ErrorFVerb (VERBLEV, "%02X ",
					VGAIN8_INDEX (pSmi, VGA_GRAPH_INDEX, VGA_GRAPH_DATA,
						i));
		}

		xf86ErrorFVerb (VERBLEV, "\n\nATTRIBUTE 0CONTROLLER\n"
				"    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
		for (i = 0x00; i <= 0x14; i++)
		{
			(void) VGAIN8 (pSmi, vgaStatus);
			if ((i & 0xF) == 0x0)
				xf86ErrorFVerb (VERBLEV, "\n%02X|", i);
			if ((i & 0x3) == 0x0)
				xf86ErrorFVerb (VERBLEV, " ");
			xf86ErrorFVerb (VERBLEV, "%02X ",
					VGAIN8_INDEX (pSmi, VGA_ATTR_INDEX, VGA_ATTR_DATA_R,
						i));
		}
		(void) VGAIN8 (pSmi, vgaStatus);
		VGAOUT8 (pSmi, VGA_ATTR_INDEX, 0x20);
	}

	xf86ErrorFVerb (VERBLEV, "\n\nDPR    x0       x4       x8       xC");
	for (i = 0x00; i <= 0x44; i += 4)
	{
		if ((i & 0xF) == 0x0)
			xf86ErrorFVerb (VERBLEV, "\n%02X|", i);
		xf86ErrorFVerb (VERBLEV, " %08lX", (unsigned long) READ_DPR (pSmi, i));
	}

	xf86ErrorFVerb (VERBLEV, "\n\nVPR    x0       x4       x8       xC");
	for (i = 0x00; i <= 0x60; i += 4)
	{
		if ((i & 0xF) == 0x0)
			xf86ErrorFVerb (VERBLEV, "\n%02X|", i);
		xf86ErrorFVerb (VERBLEV, " %08lX", (unsigned long) READ_VPR (pSmi, i));

	}

	xf86ErrorFVerb (VERBLEV, "\n\nCPR    x0       x4       x8       xC");
	for (i = 0x00; i <= 0x18; i += 4)
	{
		if ((i & 0xF) == 0x0)
			xf86ErrorFVerb (VERBLEV, "\n%02X|", i);
		xf86ErrorFVerb (VERBLEV, " %08lX", (unsigned long) READ_CPR (pSmi, i));
	}

	if (SMI_MSOC == pSmi->Chipset)
	{
		xf86ErrorFVerb (VERBLEV, "\n\nSCR    x0       x4       x8       xC");
		for (j = 0x00; j <= 0x6C; j += 4)
		{
			if ((j & 0xF) == 0x0)
				xf86ErrorFVerb (VERBLEV, "\n%02X|", j);
			xf86ErrorFVerb (VERBLEV, " %08X", (unsigned int)READ_SCR (pSmi, j));
		}
		xf86ErrorFVerb (VERBLEV, "\n\nDCR    x0       x4       x8       xC");
		for (j = 0x200; j <= 0x23C; j += 4)
		{
			if ((j & 0xF) == 0x0)
				xf86ErrorFVerb (VERBLEV, "\n%02X|", j);
			xf86ErrorFVerb (VERBLEV, " %08X", (unsigned int)READ_DCR (pSmi, j));
		}
	}

	xf86ErrorFVerb (VERBLEV, "\n\n");
	xf86DrvMsgVerb (pScrn->scrnIndex, X_INFO, VERBLEV,
			"END register dump --------------------\n");
}

/*
 * SMI_DisplayPowerManagementSet -- Sets VESA Display Power Management
 * Signaling (DPMS) Mode.
 */
	static void
SMI_DisplayPowerManagementSet (ScrnInfoPtr pScrn, int PowerManagementMode,
		int flags)
{
	vgaHWPtr hwp = VGAHWPTR (pScrn);
	SMIPtr pSmi = SMIPTR (pScrn);
	CARD8 SR01, SR20, SR21, SR22, SR23, SR24, SR31, SR34;

	ENTER_PROC ("SMI_DisplayPowerManagementSet");

	/* If we already are in the requested DPMS mode, just return */
	if (pSmi->CurrentDPMS == PowerManagementMode)
	{
		LEAVE_PROC ("SMI_DisplayPowerManagementSet");
		return;
	}


	if (SMI_MSOC != pSmi->Chipset)
	{
		/* Save the current SR registers */
		if (pSmi->CurrentDPMS == DPMSModeOn)
		{
			pSmi->DPMS_SR20 =
				VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20);
			pSmi->DPMS_SR21 =
				VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
			pSmi->DPMS_SR31 =
				VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31);
			pSmi->DPMS_SR34 =
				VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34);
		}

		/* Read the required SR registers for the DPMS handler */
		SR01 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01);
		SR20 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20);
		SR21 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
		SR22 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22);
		SR23 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23);
		SR24 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x24);
		SR31 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31);
		SR34 = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34);

		switch (PowerManagementMode)
		{
			case DPMSModeOn:
				/* Screen On: HSync: On, VSync : On */
				SR01 &= ~0x20;
				SR20 = pSmi->DPMS_SR20;
				SR21 = pSmi->DPMS_SR21;
				SR22 &= ~0x30;
				SR23 &= ~0xC0;
				SR24 |= 0x01;
				SR31 = pSmi->DPMS_SR31;
				SR34 = pSmi->DPMS_SR34;
				break;

			case DPMSModeStandby:
				/* Screen: Off; HSync: Off, VSync: On */
				SR01 |= 0x20;
				SR20 = (SR20 & ~0xB0) | 0x10;
				SR21 |= 0x88;
				SR22 = (SR22 & ~0x30) | 0x10;
				SR23 = (SR23 & ~0x07) | 0xD8;
				SR24 &= ~0x01;
				SR31 = (SR31 & ~0x07) | 0x00;
				SR34 |= 0x80;
				break;

			case DPMSModeSuspend:
				/* Screen: Off; HSync: On, VSync: Off */
				SR01 |= 0x20;
				SR20 = (SR20 & ~0xB0) | 0x10;
				SR21 |= 0x88;
				SR22 = (SR22 & ~0x30) | 0x20;
				SR23 = (SR23 & ~0x07) | 0xD8;
				SR24 &= ~0x01;
				SR31 = (SR31 & ~0x07) | 0x00;
				SR34 |= 0x80;
				break;

			case DPMSModeOff:
				/* Screen: Off; HSync: Off, VSync: Off */
				SR01 |= 0x20;
				SR20 = (SR20 & ~0xB0) | 0x10;
				SR21 |= 0x88;
				SR22 = (SR22 & ~0x30) | 0x30;
				SR23 = (SR23 & ~0x07) | 0xD8;
				SR24 &= ~0x01;
				SR31 = (SR31 & ~0x07) | 0x00;
				SR34 |= 0x80;
				break;

			default:
				xf86ErrorFVerb (VERBLEV, "Invalid PowerManagementMode %d passed to "
						"SMI_DisplayPowerManagementSet\n",
						PowerManagementMode);
				LEAVE_PROC ("SMI_DisplayPowerManagementSet");
				return;
		}


		/* Wait for vertical retrace */
		while (hwp->readST01 (hwp) & 0x8);
		while (!(hwp->readST01 (hwp) & 0x8));

		/* Write the registers */
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01, SR01);
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34, SR34);
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, SR31);
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20, SR20);
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22, SR22);
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23, SR23);
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, SR21);
		VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x24, SR24);

	}
	else
	{

		setDPMS (pSmi, PowerManagementMode);

		switch (PowerManagementMode)
		{
			case DPMSModeOn:
				setPower (pSmi, 0, 0, 0);
				break;

			case DPMSModeStandby:
				setPower (pSmi, 0, 0, 2);
				break;

			case DPMSModeSuspend:
				setPower (pSmi, 0, 0, 2);
				break;

			case DPMSModeOff:
				setPower (pSmi, 0, 0, 2);
				break;
			default:
				break;

		}


	}
	/* Save the current power state */
	pSmi->CurrentDPMS = PowerManagementMode;

	LEAVE_PROC ("SMI_DisplayPowerManagementSet");
}

	static void
SMI_ProbeDDC (ScrnInfoPtr pScrn, int index)
{
	vbeInfoPtr pVbe;
	ENTER_PROC("SMI_ProbeDDC");
	if (xf86LoadSubModule (pScrn, "vbe"))
	{
		pVbe = VBEInit (NULL, index);
		ConfiguredMonitor = vbeDoEDID (pVbe, NULL);
		vbeFree (pVbe);
	}
	LEAVE_PROC("SMI_ProbeDDC");
}

	static unsigned int
SMI_ddc1Read (ScrnInfoPtr pScrn)
{
	register vgaHWPtr hwp = VGAHWPTR (pScrn);
	SMIPtr pSmi = SMIPTR (pScrn);
	unsigned int ret;

	ENTER_PROC ("SMI_ddc1Read");

	while (hwp->readST01 (hwp) & 0x8);
	while (!(hwp->readST01 (hwp) & 0x8));

	ret = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72) & 0x08;

	LEAVE_PROC ("SMI_ddc1Read");
	return (ret);
}

	static Bool
SMI_ddc1 (int scrnIndex)
{
	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
	SMIPtr pSmi = SMIPTR (pScrn);
	Bool success = FALSE;
	xf86MonPtr pMon;
	unsigned char tmp;

	ENTER_PROC ("SMI_ddc1");

	tmp = VGAIN8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72);
	VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, tmp | 0x20);

	pMon = xf86PrintEDID (xf86DoEDID_DDC1 (scrnIndex,
				// #if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(6,9,0,0,0)
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(6,9,0,0,0)
				vgaHWddc1SetSpeedWeak (),
#elif XORG_VERSION_CURRENT == XORG_VERSION_NUMERIC(1,3,0,0,0)
				vgaHWddc1SetSpeedWeak (),
#else
				vgaHWddc1SetSpeed,
#endif
				SMI_ddc1Read));

	if (pMon != NULL)
	{
		success = TRUE;
	}
	xf86SetDDCproperties (pScrn, pMon);

	VGAOUT8_INDEX (pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, tmp);

	LEAVE_PROC ("SMI_ddc1");
	return (success);
}


	static Bool
SMI_MSOCSetMode (ScrnInfoPtr pScrn, DisplayModePtr mode)
{
	SMIPtr pSmi = SMIPTR (pScrn);

	ENTER_PROC ("SMI_MSOCSetMode");

	if (!pSmi->IsSecondary)
	{
		panelSetMode (pSmi, mode->HDisplay, mode->VDisplay, 0, 60, pSmi->Stride,
				pScrn->depth);
		panelUseLCD (pSmi, TRUE);
	}
	else
	{
		crtSetMode (pSmi, mode->HDisplay, mode->VDisplay, 0,
				(int) (mode->VRefresh + 0.5), pSmi->Stride, pScrn->depth);
		panelUseCRT (pSmi, TRUE);
	}


	/*boyod */

	LEAVE_PROC ("SMI_MSOCSetMode");

	return (TRUE);

}

void SMI_SaveReg_502(ScrnInfoPtr pScrn )
{
	return;
}

void SMI_RestoreReg_502(ScrnInfoPtr pScrn )
{
	return;
}

#ifdef RANDR
	static Bool
SMI_RandRGetInfo(ScrnInfoPtr pScrn, Rotation *rotations)
{
	SMIPtr pSmi = SMIPTR (pScrn); 
	ENTER_PROC ("SMI_RandRGetInfo");

	if(pSmi->RandRRotation)
		*rotations = RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270;
	else
		*rotations = RR_Rotate_0;
	LEAVE_PROC ("SMI_RandRGetInfo");
	return TRUE;
}

	static Bool
SMI_RandRSetConfig(ScrnInfoPtr pScrn, xorgRRConfig *config)
{
	SMIPtr pSmi = SMIPTR (pScrn);
	int bytesPerPixel = pScrn->bitsPerPixel / 8;

	ENTER_PROC ("SMI_RandRSetConfig");
	switch(config->rotation) {
		case RR_Rotate_0:
			pSmi->rotate = SMI_ROTATE_ZERO;
			pScrn->PointerMoved = pSmi->PointerMoved;
			break;

		case RR_Rotate_90:
			pSmi->rotate = SMI_ROTATE_CW;
			pScrn->PointerMoved = SMI_PointerMoved;
			pSmi->height= pSmi->ShadowHeight = pScrn->virtualX;
			pSmi->width = pSmi->ShadowWidth= pScrn->virtualY;
			pSmi->ShadowWidthBytes  = (pSmi->ShadowWidth * bytesPerPixel + 15) & ~15;
			break;

		case RR_Rotate_180:
			pSmi->rotate = SMI_ROTATE_UD;
			pScrn->PointerMoved = SMI_PointerMoved;
			pSmi->height= pSmi->ShadowHeight = pScrn->virtualY;
			pSmi->width = pSmi->ShadowWidth= pScrn->virtualX;
			pSmi->ShadowWidthBytes  = (pSmi->ShadowWidth * bytesPerPixel + 15) & ~15;			
			break;						

		case RR_Rotate_270:
			pSmi->rotate = SMI_ROTATE_CCW;
			pScrn->PointerMoved = SMI_PointerMoved;
			pSmi->height= pSmi->ShadowHeight = pScrn->virtualX;
			pSmi->width = pSmi->ShadowWidth= pScrn->virtualY;
			pSmi->ShadowWidthBytes  = (pSmi->ShadowWidth * bytesPerPixel + 15) & ~15;
			break;

		default:
			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
					"Unexpected rotation in SMI_RandRSetConfig!\n");
			pSmi->rotate = 0;
			pScrn->PointerMoved = pSmi->PointerMoved;
			return FALSE;
	}  	
	LEAVE_PROC ("SMI_RandRSetConfig");
	return TRUE;
}

	static Bool
SMI_DriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer data)
{
	ENTER_PROC ("SMI_DriverFunc");
	switch(op) {
		case RR_GET_INFO:
			LEAVE_PROC ("SMI_DriverFunc");
			return SMI_RandRGetInfo(pScrn, (Rotation*)data);
		case RR_SET_CONFIG:
			LEAVE_PROC ("SMI_DriverFunc");
			return SMI_RandRSetConfig(pScrn, (xorgRRConfig*)data);
		default:
			LEAVE_PROC ("SMI_DriverFunc");
			return FALSE;
	}
	LEAVE_PROC ("SMI_DriverFunc");
	return FALSE;
}
#endif
