/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/via/via_driver.c,v 1.28 2004/02/08 17:57:10 tsi Exp $ */
/*
 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sub license,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/*************************************************************************
 *
 *  File:       via_driver.c
 *  Content:    XFree86 4.0 for VIA/S3G UniChrom
 *
 ************************************************************************/

#include "xf86RAC.h"
#include "shadowfb.h"

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


#include "via_driver.h"
#include "via_video.h"
#include "videodev.h"
#include "via_swov.h"

#include "ddmpeg.h"
#include "via_capture.h"
#include "via.h"
#ifdef XF86DRI
#include "dri.h"
#endif

/*
 * prototypes
 */

static void VIAIdentify(int flags);
static Bool VIAProbe(DriverPtr drv, int flags);
static Bool VIAPreInit(ScrnInfoPtr pScrn, int flags);
static Bool VIAEnterVT(int scrnIndex, int flags);
static void VIALeaveVT(int scrnIndex, int flags);
static void VIASave(ScrnInfoPtr pScrn);
static void VIAWriteMode(ScrnInfoPtr pScrn, vgaRegPtr, VIARegPtr);
static Bool VIAModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
static Bool VIACloseScreen(int scrnIndex, ScreenPtr pScreen);
static Bool VIASaveScreen(ScreenPtr pScreen, int mode);
static void VIALoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies,
                           LOCO *colors, VisualPtr pVisual);
static Bool VIAScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
                          char **argv);
static int VIAInternalScreenInit(int scrnIndex, ScreenPtr pScreen);
static void VIAFreeScreen(int scrnIndex, int flags);
static ModeStatus VIAValidMode(int index, DisplayModePtr mode,
                               Bool verbose, int flags);
static void VIADPMS(ScrnInfoPtr pScrn, int mode, int flags);
static const OptionInfoRec * VIAAvailableOptions(int chipid, int busid);


static void VIAEnableMMIO(ScrnInfoPtr pScrn);
static void VIADisableMMIO(ScrnInfoPtr pScrn);
static Bool VIAMapMMIO(ScrnInfoPtr pScrn);
static Bool VIAMapFB(ScrnInfoPtr pScrn);
static void VIAUnmapMem(ScrnInfoPtr pScrn);
Bool VIADeviceSelection(ScrnInfoPtr pScrn);
Bool VIADeviceDispatch(ScrnInfoPtr pScrn);

#ifdef XF86DRI
void VIAInitialize3DEngine(ScrnInfoPtr pScrn);
#endif

DriverRec VIA =
{
    VIA_VERSION,
    DRIVER_NAME,
    VIAIdentify,
    VIAProbe,
    VIAAvailableOptions,
    NULL,
    0
};


/* Supported chipsets */

static SymTabRec VIAChipsets[] = {
    {VIA_CLE266,   "CLE266"},
    {VIA_KM400,    "KM400"},
    {VIA_K8M800,   "K8M800"},
    {-1,            NULL }
};


/* This table maps a PCI device ID to a chipset family identifier. */

static PciChipsets VIAPciChipsets[] = {
    {VIA_CLE266,   PCI_CHIP_CLE3122,   RES_SHARED_VGA},
    {VIA_CLE266,   PCI_CHIP_CLE3022,   RES_SHARED_VGA},
    {VIA_KM400,    PCI_CHIP_VT7205,    RES_SHARED_VGA},
    {VIA_KM400,    PCI_CHIP_VT3205,    RES_SHARED_VGA},
    {VIA_K8M800,   PCI_CHIP_VT7204,    RES_SHARED_VGA},
    {VIA_K8M800,   PCI_CHIP_VT3204,    RES_SHARED_VGA},
    {-1,            -1,                RES_UNDEFINED}
};

int gVIAEntityIndex = -1;

typedef enum {
    OPTION_A2,
    OPTION_PCI_BURST,
    OPTION_PCI_RETRY,
    OPTION_NOACCEL,
    OPTION_SWCURSOR,
    OPTION_HWCURSOR,
    OPTION_SHADOW_FB,
    OPTION_ROTATE,
    OPTION_USEBIOS,
    OPTION_VIDEORAM,
    OPTION_ACTIVEDEVICE,
    OPTION_LCDDUALEDGE,
    OPTION_BUSWIDTH,
    OPTION_CENTER,
    OPTION_PANELSIZE,
    OPTION_TVDOTCRAWL,
    OPTION_TVTYPE,
    OPTION_TVOUTPUT,
    OPTION_TVVSCAN,
    OPTION_TVHSCALE,
    OPTION_TVENCODER,
    OPTION_REFRESH,
    OPTION_DISABLEVQ,
    OPTION_NODDCVALUE,
    OPTION_CAP0_DEINTERLACE,
    OPTION_CAP1_DEINTERLACE,
    OPTION_CAP0_FIELDSWAP,
    OPTION_DRIXINERAMA
} VIAOpts;


static OptionInfoRec VIAOptions[] =
{
    {OPTION_A2,         "A2",           OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_NOACCEL,    "NoAccel",      OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_HWCURSOR,   "HWCursor",     OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_SWCURSOR,   "SWCursor",     OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_SHADOW_FB,  "ShadowFB",     OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_ROTATE,     "Rotate",       OPTV_ANYSTR,  {0}, FALSE},
    {OPTION_USEBIOS,    "UseBIOS",      OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_VIDEORAM,   "VideoRAM",     OPTV_INTEGER, {0}, FALSE},
    {OPTION_ACTIVEDEVICE,     "ActiveDevice",       OPTV_ANYSTR,  {0}, FALSE},
    {OPTION_LCDDUALEDGE,    "LCDDualEdge",  OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_BUSWIDTH,	"BusWidth",  	OPTV_ANYSTR, {0}, FALSE},
    {OPTION_CENTER,     "Center",       OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_PANELSIZE,  "PanelSize",    OPTV_ANYSTR,  {0}, FALSE},
    {OPTION_TVDOTCRAWL, "TVDotCrawl",   OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_TVTYPE,     "TVType",       OPTV_ANYSTR,  {0}, FALSE},
    {OPTION_TVOUTPUT,   "TVOutput",     OPTV_ANYSTR,  {0}, FALSE},
    {OPTION_TVVSCAN,    "TVVScan",      OPTV_ANYSTR,  {0}, FALSE},
    {OPTION_TVHSCALE,   "TVHScale",     OPTV_ANYSTR,  {0}, FALSE},
    {OPTION_TVENCODER,  "TVEncoder",    OPTV_ANYSTR,  {0}, FALSE},
    {OPTION_REFRESH,    "Refresh",      OPTV_INTEGER, {0}, FALSE},
    {OPTION_DISABLEVQ,  "DisableVQ",    OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_NODDCVALUE, "NoDDCValue",   OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_CAP0_DEINTERLACE, "Cap0Deinterlace",    OPTV_ANYSTR,  {0}, FALSE},
    {OPTION_CAP1_DEINTERLACE, "Cap1Deinterlace",    OPTV_ANYSTR,  {0}, FALSE},
    {OPTION_CAP0_FIELDSWAP, "Cap0FieldSwap",    OPTV_BOOLEAN,  {0}, FALSE},
    {OPTION_DRIXINERAMA,  "DRIXINERAMA",    OPTV_BOOLEAN, {0}, FALSE},
    {-1,                NULL,           OPTV_NONE,    {0}, FALSE}
};


static const char *vgaHWSymbols[] = {
    "vgaHWGetHWRec",
    "vgaHWSetMmioFuncs",
    "vgaHWSetStdFuncs",
    "vgaHWGetIOBase",
    "vgaHWSave",
    "vgaHWProtect",
    "vgaHWRestore",
    "vgaHWMapMem",
    "vgaHWUnmapMem",
    "vgaHWInit",
    "vgaHWSaveScreen",
    "vgaHWLock",
    "vgaHWUnlock",
    "vgaHWFreeHWRec",
    "vgaHWddc1SetSpeedWeak",
    NULL
};


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

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

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


static const char *i2cSymbols[] = {
    "xf86CreateI2CBusRec",
    "xf86I2CBusInit",
    "xf86CreateI2CDevRec",
    "xf86I2CDevInit",
    "xf86I2CWriteRead",
    "xf86I2CProbeAddress",
    "xf86DestroyI2CDevRec",
    NULL
};

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

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

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

#ifdef USE_FB
static const char *fbSymbols[] = {
    "fbScreenInit",
    "fbPictureInit",
    NULL
};
#else
static const char *cfbSymbols[] = {
    "cfbScreenInit",
    "cfb16ScreenInit",
    "cfb24ScreenInit",
    "cfb24_32ScreenInit",
    "cfb32ScreenInit",
    "cfb16BresS",
    "cfb24BresS",
    NULL
};
#endif

#ifdef XFree86LOADER
#ifdef XF86DRI
static const char *drmSymbols[] = {
    "drmAddBufs",
    "drmAddMap",
    "drmAgpAcquire",
    "drmAgpAlloc",
    "drmAgpBase",
    "drmAgpBind",
    "drmAgpDeviceId",
    "drmAgpEnable",
    "drmAgpFree",
    "drmAgpGetMode",
    "drmAgpRelease",
    "drmAgpVendorId",
    "drmCtlInstHandler",
    "drmCtlUninstHandler",
    "drmCommandNone",
    "drmCommandWrite",
    "drmFreeVersion",
    "drmGetInterruptFromBusID",
    "drmGetLibVersion",
    "drmGetVersion",
    "drmMap",
    "drmMapBufs",
    "drmUnmap",
    "drmUnmapBufs",
    NULL
};

static const char *driSymbols[] = {
    "DRICloseScreen",
    "DRICreateInfoRec",
    "DRIDestroyInfoRec",
    "DRIFinishScreenInit",
    "DRIGetSAREAPrivate",
    "DRILock",
    "DRIQueryVersion",
    "DRIScreenInit",
    "DRIUnlock",
    "GlxSetVisualConfigs",
    NULL
};
#endif

static MODULESETUPPROTO(VIASetup);

static XF86ModuleVersionInfo VIAVersRec = {
    "via",
    MODULEVENDORSTRING,
    MODINFOSTRING1,
    MODINFOSTRING2,
    XF86_VERSION_CURRENT,
    VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
    ABI_CLASS_VIDEODRV,
    ABI_VIDEODRV_VERSION,
    MOD_CLASS_VIDEODRV,
    {0, 0, 0, 0}
};

XF86ModuleData viaModuleData = {&VIAVersRec, VIASetup, NULL};


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

    if (!setupDone) {
        setupDone = TRUE;
        xf86AddDriver(&VIA, module, 0);
        LoaderRefSymLists(vgaHWSymbols,
#ifdef USE_FB
                          fbSymbols,
#else
                          cfbSymbols,
#endif
                          ramdacSymbols,
                          xaaSymbols,
                          shadowSymbols,
                          vbeSymbols,
                          i2cSymbols,
                          ddcSymbols,
                          /*
                          mpegSymbols,
                          */
#ifdef XF86DRI
              			  drmSymbols,
              			  driSymbols,
#endif
                          NULL);

        return (pointer) 1;
    }
    else {
        if (errmaj)
            *errmaj = LDR_ONCEONLY;

        return NULL;
    }
} /* VIASetup */

#endif /* XFree86LOADER */

static void viaFillGraphicInfo(ScrnInfoPtr pScrn)
{
	VIAPtr pVia = VIAPTR(pScrn);
	VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;

        pVia->graphicInfo.TotalVRAM = pVia->videoRambytes;
        pVia->graphicInfo.VideoHeapBase = (unsigned long) pVia->FBFreeStart;
        pVia->graphicInfo.VideoHeapEnd = (unsigned long) (pVia->FBFreeEnd - 1);
        pVia->graphicInfo.dwWidth = pBIOSInfo->CrtcHDisplay;
        pVia->graphicInfo.dwHeight = pBIOSInfo->CrtcVDisplay;
        pVia->graphicInfo.dwBPP = pScrn->bitsPerPixel;
        pVia->graphicInfo.dwPitch = (((pScrn->virtualX) + 15) & ~15) * (pScrn->bitsPerPixel) / 8;
        pVia->graphicInfo.dwRefreshRate = (unsigned long)pBIOSInfo->FoundRefresh;
        pVia->graphicInfo.dwDVIOn = pBIOSInfo->DVIAttach;
        pVia->graphicInfo.dwExpand = pBIOSInfo->scaleY;
        pVia->graphicInfo.dwPanelWidth = pBIOSInfo->panelX;
        pVia->graphicInfo.dwPanelHeight = pBIOSInfo->panelY;
        pVia->graphicInfo.Cap0_Deinterlace = pVia->Cap0_Deinterlace;
        pVia->graphicInfo.Cap1_Deinterlace = pVia->Cap1_Deinterlace;
        pVia->graphicInfo.Cap0_FieldSwap = pVia->Cap0_FieldSwap;
        pVia->graphicInfo.RevisionID = pVia->ChipRev;

        /* for SAMM mode passing screen info */
        pVia->graphicInfo.HasSecondary = pBIOSInfo->HasSecondary;
        pVia->graphicInfo.IsSecondary = pBIOSInfo->IsSecondary;

        /* Added to pass DRM info to V4L */
#ifdef XF86DRI
        pVia->graphicInfo.DRMEnabled = pVia->directRenderingEnabled;
#endif
}

