/*
 * Copyright 1992-2003 by Alan Hourihane, North Wales, UK.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Alan Hourihane not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Alan Hourihane makes no representations
 * about the suitability of this software for any purpose.  It is provided
 * "as is" without express or implied warranty.
 *
 * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * Author:  Alan Hourihane, alanh@fairlite.demon.co.uk
 *	    Re-written for XFree86 v4.0
 *
 * Previous driver (pre-XFree86 v4.0) by
 * 	    Alan Hourihane, alanh@fairlite.demon.co.uk
 *	    David Wexelblat (major contributor)
 *	    Massimiliano Ghilardi, max@Linuz.sns.it, some fixes to the
 *				   clockchip programming code.
 */
/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/trident/trident_driver.c,v 1.190 2004/01/21 22:31:54 alanh Exp $ */

#include "xf1bpp.h"
#include "xf4bpp.h"
#include "fb.h"

#include "mibank.h"
#include "micmap.h"
#include "xf86.h"
#include "xf86_OSproc.h"
#include "xf86Resources.h"
#include "xf86_ansic.h"
#include "xf86Version.h"
#include "xf86PciInfo.h"
#include "xf86Pci.h"
#include "xf86cmap.h"
#include "vgaHW.h"
#include "xf86RAC.h"
#include "vbe.h"
#include "dixstruct.h"
#include "compiler.h"

#include "mipointer.h"

#include "mibstore.h"
#include "shadow.h"
#include "trident.h"
#include "trident_regs.h"

#define _XF86DGA_SERVER_
#include "extensions/xf86dgastr.h"

#include "globals.h"
#define DPMS_SERVER
#include "extensions/dpms.h"

#include "xf86xv.h"

static const OptionInfoRec * TRIDENTAvailableOptions(int chipid, int busid);
static void	TRIDENTIdentify(int flags);
static Bool	TRIDENTProbe(DriverPtr drv, int flags);
static Bool	TRIDENTPreInit(ScrnInfoPtr pScrn, int flags);
static Bool	TRIDENTScreenInit(int Index, ScreenPtr pScreen, int argc,
			      char **argv);
static Bool	TRIDENTEnterVT(int scrnIndex, int flags);
static void	TRIDENTLeaveVT(int scrnIndex, int flags);
static Bool	TRIDENTCloseScreen(int scrnIndex, ScreenPtr pScreen);
static Bool	TRIDENTSaveScreen(ScreenPtr pScreen, int mode);

/* Optional functions */
static void	TRIDENTFreeScreen(int scrnIndex, int flags);
static ModeStatus TRIDENTValidMode(int scrnIndex, DisplayModePtr mode,
				   Bool verbose, int flags);

/* Internally used functions */
static Bool	TRIDENTMapMem(ScrnInfoPtr pScrn);
static Bool	TRIDENTUnmapMem(ScrnInfoPtr pScrn);
static void	TRIDENTSave(ScrnInfoPtr pScrn);
static void	TRIDENTRestore(ScrnInfoPtr pScrn);
static Bool	TRIDENTModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
static void 	TRIDENTBlockHandler(int, pointer, pointer, pointer);

static void	TRIDENTEnableMMIO(ScrnInfoPtr pScrn);
static void	TRIDENTDisableMMIO(ScrnInfoPtr pScrn);
static void	PC98TRIDENTInit(ScrnInfoPtr pScrn);
static void	PC98TRIDENTEnable(ScrnInfoPtr pScrn);
static void	PC98TRIDENTDisable(ScrnInfoPtr pScrn);
static void	PC98TRIDENT96xxInit(ScrnInfoPtr pScrn);
static void	PC98TRIDENT96xxEnable(ScrnInfoPtr pScrn);
static void	PC98TRIDENT96xxDisable(ScrnInfoPtr pScrn);
static void	PC98TRIDENT9385Init(ScrnInfoPtr pScrn);
static void	PC98TRIDENT9385Enable(ScrnInfoPtr pScrn);
static void	PC98TRIDENT9385Disable(ScrnInfoPtr pScrn);

/*
 * This is intentionally screen-independent.  It indicates the binding
 * choice made in the first PreInit.
 */
static int pix24bpp = 0;
 
#define VERSION 4000
#define TRIDENT_NAME "TRIDENT"
#define TRIDENT_DRIVER_NAME "trident"
#define TRIDENT_MAJOR_VERSION 1
#define TRIDENT_MINOR_VERSION 0
#define TRIDENT_PATCHLEVEL 0

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

DriverRec TRIDENT = {
    VERSION,
    TRIDENT_DRIVER_NAME,
    TRIDENTIdentify,
    TRIDENTProbe,
    TRIDENTAvailableOptions,
    NULL,
    0
};

static SymTabRec TRIDENTChipsets[] = {
    { TVGA9000,			"tvga9000" },
    { TVGA9000i,		"tvga9000i" },
    { TVGA8900C,		"tvga8900c" },
    { TVGA8900D,		"tvga8900d" },
    { TVGA9200CXr,		"tvga9200cxr" },
    { TGUI9400CXi,		"tgui9400cxi" },
    { CYBER9320,		"cyber9320" },
    { CYBER9388,		"cyber9388" },
    { CYBER9397,		"cyber9397" },
    { CYBER9397DVD,		"cyber9397dvd" },
    { CYBER9520,		"cyber9520" },
    { CYBER9525DVD,		"cyber9525dvd" },
    { CYBERBLADEE4,		"cyberblade/e4" },
    { TGUI9420DGi,		"tgui9420dgi" },
    { TGUI9440AGi,		"tgui9440agi" },
    { TGUI9660,			"tgui9660" },
    { TGUI9680,			"tgui9680" },
    { PROVIDIA9682,		"providia9682" },
    { PROVIDIA9685,		"providia9685" },
    { CYBER9382,		"cyber9382" },
    { CYBER9385,		"cyber9385" },
    { IMAGE975,			"3dimage975" },
    { IMAGE985,			"3dimage985" },
    { BLADE3D,			"blade3d" },
    { CYBERBLADEI7,		"cyberbladei7" },
    { CYBERBLADEI7D,		"cyberbladei7d" },
    { CYBERBLADEI1,		"cyberbladei1" },
    { CYBERBLADEI1D,		"cyberbladei1d" },
    { CYBERBLADEAI1,		"cyberbladeAi1" },
    { CYBERBLADEAI1D,		"cyberbladeAi1d" },
    { BLADEXP,			"bladeXP" },
    { CYBERBLADEXPAI1,		"cyberbladeXPAi1" },
    { CYBERBLADEXP4,		"cyberbladeXP4" },
    { -1,				NULL }
};

static IsaChipsets TRIDENTISAchipsets[] = {
    { TVGA9000,			RES_EXCLUSIVE_VGA },
    { TVGA9000i,		RES_EXCLUSIVE_VGA },
    { TVGA8900C,		RES_EXCLUSIVE_VGA },
    { TVGA8900D,		RES_EXCLUSIVE_VGA },
    { TVGA9200CXr,		RES_EXCLUSIVE_VGA },
    { TGUI9400CXi,		RES_EXCLUSIVE_VGA },
    { CYBER9320,		RES_EXCLUSIVE_VGA },
    { TGUI9440AGi,		RES_EXCLUSIVE_VGA },
    { -1,			RES_UNDEFINED }
};

static PciChipsets TRIDENTPciChipsets[] = {
    { CYBER9320,	PCI_CHIP_9320,	RES_SHARED_VGA },
    { CYBER9388,	PCI_CHIP_9388,	RES_SHARED_VGA },
    { CYBER9397,	PCI_CHIP_9397,	RES_SHARED_VGA },
    { CYBER9397DVD,	PCI_CHIP_939A,	RES_SHARED_VGA },
    { CYBER9520,	PCI_CHIP_9520,	RES_SHARED_VGA },
    { CYBER9525DVD,	PCI_CHIP_9525,	RES_SHARED_VGA },
    { CYBERBLADEE4,	PCI_CHIP_9540,	RES_SHARED_VGA },
    { TGUI9420DGi,	PCI_CHIP_9420,	RES_SHARED_VGA },
    { TGUI9440AGi,	PCI_CHIP_9440,	RES_SHARED_VGA },
    { TGUI9660,		PCI_CHIP_9660,	RES_SHARED_VGA },
    { TGUI9680,		PCI_CHIP_9660,	RES_SHARED_VGA },
    { PROVIDIA9682,	PCI_CHIP_9660,	RES_SHARED_VGA },
    { PROVIDIA9685,	PCI_CHIP_9660,	RES_SHARED_VGA },
    { CYBER9382,	PCI_CHIP_9660,	RES_SHARED_VGA },
    { CYBER9385,	PCI_CHIP_9660,	RES_SHARED_VGA },
    { IMAGE975,		PCI_CHIP_9750,	RES_SHARED_VGA },
    { IMAGE985,		PCI_CHIP_9850,	RES_SHARED_VGA },
    { BLADE3D,		PCI_CHIP_9880,	RES_SHARED_VGA },
    { CYBERBLADEI7,	PCI_CHIP_8400,	RES_SHARED_VGA },
    { CYBERBLADEI7D,	PCI_CHIP_8420,	RES_SHARED_VGA },
    { CYBERBLADEI1,	PCI_CHIP_8500,	RES_SHARED_VGA },
    { CYBERBLADEI1D,	PCI_CHIP_8520,	RES_SHARED_VGA },
    { CYBERBLADEAI1,	PCI_CHIP_8600,	RES_SHARED_VGA },
    { CYBERBLADEAI1D,	PCI_CHIP_8620,	RES_SHARED_VGA },
    { BLADEXP,		PCI_CHIP_9910,	RES_SHARED_VGA },
    { CYBERBLADEXPAI1,	PCI_CHIP_8820,	RES_SHARED_VGA },
    { CYBERBLADEXP4,	PCI_CHIP_2100,	RES_SHARED_VGA },
    { -1,		-1,		RES_UNDEFINED }
};
    
typedef enum {
    OPTION_SW_CURSOR,
    OPTION_PCI_RETRY,
    OPTION_RGB_BITS,
    OPTION_NOACCEL,
    OPTION_SETMCLK,
    OPTION_MUX_THRESHOLD,
    OPTION_SHADOW_FB,
    OPTION_ROTATE,
    OPTION_MMIO_ONLY,
    OPTION_VIDEO_KEY,
    OPTION_NOMMIO,
    OPTION_NOPCIBURST,
    OPTION_CYBER_SHADOW,
    OPTION_CYBER_STRETCH,
    OPTION_XV_HSYNC,
    OPTION_XV_VSYNC,
    OPTION_XV_BSKEW,
    OPTION_XV_RSKEW,
    OPTION_FP_DELAY,
    OPTION_1400_DISPLAY,
    OPTION_DISPLAY,
    OPTION_GB,
    OPTION_TV_CHIPSET,
    OPTION_TV_SIGNALMODE
} TRIDENTOpts;

static const OptionInfoRec TRIDENTOptions[] = {
    { OPTION_SW_CURSOR,		"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_PCI_RETRY,		"PciRetry",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_NOACCEL,		"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_SETMCLK,		"SetMClk",	OPTV_FREQ,	{0}, FALSE },
    { OPTION_MUX_THRESHOLD,	"MUXThreshold",	OPTV_INTEGER,	{0}, FALSE },
    { OPTION_SHADOW_FB,		"ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_ROTATE,  	        "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
    { OPTION_VIDEO_KEY,		"VideoKey",	OPTV_INTEGER,	{0}, FALSE },
    { OPTION_NOMMIO,		"NoMMIO",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_NOPCIBURST,	"NoPciBurst",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_MMIO_ONLY,		"MMIOonly",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_CYBER_SHADOW,	"CyberShadow",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_CYBER_STRETCH,	"CyberStretch",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_XV_HSYNC,          "XvHsync",      OPTV_INTEGER,   {0}, FALSE },
    { OPTION_XV_VSYNC,          "XvVsync",      OPTV_INTEGER,   {0}, FALSE },
    { OPTION_XV_BSKEW,          "XvBskew",      OPTV_INTEGER,   {0}, FALSE },
    { OPTION_XV_RSKEW,          "XvRskew",      OPTV_INTEGER,   {0}, FALSE },
    { OPTION_FP_DELAY,          "FpDelay",      OPTV_INTEGER,   {0}, FALSE },
    { OPTION_1400_DISPLAY,	"Display1400",	OPTV_BOOLEAN,	{0}, FALSE },
    { OPTION_DISPLAY,		"Display",	OPTV_ANYSTR,	{0}, FALSE },
    { OPTION_GB,		"GammaBrightness",	OPTV_ANYSTR,	{0}, FALSE },
    { OPTION_TV_CHIPSET,        "TVChipset",    OPTV_ANYSTR,    {0}, FALSE },
    { OPTION_TV_SIGNALMODE,     "TVSignal",     OPTV_INTEGER,   {0}, FALSE },
    { -1,			NULL,		OPTV_NONE,	{0}, FALSE }
};

/* Clock Limits */
static int ClockLimit[] = {
	80000,
	80000,
	80000,
	80000,
	80000,
	80000,
	80000,
	80000,
	80000,
	80000,
	80000,
	80000,
	80000,
	80000,
	90000,
	90000,
	135000,
	135000,
	170000,
	170000,
	170000,
	170000,
	170000,
	170000,
	170000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
};

static int ClockLimit16bpp[] = {
	40000,
	40000,
	40000,
	40000,
	40000,
	40000,
	40000,
	40000,
	40000,
	40000,
	40000,
	40000,
	40000,
	40000,
	45000,
	45000,
	90000,
	90000,
	135000,
	135000,
	170000,
	170000,
	170000,
	170000,
	170000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
	230000,
}; 

static int ClockLimit24bpp[] = {
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	40000,
	40000,
	70000,
	70000,
	70000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
};

static int ClockLimit32bpp[] = {
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	25180,
	40000,
	40000,
	70000,
	70000,
	70000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
	115000,
};

/*
 * These are fixed modelines for all physical display dimensions the
 *  chipsets supports on FPs. Most of them are not tested yet.
 */
#if 0
tridentLCD LCD[] = {   /* 0    3    4    5   6    7    10   11  16 */
    { 0,"640x480",25200,0x5f,0x82,0x54,0x80,0xb,0x3e,0xea,0x8c,0xb,0x08},
    { 1,"800x600",40000,0x7f,0x99,0x69,0x99,0x72,0xf0,0x59,0x2d,0x5e,0x08},
    { 2,"1024x768",65000,0xa3,/*0x6*/ 0x98,0x8f,0xa0,0x24,0xf5,0x0f,0x25,0x96,0x08},
    { 3,"1024x768",65000,0xa3,/*0x6*/ 0x98,0x8f,0xa0,0x24,0xf5,0x0f,0x25,0x96,0x08}, /*0x96*/
    { 4,"1280x1024",108000,0xa3,0x6,0x8f,0xa0,0x24,0xf5,0x0f,0x25,0x96,0x08},
    { 5,"1024x600",50500 ,0xa3,0x6,0x8f,0xa0,0xb,0x3e,0xea,0x8c,0xb,0x08},
    { 0xff,"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
#else
#if 0
tridentLCD LCD[] = { 
    { 1,640,480,25200,0x5f,0x82,0x54,0x80,0xb,0x3e,0xea,0x8c,0xb,0x08},
    { 3,800,600,40000,0x7f,0x82,0x6b,0x1b,0x72,0xf8,0x58,0x8c,0x72,0x08},
    { 2,1024,768,65000,0xa3,/*0x6*/0x98,0x8f,0xa0,0x24,0xf5,0x0f,0x24,0x0a,0x08},
    { 0,1280,1024,108000,0xce,0x81,0xa6,0x9a,0x27,0x50,0x00,0x03,0x26,0xa8},
    { 0xff,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
#else
tridentLCD LCD[] = { 
    { 1,640,480,25200,0x5f,0x80,0x52,0x1e,0xb,0x3e,0xea,0x0c,0xb,0x08},
    { 3,800,600,40000,0x7f,0x00,0x69,0x7f,0x72,0xf0,0x59,0x0d,0x00,0x08},
    { 2,1024,768,65000,0xa3,0x00,0x84,0x94,0x24,0xf5,0x03,0x09,0x24,0x08},
    { 0,1280,1024,108000,0xce,0x91,0xa6,0x14,0x28,0x5a,0x01,0x04,0x28,0xa8},
    { 4,1400,1050,122000,0xe6,0xcd,0xba,0x1d,0x38,0x00,0x1c,0x28,0x28,0xf8},
    { 0xff,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
#endif
#endif

static const char *xaaSymbols[] = {
    "XAAGetCopyROP",
    "XAACreateInfoRec",
    "XAADestroyInfoRec",
    "XAAInit",
    "XAAGetPatternROP",
    NULL
};

static const char *vgahwSymbols[] = {
    "vgaHWBlankScreenWeak",
    "vgaHWFreeHWRec",
    "vgaHWGetHWRec",
    "vgaHWGetIOBase",
    "vgaHWGetIndex",
    "vgaHWInit",
    "vgaHWLock",
    "vgaHWMapMem",
    "vgaHWProtectWeak",
    "vgaHWRestore",
    "vgaHWSave",
    "vgaHWSaveScreen",
    "vgaHWSetMmioFuncs",
    "vgaHWUnlock",
    NULL
};

#ifdef XFree86LOADER
static const char *miscfbSymbols[] = {
    "xf1bppScreenInit",
    "xf4bppScreenInit",
    NULL
};
#endif

static const char *fbSymbols[] = {
    "fbPictureInit",
    "fbScreenInit",
    NULL
};

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

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

static const char *i2cSymbols[] = {
    "xf86CreateI2CBusRec",
    "xf86I2CBusInit",
    NULL
};

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

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

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

#ifdef XFree86LOADER

static MODULESETUPPROTO(tridentSetup);

static XF86ModuleVersionInfo tridentVersRec =
{
	"trident",
	MODULEVENDORSTRING,
	MODINFOSTRING1,
	MODINFOSTRING2,
	XORG_VERSION_CURRENT,
	TRIDENT_MAJOR_VERSION, TRIDENT_MINOR_VERSION, TRIDENT_PATCHLEVEL,
	ABI_CLASS_VIDEODRV,			/* This is a video driver */
	ABI_VIDEODRV_VERSION,
	MOD_CLASS_VIDEODRV,
	{0,0,0,0}
};

XF86ModuleData tridentModuleData = { &tridentVersRec, tridentSetup, NULL };

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

    if (!setupDone) {
	setupDone = TRUE;
	xf86AddDriver(&TRIDENT, module, 0);
	LoaderRefSymLists(vgahwSymbols, fbSymbols, i2cSymbols, vbeSymbols,
			  miscfbSymbols, ramdacSymbols, int10Symbols,
			  xaaSymbols, shadowSymbols, NULL);
	return (pointer)TRUE;
    } 

    if (errmaj) *errmaj = LDR_ONCEONLY;
    return NULL;
}

#endif /* XFree86LOADER */

static Bool
TRIDENTGetRec(ScrnInfoPtr pScrn)
{
    /*
     * Allocate an TRIDENTRec, 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)
	return TRUE;

    pScrn->driverPrivate = xnfcalloc(sizeof(TRIDENTRec), 1);
    /* Initialise it */

    return TRUE;
}

static void
TRIDENTFreeRec(ScrnInfoPtr pScrn)
{
    if (pScrn->driverPrivate == NULL)
	return;
    xfree(pScrn->driverPrivate);
    pScrn->driverPrivate = NULL;
}

static void 
TRIDENTDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    CARD8 DPMSCont, PMCont, temp;

    if (!pScrn->vtSema)
	return;

    OUTB(0x3C4, 0x0E);
    temp = INB(0x3C5);
    OUTB(0x3C5, 0xC2);
    OUTB(0x83C8, 0x04); /* Read DPMS Control */
    PMCont = INB(0x83C6) & 0xFC;
    OUTB(0x3CE, 0x23);
    DPMSCont = INB(0x3CF) & 0xFC;
    switch (PowerManagementMode)
    {
	case DPMSModeOn:
		/* Screen: On, HSync: On, VSync: On */
		PMCont |= 0x03;
		DPMSCont |= 0x00;
		break;
	case DPMSModeStandby:
		/* Screen: Off, HSync: Off, VSync: On */
		PMCont |= 0x02;
		DPMSCont |= 0x01;
		break;
	case DPMSModeSuspend:
		/* Screen: Off, HSync: On, VSync: Off */
		PMCont |= 0x02;
		DPMSCont |= 0x02;
		break;
	case DPMSModeOff:
		/* Screen: Off, HSync: Off, VSync: Off */
		PMCont |= 0x00;
		DPMSCont |= 0x03;
		break;
    }
    OUTB(0x3CF, DPMSCont);
    OUTB(0x83C8, 0x04);
    OUTB(0x83C6, PMCont);
    OUTW(0x3C4, (temp<<8) | 0x0E);
}

static void
TRIDENTBlockHandler (
    int i,
    pointer     blockData,
    pointer     pTimeout,
    pointer     pReadmask
){
    ScreenPtr      pScreen = screenInfo.screens[i];
    ScrnInfoPtr    pScrn = xf86Screens[i];
    TRIDENTPtr     pTrident = TRIDENTPTR(pScrn);

    pScreen->BlockHandler = pTrident->BlockHandler;
    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
    pScreen->BlockHandler = TRIDENTBlockHandler;

    if(pTrident->VideoTimerCallback) {
	UpdateCurrentTime();
	(*pTrident->VideoTimerCallback)(pScrn, currentTime.milliseconds);
    }
} 

static const OptionInfoRec *
TRIDENTAvailableOptions(int chipid, int busid)
{
    return TRIDENTOptions;
}

/* Mandatory */
static void
TRIDENTIdentify(int flags)
{
    xf86PrintChipsets(TRIDENT_NAME, "driver for Trident chipsets", TRIDENTChipsets);
}

static void
TRIDENTFix1bpp(ScrnInfoPtr pScrn) {
   vgaHWPtr hwp = VGAHWPTR(pScrn);
/* In 1 bpp we have color 0 at LUT 0 and color 1 at LUT 0x3f.
   This makes white and black look right (otherwise they were both
   black. I'm sure there's a better way to do that, just lazy to
   search the docs.  */

   (*hwp->writeDacWriteAddr)(hwp, 0x00);
   (*hwp->writeDacData)(hwp, 0x00);
   (*hwp->writeDacData)(hwp, 0x00);
   (*hwp->writeDacData)(hwp, 0x00);

   (*hwp->writeDacWriteAddr)(hwp, 0x3F);
   (*hwp->writeDacData)(hwp, 0x3F);
   (*hwp->writeDacData)(hwp, 0x3F);
   (*hwp->writeDacData)(hwp, 0x3F);
}

Bool
TRIDENTClockSelect(ScrnInfoPtr pScrn, int no)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    unsigned char temp;

    /*
     * CS0 and CS1 are in MiscOutReg
     *
     * For 8900B, 8900C, 8900CL and 9000, CS2 is bit 0 of
     * New Mode Control Register 2.
     *
     * For 8900CL, CS3 is bit 4 of Old Mode Control Register 1.
     *
     * For 9000, CS3 is bit 6 of New Mode Control Register 2.
     *
     * For TGUI, we don't use the ClockSelect function at all.
     */
     switch(no) {
	case CLK_REG_SAVE:
	    pTrident->SaveClock1 = INB(0x3CC);
	    if (pTrident->Chipset != TVGA8800CS) {
		if ( (pScrn->numClocks == 16) && 
		     (pTrident->Chipset != TVGA9000) &&
		     (pTrident->Chipset != TVGA9000i) )
		{
		    OUTW(0x3C4, 0x000B);	/* Switch to Old Mode */
		    OUTB(0x3C4, 0x0E); pTrident->SaveClock3 = INB(0x3C5);
		}
		OUTB(0x3C4, 0x0B);	
		INB(0x3C5);		/* Now to New Mode */
		OUTB(0x3C4, 0x0D); pTrident->SaveClock2 = INB(0x3C5);
	    }
	    break;
	case CLK_REG_RESTORE:
	    OUTB(0x3C2, pTrident->SaveClock1);
	    if (pTrident->Chipset != TVGA8800CS) {
		if ( (pScrn->numClocks == 16) && 
		     (pTrident->Chipset != TVGA9000) &&
		     (pTrident->Chipset != TVGA9000i) )
		{
			OUTW(0x3C4, 0x000B);	/* Switch to Old Mode */
			OUTW(0x3C4, (pTrident->SaveClock3 << 8) | 0x0E);
		}
		OUTB(0x3C4, 0x0B);	
		INB(0x3C5);		/* Now to New Mode */
		OUTW(0x3C4, (pTrident->SaveClock2 << 8) | 0x0D); 
	    }
	    break;
	default:
	    /*
	     * Do CS0 and CS1
	     */
	    temp = INB(0x3CC);
	    OUTB(0x3C2, (temp & 0xF3) | ((no << 2) & 0x0C));
	    if (pTrident->Chipset != TVGA8800CS) {
		if ( (pScrn->numClocks == 16) && 
		     (pTrident->Chipset != TVGA9000) &&
		     (pTrident->Chipset != TVGA9000i) )
		{
			/* 
			 * Go to Old Mode for CS3.
		 	 */
			OUTW(0x3C4, 0x000B);	/* Switch to Old Mode */
			OUTB(0x3C4, 0x0E);
			temp = INB(0x3C5) & 0xEF;
			temp |= (no & 0x08) << 1;
			OUTB(0x3C5, temp);
		}
		/* 
	  	 * Go to New Mode for CS2 and TVGA9000 CS3.
	  	 */
		OUTB(0x3C4, 0x0B);
		INB(0x3C5);		/* Now to New Mode */
		OUTB(0x3C4, 0x0D);
		/*
		 * Bits 1 & 2 are dividers - set to 0 to get no
		 * clock division.
		 */
		temp = INB(0x3C5) & 0xF8;
		temp |= (no & 0x04) >> 2;
		if ( (pTrident->Chipset == TVGA9000) ||
		     (pTrident->Chipset == TVGA9000i) )
		{
			temp &= ~0x40;
			temp |= (no & 0x08) << 3;
		}
		OUTB(0x3C5, temp);
	}
    }
    return(TRUE);
}

static int
TridentFindIsaDevice(GDevPtr dev)
{
    int found = -1;
    unsigned char temp, origVal, newVal;

    /* 
     * Check first that we have a Trident card.
     */
    outb(0x3C4, 0x0B);
    temp = inb(0x3C5);	/* Save old value */
    outb(0x3C4, 0x0B);	/* Switch to Old Mode */
    outb(0x3C5, 0x00);
    inb(0x3C5);		/* Now to New Mode */
    outb(0x3C4, 0x0E);
    origVal = inb(0x3C5);
    outb(0x3C5, 0x00);
    newVal = inb(0x3C5) & 0x0F;
    outb(0x3C5, (origVal ^ 0x02));

    /* 
     * Is it a Trident card ?? 
     */
    if (newVal != 2) {
	/*
	 * Nope, so quit
	 */
	outb(0x3C4, 0x0B);	/* Restore value of 0x0B */
	outb(0x3C5, temp);
	outb(0x3C4, 0x0E);
	outb(0x3C5, origVal);
	return found;
    }

    outb(0x3C4, 0x0B);
    temp = inb(0x3C5);
    switch (temp) {
	case 0x01:
	    found = TVGA8800BR;
	    break;
	case 0x02:
	    found = TVGA8800CS;
	    break;
	case 0x03:
	    found = TVGA8900B;
	    break;
	case 0x04:
	case 0x13:
	    found = TVGA8900C;
	    break;
	case 0x23:
	    found = TVGA9000;
	    break;
	case 0x33:
	    found = TVGA8900D;
	    break;
	case 0x43:
	    found = TVGA9000i;
	    break;
	case 0x53:
	    found = TVGA9200CXr;
	    break;
	case 0x63:
	    found = TVGA9100B;
	    break;
	case 0x73:
	case 0xC3:
	    found = TGUI9420DGi;
	    break;
	case 0x83:
	    found = TVGA8200LX;
	    break;
	case 0x93:
	    found = TGUI9400CXi;
	    break;
	case 0xA3:
	    found = CYBER9320;
	    break;
	case 0xD3:
	    found = TGUI9660;
	    break;
	case 0xE3:
	    found = TGUI9440AGi;
	    break;
	case 0xF3:
	    found = TGUI9430DGi;
	    break;
    }
    return found;
}


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

    if ((numDevSections = xf86MatchDevice(TRIDENT_DRIVER_NAME,
					  &devSections)) <= 0) {
	/*
	 * There's no matching device section in the config file, so quit
	 * now.
	 */
	return FALSE;
    }

    /*
     * While we're VGA-dependent, can really only have one such instance, but
     * we'll ignore that.
     */

    /*
     * We need to probe the hardware first.  We then need to see how this
     * fits in with what is given in the config file, and allow the config
     * file info to override any contradictions.
     */

    /*
     * All of the cards this driver supports are PCI, so the "probing" just
     * amounts to checking the PCI data that the server has already collected.
     */
    if (xf86GetPciVideoInfo()) {
    	numUsed = xf86MatchPciInstances(TRIDENT_NAME, PCI_VENDOR_TRIDENT,
		   TRIDENTChipsets, TRIDENTPciChipsets, devSections,
		   numDevSections, drv, &usedChips);

	if (numUsed > 0) {
	    if (flags & PROBE_DETECT)
		foundScreen = TRUE;
	    else for (i = 0; i < numUsed; i++) {
		ScrnInfoPtr pScrn = NULL;
		
		if ((pScrn = xf86ConfigPciEntity(pScrn, 0,usedChips[i],
						       TRIDENTPciChipsets, NULL,
						       NULL, NULL, NULL, NULL))) {
		    /* Fill in what we can of the ScrnInfoRec */
		    pScrn->driverVersion = VERSION;
		    pScrn->driverName	 = TRIDENT_DRIVER_NAME;
		    pScrn->name		 = TRIDENT_NAME;
		    pScrn->Probe	 = TRIDENTProbe;
		    pScrn->PreInit	 = TRIDENTPreInit;
		    pScrn->ScreenInit	 = TRIDENTScreenInit;
		    pScrn->SwitchMode	 = TRIDENTSwitchMode;
		    pScrn->AdjustFrame	 = TRIDENTAdjustFrame;
		    pScrn->EnterVT	 = TRIDENTEnterVT;
		    pScrn->LeaveVT	 = TRIDENTLeaveVT;
		    pScrn->FreeScreen	 = TRIDENTFreeScreen;
		    pScrn->ValidMode	 = TRIDENTValidMode;
		    foundScreen = TRUE;
		}
	    }
	    xfree(usedChips);
	}
    }

    /* Isa Bus */
    numUsed = xf86MatchIsaInstances(TRIDENT_NAME,TRIDENTChipsets,
				     TRIDENTISAchipsets,
				     drv,TridentFindIsaDevice,devSections,
				     numDevSections,&usedChips);
    if (numUsed > 0) {
	if (flags & PROBE_DETECT)
	    foundScreen = TRUE;
	else 	for (i = 0; i < numUsed; i++) {
	    ScrnInfoPtr pScrn = NULL;
	    if ((pScrn = xf86ConfigIsaEntity(pScrn,0,usedChips[i],
						  TRIDENTISAchipsets,NULL,
						  NULL,NULL,NULL,NULL))) {
		pScrn->driverVersion = VERSION;
		pScrn->driverName    = TRIDENT_DRIVER_NAME;
		pScrn->name          = TRIDENT_NAME;
		pScrn->Probe         = TRIDENTProbe;
		pScrn->PreInit       = TRIDENTPreInit;
		pScrn->ScreenInit    = TRIDENTScreenInit;
		pScrn->SwitchMode    = TRIDENTSwitchMode;
		pScrn->AdjustFrame   = TRIDENTAdjustFrame;
		pScrn->EnterVT       = TRIDENTEnterVT;
		pScrn->LeaveVT       = TRIDENTLeaveVT;
		pScrn->FreeScreen    = TRIDENTFreeScreen;
		pScrn->ValidMode     = TRIDENTValidMode;
		foundScreen = TRUE;
	    }
	}
	xfree(usedChips);
    }
    
    xfree(devSections);
    return foundScreen;
}
	
/*
 * GetAccelPitchValues -
 *
 * This function returns a list of display width (pitch) values that can
 * be used in accelerated mode.
 */
static int *
GetAccelPitchValues(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    int *linePitches = NULL;
    int lines[4] = { 512, 1024, 2048, 4096 }; /* 9440AGi */
    int i, n = 0;

    if (pTrident->Chipset >= BLADEXP) {
	lines[0] = 1024;
	lines[1] = 2048;
	lines[2] = 4096;
	lines[3] = 8192;
    }
	
    for (i = 0; i < 4; i++) {
	n++;
	linePitches = xnfrealloc(linePitches, n * sizeof(int));
	linePitches[n - 1] = lines[i];
    }

    /* Mark the end of the list */
    if (n > 0) {
	linePitches = xnfrealloc(linePitches, (n + 1) * sizeof(int));
	linePitches[n] = 0;
    }
    return linePitches;
}

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

/* Mandatory */
static Bool
TRIDENTPreInit(ScrnInfoPtr pScrn, int flags)
{
    TRIDENTPtr pTrident;
    vgaHWPtr hwp;
    MessageType from;
    CARD8 videoram, videorammask;
    char *ramtype = NULL, *chipset = NULL;
    Bool Support24bpp;
    int vgaIOBase;
    float mclk;
    double real;
    int i, NoClocks = 16;
    CARD8 revision;
    ClockRangePtr clockRanges;
    char *mod = NULL;
    const char *Sym = "";
    Bool ddcLoaded = FALSE;
    char *s;

    /* Allocate the TRIDENTRec driverPrivate */
    if (!TRIDENTGetRec(pScrn)) {
	return FALSE;
    }
    pTrident = TRIDENTPTR(pScrn);
    pTrident->pScrn = pScrn;

    if (pScrn->numEntities > 1)
	return FALSE;
    /* This is the general case */
    for (i = 0; i<pScrn->numEntities; i++) {
	pTrident->pEnt = xf86GetEntityInfo(pScrn->entityList[i]);
	if (pTrident->pEnt->resources) return FALSE;
	pTrident->Chipset = pTrident->pEnt->chipset;
	pScrn->chipset = (char *)xf86TokenToString(TRIDENTChipsets,
						   pTrident->pEnt->chipset);
	/* This driver can handle ISA and PCI buses */
	if (pTrident->pEnt->location.type == BUS_PCI) {
	    pTrident->PciInfo = xf86GetPciInfoForEntity(pTrident->pEnt->index);
	    pTrident->PciTag = pciTag(pTrident->PciInfo->bus, 
				  pTrident->PciInfo->device,
				  pTrident->PciInfo->func);
    	    pTrident->Linear = TRUE;
	} else {
    	    pTrident->Linear = FALSE;
	}
    }

    if (flags & PROBE_DETECT) {
	TRIDENTProbeDDC(pScrn, pTrident->pEnt->index);
	return TRUE;
    }

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

    /*
     * The first thing we should figure out is the depth, bpp, etc.
     * Our preference for depth 24 is 24bpp, so tell it that too.
     */
    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb |
			    SupportConvert32to24 /*| PreferConvert32to24*/)) {
	return FALSE;
    } else {
	/* Check that the returned depth is one we support */
	switch (pScrn->depth) {
	case 1:
	case 4:
	case 8:
	    if (pScrn->bitsPerPixel != pScrn->depth) {
	        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
	     "Given depth (%d)/ fbbpp (%d) is not supported by this driver\n",
		       pScrn->depth, pScrn->bitsPerPixel);
		return FALSE;
	    }
	    break;
	case 15:
	case 16:
	    if (pScrn->bitsPerPixel != 16) {
	        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
	     "Given depth (%d)/ fbbpp (%d) is not supported by this driver\n",
		       pScrn->depth, pScrn->bitsPerPixel);
		return FALSE;
	    }
	    break;
	case 24:
	    if ((pScrn->bitsPerPixel != 24) && (pScrn->bitsPerPixel != 32)) {
	        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
	     "Given depth (%d)/ fbbpp (%d) is not supported by this driver\n",
		       pScrn->depth, pScrn->bitsPerPixel);
		return FALSE;
	    }
	    /* OK */
	    break;
	default:
	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
		       "Given depth (%d) is not supported by this driver\n",
		       pScrn->depth);
	    return FALSE;
	}
    }

    xf86PrintDepthBpp(pScrn);

    /* Get the depth24 pixmap format */
    if (pScrn->depth == 24 && pix24bpp == 0)
	pix24bpp = xf86GetBppFromDepth(pScrn, 24);

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

    xf86LoaderReqSymLists(vgahwSymbols, NULL);

    /*
     * Allocate a vgaHWRec
     */
    if (!vgaHWGetHWRec(pScrn))
	return FALSE;

    hwp = VGAHWPTR(pScrn);
    vgaHWGetIOBase(hwp);
    vgaIOBase = hwp->IOBase;
    pTrident->PIOBase = hwp->PIOOffset;

    xf86SetOperatingState(resVga, pTrident->pEnt->index, ResUnusedOpr);

    /* The ramdac module should be loaded here when needed */
    if (!xf86LoadSubModule(pScrn, "ramdac"))
	return FALSE;

    xf86LoaderReqSymLists(ramdacSymbols, NULL);

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

	if (!xf86SetWeight(pScrn, zeros, zeros)) {
	    return FALSE;
	} else {
	    /* XXX check that weight returned is supported */
            ;
        }
    }

    if (!xf86SetDefaultVisual(pScrn, -1)) {
	return FALSE;
    } else {
	/* 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);
	    return FALSE;
	}
    }

    /*
     * The new cmap layer needs this to be initialised.
     */

    {
	Gamma zeros = {0.0, 0.0, 0.0};

	if (!xf86SetGamma(pScrn, zeros)) {
	    return FALSE;
	}
    }

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

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

    /* Set the bits per RGB for 8bpp mode */
    if (pScrn->depth <= 8) {
	/* XXX This is here just to test options. */
	/* Default to 8 */
	pScrn->rgbBits = 6;
#if 0
	if (xf86GetOptValInteger(pTrident->Options, OPTION_RGB_BITS,
				 &pScrn->rgbBits)) {
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Bits per RGB set to %d\n",
		       pScrn->rgbBits);
	}
#endif
    }
    from = X_DEFAULT;
    pTrident->HWCursor = TRUE;
    if (xf86ReturnOptValBool(pTrident->Options, OPTION_SW_CURSOR, FALSE)) {
	from = X_CONFIG;
	pTrident->HWCursor = FALSE;
    }
    if (xf86ReturnOptValBool(pTrident->Options, OPTION_NOACCEL, FALSE)) {
	pTrident->NoAccel = TRUE;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
    }
    if (xf86ReturnOptValBool(pTrident->Options, OPTION_PCI_RETRY, FALSE)) {
	pTrident->UsePCIRetry = TRUE;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry enabled\n");
    }
    pTrident->UsePCIBurst = TRUE;
    if (xf86ReturnOptValBool(pTrident->Options, OPTION_NOPCIBURST, FALSE)) {
	pTrident->UsePCIBurst = FALSE;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI Burst disbled\n");
    }
    if (xf86ReturnOptValBool(pTrident->Options, OPTION_1400_DISPLAY, FALSE)) {
	pTrident->displaySize = 1400;
    }
    if(xf86GetOptValInteger(pTrident->Options, OPTION_VIDEO_KEY,
						&(pTrident->videoKey))) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n",
							pTrident->videoKey);
    } else {
	pTrident->videoKey =  (1 << pScrn->offset.red) | 
			(1 << pScrn->offset.green) |
			(((pScrn->mask.blue >> pScrn->offset.blue) - 1)
			<< pScrn->offset.blue); 
    }
    if (xf86ReturnOptValBool(pTrident->Options, OPTION_NOMMIO, FALSE)) {
	pTrident->NoMMIO = TRUE;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "MMIO Disabled\n");
    }
    if (xf86ReturnOptValBool(pTrident->Options, OPTION_MMIO_ONLY, FALSE)) {
	if (pTrident->NoMMIO)
	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "MMIO only cannot be set"
		       " with NoMMIO\n");
	else {
	    pTrident->MMIOonly = TRUE;
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "MMIO only enabled\n");
	}
    }
    
    pTrident->dspOverride = 0;
    if ((s = xf86GetOptValString(pTrident->Options, OPTION_DISPLAY))) {
	if(!xf86NameCmp(s, "CRT")) {
	    pTrident->dspOverride = CRT_ACTIVE;
	    xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"LCD off CRT on\n");
	} else if (!xf86NameCmp(s, "LCD")) {
	    pTrident->dspOverride = LCD_ACTIVE;
	    xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"LCD on CRT off\n");
	} else if (!xf86NameCmp(s, "Dual")) {
	    pTrident->dspOverride = LCD_ACTIVE | CRT_ACTIVE;
	    xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"LCD on CRT on\n");
	} else 
	    xf86DrvMsg(pScrn->scrnIndex,X_ERROR,
		       "%s is an unknown display option\n",s);
    }
    if ((s = xf86GetOptValString(pTrident->Options, OPTION_GB))) {
	int brightness = -1;
	double gamma = -1.0;
	Bool error = FALSE;
	int i;
	
	i = sscanf(s,"%lf %i",&gamma,&brightness);
	
	if (i != 2 || brightness == -1 || gamma == -1.0) {
	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
		       "Invalid Gamma/Brightness argument: %s\n",s);
	    error = TRUE;
	} else {
	    if (brightness < 0 || brightness > 128) {
		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
			   "brightness out of range [0,128]: %i\n",brightness);
		error = TRUE;
	    }
	    if (gamma <= 0.0 || gamma > 10.0) {
		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
			   "gamma out of range (0,10.0]: %f\n",gamma);
		error = TRUE;
	    }
	}
	
	if (!error) {
	    pTrident->GammaBrightnessOn = TRUE;
	    pTrident->gamma = gamma;
	    pTrident->brightness = brightness;
	    xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"Gamma: %f Brightness: %i\n",
		       gamma,brightness);
	}
    }

    /* The following is a temporary hack */
    pTrident->FPDelay = 7; /* invalid value */
    if (xf86GetOptValInteger(pTrident->Options, OPTION_FP_DELAY,
			     &pTrident->FPDelay)) {
	if (pTrident->FPDelay < -2 || pTrident->FPDelay > 5) {
	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "FPDelay %i out if range "
		       "(-2 < FPDelay < 5)\n",pTrident->FPDelay);
	    pTrident->FPDelay = 7;
	} else 
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "FP Delay set to %i\n",
		   pTrident->FPDelay);
    }
    if (xf86ReturnOptValBool(pTrident->Options, OPTION_CYBER_SHADOW, FALSE)) {
	pTrident->CyberShadow = TRUE;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Cyber Shadow enabled\n");
    }
    if (xf86ReturnOptValBool(pTrident->Options, OPTION_CYBER_STRETCH, FALSE)) {
	pTrident->CyberStretch = TRUE;
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Cyber Stretch enabled\n");
    }

    pTrident->MUXThreshold = 90000; /* 90MHz */
    if (xf86GetOptValInteger(pTrident->Options, OPTION_MUX_THRESHOLD, 
						&pTrident->MUXThreshold)) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "MUX Threshold set to %d\n",
						pTrident->MUXThreshold);
    }
    pTrident->OverrideHsync = 0;
    if (xf86GetOptValInteger(pTrident->Options, OPTION_XV_HSYNC, 
						&pTrident->OverrideHsync)) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Xv Hsync set to %d\n",
						pTrident->OverrideHsync);
    }
    pTrident->OverrideVsync = 0;
    if (xf86GetOptValInteger(pTrident->Options, OPTION_XV_VSYNC, 
						&pTrident->OverrideVsync)) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Xv Vsync set to %d\n",
						pTrident->OverrideVsync);
    }
    pTrident->OverrideHsync = 0;
    if (xf86GetOptValInteger(pTrident->Options, OPTION_XV_HSYNC, 
						&pTrident->OverrideHsync)) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Xv Hsync set to %d\n",
						pTrident->OverrideHsync);
    }
    pTrident->OverrideVsync = 0;
    if (xf86GetOptValInteger(pTrident->Options, OPTION_XV_VSYNC, 
						&pTrident->OverrideVsync)) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Xv Vsync set to %d\n",
						pTrident->OverrideVsync);
    }
    pTrident->OverrideRskew = 0;
    if (xf86GetOptValInteger(pTrident->Options, OPTION_XV_RSKEW, 
						&pTrident->OverrideRskew)) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Xv Rskew set to %d\n",
						pTrident->OverrideRskew);
    }
    pTrident->OverrideBskew = 0;
    if (xf86GetOptValInteger(pTrident->Options, OPTION_XV_BSKEW, 
						&pTrident->OverrideBskew)) {
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Xv Bskew set to %d\n",
						pTrident->OverrideBskew);
    }
    if (xf86ReturnOptValBool(pTrident->Options, OPTION_SHADOW_FB, FALSE)) {
        if (!pTrident->Linear) 
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring Option SHADOW_FB"
		       " in non-Linear Mode\n");
	else if (pScrn->depth < 8) 
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Tgnoring Option SHADOW_FB"
		       " when depth < 8");
	else {
	    pTrident->ShadowFB = TRUE;
	    pTrident->NoAccel = TRUE;
	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
		    "Using \"Shadow Framebuffer\" - acceleration disabled\n");
	}
    }
    pTrident->Rotate = 0;
    if ((s = xf86GetOptValString(pTrident->Options, OPTION_ROTATE))) {
        if (!pTrident->Linear) 
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring Option ROTATE "
		       "in non-Linear Mode\n");
	else if (pScrn->depth < 8) 
	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring Option ROTATE "
		       "when depth < 8");
	else {
	    if(!xf86NameCmp(s, "CW")) {
	        /* accel is disabled below for shadowFB */
	        pTrident->ShadowFB = TRUE;
		pTrident->NoAccel = TRUE;
		pTrident->HWCursor = FALSE;
		pTrident->Rotate = 1;
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 
		       "Rotating screen clockwise - acceleration disabled\n");
	    } else if(!xf86NameCmp(s, "CCW")) {
 	        pTrident->ShadowFB = TRUE;
		pTrident->NoAccel = TRUE;
		pTrident->HWCursor = FALSE;
		pTrident->Rotate = -1;
		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,  "Rotating screen"
			   "counter clockwise - acceleration disabled\n");
	    } else {
	        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
			   "value for Option \"Rotate\"\n", s);
		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
			   "Valid options are \"CW\" or \"CCW\"\n");
	    }
	}
    }

    pTrident->TVChipset = 0;
    if ((s = xf86GetOptValString(pTrident->Options, OPTION_TV_CHIPSET))) {
	if(!xf86NameCmp(s, "VT1621")) {
	    pTrident->TVChipset = 1;
	    xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"Using VIA VT1621 TV chip\n");
	} else if (!xf86NameCmp(s, "CH7005")) {
	    pTrident->TVChipset = 2;
	    xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"Using Chrontel CH7005 TV chip\n");
	} else 
	    xf86DrvMsg(pScrn->scrnIndex,X_ERROR,
		       "%s is an unknown TV chipset option\n",s);
    }
    /* Default : NTSC */
    pTrident->TVSignalMode=0;
    if (xf86GetOptValInteger(pTrident->Options, OPTION_TV_SIGNALMODE,
						&pTrident->TVSignalMode)) {
	ErrorF("TV SignalMode set to %d\n",pTrident->TVSignalMode);
    }

    /* FIXME ACCELERATION */
    if (!UseMMIO) pTrident->NoAccel = TRUE;

    if (pTrident->Linear) {
    	if (pTrident->pEnt->device->MemBase != 0) {
	    /*
	     * XXX Should check that the config file value matches one of the
	     * PCI base address values.
	     */
	    pTrident->FbAddress = pTrident->pEnt->device->MemBase;
	    from = X_CONFIG;
    	} else {
    	    if (IsPciCard)
	    	pTrident->FbAddress = pTrident->PciInfo->memBase[0]& 0xFFFFFFF0;
	    else
	    	pTrident->FbAddress = 0xA0000;
    	}

    	xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
	       (unsigned long)pTrident->FbAddress);
    }

    if (UseMMIO) {
    	if (pTrident->pEnt->device->IOBase != 0) {
	    /*
	     * XXX Should check that the config file value matches one of the
	     * PCI base address values.
	     */
	    pTrident->IOAddress = pTrident->pEnt->device->IOBase;
	    from = X_CONFIG;
    	} else {
    	    if (IsPciCard)
	    	pTrident->IOAddress = pTrident->PciInfo->memBase[1]& 0xFFFFC000;
	    else
	    	/* FIXME - Multihead UNAWARE */
    	    	pTrident->IOAddress = 0xBF000;
    	}

    	xf86DrvMsg(pScrn->scrnIndex,X_PROBED,"IO registers at 0x%lX\n",
		   (unsigned long)pTrident->IOAddress);
    }

    /* Register the PCI-assigned resources. */
    if (xf86RegisterResources(pTrident->pEnt->index, NULL, ResExclusive)) {
	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
		   "xf86RegisterResources() found resource conflicts\n");
	return FALSE;
    }

    /* Initialize VBE if possible 
     * Don't move this past MMIO enable!!
     * PIO access will be blocked
     * when MMIO is turned on!
     */

    if (xf86LoadSubModule(pScrn, "vbe")) {
	xf86MonPtr pMon;
	vbeInfoPtr pVbe;

        xf86LoaderReqSymLists(vbeSymbols, NULL);
	pVbe =  VBEInit(NULL,pTrident->pEnt->index);
	pMon = vbeDoEDID(pVbe, NULL);
#ifdef VBE_INFO
	{
	    VbeInfoBlock* vbeInfoBlockPtr;
	    if ((vbeInfoBlockPtr = VBEGetVBEInfo(pVbe))) {
		pTrident->vbeModes = VBEBuildVbeModeList(pVbe,vbeInfoBlockPtr);
		VBEFreeVBEInfo(vbeInfoBlockPtr);
	    }
	}
#endif
	vbeFree(pVbe);
	if (pMon) {
	    if (!xf86LoadSubModule(pScrn, "ddc")) {
		TRIDENTFreeRec(pScrn);
		return FALSE;
	    } else {
		xf86LoaderReqSymLists(ddcSymbols, NULL);
		xf86SetDDCproperties(pScrn,xf86PrintEDID(pMon));
		ddcLoaded = TRUE;
	    }
	}
	    
    }
    
    if (IsPciCard && UseMMIO) {
    	if (!TRIDENTMapMem(pScrn))
	    return FALSE;

    	TRIDENTEnableMMIO(pScrn);
    }

    OUTB(0x3C4, RevisionID); revision = INB(0x3C5);
    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Revision is %d\n",revision);

    pScrn->progClock = TRUE;
    pTrident->EngineOperation = 0x00;
    pTrident->IsCyber = FALSE;
    pTrident->HasSGRAM = FALSE;
    pTrident->NewClockCode = FALSE;
    pTrident->MUX = FALSE;
    Support24bpp = FALSE;

    OUTB(vgaIOBase + 4, InterfaceSel);

    switch (pTrident->Chipset) {
	case TVGA9000:
	case TVGA9000i:
	    pScrn->progClock = FALSE;
	    NoClocks = 16;
	    pTrident->NoMMIO = TRUE;
	    pTrident->NoAccel = TRUE;
	    pTrident->HWCursor = FALSE;
	    chipset = "TVGA9000/9000i";
	    ramtype = "Standard DRAM";
	    if (pTrident->UsePCIRetry)
	    	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry not supported, disabling\n");
	    pTrident->UsePCIRetry = FALSE; /* Not Supported */
	    pTrident->frequency = NTSC;
	    break;
	case TVGA9100B:
	    pScrn->progClock = FALSE;
	    NoClocks = 8;
	    pTrident->NoMMIO = TRUE;
	    pTrident->NoAccel = TRUE;
	    pTrident->HWCursor = FALSE;
	    chipset = "TVGA9100B";
	    ramtype = "Standard DRAM";
	    if (pTrident->UsePCIRetry)
	    	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry not supported, disabling\n");
	    pTrident->UsePCIRetry = FALSE; /* Not Supported */
	    pTrident->frequency = NTSC;
	    break;
	case TVGA8900B:
	    pScrn->progClock = FALSE;
	    NoClocks = 8;
	    pTrident->NoMMIO = TRUE;
	    pTrident->NoAccel = TRUE;
	    pTrident->HWCursor = FALSE;
	    chipset = "TVGA8900B";
	    ramtype = "Standard DRAM";
	    if (pTrident->UsePCIRetry)
	    	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry not supported, disabling\n");
	    pTrident->UsePCIRetry = FALSE; /* Not Supported */
	    pTrident->frequency = NTSC;
	    break;
	case TVGA8900C:
	    pScrn->progClock = FALSE;
	    NoClocks = 16;
	    pTrident->NoMMIO = TRUE;
	    pTrident->NoAccel = TRUE;
	    pTrident->HWCursor = FALSE;
	    chipset = "TVGA8900C";
	    ramtype = "Standard DRAM";
	    if (pTrident->UsePCIRetry)
	    	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry not supported, disabling\n");
	    pTrident->UsePCIRetry = FALSE; /* Not Supported */
	    pTrident->frequency = NTSC;
	    break;
	case TVGA8900D:
	    pScrn->progClock = FALSE;
	    NoClocks = 16;
	    pTrident->NoMMIO = TRUE;
	    pTrident->NoAccel = TRUE;
	    pTrident->HWCursor = FALSE;
	    chipset = "TVGA8900D";
	    ramtype = "Standard DRAM";
	    if (pTrident->UsePCIRetry)
	    	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry not supported, disabling\n");
	    pTrident->UsePCIRetry = FALSE; /* Not Supported */
	    pTrident->frequency = NTSC;
	    break;
	case TVGA9200CXr:
	    pScrn->progClock = FALSE;
	    NoClocks = 16;
	    pTrident->NoMMIO = TRUE;
	    pTrident->NoAccel = TRUE;
	    pTrident->HWCursor = FALSE;
	    chipset = "TVGA9200CXr";
	    ramtype = "Standard DRAM";
	    if (pTrident->UsePCIRetry)
	    	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry not supported, disabling\n");
	    pTrident->UsePCIRetry = FALSE; /* Not Supported */
	    pTrident->frequency = NTSC;
	    break;
	case TGUI9400CXi:
	    pScrn->progClock = FALSE;
	    NoClocks = 16;
	    pTrident->NoMMIO = TRUE;
	    pTrident->NoAccel = TRUE;
	    pTrident->HWCursor = FALSE;
	    chipset = "TVGA9200CXr";
	    ramtype = "Standard DRAM";
	    if (pTrident->UsePCIRetry)
	    	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry not supported, disabling\n");
	    pTrident->UsePCIRetry = FALSE; /* Not Supported */
	    pTrident->frequency = NTSC;
	    break;
	case TGUI9440AGi:
    	    pTrident->ddc1Read = Tridentddc1Read;
	    pTrident->HWCursor = FALSE;
	    chipset = "TGUI9440AGi";
	    ramtype = "Standard DRAM";
	    if (pTrident->UsePCIRetry)
	    	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry not supported, disabling\n");
	    pTrident->UsePCIRetry = FALSE; /* Not Supported */
	    pTrident->frequency = NTSC;
	    break;
	case CYBER9320:
    	    pTrident->ddc1Read = Tridentddc1Read;
	    chipset = "Cyber9320";
	    ramtype = "Standard DRAM";
	    if (pTrident->UsePCIRetry)
	    	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry not supported, disabling\n");
	    pTrident->UsePCIRetry = FALSE; /* Not Supported */
	    break;
	/* Trident didn't update the PCI ID's and so we have to detemine 
	 * which chips are right ! Then override pTrident->Chipset to 
	 * correct values */
	case TGUI9660:
    	    pTrident->ddc1Read = Tridentddc1Read;
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x04)
		ramtype = "EDO Ram";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x0C)
		ramtype = "Standard DRAM";
	    switch (revision) {
		case 0x00:
		    chipset = "TGUI9660";
		    pTrident->Chipset = TGUI9660;
		    if (pTrident->UsePCIRetry)
		    	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry not supported, disabling\n");
		    pTrident->UsePCIRetry = FALSE; /* Not Supported */
		    break;
		case 0x01:
		    chipset = "TGUI9680";
		    pTrident->Chipset = TGUI9680;
		    if (pTrident->UsePCIRetry)
		    	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry not supported, disabling\n");
		    pTrident->UsePCIRetry = FALSE; /* Not Supported */
		    break;
		case 0x10:
		    chipset = "ProVidia 9682";
		    Support24bpp = TRUE;
		    pTrident->Chipset = PROVIDIA9682;
		    break;
		case 0x21:
		    chipset = "ProVidia 9685";
		    Support24bpp = TRUE;
		    pTrident->NewClockCode = TRUE;
		    pTrident->Chipset = PROVIDIA9685;
		    break;
		case 0x22:
		case 0x23:
		    chipset = "Cyber 9397";
    	    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x04)
			ramtype = "EDO Ram";
    	    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x08)
			ramtype = "SDRAM";
    	    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x0C) {
			pTrident->HasSGRAM = TRUE;
			ramtype = "SGRAM";
	    	    }
		    pTrident->NewClockCode = TRUE;
		    pTrident->Chipset = CYBER9397;
		    pTrident->IsCyber = TRUE;
		    break;
		case 0x2a:
		    chipset = "Cyber 9397/DVD";
    	    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x04)
			ramtype = "EDO Ram";
    	    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x08)
			ramtype = "SDRAM";
    	    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x0C) {
			pTrident->HasSGRAM = TRUE;
			ramtype = "SGRAM";
	    	    }
		    pTrident->NewClockCode = TRUE;
		    pTrident->Chipset = CYBER9397DVD;
		    pTrident->IsCyber = TRUE;
		    break;
		case 0x30:
		case 0x33:
		case 0x34:
		case 0x35:
		case 0xB3:
		    chipset = "Cyber 9385";
		    pTrident->NewClockCode = TRUE;
		    pTrident->Chipset = CYBER9385;
		    pTrident->IsCyber = TRUE;
		    break;
		case 0x38:
		case 0x3A:
		    chipset = "Cyber 9385-1";
		    pTrident->NewClockCode = TRUE;
		    pTrident->Chipset = CYBER9385;
		    pTrident->IsCyber = TRUE;
		    break;
		case 0x40:
		case 0x41:
		case 0x42:
		case 0x43:
		    chipset = "Cyber 9382";
		    pTrident->NewClockCode = TRUE;
		    pTrident->Chipset = CYBER9382;
		    pTrident->IsCyber = TRUE;
		    break;
		case 0x4A:
		    chipset = "Cyber 9388";
    	    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x04)
			ramtype = "EDO Ram";
    	    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x08)
			ramtype = "SDRAM";
    	    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x0C) {
			pTrident->HasSGRAM = TRUE;
			ramtype = "SGRAM";
	    	    }
		    pTrident->NewClockCode = TRUE;
		    pTrident->Chipset = CYBER9388;
		    pTrident->IsCyber = TRUE;
		    break;
		default:
		    chipset = "Unknown";
		    pTrident->Chipset = TGUI9660;
		    break;
	    }
	    break;
	case CYBER9388:
    	    pTrident->ddc1Read = Tridentddc1Read;
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x04)
		ramtype = "EDO Ram";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x08)
		ramtype = "SDRAM";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x0C) {
		pTrident->HasSGRAM = TRUE;
		ramtype = "SGRAM";
	    }
	    pTrident->IsCyber = TRUE;
	    Support24bpp = TRUE;
	    chipset = "Cyber 9388";
	    pTrident->NewClockCode = TRUE;
	    break;
	case CYBER9397:
    	    pTrident->ddc1Read = Tridentddc1Read;
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x04)
		ramtype = "EDO Ram";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x08)
		ramtype = "SDRAM";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x0C) {
		pTrident->HasSGRAM = TRUE;
		ramtype = "SGRAM";
	    }
	    pTrident->IsCyber = TRUE;
	    Support24bpp = TRUE;
	    chipset = "Cyber 9397";
	    pTrident->NewClockCode = TRUE;
	    break;
	case CYBER9397DVD:
    	    pTrident->ddc1Read = Tridentddc1Read;
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x04)
		ramtype = "EDO Ram";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x08)
		ramtype = "SDRAM";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x0C) {
		pTrident->HasSGRAM = TRUE;
		ramtype = "SGRAM";
	    }
	    pTrident->IsCyber = TRUE;
	    Support24bpp = TRUE;
	    chipset = "Cyber 9397/DVD";
	    pTrident->NewClockCode = TRUE;
	    break;
	case CYBER9520:
    	    pTrident->ddc1Read = Tridentddc1Read;
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x04)
		ramtype = "EDO Ram";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x08)
		ramtype = "SDRAM";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x0C) {
		pTrident->HasSGRAM = TRUE;
		ramtype = "SGRAM";
	    }
	    pTrident->IsCyber = TRUE;
	    Support24bpp = TRUE;
	    chipset = "Cyber 9520";
	    pTrident->NewClockCode = TRUE;
	    break;
	case CYBER9525DVD:
    	    pTrident->ddc1Read = Tridentddc1Read;
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x04)
		ramtype = "EDO Ram";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x08)
		ramtype = "SDRAM";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x0C) {
		pTrident->HasSGRAM = TRUE;
		ramtype = "SGRAM";
	    }
	    pTrident->IsCyber = TRUE;
	    Support24bpp = TRUE;
	    chipset = "Cyber 9525/DVD";
	    pTrident->NewClockCode = TRUE;
	    break;
	case CYBERBLADEE4:
    	    pTrident->ddc1Read = Tridentddc1Read;
	    ramtype = "SDRAM";
	    pTrident->IsCyber = TRUE;
	    Support24bpp = TRUE;
	    chipset = "CyberBlade e4/128";
	    pTrident->NewClockCode = TRUE;
	    break;
	case IMAGE975:
    	    pTrident->ddc1Read = Tridentddc1Read;
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x04)
		ramtype = "EDO Ram";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x08)
		ramtype = "SDRAM";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x0C) {
		pTrident->HasSGRAM = TRUE;
		ramtype = "SGRAM";
	    }
	    Support24bpp = TRUE;
	    chipset = "3DImage975";
	    pTrident->NewClockCode = TRUE;
	    break;
	case IMAGE985:
    	    pTrident->ddc1Read = Tridentddc1Read;
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x04)
		ramtype = "EDO Ram";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x08)
		ramtype = "SDRAM";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x0C) {
		pTrident->HasSGRAM = TRUE;
		ramtype = "SGRAM";
	    }
	    Support24bpp = TRUE;
	    chipset = "3DImage985";
	    pTrident->NewClockCode = TRUE;
	    break;
	case BLADE3D:
    	    pTrident->ddc1Read = Tridentddc1Read;
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x08)
		ramtype = "SDRAM";
    	    if ((INB(vgaIOBase + 5) & 0x0C) == 0x0C) {
		pTrident->HasSGRAM = TRUE;
		ramtype = "SGRAM";
	    }
	    Support24bpp = TRUE;
	    chipset = "Blade3D";
	    pTrident->NewClockCode = TRUE;
	    pTrident->frequency = NTSC;
	    pTrident->UsePCIRetry = TRUE; /* To avoid lockups */
	    break;
	case CYBERBLADEI7:
    	    pTrident->ddc1Read = Tridentddc1Read;
	    ramtype = "SDRAM";
	    /* pTrident->IsCyber = TRUE; VIA MVP4 integrated Desktop version */
	    Support24bpp = TRUE;
	    chipset = "CyberBlade/i7/VIA MVP4";
	    pTrident->NewClockCode = TRUE;
	    pTrident->frequency = NTSC;
	    break;
	case CYBERBLADEI7D:
    	    pTrident->ddc1Read = Tridentddc1Read;
	    ramtype = "SDRAM";
	    pTrident->IsCyber = TRUE;
	    Support24bpp = TRUE;
	    chipset = "CyberBlade/DSTN/i7";
	    pTrident->NewClockCode = TRUE;
	    pTrident->frequency = NTSC;
	    break;
	case CYBERBLADEI1:
    	    pTrident->ddc1Read = Tridentddc1Read;
	    ramtype = "SDRAM";
	    pTrident->IsCyber = TRUE;
	    Support24bpp = TRUE;
	    chipset = "CyberBlade/i1";
	    pTrident->NewClockCode = TRUE;
	    pTrident->frequency = NTSC;
	    break;
	case CYBERBLADEI1D:
    	    pTrident->ddc1Read = Tridentddc1Read;
	    ramtype = "SDRAM";
	    pTrident->IsCyber = TRUE;
	    Support24bpp = TRUE;
	    chipset = "CyberBlade/DSTN/i1";
	    pTrident->NewClockCode = TRUE;
	    pTrident->frequency = NTSC;
	    break;
	case CYBERBLADEAI1:
    	    pTrident->ddc1Read = Tridentddc1Read;
	    ramtype = "SDRAM";
	    pTrident->IsCyber = TRUE;
	    Support24bpp = TRUE;
	    chipset = "CyberBlade/Ai1";
	    pTrident->NewClockCode = TRUE;
	    pTrident->frequency = NTSC;
	    break;
	case CYBERBLADEAI1D:
    	    pTrident->ddc1Read = Tridentddc1Read;
	    ramtype = "SDRAM";
	    pTrident->IsCyber = TRUE;
	    Support24bpp = TRUE;
	    chipset = "CyberBlade/DSTN/Ai1";
	    pTrident->NewClockCode = TRUE;
	    pTrident->frequency = NTSC;
	    break;
	case BLADEXP: /* 0x9910 */
	    pTrident->ddc1Read = Tridentddc1Read;
	    ramtype = "SGRAM";
	    pTrident->HasSGRAM = TRUE;
	    Support24bpp = TRUE;
	    pTrident->NewClockCode = TRUE;
	    pTrident->frequency = NTSC;
	    OUTB(0x3C4, 0x5D);
	    if (pTrident->PciInfo->subsysVendor != 0x1023) {
	    	chipset = "CyberBladeXP";
	    	pTrident->IsCyber = TRUE;
	    } else
	    if (!(INB(0x3C5) & 0x01)) {
	    	chipset = "BladeXP";
	    } else {
		CARD8 mem1, mem2;
		OUTB(vgaIOBase + 0x04, SPR);
		mem1 = INB(vgaIOBase + 5);
		OUTB(vgaIOBase + 0x04, 0xC1);
		mem2 = INB(vgaIOBase + 5);
		if ((mem1 & 0x0e) && (mem2 == 0x11)) {
	    	    chipset = "BladeT64";
		} else {
	    	    chipset = "BladeT16";
		}
	    }
	    break;
	case CYBERBLADEXPAI1:
    	    pTrident->ddc1Read = Tridentddc1Read;
	    ramtype = "SGRAM";
            pTrident->HasSGRAM = TRUE;
	    pTrident->IsCyber = TRUE;
	    pTrident->shadowNew = TRUE;
	    Support24bpp = TRUE;
	    chipset = "CyberBladeXPAi1";
	    pTrident->NewClockCode = TRUE;
	    pTrident->frequency = NTSC;
	    break;
	case CYBERBLADEXP4:
    	    pTrident->ddc1Read = Tridentddc1Read;
	    ramtype = "SGRAM";
            pTrident->HasSGRAM = TRUE;
	    pTrident->IsCyber = TRUE;
	    pTrident->shadowNew = TRUE;
	    pTrident->NoAccel = TRUE; /* for now */
	    Support24bpp = TRUE;
	    chipset = "CyberBladeXP4";
	    pTrident->NewClockCode = TRUE;
	    pTrident->frequency = NTSC;
	    break;
    }

    if (!pScrn->progClock) {
	pScrn->numClocks = NoClocks;
	xf86GetClocks(pScrn, NoClocks, TRIDENTClockSelect,
			  vgaHWProtectWeak(),
			  vgaHWBlankScreenWeak(),
			  vgaIOBase + 0x0A, 0x08, 1, 28322);
	from = X_PROBED;
	xf86ShowClocks(pScrn, from);
    }

    if (!chipset) {
	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No support for \"%s\"\n",
			pScrn->chipset);
	if (IsPciCard && UseMMIO) {
    	    TRIDENTDisableMMIO(pScrn);
 	    TRIDENTUnmapMem(pScrn);
	}
	return FALSE;
    }
    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Found %s chip\n", chipset);
    if (ramtype)
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "RAM type is %s\n", ramtype);

    if (pScrn->bitsPerPixel == 24 && !Support24bpp) {
	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "No support for 24bpp on this chipset, use -pixmap32.\n");
	if (IsPciCard && UseMMIO) {
    	    TRIDENTDisableMMIO(pScrn);
 	    TRIDENTUnmapMem(pScrn);
	}
	return FALSE;
    }

    /* HW bpp matches reported bpp */
    pTrident->HwBpp = pScrn->bitsPerPixel;

    /* Due to bugs in the chip, turn it off */
    if (pTrident->Chipset >= CYBERBLADEI7 && pTrident->Chipset <= CYBERBLADEAI1D)
	pTrident->HWCursor = FALSE;

    from = X_PROBED;
    if (pTrident->pEnt->device->videoRam != 0) {
	pScrn->videoRam = pTrident->pEnt->device->videoRam;
	from = X_CONFIG;
    } else {
      if (pTrident->Chipset == CYBER9525DVD) {
	pScrn->videoRam = 2560;
      } else
      {
	OUTB(vgaIOBase + 4, SPR);
	videoram = INB(vgaIOBase + 5);
	if (pTrident->Chipset < TGUI9440AGi)
	    videorammask = 0x07;
	else
	    videorammask = 0x0F;
	switch (videoram & videorammask) {
  	case 0x01:
  	    pScrn->videoRam = 512;
  	    break;
 	case 0x02: /* XP */
 	    pScrn->videoRam = 6144;
 	    break;
  	case 0x03:
  	    pScrn->videoRam = 1024;
  	    break;
	case 0x04: 
	    pScrn->videoRam = 8192;
	    break;
 	case 0x06: /* XP */
 	    pScrn->videoRam = 10240;
 	    break;
  	case 0x07:
  	    pScrn->videoRam = 2048;
  	    break;
 	case 0x08: /* XP */
 	    pScrn->videoRam = 12288;
 	    break;
 	case 0x0A: /* XP */
 	    pScrn->videoRam = 14336;
 	    break;
 	case 0x0C: /* XP */
 	    pScrn->videoRam = 16384;
 	    break;
 	case 0x0E: /* XP */
 	    OUTB(vgaIOBase + 4, 0xC1);
 	    switch (INB(vgaIOBase + 5) & 0x11) {
 		case 0x00:
 		    pScrn->videoRam = 20480;
 		    break;
 		case 0x01:
 		    pScrn->videoRam = 24576;
 		    break;
 		case 0x10:
 		    pScrn->videoRam = 28672;
 		    break;
 		case 0x11:
 		    pScrn->videoRam = 32768;
 		    break;
 	    }
 	    break;
 	case 0x0F:
  	    pScrn->videoRam = 4096;
  	    break;
	default:
	    pScrn->videoRam = 1024;
	    xf86DrvMsg(pScrn->scrnIndex, from, 
			"Unable to determine VideoRam, defaulting to 1MB\n");
	    break;
	}
      }
    }

    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
		pTrident->HWCursor ? "HW" : "SW");

    xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n",
               pScrn->videoRam);

    if (pTrident->IsCyber) {
	unsigned char mod, dsp, dsp1;
	
	pTrident->lcdMode = 0xff;

	OUTB(0x3CE,0x42);
	dsp = INB(0x3CF);
	OUTB(0x3CE,0x43);
	dsp1 = INB(0x3CF);
	OUTB(0x3CE,0x52);
	mod = INB(0x3CF);
	/*
	 * Only allow display size override if 1280x1024 is detected 
	 * Currently 1400x1050 is supported - which is detected as
	 * 1280x1024
	 */
	if (pTrident->displaySize) {
	    if (((mod >> 4) & 3) == 0) {
		for (i = 0; LCD[i].mode != 0xff; i++) {
		    if (pTrident->displaySize == LCD[i].display_x)
			pTrident->lcdMode = LCD[i].mode;
		}
		xf86DrvMsg(pScrn->scrnIndex,
			   X_CONFIG,"%s Panel %ix%i found\n",
			   (dsp & 0x80) ? "TFT" :
			   ((dsp1 & 0x20) ? "DSTN" : "STN"), 
			   LCD[i].display_x,LCD[i].display_y);		
	    } else {
		xf86DrvMsg(pScrn->scrnIndex,X_WARNING,
			   "Display size override only for 1280x1024\n");
		pTrident->displaySize = 0;
	    }
	}
	
	if (!pTrident->displaySize) {
	    for (i = 0; LCD[i].mode != 0xff; i++) {
		if (LCD[i].mode == ((mod >> 4) & 3)) {
		    pTrident->lcdMode = i;
		    xf86DrvMsg(pScrn->scrnIndex,
			       X_PROBED,"%s Panel %ix%i found\n",
			       (dsp & 0x80) ? "TFT" :
			       ((dsp1 & 0x20) ? "DSTN" : "STN"), 
			       LCD[i].display_x,LCD[i].display_y);
		}
	    }
	}
	if (pTrident->dspOverride) {
	    if (pTrident->dspOverride & LCD_ACTIVE)
		pTrident->lcdActive = TRUE;
	    else
		pTrident->lcdActive = FALSE;
	} else {
	    OUTB(0x3CE, FPConfig);
	    pTrident->lcdActive = (INB(0x3CF) & 0x10);
	}
    }

    pTrident->MCLK = 0;
    mclk = CalculateMCLK(pScrn);
    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Memory Clock is %3.2f MHz\n", mclk);
    if (xf86GetOptValFreq(pTrident->Options, OPTION_SETMCLK, OPTUNITS_MHZ,
				&real)) {
	pTrident->MCLK = (int)(real * 1000.0);
	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Setting new Memory Clock to %3.2f MHz\n",
						(float)(pTrident->MCLK / 1000));
    }
		
    /* Set the min pixel clock */
    pTrident->MinClock = 12000;	/* XXX Guess, need to check this */
    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n",
	       pTrident->MinClock / 1000);

    /*
     * If the user has specified ramdac speed in the XF86Config
     * file, we respect that setting.
     */
    if (pTrident->pEnt->device->dacSpeeds[0]) {
	int speed = 0;

	switch (pScrn->bitsPerPixel) {
	case 8:
	   speed = pTrident->pEnt->device->dacSpeeds[DAC_BPP8];
	   break;
	case 16:
	   speed = pTrident->pEnt->device->dacSpeeds[DAC_BPP16];
	   break;
	case 24:
	   speed = pTrident->pEnt->device->dacSpeeds[DAC_BPP24];
	   break;
	case 32:
	   speed = pTrident->pEnt->device->dacSpeeds[DAC_BPP32];
	   break;
	}
	if (speed == 0)
	    pTrident->MaxClock = pTrident->pEnt->device->dacSpeeds[0];
	else
	    pTrident->MaxClock = speed;
	from = X_CONFIG;
    } else {
	switch (pScrn->bitsPerPixel) {
	    case 16:
		pTrident->MaxClock = ClockLimit16bpp[pTrident->Chipset];
		break;
	    case 24:
		pTrident->MaxClock = ClockLimit24bpp[pTrident->Chipset];
		break;
	    case 32:
		pTrident->MaxClock = ClockLimit32bpp[pTrident->Chipset];
		break;
	    default:
		pTrident->MaxClock = ClockLimit[pTrident->Chipset];
		break;
	}
    }
    xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
	       pTrident->MaxClock / 1000);

    /*
     * 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;
    if (!pScrn->progClock) {
	if (pScrn->videoRam < 1024)
    	    clockRanges->ClockMulFactor = 2;
	if (pScrn->bitsPerPixel == 16)
    	    clockRanges->ClockMulFactor = 2;
    }
    clockRanges->minClock = pTrident->MinClock;
    clockRanges->maxClock = pTrident->MaxClock;
    clockRanges->clockIndex = -1;		/* programmable */
    clockRanges->interlaceAllowed = TRUE;
    clockRanges->doubleScanAllowed = FALSE;	/* XXX check this */

    /*
     * xf86ValidateModes will check that the mode HTotal and VTotal values
     * don't exceed the chipset's limit if pScrn->maxHValue and
     * pScrn->maxVValue are set.  Since our TRIDENTValidMode() already takes
     * care of this, we don't worry about setting them here.
     */

    if ((pScrn->depth < 8) || 
        (pScrn->bitsPerPixel == 24)) {
    	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 
		"Disabling Engine due to 24bpp or < 8bpp.\n");
	    pTrident->NoAccel = TRUE;
    }

    /* Select valid modes from those available */
    if (pTrident->NoAccel || Is3Dchip) {
	/*
	 * XXX Assuming min pitch 256, max 4096
	 * XXX Assuming min height 128, max 4096
	 */
	i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
			      pScrn->display->modes, clockRanges,
			      NULL, 256, 4096,
			      pScrn->bitsPerPixel, 128, 4096,
			      pScrn->display->virtualX,
			      pScrn->display->virtualY,
			      pTrident->FbMapSize,
			      LOOKUP_BEST_REFRESH);
    } else {
	/*
	 * XXX Assuming min height 128, max 2048
	 */
	i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
			      pScrn->display->modes, clockRanges,
			      GetAccelPitchValues(pScrn), 0, 0,
			      pScrn->bitsPerPixel, 128, 2048,
			      pScrn->display->virtualX,
			      pScrn->display->virtualY,
			      pTrident->FbMapSize,
			      LOOKUP_BEST_REFRESH);
    }

    if (i == -1) {
	if (IsPciCard && UseMMIO) {
    	    TRIDENTDisableMMIO(pScrn);
 	    TRIDENTUnmapMem(pScrn);
	}
	TRIDENTFreeRec(pScrn);
	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");
	if (IsPciCard && UseMMIO) {
    	    TRIDENTDisableMMIO(pScrn);
 	    TRIDENTUnmapMem(pScrn);
	}
	TRIDENTFreeRec(pScrn);
	return FALSE;
    }

    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);

    /* 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);

    /* Load bpp-specific modules */
    switch (pScrn->bitsPerPixel) {
    case 1:
	pTrident->EngineOperation |= 0x00;
	mod = "xf1bpp";
	Sym = "xf1bppScreenInit";
	break;
    case 4:
	pTrident->EngineOperation |= 0x00;
	mod = "xf4bpp";
	Sym = "xf4bppScreenInit";
	break;
    case 8:
	pTrident->EngineOperation |= 0x00;
	mod = "fb";
	break;
    case 16:
	pTrident->EngineOperation |= 0x01;
	mod = "fb";
	break;
    case 24:
	pTrident->EngineOperation |= 0x03;
	mod = "fb";
	break;
    case 32:
	pTrident->EngineOperation |= 0x02;
	mod = "fb";
	break;
    }

    if (mod && xf86LoadSubModule(pScrn, mod) == NULL) {
	if (IsPciCard && UseMMIO) {
    	    TRIDENTDisableMMIO(pScrn);
 	    TRIDENTUnmapMem(pScrn);
	}
	TRIDENTFreeRec(pScrn);
	return FALSE;
    }

    if (mod) {
	if (Sym) {
	    xf86LoaderReqSymbols(Sym, NULL);
	} else {
	    xf86LoaderReqSymLists(fbSymbols, NULL);
	}
    }

    if (!xf86LoadSubModule(pScrn, "i2c")) {
	if (IsPciCard && UseMMIO) {
    	    TRIDENTDisableMMIO(pScrn);
 	    TRIDENTUnmapMem(pScrn);
	}
	TRIDENTFreeRec(pScrn);
	return FALSE;
    }

    xf86LoaderReqSymLists(i2cSymbols, NULL);

    /* Load shadow if needed */
    if (pTrident->ShadowFB) {
	if (!xf86LoadSubModule(pScrn, "shadow")) {
	    TRIDENTFreeRec(pScrn);
	    return FALSE;
	}
	xf86LoaderReqSymLists(shadowSymbols, NULL);
    }

    /* Load XAA if needed */
    if (!pTrident->NoAccel) {
	if (!xf86LoadSubModule(pScrn, "xaa")) {
	    if (IsPciCard && UseMMIO) {
    	    	TRIDENTDisableMMIO(pScrn);
 	    	TRIDENTUnmapMem(pScrn);
	    }
	    TRIDENTFreeRec(pScrn);
	    return FALSE;
	}

        xf86LoaderReqSymLists(xaaSymbols, NULL);

        switch (pScrn->displayWidth * pScrn->bitsPerPixel / 8) {
	    case 512:
	    case 8192:
		pTrident->EngineOperation |= 0x00;
		break;
	    case 1024:
		pTrident->EngineOperation |= 0x04;
		break;
	    case 2048:
		pTrident->EngineOperation |= 0x08;
		break;
	    case 4096:
		pTrident->EngineOperation |= 0x0C;
		break;
	}
    }

    /* Load DDC if needed */
    /* This gives us DDC1 - we should be able to get DDC2B using i2c */

    if (! ddcLoaded)
	if (!xf86LoadSubModule(pScrn, "ddc")) {
	    if (IsPciCard && UseMMIO) {
		TRIDENTDisableMMIO(pScrn);
		TRIDENTUnmapMem(pScrn);
	    }
	    TRIDENTFreeRec(pScrn);
	    return FALSE;
	}
    
    xf86LoaderReqSymLists(ddcSymbols, NULL);

    if (IsPciCard && UseMMIO) {
        TRIDENTDisableMMIO(pScrn);
	TRIDENTUnmapMem(pScrn);
    }


    pTrident->FbMapSize = pScrn->videoRam * 1024;
    
    pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;

    if (pTrident->IsCyber && pTrident->MMIOonly)
	pScrn->racIoFlags = 0;
    else 
	pScrn->racIoFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;

    return TRUE;
}