static int
WaitIdleCLE266(VIAPtr pVia)
{
    int loop = 0;

    mem_barrier();

    while (!(VIAGETREG(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && (loop++ < MAXLOOP))
        ;

    while ((VIAGETREG(VIA_REG_STATUS) &
          (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) &&
          (loop++ < MAXLOOP))
        ;

    return loop >= MAXLOOP;
}


static Bool VIAGetRec(ScrnInfoPtr pScrn)
{
    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAGetRec\n"));
    if (pScrn->driverPrivate)
        return TRUE;

    pScrn->driverPrivate = xnfcalloc(sizeof(VIARec), 1);
    ((VIARec *)(pScrn->driverPrivate))->pBIOSInfo =
        xnfcalloc(sizeof(VIABIOSInfoRec), 1);
    ((VIARec *)(pScrn->driverPrivate))->pBIOSInfo->UserSetting =
        xnfcalloc(sizeof(VIAUserSettingRec), 1);
    ((VIARec *)(pScrn->driverPrivate))->pBIOSInfo->pModeTable =
        xnfcalloc(sizeof(VIAModeTableRec), 1);

    /* initial value in VIARec */
    ((VIARec *)(pScrn->driverPrivate))->SavedReg.mode = 0xFF;
    ((VIARec *)(pScrn->driverPrivate))->ModeReg.mode = 0xFF;

    ((VIARec *)(pScrn->driverPrivate))->pBIOSInfo->FirstInit = TRUE;

    return TRUE;

} /* VIAGetRec */


static void VIAFreeRec(ScrnInfoPtr pScrn)
{
    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAFreeRec\n"));
    if (!pScrn->driverPrivate)
        return;

    xfree(((VIARec *)(pScrn->driverPrivate))->pBIOSInfo->pModeTable);
    xfree(((VIARec *)(pScrn->driverPrivate))->pBIOSInfo->UserSetting);
    xfree(((VIARec *)(pScrn->driverPrivate))->pBIOSInfo);
    ViaTunerDestroy(pScrn);
    xfree(pScrn->driverPrivate);
    pScrn->driverPrivate = NULL;

    VIAUnmapMem(pScrn);

} /* VIAFreeRec */


static const OptionInfoRec * VIAAvailableOptions(int chipid, int busid)
{

    return VIAOptions;

} /* VIAAvailableOptions */


static void VIAIdentify(int flags)
{
    xf86PrintChipsets(DRIVER_NAME,
                      "driver for VIA chipsets",
                      VIAChipsets);
} /* VIAIdentify */


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

    /* sanity checks */
    if ((numDevSections = xf86MatchDevice(DRIVER_NAME, &devSections)) <= 0)
        return FALSE;

    if (xf86GetPciVideoInfo() == NULL)
        return FALSE;

    numUsed = xf86MatchPciInstances(DRIVER_NAME,
                                    PCI_VIA_VENDOR_ID,
                                    VIAChipsets,
                                    VIAPciChipsets,
                                    devSections,
                                    numDevSections,
                                    drv,
                                    &usedChips);
    xfree(devSections);

    if (numUsed <= 0)
        return FALSE;

    if (flags & PROBE_DETECT) {
        foundScreen = TRUE;
    }
    else {
        for (i = 0; i < numUsed; i++) {
            ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0);
            EntityInfoPtr pEnt;
            if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
                 VIAPciChipsets, 0, 0, 0, 0, 0)))
            {
                pScrn->driverVersion = VIA_VERSION;
                pScrn->driverName = DRIVER_NAME;
                pScrn->name = "VIA";
                pScrn->Probe = VIAProbe;
                pScrn->PreInit = VIAPreInit;
                pScrn->ScreenInit = VIAScreenInit;
                pScrn->SwitchMode = VIASwitchMode;
                pScrn->AdjustFrame = VIAAdjustFrame;
                pScrn->EnterVT = VIAEnterVT;
                pScrn->LeaveVT = VIALeaveVT;
                pScrn->FreeScreen = VIAFreeScreen;
                pScrn->ValidMode = VIAValidMode;
                foundScreen = TRUE;
            }
            /*
            xf86ConfigActivePciEntity(pScrn,
                                      usedChips[i],
                                      VIAPciChipsets,
                                      NULL,
                                      NULL,
                                      NULL,
                                      NULL,
                                      NULL);
            */

            pEnt = xf86GetEntityInfo(usedChips[i]);

            /* CLE266 card support Dual-Head, mark the entity as sharable*/
            if(pEnt->chipset == VIA_CLE266 || pEnt->chipset == VIA_KM400)
            {
                static int instance = 0;
                DevUnion* pPriv;

                xf86SetEntitySharable(usedChips[i]);
                xf86SetEntityInstanceForScreen(pScrn,
                    pScrn->entityList[0], instance);

                if(gVIAEntityIndex < 0)
                {
                    gVIAEntityIndex = xf86AllocateEntityPrivateIndex();
                    pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
                            gVIAEntityIndex);

                    if (!pPriv->ptr)
                    {
                        VIAEntPtr pVIAEnt;
                        pPriv->ptr = xnfcalloc(sizeof(VIAEntRec), 1);
                        pVIAEnt = pPriv->ptr;
                        pVIAEnt->IsDRIEnabled = FALSE;
                        pVIAEnt->BypassSecondary = FALSE;
                        pVIAEnt->HasSecondary = FALSE;
                        pVIAEnt->IsSecondaryRestored = FALSE;
                    }
                }
                instance++;
            }
            xfree(pEnt);
        }
    }

    xfree(usedChips);

    return foundScreen;

} /* VIAProbe */


static int LookupChipID(PciChipsets* pset, int ChipID)
{
    /* Is there a function to do this for me? */
    while (pset->numChipset >= 0)
    {
        if (pset->PCIid == ChipID)
            return pset->numChipset;

        pset++;
    }

    return -1;

} /* LookupChipID */


static unsigned int
VIAddc1Read(ScrnInfoPtr pScrn)
{
    register vgaHWPtr hwp = VGAHWPTR(pScrn);
    VIAPtr pVia = VIAPTR(pScrn);
    register CARD8 tmp;

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

    VGAOUT8(0x3c4, 0x26);
    tmp = VGAIN8(0x3c5);
    return ((unsigned int) ((tmp & 0x08) >> 3));
}

static Bool
VIAddc1(int scrnIndex)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    VIAPtr pVia = VIAPTR(pScrn);
    xf86MonPtr pMon;
    CARD8 tmp;
    Bool success = FALSE;

    /* initialize chipset */
    VGAOUT8(0x3c4, 0x26);
    tmp = VGAIN8(0x3c5);
    VGAOUT8(0x3c4, 0x26);
    VGAOUT8(0x3c5, (tmp | 0x11));

    if ((pMon = xf86PrintEDID(
        xf86DoEDID_DDC1(scrnIndex,vgaHWddc1SetSpeedWeak(),
	                VIAddc1Read))) != NULL)
        success = TRUE;
    xf86SetDDCproperties(pScrn,pMon);

    /* undo initialization */
    VGAOUT8(0x3c4, 0x26);
    VGAOUT8(0x3c5, tmp);
    return success;
}

static Bool
VIAddc2(int scrnIndex)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    VIAPtr pVia = VIAPTR(pScrn);
    xf86MonPtr pMon;
    CARD8 tmp;
    Bool success = FALSE;

    VGAOUT8(0x3c4, 0x26);
    tmp = VGAIN8(0x3c5);
    pMon = xf86DoEDID_DDC2(pScrn->scrnIndex, pVia->I2C_Port1);
    if (pMon)
        success = TRUE;
    pVia->DDC1 =  pMon;
    xf86PrintEDID(pMon);
    xf86SetDDCproperties(pScrn, pMon);
    VGAOUT8(0x3c4, 0x26);
    VGAOUT8(0x3c5, tmp);

    return success;
}

static void
VIAProbeDDC(ScrnInfoPtr pScrn, int index)
{
    vbeInfoPtr pVbe;

    if (xf86LoadSubModule(pScrn, "vbe")) {
        pVbe = VBEInit(NULL,index);
        ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
    }
}


static Bool VIAPreInit(ScrnInfoPtr pScrn, int flags)
{
    EntityInfoPtr   pEnt;
    VIAPtr          pVia;
    VIABIOSInfoPtr  pBIOSInfo;
    MessageType     from = X_DEFAULT;
    ClockRangePtr   clockRanges;
    char            *s = NULL;
#ifndef USE_FB
    char            *mod = NULL;
    const char      *reqSym = NULL;
#endif
    vgaHWPtr        hwp;
    int             i, bMemSize = 0, tmp;

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAPreInit\n"));

    if (pScrn->numEntities > 1)
        return FALSE;

    if (flags & PROBE_DETECT)
        return FALSE;

    if (!xf86LoadSubModule(pScrn, "vgahw"))
        return FALSE;

    xf86LoaderReqSymLists(vgaHWSymbols, NULL);
    if (!vgaHWGetHWRec(pScrn))
        return FALSE;

#if 0
    /* Here we can alter the number of registers saved and restored by the
     * standard vgaHWSave and Restore routines.
     */
    vgaHWSetRegCounts(pScrn, VGA_NUM_CRTC, VGA_NUM_SEQ, VGA_NUM_GFX, VGA_NUM_ATTR);
#endif

    if (!VIAGetRec(pScrn)) {
        return FALSE;
    }

    pVia = VIAPTR(pScrn);
    pBIOSInfo = pVia->pBIOSInfo;

    pVia->IsSecondary = FALSE;
    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
    if (pEnt->resources) {
        xfree(pEnt);
        VIAFreeRec(pScrn);
        return FALSE;
    }

    pVia->EntityIndex = pEnt->index;

    if(xf86IsEntityShared(pScrn->entityList[0]))
    {
        if(xf86IsPrimInitDone(pScrn->entityList[0]))
        {
            DevUnion* pPriv;
            VIAEntPtr pVIAEnt;
            VIAPtr pVia1;

            pVia->IsSecondary = TRUE;
            pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
                    gVIAEntityIndex);
            pVIAEnt = pPriv->ptr;
            if(pVIAEnt->BypassSecondary) return FALSE;
            pVIAEnt->pSecondaryScrn = pScrn;
            pVIAEnt->HasSecondary = TRUE;
            pVia1 = VIAPTR(pVIAEnt->pPrimaryScrn);
            pVia1->HasSecondary = TRUE;
	    pVia->sharedData = pVia1->sharedData;
        }
        else
        {
            DevUnion* pPriv;
            VIAEntPtr pVIAEnt;

            xf86SetPrimInitDone(pScrn->entityList[0]);
            pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
                    gVIAEntityIndex);
	    pVia->sharedData = xnfcalloc(sizeof(ViaSharedRec),1);
            pVIAEnt = pPriv->ptr;
            pVIAEnt->pPrimaryScrn = pScrn;
            pVIAEnt->IsDRIEnabled = FALSE;
            pVIAEnt->BypassSecondary = FALSE;
            pVIAEnt->HasSecondary = FALSE;
            pVIAEnt->RestorePrimary = FALSE;
            pVIAEnt->IsSecondaryRestored = FALSE;
        }
    } else {
	pVia->sharedData = xnfcalloc(sizeof(ViaSharedRec),1);
    }

    if (flags & PROBE_DETECT) {
        VIAProbeDDC(pScrn, pVia->EntityIndex);
        return TRUE;
    }

    pScrn->monitor = pScrn->confScreen->monitor;

    /*
     * We support depths of 8, 16 and 24.
     * We support bpp of 8, 16, and 32.
     */

    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb)) {
        return FALSE;
    }
    else {
        switch (pScrn->depth) {
        case 8:
        case 16:
        case 24:
        case 32:
            /* OK */
            break;
        default:
            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                       "Given depth (%d) is not supported by this driver\n",
                       pScrn->depth);
            return FALSE;
        }
    }

    xf86PrintDepthBpp(pScrn);

    if (pScrn->depth == 32) {
        pScrn->depth = 24;
    }

    if (pScrn->depth > 8) {
        rgb zeros = {0, 0, 0};

        if (!xf86SetWeight(pScrn, zeros, zeros))
            return FALSE;
        else {
            /* TODO check 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;
        }
    }

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

    xf86CollectOptions(pScrn, NULL);

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

    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, VIAOptions);

#ifdef XF86DRI
    pVia->drixinerama = FALSE;
    if (xf86IsOptionSet(VIAOptions, OPTION_DRIXINERAMA))
        pVia->drixinerama = TRUE;
#else
    if (xf86IsOptionSet(VIAOptions, OPTION_DRIXINERAMA))
    	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
    		"Option: drixinerama ignored, no DRI support compiled into driver.\n");
#endif
    if (xf86ReturnOptValBool(VIAOptions, OPTION_PCI_BURST, FALSE)) {
        pVia->pci_burst = TRUE;
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                   "Option: pci_burst - PCI burst read enabled\n");
    }
    else {
        pVia->pci_burst = FALSE;
    }

    pVia->NoPCIRetry = 1;       /* default */
    if (xf86ReturnOptValBool(VIAOptions, OPTION_PCI_RETRY, FALSE)) {
        if (xf86ReturnOptValBool(VIAOptions, OPTION_PCI_BURST, FALSE)) {
            pVia->NoPCIRetry = 0;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_retry\n");
        }
        else {
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                       "\"pci_retry\" option requires \"pci_burst\"\n");
        }
    }

    if (xf86IsOptionSet(VIAOptions, OPTION_SHADOW_FB)) {
        pVia->shadowFB = TRUE;
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: ShadowFB %s.\n",
                   pVia->shadowFB ? "enabled" : "disabled");
    }
    else {
        pVia->shadowFB = FALSE;
    }

    if ((s = xf86GetOptValString(VIAOptions, OPTION_ROTATE))) {
        if (!xf86NameCmp(s, "CW")) {
            /* accel is disabled below for shadowFB */
            pVia->shadowFB = TRUE;
            pVia->rotate = 1;
            pVia->hwcursor = FALSE;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                       "Rotating screen clockwise - acceleration disabled\n");
        }
        else if(!xf86NameCmp(s, "CCW")) {
            pVia->shadowFB = TRUE;
            pVia->rotate = -1;
            pVia->hwcursor = FALSE;
            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");
        }
    }

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

    if (pVia->shadowFB && !pVia->NoAccel) {
        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
                   "HW acceleration not supported with \"shadowFB\".\n");
        pVia->NoAccel = TRUE;
    }

    /*
     * The SWCursor setting takes priority over HWCursor.  The default
     * if neither is specified is HW.
     */

    from = X_DEFAULT;
    pVia->hwcursor = pVia->shadowFB ? FALSE : TRUE;
    if (xf86GetOptValBool(VIAOptions, OPTION_HWCURSOR, &pVia->hwcursor))
        from = X_CONFIG;

    if (xf86ReturnOptValBool(VIAOptions, OPTION_SWCURSOR, FALSE)) {
        pVia->hwcursor = FALSE;
        from = X_CONFIG;
    }

    if (pVia->IsSecondary) pVia->hwcursor = FALSE;

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

    if (xf86ReturnOptValBool(VIAOptions, OPTION_A2, FALSE)) {
        pBIOSInfo->A2 = TRUE;
    }
    else {
        pBIOSInfo->A2 = FALSE;
    }

    from = X_DEFAULT;
    if (xf86ReturnOptValBool(VIAOptions, OPTION_USEBIOS, FALSE)) {
        from = X_CONFIG;
        pBIOSInfo->UseBIOS = TRUE;
    }
    else {
        pBIOSInfo->UseBIOS = FALSE;
    }
    xf86DrvMsg(pScrn->scrnIndex, from, "%ssing video BIOS to set modes\n",
               pBIOSInfo->UseBIOS ? "U" : "Not u" );

    pScrn->videoRam = 0;
    if(xf86GetOptValInteger(VIAOptions, OPTION_VIDEORAM, &pScrn->videoRam)) {
    	xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
    	            "Option: VideoRAM %dkB\n", pScrn->videoRam );
    }

    if (xf86ReturnOptValBool(VIAOptions, OPTION_DISABLEVQ, FALSE)) {
        pVia->VQEnable = FALSE;
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                   "Option: DisableVQ -VQ Disabled\n");
    }
    else {
        pVia->VQEnable = TRUE;
    }

    /* ActiveDevice Option for device selection */
    pBIOSInfo->ActiveDevice = 0x00;
    if ((s = xf86GetOptValString(VIAOptions, OPTION_ACTIVEDEVICE))) {
        if (!xf86NameCmp(s, "CRT,TV") || !xf86NameCmp(s, "TV,CRT")) {
            pBIOSInfo->ActiveDevice = VIA_DEVICE_CRT1 | VIA_DEVICE_TV;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Active Device is CRT and TV.\n");
        }
        else if(!xf86NameCmp(s, "CRT,LCD") || !xf86NameCmp(s, "LCD,CRT")) {
            pBIOSInfo->ActiveDevice = VIA_DEVICE_CRT1 | VIA_DEVICE_LCD;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Active Device is CRT and LCD.\n");
        }
        else if(!xf86NameCmp(s, "CRT,DFP") || !xf86NameCmp(s, "DFP,CRT")
                || !xf86NameCmp(s, "CRT,DVI") || !xf86NameCmp(s, "DVI,CRT")) {
            pBIOSInfo->ActiveDevice = VIA_DEVICE_CRT1 | VIA_DEVICE_DFP;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Active Device is CRT and DFP.\n");
        }
        else if(!xf86NameCmp(s, "TV,DFP") || !xf86NameCmp(s, "DFP,TV")
                || !xf86NameCmp(s, "TV,DVI") || !xf86NameCmp(s, "DVI,TV")) {
            pBIOSInfo->ActiveDevice = VIA_DEVICE_TV | VIA_DEVICE_DFP;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Active Device is TV and DFP.\n");
        }
#if 0
        else if(!xf86NameCmp(s, "DFP,LCD") || !xf86NameCmp(s, "LCD,DFP")
                || !xf86NameCmp(s, "LCD,DVI") || !xf86NameCmp(s, "DVI,LCD")) {
            pBIOSInfo->ActiveDevice = VIA_DEVICE_DFP | VIA_DEVICE_LCD;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Active Device is DFP and LCD.\n");
        }
#endif
        else if(!xf86NameCmp(s, "CRT") || !xf86NameCmp(s, "CRT ONLY")) {
            pBIOSInfo->ActiveDevice = VIA_DEVICE_CRT1;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Active Device is CRT Only.\n");
        }
        else if(!xf86NameCmp(s, "LCD") || !xf86NameCmp(s, "LCD ONLY")) {
            pBIOSInfo->ActiveDevice = VIA_DEVICE_LCD;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Active Device is LCD Only.\n");
        }
        else if(!xf86NameCmp(s, "TV") || !xf86NameCmp(s, "TV ONLY")) {
            pBIOSInfo->ActiveDevice = VIA_DEVICE_TV;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Active Device is TV Only.\n");
        }
        else if(!xf86NameCmp(s, "DFP") || !xf86NameCmp(s, "DFP ONLY")
                || !xf86NameCmp(s, "DVI") || !xf86NameCmp(s, "DVI ONLY")) {
            pBIOSInfo->ActiveDevice = VIA_DEVICE_DFP;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Active Device is DFP Only.\n");
        }
        else {
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option \"%s\" can't recognize!, Active Device by default.\n", s);
        }
    }

    /* NoDDCValue Option */
    if (xf86ReturnOptValBool(VIAOptions, OPTION_NODDCVALUE, FALSE)) {
        pVia->NoDDCValue = TRUE;
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
         "Option: Not using DDC probed value to set HorizSync & VertRefresh\n");
    }
    else {
        pVia->NoDDCValue = FALSE;
    }

    /* LCDDualEdge Option */
    pBIOSInfo->LCDDualEdge = FALSE;
    if (xf86ReturnOptValBool(VIAOptions, OPTION_LCDDUALEDGE, FALSE)) {
        pBIOSInfo->LCDDualEdge = TRUE;
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
         "Option: Using Dual Edge mode to set LCD\n");
    }
    else {
        pBIOSInfo->LCDDualEdge = FALSE;
    }

    /* Digital Output Bus Width Option */
    pBIOSInfo->BusWidth = VIA_DI_12BIT;
    if ((s = xf86GetOptValString(VIAOptions, OPTION_BUSWIDTH))) {
        if (!xf86NameCmp(s, "12BIT")) {
            pBIOSInfo->BusWidth = VIA_DI_12BIT;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                       "Digital Output Bus Width is 12BIT\n");
        }
        else if (!xf86NameCmp(s, "24BIT")) {
            pBIOSInfo->BusWidth = VIA_DI_24BIT;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                       "Digital Output Bus Width is 24BIT\n");
        }
    }

    /* LCD Center/Expend Option */
    if (xf86ReturnOptValBool(VIAOptions, OPTION_CENTER, FALSE)) {
        pBIOSInfo->Center = TRUE;
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DVI Center is On\n");
    }
    else {
        pBIOSInfo->Center = FALSE;
    }

    /* Panel Size Option */
    pBIOSInfo->PanelSize = VIA_PANEL_INVALID;
    if ((s = xf86GetOptValString(VIAOptions, OPTION_PANELSIZE))) {
        if (!xf86NameCmp(s, "640x480")) {
            pBIOSInfo->PanelSize = VIA_PANEL6X4;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                       "Selected Panel Size is 640x480\n");
        }
        else if (!xf86NameCmp(s, "800x600")) {
            pBIOSInfo->PanelSize = VIA_PANEL8X6;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                       "Selected Panel Size is 800x600\n");
        }
        else if(!xf86NameCmp(s, "1024x768")) {
            pBIOSInfo->PanelSize = VIA_PANEL10X7;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                       "Selected Panel Size is 1024x768\n");
        }
        else if (!xf86NameCmp(s, "1280x768")) {
            pBIOSInfo->PanelSize = VIA_PANEL12X7;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                       "Selected Panel Size is 1280x768\n");
        }
        else if (!xf86NameCmp(s, "1280x1024")) {
            pBIOSInfo->PanelSize = VIA_PANEL12X10;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                       "Selected Panel Size is 1280x1024\n");
        }
        else if (!xf86NameCmp(s, "1400x1050")) {
            pBIOSInfo->PanelSize = VIA_PANEL14X10;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                       "Selected Panel Size is 1400x1050\n");
        }
    }

    /* TV DotCrawl Enable Option */
    if (xf86ReturnOptValBool(VIAOptions, OPTION_TVDOTCRAWL, FALSE)) {
        pBIOSInfo->TVDotCrawl = TRUE;
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DotCrawl is Enable\n");
    }
    else {
        pBIOSInfo->TVDotCrawl = FALSE;
    }

    pBIOSInfo->TVType = TVTYPE_NONE;
    if ((s = xf86GetOptValString(VIAOptions, OPTION_TVTYPE))) {
        if (!xf86NameCmp(s, "NTSC")) {
            pBIOSInfo->TVType = TVTYPE_NTSC;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TV Type is NTSC\n");
        }
        else if(!xf86NameCmp(s, "PAL")) {
            pBIOSInfo->TVType = TVTYPE_PAL;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TV Type is PAL\n");
        }
    }

    /* TV out put signal Option */
    pBIOSInfo->TVOutput = TVOUTPUT_NONE;
    if ((s = xf86GetOptValString(VIAOptions, OPTION_TVOUTPUT))) {
        if (!xf86NameCmp(s, "S-Video")) {
            pBIOSInfo->TVOutput = TVOUTPUT_SVIDEO;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TV Output Signal is S-Video\n");
        }
        else if(!xf86NameCmp(s, "Composite")) {
            pBIOSInfo->TVOutput = TVOUTPUT_COMPOSITE;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TV Output Signal is Composite\n");
        }
        else if(!xf86NameCmp(s, "SC")) {
            pBIOSInfo->TVOutput = TVOUTPUT_SC;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TV Output Signal is SC\n");
        }
        else if(!xf86NameCmp(s, "RGB")) {
            pBIOSInfo->TVOutput = TVOUTPUT_RGB;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TV Output Signal is RGB\n");
        }
        else if(!xf86NameCmp(s, "YCbCr")) {
            pBIOSInfo->TVOutput = TVOUTPUT_YCBCR;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TV Output Signal is YCbCr\n");
        }
    }

    /* TV Standard Option */
    pBIOSInfo->TVVScan = VIA_TVNORMAL;
    if ((s = xf86GetOptValString(VIAOptions, OPTION_TVVSCAN))) {
        if (!xf86NameCmp(s, "under")) {
            pBIOSInfo->TVVScan = VIA_TVNORMAL;
        }
        else if (!xf86NameCmp(s, "over")) {
            pBIOSInfo->TVVScan = VIA_TVOVER;
        }
    }

    pBIOSInfo->TVHScale = VIA_NO_TVHSCALE;
    if ((s = xf86GetOptValString(VIAOptions, OPTION_TVHSCALE))) {
#if 0
        if (!xf86NameCmp(s, "0")) {
            pBIOSInfo->TVHScale = VIA_TVHSCALE0;
        }
        else if (!xf86NameCmp(s, "1")) {
            pBIOSInfo->TVHScale = VIA_TVHSCALE1;
        }
        else if(!xf86NameCmp(s, "2")) {
            pBIOSInfo->TVHScale = VIA_TVHSCALE2;
        }
        else if (!xf86NameCmp(s, "3")) {
            pBIOSInfo->TVHScale = VIA_TVHSCALE3;
        }
        else if (!xf86NameCmp(s, "4")) {
            pBIOSInfo->TVHScale = VIA_TVHSCALE4;
        }
#endif
    }

    /* TV Encoder Type Option */
    pBIOSInfo->TVEncoder = VIA_NONETV;
    if ((s = xf86GetOptValString(VIAOptions, OPTION_TVENCODER))) {
        if (!xf86NameCmp(s, "VT1621")) {
            pBIOSInfo->TVEncoder = VIA_TV2PLUS;
            pBIOSInfo->TVI2CAdd = 0x40;
        }
        else if(!xf86NameCmp(s, "VT1622")) {
            pBIOSInfo->TVEncoder = VIA_TV3;
            pBIOSInfo->TVI2CAdd = 0x40;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TV Encoder is VT1622!\n");
        }
        else if(!xf86NameCmp(s, "VT1622A")) {
            pBIOSInfo->TVEncoder = VIA_VT1622A;
            pBIOSInfo->TVI2CAdd = 0x40;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TV Encoder is VT1622!\n");
        }
        else if(!xf86NameCmp(s, "CH7019")) {
            pBIOSInfo->TVEncoder = VIA_CH7019;
            pBIOSInfo->TVI2CAdd = 0xEA;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TV Encoder is CH7019!\n");
        }
        else if(!xf86NameCmp(s, "SAA7108")) {
            pBIOSInfo->TVEncoder = VIA_SAA7108;
            pBIOSInfo->TVI2CAdd = 0x88;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TV Encoder is SAA7108!\n");
        }
        else if(!xf86NameCmp(s, "FS454")) {
            pBIOSInfo->TVEncoder = VIA_FS454;
            pBIOSInfo->TVI2CAdd = 0xD4;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TV Encoder is FS453/FS454!\n");
        }
    }

    if (xf86GetOptValInteger(VIAOptions, OPTION_REFRESH, &(pBIOSInfo->OptRefresh))) {
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Refresh is %d\n", pBIOSInfo->OptRefresh);
    }

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

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

    pVia->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
    xf86RegisterResources(pEnt->index, NULL, ResNone);
    /*
    xf86SetOperatingState(RES_SHARED_VGA, pEnt->index, ResUnusedOpr);
    xf86SetOperatingState(resVgaMemShared, pEnt->index, ResDisableOpr);
    */

    if (pEnt->device->chipset && *pEnt->device->chipset) {
        pScrn->chipset = pEnt->device->chipset;
        pVia->ChipId = pEnt->device->chipID;
        pVia->Chipset = xf86StringToToken(VIAChipsets, pScrn->chipset);
        from = X_CONFIG;
    } else if (pEnt->device->chipID >= 0) {
        pVia->ChipId = pEnt->device->chipID;
        pVia->Chipset = LookupChipID(VIAPciChipsets, pVia->ChipId);
        pScrn->chipset = (char *)xf86TokenToString(VIAChipsets,
                                                   pVia->Chipset);
        from = X_CONFIG;
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
                   pEnt->device->chipID);
    } else {
        from = X_PROBED;
        pVia->ChipId = pVia->PciInfo->chipType;
        pVia->Chipset = LookupChipID(VIAPciChipsets, pVia->ChipId);
        pScrn->chipset = (char *)xf86TokenToString(VIAChipsets,
                                                   pVia->Chipset);
    }

    if (pEnt->device->chipRev >= 0) {
        pVia->ChipRev = pEnt->device->chipRev;
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
                   pVia->ChipRev);
    }
    else {
        /*pVia->ChipRev = pVia->PciInfo->chipRev;*/
        /* Read PCI bus 0, dev 0, function 0, index 0xF6 to get chip rev. */
        pVia->ChipRev = pciReadByte(pciTag(0, 0, 0), 0xF6);
    }

    if (pEnt->device->videoRam != 0) {
        if (!pScrn->videoRam)
    	    pScrn->videoRam = pEnt->device->videoRam;
    	else {
        	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
        	"Video Memory Size in Option is %d KB, Detect is %d KB!",
            pScrn->videoRam, pEnt->device->videoRam);
    	}
    }
    pBIOSInfo->Chipset = pVia->Chipset;
    pBIOSInfo->ChipRev = pVia->ChipRev;

    xfree(pEnt);

    VIAvfInitHWDiff(pVia);

    /* maybe throw in some more sanity checks here */

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

    pVia->PciTag = pciTag(pVia->PciInfo->bus, pVia->PciInfo->device,
                          pVia->PciInfo->func);

    switch (pVia->ChipRev) {
        case 2:
            pBIOSInfo->A2 = TRUE;
            break;
        default:
            pBIOSInfo->A2 = FALSE;
            break;
    }
    xf86DrvMsg(pScrn->scrnIndex, from, "Chipset Rev.: %d\n", pVia->ChipRev);

    hwp = VGAHWPTR(pScrn);
    vgaHWGetIOBase(hwp);

    if (!VIAMapMMIO(pScrn)) {
        vbeFree(pVia->pVbe);
        return FALSE;
    }

    /* Get BIOS ver. From BIOS Call Function */
    tmp = VIABIOS_GetBIOSVersion(pScrn);
    pBIOSInfo->BIOSMajorVersion = tmp >> 8;
    pBIOSInfo->BIOSMinorVersion = tmp & 0xFF;
    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS Version is = %d.%d\n", pBIOSInfo->BIOSMajorVersion, pBIOSInfo->BIOSMinorVersion));
    VIABIOS_GetBIOSDate(pScrn);

    if (pBIOSInfo->TVType == TVTYPE_NONE) {
        /* use jumper to determine TV Type */
        VGAOUT8(0x3D4, 0x3B);
        if (VGAIN8(0x3D5) & 0x02) {
            pBIOSInfo->TVType = TVTYPE_PAL;
        }
        else {
            pBIOSInfo->TVType = TVTYPE_NTSC;
        }
    }

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

        if (!xf86SetGamma(pScrn, zeros)) {
            vbeFree(pVia->pVbe);
            return FALSE;
        }
    }

    /* Next go on to detect amount of installed ram */
    if (pScrn->videoRam < 16384 || pScrn->videoRam > 65536) {
        bMemSize = VIABIOS_GetVideoMemSize(pScrn);
        if (bMemSize) {
            pScrn->videoRam = bMemSize << 6;
        }
        else {
            if(pVia->Chipset == VIA_CLE266)
                VGAOUT8(0x3C4, 0x34);
            else
            	VGAOUT8(0x3C4, 0x39);
            bMemSize = VGAIN8(0x3c5);
            if (bMemSize > 16 && bMemSize <= 128) {
                pScrn->videoRam = (bMemSize + 1) << 9;
            }
            else if (bMemSize > 0 && bMemSize < 31){
                pScrn->videoRam = bMemSize << 12;
            }
            else {
                DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                "bMemSize = %d\nGet Video Memory Size by default.\n", bMemSize));
                pScrn->videoRam = 16 << 10;	/* Assume the base 16Mb */
            }
        }
    }

    /* Split FB for SAMM */
    /* FIXME: For now, split FB into two equal sections. This should
     *        be able to be adjusted by user with a config option. */
    if (pVia->IsSecondary) {
        DevUnion* pPriv;
        VIAEntPtr pVIAEnt;
        VIAPtr    pVia1;

        pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
              gVIAEntityIndex);
        pVIAEnt = pPriv->ptr;
        pScrn->videoRam = pScrn->videoRam >> 1;
        pVIAEnt->pPrimaryScrn->videoRam = pScrn->videoRam;
        pVia1 = VIAPTR(pVIAEnt->pPrimaryScrn);
        pVia1->videoRambytes = pScrn->videoRam << 10;
        pVia->FrameBufferBase += (pScrn->videoRam << 10);
    }

    pVia->videoRambytes = pScrn->videoRam << 10;
    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,"videoram =  %dk\n",
               pScrn->videoRam);

    /* Set status word positions based on chip type. */

    switch (pVia->Chipset) {
        case VIA_CLE266:
            pVia->myWaitIdle = WaitIdleCLE266;
            break;
        default:
            pVia->myWaitIdle = WaitIdleCLE266;
            break;
    }

    if (!xf86LoadSubModule(pScrn, "i2c")) {
        VIAFreeRec(pScrn);
        return FALSE;
    }
    else {
        xf86LoaderReqSymLists(i2cSymbols,NULL);
        VIAI2CInit(pScrn);
    }

    if (!xf86LoadSubModule(pScrn, "ddc")) {
        VIAFreeRec(pScrn);
        return FALSE;
    }
    else {
        xf86MonPtr pMon = NULL;

        xf86LoaderReqSymLists(ddcSymbols, NULL);
        if ((pVia->pVbe)
            && ((pMon = xf86PrintEDID(vbeDoEDID(pVia->pVbe, NULL))) != NULL)) {
            pVia->DDC1 = pMon;
            xf86SetDDCproperties(pScrn,pMon);
        }
        else if (!VIAddc2(pScrn->scrnIndex)) {
            VIAddc1(pScrn->scrnIndex);
        }
    }

    /* Reset HorizSync & VertRefresh Rang Using DDC Value */
    if (pVia->DDC1 && !pVia->NoDDCValue) {
        int i;
        int h = 0;
        int v = 0;

        for (i = 0; i < DET_TIMINGS; i++) {
            if (pVia->DDC1->det_mon[i].type == DS_RANGES) {
                pScrn->monitor->hsync[h].lo
                    = pVia->DDC1->det_mon[i].section.ranges.min_h;
                pScrn->monitor->hsync[h++].hi
                    = pVia->DDC1->det_mon[i].section.ranges.max_h;
                pScrn->monitor->vrefresh[v].lo
                    = pVia->DDC1->det_mon[i].section.ranges.min_v;
                pScrn->monitor->vrefresh[v++].hi
                    = pVia->DDC1->det_mon[i].section.ranges.max_v;
                break;
            }
        }
        pScrn->monitor->nHsync = h;
        pScrn->monitor->nVrefresh = v;
    }

    /*
     * Setup the ClockRanges, which describe what clock ranges are available,
     * and what sort of modes they can be used for.
     */

    clockRanges = xnfalloc(sizeof(ClockRange));
    clockRanges->next = NULL;
    clockRanges->minClock = 20000;
    clockRanges->maxClock = 230000;

    clockRanges->clockIndex = -1;
    clockRanges->interlaceAllowed = TRUE;
    clockRanges->doubleScanAllowed = FALSE;


    /*
     * 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 VIAValidMode() already takes
     * care of this, we don't worry about setting them here.
     */

    /* Select valid modes from those available */
    i = xf86ValidateModes(pScrn,
                          pScrn->monitor->Modes,    /* availModes */
                          pScrn->display->modes,    /* modeNames */
                          clockRanges,              /* list of clock ranges */
                          NULL,                     /* list of line pitches */
                          256,                      /* mini line pitch */
                          2048,                     /* max line pitch */
                          16 * pScrn->bitsPerPixel, /* pitch inc (bits) */
                          128,                      /* min height */
                          2048,                     /* max height */
                          pScrn->display->virtualX, /* virtual width */
                          pScrn->display->virtualY, /* virutal height */
                          pVia->videoRambytes,      /* size of video memory */
                          LOOKUP_BEST_REFRESH);     /* lookup mode flags */

    if (i == -1) {
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86ValidateModes failure\n");
        VIAFreeRec(pScrn);
        return FALSE;
    }

    xf86PruneDriverModes(pScrn);

    if (i == 0 || pScrn->modes == NULL) {
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
        VIAFreeRec(pScrn);
        return FALSE;
    }
    
    /* Set up screen parameters. */
    pVia->Bpp = pScrn->bitsPerPixel >> 3;
    pVia->Bpl = pScrn->displayWidth * pVia->Bpp;

    if (!VIAGetBIOSTable(pBIOSInfo)) {
        VIAFreeRec(pScrn);
        return FALSE;
    }

    pBIOSInfo->I2C_Port1 = pVia->I2C_Port1;
    pBIOSInfo->I2C_Port2 = pVia->I2C_Port2;
    pBIOSInfo->DDC1 = pVia->DDC1;
    pBIOSInfo->DDC2 = pVia->DDC2;

    /* Detect TV Encoder */
    if (!pBIOSInfo->TVEncoder) {
        pBIOSInfo->TVEncoder = VIACheckTVExist(pBIOSInfo);
    }
    /* Detect TMDS/LVDS Encoder */
    VIAPostDVI(pBIOSInfo);
	/*VIAGetPanelInfo(pBIOSInfo);*/
    pBIOSInfo->ConnectedDevice = VIAGetDeviceDetect(pBIOSInfo);

    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
    pScrn->currentMode = pScrn->modes;
    xf86PrintModes(pScrn);
    xf86SetDpi(pScrn, 0, 0);