/*
 * Map the framebuffer and MMIO memory.
 */

static Bool
TRIDENTMapMem(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    int mapsize = 0x10000;

    if (Is3Dchip) mapsize = 0x20000;

    if (IsPciCard && UseMMIO)
    	pTrident->IOBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, 
		pTrident->PciTag, pTrident->IOAddress, mapsize);
    else {
    	pTrident->IOBase = xf86MapDomainMemory(pScrn->scrnIndex, VIDMEM_MMIO, 
		pTrident->PciTag, pTrident->IOAddress, 0x1000);
    	pTrident->IOBase += 0xF00;
    }

    if (pTrident->IOBase == NULL)
	return FALSE;

    if (pTrident->Linear) {
        if (pTrident->FbMapSize != 0) {
	    pTrident->FbBase = xf86MapPciMem(pScrn->scrnIndex, 
				VIDMEM_FRAMEBUFFER,
				 pTrident->PciTag,
				 (unsigned long)pTrident->FbAddress,
				 pTrident->FbMapSize);
    	if (pTrident->FbBase == NULL)
	    return FALSE;
    	}
    }
    else
	pTrident->FbBase = hwp->Base;

    return TRUE;
}

/*
 * Unmap the framebuffer and MMIO memory.
 */

static Bool
TRIDENTUnmapMem(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    int mapsize = 0x10000;

    if (Is3Dchip) mapsize = 0x20000;

    /*
     * Unmap IO registers to virtual address space
     */ 
    if (IsPciCard && UseMMIO) 
    	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pTrident->IOBase, mapsize);
    else {
    	pTrident->IOBase -= 0xF00;
    	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pTrident->IOBase, 0x1000);
    }
    pTrident->IOBase = NULL;

    if (pTrident->Linear) {
    	if (pTrident->FbMapSize != 0) {
    	    xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pTrident->FbBase, 
							pTrident->FbMapSize);
    	pTrident->FbBase = NULL;
        }
    }

    return TRUE;
}


/*
 * This function saves the video state.
 */
static void
TRIDENTSave(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident;
    vgaRegPtr vgaReg;
    TRIDENTRegPtr tridentReg;

    pTrident = TRIDENTPTR(pScrn);
    vgaReg = &VGAHWPTR(pScrn)->SavedReg;
    tridentReg = &pTrident->SavedReg;

    vgaHWSave(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP |
			     (IsPrimaryCard ? VGA_SR_FONTS : 0));

    if (pScrn->progClock)
    	TridentSave(pScrn, tridentReg);
    else
    	TVGASave(pScrn, tridentReg);

    if (pTrident->TVChipset != 0)
       VIA_SaveTVDepentVGAReg(pScrn);
}


/*
 * Initialise a new mode.  This is currently still using the old
 * "initialise struct, restore/write struct to HW" model.  That could
 * be changed.
 */

static Bool
TRIDENTModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    vgaRegPtr vgaReg;
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    TRIDENTRegPtr tridentReg;

    WAITFORVSYNC;

    TridentFindClock(pScrn,mode->Clock);

    switch (pTrident->Chipset) {
	case TGUI9660:
	case TGUI9680:
	case PROVIDIA9682:
	case PROVIDIA9685:
	case IMAGE975:
	case IMAGE985:
	case BLADE3D:
	case CYBERBLADEI7:
	case CYBERBLADEI7D:
	case CYBERBLADEI1:
	case CYBERBLADEI1D:
	case CYBERBLADEAI1:
	case CYBERBLADEAI1D:
	case CYBER9520:
	case CYBER9525DVD:
	case CYBERBLADEE4:
	case CYBER9397:
	case CYBER9397DVD:
	case BLADEXP:
	case CYBERBLADEXPAI1:
	case CYBERBLADEXP4:
	    /* Get ready for MUX mode */
	    if (pTrident->MUX && 
		pScrn->bitsPerPixel == 8 && 
		!mode->CrtcHAdjusted) {
		mode->CrtcHDisplay >>= 1;
		mode->CrtcHSyncStart >>= 1;
		mode->CrtcHSyncEnd >>= 1;
		mode->CrtcHBlankStart >>= 1;
		mode->CrtcHBlankEnd >>= 1;
		mode->CrtcHTotal >>= 1;
		mode->CrtcHAdjusted = TRUE;
	    }
	    break;
	default:
	    if (pScrn->videoRam < 1024 &&
		!mode->CrtcHAdjusted) {
		mode->CrtcHDisplay <<= 1;
		mode->CrtcHSyncStart <<= 1;
		mode->CrtcHSyncEnd <<= 1;
		mode->CrtcHBlankStart <<= 1;
		mode->CrtcHBlankEnd <<= 1;
		mode->CrtcHTotal <<= 1;
		mode->CrtcHAdjusted = TRUE;
	    }
	    break;
    }

    vgaHWUnlock(hwp);
    /* Initialise the ModeReg values */
    if (!vgaHWInit(pScrn, mode))
	return FALSE;
    pScrn->vtSema = TRUE;
    /*
     * We used to do this at a later time. 
     * Now since READOUT isn't defined any more
     * we do it here. 
     * The original NOTE read:
     * TridentInit() has to modify registers
     * that have already been set by vgaHWRestore().
     * So we call it _after_ vgaHWRestore() has
     * programmed these registers.
     */
    if (pScrn->progClock) {
    	if (!TridentInit(pScrn, mode))
	    return FALSE;
    } else {
    	if (!TVGAInit(pScrn, mode))
	    return FALSE;
    }

    /* Program the registers */
    vgaHWProtect(pScrn, TRUE);
    vgaReg = &hwp->ModeReg;
    tridentReg = &pTrident->ModeReg;

    vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE);
    if (pScrn->progClock)
    	TridentRestore(pScrn, tridentReg);
    else
	TVGARestore(pScrn, tridentReg);

    vgaHWProtect(pScrn, FALSE);

    if (xf86IsPc98())
	PC98TRIDENTEnable(pScrn);

    if (pTrident->TVChipset != 0)
       VIA_TVInit(pScrn);
	
    return TRUE;
}