#ifdef USE_FB
    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
        VIAFreeRec(pScrn);
        return FALSE;
    }

    xf86LoaderReqSymLists(fbSymbols, NULL);

#else
    /* load bpp-specific modules */
    switch (pScrn->bitsPerPixel) {
        case 8:
            mod = "cfb";
            reqSym = "cfbScreenInit";
            break;
        case 16:
            mod = "cfb16";
            reqSym = "cfb16ScreenInit";
            break;
        case 32:
            mod = "cfb32";
            reqSym = "cfb32ScreenInit";
            break;
    }

    if (mod && xf86LoadSubModule(pScrn, mod) == NULL) {
        VIAFreeRec(pScrn);
        return FALSE;
    }

    xf86LoaderReqSymbols(reqSym, NULL);
#endif

    if (!pVia->NoAccel) {
        if(!xf86LoadSubModule(pScrn, "xaa")) {
            VIAFreeRec(pScrn);
            return FALSE;
        }
        xf86LoaderReqSymLists(xaaSymbols, NULL);
    }

    if (pVia->hwcursor) {
        if (!xf86LoadSubModule(pScrn, "ramdac")) {
            VIAFreeRec(pScrn);
            return FALSE;
        }
        xf86LoaderReqSymLists(ramdacSymbols, NULL);
    }

    if (pVia->shadowFB) {
        if (!xf86LoadSubModule(pScrn, "shadowfb")) {
            VIAFreeRec(pScrn);
            return FALSE;
        }
        xf86LoaderReqSymLists(shadowSymbols, NULL);
    }

    /* Capture option parameter */
    pVia->Cap0_Deinterlace = CAP_BOB;
    if ((s = xf86GetOptValString(VIAOptions, OPTION_CAP0_DEINTERLACE))) {
        if (!xf86NameCmp(s, "Bob")) {
            pVia->Cap0_Deinterlace = CAP_BOB;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Capture 0 de-interlace mode is Bob\n");
        }
        else if(!xf86NameCmp(s, "Weave")) {
            pVia->Cap0_Deinterlace = CAP_WEAVE;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Capture 0 de-interlace mode is Weave\n");
        }
    }

    pVia->Cap1_Deinterlace = CAP_BOB;
    if ((s = xf86GetOptValString(VIAOptions, OPTION_CAP1_DEINTERLACE))) {
        if (!xf86NameCmp(s, "Bob")) {
            pVia->Cap1_Deinterlace = CAP_BOB;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Capture 1 de-interlace mode is Bob\n");
        }
        else if(!xf86NameCmp(s, "Weave")) {
            pVia->Cap1_Deinterlace = CAP_WEAVE;
            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Capture 1 de-interlace mode is Weave\n");
        }
    }
    
    if (xf86ReturnOptValBool(VIAOptions, OPTION_CAP0_FIELDSWAP, FALSE)) {
        pVia->Cap0_FieldSwap = TRUE;
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                   "Option: Cap0_FieldSwap Enabled\n");
    }
    else {
        pVia->Cap0_FieldSwap = FALSE;
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                   "Option: Cap0_FieldSwap Disabled\n");
    }

    /* xf86LoaderReqSymLists(mpegSymbols, NULL); */

    VIADeviceSelection(pScrn);
    if (pVia->IsSecondary) {
        if (pBIOSInfo->SAMM)
            VIADeviceDispatch(pScrn);
        else
            return FALSE;
    }

    VIAUnmapMem(pScrn);

    return TRUE;
}


static Bool VIAEnterVT(int scrnIndex, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    VIAPtr      pVia = VIAPTR(pScrn);
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    Bool        ret;

    /* FIXME: Rebind AGP memory here */
    /* FIXME: Unlock DRI here */
    DEBUG(xf86DrvMsg(scrnIndex, X_INFO, "VIAEnterVT\n"));
    VIASave(pScrn);
    vgaHWUnlock(hwp);

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

    /* Patch for APM suspend resume, HWCursor has garbage */
    if (pVia->hwcursor && pVia->CursorImage) {
        DEBUG(xf86DrvMsg(scrnIndex, X_INFO, "Restore Cursor Image!\n"));
        memcpy(pVia->FBBase + pVia->CursorStart, pVia->CursorImage, 0x1000);
    	VIASETREG(VIA_REG_CURSOR_FG, pVia->CursorFG);
    	VIASETREG(VIA_REG_CURSOR_BG, pVia->CursorBG);
    	VIASETREG(VIA_REG_CURSOR_MODE, pVia->CursorMC);
        xfree(pVia->CursorImage);
        /*VIALoadCursorImage(pScrn, *pVia->CursorImage);*/
    }

    /* retore video status */
    if (!pVia->IsSecondary)
        viaRestoreVideo(pScrn);

    VIAAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
    return ret;
}


static void VIALeaveVT(int scrnIndex, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    vgaHWPtr    hwp = VGAHWPTR(pScrn);
    VIAPtr      pVia = VIAPTR(pScrn);
    vgaRegPtr   vgaSavePtr = &hwp->SavedReg;
    VIARegPtr   viaSavePtr = &pVia->SavedReg;

    DEBUG(xf86DrvMsg(scrnIndex, X_INFO, "VIALeaveVT\n"));
    
    /* FIXME: take the DRI lock here to avoid accidents */
    /* FIXME: unbind the AGP memory ? */
    
    /* Wait Hardware Engine idle to exit graphicd mode */
    WaitIdle();

    if (pVia->VQEnable) {
        /* if we use VQ, disable it before we exit */
        VIASETREG(0x43c, 0x00fe0000);
        VIASETREG(0x440, 0x00000004);
    }

    /* Save video status and turn off all video activities */
    if (!pVia->IsSecondary)
        viaSaveVideo(pScrn);

    if (pVia->hwcursor) {
        pVia->CursorImage = xcalloc(1, 0x1000);
        memcpy(pVia->CursorImage, pVia->FBBase + pVia->CursorStart, 0x1000);
    	pVia->CursorFG = (CARD32)VIAGETREG(VIA_REG_CURSOR_FG);
    	pVia->CursorBG = (CARD32)VIAGETREG(VIA_REG_CURSOR_BG);
    	pVia->CursorMC = (CARD32)VIAGETREG(VIA_REG_CURSOR_MODE);
    }

    VIAWriteMode(pScrn, vgaSavePtr, viaSavePtr);
    vgaHWLock(hwp);
}