/*
 * Restore the initial (text) mode.
 */
static void 
TRIDENTRestore(ScrnInfoPtr pScrn)
{
    vgaHWPtr hwp;
    vgaRegPtr vgaReg;
    TRIDENTPtr pTrident;
    TRIDENTRegPtr tridentReg;

    hwp = VGAHWPTR(pScrn);
    pTrident = TRIDENTPTR(pScrn);
    vgaReg = &hwp->SavedReg;
    tridentReg = &pTrident->SavedReg;

    vgaHWProtect(pScrn, TRUE);

    if (pScrn->progClock)
    	TridentRestore(pScrn, tridentReg);
    else
	TVGARestore(pScrn, tridentReg);

    vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP |
				(IsPrimaryCard ? VGA_SR_FONTS : 0));

    if (pTrident->TVChipset != 0)
       VIA_RestoreTVDependVGAReg(pScrn);

    vgaHWProtect(pScrn, FALSE);
}


/* Mandatory */

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

static Bool
TRIDENTScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
{
    /* The vgaHW references will disappear one day */
    ScrnInfoPtr pScrn;
    vgaHWPtr hwp;
    TRIDENTPtr pTrident;
    int ret;
    VisualPtr visual;
    unsigned char *FBStart;
    int width, height, displayWidth;

    /* 
     * First get the ScrnInfoRec
     */
    pScrn = xf86Screens[pScreen->myNum];
    pTrident = TRIDENTPTR(pScrn);

    if (IsPrimaryCard) {
	if (!vgaHWMapMem(pScrn))
   	    return FALSE;
    }

    /* Map the TRIDENT memory and MMIO areas */
    if (!TRIDENTMapMem(pScrn))
	return FALSE;

    if (!xf86IsPc98()) {
#ifdef VBE_INFO
	if (pTrident->vbeModes) {
	    pTrident->pVbe = VBEInit(NULL,pTrident->pEnt->index);
	    pTrident->Int10 = pTrident->pVbe->pInt10;
	} else
#endif
	{
	    if (xf86LoadSubModule(pScrn, "int10")) {
		xf86LoaderReqSymLists(int10Symbols, NULL);
		xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Initializing int10\n");
		pTrident->Int10 = xf86InitInt10(pTrident->pEnt->index);
	    }
	}
    }
    
    hwp = VGAHWPTR(pScrn);

    if (IsPciCard && UseMMIO) {
    	TRIDENTEnableMMIO(pScrn);

    	/* Initialize the MMIO vgahw functions */
    	vgaHWSetMmioFuncs(hwp, pTrident->IOBase, 0);
    }

    /* Save the current state */
    TRIDENTSave(pScrn);

    /*
     * Some Trident chip on PC-9821 needs setup,
     * because VGA chip is not initialized by VGA BIOS.
     */
    if (IsPciCard && xf86IsPc98()) {
	 PC98TRIDENTInit(pScrn);
    } else tridentSetModeBIOS(pScrn,pScrn->currentMode);

    /* Initialise the first mode */
    if (!TRIDENTModeInit(pScrn, pScrn->currentMode))
	return FALSE;

    /* Darken the screen for aesthetic reasons and set the viewport */
    TRIDENTSaveScreen(pScreen, SCREEN_SAVER_ON);
    TRIDENTAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);

    /*
     * The next step is to setup the screen's visuals, and initialise the
     * framebuffer code.  In cases where the framebuffer's default
     * choices 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 visual list.
     */
    miClearVisualTypes();

    /* Setup the visuals we support. */

    if (!miSetVisualTypes(pScrn->depth, 
			  miGetDefaultVisualMask(pScrn->depth),
			  pScrn->rgbBits, pScrn->defaultVisual)) {
	if (pTrident->pVbe)
	    	vbeFree(pTrident->pVbe);
	else
	    xf86FreeInt10(pTrident->Int10);
      return FALSE;
    }

    miSetPixmapDepths ();

    /* FIXME - we don't do shadowfb for < 4 */
    displayWidth = pScrn->displayWidth;
    if (pTrident->Rotate) {
	height = pScrn->virtualX;
	width = pScrn->virtualY;
    } else {
	width = pScrn->virtualX;
	height = pScrn->virtualY;
    }

    if(pTrident->ShadowFB) {
 	pTrident->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
        pTrident->ShadowPtr = xalloc(pTrident->ShadowPitch * height);
	displayWidth = pTrident->ShadowPitch / (pScrn->bitsPerPixel >> 3);
        FBStart = pTrident->ShadowPtr;
    } else {
	pTrident->ShadowFB = FALSE;
	pTrident->ShadowPtr = NULL;
	FBStart = pTrident->FbBase;
    }

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

    switch (pScrn->bitsPerPixel) {
    case 1:
	ret = xf1bppScreenInit(pScreen, FBStart, width,
			height, pScrn->xDpi, pScrn->yDpi, 
			displayWidth);
	break;
    case 4:
	ret = xf4bppScreenInit(pScreen, FBStart, width,
			height, pScrn->xDpi, pScrn->yDpi, 
			displayWidth);
	break;
    case 8:
    case 16:
    case 24:
    case 32:
	ret = fbScreenInit(pScreen, FBStart, width,
			height, pScrn->xDpi, pScrn->yDpi, 
			displayWidth, pScrn->bitsPerPixel);
    
	break;
    default:
	xf86DrvMsg(scrnIndex, X_ERROR,
		   "Internal error: invalid bpp (%d) in TRIDENTScrnInit\n",
		   pScrn->bitsPerPixel);
	    ret = FALSE;
	break;
    }
    if (!ret) {
	if (pTrident->pVbe)
	    vbeFree(pTrident->pVbe);
	else
	    xf86FreeInt10(pTrident->Int10);
	return FALSE;
    }
    if (pScrn->bitsPerPixel > 8) {
        /* 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;
	    }
	}
    } else {
	if (pScrn->bitsPerPixel == 1) {
	    TRIDENTFix1bpp(pScrn);
	}
    }

    /* must be after RGB ordering fixed */
    if (pScrn->bitsPerPixel > 4)
	fbPictureInit (pScreen, 0, 0);

    xf86SetBlackWhitePixels(pScreen);

    pTrident->BlockHandler = pScreen->BlockHandler;
    pScreen->BlockHandler = TRIDENTBlockHandler;

    if (!pTrident->ShadowFB)
	TRIDENTDGAInit(pScreen);

    if (!pTrident->Linear) {
	miBankInfoPtr pBankInfo;

	/* Setup the vga banking variables */
	pBankInfo = xnfcalloc(sizeof(miBankInfoRec),1);
	if (pBankInfo == NULL) {
	    if (pTrident->pVbe)
		vbeFree(pTrident->pVbe);
	    else
		xf86FreeInt10(pTrident->Int10);
	    return FALSE;
	}
	pBankInfo->pBankA = pTrident->FbBase;
	pBankInfo->pBankB = pTrident->FbBase;
	pBankInfo->BankSize = 0x10000;
	pBankInfo->nBankDepth = (pScrn->depth == 4) ? 1 : pScrn->depth;

	pBankInfo->SetSourceBank = 
		(miBankProcPtr)TVGA8900SetRead;
	pBankInfo->SetDestinationBank = 
		(miBankProcPtr)TVGA8900SetWrite;
	pBankInfo->SetSourceAndDestinationBanks = 
		(miBankProcPtr)TVGA8900SetReadWrite;
	if (!miInitializeBanking(pScreen, pScrn->virtualX, pScrn->virtualY,
				 pScrn->displayWidth, pBankInfo)) {
	    xfree(pBankInfo);
	    pBankInfo = NULL;
	    if (pTrident->pVbe)
	    	vbeFree(pTrident->pVbe);
	    else
		xf86FreeInt10(pTrident->Int10);
	    return FALSE;
	}
    }

    {
    	BoxRec AvailFBArea;

	AvailFBArea.x1 = 0;
    	AvailFBArea.y1 = 0;
    	AvailFBArea.x2 = pScrn->displayWidth;
    	AvailFBArea.y2 = pTrident->FbMapSize / (pScrn->displayWidth *
					    pScrn->bitsPerPixel / 8);

    	if (AvailFBArea.y2 > 2047) AvailFBArea.y2 = 2047; 

    	if (xf86InitFBManager(pScreen, &AvailFBArea)) {
	    int cpp = pScrn->bitsPerPixel / 8;
	    int area = AvailFBArea.y2 * pScrn->displayWidth;
	    int areaoffset = area * cpp;

    	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
	       "Using %i scanlines of offscreen memory for area's \n",
 	       AvailFBArea.y2 - pScrn->virtualY);

	    if (xf86InitFBManagerLinear(pScreen, area, ((pTrident->FbMapSize/cpp) - area))) {
		xf86DrvMsg(scrnIndex, X_INFO, 
			"Using %ld bytes of offscreen memory for linear (offset=0x%x)\n", (pTrident->FbMapSize - areaoffset), areaoffset);
	    }
    	}
    }

    if (Is3Dchip) {
	if ((pTrident->Chipset == CYBERBLADEI7) ||
	    (pTrident->Chipset == CYBERBLADEI7D) ||
	    (pTrident->Chipset == CYBERBLADEI1) ||
	    (pTrident->Chipset == CYBERBLADEI1D) ||
	    (pTrident->Chipset == CYBERBLADEAI1) ||
	    (pTrident->Chipset == CYBERBLADEAI1D) ||
	    (pTrident->Chipset == CYBERBLADEE4) ||
	    (pTrident->Chipset == BLADE3D))
		BladeAccelInit(pScreen);
	    else
	    if (pTrident->Chipset >= BLADEXP)
		XPAccelInit(pScreen);
	    else
	    	ImageAccelInit(pScreen);
    } else {
    	TridentAccelInit(pScreen);
    }

    miInitializeBackingStore(pScreen);
    xf86SetBackingStore(pScreen);

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

    if (pScrn->bitsPerPixel < 8) 
	pTrident->HWCursor = FALSE;

    if (pTrident->HWCursor) {
        xf86SetSilkenMouse(pScreen);
	TridentHWCursorInit(pScreen);
    }

    /* Initialise default colourmap */
    if (!miCreateDefColormap(pScreen)) {
	if (pTrident->pVbe)
	    vbeFree(pTrident->pVbe);
	else
	    xf86FreeInt10(pTrident->Int10);
	return FALSE;
    }
    if(!xf86HandleColormaps(pScreen, 256, 6, TridentLoadPalette,
			    TridentSetOverscan, CMAP_RELOAD_ON_MODE_SWITCH|CMAP_PALETTED_TRUECOLOR)) {
	if (pTrident->pVbe)
	    vbeFree(pTrident->pVbe);
	else
	    xf86FreeInt10(pTrident->Int10);
	return FALSE;
    }
    if(pTrident->ShadowFB) {
        if(pTrident->Rotate) {
	    if (!pTrident->PointerMoved) {
	        pTrident->PointerMoved = pScrn->PointerMoved;
		pScrn->PointerMoved = TRIDENTPointerMoved;
	    }
	    switch (pScrn->bitsPerPixel) {
	    case 8:    pTrident->RefreshArea = TRIDENTRefreshArea8; break;
	    case 16:   pTrident->RefreshArea = TRIDENTRefreshArea16; break;
	    case 24:   pTrident->RefreshArea = TRIDENTRefreshArea24; break;
	    case 32:   pTrident->RefreshArea = TRIDENTRefreshArea32; break;
	    }
	} else {
	  pTrident->RefreshArea = TRIDENTRefreshArea;
	}
	shadowInit (pScreen, TRIDENTShadowUpdate, 0);
    }

    xf86DPMSInit(pScreen, (DPMSSetProcPtr)TRIDENTDisplayPowerManagementSet, 0);

    pScrn->memPhysBase = pTrident->FbAddress;
    pScrn->fbOffset = 0;

    if (pTrident->Chipset >= TGUI9660)
	TRIDENTInitVideo(pScreen);

    pTrident->CloseScreen = pScreen->CloseScreen;
    pScreen->CloseScreen = TRIDENTCloseScreen;
    pScreen->SaveScreen = TRIDENTSaveScreen;

    /* Report any unused options (only for the first generation) */
    if (serverGeneration == 1) {
	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
    }

#if 0
    TRIDENTI2CInit(pScreen);

    xf86PrintEDID(xf86DoEDID_DDC2(pScrn->scrnIndex,pTrident->DDC));
#endif

    return TRUE;
}

/* Usually mandatory */
Bool
TRIDENTSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
{
    return TRIDENTModeInit(xf86Screens[scrnIndex], mode);
}


/*
 * This function is used to initialize the Start Address - the first
 * displayed location in the video memory.
 */
/* Usually mandatory */
void 
TRIDENTAdjustFrame(int scrnIndex, int x, int y, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    TRIDENTPtr pTrident;
    int base = y * pScrn->displayWidth + x;
    int vgaIOBase;
    CARD8 temp;

    pTrident = TRIDENTPTR(pScrn);
    vgaIOBase = VGAHWPTR(pScrn)->IOBase;

    switch (pScrn->bitsPerPixel) {
	case 4:
	    base >>= 3;
	    break;
	case 8:
	    if (pScrn->progClock)
	    	base = (base & 0xFFFFFFF8) >> 2;
	    else
	    	base = (base & 0xFFFFFFF8) >> 3;
	    break;
	case 16:
	    base >>= 1;
	    break;
	case 24:
	    base = (((base + 1) & ~0x03) * 3) >> 2;
	    break;
	case 32:
	    break;
    }

    /* CRT bits 0-15 */
    OUTW(vgaIOBase + 4, (base & 0x00FF00) | 0x0C);
    OUTW(vgaIOBase + 4, ((base & 0x00FF) << 8) | 0x0D);
    /* CRT bit 16 */
    OUTB(vgaIOBase + 4, CRTCModuleTest); temp = INB(vgaIOBase + 5) & 0xDF;
    OUTB(vgaIOBase + 5, temp | ((base & 0x10000) >> 11));
    /* CRT bit 17-19 */
    OUTB(vgaIOBase + 4, CRTHiOrd); temp = INB(vgaIOBase + 5) & 0xF8;
    OUTB(vgaIOBase + 5, temp | ((base & 0xE0000) >> 17));
}