static void VIASave(ScrnInfoPtr pScrn)
{
    vgaHWPtr        hwp = VGAHWPTR(pScrn);
    vgaRegPtr       vgaSavePtr = &hwp->SavedReg;
    VIAPtr          pVia = VIAPTR(pScrn);
    VIABIOSInfoPtr  pBIOSInfo = pVia->pBIOSInfo;
    VIARegPtr       save = &pVia->SavedReg;
    int             vgaCRIndex, vgaCRReg, vgaIOBase;
    int             i;
    I2CDevPtr       dev;
    unsigned char   W_Buffer[1];
    unsigned char   TVRegs[0xFF];

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIASave\n"));

    if(pVia->IsSecondary)
    {
        DevUnion* pPriv;
        VIAEntPtr pVIAEnt;
        VIAPtr   pVia1;
        vgaHWPtr hwp1;
        pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
              gVIAEntityIndex);
        pVIAEnt = pPriv->ptr;
        hwp1 = VGAHWPTR(pVIAEnt->pPrimaryScrn);
        pVia1 = VIAPTR(pVIAEnt->pPrimaryScrn);
        hwp->SavedReg = hwp1->SavedReg;
        pVia->SavedReg = pVia1->SavedReg;
    }
    else {
        vgaHWProtect(pScrn, TRUE);

        if (xf86IsPrimaryPci(pVia->PciInfo)) {
            vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL);
        }
        else {
            vgaHWSave(pScrn, vgaSavePtr, VGA_SR_MODE);
        }

        vgaIOBase = hwp->IOBase;
        vgaCRReg = vgaIOBase + 5;
        vgaCRIndex = vgaIOBase + 4;

        /* Unlock Extended Regs */
        outb(0x3c4, 0x10);
        outb(0x3c5, 0x01);

        VGAOUT8(0x3c4, 0x14);
        save->SR14 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x15);
        save->SR15 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x16);
        save->SR16 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x17);
        save->SR17 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x18);
        save->SR18 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x19);
        save->SR19 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x1a);
        save->SR1A = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x1b);
        save->SR1B = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x1c);
        save->SR1C = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x1d);
        save->SR1D = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x1e);
        save->SR1E = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x1f);
        save->SR1F = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x22);
        save->SR22 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x23);
        save->SR23 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x24);
        save->SR24 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x25);
        save->SR25 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x26);
        save->SR26 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x27);
        save->SR27 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x28);
        save->SR28 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x29);
        save->SR29 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x2a);
        save->SR2A = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x2b);
        save->SR2B = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x2e);
        save->SR2E = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x44);
        save->SR44 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x45);
        save->SR45 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x46);
        save->SR46 = VGAIN8(0x3c5);
        VGAOUT8(0x3c4, 0x47);
        save->SR47 = VGAIN8(0x3c5);

        VGAOUT8(vgaCRIndex, 0x13);
        save->CR13 = VGAIN8(vgaCRReg);
        VGAOUT8(vgaCRIndex, 0x32);
        save->CR32 = VGAIN8(vgaCRReg);
        VGAOUT8(vgaCRIndex, 0x33);
        save->CR33 = VGAIN8(vgaCRReg);
        VGAOUT8(vgaCRIndex, 0x34);
        save->CR34 = VGAIN8(vgaCRReg);
        VGAOUT8(vgaCRIndex, 0x35);
        save->CR35 = VGAIN8(vgaCRReg);
        VGAOUT8(vgaCRIndex, 0x36);
        save->CR36 = VGAIN8(vgaCRReg);

        /* Saving TV register status before set mode */
        switch (pBIOSInfo->TVEncoder) {
            case VIA_NONETV:
                break;
            case VIA_VT1623:
                VIAGPIOI2C_Initial(pBIOSInfo, 0x40);
                for (i = 0; i < 0x6C; i++) {
                    VIAGPIOI2C_ReadByte(pBIOSInfo, i, (TVRegs + i));
                    save->TVRegs[i] = TVRegs[i];
                    /*DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Save TV Register[%d]0x%X\n", i, save->TVRegs[i]));*/
                }
                break;
            default:
                if (xf86I2CProbeAddress(pVia->I2C_Port2, pBIOSInfo->TVI2CAdd)) {
                    dev = xf86CreateI2CDevRec();
                    dev->DevName = "TV";
                    dev->SlaveAddr = pBIOSInfo->TVI2CAdd;
                    dev->pI2CBus = pVia->I2C_Port2;

                    if (xf86I2CDevInit(dev)) {
                        W_Buffer[0] = 0;
                        xf86I2CWriteRead(dev, W_Buffer,1, TVRegs, 0xFF);
                        for (i = 0; i < 0xFF; i++) {
                            save->TVRegs[i] = TVRegs[i];
                        }
                        xf86DestroyI2CDevRec(dev,TRUE);
                    }
                    else
                        xf86DestroyI2CDevRec(dev,TRUE);
                }
                break;
        }

        /* Saving LVDS register status before set mode
        if (pBIOSInfo->LVDS == VIA_CH7019LVDS) {
            dev = xf86CreateI2CDevRec();
            dev->DevName = "LVDS";
            dev->SlaveAddr = 0xEA;
            dev->pI2CBus = pVia->I2C_Port2;

            if (xf86I2CDevInit(dev)) {
                for (i = 0; i < 0x40; i++) {
                    W_Buffer[0] = i + 0x40;
                    xf86I2CWriteRead(dev, W_Buffer, 1, save->LCDRegs + i, 1);
                }
                xf86DestroyI2CDevRec(dev,TRUE);
            }
            else
                xf86DestroyI2CDevRec(dev,TRUE);
        }*/

        /* Save LCD control regs */
        for (i = 0; i < 68; i++) {
            VGAOUT8(vgaCRIndex, i + 0x50);
            save->CRTCRegs[i] = VGAIN8(vgaCRReg);
        }

        if (!pVia->ModeStructInit) {
            vgaHWCopyReg(&hwp->ModeReg, vgaSavePtr);
            memcpy(&pVia->ModeReg, save, sizeof(VIARegRec));
            pVia->ModeStructInit = TRUE;
        }
        vgaHWProtect(pScrn, FALSE);
    }
    return;
}


static void VIAWriteMode(ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr,
                         VIARegPtr restore)
{
    vgaHWPtr        hwp = VGAHWPTR(pScrn);
    VIAPtr          pVia = VIAPTR(pScrn);
    VIABIOSInfoPtr  pBIOSInfo = pVia->pBIOSInfo;
    int             vgaCRIndex, vgaCRReg, vgaIOBase;
/*    Bool            graphicsMode = FALSE;*/
    int             i;
    unsigned char   W_Buffer[3];
    I2CDevPtr       dev = NULL;
    CARD8           tmp;

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAWriteMode\n"));
    vgaIOBase = hwp->IOBase;
    vgaCRIndex = vgaIOBase + 4;
    vgaCRReg = vgaIOBase + 5;

    /*
     * If we figured out a VESA mode number for this timing, just use
     * the VGA BIOS to do the switching, with a few additional tweaks.
     */
    if (restore->mode != 0xFF)
    {
        /* Set up the mode.  Don't clear video RAM. */
        if (!pVia->IsSecondary)
            VIASetModeUseBIOSTable(pBIOSInfo);
        else
            VIASetModeForMHS(pBIOSInfo);

        /* Restore the DAC.*/
        if (pBIOSInfo->FirstInit ) {
            vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_CMAP);
        }
        /*else {
            vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_MODE);
        }
        vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_CMAP);*/
        pBIOSInfo->FirstInit = FALSE;
        /* Enable the graphics engine. */
        if (!pVia->NoAccel)
            VIAInitialize2DEngine(pScrn);

#ifdef XF86DRI
      	VIAInitialize3DEngine(pScrn);
#endif
        return;
    }
    vgaHWProtect(pScrn, TRUE);
    /* Unlock Extended Regs */
    outb(0x3c4, 0x10);
    outb(0x3c5, 0x01);

    /* How can we know the mode is graphical mode or not ? */
    /* graphicsMode = (restore->mode == 0xFF) ? FALSE : TRUE; */

    VGAOUT8(vgaCRIndex, 0x6a);
    VGAOUT8(vgaCRReg, 0);
    VGAOUT8(vgaCRIndex, 0x6b);
    VGAOUT8(vgaCRReg, 0);
    VGAOUT8(vgaCRIndex, 0x6c);
    VGAOUT8(vgaCRReg, 0);

    switch (pBIOSInfo->TVEncoder) {
        case VIA_TV2PLUS:
        case VIA_TV3:
        case VIA_CH7009:
        case VIA_CH7019:
        case VIA_SAA7108:
        case VIA_CH7005:
        case VIA_VT1622A:
        dev = xf86CreateI2CDevRec();
        dev->DevName = "TV";
        dev->SlaveAddr = pBIOSInfo->TVI2CAdd;
        dev->pI2CBus = pVia->I2C_Port2;
        if (xf86I2CDevInit(dev)) {
                for (i = 0; i < 0xFF; i++) {
                    W_Buffer[0] = (unsigned char)(i);
                    W_Buffer[1] = (unsigned char)(restore->TVRegs[i]);
                    xf86I2CWriteRead(dev, W_Buffer, 2, NULL,0);
                }
                xf86DestroyI2CDevRec(dev,TRUE);
            }
            else
                xf86DestroyI2CDevRec(dev,TRUE);
            break;
        case VIA_FS454:
            dev = xf86CreateI2CDevRec();
            dev->DevName = "TV";
            dev->SlaveAddr = pBIOSInfo->TVI2CAdd;
            dev->pI2CBus = pVia->I2C_Port2;
            if (xf86I2CDevInit(dev)) {

                /* QPR programming */
                W_Buffer[0] = 0xC4;
                W_Buffer[1] = (unsigned char)(restore->TVRegs[0xC4]);
                W_Buffer[2] = (unsigned char)(restore->TVRegs[0xC5]);
                xf86I2CWriteRead(dev, W_Buffer,3, NULL,0);

                /* Restore TV Regs */
                for (i = 0; i < 0xFF; i++) {
                    W_Buffer[0] = (unsigned char)(i);
                    W_Buffer[1] = (unsigned char)(restore->TVRegs[i]);
                    if (i == 0xC4)
                        i++;
                    else
                        xf86I2CWriteRead(dev, W_Buffer, 2, NULL,0);
                }
            xf86DestroyI2CDevRec(dev,TRUE);
        }
        else
            xf86DestroyI2CDevRec(dev,TRUE);
            break;
        case VIA_VT1623:
            VIAGPIOI2C_Initial(pBIOSInfo, 0x40);
            for (i = 0; i < 0x6C; i++) {
                VIAGPIOI2C_Write(pBIOSInfo, i, restore->TVRegs[i]);
                /*DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Write Back Register[%d]:0x%X\n", i, restore->TVRegs[i]));*/
            }
            break;
        default:
            break;
    }

    /* restore the standard vga regs */
    if (xf86IsPrimaryPci(pVia->PciInfo))
        vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
    else
        vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_MODE);

    /* restore extended regs */
    VGAOUT8(0x3c4, 0x14);
    VGAOUT8(0x3c5, restore->SR14);
    VGAOUT8(0x3c4, 0x15);
    VGAOUT8(0x3c5, restore->SR15);
    VGAOUT8(0x3c4, 0x16);
    VGAOUT8(0x3c5, restore->SR16);
    VGAOUT8(0x3c4, 0x17);
    VGAOUT8(0x3c5, restore->SR17);
    VGAOUT8(0x3c4, 0x18);
    VGAOUT8(0x3c5, restore->SR18);
    VGAOUT8(0x3c4, 0x19);
    VGAOUT8(0x3c5, restore->SR19);
    VGAOUT8(0x3c4, 0x1a);
    VGAOUT8(0x3c5, restore->SR1A);
    VGAOUT8(0x3c4, 0x1b);
    VGAOUT8(0x3c5, restore->SR1B);
    VGAOUT8(0x3c4, 0x1c);
    VGAOUT8(0x3c5, restore->SR1C);
    VGAOUT8(0x3c4, 0x1d);
    VGAOUT8(0x3c5, restore->SR1D);
    VGAOUT8(0x3c4, 0x1e);
    VGAOUT8(0x3c5, restore->SR1E);
    VGAOUT8(0x3c4, 0x1f);
    VGAOUT8(0x3c5, restore->SR1F);
    VGAOUT8(0x3c4, 0x22);
    VGAOUT8(0x3c5, restore->SR22);
    VGAOUT8(0x3c4, 0x23);
    VGAOUT8(0x3c5, restore->SR23);
    VGAOUT8(0x3c4, 0x24);
    VGAOUT8(0x3c5, restore->SR24);
    VGAOUT8(0x3c4, 0x25);
    VGAOUT8(0x3c5, restore->SR25);
    VGAOUT8(0x3c4, 0x26);
    VGAOUT8(0x3c5, restore->SR26);
    VGAOUT8(0x3c4, 0x27);
    VGAOUT8(0x3c5, restore->SR27);
    VGAOUT8(0x3c4, 0x28);
    VGAOUT8(0x3c5, restore->SR28);
    VGAOUT8(0x3c4, 0x29);
    VGAOUT8(0x3c5, restore->SR29);
    VGAOUT8(0x3c4, 0x2a);
    VGAOUT8(0x3c5, restore->SR2A);
    VGAOUT8(0x3c4, 0x2b);
    VGAOUT8(0x3c5, restore->SR2B);
    VGAOUT8(0x3c4, 0x2e);
    VGAOUT8(0x3c5, restore->SR2E);
    VGAOUT8(0x3c4, 0x44);
    VGAOUT8(0x3c5, restore->SR44);
    VGAOUT8(0x3c4, 0x45);
    VGAOUT8(0x3c5, restore->SR45);
    VGAOUT8(0x3c4, 0x46);
    VGAOUT8(0x3c5, restore->SR46);
    VGAOUT8(0x3c4, 0x47);
    VGAOUT8(0x3c5, restore->SR47);

    VGAOUT8(vgaCRIndex, 0x13);
    VGAOUT8(vgaCRReg, restore->CR13);
    VGAOUT8(vgaCRIndex, 0x32);
    VGAOUT8(vgaCRReg, restore->CR32);
    VGAOUT8(vgaCRIndex, 0x33);
    VGAOUT8(vgaCRReg, restore->CR33);
    VGAOUT8(vgaCRIndex, 0x34);
    VGAOUT8(vgaCRReg, restore->CR34);
    VGAOUT8(vgaCRIndex, 0x35);
    VGAOUT8(vgaCRReg, restore->CR35);
    VGAOUT8(vgaCRIndex, 0x36);
    VGAOUT8(vgaCRReg, restore->CR36);

    /* Restore LCD control regs */
    for (i = 0; i < 68; i++) {
        VGAOUT8(vgaCRIndex, i + 0x50);
        VGAOUT8(vgaCRReg, restore->CRTCRegs[i]);
    }

    /*if (pBIOSInfo->LVDS == VIA_CH7019LVDS) {
        dev = xf86CreateI2CDevRec();
        dev->DevName = "LVDS";
        dev->SlaveAddr = 0xEA;
        dev->pI2CBus = pVia->I2C_Port2;

        if (xf86I2CDevInit(dev)) {
            for (i = 0; i < 0x40; i++) {
                W_Buffer[0] = (unsigned char)(i + 0x40);
                W_Buffer[1] = (unsigned char)(restore->LCDRegs[i]);
                xf86I2CWriteRead(dev, W_Buffer, 2, NULL,0);
            }

            xf86DestroyI2CDevRec(dev,TRUE);
        }
        else
            xf86DestroyI2CDevRec(dev,TRUE);

        ActiveDevice = VIABIOS_GetActiveDevice(pScrn);
    }*/
    if (pBIOSInfo->DefaultActiveDevice & VIA_DEVICE_LCD)
        VIAEnableLCD(pBIOSInfo);

    VIADisabledExtendedFIFO(pBIOSInfo);
    /* Reset clock */
    tmp = VGAIN8(0x3cc);
    VGAOUT8(0x3c2, tmp);

    /* If we're going into graphics mode and acceleration was enabled, */