/*
 * This is called when VT switching back to the X server.  Its job is
 * to reinitialise the video mode.
 */

/* Mandatory */
static Bool
TRIDENTEnterVT(int scrnIndex, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    if (IsPciCard && UseMMIO) TRIDENTEnableMMIO(pScrn);

    /* Should we re-save the text mode on each VT enter? */
    if (!TRIDENTModeInit(pScrn, pScrn->currentMode))
	return FALSE;

    if (pTrident->InitializeAccelerator)
        pTrident->InitializeAccelerator(pScrn);

    return TRUE;
}


/*
 * 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.
 */

/* Mandatory */
static void
TRIDENTLeaveVT(int scrnIndex, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    vgaHWPtr hwp = VGAHWPTR(pScrn);

    if (!pTrident->NoAccel)
	pTrident->AccelInfoRec->Sync(pScrn);

    TRIDENTRestore(pScrn);
    vgaHWLock(hwp);

    if (xf86IsPc98())
	PC98TRIDENTDisable(pScrn);

    if (IsPciCard && UseMMIO) TRIDENTDisableMMIO(pScrn);
}


/*
 * This is called at the end of each server generation.  It restores the
 * original (text) mode.  It should really also unmap the video memory too.
 */

/* Mandatory */
static Bool
TRIDENTCloseScreen(int scrnIndex, ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    if (!pTrident->NoAccel)
	pTrident->AccelInfoRec->Sync(pScrn);
	
    if (xf86IsPc98())
	PC98TRIDENTDisable(pScrn);

    if (pScrn->vtSema) {
    	TRIDENTRestore(pScrn);
    	vgaHWLock(hwp);
	if (IsPciCard && UseMMIO) TRIDENTDisableMMIO(pScrn);
    	TRIDENTUnmapMem(pScrn);
    }
    if (pTrident->AccelInfoRec)
	XAADestroyInfoRec(pTrident->AccelInfoRec);
    if (pTrident->CursorInfoRec)
	xf86DestroyCursorInfoRec(pTrident->CursorInfoRec);
    if (pTrident->ShadowPtr)
	xfree(pTrident->ShadowPtr);
    if (pTrident->DGAModes)
	xfree(pTrident->DGAModes);
    pScrn->vtSema = FALSE;

    if(pTrident->BlockHandler)
	pScreen->BlockHandler = pTrident->BlockHandler;
    
    if (pTrident->pVbe)
	vbeFree(pTrident->pVbe);
    else
	xf86FreeInt10(pTrident->Int10);
    pScreen->CloseScreen = pTrident->CloseScreen;
    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
}


/* Free up any per-generation data structures */

/* Optional */
static void
TRIDENTFreeScreen(int scrnIndex, int flags)
{
    if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
	vgaHWFreeHWRec(xf86Screens[scrnIndex]);
    TRIDENTFreeRec(xf86Screens[scrnIndex]);
}


/* Checks if a mode is suitable for the selected chipset. */