/*
    if (graphicsMode && (!pVia->NoAccel)) {
        VIAInitialize2DEngine(pScrn);
    }
*/
    vgaHWProtect(pScrn, FALSE);
    return;
}


static Bool VIAMapMMIO(ScrnInfoPtr pScrn)
{
    VIAPtr pVia = VIAPTR(pScrn);
    VIABIOSInfoPtr  pBIOSInfo = pVia->pBIOSInfo;
    vgaHWPtr hwp;

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAMapMMIO\n"));

    pVia->FrameBufferBase = pVia->PciInfo->memBase[0];
    pVia->MmioBase = pVia->PciInfo->memBase[1];

    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
               "mapping MMIO @ 0x%lx with size 0x%x\n",
               pVia->MmioBase, VIA_MMIO_REGSIZE);

    pVia->MapBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pVia->PciTag,
                                  pVia->MmioBase,
                                  VIA_MMIO_REGSIZE);
    pBIOSInfo->MapBase = pVia->MapBase;

    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
               "mapping BitBlt MMIO @ 0x%lx with size 0x%x\n",
               pVia->MmioBase + VIA_MMIO_BLTBASE, VIA_MMIO_BLTSIZE);

    pVia->BltBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pVia->PciTag,
                                  pVia->MmioBase + VIA_MMIO_BLTBASE,
                                  VIA_MMIO_BLTSIZE);

    if (!pVia->MapBase || !pVia->BltBase) {
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                   "Internal error: cound not map registers\n");
        return FALSE;
    }

    /* Memory mapped IO for Video Engine */
    pVia->VidMapBase = pVia->MapBase + 0x200;

    VIAEnableMMIO(pScrn);
    hwp = VGAHWPTR(pScrn);
    vgaHWGetIOBase(hwp);

    return TRUE;
}


static Bool VIAMapFB(ScrnInfoPtr pScrn)
{
    VIAPtr pVia = VIAPTR(pScrn);
    VIABIOSInfoPtr  pBIOSInfo = pVia->pBIOSInfo;

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAMapFB\n"));
    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
               "mapping framebuffer @ 0x%lx with size 0x%lx\n",
               pVia->FrameBufferBase, pVia->videoRambytes);

    if (pVia->videoRambytes) {

	/*
	 * FIXME: This is a hack to get rid of offending wrongly sized
	 * MTRR regions set up by the VIA BIOS. Should be taken care of
	 * in the OS support layer.
	 */

        unsigned char *tmp; 
        tmp = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
			    pVia->PciTag, pVia->FrameBufferBase,
			    pVia->videoRambytes);
        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)tmp,
                        pVia->videoRambytes);

	/*
	 * End of hack.
	 */

        pVia->FBBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
                                     pVia->PciTag, pVia->FrameBufferBase,
                                     pVia->videoRambytes);
	    pBIOSInfo->FBBase = pVia->FBBase;
	    pBIOSInfo->videoRambytes = pVia->videoRambytes;

        if (!pVia->FBBase) {
            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                       "Internal error: could not map framebuffer\n");
            return FALSE;
        }

        pVia->FBStart = pVia->FBBase;
        pVia->FBFreeStart = (pScrn->displayWidth * pScrn->bitsPerPixel >> 3) *
                            pScrn->virtualY;
        pVia->FBFreeEnd = pVia->videoRambytes;

        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
                   "Frame buffer start: %p, free start: 0x%x end: 0x%x\n",
                   pVia->FBStart, pVia->FBFreeStart, pVia->FBFreeEnd);
    }

    pScrn->memPhysBase = pVia->PciInfo->memBase[0];
    pScrn->fbOffset = 0;
    if(pVia->IsSecondary) pScrn->fbOffset = pScrn->videoRam << 10;

    return TRUE;
}


static void VIAUnmapMem(ScrnInfoPtr pScrn)
{
    VIAPtr pVia;

    pVia = VIAPTR(pScrn);

    VIADisableMMIO(pScrn);

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAUnmapMem\n"));

    if (pVia->MapBase) {
        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pVia->MapBase,
                        VIA_MMIO_REGSIZE);
    }

    if (pVia->BltBase) {
        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pVia->BltBase,
                        VIA_MMIO_BLTSIZE);
    }

    if (pVia->FBBase) {
        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pVia->FBBase,
                        pVia->videoRambytes);
    }

    return;
}


static Bool VIAScreenInit(int scrnIndex, ScreenPtr pScreen,
                          int argc, char **argv)
{
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    VIAPtr pVia = VIAPTR(pScrn);
    int ret;

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAScreenInit\n"));
    vgaHWUnlock(hwp);

    if (!VIAMapFB(pScrn))
        return FALSE;

    if (!VIAMapMMIO(pScrn))
        return FALSE;

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "- Mem Mapped\n"));

    VIASave(pScrn);

    vgaHWBlankScreen(pScrn, FALSE);

    if (!VIAModeInit(pScrn, pScrn->currentMode))
        return FALSE;

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "- State saved\n"));

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

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "- Blanked\n"));

    miClearVisualTypes();

    if (pScrn->bitsPerPixel > 8 && !pVia->IsSecondary) {
        if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
                              pScrn->rgbBits, pScrn->defaultVisual))
            return FALSE;
        if (!miSetPixmapDepths())
            return FALSE;
    } else {
        if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
                              pScrn->rgbBits, pScrn->defaultVisual))
            return FALSE;
        if (!miSetPixmapDepths())
            return FALSE;
    }

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "- Visuals set up\n"));

    ret = VIAInternalScreenInit(scrnIndex, pScreen);

    if (!ret)
        return FALSE;

    xf86SetBlackWhitePixels(pScreen);
    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "- B & W\n"));

    if (pScrn->bitsPerPixel > 8) {
        VisualPtr visual;

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

#ifdef USE_FB
    /* must be after RGB ordering fixed */
    fbPictureInit(pScreen, 0, 0);
#endif

    if (!pVia->NoAccel) {
        VIAInitAccel(pScreen);
    } 
#ifdef XFREE86_44
    else {
	/*
	 * This is needed because xf86InitFBManagerLinear in VIAInitLinear
	 * needs xf86InitFBManager to have been initialized, and 
	 * xf86InitFBManager needs at least one line of free memory to
	 * work. This is only for Xv in Noaccel part, and since Xv is in some
	 * sense accelerated, it might be a better idea to disable it
	 * altogether.
	 */ 
        BoxRec AvailFBArea;

        AvailFBArea.x1 = 0;
        AvailFBArea.y1 = 0;
        AvailFBArea.x2 = pScrn->displayWidth;
        AvailFBArea.y2 = pScrn->virtualY + 1;
	/* 
	 * Update FBFreeStart also for other memory managers, since 
	 * we steal one line to make xf86InitFBManager work.
	 */
	pVia->FBFreeStart = (AvailFBArea.y2 + 1) * pVia->Bpl;
	xf86InitFBManager(pScreen, &AvailFBArea);	
    }
#endif

    miInitializeBackingStore(pScreen);
    xf86SetBackingStore(pScreen);
    /*xf86SetSilkenMouse(pScreen);*/
    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "- Backing store set up\n"));

    if(!pVia->shadowFB)         /* hardware cursor needs to wrap this layer */
        VIADGAInit(pScreen);

    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "- SW cursor set up\n"));

    if (pVia->hwcursor) {
        if (!VIAHWCursorInit(pScreen)) {
            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                       "Hardware cursor initialization failed\n");
        }
    }

    if (pVia->shadowFB) {
        RefreshAreaFuncPtr refreshArea = VIARefreshArea;

        if(pVia->rotate) {
            if (!pVia->PointerMoved) {
                pVia->PointerMoved = pScrn->PointerMoved;
                pScrn->PointerMoved = VIAPointerMoved;
            }

            switch(pScrn->bitsPerPixel) {
            case 8:
                refreshArea = VIARefreshArea8;
                break;
            case 16:
                refreshArea = VIARefreshArea16;
                break;
            case 32:
                refreshArea = VIARefreshArea32;
                break;
            }
        }

        ShadowFBInit(pScreen, refreshArea);
    }

    if (!miCreateDefColormap(pScreen))
        return FALSE;
    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "- Def Color map set up\n"));

    if (!xf86HandleColormaps(pScreen, 256, 6, VIALoadPalette, NULL,
                             CMAP_RELOAD_ON_MODE_SWITCH
                             | CMAP_PALETTED_TRUECOLOR))
        return FALSE;

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "- Palette loaded\n"));

    vgaHWBlankScreen(pScrn, TRUE);

    pVia->CloseScreen = pScreen->CloseScreen;
    pScreen->SaveScreen = VIASaveScreen;
    pScreen->CloseScreen = VIACloseScreen;

    xf86DPMSInit(pScreen, VIADPMS, 0);
    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "- DPMS set up\n"));

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "- Color maps etc. set up\n"));

#ifdef XF86DRI
    pVia->directRenderingEnabled = VIADRIScreenInit(pScreen);

    if (pVia->directRenderingEnabled) {
    pVia->directRenderingEnabled = VIADRIFinishScreenInit(pScreen);
    }
    if (pVia->directRenderingEnabled) {
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering enabled\n");
    }
    else {
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering disabled\n");
    }
    if (!pVia->directRenderingEnabled)
	VIAInitLinear(pScreen);
#else    
    VIAInitLinear(pScreen);
#endif

    
    if (!pVia->IsSecondary) {
        /* The chipset is checked in viaInitVideo */
        viaFillGraphicInfo(pScrn);
       	viaInitVideo(pScreen);
    }

    if (serverGeneration == 1)
        xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "- Done\n"));
    return TRUE;
}


static int VIAInternalScreenInit(int scrnIndex, ScreenPtr pScreen)
{
    ScrnInfoPtr     pScrn;
    VIAPtr          pVia;
    int             width, height, displayWidth;
    unsigned char   *FBStart;
    int             ret = TRUE;

    xf86DrvMsg(scrnIndex, X_INFO, "VIAInternalScreenInit\n");

    pScrn = xf86Screens[pScreen->myNum];
    pVia = VIAPTR(pScrn);

    displayWidth = pScrn->displayWidth;

    if (pVia->rotate) {
        height = pScrn->virtualX;
        width = pScrn->virtualY;
    } else {
        width = pScrn->virtualX;
        height = pScrn->virtualY;
    }

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

#ifdef USE_FB
    ret = fbScreenInit(pScreen, FBStart, width, height,
                       pScrn->xDpi, pScrn->yDpi, displayWidth,
                       pScrn->bitsPerPixel);
#else
    switch (pScrn->bitsPerPixel) {
    case 8:
        ret = cfbScreenInit(pScreen, FBStart, width, height, pScrn->xDpi,
                            pScrn->yDpi, displayWidth);
        break;

    case 16:
        ret = cfb16ScreenInit(pScreen, FBStart, width, height, pScrn->xDpi,
                              pScrn->yDpi, displayWidth);
        break;

    case 32:
        ret = cfb32ScreenInit(pScreen, FBStart, width, height, pScrn->xDpi,
                              pScrn->yDpi, displayWidth);
        break;

    default:
        xf86DrvMsg(scrnIndex, X_ERROR,
                   "Internal error: invalid bpp (%d) in SavageScreenInit\n",
                   pScrn->bitsPerPixel);
        ret = FALSE;
        break;
    }
#endif

    return ret;
}


static ModeStatus VIAValidMode(int scrnIndex, DisplayModePtr mode,
                               Bool verbose, int flags)
{
    DEBUG(xf86DrvMsg(scrnIndex, X_INFO, "VIAValidMode\n"));
    /* TODO check modes */
    return MODE_OK;
}


static void VIABIOSInit(VIAPtr pVia, ScrnInfoPtr pScrn, DisplayModePtr pMode)
{
    int             i;
    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;

    pBIOSInfo->bitsPerPixel = pScrn->bitsPerPixel;
    pBIOSInfo->displayWidth = pScrn->displayWidth;
    pBIOSInfo->frameX1 = pScrn->frameX1;
    pBIOSInfo->frameY1 = pScrn->frameY1;
    pBIOSInfo->scrnIndex = pScrn->scrnIndex;

    pBIOSInfo->Clock = pMode->Clock;
    pBIOSInfo->HTotal = pMode->HTotal;
    pBIOSInfo->VTotal = pMode->VTotal;
    pBIOSInfo->HDisplay = pMode->HDisplay;
    pBIOSInfo->VDisplay = pMode->VDisplay;
    pBIOSInfo->CrtcHDisplay = pMode->CrtcHDisplay;
    pBIOSInfo->CrtcVDisplay = pMode->CrtcVDisplay;
    if (pBIOSInfo->FirstInit) {
        pBIOSInfo->SaveframeX1 = pScrn->frameX1;
        pBIOSInfo->SaveframeY1 = pScrn->frameY1;
        pBIOSInfo->SaveHDisplay = pMode->HDisplay;
        pBIOSInfo->SaveVDisplay = pMode->VDisplay;
        pBIOSInfo->SaveCrtcHDisplay = pMode->CrtcHDisplay;
        pBIOSInfo->SaveCrtcVDisplay = pMode->CrtcVDisplay;
    }

    pBIOSInfo->IsSecondary = pVia->IsSecondary;
    pBIOSInfo->HasSecondary = pVia->HasSecondary;

    for (i = 0; i < 0xFF; i++) {
        pBIOSInfo->TVRegs[i] = pVia->SavedReg.TVRegs[i];
    }
}


static void VIAPostFindMode(VIAPtr pVia, ScrnInfoPtr pScrn, DisplayModePtr pMode)
{
    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;

    pVia->ModeReg.mode = pBIOSInfo->mode;
    pVia->ModeReg.resMode = pBIOSInfo->resMode;
    pVia->ModeReg.refresh = pBIOSInfo->refresh;
    pVia->ModeReg.offsetWidthByQWord = pBIOSInfo->offsetWidthByQWord;
    pVia->ModeReg.countWidthByQWord = pBIOSInfo->countWidthByQWord;

    pScrn->frameX1 = pBIOSInfo->frameX1;
    pScrn->frameY1 = pBIOSInfo->frameY1;
    pMode->HDisplay = pBIOSInfo->HDisplay;
    pMode->VDisplay = pBIOSInfo->VDisplay;

}


static Bool VIAModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
    vgaHWPtr        hwp = VGAHWPTR(pScrn);
    VIAPtr          pVia = VIAPTR(pScrn);
    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
    VIARegPtr       new = &pVia->ModeReg;
    vgaRegPtr       vganew = &hwp->ModeReg;
    /* DDUPDATEOVERLAY UpdateOverlay; */

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAModeInit\n"));


    if (!vgaHWInit(pScrn, mode)) {
        vgaHWBlankScreen(pScrn, TRUE);
        return FALSE;
    }

    pScrn->vtSema = TRUE;

    VIABIOSInit(pVia, pScrn, mode);

    if (!VIAFindModeUseBIOSTable(pBIOSInfo)) {
        vgaHWBlankScreen(pScrn, TRUE);
        VIAFreeRec(pScrn);
        return FALSE;
    }

    VIAPostFindMode(pVia, pScrn, mode);

    /* FIXME - need DRI lock for this bit - see i810 */
    /* do it! */
    VIAWriteMode(pScrn, vganew, new);

    /* pass graphic info to via_v4l kernel module */
    /* Coz mode changes, some member in pVia->graphicInfo need to modify */
    if (VIA_SERIES(pVia->Chipset) && !pVia->IsSecondary)
    {
        viaFillGraphicInfo(pScrn);

        DBG_DD(ErrorF("SWOV:  VIAVidSet2DInfo\n"));

        /* Save MCLK value*/
        VGAOUT8(0x3C4, 0x16); pVia->swov.Save_3C4_16 = VGAIN8(0x3C5);
        DBG_DD(ErrorF("        3c4.16 : %08x \n",VGAIN8(0x3C5)));
        VGAOUT8(0x3C4, 0x17); pVia->swov.Save_3C4_17 = VGAIN8(0x3C5);
        DBG_DD(ErrorF("        3c4.17 : %08x \n",VGAIN8(0x3C5)));
        VGAOUT8(0x3C4, 0x18); pVia->swov.Save_3C4_18 = VGAIN8(0x3C5);
        DBG_DD(ErrorF("        3c4.18 : %08x \n",VGAIN8(0x3C5)));
    }
    VIAAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
    return TRUE;
}


static Bool VIACloseScreen(int scrnIndex, ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    vgaHWPtr    hwp = VGAHWPTR(pScrn);
    VIAPtr      pVia = VIAPTR(pScrn);
    vgaRegPtr   vgaSavePtr = &hwp->SavedReg;
    VIARegPtr   viaSavePtr = &pVia->SavedReg;
    CARD32      dwCursorMode;

    DEBUG(xf86DrvMsg(scrnIndex, X_INFO, "VIACloseScreen\n"));

    /* Is the display currently visible ? */
    if(pScrn->vtSema)
    {
        /* Wait Hardware Engine idle to exit graphical mode */
        WaitIdle();
    
	/* Patch for normal log out and restart X, 3D application will hang */
	VIAWriteMode(pScrn, vgaSavePtr, viaSavePtr);

	if (!pVia->IsSecondary) {
            /* Turn off all video activities */
            viaExitVideo(pScrn);
            /* Diable Hardware Cursor */
            dwCursorMode = VIAGETREG(VIA_REG_CURSOR_MODE);
            VIASETREG(VIA_REG_CURSOR_MODE, dwCursorMode & 0xFFFFFFFE);
        }

        if (pVia->VQEnable) {
            /* if we use VQ, disable it before we exit */
            VIASETREG(0x43c, 0x00fe0000);
            VIASETREG(0x440, 0x00000004);
        }
    }
#ifdef XF86DRI
    if (pVia->directRenderingEnabled) {
	VIADRICloseScreen(pScreen);
    }
#endif
    if (pVia->AccelInfoRec) {
        XAADestroyInfoRec(pVia->AccelInfoRec);
        pVia->AccelInfoRec = NULL;
    }
    if (pVia->CursorInfoRec) {
        xf86DestroyCursorInfoRec(pVia->CursorInfoRec);
        pVia->CursorInfoRec = NULL;
    }
    if (pVia->ShadowPtr) {
        xfree(pVia->ShadowPtr);
        pVia->ShadowPtr = NULL;
    }
    if (pVia->DGAModes) {
        xfree(pVia->DGAModes);
        pVia->DGAModes = NULL;
    }
    if(pVia->pInt10) {
        xf86FreeInt10(pVia->pInt10);
        pVia->pInt10 = NULL;
    }

    if (pScrn->vtSema) {
        VIAWriteMode(pScrn, vgaSavePtr, viaSavePtr);
        vgaHWLock(hwp);
        VIAUnmapMem(pScrn);
    }
    pScrn->vtSema = FALSE;
    pScreen->CloseScreen = pVia->CloseScreen;
    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
}

/*
 * This only gets called when a screen is being deleted.  It does not
 * get called routinely at the end of a server generation.
 */
static void VIAFreeScreen(int scrnIndex, int flags)
{
    DEBUG(xf86DrvMsg(scrnIndex, X_INFO, "VIAFreeScreen\n"));
    if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
	    vgaHWFreeHWRec(xf86Screens[scrnIndex]);
    VIAFreeRec(xf86Screens[scrnIndex]);
}

static Bool VIASaveScreen(ScreenPtr pScreen, int mode)
{
    return vgaHWSaveScreen(pScreen, mode);
}


void VIAAdjustFrame(int scrnIndex, int x, int y, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    vgaHWPtr    hwp = VGAHWPTR(pScrn);
    VIAPtr      pVia = VIAPTR(pScrn);
    int         Base, tmp;
    int         vgaCRIndex, vgaCRReg, vgaIOBase;
    DDLOCK      ddLock;
    LPDDLOCK    lpddLock = &ddLock;
    DDUPDATEOVERLAY UpdateOverlay;
    ADJUSTFRAME AdjustFrame;

    DEBUG(xf86DrvMsg(scrnIndex, X_INFO, "VIAAdjustFrame\n"));
    vgaIOBase = hwp->IOBase;
    vgaCRIndex = vgaIOBase + 4;
    vgaCRReg = vgaIOBase + 5;

    Base = (y * pScrn->displayWidth + x) * (pScrn->bitsPerPixel / 8);

    /* now program the start address registers */
    if (pVia->IsSecondary) {
        Base = (Base + pScrn->fbOffset) >> 3;
        VGAOUT8(vgaCRIndex, 0x62);
        tmp = VGAIN8(vgaCRReg) & 0x01;
        tmp |= (Base & 0x7F) << 1;
        VGAOUT8(vgaCRReg, tmp);
        VGAOUT8(vgaCRIndex, 0x63);
        VGAOUT8(vgaCRReg, ((Base & 0x7F80) >> 7));
        VGAOUT8(vgaCRIndex, 0x64);
        VGAOUT8(vgaCRReg, ((Base & 0x7F8000) >> 15));
    }
    else {
        Base = Base >> 1;
        VGAOUT16(vgaCRIndex, (Base & 0x00ff00) | 0x0c);
        VGAOUT16(vgaCRIndex, ((Base & 0x00ff) << 8) | 0x0d);
        VGAOUT16(vgaCRIndex, ((Base & 0xff0000) >> 8) | 0x34);
    }

    /* Pass Panning (x, y) info to V4L */
    AdjustFrame.x = x;
    AdjustFrame.y = y;

    VIAVidAdjustFrame(pScrn,&AdjustFrame);

    /* Check if HW mpeg engine active */
    if (pVia->Video.VideoStatus & SW_VIDEO_ON) /* SW video case */
    {
        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                      " Call SW MPEG UpdateOverlay at panning mode.\n");

        ddLock.dwFourCC = FOURCC_YUY2;

        VIAVidLockSurface(pScrn, &ddLock);

        UpdateOverlay.dwFlags = DDOVER_SHOW | DDOVER_KEYDEST;
        UpdateOverlay.dwColorSpaceLowValue = VIAGETREG(0x220);
        UpdateOverlay.rSrc.left = 0;
        UpdateOverlay.rSrc.top = 0;
        UpdateOverlay.rSrc.right = 720;
        UpdateOverlay.rSrc.bottom = 480;

        UpdateOverlay.rDest.left = (int) lpddLock->SWDevice.gdwSWDstLeft;
        UpdateOverlay.rDest.top = (int) lpddLock->SWDevice.gdwSWDstTop;
        UpdateOverlay.rDest.right = UpdateOverlay.rDest.left + lpddLock->SWDevice.gdwSWDstWidth;
        UpdateOverlay.rDest.bottom = UpdateOverlay.rDest.top + lpddLock->SWDevice.gdwSWDstHeight;

        VIAVidUpdateOverlay(pScrn, &UpdateOverlay);
    }
    else if (VIAGETREG(0x310) & 0x1) /* capture 0 (TV0) case */
    {
        ddLock.dwFourCC = FOURCC_TV0;

        VIAVidLockSurface(pScrn, &ddLock);
    }

    if (VIAGETREG(0x354) & 0x1) /* capture 1 (TV1) case */
    {
        ddLock.dwFourCC = FOURCC_TV1;

        VIAVidLockSurface(pScrn, &ddLock);
    }

    return;
}


Bool VIASwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
{
    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    VIAPtr      pVia = VIAPTR(pScrn);

    DEBUG(xf86DrvMsg(scrnIndex, X_INFO, "VIASwitchMode\n"));
    /* Wait Hardware Engine idle to switch graphicd mode */
    WaitIdle();

    if (pVia->VQEnable) {
        /* if we use VQ, disable it before we exit */
        VIASETREG(0x43c, 0x00fe0000);
        VIASETREG(0x440, 0x00000004);
    }

    return VIAModeInit(xf86Screens[scrnIndex], mode);
}


void VIAEnableMMIO(ScrnInfoPtr pScrn)
{
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    VIAPtr pVia = VIAPTR(pScrn);
    unsigned char val;

    if (xf86IsPrimaryPci(pVia->PciInfo)) {
        /* If we are primary card, we still use std vga port. If we use
         * MMIO, system will hang in vgaHWSave when our card used in
         * PLE and KLE (integrated Trident MVP4)
         */
        vgaHWSetStdFuncs(hwp);
    }
    else {
        vgaHWSetMmioFuncs(hwp, pVia->MapBase, 0x8000);
    }

    val = VGAIN8(0x3c3);
    VGAOUT8(0x3c3, val | 0x01);
    val = VGAIN8(VGA_MISC_OUT_R);
    VGAOUT8(VGA_MISC_OUT_W, val | 0x01);

    /* Unlock Extended IO Space */
    VGAOUT8(0x3c4, 0x10);
    VGAOUT8(0x3c5, 0x01);

    /* Enable MMIO */
    if(!pVia->IsSecondary) {
	VGAOUT8(0x3c4, 0x1a);
	val = VGAIN8(0x3c5);
	DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "primary val = %x\n", val));
	VGAOUT8(0x3c5, val | 0x68);
    }
    else {
	VGAOUT8(0x3c4, 0x1a);
	val = VGAIN8(0x3c5);
	DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "secondary val = %x\n", val));
	VGAOUT8(0x3c5, val | 0x38);
    }

    return;
}


void VIADisableMMIO(ScrnInfoPtr pScrn)
{
    VIAPtr pVia = VIAPTR(pScrn);
    unsigned char val;

    VGAOUT8(0x3c4, 0x1a);
    val = VGAIN8(0x3c5);
    VGAOUT8(0x3c5, val & 0x97);

    return;
}


void VIALoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies,
                    LOCO *colors, VisualPtr pVisual)
{
    VIAPtr pVia = VIAPTR(pScrn);
    int i, index;
    int sr1a, sr1b, cr67, cr6a;

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIALoadPalette\n"));

    if (pScrn->bitsPerPixel != 8)
        return;
    VGAOUT8(0x3C4, 0x1A);
    sr1a = VGAIN8(0x3C5);
    VGAOUT8(0x3C4, 0x1B);
    sr1b = VGAIN8(0x3C5);
    VGAOUT8(0x3D4, 0x67);
    cr67 = VGAIN8(0x3D5);
    VGAOUT8(0x3D4, 0x6A);
    cr6a = VGAIN8(0x3D5);

    if (pVia->IsSecondary) {
        VGAOUT8(0x3C4, 0x1A);
        VGAOUT8(0x3C5, sr1a | 0x01);
        VGAOUT8(0x3C4, 0x1B);
        VGAOUT8(0x3C5, sr1b | 0x80);
        VGAOUT8(0x3D4, 0x67);
        VGAOUT8(0x3D5, cr67 & 0x3F);
        VGAOUT8(0x3D4, 0x6A);
        VGAOUT8(0x3D5, cr6a | 0xC0);
    }

    for (i = 0; i < numColors; i++) {
        index = indicies[i];
        VGAOUT8(0x3c8, index);
        VGAOUT8(0x3c9, colors[index].red);
        VGAOUT8(0x3c9, colors[index].green);
        VGAOUT8(0x3c9, colors[index].blue);
    }

    if (pVia->IsSecondary) {
        VGAOUT8(0x3C4, 0x1A);
        VGAOUT8(0x3C5, sr1a);
        VGAOUT8(0x3C4, 0x1B);
        VGAOUT8(0x3C5, sr1b);
        VGAOUT8(0x3D4, 0x67);
        VGAOUT8(0x3D5, cr67);
        VGAOUT8(0x3D4, 0x6A);
        VGAOUT8(0x3D5, cr6a);

        /* Screen 0 palette was changed by mode setting of Screen 1,
         * so load again */
        for (i = 0; i < numColors; i++) {
            index = indicies[i];
            VGAOUT8(0x3c8, index);
            VGAOUT8(0x3c9, colors[index].red);
            VGAOUT8(0x3c9, colors[index].green);
            VGAOUT8(0x3c9, colors[index].blue);
        }

    }

}