/* Optional */
static ModeStatus
TRIDENTValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    
    if (pTrident->lcdActive && (pTrident->lcdMode != 0xff)){
	if (((mode->HDisplay > LCD[pTrident->lcdMode].display_x) 
	|| (mode->VDisplay > LCD[pTrident->lcdMode].display_y))) {
	    xf86DrvMsg(scrnIndex,X_INFO, "Removing mode (%dx%d) "
		       "larger than the LCD panel (%dx%d)\n",
		       mode->HDisplay,
		       mode->VDisplay,
		       LCD[pTrident->lcdMode].display_x,
		       LCD[pTrident->lcdMode].display_y);
	    return(MODE_BAD);
	}
	if (((float)mode->HDisplay/(float)mode->VDisplay) > 2.0) {
	    xf86DrvMsg(scrnIndex,X_INFO, "Removing mode (%dx%d) "
		       "unusual aspect ratio\n",
		       mode->HDisplay,
		       mode->VDisplay);
	    return(MODE_BAD);
	}
    }
    return (MODE_OK);
}

/* Do screen blanking */

/* Mandatory */
static Bool
TRIDENTSaveScreen(ScreenPtr pScreen, int mode)
{
    return vgaHWSaveScreen(pScreen, mode);
}

static void
TRIDENTEnableMMIO(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    IOADDRESS vgaIOBase = pTrident->PIOBase + VGAHWPTR(pScrn)->IOBase;
    CARD8 temp = 0, protect = 0;

    /*
     * Skip MMIO Enable in PC-9821 PCI Trident Card!!
     * Because of lack of non PCI VGA port
     */
    if (IsPciCard && xf86IsPc98())
      return;

    /* Goto New Mode */
    outb(pTrident->PIOBase + 0x3C4, 0x0B);
    inb(pTrident->PIOBase + 0x3C5);

    /* Unprotect registers */
    if (pTrident->Chipset > PROVIDIA9685) {
    	outb(pTrident->PIOBase + 0x3C4, Protection);
    	protect = inb(pTrident->PIOBase + 0x3C5);
    	outb(pTrident->PIOBase + 0x3C5, 0x92);
    }
    outb(pTrident->PIOBase + 0x3C4, NewMode1);
    temp = inb(pTrident->PIOBase + 0x3C5);
    outb(pTrident->PIOBase + 0x3C5, 0x80);

    /* Enable MMIO */
    outb(vgaIOBase + 4, PCIReg);
    pTrident->REGPCIReg = inb(vgaIOBase + 5);
    outb(vgaIOBase + 5, pTrident->REGPCIReg | 0x01); /* Enable it */

    /* Protect registers */
    if (pTrident->Chipset > PROVIDIA9685) {
    	OUTB(0x3C4, Protection);
    	OUTB(0x3C5, protect);
    }
    OUTB(0x3C4, NewMode1);
    OUTB(0x3C5, temp);
}

static void
TRIDENTDisableMMIO(ScrnInfoPtr pScrn)
{
    int vgaIOBase = VGAHWPTR(pScrn)->IOBase;
    CARD8 temp = 0, protect = 0;
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    /*
     * Skip MMIO Disable in PC-9821 PCI Trident Card!!
     * Because of lack of non PCI VGA port
     */
    if (IsPciCard && xf86IsPc98())
      return;

    /* Goto New Mode */
    OUTB(0x3C4, 0x0B); temp = INB(0x3C5);

    /* Unprotect registers */
    OUTB(0x3C4, NewMode1); temp = INB(0x3C5);
    OUTB(0x3C5, 0x80);
    if (pTrident->Chipset > PROVIDIA9685) {
    	OUTB(0x3C4, Protection);
    	protect = INB(0x3C5);
    	OUTB(0x3C5, 0x92);
    }

    /* Disable MMIO access */
    OUTB(vgaIOBase + 4, PCIReg); 
    pTrident->REGPCIReg = INB(vgaIOBase + 5);
    OUTB(vgaIOBase + 5, pTrident->REGPCIReg & 0xFE);

    /* Protect registers */
    if (pTrident->Chipset > PROVIDIA9685) {
    	outb(pTrident->PIOBase + 0x3C4, Protection);
    	outb(pTrident->PIOBase + 0x3C5, protect);
    }
    outb(pTrident->PIOBase + 0x3C4, NewMode1);
    outb(pTrident->PIOBase + 0x3C5, temp);
}

/* Initialize VGA Block for Trident Chip on PC-98x1 */
static void
PC98TRIDENTInit(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    switch (pTrident->Chipset) {
    case TGUI9660:
    case TGUI9680:
    case PROVIDIA9682:
	PC98TRIDENT96xxInit(pScrn);
	break;
    case CYBER9320:
    case CYBER9385:
	PC98TRIDENT9385Init(pScrn);
	break;
    default: /* Run 96xx code as default */
	PC98TRIDENT96xxInit(pScrn);
	break;
    }
}

static void
PC98TRIDENTEnable(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    switch (pTrident->Chipset) {
    case TGUI9660:
    case TGUI9680:
    case PROVIDIA9682:
	PC98TRIDENT96xxEnable(pScrn);
	break;
    case CYBER9320:
    case CYBER9385:
	PC98TRIDENT9385Enable(pScrn);
	break;
    default: /* Run 96xx code as default */
	PC98TRIDENT96xxEnable(pScrn);
	break;
    }
}

static void
PC98TRIDENTDisable(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    switch (pTrident->Chipset) {
    case TGUI9660:
    case TGUI9680:
    case PROVIDIA9682:
	PC98TRIDENT96xxDisable(pScrn);
	break;
    case CYBER9320:
    case CYBER9385:
	PC98TRIDENT9385Disable(pScrn);
	break;
    default: /* Run 96xx code as default */
	PC98TRIDENT96xxDisable(pScrn);
	break;
    }
}

/* Initialize VGA Block for Cyber9385 on PC-98x1 */
static void
PC98TRIDENT9385Init(ScrnInfoPtr pScrn)
{
/* Nothing to initialize */
}

static void
PC98TRIDENT9385Enable(ScrnInfoPtr pScrn)
{
    outb(0xFAC, 0x02);
}

static void
PC98TRIDENT9385Disable(ScrnInfoPtr pScrn)
{
    outb(0xFAC, 0x00);
}

/* Initialize VGA Block for Trident96xx on PC-98x1 */
static void
PC98TRIDENT96xxInit(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    CARD8 temp = 0;

    vgaHWProtect(pScrn, TRUE);

    /* Video SusSystem Enable */
    temp = INB(0x3CC);
    OUTB(0x3C2, temp | 0xC3);
    /* Switch Old */
    OUTB(0x3C4, 0x0B); temp = INB(0x3C5);
    OUTW(0x3C4, 0x0B | (temp << 8));
    /* Select Configuration Port 1 */
    OUTB(0x3C4, 0x0E); temp = INB(0x3C5);
    OUTW(0x3C4, 0x0E | ((temp | 0x20) << 8));

    OUTB(0x3C4, 0x0c);
    if((INB(0x3C5) & 0x10) == 0x10)
    {
	OUTB(0x3C4, 0x0E | (temp << 8));
	OUTB(0x94,  0x00);
	OUTB(0x102, 0x01);
	OUTB(0x94,  0x20);
	temp = INB(0x3C3);
	OUTB(0x3C3, temp | 0x01);
    } else {
	OUTB(0x3C4, 0x0E | (temp << 8));
	OUTB(0x46E8, 0x10);
	OUTB(0x102,  0x01);
	OUTB(0x46E8, 0x08);
    }

    INB(0x3DA);
    OUTB(0x3C0,0x10);
    OUTB(0x3C0,0x41);
  
    /* Register Unlock */
    vgaHWUnlock(hwp);
    OUTB(0x3C4, 0x0B); temp = INB(0x3C5); /* Switch New */
    OUTB(0x3C4, 0x0E); temp = INB(0x3C5);
    OUTW(0x3C4, 0x0E | ((temp | 0x80) << 8));

    /* For Speed Up [Facoor 2 at Xengine] */
    OUTW(0x3D4, 0x3820); /* Command FIFO Register */
    OUTW(0x3D4, 0x2020); /* Command FIFO Register */
    /* Latency Control Registers 0x30 - 0x32 */
    /* Parameter Range 0x00 - 0x0F */
    /* Tune these parameter to avoid GE Timeout */
    OUTW(0x3D4, 0x0E30); /* Display Queue Latency Control */
    /* 8bpp GE No Timeout Parameter 0x0D - 0x0F for PC-9821Xa7 TGUi9680 */
    OUTW(0x3D4, 0x0031); /* Frame Buffer Latency Control */
    OUTW(0x3D4, 0x0032); /* Display & Frame Buffer Latency Control */
    OUTW(0x3D4, 0x213B); /* Clock and Tuning */

    /* MCLK Init */
    OUTB(0x43C6, 0xAF); OUTB(0x43C7, 0x00); /* 80.0MHz */
#if 0
    /* Sample MCLKs */
    OUTB(0x43C6, 0xAF); OUTB(0x43C7, 0x00); /* 80.0MHz */
    OUTB(0x43C6, 0xA7); OUTB(0x43C7, 0x00); /* 77.0MHz */
    OUTB(0x43C6, 0x8E); OUTB(0x43C7, 0x00); /* 75.0MHz */
    OUTB(0x43C6, 0x86); OUTB(0x43C7, 0x00); /* 72.0MHz */
    OUTB(0x43C6, 0x8F); OUTB(0x43C7, 0x00); /* 67.2MHz */
    OUTB(0x43C6, 0xD5); OUTB(0x43C7, 0x02); /* 61.6MHz */
#endif

    /* Register Lock */
    OUTB(0x3C4, 0x0B); temp = INB(0x3C5); /* Switch New */
    OUTB(0x3C4, 0x0E); temp = INB(0x3C5);
    OUTW(0x3C4, 0x0E | ((temp & 0x7F) << 8));
    vgaHWLock(hwp);

    vgaHWProtect(pScrn, FALSE);
}

static void
PC98TRIDENT96xxEnable(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    CARD8 temp = 0;

    outb(0x68, 0x0E);
    outb(0x6A, 0x07);
    outb(0x6A, 0x8F);
    outb(0x6A, 0x06);

    vgaHWProtect(pScrn, TRUE);

    OUTB(0x3D4, 0x23); temp = INB(0x3D5);
    OUTW(0x3D4, 0x23 | ((temp & 0xDF) << 8));

    OUTB(0x3D4, 0x29); temp = INB(0x3D5);
    OUTW(0x3D4, 0x29 | ((temp | 0x04) << 8));

    OUTB(0x83C8, 0x04); temp = INB(0x83c6);
    OUTB(0x83C8, 0x04); OUTB(0x83c6, (temp | 0x06));

    OUTB(0x83C8, 0x04); temp = INB(0x83c6);
    OUTB(0x83C8, 0x04); OUTB(0x83c6, (temp | 0x08));

    OUTB(0x3CE, 0x23); temp = INB(0x3CF);
    OUTW(0x3CE, 0x23 | ((temp & 0xFC) << 8));

    OUTB(0x83C8, 0x04); temp = INB(0x83c6);
    OUTB(0x83C8, 0x04); OUTB(0x83c6, (temp | 0x01));

    OUTB(0x3C4, 0x01); temp = INB(0x3C5);
    OUTW(0x3C4, 0x01 | ((temp & 0xEF) << 8));

    vgaHWProtect(pScrn, FALSE);

    outb(0xFAC, 0x02);
}

static void
PC98TRIDENT96xxDisable(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    CARD8 temp = 0;

    outb(0xFAC, 0x00);

    vgaHWProtect(pScrn, TRUE);

    OUTB(0x3C4, 0x01); temp = INB(0x3C5);
    OUTW(0x3C4, 0x01 | ((temp | 0x10) << 8));

    OUTB(0x83C8, 0x04); temp = INB(0x83c6);
    OUTB(0x83C8, 0x04); OUTB(0x83c6, (temp & 0xFE));

    OUTB(0x3CE, 0x23); temp = INB(0x3CF);
    OUTW(0x3CE, 0x23 | (((temp & 0xFC) | 0x01) << 8));

    OUTB(0x83C8, 0x04); temp = INB(0x83c6);
    OUTB(0x83C8, 0x04); OUTB(0x83c6, (temp & 0xFD));

    OUTB(0x83C8, 0x04); temp = INB(0x83c6);
    OUTB(0x83C8, 0x04); OUTB(0x83c6, (temp & 0xCF));

    OUTB(0x83C8, 0x04); temp = INB(0x83c6);
    OUTB(0x83C8, 0x04); OUTB(0x83c6, (temp & 0xF7));

    OUTB(0x83C8, 0x04); temp = INB(0x83c6);
    OUTB(0x83C8, 0x04); OUTB(0x83c6, (temp & 0xFB));

    OUTB(0x3D4, 0x29); temp = INB(0x3D5);
    OUTW(0x3D4, 0x29 | ((temp & 0xFB) << 8));

    OUTB(0x3D4, 0x23); temp = INB(0x3D5);
    OUTW(0x3D4, 0x23 | ((temp | 0x20) << 8));

    vgaHWProtect(pScrn, FALSE);

    outb(0x6A, 0x07);
    outb(0x6A, 0x8E);
    outb(0x6A, 0x06);
    outb(0x68, 0x0F);
}


/* 
 * This is a terrible hack! If we are on a notebook in a stretched
 * mode and don't want full screen we use the BIOS to set an unstreched
 * mode.
 */
void
tridentSetModeBIOS(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);


#ifdef VBE_INFO
    if (pTrident->vbeModes) {
	vbeSaveRestoreRec vbesr;
	vbesr.stateMode = VBECalcVbeModeIndex(pTrident->vbeModes,
					     mode, pScrn->bitsPerPixel);
	vbesr.pstate = NULL;
	if (vbesr.stateMode) {
	    if (IsPciCard && UseMMIO) 
		TRIDENTDisableMMIO(pScrn);
	    VBEVesaSaveRestore(pTrident->pVbe,&vbesr,MODE_RESTORE);
	    if (IsPciCard && UseMMIO) 
		TRIDENTEnableMMIO(pScrn);
	    return;
	} else
	    xf86DrvMsg(pScrn->scrnIndex,X_WARNING,"No BIOS Mode matches "
		       "%ix%I@%ibpp\n",mode->HDisplay,mode->VDisplay,
		       pScrn->bitsPerPixel);
    } 
#endif
    /* This function is only for LCD screens, and also when we have
     * int10 available */

    if (pTrident->IsCyber && pTrident->lcdMode && pTrident->Int10) {
        int i = pTrident->lcdMode;
	if ((pScrn->currentMode->HDisplay != LCD[i].display_x) /* !fullsize? */
	    || (pScrn->currentMode->VDisplay != LCD[i].display_y)) {
	    if (pTrident->lcdActive)  { /* LCD Active ?*/
	        int h_str, v_str;
		
		OUTB(0x3CE,HorStretch);  h_str = INB(0x3CF) & 0x01;
		OUTB(0x3CE,VertStretch); v_str = INB(0x3CF) & 0x01;
		if (h_str || v_str) {
		    OUTB(0x3C4, 0x11); OUTB(0x3C5, 0x92);
		    OUTW(0x3CE, BiosReg );
		    pTrident->Int10->ax = 0x3;
		    pTrident->Int10->num = 0x10;
		    if (IsPciCard && UseMMIO) 
			TRIDENTDisableMMIO(pScrn);
		    xf86ExecX86int10(pTrident->Int10);
		    if (IsPciCard && UseMMIO) 
			TRIDENTEnableMMIO(pScrn);
		}
	    }
	}
    }
}