static void VIADPMS(ScrnInfoPtr pScrn, int mode, int flags)
{
    vgaHWPtr        hwp = VGAHWPTR(pScrn);
    VIAPtr          pVia = VIAPTR(pScrn);
    VIABIOSInfoPtr  pBIOSInfo = pVia->pBIOSInfo;
    int             vgaCRIndex, vgaCRReg;
    CARD8           val;

    I2CDevPtr       dev;
    unsigned char   W_Buffer[2];

    vgaCRIndex = hwp->IOBase + 4;
    vgaCRReg = hwp->IOBase + 5;

    /* Clear DPMS setting */
    VGAOUT8(vgaCRIndex, 0x36);
    val = VGAIN8(vgaCRReg);
    val &= 0xCF;
    /* Turn Off CRT, if user doesn't want crt on */
    if (!pVia->IsSecondary && !(pBIOSInfo->ActiveDevice & VIA_DEVICE_CRT1)) {
        val |= 0x30;
    }

    switch (mode) {
    case DPMSModeOn:
        if (pBIOSInfo->ActiveDevice & (VIA_DEVICE_DFP | VIA_DEVICE_LCD)) {
            /* Enable LCD */
            VIAEnableLCD(pBIOSInfo);
        }

        if (pBIOSInfo->ActiveDevice & VIA_DEVICE_TV) {
            dev = xf86CreateI2CDevRec();
            dev->DevName = "TV";
            dev->SlaveAddr = pBIOSInfo->TVI2CAdd;
            dev->pI2CBus = pBIOSInfo->I2C_Port2;
            if (xf86I2CDevInit(dev)) {
                switch (pBIOSInfo->TVEncoder) {
                    case VIA_TV2PLUS:
                    case VIA_TV3:
                    case VIA_VT1622A:
                        W_Buffer[0] = 0x0E;
                        W_Buffer[1] = 0x0;
                        xf86I2CWriteRead(dev, W_Buffer,2, NULL,0);
                        break;
                    case VIA_VT1623:
                        VIAGPIOI2C_Initial(pBIOSInfo, 0x40);
                        VIAGPIOI2C_Write(pBIOSInfo, 0x0E, 0);
                        break;
                    case VIA_CH7019:
                        W_Buffer[0] = 0x49;
                        W_Buffer[1] = 0x20;
                        xf86I2CWriteRead(dev, W_Buffer,2, NULL,0);
                        /*W_Buffer[0] = 0x1E;
                        W_Buffer[1] = 0xD0;
                        xf86I2CWriteRead(dev, W_Buffer,2, NULL,0);*/
                        break;
                    case VIA_SAA7108:
                        W_Buffer[0] = 0x2D;
                        switch (pBIOSInfo->TVOutput) {
                            case TVOUTPUT_COMPOSITE:
                            case TVOUTPUT_SVIDEO:
                                W_Buffer[1] = 0xB4;
                                break;
                            case TVOUTPUT_RGB:
                                W_Buffer[1] = 0;
                                break;
                            case TVOUTPUT_YCBCR:
                                W_Buffer[1] = 0x84;
                                break;
                            default:
                                W_Buffer[1] = 0x08;
                                break;
                        }
                        xf86I2CWriteRead(dev, W_Buffer,2, NULL,0);
                        break;
                    default:
                        break;
                }
                xf86DestroyI2CDevRec(dev,TRUE);
            }
            else
                xf86DestroyI2CDevRec(dev,TRUE);
        }
        VGAOUT8(vgaCRIndex, 0x36);
        VGAOUT8(vgaCRReg, val);
        break;
    case DPMSModeStandby:
    case DPMSModeSuspend:
    case DPMSModeOff:
        if (pBIOSInfo->ActiveDevice & (VIA_DEVICE_DFP | VIA_DEVICE_LCD)) {
            VIADisableLCD(pBIOSInfo);
        }
        if (pBIOSInfo->ActiveDevice & VIA_DEVICE_TV) {
            dev = xf86CreateI2CDevRec();
            dev->DevName = "TV";
            dev->SlaveAddr = pBIOSInfo->TVI2CAdd;
            dev->pI2CBus = pBIOSInfo->I2C_Port2;
            if (xf86I2CDevInit(dev)) {
                switch (pBIOSInfo->TVEncoder) {
                    case VIA_TV2PLUS:
                        W_Buffer[0] = 0x0E;
                        W_Buffer[1] = 0x03;
                        xf86I2CWriteRead(dev, W_Buffer,2, NULL,0);
                        break;
                    case VIA_TV3:
                    case VIA_VT1622A:
                        W_Buffer[0] = 0x0E;
                        W_Buffer[1] = 0x0F;
                        xf86I2CWriteRead(dev, W_Buffer,2, NULL,0);
                        break;
                    case VIA_VT1623:
                        VIAGPIOI2C_Initial(pBIOSInfo, 0x40);
                        VIAGPIOI2C_Write(pBIOSInfo, 0x0E, 0x0F);
                        break;
                    case VIA_CH7019:
                        W_Buffer[0] = 0x49;
                        W_Buffer[1] = 0x3E;
                        xf86I2CWriteRead(dev, W_Buffer,2, NULL,0);
                        W_Buffer[0] = 0x1E;
                        W_Buffer[1] = 0xD0;
                        xf86I2CWriteRead(dev, W_Buffer,2, NULL,0);
                        break;
                    case VIA_SAA7108:
                        W_Buffer[0] = 0x2D;
                        W_Buffer[1] = 0x08;
                        xf86I2CWriteRead(dev, W_Buffer,2, NULL,0);
                        break;
                    default:
                        break;
                }
                xf86DestroyI2CDevRec(dev,TRUE);
            }
            else
                xf86DestroyI2CDevRec(dev,TRUE);
        }

        val |= 0x30;
        VGAOUT8(vgaCRIndex, 0x36);
        VGAOUT8(vgaCRReg, val);
        break;
    default:
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode %d\n", mode);
        break;
    }
    return;
}


/* Active Device according connected status */
Bool VIADeviceSelection(ScrnInfoPtr pScrn)
{
    VIAPtr pVia = VIAPTR(pScrn);
    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
    /*unsigned int  i;
    unsigned char   numDevice;*/
    pBIOSInfo->SAMM = FALSE;

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIADeviceSelection\n"));
    pBIOSInfo->DefaultActiveDevice = VIABIOS_GetActiveDevice(pScrn);
    /* if XF86Config Option "ActiveDevice" hasn't set, active device according CMOS */
    if (!pBIOSInfo->ActiveDevice) {
        pBIOSInfo->ActiveDevice = pBIOSInfo->DefaultActiveDevice;
    }
    /* if XF86Config-4 set SAMM, and only active one device, active device according CMOS */
    else if (pVia->IsSecondary && (pBIOSInfo->ActiveDevice == VIA_DEVICE_CRT1 ||
            pBIOSInfo->ActiveDevice == VIA_DEVICE_LCD ||
            pBIOSInfo->ActiveDevice == VIA_DEVICE_TV ||
            pBIOSInfo->ActiveDevice == VIA_DEVICE_DFP ||
            pBIOSInfo->ActiveDevice == VIA_DEVICE_CRT2)){
        pBIOSInfo->ActiveDevice = VIABIOS_GetActiveDevice(pScrn);
    }
    if (((pBIOSInfo->ActiveDevice & pBIOSInfo->ConnectedDevice) == pBIOSInfo->ActiveDevice)
         && (pVia->IsSecondary)) {
        pBIOSInfo->SAMM = TRUE;
    }
    pBIOSInfo->ActiveDevice &= pBIOSInfo->ConnectedDevice;
    pVia->ActiveDevice = pBIOSInfo->ActiveDevice;

    /*if (pBIOSInfo->ActiveDevice & VIA_DEVICE_LCD) {
        pBIOSInfo->DVIEncoder = VIA_VT3191;
        numDevice = 0x02;
        i = VIABIOS_GetDisplayDeviceInfo(pScrn, &numDevice);
        if (i != 0xFFFF) {
            if (pBIOSInfo->PanelSize == VIA_PANEL_INVALID)
                pBIOSInfo->PanelSize = numDevice;
    }*/

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Connected Device is %d\n", pBIOSInfo->ConnectedDevice));
    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Active Device is %d\n", pBIOSInfo->ActiveDevice));

    return TRUE;
}

/* SAMM device dispatch */
Bool VIADeviceDispatch(ScrnInfoPtr pScrn)
{
    DevUnion* pPriv = xf86GetEntityPrivate(pScrn->entityList[0], gVIAEntityIndex);
    VIAEntPtr pVIAEnt = pPriv->ptr;
    VIAPtr pVia1 = VIAPTR(pScrn), pVia0 = VIAPTR(pVIAEnt->pPrimaryScrn);
    VIABIOSInfoPtr pBIOSInfo1 = pVia1->pBIOSInfo, pBIOSInfo0 = pVia0->pBIOSInfo;

    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIADeviceDispatch\n"));
    pBIOSInfo0->SAMM = TRUE;
    switch (pBIOSInfo1->ActiveDevice) {
        case (VIA_DEVICE_CRT1 | VIA_DEVICE_LCD) :       /* If CRT + LCD, CRT is IGA1 */
            pBIOSInfo0->ActiveDevice = VIA_DEVICE_CRT1;
            pBIOSInfo1->ActiveDevice = VIA_DEVICE_LCD;
            break;
        case (VIA_DEVICE_CRT1 | VIA_DEVICE_TV) :        /* If CRT + TV, CRT is IGA1 */
            pBIOSInfo0->ActiveDevice = VIA_DEVICE_CRT1;
            pBIOSInfo1->ActiveDevice = VIA_DEVICE_TV;
            break;
        case (VIA_DEVICE_CRT1 | VIA_DEVICE_DFP) :       /* If CRT + DFP, CRT is IGA1 */
            pBIOSInfo0->ActiveDevice = VIA_DEVICE_CRT1;
            pBIOSInfo1->ActiveDevice = VIA_DEVICE_DFP;
            break;
        case (VIA_DEVICE_LCD | VIA_DEVICE_TV) :         /* If LCD + TV, TV is IGA1 */
            pBIOSInfo0->ActiveDevice = VIA_DEVICE_TV;
            pBIOSInfo1->ActiveDevice = VIA_DEVICE_LCD;
            break;
        case (VIA_DEVICE_LCD | VIA_DEVICE_DFP) :        /* If LCD + DFP, DFP is IGA1 */
            pBIOSInfo0->ActiveDevice = VIA_DEVICE_DFP;
            pBIOSInfo1->ActiveDevice = VIA_DEVICE_LCD;
            break;
        case (VIA_DEVICE_TV | VIA_DEVICE_DFP) :         /* If TV + DFP, TV is IGA1 */
            pBIOSInfo0->ActiveDevice = VIA_DEVICE_TV;
            pBIOSInfo1->ActiveDevice = VIA_DEVICE_DFP;
            break;
        default :
            return FALSE;
            break;
    }
    DEBUG(xf86DrvMsg(pVIAEnt->pPrimaryScrn->scrnIndex, X_INFO, "Active Device is %d\n", pBIOSInfo0->ActiveDevice));
    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Active Device is %d\n", pBIOSInfo1->ActiveDevice));
    return TRUE;
}

#ifdef XF86DRI
void
VIAInitialize3DEngine(ScrnInfoPtr pScrn)
{
    VIAPtr  pVia = VIAPTR(pScrn);
    int i;

    if (!pVia->sharedData->b3DRegsInitialized)
    {

        VIASETREG(0x43C, 0x00010000);

        for (i = 0; i <= 0x7D; i++)
        {
            VIASETREG(0x440, (CARD32) i << 24);
        }

        VIASETREG(0x43C, 0x00020000);

        for (i = 0; i <= 0x94; i++)
        {
            VIASETREG(0x440, (CARD32) i << 24);
        }

        VIASETREG(0x440, 0x82400000);

        VIASETREG(0x43C, 0x01020000);


        for (i = 0; i <= 0x94; i++)
        {
            VIASETREG(0x440, (CARD32) i << 24);
        }

        VIASETREG(0x440, 0x82400000);
        VIASETREG(0x43C, 0xfe020000);

        for (i = 0; i <= 0x03; i++)
        {
            VIASETREG(0x440, (CARD32) i << 24);
        }

        VIASETREG(0x43C, 0x00030000);

        for (i = 0; i <= 0xff; i++)
        {
            VIASETREG(0x440, 0);
        }
        VIASETREG(0x43C, 0x00100000);
        VIASETREG(0x440, 0x00333004);
        VIASETREG(0x440, 0x10000002);
        VIASETREG(0x440, 0x60000000);
        VIASETREG(0x440, 0x61000000);
        VIASETREG(0x440, 0x62000000);
        VIASETREG(0x440, 0x63000000);
        VIASETREG(0x440, 0x64000000);

        VIASETREG(0x43C, 0x00fe0000);

        if (pVia->ChipRev >= 3 )
            VIASETREG(0x440,0x40008c0f);
        else
            VIASETREG(0x440,0x4000800f);

        VIASETREG(0x440,0x44000000);
        VIASETREG(0x440,0x45080C04);
        VIASETREG(0x440,0x46800408);
        VIASETREG(0x440,0x50000000);
        VIASETREG(0x440,0x51000000);
        VIASETREG(0x440,0x52000000);
        VIASETREG(0x440,0x53000000);

        pVia->sharedData->b3DRegsInitialized = 1;
        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
            "3D Engine has been initialized.\n");
    }

    VIASETREG(0x43C,0x00fe0000);
    VIASETREG(0x440,0x08000001);
    VIASETREG(0x440,0x0A000183);
    VIASETREG(0x440,0x0B00019F);
    VIASETREG(0x440,0x0C00018B);
    VIASETREG(0x440,0x0D00019B);
    VIASETREG(0x440,0x0E000000);
    VIASETREG(0x440,0x0F000000);
    VIASETREG(0x440,0x10000000);
    VIASETREG(0x440,0x11000000);
    VIASETREG(0x440,0x20000000);
}
#endif
