patch-2.4.25 linux-2.4.25/drivers/video/sis/init.c

Next file: linux-2.4.25/drivers/video/sis/init.h
Previous file: linux-2.4.25/drivers/video/sis/310vtbl.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.24/drivers/video/sis/init.c linux-2.4.25/drivers/video/sis/init.c
@@ -1,35 +1,60 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init.c,v 1.3 2002/24/04 01:16:16 dawes Exp $ */
+/* $XFree86$ */
 /*
- * Mode switching code (CRT1 section) for
- * SiS 300/540/630/730/315/550/650/M650/651/M652/740/330/660/M660/760
+ * Mode initializing code (CRT1 section) for
+ * for SiS 300/305/540/630/730 and
+ *     SiS 315/550/650/M650/651/661FX/M661FX/740/741/M741/330/660/M660/760/M760
  * (Universal module for Linux kernel framebuffer and XFree86 4.x)
  *
- * Assembler-To-C translation
- * Copyright 2002, 2003 by Thomas Winischhofer <thomas@winischhofer.net>
- * Formerly based on non-functional code-fragements by SiS, Inc.
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
  *
- * If distributed as part of the linux kernel, the contents of this file
- * is entirely covered by the GPL.
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
  *
- * Otherwise, the following terms apply:
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
  *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the copyright holder not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission.  The copyright holder makes no representations
- * about the suitability of this software for any purpose.  It is provided
- * "as is" without express or implied warranty.
+ * Otherwise, the following license terms apply:
  *
- * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) All advertising materials mentioning features or use of this software
+ * *    must display the following acknowledgement: "This product includes
+ * *    software developed by Thomas Winischhofer, Vienna, Austria."
+ * * 4) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Formerly based on non-functional code-fragements for 300 series by SiS, Inc.
+ * Used by permission.
  *
  * TW says: This code looks awful, I know. But please don't do anything about
  * this otherwise debugging will be hell.
@@ -51,109 +76,33 @@
 #include "310vtbl.h"
 #endif
 
-#ifdef LINUX_XF86
-BOOLEAN SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                       ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN IsCustom);
-DisplayModePtr SiSBuildBuiltInModeList(ScrnInfoPtr pScrn, BOOLEAN includelcdmodes, BOOLEAN isfordvi);
-#ifdef SISDUALHEAD
-BOOLEAN SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                       ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN IsCustom);
-BOOLEAN SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                       ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN IsCustom);
-#endif /* dual head */
-#endif /* linux_xf86 */
-
-#ifdef LINUX_XF86
-BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                   ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch);
-#else
-BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                   USHORT ModeNo);
-#endif
-
-#ifndef LINUX_XF86
-static ULONG GetDRAMSize(SiS_Private *SiS_Pr,
-                         PSIS_HW_DEVICE_INFO HwDeviceExtension);
-#endif
-
 #if defined(ALLOC_PRAGMA)
 #pragma alloc_text(PAGE,SiSSetMode)
 #pragma alloc_text(PAGE,SiSInit)
 #endif
 
+/*********************************************/
+/*         POINTER INITIALIZATION            */
+/*********************************************/
+
 static void
-InitCommonPointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+InitCommonPointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
    SiS_Pr->SiS_StResInfo     = SiS_StResInfo;
    SiS_Pr->SiS_ModeResInfo   = SiS_ModeResInfo;
    SiS_Pr->SiS_StandTable    = SiS_StandTable;
-   if(HwDeviceExtension->jChipType < SIS_315H) {
-      SiS_StandTable[0x04].CRTC[4] = 0x2b;
-      SiS_StandTable[0x05].CRTC[4] = 0x2b;
-      SiS_StandTable[0x06].CRTC[4] = 0x54;
-      SiS_StandTable[0x06].CRTC[5] = 0x80;
-      SiS_StandTable[0x0d].CRTC[4] = 0x2b;
-      SiS_StandTable[0x0e].CRTC[4] = 0x54;
-      SiS_StandTable[0x0e].CRTC[5] = 0x80;
-      SiS_StandTable[0x11].CRTC[4] = 0x54;
-      SiS_StandTable[0x11].CRTC[5] = 0x80;
-      SiS_StandTable[0x11].CRTC[16] = 0x83;
-      SiS_StandTable[0x11].CRTC[17] = 0x85;
-      SiS_StandTable[0x12].CRTC[4] = 0x54;
-      SiS_StandTable[0x12].CRTC[5] = 0x80;
-      SiS_StandTable[0x12].CRTC[16] = 0x83;
-      SiS_StandTable[0x12].CRTC[17] = 0x85;
-      SiS_StandTable[0x13].CRTC[5] = 0xa0;
-      SiS_StandTable[0x17].CRTC[5] = 0xa0;
-      SiS_StandTable[0x1a].CRTC[4] = 0x54;
-      SiS_StandTable[0x1a].CRTC[5] = 0x80;
-      SiS_StandTable[0x1a].CRTC[16] = 0xea;
-      SiS_StandTable[0x1a].CRTC[17] = 0x8c;
-      SiS_StandTable[0x1b].CRTC[4] = 0x54;
-      SiS_StandTable[0x1b].CRTC[5] = 0x80;
-      SiS_StandTable[0x1b].CRTC[16] = 0xea;
-      SiS_StandTable[0x1b].CRTC[17] = 0x8c;
-      SiS_StandTable[0x1c].CRTC[4] = 0x54;
-      SiS_StandTable[0x1c].CRTC[5] = 0x80;
-   } else {
-      SiS_StandTable[0x04].CRTC[4] = 0x2c;
-      SiS_StandTable[0x05].CRTC[4] = 0x2c;
-      SiS_StandTable[0x06].CRTC[4] = 0x55;
-      SiS_StandTable[0x06].CRTC[5] = 0x81;
-      SiS_StandTable[0x0d].CRTC[4] = 0x2c;
-      SiS_StandTable[0x0e].CRTC[4] = 0x55;
-      SiS_StandTable[0x0e].CRTC[5] = 0x81;
-      SiS_StandTable[0x11].CRTC[4] = 0x55;
-      SiS_StandTable[0x11].CRTC[5] = 0x81;
-      SiS_StandTable[0x11].CRTC[16] = 0x82;
-      SiS_StandTable[0x11].CRTC[17] = 0x84;
-      SiS_StandTable[0x12].CRTC[4] = 0x55;
-      SiS_StandTable[0x12].CRTC[5] = 0x81;
-      SiS_StandTable[0x12].CRTC[16] = 0x82;
-      SiS_StandTable[0x12].CRTC[17] = 0x84;
-      SiS_StandTable[0x13].CRTC[5] = 0xb1;
-      SiS_StandTable[0x17].CRTC[5] = 0xb1;
-      SiS_StandTable[0x1a].CRTC[4] = 0x55;
-      SiS_StandTable[0x1a].CRTC[5] = 0x81;
-      SiS_StandTable[0x1a].CRTC[16] = 0xe9;
-      SiS_StandTable[0x1a].CRTC[17] = 0x8b;
-      SiS_StandTable[0x1b].CRTC[4] = 0x55;
-      SiS_StandTable[0x1b].CRTC[5] = 0x81;
-      SiS_StandTable[0x1b].CRTC[16] = 0xe9;
-      SiS_StandTable[0x1b].CRTC[17] = 0x8b;
-      SiS_StandTable[0x1c].CRTC[4] = 0x55;
-      SiS_StandTable[0x1c].CRTC[5] = 0x81;
-   }
-
-   SiS_Pr->SiS_NTSCPhase    = SiS_NTSCPhase;
-   SiS_Pr->SiS_PALPhase     = SiS_PALPhase;
-   SiS_Pr->SiS_NTSCPhase2   = SiS_NTSCPhase2;
-   SiS_Pr->SiS_PALPhase2    = SiS_PALPhase2;
-   SiS_Pr->SiS_PALMPhase    = SiS_PALMPhase;
-   SiS_Pr->SiS_PALNPhase    = SiS_PALNPhase;
-   SiS_Pr->SiS_PALMPhase2   = SiS_PALMPhase2;
-   SiS_Pr->SiS_PALNPhase2   = SiS_PALNPhase2;
-   SiS_Pr->SiS_SpecialPhase = SiS_SpecialPhase;
+
+   SiS_Pr->SiS_NTSCPhase     = SiS_NTSCPhase;
+   SiS_Pr->SiS_PALPhase      = SiS_PALPhase;
+   SiS_Pr->SiS_NTSCPhase2    = SiS_NTSCPhase2;
+   SiS_Pr->SiS_PALPhase2     = SiS_PALPhase2;
+   SiS_Pr->SiS_PALMPhase     = SiS_PALMPhase;
+   SiS_Pr->SiS_PALNPhase     = SiS_PALNPhase;
+   SiS_Pr->SiS_PALMPhase2    = SiS_PALMPhase2;
+   SiS_Pr->SiS_PALNPhase2    = SiS_PALNPhase2;
+   SiS_Pr->SiS_SpecialPhase  = SiS_SpecialPhase;
+   SiS_Pr->SiS_SpecialPhaseM = SiS_SpecialPhaseM;
+   SiS_Pr->SiS_SpecialPhaseJ = SiS_SpecialPhaseJ;
 
    SiS_Pr->SiS_NTSCTiming     = SiS_NTSCTiming;
    SiS_Pr->SiS_PALTiming      = SiS_PALTiming;
@@ -172,6 +121,12 @@
 /* SiS_Pr->SiS_St1HiTVData = SiS_St1HiTVData;  */
    SiS_Pr->SiS_St2HiTVData = SiS_St2HiTVData;
    SiS_Pr->SiS_ExtHiTVData = SiS_ExtHiTVData;
+   SiS_Pr->SiS_St525iData  = SiS_StNTSCData;
+   SiS_Pr->SiS_St525pData  = SiS_St525pData;
+   SiS_Pr->SiS_St750pData  = SiS_St750pData;
+   SiS_Pr->SiS_Ext525iData = SiS_ExtNTSCData;
+   SiS_Pr->SiS_Ext525pData = SiS_ExtNTSCData;
+   SiS_Pr->SiS_Ext750pData = SiS_Ext750pData;
 
    SiS_Pr->pSiS_OutputSelect = &SiS_OutputSelect;
    SiS_Pr->pSiS_SoftSetting  = &SiS_SoftSetting;
@@ -221,12 +176,17 @@
    SiS_Pr->SiS_LVDS848x480Data_1   = SiS_LVDS848x480Data_1;
    SiS_Pr->SiS_LVDS848x480Data_2   = SiS_LVDS848x480Data_2;
 
+   SiS_Pr->SiS_CHTVUNTSCData = SiS_CHTVUNTSCData;
+   SiS_Pr->SiS_CHTVONTSCData = SiS_CHTVONTSCData;
+
+   SiS_Pr->SiS_LCDA1024x768Data_1  = SiS_LCDA1024x768Data_1;
+   SiS_Pr->SiS_LCDA1024x768Data_2  = SiS_LCDA1024x768Data_2;
+   SiS_Pr->SiS_LCDA1280x1024Data_1 = SiS_LCDA1280x1024Data_1;
+   SiS_Pr->SiS_LCDA1280x1024Data_2 = SiS_LCDA1280x1024Data_2;
    SiS_Pr->SiS_LCDA1400x1050Data_1 = SiS_LCDA1400x1050Data_1;
    SiS_Pr->SiS_LCDA1400x1050Data_2 = SiS_LCDA1400x1050Data_2;
    SiS_Pr->SiS_LCDA1600x1200Data_1 = SiS_LCDA1600x1200Data_1;
    SiS_Pr->SiS_LCDA1600x1200Data_2 = SiS_LCDA1600x1200Data_2;
-   SiS_Pr->SiS_CHTVUNTSCData = SiS_CHTVUNTSCData;
-   SiS_Pr->SiS_CHTVONTSCData = SiS_CHTVONTSCData;
 
    SiS_Pr->LVDS1024x768Des_1  = SiS_PanelType1076_1;
    SiS_Pr->LVDS1280x1024Des_1 = SiS_PanelType1210_1;
@@ -270,23 +230,48 @@
 
 #ifdef SIS300
 static void
-InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
-   InitCommonPointer(SiS_Pr, HwDeviceExtension);
+   InitCommonPointer(SiS_Pr, HwInfo);
+
+   SiS_StandTable[0x04].CRTC[4] = 0x2b;
+   SiS_StandTable[0x05].CRTC[4] = 0x2b;
+   SiS_StandTable[0x06].CRTC[4] = 0x54;
+   SiS_StandTable[0x06].CRTC[5] = 0x80;
+   SiS_StandTable[0x0d].CRTC[4] = 0x2b;
+   SiS_StandTable[0x0e].CRTC[4] = 0x54;
+   SiS_StandTable[0x0e].CRTC[5] = 0x80;
+   SiS_StandTable[0x11].CRTC[4] = 0x54;
+   SiS_StandTable[0x11].CRTC[5] = 0x80;
+   SiS_StandTable[0x11].CRTC[16] = 0x83;
+   SiS_StandTable[0x11].CRTC[17] = 0x85;
+   SiS_StandTable[0x12].CRTC[4] = 0x54;
+   SiS_StandTable[0x12].CRTC[5] = 0x80;
+   SiS_StandTable[0x12].CRTC[16] = 0x83;
+   SiS_StandTable[0x12].CRTC[17] = 0x85;
+   SiS_StandTable[0x13].CRTC[5] = 0xa0;
+   SiS_StandTable[0x17].CRTC[5] = 0xa0;
+   SiS_StandTable[0x1a].CRTC[4] = 0x54;
+   SiS_StandTable[0x1a].CRTC[5] = 0x80;
+   SiS_StandTable[0x1a].CRTC[16] = 0xea;
+   SiS_StandTable[0x1a].CRTC[17] = 0x8c;
+   SiS_StandTable[0x1b].CRTC[4] = 0x54;
+   SiS_StandTable[0x1b].CRTC[5] = 0x80;
+   SiS_StandTable[0x1b].CRTC[16] = 0xea;
+   SiS_StandTable[0x1b].CRTC[17] = 0x8c;
+   SiS_StandTable[0x1c].CRTC[4] = 0x54;
+   SiS_StandTable[0x1c].CRTC[5] = 0x80;
 
    SiS_Pr->SiS_SModeIDTable  = (SiS_StStruct *)SiS300_SModeIDTable;
    SiS_Pr->SiS_VBModeIDTable = (SiS_VBModeStruct *)SiS300_VBModeIDTable;
    SiS_Pr->SiS_EModeIDTable  = (SiS_ExtStruct *)SiS300_EModeIDTable;
    SiS_Pr->SiS_RefIndex      = (SiS_Ext2Struct *)SiS300_RefIndex;
    SiS_Pr->SiS_CRT1Table     = (SiS_CRT1TableStruct *)SiS300_CRT1Table;
-   if(HwDeviceExtension->jChipType == SIS_300) {
+   if(HwInfo->jChipType == SIS_300) {
       SiS_Pr->SiS_MCLKData_0    = (SiS_MCLKDataStruct *)SiS300_MCLKData_300; /* 300 */
    } else {
       SiS_Pr->SiS_MCLKData_0    = (SiS_MCLKDataStruct *)SiS300_MCLKData_630; /* 630, 730 */
    }
-#ifdef LINUXBIOS
-   SiS_Pr->SiS_ECLKData      = (SiS_ECLKDataStruct *)SiS300_ECLKData;
-#endif
    SiS_Pr->SiS_VCLKData      = (SiS_VCLKDataStruct *)SiS300_VCLKData;
    SiS_Pr->SiS_VBVCLKData    = (SiS_VBVCLKDataStruct *)SiS300_VCLKData;
    SiS_Pr->SiS_ScreenOffset  = SiS300_ScreenOffset;
@@ -328,7 +313,10 @@
    SiS_Pr->SiS_NoScaleData1280x1024 = (SiS_LCDDataStruct *)SiS300_NoScaleData1280x1024;
 
    SiS_Pr->SiS_PanelDelayTbl     = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTbl;
+   SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTbl;
+#if 0
    SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTblLVDS;
+#endif
 
    SiS_Pr->SiS_CHTVUPALData  = (SiS_LVDSDataStruct *)SiS300_CHTVUPALData;
    SiS_Pr->SiS_CHTVOPALData  = (SiS_LVDSDataStruct *)SiS300_CHTVOPALData;
@@ -429,7 +417,7 @@
    SiS_Pr->SiS_CRT2Part2_1400x1050_3 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1400x1050_3;
    SiS_Pr->SiS_CRT2Part2_1600x1200_3 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1600x1200_3;
 
-   /* TW: LCDResInfo will on 300 series be translated to 315 series definitions */
+   /* LCDResInfo will on 300 series be translated to 315 series definitions */
    SiS_Pr->SiS_Panel320x480   = Panel_320x480;
    SiS_Pr->SiS_Panel640x480   = Panel_640x480;
    SiS_Pr->SiS_Panel800x600   = Panel_800x600;
@@ -439,14 +427,14 @@
    SiS_Pr->SiS_Panel1024x600  = Panel_1024x600;
    SiS_Pr->SiS_Panel1152x768  = Panel_1152x768;
    SiS_Pr->SiS_Panel1280x768  = Panel_1280x768;
-   SiS_Pr->SiS_Panel1600x1200 = 255;  		/* TW: Something illegal */
-   SiS_Pr->SiS_Panel1400x1050 = 255;  		/* TW: Something illegal */
-   SiS_Pr->SiS_Panel640x480_2 = 255;  		/* TW: Something illegal */
-   SiS_Pr->SiS_Panel640x480_3 = 255;  		/* TW: Something illegal */
-   SiS_Pr->SiS_Panel1152x864  = 255;   		/* TW: Something illegal */
-   SiS_Pr->SiS_PanelMax       = Panel_320x480;     /* TW: highest value */
-   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;     /* TW: Lowest value LVDS */
-   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;    /* TW: lowest value 301 */
+   SiS_Pr->SiS_Panel1600x1200 = 255;  		   /* Something illegal */
+   SiS_Pr->SiS_Panel1400x1050 = 255;
+   SiS_Pr->SiS_Panel640x480_2 = 255;
+   SiS_Pr->SiS_Panel640x480_3 = 255;
+   SiS_Pr->SiS_Panel1152x864  = 255;
+   SiS_Pr->SiS_PanelMax       = Panel_320x480;     /* highest value */
+   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;     /* Lowest value LVDS */
+   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;    /* lowest value 301 */
    SiS_Pr->SiS_PanelCustom    = Panel_Custom;
    SiS_Pr->SiS_PanelBarco1366 = Panel_Barco1366;
 }
@@ -454,32 +442,52 @@
 
 #ifdef SIS315H
 static void
-InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
-   InitCommonPointer(SiS_Pr, HwDeviceExtension);
+   InitCommonPointer(SiS_Pr, HwInfo);
+
+   SiS_StandTable[0x04].CRTC[4] = 0x2c;
+   SiS_StandTable[0x05].CRTC[4] = 0x2c;
+   SiS_StandTable[0x06].CRTC[4] = 0x55;
+   SiS_StandTable[0x06].CRTC[5] = 0x81;
+   SiS_StandTable[0x0d].CRTC[4] = 0x2c;
+   SiS_StandTable[0x0e].CRTC[4] = 0x55;
+   SiS_StandTable[0x0e].CRTC[5] = 0x81;
+   SiS_StandTable[0x11].CRTC[4] = 0x55;
+   SiS_StandTable[0x11].CRTC[5] = 0x81;
+   SiS_StandTable[0x11].CRTC[16] = 0x82;
+   SiS_StandTable[0x11].CRTC[17] = 0x84;
+   SiS_StandTable[0x12].CRTC[4] = 0x55;
+   SiS_StandTable[0x12].CRTC[5] = 0x81;
+   SiS_StandTable[0x12].CRTC[16] = 0x82;
+   SiS_StandTable[0x12].CRTC[17] = 0x84;
+   SiS_StandTable[0x13].CRTC[5] = 0xb1;
+   SiS_StandTable[0x17].CRTC[5] = 0xb1;
+   SiS_StandTable[0x1a].CRTC[4] = 0x55;
+   SiS_StandTable[0x1a].CRTC[5] = 0x81;
+   SiS_StandTable[0x1a].CRTC[16] = 0xe9;
+   SiS_StandTable[0x1a].CRTC[17] = 0x8b;
+   SiS_StandTable[0x1b].CRTC[4] = 0x55;
+   SiS_StandTable[0x1b].CRTC[5] = 0x81;
+   SiS_StandTable[0x1b].CRTC[16] = 0xe9;
+   SiS_StandTable[0x1b].CRTC[17] = 0x8b;
+   SiS_StandTable[0x1c].CRTC[4] = 0x55;
+   SiS_StandTable[0x1c].CRTC[5] = 0x81;
 
    SiS_Pr->SiS_SModeIDTable  = (SiS_StStruct *)SiS310_SModeIDTable;
    SiS_Pr->SiS_EModeIDTable  = (SiS_ExtStruct *)SiS310_EModeIDTable;
    SiS_Pr->SiS_RefIndex      = (SiS_Ext2Struct *)SiS310_RefIndex;
    SiS_Pr->SiS_CRT1Table     = (SiS_CRT1TableStruct *)SiS310_CRT1Table;
-   /* TW: MCLK is different */
-#ifdef LINUXBIOS
-   if(HwDeviceExtension->jChipType >= SIS_660) {
-      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_660;  /* 660/760 */
-   } else if(HwDeviceExtension->jChipType == SIS_330) {
-#endif
+   if(HwInfo->jChipType >= SIS_661) {
+      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_660;  /* 661/741/760 */
+   } else if(HwInfo->jChipType == SIS_330) {
       SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_330;  /* 330 */
-#ifdef LINUXBIOS
-   } else if(HwDeviceExtension->jChipType > SIS_315PRO) {
+   } else if(HwInfo->jChipType > SIS_315PRO) {
       SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_650;  /* 550, 650, 740 */
    } else {
       SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_315;  /* 315 */
    }
-#endif
    SiS_Pr->SiS_MCLKData_1    = (SiS_MCLKDataStruct *)SiS310_MCLKData_1;
-#ifdef LINUXBIOS
-   SiS_Pr->SiS_ECLKData      = (SiS_ECLKDataStruct *)SiS310_ECLKData;
-#endif
    SiS_Pr->SiS_VCLKData      = (SiS_VCLKDataStruct *)SiS310_VCLKData;
    SiS_Pr->SiS_VBVCLKData    = (SiS_VBVCLKDataStruct *)SiS310_VBVCLKData;
    SiS_Pr->SiS_ScreenOffset  = SiS310_ScreenOffset;
@@ -601,7 +609,7 @@
    SiS_Pr->SiS_CHTVCRT1ONTSC         = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1ONTSC;
    SiS_Pr->SiS_CHTVCRT1UPAL          = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UPAL;
    SiS_Pr->SiS_CHTVCRT1OPAL          = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1OPAL;
-   SiS_Pr->SiS_CHTVCRT1SOPAL         = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1SOPAL;
+   SiS_Pr->SiS_CHTVCRT1SOPAL         = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1OPAL;
 
    SiS_Pr->SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UNTSC;
    SiS_Pr->SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_ONTSC;
@@ -611,24 +619,20 @@
    SiS_Pr->SiS_CHTVReg_OPALM = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPALM;
    SiS_Pr->SiS_CHTVReg_UPALN = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UPALN;
    SiS_Pr->SiS_CHTVReg_OPALN = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPALN;
-   SiS_Pr->SiS_CHTVReg_SOPAL = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_SOPAL;
+   SiS_Pr->SiS_CHTVReg_SOPAL = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPAL;
 
-   SiS_Pr->SiS_LCDACRT1800x600_1     = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_1;
    SiS_Pr->SiS_LCDACRT11024x768_1    = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_1;
    SiS_Pr->SiS_LCDACRT11280x1024_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_1;
    SiS_Pr->SiS_LCDACRT11400x1050_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_1;
    SiS_Pr->SiS_LCDACRT11600x1200_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_1;
-   SiS_Pr->SiS_LCDACRT1800x600_1_H   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_1_H;
    SiS_Pr->SiS_LCDACRT11024x768_1_H  = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_1_H;
    SiS_Pr->SiS_LCDACRT11280x1024_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_1_H;
    SiS_Pr->SiS_LCDACRT11400x1050_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_1_H;
    SiS_Pr->SiS_LCDACRT11600x1200_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_1_H;
-   SiS_Pr->SiS_LCDACRT1800x600_2     = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_2;
    SiS_Pr->SiS_LCDACRT11024x768_2    = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_2;
    SiS_Pr->SiS_LCDACRT11280x1024_2   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_2;
    SiS_Pr->SiS_LCDACRT11400x1050_2   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_2;
    SiS_Pr->SiS_LCDACRT11600x1200_2   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_2;
-   SiS_Pr->SiS_LCDACRT1800x600_2_H   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_2_H;
    SiS_Pr->SiS_LCDACRT11024x768_2_H  = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_2_H;
    SiS_Pr->SiS_LCDACRT11280x1024_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_2_H;
    SiS_Pr->SiS_LCDACRT11400x1050_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_2_H;
@@ -642,7 +646,7 @@
    SiS_Pr->SiS_CHTVVCLKOPALM = SiS310_CHTVVCLKOPALM;
    SiS_Pr->SiS_CHTVVCLKUPALN = SiS310_CHTVVCLKUPALN;
    SiS_Pr->SiS_CHTVVCLKOPALN = SiS310_CHTVVCLKOPALN;   
-   SiS_Pr->SiS_CHTVVCLKSOPAL = SiS310_CHTVVCLKSOPAL;
+   SiS_Pr->SiS_CHTVVCLKSOPAL = SiS310_CHTVVCLKOPAL;
 
    SiS_Pr->SiS_Panel320x480   = Panel_320x480;
    SiS_Pr->SiS_Panel640x480   = Panel_640x480;
@@ -658,50 +662,612 @@
    SiS_Pr->SiS_Panel1024x600  = Panel_1024x600;
    SiS_Pr->SiS_Panel640x480_2 = Panel_640x480_2;
    SiS_Pr->SiS_Panel640x480_3 = Panel_640x480_3;
-   SiS_Pr->SiS_PanelMax       = Panel_320x480;    /* TW: highest value */
-   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;    /* TW: lowest value LVDS/LCDA */
-   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;   /* TW: lowest value 301 */
+   SiS_Pr->SiS_PanelMax       = Panel_320x480;    /* highest value */
+   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;    /* lowest value LVDS/LCDA */
+   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;   /* lowest value 301 */
    SiS_Pr->SiS_PanelCustom    = Panel_Custom;
    SiS_Pr->SiS_PanelBarco1366 = 255;
 }
 #endif
 
+static void
+SiSInitPtr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   switch(HwInfo->jChipType) {
 #ifdef SIS315H
-UCHAR
-SiS_Get310DRAMType(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+   case SIS_315H:
+   case SIS_315:
+   case SIS_315PRO:
+   case SIS_550:
+   case SIS_650:
+   case SIS_740:
+   case SIS_330:
+   case SIS_661:
+   case SIS_741:
+   case SIS_660:
+   case SIS_760:
+      InitTo310Pointer(SiS_Pr, HwInfo);
+      break;
+#endif
+#ifdef SIS300
+   case SIS_300:
+   case SIS_540:
+   case SIS_630:
+   case SIS_730:
+      InitTo300Pointer(SiS_Pr, HwInfo);
+      break;
+#endif
+   default:
+      break;
+   }
+}
+
+/*********************************************/
+/*            HELPER: Get ModeID             */
+/*********************************************/
+
+USHORT
+SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, BOOLEAN FSTN)
 {
-   UCHAR data, temp;
+   USHORT ModeIndex = 0;
 
-   if(*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) {
-     data = *SiS_Pr->pSiS_SoftSetting & 0x03;
-   } else {
-     if(IS_SIS550650740660) {
-        data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x07;
-     } else {	/* TW: 315, 330 */
-        data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3a) & 0x03;
-        if(HwDeviceExtension->jChipType == SIS_330) {
-	   if(data > 1) {
-	      temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5f) & 0x30;
-	      switch(temp) {
-	      case 0x00: data = 1; break;
-	      case 0x10: data = 3; break;
-	      case 0x20: data = 3; break;
-	      case 0x30: data = 2; break;
-	      }
-	   } else {
-	      data = 0;
-	   }
-	}
-     }
+   switch(HDisplay)
+   {
+     case 320:
+     	  if(VDisplay == 200)     ModeIndex = ModeIndex_320x200[Depth];
+	  else if(VDisplay == 240) {
+	     if(FSTN) ModeIndex = ModeIndex_320x240_FSTN[Depth];
+	     else     ModeIndex = ModeIndex_320x240[Depth];
+          }
+          break;
+     case 400:
+          if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
+          break;
+     case 512:
+          if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
+          break;
+     case 640:
+          if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
+	  else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
+          break;
+     case 720:
+          if(!(VBFlags & CRT1_LCDA)) {
+             if(VDisplay == 480)      ModeIndex = ModeIndex_720x480[Depth];
+             else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth];
+          }
+          break;
+     case 768:
+          if(!(VBFlags & CRT1_LCDA)) {
+             if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
+          }
+	  break;
+     case 800:
+	  if(VDisplay == 600)    ModeIndex = ModeIndex_800x600[Depth];
+	  else if(!(VBFlags & CRT1_LCDA)) {
+	     if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth];
+	  }
+          break;
+     case 848:
+          if(!(VBFlags & CRT1_LCDA)) {
+	     if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
+	  }
+	  break;
+     case 856:
+          if(!(VBFlags & CRT1_LCDA)) {
+	     if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
+	  }
+	  break;
+     case 1024:
+          if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
+	  else if(!(VBFlags & CRT1_LCDA)) {
+	     if(VDisplay == 576)    ModeIndex = ModeIndex_1024x576[Depth];
+	     else if(VGAEngine == SIS_300_VGA) {
+	        if(VDisplay == 600) ModeIndex = ModeIndex_1024x600[Depth];
+             }
+	  }
+          break;
+     case 1152:
+          if(!(VBFlags & CRT1_LCDA)) {
+             if(VDisplay == 864)    ModeIndex = ModeIndex_1152x864[Depth];
+             else if(VGAEngine == SIS_300_VGA) {
+	        if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth];
+             }
+	  }
+	  break;
+     case 1280:
+          if(VDisplay == 1024)        ModeIndex = ModeIndex_1280x1024[Depth];
+	  else if(!(VBFlags & CRT1_LCDA)) {
+             if(VDisplay == 960)      ModeIndex = ModeIndex_1280x960[Depth];
+	     else if(VDisplay == 720) ModeIndex = ModeIndex_1280x720[Depth];
+	     else if(VDisplay == 768) {
+	        if(VGAEngine == SIS_300_VGA) {
+	           ModeIndex = ModeIndex_300_1280x768[Depth];
+	        } else {
+	           ModeIndex = ModeIndex_310_1280x768[Depth];
+	        }
+	     }
+	  }
+          break;
+     case 1360:
+          if(!(VBFlags & CRT1_LCDA)) {
+	     if(VDisplay == 768)     ModeIndex = ModeIndex_1360x768[Depth];
+	     else if(VGAEngine == SIS_300_VGA) {
+	        if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth];
+             }
+	  }
+          break;
+     case 1400:
+          if(VGAEngine == SIS_315_VGA) {
+	     if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth];
+	  }
+          break;
+     case 1600:
+          if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
+          break;
+     case 1920:
+          if(!(VBFlags & CRT1_LCDA)) {
+             if(VDisplay == 1440) ModeIndex = ModeIndex_1920x1440[Depth];
+	  }
+          break;
+     case 2048:
+          if(!(VBFlags & CRT1_LCDA)) {
+             if(VDisplay == 1536) {
+                if(VGAEngine == SIS_300_VGA) {
+	            ModeIndex = ModeIndex_300_2048x1536[Depth];
+  	        } else {
+	            ModeIndex = ModeIndex_310_2048x1536[Depth];
+                }
+	     }
+	  }
+          break;
    }
 
-   return data;
+   return(ModeIndex);
+}
+
+USHORT
+SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay,
+                  int Depth, BOOLEAN FSTN, USHORT CustomT, int LCDwidth, int LCDheight)
+{
+   USHORT ModeIndex = 0;
+
+   if(VBFlags & (VB_LVDS | VB_30xBDH)) {
+
+      switch(HDisplay)
+      {
+	case 320:
+	     if(CustomT != CUT_PANEL848) {
+     	  	if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth];
+	  	else if(VDisplay == 240) {
+		   if(!FSTN) ModeIndex = ModeIndex_320x240[Depth];
+          	   else if(VGAEngine == SIS_315_VGA) {
+                      ModeIndex = ModeIndex_320x240_FSTN[Depth];
+		   }
+		}
+	     }
+             break;
+     	case 400:
+	     if(CustomT != CUT_PANEL848) {
+          	if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
+	     }
+             break;
+	case 512:
+	     if(CustomT != CUT_PANEL848) {
+		if(VDisplay == 384) {
+		   if(LCDwidth != 1024 || LCDheight != 600) {
+		      ModeIndex = ModeIndex_512x384[Depth];
+		   }
+		}
+	     }
+	     break;
+	case 640:
+	     if(VDisplay == 480)            ModeIndex = ModeIndex_640x480[Depth];
+	     else if(VDisplay == 400) {
+	        if(CustomT != CUT_PANEL848) ModeIndex = ModeIndex_640x400[Depth];
+	     }
+	     break;
+	case 800:
+	     if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth];
+	     break;
+	case 848:
+	     if(CustomT == CUT_PANEL848) {
+	        if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
+	     }
+	     break;
+	case 1024:
+	     if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
+	     else if(VGAEngine == SIS_300_VGA) {
+		if((VDisplay == 600) && (LCDheight == 600)) {
+		   ModeIndex = ModeIndex_1024x600[Depth];
+		}
+	     }
+	     break;
+	case 1152:
+	     if(VGAEngine == SIS_300_VGA) {
+	        if((VDisplay == 768) && (LCDheight == 768)) {
+		   ModeIndex = ModeIndex_1152x768[Depth];
+		}
+	     }
+	     break;
+        case 1280:
+	     if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth];
+	     else if(VGAEngine == SIS_315_VGA) {
+	        if((VDisplay == 768) && (LCDheight == 768)) {
+		   ModeIndex = ModeIndex_310_1280x768[Depth];
+		}
+	     }
+	     break;
+	case 1360:
+	     if(VGAEngine == SIS_300_VGA) {
+	        if(CustomT == CUT_BARCO1366) {
+		   if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth];
+		}
+	     }
+	     if(CustomT == CUT_PANEL848) {
+	        if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth];
+	     }
+	     break;
+	case 1400:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth];
+	     }
+	     break;
+	case 1600:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
+	     }
+	     break;
+      }
+
+   } else if(VBFlags & VB_SISBRIDGE) {
+
+      switch(HDisplay)
+      {
+	case 320:
+     	     if(VDisplay == 200)      ModeIndex = ModeIndex_320x200[Depth];
+	     else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth];
+             break;
+     	case 400:
+             if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
+             break;
+	case 512:
+	     if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
+	     break;
+	case 640:
+	     if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
+	     else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
+	     break;
+	case 800:
+	     if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth];
+	     break;
+	case 1024:
+	     if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
+	     break;
+	case 1280:
+	     if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth];
+	     else if(VDisplay == 768) {
+		if((LCDheight == 768) ||
+		   ((LCDheight == 1024) && (VBFlags & (VB_301|VB_301B|VB_301C|VB_302B)))) {
+		   if(VGAEngine == SIS_300_VGA) {
+		      ModeIndex = ModeIndex_300_1280x768[Depth];
+		   } else {
+		      ModeIndex = ModeIndex_310_1280x768[Depth];
+		   }
+		}
+	     } else if(VDisplay == 960) {
+	        if((LCDheight == 960) ||
+		   ((LCDheight == 1024) && (VBFlags & (VB_301|VB_301B|VB_301C|VB_302B)))) {
+		   ModeIndex = ModeIndex_1280x960[Depth];
+		}
+	     }
+	     break;
+	case 1400:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VBFlags & (VB_301B | VB_301C | VB_302B | VB_302LV | VB_302ELV)) {
+		   if(LCDheight != 1200) {
+	              if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth];
+		   }
+		}
+	     }
+	     break;
+	case 1600:
+	     if(VBFlags & (VB_301C | VB_302B | VB_302LV | VB_302ELV)) {
+	        if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
+	     }
+	     break;
+      }
+   }
+
+   return ModeIndex;
+}
+
+USHORT
+SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth)
+{
+   USHORT ModeIndex = 0;
+
+   if(VBFlags & VB_CHRONTEL) {
+
+      switch(HDisplay)
+      {
+      	case 512:
+	     if(VGAEngine == SIS_315_VGA) {
+		if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
+	     }
+	     break;
+	case 640:
+	     if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
+	     else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
+	     break;
+	case 800:
+	     if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth];
+	     break;
+	case 1024:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
+	     }
+	     break;
+      }
+
+   } else if(VBFlags & VB_SISTVBRIDGE) {
+
+      switch(HDisplay)
+      {
+	case 320:
+     	     if(VDisplay == 200)      ModeIndex = ModeIndex_320x200[Depth];
+	     else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth];
+             break;
+        case 400:
+             if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
+             break;
+      	case 512:
+	     if( ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR525P | TV_YPBPR750P))) ||
+	         (VBFlags & TV_HIVISION) 					     ||
+	         ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) {
+	        if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
+	     }
+	     break;
+	case 640:
+	     if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
+	     else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
+	     break;
+	case 720:
+	     if(!(VBFlags & TV_HIVISION)) {
+                if(VDisplay == 480) {
+		   if((VBFlags & TV_YPBPR) || (VBFlags & (TV_NTSC | TV_PALM)))
+                      ModeIndex = ModeIndex_720x480[Depth];
+                } else if(VDisplay == 576) {
+		   if((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL))
+                      ModeIndex = ModeIndex_720x576[Depth];
+                }
+	     }
+             break;
+	case 768:
+	     if(!(VBFlags & TV_HIVISION)) {
+	        if((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) {
+          	   if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
+		}
+             }
+	     break;
+	case 800:
+	     if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth];
+	     else if(VDisplay == 480) {
+	        if(VBFlags & TV_HIVISION) {
+		   ModeIndex = ModeIndex_800x480[Depth];
+		}
+	     }
+	     break;
+	case 1024:
+	     if(VDisplay == 768) {
+		if(VBFlags & (VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV|VB_302ELV)) {
+		   ModeIndex = ModeIndex_1024x768[Depth];
+		}
+	     } else if(VDisplay == 576) {
+	        if(VBFlags & TV_HIVISION) {
+		   ModeIndex = ModeIndex_1024x576[Depth];
+		}
+	     }
+	     break;
+	case 1280:
+	     if(VBFlags & TV_HIVISION) {
+	        if(VDisplay == 720)       ModeIndex = ModeIndex_1280x720[Depth];
+		else if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth];
+	     }
+	     break;
+      }
+   }
+   return ModeIndex;
+}
+
+USHORT
+SiS_GetModeID_VGA2(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth)
+{
+   USHORT ModeIndex = 0;
+
+   if(!(VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0;
+
+   switch(HDisplay)
+   {
+	case 320:
+     	  	if(VDisplay == 200)      ModeIndex = ModeIndex_320x200[Depth];
+	  	else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth];
+          	break;
+     	case 400:
+          	if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
+          	break;
+  	case 512:
+		if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
+		break;
+	case 640:
+		if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
+		else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
+		break;
+	case 720:
+		if(VDisplay == 480)      ModeIndex = ModeIndex_720x480[Depth];
+		else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth];
+		break;
+	case 768:
+          	if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
+	  	break;
+	case 800:
+		if(VDisplay == 600)      ModeIndex = ModeIndex_800x600[Depth];
+   	        else if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth];
+		break;
+	case 848:
+		if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
+		break;
+	case 856:
+		if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
+		break;
+	case 1024:
+		if(VDisplay == 768)      ModeIndex = ModeIndex_1024x768[Depth];
+		else if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth];
+		break;
+	case 1152:
+	        if(VDisplay == 864)    ModeIndex = ModeIndex_1152x864[Depth];
+		else if(VGAEngine == SIS_300_VGA) {
+		   if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth];
+		}
+		break;
+	case 1280:
+	        if(VDisplay == 768) {
+		   if(VGAEngine == SIS_300_VGA) {
+		      ModeIndex = ModeIndex_300_1280x768[Depth];
+		   } else {
+		      ModeIndex = ModeIndex_310_1280x768[Depth];
+		   }
+		} else if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth];
+		else if(VDisplay == 720)    ModeIndex = ModeIndex_1280x720[Depth];
+		else if(VDisplay == 960)    ModeIndex = ModeIndex_1280x960[Depth];
+		break;
+        case 1360:
+	        if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth];
+                break;
+        case 1400:
+		if(VGAEngine == SIS_315_VGA) {
+	           if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth];
+		}
+		break;
+	case 1600:
+		if(VGAEngine == SIS_315_VGA) {
+		   if(VBFlags & (VB_301B|VB_301C|VB_302B)) {
+	              if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
+		   }
+		}
+		break;
+   }
+
+   return ModeIndex;
+}
+
+
+/*********************************************/
+/*          HELPER: SetReg, GetReg           */
+/*********************************************/
+
+void
+SiS_SetReg(SISIOADDRESS port, USHORT index, USHORT data)
+{
+   OutPortByte(port,index);
+   OutPortByte(port + 1,data);
+}
+
+void
+SiS_SetRegByte(SISIOADDRESS port, USHORT data)
+{
+   OutPortByte(port,data);
+}
+
+void
+SiS_SetRegShort(SISIOADDRESS port, USHORT data)
+{
+   OutPortWord(port,data);
+}
+
+void
+SiS_SetRegLong(SISIOADDRESS port, ULONG data)
+{
+   OutPortLong(port,data);
+}
+
+UCHAR
+SiS_GetReg(SISIOADDRESS port, USHORT index)
+{
+   OutPortByte(port,index);
+   return(InPortByte(port + 1));
+}
+
+UCHAR
+SiS_GetRegByte(SISIOADDRESS port)
+{
+   return(InPortByte(port));
+}
+
+USHORT
+SiS_GetRegShort(SISIOADDRESS port)
+{
+   return(InPortWord(port));
+}
+
+ULONG
+SiS_GetRegLong(SISIOADDRESS port)
+{
+   return(InPortLong(port));
+}
+
+void
+SiS_SetRegANDOR(SISIOADDRESS Port,USHORT Index,USHORT DataAND,USHORT DataOR)
+{
+  USHORT temp;
+
+  temp = SiS_GetReg(Port,Index);
+  temp = (temp & (DataAND)) | DataOR;
+  SiS_SetReg(Port,Index,temp);
+}
+
+void
+SiS_SetRegAND(SISIOADDRESS Port,USHORT Index,USHORT DataAND)
+{
+  USHORT temp;
+
+  temp = SiS_GetReg(Port,Index);
+  temp &= DataAND;
+  SiS_SetReg(Port,Index,temp);
+}
+
+void
+SiS_SetRegOR(SISIOADDRESS Port,USHORT Index,USHORT DataOR)
+{
+  USHORT temp;
+
+  temp = SiS_GetReg(Port,Index);
+  temp |= DataOR;
+  SiS_SetReg(Port,Index,temp);
+}
+
+/*********************************************/
+/*      HELPER: DisplayOn, DisplayOff        */
+/*********************************************/
+
+void
+SiS_DisplayOn(SiS_Private *SiS_Pr)
+{
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x01,0xDF,0x00);
+}
+
+void
+SiS_DisplayOff(SiS_Private *SiS_Pr)
+{
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x01,0xDF,0x20);
 }
-#endif
 
-/* ----------------------------------------- */
 
-void SiSRegInit(SiS_Private *SiS_Pr, USHORT BaseAddr)
+/*********************************************/
+/*        HELPER: Init Port Addresses        */
+/*********************************************/
+
+void
+SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr)
 {
    SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
    SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
@@ -726,10 +1292,62 @@
    SiS_Pr->SiS_VidPlay = BaseAddr + SIS_VIDEO_PLAYBACK;
 }
 
-void
-SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+/*********************************************/
+/*             HELPER: GetSysFlags           */
+/*********************************************/
+
+static void
+SiS_GetSysFlags(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   unsigned char cr5f, temp1, temp2;
+
+   /* You should use the macros, not these flags directly */
+
+   SiS_Pr->SiS_SysFlags = 0;
+   if(HwInfo->jChipType == SIS_650) {
+      cr5f = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0;
+      SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x5c,0x07);
+      temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
+      SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x5c,0xf8);
+      temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
+      if((!temp1) || (temp2)) {
+         switch(cr5f) {
+	    case 0x80:
+	    case 0x90:
+	    case 0xc0:
+	       SiS_Pr->SiS_SysFlags |= SF_IsM650;  break;
+	    case 0xa0:
+	    case 0xb0:
+	    case 0xe0:
+	       SiS_Pr->SiS_SysFlags |= SF_Is651;   break;
+	 }
+      } else {
+         switch(cr5f) {
+	    case 0x90:
+	       temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
+	       switch(temp1) {
+	          case 0x00: SiS_Pr->SiS_SysFlags |= SF_IsM652; break;
+		  case 0x40: SiS_Pr->SiS_SysFlags |= SF_IsM653; break;
+		  default:   SiS_Pr->SiS_SysFlags |= SF_IsM650; break;
+	       }
+	       break;
+	    case 0xb0:
+	       SiS_Pr->SiS_SysFlags |= SF_Is652;  break;
+	    default:
+	       SiS_Pr->SiS_SysFlags |= SF_IsM650; break;
+	 }
+      }
+   }
+}
+
+/*********************************************/
+/*         HELPER: Init PCI & Engines        */
+/*********************************************/
+
+static void
+SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
-   switch(HwDeviceExtension->jChipType) {
+   switch(HwInfo->jChipType) {
    case SIS_300:
    case SIS_540:
    case SIS_630:
@@ -738,7 +1356,7 @@
        *     - RELOCATED VGA IO  (0x20)
        *     - MMIO ENABLE (0x1)
        */
-      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xa1);
+      SiS_SetReg(SiS_Pr->SiS_P3c4,0x20,0xa1);
       /*  - Enable 2D (0x40)
        *  - Enable 3D (0x02)
        *  - Enable 3D Vertex command fetch (0x10) ?
@@ -752,9 +1370,11 @@
    case SIS_650:
    case SIS_740:
    case SIS_330:
+   case SIS_661:
+   case SIS_741:
    case SIS_660:
    case SIS_760:
-      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xa1);
+      SiS_SetReg(SiS_Pr->SiS_P3c4,0x20,0xa1);
       /*  - Enable 2D (0x40)
        *  - Enable 3D (0x02)
        *  - Enable 3D vertex command fetch (0x10)
@@ -764,7 +1384,7 @@
       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0xDA);
       break;
    case SIS_550:
-      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xa1);
+      SiS_SetReg(SiS_Pr->SiS_P3c4,0x20,0xa1);
       /* No 3D engine ! */
       /*  - Enable 2D (0x40)
        */
@@ -772,38 +1392,33 @@
    }
 }
 
+/*********************************************/
+/*             HELPER: SetLVDSetc            */
+/*********************************************/
+
 void
-SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
+SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
    ULONG   temp;
 
    SiS_Pr->SiS_IF_DEF_LVDS = 0;
    SiS_Pr->SiS_IF_DEF_TRUMPION = 0;
    SiS_Pr->SiS_IF_DEF_CH70xx = 0;
-   SiS_Pr->SiS_IF_DEF_HiVision = 0;
    SiS_Pr->SiS_IF_DEF_DSTN = 0;
    SiS_Pr->SiS_IF_DEF_FSTN = 0;
+   SiS_Pr->SiS_IF_DEF_CONEX = 0;
 
    SiS_Pr->SiS_ChrontelInit = 0;
 
-#if 0
-   if(HwDeviceExtension->jChipType >= SIS_315H) {
-      if((ModeNo == 0x5a) || (ModeNo == 0x5b)) {
-   	 SiS_Pr->SiS_IF_DEF_DSTN = 1;   /* for 550 dstn */
-   	 SiS_Pr->SiS_IF_DEF_FSTN = 1;   /* for fstn */
-      }
-   }
-#endif
-
-   switch(HwDeviceExtension->jChipType) {
+   switch(HwInfo->jChipType) {
 #ifdef SIS300
    case SIS_540:
    case SIS_630:
    case SIS_730:
         /* Check for SiS30x first */
-        temp = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x00);
+        temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00);
 	if((temp == 1) || (temp == 2)) return;
-      	temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
+      	temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37);
       	temp = (temp & 0x0E) >> 1;
       	if((temp >= 2) && (temp <= 5)) SiS_Pr->SiS_IF_DEF_LVDS = 1;
       	if(temp == 3)   SiS_Pr->SiS_IF_DEF_TRUMPION = 1;
@@ -819,12 +1434,20 @@
    case SIS_650:
    case SIS_740:
    case SIS_330:
+        temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37);
+      	temp = (temp & 0x0E) >> 1;
+      	if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1;
+      	if(temp == 3)  SiS_Pr->SiS_IF_DEF_CH70xx = 2;
+        break;
+   case SIS_661:
+   case SIS_741:
    case SIS_660:
    case SIS_760:
-	temp=SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
-      	temp = (temp & 0x0E) >> 1;
+        temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+      	temp = (temp & 0xe0) >> 5;
       	if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1;
       	if(temp == 3)  SiS_Pr->SiS_IF_DEF_CH70xx = 2;
+	if(temp == 4)  SiS_Pr->SiS_IF_DEF_CONEX = 1;  /* Not yet supported */
         break;
 #endif
    default:
@@ -832,2757 +1455,2793 @@
    }
 }
 
+/*********************************************/
+/*          HELPER: Enable DSTN/FSTN         */
+/*********************************************/
+
 void
-SiSInitPtr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable)
 {
-   switch(HwDeviceExtension->jChipType) {
-#ifdef SIS315H
-   case SIS_315H:
-   case SIS_315:
-   case SIS_315PRO:
-   case SIS_550:
-   case SIS_650:
-   case SIS_740:
-   case SIS_330:
-   case SIS_660:
-   case SIS_760:
-      InitTo310Pointer(SiS_Pr, HwDeviceExtension);
-      break;
-#endif
-#ifdef SIS300
-   case SIS_300:
-   case SIS_540:
-   case SIS_630:
-   case SIS_730:
-      InitTo300Pointer(SiS_Pr, HwDeviceExtension);
-      break;
-#endif
-   default:
-      break;
-   }
+   SiS_Pr->SiS_IF_DEF_DSTN = enable ? 1 : 0;
 }
 
 void
-SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, UCHAR *ROMAddr)
+SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable)
+{
+   SiS_Pr->SiS_IF_DEF_FSTN = enable ? 1 : 0;
+}
+
+/*********************************************/
+/*        HELPER: Determine ROM usage        */
+/*********************************************/
+
+static void
+SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
-   if((ROMAddr) && (HwDeviceExtension->UseROM)) {
-     if((ROMAddr[0x00] != 0x55) || (ROMAddr[0x01] != 0xAA)) {
-        SiS_Pr->SiS_UseROM = FALSE;
-     } else if(HwDeviceExtension->jChipType == SIS_300) {
-        /* TW: 300: We check if the code starts below 0x220 by
-	 *     checking the jmp instruction at the beginning
-	 *     of the BIOS image.
+   UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
+
+   if((ROMAddr) && (HwInfo->UseROM)) {
+      if((ROMAddr[0x00] != 0x55) || (ROMAddr[0x01] != 0xAA)) {
+         SiS_Pr->SiS_UseROM = FALSE;
+      } else if(HwInfo->jChipType == SIS_300) {
+        /* 300: We check if the code starts below 0x220 by
+	 * checking the jmp instruction at the beginning
+	 * of the BIOS image.
 	 */
 	 if((ROMAddr[3] == 0xe9) &&
 	    ((ROMAddr[5] << 8) | ROMAddr[4]) > 0x21a)
-	      SiS_Pr->SiS_UseROM = TRUE;
-	 else SiS_Pr->SiS_UseROM = FALSE;
-     } else if(HwDeviceExtension->jChipType < SIS_315H) {
+	    SiS_Pr->SiS_UseROM = TRUE;
+	 else
+	    SiS_Pr->SiS_UseROM = FALSE;
+      } else if(HwInfo->jChipType < SIS_315H) {
 #if 0
-        /* TW: Rest of 300 series: We don't use the ROM image if
-	 *     the BIOS version < 2.0.0 as such old BIOSes don't
-	 *     have the needed data at the expected locations.
+        /* Rest of 300 series: We don't use the ROM image if
+	 * the BIOS version < 2.0.0 as such old BIOSes don't
+	 * have the needed data at the expected locations.
 	 */
-        if(ROMAddr[0x06] < '2')  SiS_Pr->SiS_UseROM = FALSE;
-	else                     SiS_Pr->SiS_UseROM = TRUE;
+         if(ROMAddr[0x06] < '2')  SiS_Pr->SiS_UseROM = FALSE;
+	 else                     SiS_Pr->SiS_UseROM = TRUE;
 #else
 	/* Sony's VAIO BIOS 1.09 follows the standard, so perhaps
 	 * the others do as well
 	 */
-	SiS_Pr->SiS_UseROM = TRUE;
+	 SiS_Pr->SiS_UseROM = TRUE;
 #endif
-     } else {
-        /* TW: 315/330 series stick to the standard */
-	SiS_Pr->SiS_UseROM = TRUE;
-     }
+      } else {
+         /* 315/330 series stick to the standard */
+	 SiS_Pr->SiS_UseROM = TRUE;
+      }
    } else SiS_Pr->SiS_UseROM = FALSE;
 
 }
 
-/*
- 	=========================================
- 	======== SiS SetMode Functions ==========
- 	=========================================
-*/
-#ifdef LINUX_XF86
-/* TW: This is used for non-Dual-Head mode from X */
-BOOLEAN
-SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
-               DisplayModePtr mode, BOOLEAN IsCustom)
+/*********************************************/
+/*        HELPER: SET SEGMENT REGISTERS      */
+/*********************************************/
+
+static void
+SiS_SetSegRegLower(SiS_Private *SiS_Pr, USHORT value)
 {
-   SISPtr  pSiS = SISPTR(pScrn);
-   UShort  ModeNo=0;
-   
-   SiS_Pr->UseCustomMode = FALSE;
+   USHORT temp;
 
-   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
+   value &= 0x00ff;
+   temp = SiS_GetRegByte(SiS_Pr->SiS_P3cb) & 0xf0;
+   temp |= (value >> 4);
+   SiS_SetRegByte(SiS_Pr->SiS_P3cb, temp);
+   temp = SiS_GetRegByte(SiS_Pr->SiS_P3cd) & 0xf0;
+   temp |= (value & 0x0f);
+   SiS_SetRegByte(SiS_Pr->SiS_P3cd, temp);
+}
 
-         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting custom mode %dx%d\n",
-	 	SiS_Pr->CHDisplay,
-		(mode->Flags & V_INTERLACE ? SiS_Pr->CVDisplay * 2 :
-		   (mode->Flags & V_DBLSCAN ? SiS_Pr->CVDisplay / 2 :
-		      SiS_Pr->CVDisplay)));
+static void
+SiS_SetSegRegUpper(SiS_Private *SiS_Pr, USHORT value)
+{
+   USHORT temp;
 
-	 return(SiSSetMode(SiS_Pr, HwDeviceExtension, pScrn, ModeNo, TRUE));
+   value &= 0x00ff;
+   temp = SiS_GetRegByte(SiS_Pr->SiS_P3cb) & 0x0f;
+   temp |= (value & 0xf0);
+   SiS_SetRegByte(SiS_Pr->SiS_P3cb, temp);
+   temp = SiS_GetRegByte(SiS_Pr->SiS_P3cd) & 0x0f;
+   temp |= (value << 4);
+   SiS_SetRegByte(SiS_Pr->SiS_P3cd, temp);
+}
 
-   }
+static void
+SiS_SetSegmentReg(SiS_Private *SiS_Pr, USHORT value)
+{
+   SiS_SetSegRegLower(SiS_Pr, value);
+   SiS_SetSegRegUpper(SiS_Pr, value);
+}
 
-   ModeNo = SiS_CalcModeIndex(pScrn, mode, pSiS->HaveCustomModes);
-   if(!ModeNo) return FALSE;
+static void
+SiS_ResetSegmentReg(SiS_Private *SiS_Pr)
+{
+   SiS_SetSegmentReg(SiS_Pr, 0);
+}
 
-   xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x\n", ModeNo);
+static void
+SiS_SetSegmentRegOver(SiS_Private *SiS_Pr, USHORT value)
+{
+   USHORT temp = value >> 8;
 
-   return(SiSSetMode(SiS_Pr, HwDeviceExtension, pScrn, ModeNo, TRUE));
+   temp &= 0x07;
+   temp |= (temp << 4);
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x1d,temp);
+   SiS_SetSegmentReg(SiS_Pr, value);
 }
 
-#ifdef SISDUALHEAD
-/* TW: Set CRT1 mode (used for dual head and MergedFB) */
-BOOLEAN
-SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
-               DisplayModePtr mode, BOOLEAN IsCustom)
+static void
+SiS_ResetSegmentRegOver(SiS_Private *SiS_Pr)
 {
-   ULONG   temp;
-   USHORT  ModeIdIndex;
-   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
-   USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
-   SISPtr  pSiS = SISPTR(pScrn);
-   SISEntPtr pSiSEnt = pSiS->entityPrivate;
-   unsigned char backupreg=0;
-   BOOLEAN backupcustom;
-   UShort  ModeNo=0;
-   
-   SiS_Pr->UseCustomMode = FALSE;
-
-   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
+   SiS_SetSegmentRegOver(SiS_Pr, 0);
+}
 
-         USHORT temptemp = SiS_Pr->CVDisplay;
+static void
+SiS_ResetSegmentRegisters(SiS_Private *SiS_Pr,PSIS_HW_INFO HwInfo)
+{
+   if((IS_SIS65x) || (HwInfo->jChipType >= SIS_661)) {
+      SiS_ResetSegmentReg(SiS_Pr);
+      SiS_ResetSegmentRegOver(SiS_Pr);
+   }
+}
 
-         if(SiS_Pr->CModeFlag & DoubleScanMode)     temptemp >>= 1;
-         else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
+/*********************************************/
+/*             HELPER: GetVBType             */
+/*********************************************/
 
-         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
-	 	"Setting custom mode %dx%d on CRT1\n",
-	 	SiS_Pr->CHDisplay, temptemp);
-	 ModeNo = 0xfe;
+void
+SiS_GetVBType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT flag=0, rev=0, nolcd=0;
 
-   } else {
+  SiS_Pr->SiS_VBType = 0;
 
-         ModeNo = SiS_CalcModeIndex(pScrn, mode, pSiS->HaveCustomModes);
-         if(!ModeNo) return FALSE;
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) return;
 
-         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
-	 	"Setting standard mode 0x%x on CRT1\n", ModeNo);
-   }
+  flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00);
 
-   SiSInitPtr(SiS_Pr, HwDeviceExtension);
+  if(flag > 3) return;
 
-   SiSRegInit(SiS_Pr, BaseAddr);
+  rev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01);
 
-   SiS_GetSysFlags(SiS_Pr, HwDeviceExtension);
+  if(flag >= 2) {
+     SiS_Pr->SiS_VBType = VB_SIS302B;
+  } else if(flag == 1) {
+     SiS_Pr->SiS_VBType = VB_SIS301;
+     if(rev >= 0xC0) {
+       	SiS_Pr->SiS_VBType = VB_SIS301C;
+     } else if(rev >= 0xB0) {
+       	SiS_Pr->SiS_VBType = VB_SIS301B;
+	/* Check if 30xB DH version (no LCD support, use Panel Link instead) */
+    	nolcd = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x23);
+        if(!(nolcd & 0x02)) SiS_Pr->SiS_VBType |= VB_NoLCD;
+     }
+  }
+  if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS301C | VB_SIS302B)) {
+     if(rev >= 0xD0) {
+	SiS_Pr->SiS_VBType &= ~(VB_SIS301B | VB_SIS301C | VB_SIS302B | VB_NoLCD);
+	if(rev >= 0xE0) {
+	   flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x39);
+	   if(flag == 0xff)
+	      SiS_Pr->SiS_VBType |= VB_SIS302LV;
+	   else
+	      SiS_Pr->SiS_VBType |= VB_SIS302ELV;
+	} else {
+	   SiS_Pr->SiS_VBType |= VB_SIS301LV;
+	}
+     }
+  }
+}
 
-   SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
+/*********************************************/
+/*            HELPER: GetDRAMSize            */
+/*********************************************/
 
-   SiSInitPCIetc(SiS_Pr, HwDeviceExtension);
+#ifndef LINUX_XF86
+static ULONG
+GetDRAMSize(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  ULONG   AdapterMemorySize = 0;
+#ifdef SIS315H
+  USHORT  counter;
+#endif
 
-   SiSSetLVDSetc(SiS_Pr, HwDeviceExtension, ModeNo);
+  switch(HwInfo->jChipType) {
+#ifdef SIS315H
+  case SIS_315H:
+  case SIS_315:
+  case SIS_315PRO:
+    	counter = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
+	AdapterMemorySize = 1 << ((counter & 0xF0) >> 4);
+	counter >>= 2;
+	counter &= 0x03;
+	if(counter == 0x02) {
+		AdapterMemorySize += (AdapterMemorySize / 2);      /* DDR asymetric */
+	} else if(counter != 0) {
+		AdapterMemorySize <<= 1;                           /* SINGLE_CHANNEL_2_RANK or DUAL_CHANNEL_1_RANK */
+	}
+	AdapterMemorySize *= (1024*1024);
+        break;
 
-   SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
+  case SIS_330:
+    	counter = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
+	AdapterMemorySize = 1 << ((counter & 0xF0) >> 4);
+	counter &= 0x0c;
+	if(counter != 0) {
+		AdapterMemorySize <<= 1;
+	}
+	AdapterMemorySize *= (1024*1024);
+	break;
 
-   /* We don't clear the buffer under X */
-   SiS_Pr->SiS_flag_clearbuffer = 0;
+  case SIS_550:
+  case SIS_650:
+  case SIS_740:
+  	counter = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
+      	counter++;
+      	AdapterMemorySize = counter * 4;
+      	AdapterMemorySize *= (1024*1024);
+	break;
 
-   /* 1.Openkey */
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
+  case SIS_661:
+  case SIS_741:
+  case SIS_660:
+  case SIS_760:
+        counter = (SiS_GetReg(SiS_Pr->SiS_P3c4,0x79) & 0xf0) >> 4;
+	AdapterMemorySize = 1 << counter;
+      	AdapterMemorySize *= (1024*1024);
+        break;
+#endif
 
-   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+#ifdef SIS300
+  case SIS_300:
+  case SIS_540:
+  case SIS_630:
+  case SIS_730:
+      	AdapterMemorySize = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
+      	AdapterMemorySize++;
+      	AdapterMemorySize *= (1024*1024);
+	break;
+#endif
+  default:
+        break;
+  }
 
-   /* 2.Get ModeID Table  */
-   if(!SiS_Pr->UseCustomMode) {
-      temp = SiS_SearchModeID(SiS_Pr, ROMAddr,&ModeNo,&ModeIdIndex);
-      if(temp == 0)  return(0);
-   } else {
-      ModeIdIndex = 0;
-   }
+  return AdapterMemorySize;
+}
+#endif
 
-   /* TW: Determine VBType (301,301B,301LV,302B,302LV) */
-   SiS_GetVBType(SiS_Pr, BaseAddr,HwDeviceExtension);
+/*********************************************/
+/*           HELPER: Check RAM size          */
+/*********************************************/
 
-   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-      if(HwDeviceExtension->jChipType >= SIS_315H) {
-         backupreg = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
-      } else {
-         backupreg = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x35);
-      }
-   }
+#ifndef LINUX_XF86
+static BOOLEAN
+SiS_CheckMemorySize(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                    USHORT ModeNo, USHORT ModeIdIndex)
+{
+  USHORT memorysize,modeflag;
+  ULONG  temp;
 
-   /* TW: Get VB information (connectors, connected devices) */
-   /* (We don't care if the current mode is a CRT2 mode) */
-   SiS_GetVBInfo(SiS_Pr, BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,0);
-   SiS_SetHiVision(SiS_Pr, BaseAddr,HwDeviceExtension);
-   SiS_GetLCDResInfo(SiS_Pr, ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+  if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+  } else {
+     if(ModeNo <= 0x13) {
+        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     } else {
+        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     }
+  }
 
-   if(HwDeviceExtension->jChipType >= SIS_315H) {
-      if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
-         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-            if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= SetDOSMode;
-         } else if((IS_SIS651) && (SiS_Pr->SiS_VBType & VB_NoLCD)) {
-            SiS_Pr->SiS_SetFlag |= SetDOSMode;
-         }
-      }
+  memorysize = modeflag & MemoryInfoFlag;
+  memorysize >>= MemorySizeShift;		/* Get required memory size */
+  memorysize++;
 
-      if(IS_SIS650) {
-         if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
-	    if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20);
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
-	 }
-      }
-   }
+  temp = GetDRAMSize(SiS_Pr, HwInfo);       	/* Get adapter memory size (in MB) */
+  temp /= (1024*1024);
 
-   /* Set mode on CRT1 */
-   SiS_SetCRT1Group(SiS_Pr, ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,BaseAddr);
+  if(temp < memorysize) return(FALSE);
+  else return(TRUE);
+}
+#endif
 
-   /* SetPitch: Adapt to virtual size & position */
-   SiS_SetPitchCRT1(SiS_Pr, pScrn, BaseAddr);
+/*********************************************/
+/*           HELPER: Get DRAM type           */
+/*********************************************/
 
-   if(pSiS->DualHeadMode) {
-      pSiSEnt->CRT1ModeNo = ModeNo;
-      pSiSEnt->CRT1DMode = mode;
-   }
+#ifdef SIS315H
+static UCHAR
+SiS_Get310DRAMType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   UCHAR data, temp;
 
-   if(SiS_Pr->UseCustomMode) {
-      SiS_Pr->CRT1UsesCustomMode = TRUE;
-      SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
-      SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
+   if(*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) {
+     data = *SiS_Pr->pSiS_SoftSetting & 0x03;
    } else {
-      SiS_Pr->CRT1UsesCustomMode = FALSE;
+     if(HwInfo->jChipType >= SIS_661) {
+        data = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x07;
+     } else if(IS_SIS550650740) {
+        data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x07;
+     } else {	/* 315, 330 */
+        data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3a) & 0x03;
+        if(HwInfo->jChipType == SIS_330) {
+	   if(data > 1) {
+	      temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0x30;
+	      switch(temp) {
+	      case 0x00: data = 1; break;
+	      case 0x10: data = 3; break;
+	      case 0x20: data = 3; break;
+	      case 0x30: data = 2; break;
+	      }
+	   } else {
+	      data = 0;
+	   }
+	}
+     }
    }
 
-   /* We have to reset CRT2 if changing mode on CRT1 */
-   if(pSiS->DualHeadMode) {
-      if(pSiSEnt->CRT2ModeNo != -1) {
-         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
-				"(Re-)Setting mode for CRT2\n");
-	 backupcustom = SiS_Pr->UseCustomMode;
-	 SiSBIOSSetModeCRT2(SiS_Pr, HwDeviceExtension, pSiSEnt->pScrn_1,
-			    pSiSEnt->CRT2DMode, pSiSEnt->CRT2IsCustom);
-	 SiS_Pr->UseCustomMode = backupcustom;
-      }
-   }
-
-   /* Warning: From here, the custom mode entries in SiS_Pr are
-    * possibly overwritten
-    */
-
-   SiS_HandleCRT1(SiS_Pr);
+   return data;
+}
 
-   SiS_StrangeStuff(SiS_Pr, HwDeviceExtension);
+USHORT
+SiS_GetMCLK(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT index;
 
-   SiS_DisplayOn(SiS_Pr);
-   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
+  index = SiS_Get310DRAMType(SiS_Pr, HwInfo);
+  if(HwInfo->jChipType >= SIS_661) {
+     return(SiS_Pr->SiS_MCLKData_0[index].CLOCK);
+  } else if(index >= 4) {
+     index -= 4;
+     return(SiS_Pr->SiS_MCLKData_1[index].CLOCK);
+  } else {
+     return(SiS_Pr->SiS_MCLKData_0[index].CLOCK);
+  }
+}
+#endif
 
-   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-      if(HwDeviceExtension->jChipType >= SIS_315H) {
-	 SiS_SetReg1(SiS_Pr->SiS_P3d4,0x38,backupreg);
-      } else if((HwDeviceExtension->jChipType == SIS_630) ||
-                (HwDeviceExtension->jChipType == SIS_730)) {
-         SiS_SetReg1(SiS_Pr->SiS_P3d4,0x35,backupreg);
-      }
-   }
+/*********************************************/
+/*           HELPER: ClearBuffer             */
+/*********************************************/
 
-   /* Backup/Set ModeNo in BIOS scratch area */
-   SiS_GetSetModeID(pScrn,ModeNo);
+#ifndef LINUX_XF86
+static void
+SiS_ClearBuffer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo)
+{
+  UCHAR   *VideoMemoryAddress = HwInfo->pjVideoMemoryAddress;
+  ULONG   AdapterMemorySize  = (ULONG)HwInfo->ulVideoMemorySize;
+  USHORT  *pBuffer;
+  int i;
 
-   return TRUE;
+  if(SiS_Pr->SiS_ModeType >= ModeEGA) {
+     if(ModeNo > 0x13) {
+        AdapterMemorySize = GetDRAMSize(SiS_Pr, HwInfo);
+        SiS_SetMemory(VideoMemoryAddress,AdapterMemorySize,0);
+     } else {
+        pBuffer = (USHORT *)VideoMemoryAddress;
+        for(i=0; i<0x4000; i++)
+           pBuffer[i] = 0x0000;
+     }
+  } else {
+     pBuffer = (USHORT *)VideoMemoryAddress;
+     if(SiS_Pr->SiS_ModeType < ModeCGA) {
+        for(i=0; i<0x4000; i++)
+           pBuffer[i] = 0x0720;
+     } else {
+        SiS_SetMemory(VideoMemoryAddress,0x8000,0);
+     }
+  }
 }
+#endif
+
+/*********************************************/
+/*           HELPER: SearchModeID            */
+/*********************************************/
 
-/* TW: Set CRT2 mode (used for dual head) */
 BOOLEAN
-SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
-               DisplayModePtr mode, BOOLEAN IsCustom)
+SiS_SearchModeID(SiS_Private *SiS_Pr, USHORT *ModeNo, USHORT *ModeIdIndex)
 {
-   ULONG   temp;
-   USHORT  ModeIdIndex;
-   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
-   USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
-   UShort  ModeNo   = 0;
-   SISPtr  pSiS     = SISPTR(pScrn);
-   SISEntPtr pSiSEnt = pSiS->entityPrivate;
-   unsigned char tempr1, tempr2, backupreg=0;
+   UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO;
 
-   SiS_Pr->UseCustomMode = FALSE;
+   if(*ModeNo <= 0x13) {
 
-   /* Remember: Custom modes for CRT2 are ONLY supported
-    * 		-) on 315/330 series,
-    *           -) on the 301 and 30xB, and
-    *           -) if CRT2 is LCD or VGA
-    */
+      if((*ModeNo) <= 0x05) (*ModeNo) |= 0x01;
 
-   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
+      for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+         if(SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == (*ModeNo)) break;
+         if(SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == 0xFF)   return FALSE;
+      }
 
-	 ModeNo = 0xfe;
+      if(*ModeNo == 0x07) {
+          if(VGAINFO & 0x10) (*ModeIdIndex)++;   /* 400 lines */
+          /* else 350 lines */
+      }
+      if(*ModeNo <= 0x03) {
+         if(!(VGAINFO & 0x80)) (*ModeIdIndex)++;
+         if(VGAINFO & 0x10)    (*ModeIdIndex)++; /* 400 lines  */
+         /* else 350 lines  */
+      }
+      /* else 200 lines  */
 
    } else {
 
-         BOOLEAN havecustommodes = pSiS->HaveCustomModes;
-
-#ifdef SISMERGED
-	 if(pSiS->MergedFB) havecustommodes = pSiS->HaveCustomModes2;
-#endif
-
-         ModeNo = SiS_CalcModeIndex(pScrn, mode, havecustommodes);
-         if(!ModeNo) return FALSE;
+      for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+         if(SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) break;
+         if(SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)      return FALSE;
+      }
 
    }
+   return TRUE;
+}
 
-   /* Save mode info so we can set it from within SetMode for CRT1 */
-   if(pSiS->DualHeadMode) {
-      pSiSEnt->CRT2ModeNo = ModeNo;
-      pSiSEnt->CRT2DMode = mode;
-      pSiSEnt->CRT2IsCustom = IsCustom;
+/*********************************************/
+/*            HELPER: GetModePtr             */
+/*********************************************/
 
-      /* We can't set CRT2 mode before CRT1 mode is set */
-      if(pSiSEnt->CRT1ModeNo == -1) {
-    	 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
-		"Setting CRT2 mode delayed until after setting CRT1 mode\n");
-   	 return TRUE;
-      }
-   }
+UCHAR
+SiS_GetModePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex)
+{
+   UCHAR index;
 
-   SiSInitPtr(SiS_Pr, HwDeviceExtension);
+   if(ModeNo <= 0x13) {
+     	index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_StTableIndex;
+   } else {
+     	if(SiS_Pr->SiS_ModeType <= 0x02) index = 0x1B;    /* 02 -> ModeEGA  */
+     	else index = 0x0F;
+   }
+   return index;
+}
 
-   SiSRegInit(SiS_Pr, BaseAddr);
+/*********************************************/
+/*           HELPER: LowModeTests            */
+/*********************************************/
+
+static BOOLEAN
+SiS_DoLowModeTest(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo)
+{
+    USHORT temp,temp1,temp2;
+
+    if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12))
+       return(1);
+    temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x11);
+    SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x11,0x80);
+    temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00);
+    SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,0x55);
+    temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00);
+    SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,temp1);
+    SiS_SetReg(SiS_Pr->SiS_P3d4,0x11,temp);
+    if((HwInfo->jChipType >= SIS_315H) ||
+       (HwInfo->jChipType == SIS_300)) {
+       if(temp2 == 0x55) return(0);
+       else return(1);
+    } else {
+       if(temp2 != 0x55) return(1);
+       else {
+          SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
+          return(0);
+       }
+    }
+}
 
-   SiS_GetSysFlags(SiS_Pr, HwDeviceExtension);
+static void
+SiS_SetLowModeTest(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo)
+{
+    if(SiS_DoLowModeTest(SiS_Pr, ModeNo, HwInfo)) {
+       SiS_Pr->SiS_SetFlag |= LowModeTests;
+    }
+}
 
-   SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
+/*********************************************/
+/*           HELPER: GetColorDepth           */
+/*********************************************/
 
-   SiSInitPCIetc(SiS_Pr, HwDeviceExtension);
+USHORT
+SiS_GetColorDepth(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex)
+{
+  USHORT ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
+  SHORT  index;
+  USHORT modeflag;
 
-   SiSSetLVDSetc(SiS_Pr, HwDeviceExtension, ModeNo);
+  /* Do NOT check UseCustomMode, will skrew up FIFO */
+  if(ModeNo == 0xfe) {
+     modeflag = SiS_Pr->CModeFlag;
+  } else {
+     if(ModeNo <= 0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     else
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
 
-   SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
+  index = (modeflag & ModeInfoFlag) - ModeEGA;
+  if(index < 0) index = 0;
+  return(ColorDepth[index]);
+}
 
-   /* We don't clear the buffer under X */
-   SiS_Pr->SiS_flag_clearbuffer=0;
+/*********************************************/
+/*             HELPER: GetOffset             */
+/*********************************************/
 
-   if(SiS_Pr->UseCustomMode) {
+USHORT
+SiS_GetOffset(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
+              USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo)
+{
+  USHORT temp,colordepth,infoflag;
 
-      USHORT temptemp = SiS_Pr->CVDisplay;
+  if(SiS_Pr->UseCustomMode) {
+     infoflag = SiS_Pr->CInfoFlag;
+     temp = SiS_Pr->CHDisplay / 16;
+  } else {
+     infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+     temp = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeOffset;
+     temp = SiS_Pr->SiS_ScreenOffset[temp];
+  }
 
-      if(SiS_Pr->CModeFlag & DoubleScanMode)     temptemp >>= 1;
-      else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
+  colordepth = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex);
 
-      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
-	  "Setting custom mode %dx%d on CRT2\n",
-	  SiS_Pr->CHDisplay, temptemp);
+  if(infoflag & InterlaceMode) temp <<= 1;
 
-   } else {
+  temp *= colordepth;
 
-      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
-   	  "Setting standard mode 0x%x on CRT2\n", ModeNo);
+  if( ( ((ModeNo >= 0x26) && (ModeNo <= 0x28)) ||
+        ModeNo == 0x3f ||
+	ModeNo == 0x42 ||
+	ModeNo == 0x45 ) ||
+      (SiS_Pr->UseCustomMode && (SiS_Pr->CHDisplay % 16)) ) {
+     colordepth >>= 1;
+     temp += colordepth;
+  }
 
-   }
+  return(temp);
+}
 
-   /* 1.Openkey */
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
+/*********************************************/
+/*                   SEQ                     */
+/*********************************************/
 
-   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+static void
+SiS_SetSeqRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, PSIS_HW_INFO HwInfo)
+{
+   UCHAR SRdata;
+   USHORT i;
 
-   /* 2.Get ModeID */
-   if(!SiS_Pr->UseCustomMode) {
-      temp = SiS_SearchModeID(SiS_Pr, ROMAddr,&ModeNo,&ModeIdIndex);
-      if(temp == 0)  return(0);
-   } else {
-      ModeIdIndex = 0;
-   }
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x03);           	/* Set SR0  */
 
-   /* Determine VBType (301,301B,301LV,302B,302LV) */
-   SiS_GetVBType(SiS_Pr, BaseAddr,HwDeviceExtension);
+   SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0];
 
    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-      if(HwDeviceExtension->jChipType >= SIS_315H) {
-         SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension,BaseAddr);
-	 if(HwDeviceExtension->jChipType < SIS_330) {
-           if(ROMAddr && SiS_Pr->SiS_UseROM) {
-             temp = ROMAddr[VB310Data_1_2_Offset];
-	     temp |= 0x40;
-             SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x02,temp);
-           }
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+         SRdata |= 0x01;
+      }
+      if(HwInfo->jChipType >= SIS_661) {
+         if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) {
+	    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+               SRdata |= 0x01;          		/* 8 dot clock  */
+            }
+	 }
+      } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+         if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+	    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+               SRdata |= 0x01;          		/* 8 dot clock  */
+            }
 	 }
-	 SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
-
-	 SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x02,0x0c);
-
-         backupreg = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
-      } else {
-         backupreg = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x35);
       }
    }
 
-   /* Get VB information (connectors, connected devices) */
-   if(!SiS_Pr->UseCustomMode) {
-      SiS_GetVBInfo(SiS_Pr, BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,1);
-   } else {
-      /* If this is a custom mode, we don't check the modeflag for CRT2Mode */
-      SiS_GetVBInfo(SiS_Pr, BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,0);
-   }
-   SiS_SetHiVision(SiS_Pr, BaseAddr,HwDeviceExtension);
-   SiS_GetLCDResInfo(SiS_Pr, ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
-
-   if(HwDeviceExtension->jChipType >= SIS_315H) {
-      if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
-         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-            if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= SetDOSMode;
-         } else if((IS_SIS651) && (SiS_Pr->SiS_VBType & VB_NoLCD)) {
-            SiS_Pr->SiS_SetFlag |= SetDOSMode;
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+      if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+         if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+            if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+               SRdata |= 0x01;        			/* 8 dot clock  */
+            }
+         }
+      }
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+         if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+            SRdata |= 0x01;          			/* 8 dot clock  */
          }
       }
    }
 
-   /* Set mode on CRT2 */
-   switch (HwDeviceExtension->ujVBChipID) {
-     case VB_CHIP_301:
-     case VB_CHIP_301B:
-     case VB_CHIP_301C:
-     case VB_CHIP_301LV:
-     case VB_CHIP_302:
-     case VB_CHIP_302B:
-     case VB_CHIP_302LV:
-        SiS_SetCRT2Group(SiS_Pr, BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
-        break;
-     case VB_CHIP_UNKNOWN:
-        if(SiS_Pr->SiS_IF_DEF_LVDS     == 1 ||
-	   SiS_Pr->SiS_IF_DEF_CH70xx   != 0 ||
-	   SiS_Pr->SiS_IF_DEF_TRUMPION != 0) {
-           SiS_SetCRT2Group(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
-  	}
-        break;
-   }
-
-   SiS_StrangeStuff(SiS_Pr, HwDeviceExtension);
+   SRdata |= 0x20;                			/* screen off  */
 
-   SiS_DisplayOn(SiS_Pr);
-   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x01,SRdata);
 
-   if(HwDeviceExtension->jChipType >= SIS_315H) {
-      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-         if(!(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr))) {
-	     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
-	 }
-      }
+   for(i = 2; i <= 4; i++) {
+      SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+      SiS_SetReg(SiS_Pr->SiS_P3c4,i,SRdata);
    }
+}
 
-   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-      if(HwDeviceExtension->jChipType >= SIS_315H) {
-	 if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
-	     SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
-	 } else {
-	     SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE);
-	 }
+/*********************************************/
+/*                  MISC                     */
+/*********************************************/
 
-	 SiS_SetReg1(SiS_Pr->SiS_P3d4,0x38,backupreg);
+static void
+SiS_SetMiscRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, PSIS_HW_INFO HwInfo)
+{
+   UCHAR Miscdata;
 
-	 tempr1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
-	 tempr2 = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x00);
-	 if(tempr1 & SetCRT2ToAVIDEO) tempr2 &= 0xF7;
-	 if(tempr1 & SetCRT2ToSVIDEO) tempr2 &= 0xFB;
-	 SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,tempr2);
+   Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC;
 
-	 if(tempr1 & SetCRT2ToLCD) {
-	       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc);
-	 }
-      } else if((HwDeviceExtension->jChipType == SIS_630) ||
-                (HwDeviceExtension->jChipType == SIS_730)) {
-         SiS_SetReg1(SiS_Pr->SiS_P3d4,0x35,backupreg);
+   if(HwInfo->jChipType < SIS_661) {
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+            Miscdata |= 0x0C;
+         }
       }
    }
 
-   /* SetPitch: Adapt to virtual size & position */
-   SiS_SetPitchCRT2(SiS_Pr, pScrn, BaseAddr);
-
-   return TRUE;
+   SiS_SetRegByte(SiS_Pr->SiS_P3c2,Miscdata);
 }
-#endif /* Dualhead */
-#endif /* Linux_XF86 */
 
-#ifdef LINUX_XF86
-/* TW: We need pScrn for setting the pitch correctly */
-BOOLEAN
-SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch)
-#else
-BOOLEAN
-SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
-#endif
+/*********************************************/
+/*                  CRTC                     */
+/*********************************************/
+
+static void
+SiS_SetCRTCRegs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                USHORT StandTableIndex)
 {
-   ULONG   temp;
-   USHORT  ModeIdIndex,KeepLockReg;
-   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
-   USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
-   unsigned char backupreg=0, tempr1, tempr2;
+  UCHAR CRTCdata;
+  USHORT i;
 
-#ifndef LINUX_XF86
-   SiS_Pr->UseCustomMode = FALSE;
-   SiS_Pr->CRT1UsesCustomMode = FALSE;
-#endif
-   
-   if(SiS_Pr->UseCustomMode) {
-      ModeNo = 0xfe;
-   }
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);                       /* Unlock CRTC */
 
-   SiSInitPtr(SiS_Pr, HwDeviceExtension);
+  for(i = 0; i <= 0x18; i++) {
+     CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
+     SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata);                     /* Set CRTC(3d4) */
+  }
+  if( ( (HwInfo->jChipType == SIS_630) ||
+        (HwInfo->jChipType == SIS_730) )  &&
+      (HwInfo->jChipRevision >= 0x30) ) {       	   /* for 630S0 */
+     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) {
+           SiS_SetReg(SiS_Pr->SiS_P3d4,0x18,0xFE);
+        }
+     }
+  }
+}
 
-   SiSRegInit(SiS_Pr, BaseAddr);
+/*********************************************/
+/*                   ATT                     */
+/*********************************************/
 
-   SiS_GetSysFlags(SiS_Pr, HwDeviceExtension);
+static void
+SiS_SetATTRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex,
+               PSIS_HW_INFO HwInfo)
+{
+   UCHAR ARdata;
+   USHORT i;
 
-#ifdef LINUX_XF86
-   if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
-   else
-#endif
-         SiS_Pr->SiS_VGAINFO = 0x11;
-
-#ifdef LINUX_XF86
-#ifdef TWDEBUG
-   xf86DrvMsg(0, X_INFO, "VGAInfo 0x%02x\n", SiS_Pr->SiS_VGAINFO);
-#endif
+   for(i = 0; i <= 0x13; i++) {
+      ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
+#if 0
+      if((i <= 0x0f) || (i == 0x11)) {
+         if(ds:489 & 0x08) {
+	    continue;
+         }
+      }
 #endif
+      if(i == 0x13) {
+         /* Pixel shift. If screen on LCD or TV is shifted left or right,
+          * this might be the cause.
+          */
+         if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+            if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)  ARdata=0;
+         }
+         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+            if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+               if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+                  if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0;
+               }
+            }
+         }
+	 if(HwInfo->jChipType >= SIS_661) {
+	    if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD)) {
+	       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0;
+	    }
+	 } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+            if(HwInfo->jChipType >= SIS_315H) {
+	       if(IS_SIS550650740660) {
+	          /* 315, 330 don't do this */
+	          if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	             if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0;
+	          } else {
+	             ARdata = 0;
+	          }
+	       }
+	    } else {
+               if(SiS_Pr->SiS_VBInfo & SetInSlaveMode)  ARdata=0;
+	    }
+         }
+      }
+      SiS_GetRegByte(SiS_Pr->SiS_P3da);                         /* reset 3da  */
+      SiS_SetRegByte(SiS_Pr->SiS_P3c0,i);                       /* set index  */
+      SiS_SetRegByte(SiS_Pr->SiS_P3c0,ARdata);                  /* set data   */
+   }
+   SiS_GetRegByte(SiS_Pr->SiS_P3da);                            /* reset 3da  */
+   SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x14);                       /* set index  */
+   SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x00);                       /* set data   */
+
+   SiS_GetRegByte(SiS_Pr->SiS_P3da);
+   SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x20);			/* Enable Attribute  */
+   SiS_GetRegByte(SiS_Pr->SiS_P3da);
+}
+
+/*********************************************/
+/*                   GRC                     */
+/*********************************************/
 
-   SiSInitPCIetc(SiS_Pr, HwDeviceExtension);
-
-   SiSSetLVDSetc(SiS_Pr, HwDeviceExtension, ModeNo);
+static void
+SiS_SetGRCRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex)
+{
+   UCHAR GRdata;
+   USHORT i;
 
-   SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
+   for(i = 0; i <= 0x08; i++) {
+      GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
+      SiS_SetReg(SiS_Pr->SiS_P3ce,i,GRdata);
+   }
 
-   if(!SiS_Pr->UseCustomMode) {
-      /* TW: Shift the clear-buffer-bit away */
-      ModeNo = ((ModeNo & 0x80) << 8) | (ModeNo & 0x7f);
+   if(SiS_Pr->SiS_ModeType > ModeVGA) {
+      /* 256 color disable */
+      SiS_SetRegAND(SiS_Pr->SiS_P3ce,0x05,0xBF);
    }
+}
 
-#ifdef LINUX_XF86
-   /* We never clear the buffer in X */
-   ModeNo |= 0x8000;
-#endif
+/*********************************************/
+/*          CLEAR EXTENDED REGISTERS         */
+/*********************************************/
 
-   if(ModeNo & 0x8000) {
-     	ModeNo &= 0x7fff;
-     	SiS_Pr->SiS_flag_clearbuffer = 0;
+static void
+SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT i;
+
+  for(i = 0x0A; i <= 0x0E; i++) {
+     SiS_SetReg(SiS_Pr->SiS_P3c4,i,0x00);
+  }
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x37,0xFE);
+  }
+}
+
+/*********************************************/
+/*                 RESET VCLK                */
+/*********************************************/
+
+static void
+SiS_ResetCRT1VCLK(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   if(HwInfo->jChipType >= SIS_315H) {
+      if(HwInfo->jChipType < SIS_661) {
+         if(SiS_Pr->SiS_IF_DEF_LVDS == 0) return;
+      }
    } else {
-     	SiS_Pr->SiS_flag_clearbuffer = 1;
+      if((SiS_Pr->SiS_IF_DEF_LVDS == 0) &&
+         (!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) {
+	 return;
+      }
    }
 
-   /* 1.Openkey */
-   KeepLockReg = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x05);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
+   if(HwInfo->jChipType >= SIS_315H) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xCF,0x20);
+   } else {
+      SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x20);
+   }
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[1].SR2B);
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[1].SR2C);
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80);
+   if(HwInfo->jChipType >= SIS_315H) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x10);
+   } else {
+      SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x10);
+   }
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[0].SR2B);
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[0].SR2C);
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80);
+}
 
-   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+/*********************************************/
+/*                  SYNC                     */
+/*********************************************/
 
-   if(!SiS_Pr->UseCustomMode) {
+static void
+SiS_SetCRT1Sync(SiS_Private *SiS_Pr, USHORT RefreshRateTableIndex)
+{
+  USHORT sync;
 
-      /* 2.Get ModeID Table  */
-      temp = SiS_SearchModeID(SiS_Pr,ROMAddr,&ModeNo,&ModeIdIndex);
-      if(temp == 0) return(0);
+  if(SiS_Pr->UseCustomMode) {
+     sync = SiS_Pr->CInfoFlag >> 8;
+  } else {
+     sync = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag >> 8;
+  }
 
-   } else {
+  sync &= 0xC0;
+  sync |= 0x2f;
+  SiS_SetRegByte(SiS_Pr->SiS_P3c2,sync);
+}
 
-      ModeIdIndex = 0;
+/*********************************************/
+/*                  CRTC/2                   */
+/*********************************************/
 
-   }
+#ifdef SIS315H
+static void
+SiS_GetLCDACRT1Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+		   USHORT RefreshRateTableIndex, USHORT *ResIndex,
+		   USHORT *DisplayType)
+ {
+  USHORT modeflag = 0;
 
-   /* Determine VBType (301,301B,301LV,302B,302LV) */
-   SiS_GetVBType(SiS_Pr,BaseAddr,HwDeviceExtension);
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     *ResIndex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     *ResIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
 
-   /* Init/restore some VB registers */
-   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-       if(HwDeviceExtension->jChipType >= SIS_315H) {
-         SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension,BaseAddr);
-	 if(HwDeviceExtension->jChipType < SIS_330) {
-           if(ROMAddr && SiS_Pr->SiS_UseROM) {
-             temp = ROMAddr[VB310Data_1_2_Offset];
-	     temp |= 0x40;
-             SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x02,temp);
-           }
-	 }
-	 SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
+  *ResIndex &= 0x3F;
 
-	 SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x02,0x0c);
+  *DisplayType = SiS_Pr->SiS_LCDResInfo;
+  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) *DisplayType += 32;
+  if(modeflag & HalfDCLK)                 *DisplayType += 16;
 
-         backupreg = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
-       } else {
-         backupreg = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x35);
-       }
-   }
-   
-   /* Get VB information (connectors, connected devices) */
-   if(SiS_Pr->UseCustomMode) {
-      SiS_GetVBInfo(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,0);
-   } else {
-      SiS_GetVBInfo(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,1);
-   }
-   SiS_SetHiVision(SiS_Pr,BaseAddr,HwDeviceExtension);
-   SiS_GetLCDResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+  if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+        *DisplayType = 100;
+	if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) *DisplayType += 2;
+        if(modeflag & HalfDCLK)                 *DisplayType += 1;
+     }
+  } else if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
+     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+        *DisplayType = 104;
+	if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) *DisplayType += 2;
+        if(modeflag & HalfDCLK)                 *DisplayType += 1;
+     }
+  }
 
-#ifndef LINUX_XF86
-   /* 3. Check memory size (Kernel framebuffer driver only) */
-   temp = SiS_CheckMemorySize(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex);
-   if(!temp) return(0);
+}
 #endif
 
-   if(HwDeviceExtension->jChipType >= SIS_315H) {
-      if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
-         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-            if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= SetDOSMode;
-         } else if((IS_SIS651) && (SiS_Pr->SiS_VBType & VB_NoLCD)) {
-            SiS_Pr->SiS_SetFlag |= SetDOSMode;
-         }
-      }
+static void
+SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex,
+		PSIS_HW_INFO HwInfo)
+{
+  UCHAR  index;
+  USHORT temp,i,j,modeflag;
+#ifdef SIS315H
+  USHORT ResIndex,DisplayType;
+  const SiS_LCDACRT1DataStruct *LCDACRT1Ptr = NULL;
+#endif
 
-      if(IS_SIS650) {
-         if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
-	    if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20);
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
-	 }
-      }
-   }
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);		/* unlock cr0-7 */
 
-   if(SiS_Pr->UseCustomMode) {
-      SiS_Pr->CRT1UsesCustomMode = TRUE;
-      SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
-      SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
-   } else {
-      SiS_Pr->CRT1UsesCustomMode = FALSE;
-   }
+  if(SiS_Pr->UseCustomMode) {
 
-   /* Set mode on CRT1 */
-   if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) {
-   	SiS_SetCRT1Group(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,BaseAddr);
-   } else {
-     if(!(SiS_Pr->SiS_VBInfo & SwitchToCRT2)) {
-       	SiS_SetCRT1Group(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,BaseAddr);
-     }
-   }
+     modeflag = SiS_Pr->CModeFlag;
 
-   /* Set mode on CRT2 */
-   if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2 | SetCRT2ToLCDA)) {
-     switch (HwDeviceExtension->ujVBChipID) {
-     case VB_CHIP_301:
-     case VB_CHIP_301B:
-     case VB_CHIP_301C:
-     case VB_CHIP_301LV:
-     case VB_CHIP_302:
-     case VB_CHIP_302B:
-     case VB_CHIP_302LV:
-        SiS_SetCRT2Group(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
-        break;
-     case VB_CHIP_UNKNOWN:
-	if(SiS_Pr->SiS_IF_DEF_LVDS     == 1 ||
-	   SiS_Pr->SiS_IF_DEF_CH70xx   != 0 ||
-	   SiS_Pr->SiS_IF_DEF_TRUMPION != 0)
-           SiS_SetCRT2Group(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
-        break;
+     for(i=0,j=0;i<=07;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
+     }
+     for(j=0x10;i<=10;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
+     }
+     for(j=0x15;i<=12;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
+     }
+     for(j=0x0A;i<=15;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->CCRT1CRTC[i]);
      }
-   }
-   
-   SiS_HandleCRT1(SiS_Pr);
 
-   SiS_StrangeStuff(SiS_Pr, HwDeviceExtension);
-   
-   SiS_DisplayOn(SiS_Pr);
-   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
+     temp = SiS_Pr->CCRT1CRTC[16] & 0xE0;
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp);
 
-   if(HwDeviceExtension->jChipType >= SIS_315H) {
-      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-         if(!(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr))) {
-	     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
-	 }
-      }
-   }
+     temp = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5;
+     if(modeflag & DoubleScanMode) temp |= 0x80;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,temp);
 
-   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-      if(HwDeviceExtension->jChipType >= SIS_315H) {
-	 if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
-	     SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
-	 } else {
-	     SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE);
-	 }
+  } else {
 
-	 SiS_SetReg1(SiS_Pr->SiS_P3d4,0x38,backupreg);
+     if(ModeNo <= 0x13) {
+        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     } else {
+        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     }
 
-	 tempr1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
-	 tempr2 = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x00);
-	 if(tempr1 & SetCRT2ToAVIDEO) tempr2 &= 0xF7;
-	 if(tempr1 & SetCRT2ToSVIDEO) tempr2 &= 0xFB;
-	 SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,tempr2);
+     if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
 
-	 if((IS_SIS650) && (SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30) & 0xfc)) {
-	    if((ModeNo == 0x03) || (ModeNo == 0x10)) {
-	        SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x80);
-	        SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x56,0x08);
-            }
-	 }
+#ifdef SIS315H
 
-	 if(tempr1 & SetCRT2ToLCD) {
-	       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc);
-	 }
-      } else if((HwDeviceExtension->jChipType == SIS_630) ||
-                (HwDeviceExtension->jChipType == SIS_730)) {
-         SiS_SetReg1(SiS_Pr->SiS_P3d4,0x35,backupreg);
-      }
-   }
+        SiS_GetLCDACRT1Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, &ResIndex, &DisplayType);
 
-#ifdef LINUX_XF86
-   if(pScrn) {
-      /* SetPitch: Adapt to virtual size & position */
-      if((ModeNo > 0x13) && (dosetpitch)) {
-         SiS_SetPitch(SiS_Pr, pScrn, BaseAddr);
-      }
+        switch(DisplayType) {
+        case Panel_1024x768      : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1;     break;
+        case Panel_1280x1024     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_1;    break;
+        case Panel_1400x1050     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_1;    break;
+        case Panel_1600x1200     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_1;    break;
+        case Panel_1024x768  + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1_H;   break;
+        case Panel_1280x1024 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_1_H;  break;
+        case Panel_1400x1050 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_1_H;  break;
+        case Panel_1600x1200 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_1_H;  break;
+        case Panel_1024x768  + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_2;     break;
+        case Panel_1280x1024 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2;    break;
+        case Panel_1400x1050 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_2;    break;
+        case Panel_1600x1200 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_2;    break;
+        case Panel_1024x768  + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_2_H;   break;
+        case Panel_1280x1024 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2_H;  break;
+        case Panel_1400x1050 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_2_H;  break;
+        case Panel_1600x1200 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_2_H;  break;
+        case 100:	  	   LCDACRT1Ptr = Compaq1280x1024_LCDACRT1_1;         break;
+        case 101:		   LCDACRT1Ptr = Compaq1280x1024_LCDACRT1_1_H;       break;
+        case 102:		   LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2;    break;
+        case 103:		   LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2_H;  break;
+        case 104:		   LCDACRT1Ptr = Clevo1024x768_LCDACRT1_1;           break;
+        case 105:		   LCDACRT1Ptr = Clevo1024x768_LCDACRT1_1_H;         break;
+        case 106:		   LCDACRT1Ptr = Clevo1024x768_LCDACRT1_2;           break;
+        case 107:		   LCDACRT1Ptr = Clevo1024x768_LCDACRT1_2_H;         break;
+        default:                   LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1;     break;
+        }
 
-      /* Backup/Set ModeNo in BIOS scratch area */
-      SiS_GetSetModeID(pScrn, ModeNo);
-   }
-#endif
+        for(i=0, j=0; i<=0x07; i++, j++) {
+           SiS_SetReg(SiS_Pr->SiS_P3d4,i,(LCDACRT1Ptr+ResIndex)->CR[j]);
+        }
+        for(i=0x10, j=8; i<=0x12; i++, j++) {
+           SiS_SetReg(SiS_Pr->SiS_P3d4,i,(LCDACRT1Ptr+ResIndex)->CR[j]);
+        }
+        for(i=0x15, j=11; i<=0x16; i++, j++) {
+           SiS_SetReg(SiS_Pr->SiS_P3d4,i,(LCDACRT1Ptr+ResIndex)->CR[j]);
+        }
+        for(i=0x0A, j=13; i<=0x0C; i++, j++) {
+           SiS_SetReg(SiS_Pr->SiS_P3c4,i,(LCDACRT1Ptr+ResIndex)->CR[j]);
+        }
+
+        temp = (LCDACRT1Ptr+ResIndex)->CR[16] & 0xE0;
+        SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp);
+
+        temp = ((LCDACRT1Ptr+ResIndex)->CR[16] & 0x01) << 5;
+        if(modeflag & DoubleScanMode) temp |= 0x80;
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,temp);
 
-#ifndef LINUX_XF86  /* We never lock registers in XF86 */
-   if(KeepLockReg == 0xA1) SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
-   else SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x00);
 #endif
 
-   return TRUE;
-}
+     } else {
 
-void
-SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable)
-{
-   SiS_Pr->SiS_IF_DEF_DSTN = enable ? 1 : 0;
+        index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+
+        for(i=0,j=0;i<=07;i++,j++) {
+          SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
+        }
+        for(j=0x10;i<=10;i++,j++) {
+          SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
+        }
+        for(j=0x15;i<=12;i++,j++) {
+          SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
+        }
+        for(j=0x0A;i<=15;i++,j++) {
+          SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
+        }
+
+        temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
+        SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp);
+
+        temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
+        if(modeflag & DoubleScanMode)  temp |= 0x80;
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,temp);
+
+     }
+  }
+
+  if(SiS_Pr->SiS_ModeType > ModeVGA) SiS_SetReg(SiS_Pr->SiS_P3d4,0x14,0x4F);
 }
 
-void
-SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable)
+/*********************************************/
+/*               OFFSET & PITCH              */
+/*********************************************/
+/*  (partly overruled by SetPitch() in XF86) */
+/*********************************************/
+
+static void
+SiS_SetCRT1Offset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                  USHORT RefreshRateTableIndex,
+		  PSIS_HW_INFO HwInfo)
 {
-   SiS_Pr->SiS_IF_DEF_FSTN = enable ? 1 : 0;
+   USHORT temp, DisplayUnit, infoflag;
+
+   if(SiS_Pr->UseCustomMode) {
+      infoflag = SiS_Pr->CInfoFlag;
+   } else {
+      infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+   }
+
+   DisplayUnit = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex,
+                     	       RefreshRateTableIndex,HwInfo);
+
+   temp = (DisplayUnit >> 8) & 0x0f;
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,temp);
+
+   temp = DisplayUnit & 0xFF;
+   SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,temp);
+
+   if(infoflag & InterlaceMode) DisplayUnit >>= 1;
+
+   DisplayUnit <<= 5;
+   temp = (DisplayUnit & 0xff00) >> 8;
+   if (DisplayUnit & 0xff) temp++;
+   temp++;
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x10,temp);
 }
 
-void
-SiS_HandleCRT1(SiS_Private *SiS_Pr)
-{
-  /* TW: We don't do this at all. There is a new
-   * CRT1-is-connected-at-boot-time logic in the 650 BIOS, which
-   * confuses our own. So just clear the bit and skip the rest.
-   */
+/*********************************************/
+/*                  VCLK                     */
+/*********************************************/
 
-  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x63,0xbf);
+static void
+SiS_SetCRT1VCLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex)
+{
+  USHORT  index=0, clka, clkb;
 
-#if 0
-  if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15) & 0x01)) {
-     if((SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15) & 0x0a) ||
-        (SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16) & 0x01)) {
-        SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x63,0x40);
+  if(SiS_Pr->UseCustomMode) {
+     clka = SiS_Pr->CSR2B;
+     clkb = SiS_Pr->CSR2C;
+  } else {
+     index = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+     if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+        clka = SiS_Pr->SiS_VBVCLKData[index].Part4_A;
+	clkb = SiS_Pr->SiS_VBVCLKData[index].Part4_B;
+     } else {
+        clka = SiS_Pr->SiS_VCLKData[index].SR2B;
+	clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
      }
   }
-#endif
-}
 
-void
-SiS_GetSysFlags(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-   unsigned char cr5f, temp1, temp2;
+  if(HwInfo->jChipType >= SIS_315H) {
+     SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF);
+  } else {
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x00);
+  }
 
-   /* You should use the macros, not these flags directly */
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,clka);
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,clkb);
 
-   SiS_Pr->SiS_SysFlags = 0;
-   if(HwDeviceExtension->jChipType == SIS_650) {
-      cr5f = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5f) & 0xf0;
-      SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x5c,0x07);
-      temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
-      SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x5c,0xf8);
-      temp2 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
-      if((!temp1) || (temp2)) {
-         switch(cr5f) {
-	    case 0x80:
-	    case 0x90:
-	    case 0xc0:
-	       SiS_Pr->SiS_SysFlags |= SF_IsM650;  break;
-	    case 0xa0:
-	    case 0xb0:
-	    case 0xe0:
-	       SiS_Pr->SiS_SysFlags |= SF_Is651;   break;
-	 }
-      } else {
-         switch(cr5f) {
-	    case 0x90:
-	       temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
-	       switch(temp1) {
-	          case 0x00: SiS_Pr->SiS_SysFlags |= SF_IsM652; break;
-		  case 0x40: SiS_Pr->SiS_SysFlags |= SF_IsM653; break;
-		  default:   SiS_Pr->SiS_SysFlags |= SF_IsM650; break;
-	       }
-	       break;
-	    case 0xb0:
-	       SiS_Pr->SiS_SysFlags |= SF_Is652;  break;
-	    default:
-	       SiS_Pr->SiS_SysFlags |= SF_IsM650; break;
-	 }
-      }
-   }
-}
-
-void
-SiS_StrangeStuff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-   if((IS_SIS651) || (IS_SISM650)) {
-      SiS_SetReg1(SiS_Pr->SiS_VidCapt, 0x3f, 0x00);   /* Fiddle with capture regs */
-      SiS_SetReg1(SiS_Pr->SiS_VidCapt, 0x00, 0x00);
-      SiS_SetReg1(SiS_Pr->SiS_VidPlay, 0x00, 0x86);   /* (BIOS does NOT unlock) */
-      SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x30, 0xfe); /* Fiddle with video regs */
-      SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x3f, 0xef);
-   }
-   /* !!! This does not support modes < 0x13 !!! */
-}
-
-void
-SiS_SetCRT1Group(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                 USHORT ModeNo,USHORT ModeIdIndex,USHORT BaseAddr)
-{
-  USHORT  StandTableIndex,RefreshRateTableIndex;
-
-  SiS_Pr->SiS_CRT1Mode = ModeNo;
-  StandTableIndex = SiS_GetModePtr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
-  if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
-    if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2)) {
-       SiS_DisableBridge(SiS_Pr,HwDeviceExtension,BaseAddr);
-    }
-  }
-
-  /* 550, 651 */
-  SiS_WhatTheHellIsThis(SiS_Pr,HwDeviceExtension,BaseAddr);
-
-  SiS_SetSeqRegs(SiS_Pr,ROMAddr,StandTableIndex);
-  SiS_SetMiscRegs(SiS_Pr,ROMAddr,StandTableIndex);
-  SiS_SetCRTCRegs(SiS_Pr,ROMAddr,HwDeviceExtension,StandTableIndex);
-  SiS_SetATTRegs(SiS_Pr,ROMAddr,StandTableIndex,HwDeviceExtension);
-  SiS_SetGRCRegs(SiS_Pr,ROMAddr,StandTableIndex);
-  SiS_ClearExt1Regs(SiS_Pr,HwDeviceExtension);
-  SiS_ResetCRT1VCLK(SiS_Pr,ROMAddr,HwDeviceExtension);
-
-  SiS_Pr->SiS_SelectCRT2Rate = 0;
-  SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
-
-#ifdef LINUX_XF86
-  xf86DrvMsgVerb(0, X_PROBED, 3, "(init: VBType=0x%04x, VBInfo=0x%04x)\n",
-                    SiS_Pr->SiS_VBType, SiS_Pr->SiS_VBInfo);
-#endif
-
-  if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) {
-     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
-        SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
-     }
-  }
-
-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
-	SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
-  }
-
-  RefreshRateTableIndex = SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
-
-  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
-	SiS_Pr->SiS_SetFlag &= ~ProgrammingCRT2;
+  if(HwInfo->jChipType >= SIS_315H) {
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x01);
+  } else {
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80);
   }
+}
 
-  if(RefreshRateTableIndex != 0xFFFF) {
-    	SiS_SetSync(SiS_Pr,ROMAddr,RefreshRateTableIndex);
-    	SiS_SetCRT1CRTC(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwDeviceExtension);
-    	SiS_SetCRT1Offset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwDeviceExtension);
-    	SiS_SetCRT1VCLK(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,RefreshRateTableIndex);
-  }
+/*********************************************/
+/*                  FIFO                     */
+/*********************************************/
 
 #ifdef SIS300
-  if(HwDeviceExtension->jChipType == SIS_300) {
-     	SiS_SetCRT1FIFO_300(SiS_Pr,ROMAddr,ModeNo,HwDeviceExtension,RefreshRateTableIndex);
-  }
-  if((HwDeviceExtension->jChipType == SIS_630) ||
-     (HwDeviceExtension->jChipType == SIS_730) ||
-     (HwDeviceExtension->jChipType == SIS_540)) {
-     	SiS_SetCRT1FIFO_630(SiS_Pr,ROMAddr,ModeNo,HwDeviceExtension,RefreshRateTableIndex);
-  }
-#endif
-#ifdef SIS315H
-  if(HwDeviceExtension->jChipType >= SIS_315H) {
-     	SiS_SetCRT1FIFO_310(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
-  }
-#endif
+static USHORT
+SiS_DoCalcDelay(SiS_Private *SiS_Pr, USHORT MCLK, USHORT VCLK, USHORT colordepth, USHORT key)
+{
+  const UCHAR ThLowA[]   = { 61, 3,52, 5,68, 7,100,11,
+                             43, 3,42, 5,54, 7, 78,11,
+                             34, 3,37, 5,47, 7, 67,11 };
 
-  SiS_SetCRT1ModeRegs(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,RefreshRateTableIndex);
+  const UCHAR ThLowB[]   = { 81, 4,72, 6,88, 8,120,12,
+                             55, 4,54, 6,66, 8, 90,12,
+                             42, 4,45, 6,55, 8, 75,12 };
 
-  SiS_LoadDAC(SiS_Pr,HwDeviceExtension,ROMAddr,ModeNo,ModeIdIndex);
+  const UCHAR ThTiming[] = {  1, 2, 2, 3, 0, 1,  1, 2 };
 
-#ifndef LINUX_XF86
-  if(SiS_Pr->SiS_flag_clearbuffer) {
-        SiS_ClearBuffer(SiS_Pr,HwDeviceExtension,ModeNo);
-  }
-#endif
+  USHORT tempah, tempal, tempcl, tempbx, temp;
+  ULONG  longtemp;
 
-  if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2 | SetCRT2ToLCDA))) {
-        SiS_LongWait(SiS_Pr);
-        SiS_DisplayOn(SiS_Pr);
+  tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18);
+  tempah &= 0x62;
+  tempah >>= 1;
+  tempal = tempah;
+  tempah >>= 3;
+  tempal |= tempah;
+  tempal &= 0x07;
+  tempcl = ThTiming[tempal];
+  tempbx = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16);
+  tempbx >>= 6;
+  tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
+  tempah >>= 4;
+  tempah &= 0x0c;
+  tempbx |= tempah;
+  tempbx <<= 1;
+  if(key == 0) {
+     tempal = ThLowA[tempbx + 1];
+     tempal *= tempcl;
+     tempal += ThLowA[tempbx];
+  } else {
+     tempal = ThLowB[tempbx + 1];
+     tempal *= tempcl;
+     tempal += ThLowB[tempbx];
   }
+  longtemp = tempal * VCLK * colordepth;
+  temp = longtemp % (MCLK * 16);
+  longtemp /= (MCLK * 16);
+  if(temp) longtemp++;
+  return((USHORT)longtemp);
 }
 
-#ifdef LINUX_XF86
-void
-SiS_SetPitch(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr)
+static USHORT
+SiS_CalcDelay(SiS_Private *SiS_Pr, USHORT VCLK, USHORT colordepth, USHORT MCLK)
 {
-   SISPtr pSiS = SISPTR(pScrn);
-   BOOLEAN isslavemode = FALSE;
-
-   if( (pSiS->VBFlags & VB_VIDEOBRIDGE) &&
-       ( ((pSiS->VGAEngine == SIS_300_VGA) && (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) ||
-         ((pSiS->VGAEngine == SIS_315_VGA) && (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) {
-      isslavemode = TRUE;
-   }
+  USHORT tempax, tempbx;
 
-   /* We need to set pitch for CRT1 if bridge is in slave mode, too */
-   if( (pSiS->VBFlags & DISPTYPE_DISP1) || (isslavemode) ) {
-   	SiS_SetPitchCRT1(SiS_Pr, pScrn, BaseAddr);
-   }
-   /* We must not set the pitch for CRT2 if bridge is in slave mode */
-   if( (pSiS->VBFlags & DISPTYPE_DISP2) && (!isslavemode) ) {
-   	SiS_SetPitchCRT2(SiS_Pr, pScrn, BaseAddr);
-   }
+  tempbx = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 0);
+  tempax = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 1);
+  if(tempax < 4) tempax = 4;
+  tempax -= 4;
+  if(tempbx < tempax) tempbx = tempax;
+  return(tempbx);
 }
 
-void
-SiS_SetPitchCRT1(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr)
+static void
+SiS_SetCRT1FIFO_300(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo,
+                    USHORT RefreshRateTableIndex)
 {
-    SISPtr pSiS = SISPTR(pScrn);
-    ULong  HDisplay,temp;
-
-    HDisplay = pSiS->scrnPitch / 8;
-    SiS_SetReg1(SiS_Pr->SiS_P3d4, 0x13, (HDisplay & 0xFF));
-    temp = (SiS_GetReg1(SiS_Pr->SiS_P3c4, 0x0E) & 0xF0) | (HDisplay>>8);
-    SiS_SetReg1(SiS_Pr->SiS_P3c4, 0x0E, temp);
-}
+  USHORT  ThresholdLow = 0;
+  USHORT  index, VCLK, MCLK, colorth=0;
+  USHORT  tempah, temp;
 
-void
-SiS_SetPitchCRT2(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr)
-{
-    SISPtr pSiS = SISPTR(pScrn);
-    ULong  HDisplay,temp;
+  if(ModeNo > 0x13) {
 
-    HDisplay = pSiS->scrnPitch2 / 8;
+     if(SiS_Pr->UseCustomMode) {
+        VCLK = SiS_Pr->CSRClock;
+     } else {
+        index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+        index &= 0x3F;
+        VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;             /* Get VCLK  */
+     }
 
-    /* Unlock CRT2 */
-    if (pSiS->VGAEngine == SIS_315_VGA)
-        SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2F, 0x01);
-    else
-        SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24, 0x01);
+     switch (SiS_Pr->SiS_ModeType - ModeEGA) {     /* Get half colordepth */
+        case 0 : colorth = 1; break;
+        case 1 : colorth = 1; break;
+        case 2 : colorth = 2; break;
+        case 3 : colorth = 2; break;
+        case 4 : colorth = 3; break;
+        case 5 : colorth = 4; break;
+     }
 
-    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07, (HDisplay & 0xFF));
-    temp = (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x09) & 0xF0) | ((HDisplay >> 8) & 0xFF);
-    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x09, temp);
-}
-#endif
+     index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3A);
+     index &= 0x07;
+     MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;           /* Get MCLK  */
 
-void
-SiS_GetVBType(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-  USHORT flag=0, rev=0, nolcd=0;
+     tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+     tempah &= 0xc3;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3c,tempah);
 
-  SiS_Pr->SiS_VBType = 0;
+     do {
+        ThresholdLow = SiS_CalcDelay(SiS_Pr, VCLK, colorth, MCLK);
+        ThresholdLow++;
+        if(ThresholdLow < 0x13) break;
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x16,0xfc);
+        ThresholdLow = 0x13;
+        tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16);
+        tempah >>= 6;
+        if(!(tempah)) break;
+        tempah--;
+        tempah <<= 6;
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3f,tempah);
+     } while(0);
 
-  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) return;
+  } else ThresholdLow = 2;
 
-  flag = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x00);
+  /* Write CRT/CPU threshold low, CRT/Engine threshold high */
+  temp = (ThresholdLow << 4) | 0x0f;
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,temp);
 
-  if(flag > 3) return;
+  temp = (ThresholdLow & 0x10) << 1;
+  if(ModeNo > 0x13) temp |= 0x40;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0f,0x9f,temp);
 
-  rev = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x01);
+  /* What is this? */
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09);
 
-  if(flag >= 2) {
-        SiS_Pr->SiS_VBType = VB_SIS302B;
-  } else if(flag == 1) {
-        SiS_Pr->SiS_VBType = VB_SIS301;
-	if(rev >= 0xC0) {
-            	SiS_Pr->SiS_VBType = VB_SIS301C;
-        } else if(rev >= 0xB0) {
-            	SiS_Pr->SiS_VBType = VB_SIS301B;
-		/* Check if 30xB DH version (no LCD support, use Panel Link instead) */
-    		nolcd = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x23);
-                if(!(nolcd & 0x02)) SiS_Pr->SiS_VBType |= VB_NoLCD;
-        }
-  }
-  if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS301C | VB_SIS302B)) {
-        if(rev >= 0xD0) {
-	        SiS_Pr->SiS_VBType &= ~(VB_SIS301B | VB_SIS301C | VB_SIS302B);
-          	SiS_Pr->SiS_VBType |= VB_SIS301LV;
-		SiS_Pr->SiS_VBType &= ~(VB_NoLCD);
-		if(rev >= 0xE0) {
-		    SiS_Pr->SiS_VBType &= ~(VB_SIS301LV);
-		    SiS_Pr->SiS_VBType |= VB_SIS302LV;
-		}
-        }
-  }
+  /* Write CRT/CPU threshold high */
+  temp = ThresholdLow + 3;
+  if(temp > 0x0f) temp = 0x0f;
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x09,temp);
 }
 
-BOOLEAN
-SiS_SearchModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT *ModeNo,USHORT *ModeIdIndex)
+static USHORT
+SiS_CalcDelay2(SiS_Private *SiS_Pr, UCHAR key, PSIS_HW_INFO HwInfo)
 {
-   UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO;
-
-   if(*ModeNo <= 0x13) {
-
-      if((*ModeNo) <= 0x05) (*ModeNo) |= 0x01;
+  USHORT data,index;
+  const UCHAR  LatencyFactor[] = {
+   	97, 88, 86, 79, 77, 00,       /*; 64  bit    BQ=2   */
+        00, 87, 85, 78, 76, 54,       /*; 64  bit    BQ=1   */
+        97, 88, 86, 79, 77, 00,       /*; 128 bit    BQ=2   */
+        00, 79, 77, 70, 68, 48,       /*; 128 bit    BQ=1   */
+        80, 72, 69, 63, 61, 00,       /*; 64  bit    BQ=2   */
+        00, 70, 68, 61, 59, 37,       /*; 64  bit    BQ=1   */
+        86, 77, 75, 68, 66, 00,       /*; 128 bit    BQ=2   */
+        00, 68, 66, 59, 57, 37        /*; 128 bit    BQ=1   */
+  };
+  const UCHAR  LatencyFactor730[] = {
+         69, 63, 61,
+	 86, 79, 77,
+	103, 96, 94,
+	120,113,111,
+	137,130,128,    /* --- Table ends with this entry, data below */
+	137,130,128,	/* to avoid using illegal values              */
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+  };
 
-      for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
-         if(SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == (*ModeNo)) break;
-         if(SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == 0xFF)   return FALSE;
-      }
+  if(HwInfo->jChipType == SIS_730) {
+     index = ((key & 0x0f) * 3) + ((key & 0xC0) >> 6);
+     data = LatencyFactor730[index];
+  } else {
+     index = (key & 0xE0) >> 5;
+     if(key & 0x10) index +=6;
+     if(!(key & 0x01)) index += 24;
+     data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
+     if(data & 0x0080) index += 12;
+     data = LatencyFactor[index];
+  }
+  return(data);
+}
 
-      if(*ModeNo == 0x07) {
-          if(VGAINFO & 0x10) (*ModeIdIndex)++;   /* 400 lines */
-          /* else 350 lines */
-      }
-      if(*ModeNo <= 0x03) {
-         if(!(VGAINFO & 0x80)) (*ModeIdIndex)++;
-         if(VGAINFO & 0x10)    (*ModeIdIndex)++; /* 400 lines  */
-         /* else 350 lines  */
-      }
-      /* else 200 lines  */
+static void
+SiS_SetCRT1FIFO_630(SiS_Private *SiS_Pr, USHORT ModeNo,
+ 		    PSIS_HW_INFO HwInfo,
+                    USHORT RefreshRateTableIndex)
+{
+  USHORT  i,index,data,VCLK,MCLK,colorth=0;
+  ULONG   B,eax,bl,data2;
+  USHORT  ThresholdLow=0;
+  UCHAR   FQBQData[]= {
+  	0x01,0x21,0x41,0x61,0x81,
+        0x31,0x51,0x71,0x91,0xb1,
+        0x00,0x20,0x40,0x60,0x80,
+        0x30,0x50,0x70,0x90,0xb0,
+	0xFF
+  };
+  UCHAR   FQBQData730[]= {
+        0x34,0x74,0xb4,
+	0x23,0x63,0xa3,
+	0x12,0x52,0x92,
+	0x01,0x41,0x81,
+	0x00,0x40,0x80,
+	0xff
+  };
 
-   } else {
+  i=0;
+  if(ModeNo > 0x13) {
+    if(SiS_Pr->UseCustomMode) {
+       VCLK = SiS_Pr->CSRClock;
+    } else {
+       index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+       index &= 0x3F;
+       VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;          /* Get VCLK  */
+    }       
 
-      for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
-         if(SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) break;
-         if(SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)      return FALSE;
-      }
+    index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1A);
+    index &= 0x07;
+    MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;           /* Get MCLK  */
 
-   }
-   return TRUE;
-}
+    data2 = SiS_Pr->SiS_ModeType - ModeEGA;	  /* Get half colordepth */
+    switch (data2) {
+        case 0 : colorth = 1; break;
+        case 1 : colorth = 1; break;
+        case 2 : colorth = 2; break;
+        case 3 : colorth = 2; break;
+        case 4 : colorth = 3; break;
+        case 5 : colorth = 4; break;
+    }
 
-BOOLEAN
-SiS_SearchVBModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo)
-{
-   USHORT ModeIdIndex;
-   UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO;
+    if(HwInfo->jChipType == SIS_730) {
 
-   if(*ModeNo <= 5) *ModeNo |= 1;
+       do {
+          B = SiS_CalcDelay2(SiS_Pr, FQBQData730[i], HwInfo) * VCLK * colorth;
+	  bl = B / (MCLK * 16);
 
-   for(ModeIdIndex=0; ; ModeIdIndex++) {
-        if(SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].ModeID == *ModeNo) break;
-        if(SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].ModeID == 0xFF)    return FALSE;
-   }
+          if(B == bl * 16 * MCLK) {
+             bl = bl + 1;
+          } else {
+             bl = bl + 2;
+          }
 
-   if(*ModeNo != 0x07) {
-        if(*ModeNo > 0x03) return ((BOOLEAN)ModeIdIndex);
-	if(VGAINFO & 0x80) return ((BOOLEAN)ModeIdIndex);
-	ModeIdIndex++;
-   }
-   if(VGAINFO & 0x10) ModeIdIndex++;   /* 400 lines */
-	                               /* else 350 lines */
-   return ((BOOLEAN)ModeIdIndex);
-}
+          if(bl > 0x13) {
+             if(FQBQData730[i+1] == 0xFF) {
+                ThresholdLow = 0x13;
+                break;
+             }
+             i++;
+          } else {
+             ThresholdLow = bl;
+             break;
+          }
+       } while(FQBQData730[i] != 0xFF);
+       
+    } else {
+    
+       do {
+          B = SiS_CalcDelay2(SiS_Pr, FQBQData[i], HwInfo) * VCLK * colorth;
+          bl = B / (MCLK * 16);
 
-#ifndef LINUX_XF86
-BOOLEAN
-SiS_CheckMemorySize(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                    USHORT ModeNo,USHORT ModeIdIndex)
-{
-  USHORT memorysize,modeflag;
-  ULONG  temp;
+          if(B == bl * 16 * MCLK) {
+             bl = bl + 1;
+          } else {
+             bl = bl + 2;
+          }
 
-  if(SiS_Pr->UseCustomMode) {
-     modeflag = SiS_Pr->CModeFlag;
-  } else {
-     if(ModeNo <= 0x13) {
-        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-     } else {
-        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-     }
+          if(bl > 0x13) {
+             if(FQBQData[i+1] == 0xFF) {
+                ThresholdLow = 0x13;
+                break;
+             }
+             i++;
+          } else {
+             ThresholdLow = bl;
+             break;
+          }
+       } while(FQBQData[i] != 0xFF);
+    }
+  }
+  else {
+    if(HwInfo->jChipType == SIS_730) {
+    } else {
+      i = 9;
+    }
+    ThresholdLow = 0x02;
   }
 
-  memorysize = modeflag & MemoryInfoFlag;
-  memorysize >>= MemorySizeShift;			/* Get required memory size */
-  memorysize++;
-
-  temp = GetDRAMSize(SiS_Pr, HwDeviceExtension);       	/* Get adapter memory size */
-  temp /= (1024*1024);   				/* (in MB) */
+  /* Write foreground and background queue */
+  if(HwInfo->jChipType == SIS_730) {
+   
+     data2 = FQBQData730[i];
+     data2 = (data2 & 0xC0) >> 5;
+     data2 <<= 8;
 
-  if(temp < memorysize) return(FALSE);
-  else return(TRUE);
-}
+#ifndef LINUX_XF86
+     SiS_SetRegLong(0xcf8,0x80000050);
+     eax = SiS_GetRegLong(0xcfc);
+     eax &= 0xfffff9ff;
+     eax |= data2;
+     SiS_SetRegLong(0xcfc,eax);
+#else
+     /* We use pci functions X offers. We use pcitag 0, because
+      * we want to read/write to the host bridge (which is always
+      * 00:00.0 on 630, 730 and 540), not the VGA device.
+      */
+     eax = pciReadLong(0x00000000, 0x50);
+     eax &= 0xfffff9ff;
+     eax |= data2;
+     pciWriteLong(0x00000000, 0x50, eax);
 #endif
 
-UCHAR
-SiS_GetModePtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
-{
-   UCHAR index;
-
-   if(ModeNo <= 0x13) {
-     	index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_StTableIndex;
-   } else {
-     	if(SiS_Pr->SiS_ModeType <= 0x02) index = 0x1B;    /* 02 -> ModeEGA  */
-     	else index = 0x0F;
-   }
-   return index;
-}
-
-static void
-SiS_WhatIsThis1a(SiS_Private *SiS_Pr, USHORT somevalue)
-{
-   USHORT temp, tempbl, tempbh;
-
-   tempbl = tempbh = somevalue;
-   temp = SiS_GetReg2(SiS_Pr->SiS_P3cb);
-   temp &= 0xf0;
-   tempbl >>= 4;
-   temp |= tempbl;
-   SiS_SetReg3(SiS_Pr->SiS_P3cb, temp);
-   temp = SiS_GetReg2(SiS_Pr->SiS_P3cd);
-   temp &= 0xf0;
-   tempbh &= 0x0f;
-   temp |= tempbh;
-   SiS_SetReg3(SiS_Pr->SiS_P3cd, temp);
-}
-
-static void
-SiS_WhatIsThis1b(SiS_Private *SiS_Pr, USHORT somevalue)
-{
-   USHORT temp, tempbl, tempbh;
-
-   tempbl = tempbh = somevalue;
-   temp = SiS_GetReg2(SiS_Pr->SiS_P3cb);
-   temp &= 0x0f;
-   tempbl &= 0xf0;
-   temp |= tempbl;
-   SiS_SetReg3(SiS_Pr->SiS_P3cb, temp);
-   temp = SiS_GetReg2(SiS_Pr->SiS_P3cd);
-   temp &= 0x0f;
-   tempbh <<= 4;
-   temp |= tempbh;
-   SiS_SetReg3(SiS_Pr->SiS_P3cd, temp);
-}
-
-static void
-SiS_WhatIsThis2b(SiS_Private *SiS_Pr, USHORT somevalue)
-{
-   SiS_WhatIsThis1a(SiS_Pr, somevalue);
-   SiS_WhatIsThis1b(SiS_Pr, somevalue);
-}
-
-static void
-SiS_WhatIsThis1(SiS_Private *SiS_Pr)
-{
-   SiS_WhatIsThis2b(SiS_Pr, 0);
-}
-
-static void
-SiS_WhatIsThis2a(SiS_Private *SiS_Pr, USHORT somevalue)
-{
-   USHORT temp = somevalue >> 8;
-
-   temp &= 0x07;
-   temp |= (temp << 4);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1d,temp);
-   SiS_WhatIsThis2b(SiS_Pr, somevalue);
-}
-
-static void
-SiS_WhatIsThis2(SiS_Private *SiS_Pr)
-{
-   SiS_WhatIsThis2a(SiS_Pr, 0);
-}
-
-void
-SiS_WhatTheHellIsThis(SiS_Private *SiS_Pr,PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
-{
-   if(IS_SIS65x) {
-      SiS_WhatIsThis1(SiS_Pr);
-      SiS_WhatIsThis2(SiS_Pr);
-   }
-}
+     /* Write GUI grant timer (PCI config 0xA3) */
+     data2 = FQBQData730[i] << 8;
+     data2 = (data2 & 0x0f00) | ((data2 & 0x3000) >> 8);
+     data2 <<= 20;
 
-void
-SiS_SetSeqRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex)
-{
-   UCHAR SRdata;
-   USHORT i;
+#ifndef LINUX_XF86
+     SiS_SetRegLong(0xcf8,0x800000A0);
+     eax = SiS_GetRegLong(0xcfc);
+     eax &= 0x00ffffff;
+     eax |= data2;
+     SiS_SetRegLong(0xcfc,eax);
+#else
+     eax = pciReadLong(0x00000000, 0xA0);
+     eax &= 0x00ffffff;
+     eax |= data2;
+     pciWriteLong(0x00000000, 0xA0, eax);
+#endif
 
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x00,0x03);           	/* Set SR0  */
+  } else {
 
-   SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0];
+     data2 = FQBQData[i];
+     data2 = (data2 & 0xf0) >> 4;
+     data2 <<= 24;
 
-   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
-         SRdata |= 0x01;
-      }
-      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-         if(SiS_Pr->SiS_VBType & VB_NoLCD) {
-	    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
-               SRdata |= 0x01;          		/* 8 dot clock  */
-            }
-	 }
-      }
-   }
-   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-     if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
-       if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-         if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
-           SRdata |= 0x01;        			/* 8 dot clock  */
-         }
-       }
-     }
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
-         SRdata |= 0x01;          			/* 8 dot clock  */
-       }
-     }
-   }
+#ifndef LINUX_XF86
+     SiS_SetRegLong(0xcf8,0x80000050);
+     eax = SiS_GetRegLong(0xcfc);
+     eax &= 0xf0ffffff;
+     eax |= data2;
+     SiS_SetRegLong(0xcfc,eax);
+#else
+     eax = pciReadLong(0x00000000, 0x50);
+     eax &= 0xf0ffffff;
+     eax |= data2;
+     pciWriteLong(0x00000000, 0x50, eax);
+#endif
 
-   SRdata |= 0x20;                			/* screen off  */
+     /* Write GUI grant timer (PCI config 0xA3) */
+     data2 = FQBQData[i];
+     data2 &= 0x0f;
+     data2 <<= 24;
 
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x01,SRdata);
+#ifndef LINUX_XF86
+     SiS_SetRegLong(0xcf8,0x800000A0);
+     eax = SiS_GetRegLong(0xcfc);
+     eax &= 0xf0ffffff;
+     eax |= data2;
+     SiS_SetRegLong(0xcfc,eax);
+#else
+     eax = pciReadLong(0x00000000, 0xA0);
+     eax &= 0xf0ffffff;
+     eax |= data2;
+     pciWriteLong(0x00000000, 0xA0, eax);
+#endif
 
-   for(i = 2; i <= 4; i++) {
-       	SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
-     	SiS_SetReg1(SiS_Pr->SiS_P3c4,i,SRdata);
-   }
-}
+  }
 
-void
-SiS_SetMiscRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex)
-{
-   UCHAR Miscdata;
+  /* Write CRT/CPU threshold low, CRT/Engine threshold high */
+  data = ((ThresholdLow & 0x0f) << 4) | 0x0f;
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,data);
 
-   Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC;
+  data = (ThresholdLow & 0x10) << 1;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xDF,data);
 
-   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
-        Miscdata |= 0x0C;
-      }
-   }
+  /* What is this? */
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09);
 
-   SiS_SetReg3(SiS_Pr->SiS_P3c2,Miscdata);
+  /* Write CRT/CPU threshold high (gap = 3) */
+  data = ThresholdLow + 3;
+  if(data > 0x0f) data = 0x0f;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data);
 }
+#endif
 
-void
-SiS_SetCRTCRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                USHORT StandTableIndex)
+#ifdef SIS315H
+static void
+SiS_SetCRT1FIFO_310(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                    PSIS_HW_INFO HwInfo)
 {
-  UCHAR CRTCdata;
-  USHORT i;
+  USHORT modeflag;
 
-  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);                       /* Unlock CRTC */
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE);  /* disable auto-threshold */
 
-  for(i = 0; i <= 0x18; i++) {
-     CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
-     SiS_SetReg1(SiS_Pr->SiS_P3d4,i,CRTCdata);                     /* Set CRTC(3d4) */
-  }
-  if( ( (HwDeviceExtension->jChipType == SIS_630) ||
-        (HwDeviceExtension->jChipType == SIS_730) )  &&
-      (HwDeviceExtension->jChipRevision >= 0x30) ) {       	   /* for 630S0 */
-    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
-      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) {
-         SiS_SetReg1(SiS_Pr->SiS_P3d4,0x18,0xFE);
-      }
-    }
+  if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
-}
-
-void
-SiS_SetATTRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex,
-               PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-   UCHAR ARdata;
-   USHORT i;
 
-   for(i = 0; i <= 0x13; i++) {
-    ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
-#if 0
-    if((i <= 0x0f) || (i == 0x11)) {
-        if(ds:489 & 0x08) {
-	   continue;
-        }
-    }
-#endif
-    if(i == 0x13) {
-      /* Pixel shift. If screen on LCD or TV is shifted left or right, 
-       * this might be the cause. 
-       */
-      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)  ARdata=0;
-      }
-      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-         if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
-            if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-               if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0;
-            }
-         }
-      }
-      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-         if(HwDeviceExtension->jChipType >= SIS_315H) {
-	    if(IS_SIS550650740660) {
-	       /* 315, 330 don't do this */
-	       if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
-	          if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0;
-	       } else {
-	          ARdata = 0;
-	       }
-	    }
-	 } else {
-           if(SiS_Pr->SiS_VBInfo & SetInSlaveMode)  ARdata=0;
+  if(HwInfo->jChipType >= SIS_661) {
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE);
+     SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
+     if(ModeNo > 0x13) {
+        if(!(modeflag & HalfDCLK)) {
+	   SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34);
+	   if(ModeNo != 0x38) {
+	      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
+	   }
 	}
-      }
-    }
-    SiS_GetReg2(SiS_Pr->SiS_P3da);                              /* reset 3da  */
-    SiS_SetReg3(SiS_Pr->SiS_P3c0,i);                            /* set index  */
-    SiS_SetReg3(SiS_Pr->SiS_P3c0,ARdata);                       /* set data   */
-   }
-   SiS_GetReg2(SiS_Pr->SiS_P3da);                               /* reset 3da  */
-   SiS_SetReg3(SiS_Pr->SiS_P3c0,0x14);                          /* set index  */
-   SiS_SetReg3(SiS_Pr->SiS_P3c0,0x00);                          /* set data   */
-
-   SiS_GetReg2(SiS_Pr->SiS_P3da);
-   SiS_SetReg3(SiS_Pr->SiS_P3c0,0x20);				/* Enable Attribute  */
-   SiS_GetReg2(SiS_Pr->SiS_P3da);
+     }
+  } else {
+     if(ModeNo > 0x13) {
+        if( (!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
+           SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34);
+           SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
+           SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
+        } else {
+           SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE);
+           SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
+        }
+     } else {
+        SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE);
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
+     }
+  }
 }
+#endif
 
-void
-SiS_SetGRCRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex)
+/*********************************************/
+/*              MODE REGISTERS               */
+/*********************************************/
+
+static void
+SiS_SetVCLKState(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                 USHORT ModeNo, USHORT RefreshRateTableIndex,
+                 USHORT ModeIdIndex)
 {
-   UCHAR GRdata;
-   USHORT i;
+  USHORT data, data2=0;
+  USHORT VCLK, index=0;
 
-   for(i = 0; i <= 0x08; i++) {
-     GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
-     SiS_SetReg1(SiS_Pr->SiS_P3ce,i,GRdata);                    /* Set GR(3ce) */
-   }
+  if(ModeNo <= 0x13) VCLK = 0;
+  else {
+     if(SiS_Pr->UseCustomMode) {
+        VCLK = SiS_Pr->CSRClock;
+     } else {
+        index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex,
+	               RefreshRateTableIndex,HwInfo);
+        VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
+     }
+  }
 
-   if(SiS_Pr->SiS_ModeType > ModeVGA) {
-     SiS_SetRegAND(SiS_Pr->SiS_P3ce,0x05,0xBF);			/* 256 color disable */
-   }
-}
+  if(HwInfo->jChipType < SIS_315H) {		/* 300 series */
 
-void
-SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-  USHORT i;
+     data2 = 0x00;
+     if(VCLK > 150) data2 |= 0x80;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data2);
 
-  for(i = 0x0A; i <= 0x0E; i++) {
-      SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0x00);      /* Clear SR0A-SR0E */
-  }
+     data2 = 0x00;
+     if(VCLK >= 150) data2 |= 0x08;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data2);
 
-  /* TW: 330, 650/LVDS/301LV, 740/LVDS */
-  if(HwDeviceExtension->jChipType >= SIS_315H) {
-     SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x37,0xFE);
+  } else { 					/* 315 series */
+
+     data = 0;
+     if(VCLK >= 166) data |= 0x0c;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data);
+
+     if(VCLK >= 166) {
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1f,0xe7);
+     }
   }
-}
 
-void
-SiS_SetSync(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT RefreshRateTableIndex)
-{
-  USHORT sync;
-  USHORT temp;
+  data2 = 0x03;
+  if((VCLK >= 135) && (VCLK < 160))      data2 = 0x02;
+  else if((VCLK >= 160) && (VCLK < 260)) data2 = 0x01;
+  else if(VCLK >= 260)                   data2 = 0x00;
 
-  if(SiS_Pr->UseCustomMode) {
-     sync = SiS_Pr->CInfoFlag >> 8;
-  } else {
-     sync = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag >> 8;
-  }     
+  if(HwInfo->jChipType == SIS_540) {
+     if((VCLK == 203) || (VCLK < 234)) data2 = 0x02;
+  }
 
-  sync &= 0xC0;
-  temp = 0x2F | sync;
-  SiS_SetReg3(SiS_Pr->SiS_P3c2,temp);           /* Set Misc(3c2) */
+  if(HwInfo->jChipType < SIS_315H) {
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data2);  	/* DAC speed */
+  } else {
+     if(HwInfo->jChipType > SIS_315PRO) {
+        /* This "if" is done in 330 and 650/LVDS/301LV BIOSes; Not in 315 BIOS */
+        if(ModeNo > 0x13) data2 &= 0xfc;
+     }
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data2);  	/* DAC speed */
+  }
 }
 
-void
-SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                USHORT RefreshRateTableIndex,
-		PSIS_HW_DEVICE_INFO HwDeviceExtension)
+static void
+SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                    USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex)
 {
-  UCHAR  index;
-  USHORT tempah,i,modeflag,j;
+  USHORT data,data2;
+  USHORT infoflag=0,modeflag;
+  USHORT resindex,xres;
 #ifdef SIS315H
-  USHORT temp;
-  USHORT ResIndex,DisplayType;
-  const SiS_LCDACRT1DataStruct *LCDACRT1Ptr = NULL;
+  USHORT data3;
+  ULONG  longdata;
+#if 0
+  resinfo = 0;
+#endif
 #endif
-
-  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);		/*unlock cr0-7  */
 
   if(SiS_Pr->UseCustomMode) {
      modeflag = SiS_Pr->CModeFlag;
+     infoflag = SiS_Pr->CInfoFlag;
   } else {
-     if(ModeNo <= 0x13) {
-        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     if(ModeNo > 0x13) {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+#ifdef SIS315H
+#if 0
+	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+#endif
+#endif
      } else {
-        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
      }
-  }     
-
-  if((SiS_Pr->SiS_IF_DEF_LVDS == 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
-
-#ifdef SIS315H
+  }
 
-     /* LCDA */
+  /* Disable DPMS */
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1F,0x3F);
 
-     temp = SiS_GetLCDACRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
-                       RefreshRateTableIndex,&ResIndex,&DisplayType);
+  if(ModeNo > 0x13) data = infoflag;
+  else data = 0;
 
-     switch(DisplayType) {
-      case Panel_800x600       : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_1;      break;
-      case Panel_1024x768      : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1;     break;
-      case Panel_1280x1024     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_1;    break;
-      case Panel_1400x1050     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_1;    break;
-      case Panel_1600x1200     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_1;    break;
-      case Panel_800x600   + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_1_H;    break;
-      case Panel_1024x768  + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1_H;   break;
-      case Panel_1280x1024 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_1_H;  break;
-      case Panel_1400x1050 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_1_H;  break;
-      case Panel_1600x1200 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_1_H;  break;
-      case Panel_800x600   + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_2;      break;
-      case Panel_1024x768  + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_2;     break;
-      case Panel_1280x1024 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2;    break;
-      case Panel_1400x1050 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_2;    break;
-      case Panel_1600x1200 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_2;    break;
-      case Panel_800x600   + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_2_H;    break;
-      case Panel_1024x768  + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_2_H;   break;
-      case Panel_1280x1024 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2_H;  break;
-      case Panel_1400x1050 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_2_H;  break;
-      case Panel_1600x1200 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_2_H;  break;
-      default:                   LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1;     break;
-     }
-
-     tempah = (LCDACRT1Ptr+ResIndex)->CR[0];
-     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x00,tempah);
-     for(i=0x01,j=1;i<=0x07;i++,j++){
-       tempah = (LCDACRT1Ptr+ResIndex)->CR[j];
-       SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
-     }
-     for(i=0x10,j=8;i<=0x12;i++,j++){
-       tempah = (LCDACRT1Ptr+ResIndex)->CR[j];
-       SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
-     }
-     for(i=0x15,j=11;i<=0x16;i++,j++){
-       tempah =(LCDACRT1Ptr+ResIndex)->CR[j];
-       SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
-     }
-     for(i=0x0A,j=13;i<=0x0C;i++,j++){
-       tempah = (LCDACRT1Ptr+ResIndex)->CR[j];
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,i,tempah);
-     }
-
-     tempah = (LCDACRT1Ptr+ResIndex)->CR[16];
-     tempah &= 0x0E0;
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x0E,tempah);
-
-     tempah = (LCDACRT1Ptr+ResIndex)->CR[16];
-     tempah &= 0x01;
-     tempah <<= 5;
-     if(modeflag & DoubleScanMode)  tempah |= 0x080;
-     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah);
+  data2 = 0;
+  if(ModeNo > 0x13) {
+     if(SiS_Pr->SiS_ModeType > 0x02) {
+        data2 |= 0x02;
+        data2 |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
+     }
+  }
 
+#ifdef TWDEBUG
+  xf86DrvMsg(0, X_INFO, "Debug: Mode infoflag = %x, Chiptype %d\n",
+  	data, HwInfo->jChipType);
 #endif
 
+  if(data & InterlaceMode) data2 |= 0x20;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0,data2);
+
+  if(SiS_Pr->UseCustomMode) {
+     xres = SiS_Pr->CHDisplay;
   } else {
+     resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex);
+     if(ModeNo <= 0x13) {
+      	xres = SiS_Pr->SiS_StResInfo[resindex].HTotal;
+     } else {
+      	xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal;
+     }
+  }
 
-     /* LVDS, 301, 301B, 301LV, 302LV, ... (non-LCDA) */
+  if(HwInfo->jChipType != SIS_300) {
+     data = 0x0000;
+     if(infoflag & InterlaceMode) {
+        if(xres <= 800) data = 0x0020;
+        else if(xres <= 1024) data = 0x0035;
+        else data = 0x0048;
+     }
+     SiS_SetReg(SiS_Pr->SiS_P3d4,0x19,(data & 0x00FF));
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x1a,0xFC,(data >> 8));
+  }
 
-     if(SiS_Pr->UseCustomMode) {
-     
-        for(i=0,j=0;i<=07;i++,j++) {
-          SiS_SetReg1(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
-        }
-        for(j=0x10;i<=10;i++,j++) {
-          SiS_SetReg1(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
-        }
-        for(j=0x15;i<=12;i++,j++) {
-          SiS_SetReg1(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
-        }
-        for(j=0x0A;i<=15;i++,j++) {
-          SiS_SetReg1(SiS_Pr->SiS_P3c4,j,SiS_Pr->CCRT1CRTC[i]);
+  if(modeflag & HalfDCLK) {
+     SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x08);
+  }
+
+  if(HwInfo->jChipType == SIS_300) {
+     if(modeflag & LineCompareOff) {
+        SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x08);
+     } else {
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xF7);
+     }
+  } else {
+     if(modeflag & LineCompareOff) {
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,0x08);
+     } else {
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xB7);
+     }
+     if(SiS_Pr->SiS_ModeType == ModeEGA) {
+        if(ModeNo > 0x13) {
+  	   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x40);
         }
+     }
+  }
 
-        tempah = SiS_Pr->CCRT1CRTC[16] & 0xE0;
-        SiS_SetReg1(SiS_Pr->SiS_P3c4,0x0E,tempah);
+#ifdef SIS315H
+  /* 315 BIOS sets SR17 at this point */
+  if(HwInfo->jChipType == SIS_315PRO) {
+     data = SiS_Get310DRAMType(SiS_Pr, HwInfo);
+     data = SiS_Pr->SiS_SR15[2][data];
+     if(SiS_Pr->SiS_ModeType == ModeText) {
+        data &= 0xc7;
+     } else {
+        data2 = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex,
+                              RefreshRateTableIndex,HwInfo);
+	data2 >>= 1;
+	if(infoflag & InterlaceMode) data2 >>= 1;
+	data3 = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex) >> 1;
+	if(!data3) data3++;
+	data2 /= data3;
+	if(data2 >= 0x50) {
+	   data &= 0x0f;
+	   data |= 0x50;
+	}
+     }
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data);
+  }
 
-        tempah = SiS_Pr->CCRT1CRTC[16];
-        tempah &= 0x01;
-        tempah <<= 5;
-        if(modeflag & DoubleScanMode)  tempah |= 0x80;
-        SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,tempah);
-     
-     
+  /* 330 BIOS sets SR17 at this point */
+  if(HwInfo->jChipType == SIS_330) {
+     data = SiS_Get310DRAMType(SiS_Pr, HwInfo);
+     data = SiS_Pr->SiS_SR15[2][data];
+     if(SiS_Pr->SiS_ModeType <= ModeEGA) {
+        data &= 0xc7;
      } else {
-     
-        index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;  	/* Get index */
-#if 0   /* Not any longer... */     
-        if(HwDeviceExtension->jChipType < SIS_315H) {
-           index &= 0x3F;
-        }
-#endif
+        if(SiS_Pr->UseCustomMode) {
+	   data2 = SiS_Pr->CSRClock;
+	} else {
+           data2 = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex,
+                                   RefreshRateTableIndex,HwInfo);
+           data2 = SiS_Pr->SiS_VCLKData[data2].CLOCK;
+	}
 
-        for(i=0,j=0;i<=07;i++,j++) {
-          tempah=SiS_Pr->SiS_CRT1Table[index].CR[i];
-          SiS_SetReg1(SiS_Pr->SiS_P3d4,j,tempah);
-        }
-        for(j=0x10;i<=10;i++,j++) {
-          tempah=SiS_Pr->SiS_CRT1Table[index].CR[i];
-          SiS_SetReg1(SiS_Pr->SiS_P3d4,j,tempah);
-        }
-        for(j=0x15;i<=12;i++,j++) {
-          tempah=SiS_Pr->SiS_CRT1Table[index].CR[i];
-          SiS_SetReg1(SiS_Pr->SiS_P3d4,j,tempah);
-        }
-        for(j=0x0A;i<=15;i++,j++) {
-          tempah=SiS_Pr->SiS_CRT1Table[index].CR[i];
-          SiS_SetReg1(SiS_Pr->SiS_P3c4,j,tempah);
-        }
+	data3 = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex) >> 1;
+	if(!data3) data3++;
 
-        tempah = SiS_Pr->SiS_CRT1Table[index].CR[16];
-        tempah &= 0xE0;
-        SiS_SetReg1(SiS_Pr->SiS_P3c4,0x0E,tempah);
+	data2 *= data3;
 
-        tempah = SiS_Pr->SiS_CRT1Table[index].CR[16];
-        tempah &= 0x01;
-        tempah <<= 5;
-        if(modeflag & DoubleScanMode)  tempah |= 0x80;
-        SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,tempah);
+	longdata = SiS_GetMCLK(SiS_Pr, HwInfo) * 1024;
 
-     }
+	data2 = longdata / data2;
+
+	if(SiS_Pr->SiS_ModeType != Mode16Bpp) {
+           if(data2 >= 0x19c)      data = 0xba;
+	   else if(data2 >= 0x140) data = 0x7a;
+	   else if(data2 >= 0x101) data = 0x3a;
+	   else if(data2 >= 0xf5)  data = 0x32;
+	   else if(data2 >= 0xe2)  data = 0x2a;
+	   else if(data2 >= 0xc4)  data = 0x22;
+	   else if(data2 >= 0xac)  data = 0x1a;
+	   else if(data2 >= 0x9e)  data = 0x12;
+	   else if(data2 >= 0x8e)  data = 0x0a;
+	   else                    data = 0x02;
+	 } else {
+	   if(data2 >= 0x127)      data = 0xba;
+	   else                    data = 0x7a;
+	 }
+      }
+      SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data);
   }
+#endif
 
-  if(SiS_Pr->SiS_ModeType > ModeVGA) SiS_SetReg1(SiS_Pr->SiS_P3d4,0x14,0x4F);
-}
+  data = 0x60;
+  if(SiS_Pr->SiS_ModeType != ModeText) {
+     data ^= 0x60;
+     if(SiS_Pr->SiS_ModeType != ModeEGA) {
+        data ^= 0xA0;
+     }
+  }
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x21,0x1F,data);
 
-BOOLEAN
-SiS_GetLCDACRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-		   USHORT RefreshRateTableIndex,USHORT *ResIndex,
-		   USHORT *DisplayType)
- {
-  USHORT tempbx=0,modeflag=0;
-  USHORT CRT2CRTC=0;
+  SiS_SetVCLKState(SiS_Pr, HwInfo, ModeNo, RefreshRateTableIndex, ModeIdIndex);
 
-  if(ModeNo <= 0x13) {
-  	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-  	CRT2CRTC = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  } else {
-  	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-  	CRT2CRTC = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+#ifdef SIS315H
+  if(HwInfo->jChipType >= SIS_315H) {
+     if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x2c);
+     } else {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x6c);
+     }
+#if 0   /* What is SR0E[D5:6]? */
+     if(HwInfo->jChipType >= SIS_661) {
+        data = 0;
+        if((ModeNo == 6) || ((ModeNo >= 0x0e) && (ModeNo <= 0x13))) {
+	   data |= 0x20;
+	}
+	if(SiS_Pr->SiS_ModeType != ModeVGA) {
+	   if(SiS_Pr->UseCustomMode) {
+              if((xres >= 640) && (SiS_Pr->CVDisplay >= 480)) {
+	         data |= 0x40;
+	      }
+	      if((xres > 1280) && (SiS_Pr->CVDisplay > 1024)) {
+	         data |= 0x60;
+	      }
+	   }
+	} else if(ModeNo > 0x13) {   /* These are in the CRT1 table, and set by CRT1CRTC */
+	   if(resinfo >= SIS_RI_640x480) {
+	      if(resinfo <= SIS_RI_2048x1536) {
+	         data |= 0x40;
+		 if(resinfo > SIS_RI_1280x1024) {
+		    data |= 0x60;
+		    if(resinfo != SIS_RI_1600x1200) {
+		       data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x0e);
+		       data += 0x60;
+		       SiS_SetReg(SiS_Pr->SiS_P3c4,0x0e);
+		       data = 0;
+		    }
+		 }
+	      }
+	      if(resinfo == SIS_RI_1152x864) {
+		 data = 0x40;
+	      }
+	      if(resinfo == SIS_RI_1400x1050) { /* TW */
+		 data = 0x60;
+	      }
+	   }
+	}
+	SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0e,data);
+     }
+#endif
   }
+#endif
+}
+
+/*********************************************/
+/*                 LOAD DAC                  */
+/*********************************************/
 
-  tempbx = SiS_Pr->SiS_LCDResInfo;
+#if 0
+static void
+SiS_ClearDAC(SiS_Private *SiS_Pr, ULONG port)
+{
+   int i;
 
-  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 32;
-  if(modeflag & HalfDCLK)                 tempbx += 16;
+   OutPortByte(port, 0);
+   port++;
+   for (i=0; i < (256 * 3); i++) {
+      OutPortByte(port, 0);
+   }
+}
+#endif
 
-  *ResIndex = CRT2CRTC & 0x3F;
-  *DisplayType = tempbx;
+static void
+SiS_WriteDAC(SiS_Private *SiS_Pr, SISIOADDRESS DACData, USHORT shiftflag,
+             USHORT dl, USHORT ah, USHORT al, USHORT dh)
+{
+  USHORT temp,bh,bl;
 
-  return 1;
+  bh = ah;
+  bl = al;
+  if(dl != 0) {
+     temp = bh;
+     bh = dh;
+     dh = temp;
+     if(dl == 1) {
+        temp = bl;
+        bl = dh;
+        dh = temp;
+     } else {
+        temp = bl;
+        bl = bh;
+        bh = temp;
+     }
+  }
+  if(shiftflag) {
+     dh <<= 2;
+     bh <<= 2;
+     bl <<= 2;
+  }
+  SiS_SetRegByte(DACData,(USHORT)dh);
+  SiS_SetRegByte(DACData,(USHORT)bh);
+  SiS_SetRegByte(DACData,(USHORT)bl);
 }
 
-/* TW: Set offset and pitch - partly overruled by SetPitch() in XF86 */
 void
-SiS_SetCRT1Offset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                  USHORT RefreshRateTableIndex,
-		  PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+            USHORT ModeNo, USHORT ModeIdIndex)
 {
-   USHORT temp, DisplayUnit, infoflag;
+   USHORT data,data2;
+   USHORT time,i,j,k,m,n,o;
+   USHORT si,di,bx,dl,al,ah,dh;
+   USHORT shiftflag;
+   SISIOADDRESS DACAddr, DACData;
+   const USHORT *table = NULL;
 
-   if(SiS_Pr->UseCustomMode) {
-      infoflag = SiS_Pr->CInfoFlag;
+   if(ModeNo <= 0x13) {
+      data = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
    } else {
-      infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+      if(SiS_Pr->UseCustomMode) {
+	 data = SiS_Pr->CModeFlag;
+      } else {
+         data = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+      }
    }
-   
-   DisplayUnit = SiS_GetOffset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
-                     RefreshRateTableIndex,HwDeviceExtension);		     
 
-   temp = (DisplayUnit >> 8) & 0x0f;
-   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,temp);
-
-   temp = DisplayUnit & 0xFF;
-   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x13,temp);
-
-   if(infoflag & InterlaceMode) DisplayUnit >>= 1;
+   data &= DACInfoFlag;
+   time = 64;
+   if(data == 0x00) table = SiS_MDA_DAC;
+   if(data == 0x08) table = SiS_CGA_DAC;
+   if(data == 0x10) table = SiS_EGA_DAC;
+   if(data == 0x18) {
+      time = 256;
+      table = SiS_VGA_DAC;
+   }
+   if(time == 256) j = 16;
+   else            j = time;
+
+   if( ( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) &&        /* 301B-DH LCD */
+         (SiS_Pr->SiS_VBType & VB_NoLCD) )        ||
+       (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)       ||   /* LCDA */
+       (!(SiS_Pr->SiS_SetFlag & ProgrammingCRT2)) ) {  /* Programming CRT1 */
+      DACAddr = SiS_Pr->SiS_P3c8;
+      DACData = SiS_Pr->SiS_P3c9;
+      shiftflag = 0;
+      SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
+   } else {
+      shiftflag = 1;
+      DACAddr = SiS_Pr->SiS_Part5Port;
+      DACData = SiS_Pr->SiS_Part5Port + 1;
+   }
+
+   SiS_SetRegByte(DACAddr,0x00);
+
+   for(i=0; i<j; i++) {
+      data = table[i];
+      for(k=0; k<3; k++) {
+	data2 = 0;
+	if(data & 0x01) data2 = 0x2A;
+	if(data & 0x02) data2 += 0x15;
+	if(shiftflag) data2 <<= 2;
+	SiS_SetRegByte(DACData, data2);
+	data >>= 2;
+      }
+   }
 
-   DisplayUnit <<= 5;
-   temp = (DisplayUnit & 0xff00) >> 8;
-   if (DisplayUnit & 0xff) temp++;
-   temp++;
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x10,temp);
+   if(time == 256) {
+      for(i = 16; i < 32; i++) {
+   	 data = table[i];
+	 if(shiftflag) data <<= 2;
+	 for(k = 0; k < 3; k++) SiS_SetRegByte(DACData, data);
+      }
+      si = 32;
+      for(m = 0; m < 9; m++) {
+         di = si;
+         bx = si + 4;
+         dl = 0;
+         for(n = 0; n < 3; n++) {
+  	    for(o = 0; o < 5; o++) {
+	       dh = table[si];
+	       ah = table[di];
+	       al = table[bx];
+	       si++;
+	       SiS_WriteDAC(SiS_Pr, DACData, shiftflag, dl, ah, al, dh);
+	    }
+	    si -= 2;
+	    for(o = 0; o < 3; o++) {
+	       dh = table[bx];
+	       ah = table[di];
+	       al = table[si];
+	       si--;
+	       SiS_WriteDAC(SiS_Pr, DACData, shiftflag, dl, ah, al, dh);
+	    }
+	    dl++;
+	 }            /* for n < 3 */
+	 si += 5;
+      }               /* for m < 9 */
+   }
 }
 
-/* TW: New from 650/LVDS 1.10.07, 630/301B and 630/LVDS BIOS */
-void
-SiS_ResetCRT1VCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+/*********************************************/
+/*         SET CRT1 REGISTER GROUP           */
+/*********************************************/
+
+static void
+SiS_SetCRT1Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                 USHORT ModeNo, USHORT ModeIdIndex)
 {
-   USHORT index;
+  USHORT  StandTableIndex,RefreshRateTableIndex;
 
-   /* TW: We only need to do this if Panel Link is to be
-    *     initialized, thus on 630/LVDS/301BDH, and 650/LVDS
-    */
-   if(HwDeviceExtension->jChipType >= SIS_315H) {
-      if(SiS_Pr->SiS_IF_DEF_LVDS == 0)  return;
-   } else {
-      if( (SiS_Pr->SiS_IF_DEF_LVDS == 0) &&
-          (!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) {
-	 return;
-      }
-   }
+  SiS_Pr->SiS_CRT1Mode = ModeNo;
+  StandTableIndex = SiS_GetModePtr(SiS_Pr, ModeNo, ModeIdIndex);
+  if(SiS_Pr->SiS_SetFlag & LowModeTests) {
+     if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2)) {
+        SiS_DisableBridge(SiS_Pr, HwInfo);
+     }
+  }
+
+  SiS_ResetSegmentRegisters(SiS_Pr, HwInfo);
+
+  SiS_SetSeqRegs(SiS_Pr, StandTableIndex, HwInfo);
+  SiS_SetMiscRegs(SiS_Pr, StandTableIndex, HwInfo);
+  SiS_SetCRTCRegs(SiS_Pr, HwInfo, StandTableIndex);
+  SiS_SetATTRegs(SiS_Pr, StandTableIndex, HwInfo);
+  SiS_SetGRCRegs(SiS_Pr, StandTableIndex);
+  SiS_ClearExt1Regs(SiS_Pr,HwInfo);
+  SiS_ResetCRT1VCLK(SiS_Pr, HwInfo);
+
+  SiS_Pr->SiS_SelectCRT2Rate = 0;
+  SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
 
-   if(HwDeviceExtension->jChipType >= SIS_315H) {
-   	SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xCF,0x20);
-   } else {
-   	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x20);
-   }
-   index = 1;
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[index].SR2B);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[index].SR2C);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x80);
-   if(HwDeviceExtension->jChipType >= SIS_315H) {
-   	SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x10);
-   } else {
-   	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x10);
-   }
-   index = 0;
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[index].SR2B);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[index].SR2C);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x80);
-}
+#ifdef LINUX_XF86
+  xf86DrvMsgVerb(0, X_PROBED, 4, "(init: VBType=0x%04x, VBInfo=0x%04x)\n",
+                    SiS_Pr->SiS_VBType, SiS_Pr->SiS_VBInfo);
+#endif
 
-void
-SiS_SetCRT1VCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                PSIS_HW_DEVICE_INFO HwDeviceExtension,
-		USHORT RefreshRateTableIndex)
-{
-  USHORT  index=0;
+  if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) {
+     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+        SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+     }
+  }
 
-  if(!SiS_Pr->UseCustomMode) {
-     index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
-	                  RefreshRateTableIndex,HwDeviceExtension);
-  }			  
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+     SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+  }
 
-  if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ){
+  RefreshRateTableIndex = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
 
-    	SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF);
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+     SiS_Pr->SiS_SetFlag &= ~ProgrammingCRT2;
+  }
 
-    	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VBVCLKData[index].Part4_A);
-    	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VBVCLKData[index].Part4_B);
+  if(RefreshRateTableIndex != 0xFFFF) {
+     SiS_SetCRT1Sync(SiS_Pr, RefreshRateTableIndex);
+     SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+     SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+     SiS_SetCRT1VCLK(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
+  }
 
-    	if(HwDeviceExtension->jChipType >= SIS_315H) {
-		SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x01);
-   	} else {
-    		SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x80);
-    	}
+#ifdef SIS300
+  if(HwInfo->jChipType == SIS_300) {
+     SiS_SetCRT1FIFO_300(SiS_Pr, ModeNo,HwInfo,RefreshRateTableIndex);
+  } else if((HwInfo->jChipType == SIS_630) ||
+            (HwInfo->jChipType == SIS_730) ||
+            (HwInfo->jChipType == SIS_540)) {
+     SiS_SetCRT1FIFO_630(SiS_Pr, ModeNo, HwInfo, RefreshRateTableIndex);
+  }
+#endif
+#ifdef SIS315H
+  if(HwInfo->jChipType >= SIS_315H) {
+     SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+  }
+#endif
 
-  } else {
+  SiS_SetCRT1ModeRegs(SiS_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex);
 
-	if(HwDeviceExtension->jChipType >= SIS_315H) {
-	    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF);
-	} else {
-	    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x00);
-	}
+  SiS_LoadDAC(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
 
-	if(SiS_Pr->UseCustomMode) {
-	   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->CSR2B);
-	   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->CSR2C);
-	} else {
-    	   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[index].SR2B);
-    	   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[index].SR2C);
-  	}	   
+#ifndef LINUX_XF86
+  if(SiS_Pr->SiS_flag_clearbuffer) {
+     SiS_ClearBuffer(SiS_Pr,HwInfo,ModeNo);
+  }
+#endif
 
-    	if(HwDeviceExtension->jChipType >= SIS_315H) {
-	    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x01);
-	} else {
-      	    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x80);
-        }
+  if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA))) {
+     SiS_WaitRetrace1(SiS_Pr);
+     SiS_DisplayOn(SiS_Pr);
   }
 }
 
-#if 0  /* TW: Not used */
-void
-SiS_IsLowResolution(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+/*********************************************/
+/*            HELPER: ENABLE CRT1            */
+/*********************************************/
+
+static void
+SiS_HandleCRT1(SiS_Private *SiS_Pr)
 {
-  USHORT ModeFlag;
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x63,0xbf);
+#if 0
+  if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x01)) {
+     if((SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x0a) ||
+        (SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x01)) {
+        SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x63,0x40);
+     }
+  }
+#endif
+}
 
-  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0x7F);
+/*********************************************/
+/*         HELPER: SET VIDEO REGISTERS       */
+/*********************************************/
 
-  if(ModeNo > 0x13) {
-    ModeFlag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    if ((ModeFlag & HalfDCLK) && (ModeFlag & DoubleScanMode)) {
-      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x80);
-      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x01,0xF7);
-    }
-  }
+static void
+SiS_StrangeStuff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   if((IS_SIS651) || (IS_SISM650)) {
+      SiS_SetReg(SiS_Pr->SiS_VidCapt, 0x3f, 0x00);   /* Fiddle with capture regs */
+      SiS_SetReg(SiS_Pr->SiS_VidCapt, 0x00, 0x00);
+      SiS_SetReg(SiS_Pr->SiS_VidPlay, 0x00, 0x86);   /* (BIOS does NOT unlock) */
+      SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x30, 0xfe); /* Fiddle with video regs */
+      SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x3f, 0xef);
+   }
+   /* !!! This does not support modes < 0x13 !!! */
 }
-#endif
 
-void
-SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                    USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex)
+/*********************************************/
+/*         XFree86: SET SCREEN PITCH         */
+/*********************************************/
+
+#ifdef LINUX_XF86
+static void
+SiS_SetPitchCRT1(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
 {
-  USHORT data,data2,data3;
-  USHORT infoflag=0,modeflag;
-  USHORT resindex,xres;
-#ifdef SIS315H
-  ULONG  longdata;
-#endif  
+   SISPtr pSiS = SISPTR(pScrn);
+   UShort HDisplay = pSiS->scrnPitch >> 3;
 
-  if(SiS_Pr->UseCustomMode) {
-     modeflag = SiS_Pr->CModeFlag;
-     infoflag = SiS_Pr->CInfoFlag;
-  } else {
-     if(ModeNo > 0x13) {
-    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    	infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
-     } else {
-    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-     }
-  }
+   SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,(HDisplay & 0xFF));
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,(HDisplay>>8));
+}
 
-  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1F,0x3F); 		/* DAC pedestal */
+static void
+SiS_SetPitchCRT2(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
+{
+   SISPtr pSiS = SISPTR(pScrn);
+   UShort HDisplay = pSiS->scrnPitch2 >> 3;
 
-  if(ModeNo > 0x13) data = infoflag;
-  else data = 0;
+    /* Unlock CRT2 */
+   if(pSiS->VGAEngine == SIS_315_VGA)
+     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2F, 0x01);
+   else
+     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24, 0x01);
 
-  data2 = 0;
-  if(ModeNo > 0x13) {
-     if(SiS_Pr->SiS_ModeType > 0x02) {
-        data2 |= 0x02;
-        data3 = (SiS_Pr->SiS_ModeType - ModeVGA) << 2;
-        data2 |= data3;
-     }
-  }
-#ifdef TWDEBUG
-  xf86DrvMsg(0, X_INFO, "Debug: Mode infoflag = %x, Chiptype %d\n", 
-  	data, HwDeviceExtension->jChipType);
-#endif  
-  if(data & InterlaceMode) data2 |= 0x20;
-  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0,data2);
+   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(HDisplay & 0xFF));
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0xF0,(HDisplay >> 8));
+}
 
-  if(SiS_Pr->UseCustomMode) {
-     xres = SiS_Pr->CHDisplay;
-  } else {
-     resindex = SiS_GetResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
-     if(ModeNo <= 0x13) {
-      	xres = SiS_Pr->SiS_StResInfo[resindex].HTotal;
-     } else {
-      	xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal;
-     }
-  }
+static void
+SiS_SetPitch(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
+{
+   SISPtr pSiS = SISPTR(pScrn);
+   BOOLEAN isslavemode = FALSE;
 
-  if(HwDeviceExtension->jChipType != SIS_300) {
-     data = 0x0000;
-     if(infoflag & InterlaceMode) {
-        if(xres <= 800)  data = 0x0020;
-        else if(xres <= 1024) data = 0x0035;
-        else data = 0x0048;
-     }
-     data2 = data & 0x00FF;
-     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x19,data2);
-     data2 = (data & 0xFF00) >> 8;
-     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x1a,0xFC,data2);
-  }
+   if( (pSiS->VBFlags & VB_VIDEOBRIDGE) &&
+       ( ((pSiS->VGAEngine == SIS_300_VGA) &&
+          (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) ||
+         ((pSiS->VGAEngine == SIS_315_VGA) &&
+	  (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) {
+      isslavemode = TRUE;
+   }
 
-  if(modeflag & HalfDCLK) {
-     SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x08);
-  }
+   /* We need to set pitch for CRT1 if bridge is in slave mode, too */
+   if((pSiS->VBFlags & DISPTYPE_DISP1) || (isslavemode)) {
+      SiS_SetPitchCRT1(SiS_Pr, pScrn);
+   }
+   /* We must not set the pitch for CRT2 if bridge is in slave mode */
+   if((pSiS->VBFlags & DISPTYPE_DISP2) && (!isslavemode)) {
+      SiS_SetPitchCRT2(SiS_Pr, pScrn);
+   }
+}
+#endif
 
-  if(HwDeviceExtension->jChipType == SIS_300) {
-     if(modeflag & LineCompareOff) {
-        SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x08);
-     } else {
-        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xF7);
-     }
-  } else if(HwDeviceExtension->jChipType < SIS_315H) {
-     if(modeflag & LineCompareOff) {
-        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,0x08);
-     } else {
-        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xB7);
-     }
-     /* 630 BIOS does something for mode 0x12 here */
-  } else {
-     if(modeflag & LineCompareOff) {
-        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,0x08);
-     } else {
-        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xB7);
-     }
-     /* 651 BIOS does something for mode 0x12 here */
-  }
+/*********************************************/
+/*                 SiSSetMode()              */
+/*********************************************/
 
-  if(HwDeviceExtension->jChipType != SIS_300) {
-     if(SiS_Pr->SiS_ModeType == ModeEGA) {
-        if(ModeNo > 0x13) {
-  	   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x40);
-        }
-     }
-  }
+#ifdef LINUX_XF86
+/* We need pScrn for setting the pitch correctly */
+BOOLEAN
+SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch)
+#else
+BOOLEAN
+SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo)
+#endif
+{
+   ULONG   temp;
+   USHORT  ModeIdIndex;
+   UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
+   SISIOADDRESS BaseAddr = HwInfo->ulIOAddress;
+   unsigned char backupreg=0, tempr1, tempr2;
+#ifndef LINUX_XF86
+   USHORT  KeepLockReg;
 
-#ifdef SIS315H
-  /* TW: 315 BIOS sets SR17 at this point */
-  if(HwDeviceExtension->jChipType == SIS_315PRO) {
-      data = SiS_Get310DRAMType(SiS_Pr,ROMAddr,HwDeviceExtension);
-      data = SiS_Pr->SiS_SR15[2][data];
-      if(SiS_Pr->SiS_ModeType == ModeText) {
-          data &= 0xc7;
-      } else {
-          data2 = SiS_GetOffset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
-                                RefreshRateTableIndex,HwDeviceExtension);
-	  data2 >>= 1;
-	  if(infoflag & InterlaceMode) data2 >>= 1;
-	  data3 = SiS_GetColorDepth(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
-	  data3 >>= 1;
-	  if(data3 == 0) data3++;
-	  data2 /= data3;
-	  if(data2 >= 0x50) {
-	      data &= 0x0f;
-	      data |= 0x50;
-	  }
-      }
-      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,data);
-  }
+   SiS_Pr->UseCustomMode = FALSE;
+   SiS_Pr->CRT1UsesCustomMode = FALSE;
+#endif
 
-  /* TW: 330 BIOS sets SR17 at this point */
-  if(HwDeviceExtension->jChipType == SIS_330) {
-      data = SiS_Get310DRAMType(SiS_Pr,ROMAddr,HwDeviceExtension);
-      data = SiS_Pr->SiS_SR15[2][data];
-      if(SiS_Pr->SiS_ModeType <= ModeEGA) {
-          data &= 0xc7;
-      } else {
-          if(SiS_Pr->UseCustomMode) {
-	     data2 = SiS_Pr->CSRClock;
-	  } else {
-             data2 = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
-                               RefreshRateTableIndex,HwDeviceExtension);
-             data2 = SiS_Pr->SiS_VCLKData[data2].CLOCK;
-	  }
+   if(SiS_Pr->UseCustomMode) {
+      ModeNo = 0xfe;
+   }
 
-	  data3 = SiS_GetColorDepth(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
-	  data3 >>= 1;
+   SiSInitPtr(SiS_Pr, HwInfo);
 
-	  data2 *= data3;
+   SiSRegInit(SiS_Pr, BaseAddr);
 
-	  data3 = SiS_GetMCLK(SiS_Pr,ROMAddr, HwDeviceExtension);
-	  longdata = data3 * 1024;
+   SiS_GetSysFlags(SiS_Pr, HwInfo);
 
-	  data2 = longdata / data2;
-
-	  if(SiS_Pr->SiS_ModeType != Mode16Bpp) {
-            if(data2 >= 0x19c)      data = 0xba;
-	    else if(data2 >= 0x140) data = 0x7a;
-	    else if(data2 >= 0x101) data = 0x3a;
-	    else if(data2 >= 0xf5)  data = 0x32;
-	    else if(data2 >= 0xe2)  data = 0x2a;
-	    else if(data2 >= 0xc4)  data = 0x22;
-	    else if(data2 >= 0xac)  data = 0x1a;
-	    else if(data2 >= 0x9e)  data = 0x12;
-	    else if(data2 >= 0x8e)  data = 0x0a;
-	    else                    data = 0x02;
-	  } else {
-	    if(data2 >= 0x127)      data = 0xba;
-	    else                    data = 0x7a;
-	  }
-      }
-      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,data);
-  }
+#ifdef LINUX_XF86
+   if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
+   else
 #endif
+         SiS_Pr->SiS_VGAINFO = 0x11;
 
-  data = 0x60;
-  if(SiS_Pr->SiS_ModeType != ModeText) {
-      data ^= 0x60;
-      if(SiS_Pr->SiS_ModeType != ModeEGA) {
-          data ^= 0xA0;
-      }
-  }
-  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x21,0x1F,data);
+   SiSInitPCIetc(SiS_Pr, HwInfo);
 
-  SiS_SetVCLKState(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,RefreshRateTableIndex,ModeIdIndex);
+   SiSSetLVDSetc(SiS_Pr, HwInfo);
 
-#ifdef SIS315H
-  if(HwDeviceExtension->jChipType >= SIS_315H) {
-    if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x40) {
-        SiS_SetReg1(SiS_Pr->SiS_P3d4,0x52,0x2c);
-    } else {
-        SiS_SetReg1(SiS_Pr->SiS_P3d4,0x52,0x6c);
-    }
-  }
+   SiSDetermineROMUsage(SiS_Pr, HwInfo);
+
+   if(!SiS_Pr->UseCustomMode) {
+      ModeNo = ((ModeNo & 0x80) << 8) | (ModeNo & 0x7f);
+   }
+
+#ifdef LINUX_XF86
+   /* We never clear the buffer in X */
+   ModeNo |= 0x8000;
 #endif
-}
 
-void
-SiS_SetVCLKState(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                 USHORT ModeNo,USHORT RefreshRateTableIndex,
-                 USHORT ModeIdIndex)
-{
-  USHORT data, data2=0;
-  USHORT VCLK, index=0;
+   if(ModeNo & 0x8000) {
+     	ModeNo &= 0x7fff;
+     	SiS_Pr->SiS_flag_clearbuffer = 0;
+   } else {
+     	SiS_Pr->SiS_flag_clearbuffer = 1;
+   }
 
-  if (ModeNo <= 0x13) VCLK = 0;
-  else {
-     if(SiS_Pr->UseCustomMode) {
-        VCLK = SiS_Pr->CSRClock;
-     } else {
-        index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
-	               RefreshRateTableIndex,HwDeviceExtension);
-        VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
-     }	
-  }
+#ifndef LINUX_XF86
+   KeepLockReg = SiS_GetReg(SiS_Pr->SiS_P3c4,0x05);
+#endif
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
 
-  if(HwDeviceExtension->jChipType < SIS_315H) {		/* 300 series */
+   SiS_UnLockCRT2(SiS_Pr, HwInfo);
 
-    data2 = 0x00;
-    if(VCLK > 150) data2 |= 0x80;
-    SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data2); 	/* DAC speed */
+   if(!SiS_Pr->UseCustomMode) {
+      if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
+   } else {
+      ModeIdIndex = 0;
+   }
 
-    data2 = 0x00;
-    if(VCLK >= 150) data2 |= 0x08;       	/* VCLK > 150 */
-    SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data2);
+   SiS_GetVBType(SiS_Pr, HwInfo);
 
-  } else { 						/* 315 series */
+   /* Init/restore some VB registers */
 
-    data = 0;
-    if(VCLK >= 166) data |= 0x0c;         	/* TW: Was 200; is 166 in 650, 315 and 330 BIOSes */
-    SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data);
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(HwInfo->jChipType >= SIS_315H) {
+         SiS_UnLockCRT2(SiS_Pr,HwInfo);
+	 if(ROMAddr && SiS_Pr->SiS_UseROM) {
+	    if(HwInfo->jChipType < SIS_330) {
+               temp = ROMAddr[VB310Data_1_2_Offset];
+	       temp |= 0x40;
+	       SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
+            }
+	    if(HwInfo->jChipType > SIS_330) {
+	       temp = ROMAddr[0x7e];
+	       if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x7b) >= 100) temp |= 0x40;
+	       SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
+	    }
+	 }
+	 SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
 
-    if(VCLK >= 166) {				/* TW: Was 200, is 166 in 650, 315 and 330 BIOSes */
-       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1f,0xe7);
-    }
-  }
+	 SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c);
 
-  data2 = 0x03;
-  if((VCLK >= 135) && (VCLK < 160)) data2 = 0x02;
-  if((VCLK >= 160) && (VCLK < 260)) data2 = 0x01;
-  if(VCLK >= 260) data2 = 0x00;
-
-  if(HwDeviceExtension->jChipType == SIS_540) {
-    	if((VCLK == 203) || (VCLK < 234)) data2 = 0x02;
-  }
-  
-  if(HwDeviceExtension->jChipType < SIS_315H) {
-      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data2);  	/* DAC speed */
-  } else {
-      if(HwDeviceExtension->jChipType > SIS_315PRO) {
-         /* TW: This "if" is done in 330 and 650/LVDS/301LV BIOSes; Not in 315 BIOS */
-         if(ModeNo > 0x13) data2 &= 0xfc;
+         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+      } else {
+         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
       }
-      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data2);  	/* DAC speed */
-  }
-}
+   }
 
-void
-SiS_LoadDAC(SiS_Private *SiS_Pr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-            UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
-{
-   USHORT data,data2;
-   USHORT time,i,j,k;
-   USHORT m,n,o;
-   USHORT si,di,bx,dl;
-   USHORT al,ah,dh;
-   USHORT DACAddr, DACData, shiftflag;
-   const USHORT *table = NULL;
+   /* Get VB information (connectors, connected devices) */
+   SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, (SiS_Pr->UseCustomMode) ? 0 : 1);
+   SiS_SetYPbPr(SiS_Pr, HwInfo);
+   SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo);
+
+#ifndef LINUX_XF86
+   /* 3. Check memory size (Kernel framebuffer driver only) */
+   temp = SiS_CheckMemorySize(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
+   if(!temp) return(0);
+#endif
+
+   if(HwInfo->jChipType >= SIS_315H) {
 #if 0
-   USHORT tempah,tempch,tempcl,tempdh,tempal,tempbx;
+      if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
+         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+            if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= SetDOSMode;
+         } else if((IS_SIS651) && (SiS_Pr->SiS_VBType & VB_NoLCD)) {
+            SiS_Pr->SiS_SetFlag |= SetDOSMode;
+         }
+      }
 #endif
 
-   if(ModeNo <= 0x13) {
-        data = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+         if(IS_SIS650) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
+	    if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20);
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
+	 } else if(IS_SIS661741660760) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef);
+	 }
+      }
+   }
+
+   if(SiS_Pr->UseCustomMode) {
+      SiS_Pr->CRT1UsesCustomMode = TRUE;
+      SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
+      SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
    } else {
-        if(SiS_Pr->UseCustomMode) {
-	   data = SiS_Pr->CModeFlag;
-	} else {
-           data = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- 	}	   
+      SiS_Pr->CRT1UsesCustomMode = FALSE;
    }
 
-#if 0
-   if(!(ds:489 & 0x08)) {
-#endif
+   /* Set mode on CRT1 */
+   if( (SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) ||
+       (!(SiS_Pr->SiS_VBInfo & SwitchCRT2)) ) {
+      SiS_SetCRT1Group(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
+   }
 
-	data &= DACInfoFlag;
-	time = 64;
-	if(data == 0x00) table = SiS_MDA_DAC;
-	if(data == 0x08) table = SiS_CGA_DAC;
-	if(data == 0x10) table = SiS_EGA_DAC;
-	if(data == 0x18) {
-	   time = 256;
-	   table = SiS_VGA_DAC;
-	}
-	if(time == 256) j = 16;
-	else            j = time;
+   /* Set mode on CRT2 */
+   if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA)) {
+      if( (SiS_Pr->SiS_VBType & VB_SISVB)    ||
+          (SiS_Pr->SiS_IF_DEF_LVDS     == 1) ||
+          (SiS_Pr->SiS_IF_DEF_CH70xx   != 0) ||
+          (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) {
+         SiS_SetCRT2Group(SiS_Pr, HwInfo, ModeNo);
+      }
+   }
 
-	if( ( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) &&        /* 301B-DH LCD */
-	      (SiS_Pr->SiS_VBType & VB_NoLCD) )        ||
-	    (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)       ||   /* LCDA */
-	    (!(SiS_Pr->SiS_SetFlag & ProgrammingCRT2)) ) {  /* Programming CRT1 */
-	   DACAddr = SiS_Pr->SiS_P3c8;
-	   DACData = SiS_Pr->SiS_P3c9;
-	   shiftflag = 0;
-	   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
-	} else {
-	   shiftflag = 1;
-	   DACAddr = SiS_Pr->SiS_Part5Port;
-	   DACData = SiS_Pr->SiS_Part5Port + 1;
-	}
+   SiS_HandleCRT1(SiS_Pr);
 
-	SiS_SetReg3(DACAddr,0x00);
+   SiS_StrangeStuff(SiS_Pr, HwInfo);
 
-	for(i=0; i<j; i++) {
-	   data = table[i];
-	   for(k=0; k<3; k++) {
-		data2 = 0;
-		if(data & 0x01) data2 = 0x2A;
-		if(data & 0x02) data2 += 0x15;
-		if(shiftflag) data2 <<= 2;
-		SiS_SetReg3(DACData,data2);
-		data >>= 2;
-	   }
-	}
+   SiS_DisplayOn(SiS_Pr);
+   SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
 
-	if(time == 256) {
-	   for(i = 16; i < 32; i++) {
-		data = table[i];
-		if(shiftflag) data <<= 2;
-		for(k=0; k<3; k++) SiS_SetReg3(DACData,data);
-	   }
-	   si = 32;
-	   for(m = 0; m < 9; m++) {
-	      di = si;
-	      bx = si + 4;
-	      dl = 0;
-	      for(n = 0; n < 3; n++) {
-		 for(o = 0; o < 5; o++) {
-		    dh = table[si];
-		    ah = table[di];
-		    al = table[bx];
-		    si++;
-		    SiS_WriteDAC(SiS_Pr,DACData,shiftflag,dl,ah,al,dh);
-		 }
-		 si -= 2;
-		 for(o = 0; o < 3; o++) {
-		    dh = table[bx];
-		    ah = table[di];
-		    al = table[si];
-		    si--;
-		    SiS_WriteDAC(SiS_Pr,DACData,shiftflag,dl,ah,al,dh);
-		 }
-		 dl++;
-	      }            /* for n < 3 */
-	      si += 5;
-	   }               /* for m < 9 */
-	}
-#if 0
-    }  /* ds:489 & 0x08 */
-#endif
+   if(HwInfo->jChipType >= SIS_315H) {
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+         if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) {
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
+	 }
+      }
+   }
 
-#if 0
-    if((!(ds:489 & 0x08)) && (ds:489 & 0x06)) {
-           tempbx = 0;
-	   for(i=0; i< 256; i++) {
-               SiS_SetReg3(SiS_Pr->SiS_P3c8-1,tempbx);    	/* 7f87 */
-               tempah = SiS_GetReg3(SiS_Pr->SiS_P3c8+1);  	/* 7f83 */
-	       tempch = SiS_GetReg3(SiS_Pr->SiS_P3c8+1);
-	       tempcl = SiS_GetReg3(SiS_Pr->SiS_P3c8+1);
-	       tempdh = tempah;
-	       tempal = 0x4d * tempdh;          	/* 7fb8 */
-	       tempbx += tempal;
-	       tempal = 0x97 * tempch;
-	       tempbx += tempal;
-	       tempal = 0x1c * tempcl;
-	       tempbx += tempal;
-	       if((tempbx & 0x00ff) > 0x80) tempbx += 0x100;
-	       tempdh = (tempbx & 0x00ff) >> 8;
-	       tempch = tempdh;
-	       tempcl = tempdh;
-	       SiS_SetReg3(SiS_Pr->SiS_P3c8,(tempbx & 0xff));  	/* 7f7c */
-	       SiS_SetReg3(SiS_Pr->SiS_P3c8+1,tempdh);          /* 7f92 */
-	       SiS_SetReg3(SiS_Pr->SiS_P3c8+1,tempch);
-	       SiS_SetReg3(SiS_Pr->SiS_P3c8+1,tempcl);
-           }
-    }
-#endif
-}
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(HwInfo->jChipType >= SIS_315H) {
+         if(HwInfo->jChipType < SIS_661) {
+	    if(SiS_IsVAMode(SiS_Pr,HwInfo)) {
+	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
+	    } else {
+	       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE);
+	    }
+	 }
 
-void
-SiS_WriteDAC(SiS_Private *SiS_Pr, USHORT DACData, USHORT shiftflag,
-             USHORT dl, USHORT ah, USHORT al, USHORT dh)
-{
-  USHORT temp;
-  USHORT bh,bl;
+	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
 
-  bh = ah;
-  bl = al;
-  if(dl != 0) {
-    temp = bh;
-    bh = dh;
-    dh = temp;
-    if(dl == 1) {
-       temp = bl;
-       bl = dh;
-       dh = temp;
-    } else {
-       temp = bl;
-       bl = bh;
-       bh = temp;
-    }
-  }
-  if(shiftflag) {
-     dh <<= 2;
-     bh <<= 2;
-     bl <<= 2;
-  }
-  SiS_SetReg3(DACData,(USHORT)dh);
-  SiS_SetReg3(DACData,(USHORT)bh);
-  SiS_SetReg3(DACData,(USHORT)bl);
-}
+	 tempr1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+	 tempr2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00);
+	 if(tempr1 & SetCRT2ToAVIDEO) tempr2 &= 0xF7;
+	 else			      tempr2 |= 0x08;
+	 if(tempr1 & SetCRT2ToSVIDEO) tempr2 &= 0xFB;
+	 else			      tempr2 |= 0x04;
+	 SiS_SetReg(SiS_Pr->SiS_Part2Port,0x00,tempr2);
 
-#ifndef LINUX_XF86
-static ULONG
-GetDRAMSize(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-  ULONG   AdapterMemorySize = 0;
-#ifdef SIS315H
-  USHORT  counter;
-#endif
+	 if((IS_SIS650) && (SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & 0xfc)) {
+	    if((ModeNo == 0x03) || (ModeNo == 0x10)) {
+	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x80);
+	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x56,0x08);
+            }
+	 }
 
-  switch(HwDeviceExtension->jChipType) {
-#ifdef SIS315H
-  case SIS_315H:
-  case SIS_315:
-  case SIS_315PRO:
-    	counter = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
-	AdapterMemorySize = 1 << ((counter & 0xF0) >> 4);
-	counter >>= 2;
-	counter &= 0x03;
-	if(counter == 0x02) {
-		AdapterMemorySize += (AdapterMemorySize / 2);      /* DDR asymetric */
-	} else if(counter != 0) {
-		AdapterMemorySize <<= 1;                           /* SINGLE_CHANNEL_2_RANK or DUAL_CHANNEL_1_RANK */
-	}
-	AdapterMemorySize *= (1024*1024);
-        break;
+	 if(tempr1 & SetCRT2ToLCD) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc);
+	 }
+      } else if((HwInfo->jChipType == SIS_630) ||
+                (HwInfo->jChipType == SIS_730)) {
+         SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
+      }
+   }
 
-  case SIS_330:
-    	counter = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
-	AdapterMemorySize = 1 << ((counter & 0xF0) >> 4);
-	counter &= 0x0c;
-	if(counter != 0) {
-		AdapterMemorySize <<= 1;
-	}
-	AdapterMemorySize *= (1024*1024);
-	break;
+#ifdef LINUX_XF86
+   if(pScrn) {
+      /* SetPitch: Adapt to virtual size & position */
+      if((ModeNo > 0x13) && (dosetpitch)) {
+         SiS_SetPitch(SiS_Pr, pScrn);
+      }
 
-  case SIS_550:
-  case SIS_650:
-  case SIS_740:
-  case SIS_660:
-  case SIS_760:
-  	counter = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
-      	counter++;
-      	AdapterMemorySize = counter * 4;
-      	AdapterMemorySize *= (1024*1024);
-	break;
+      /* Backup/Set ModeNo in BIOS scratch area */
+      SiS_GetSetModeID(pScrn, ModeNo);
+   }
 #endif
 
-#ifdef SIS300
-  case SIS_300:
-  case SIS_540:
-  case SIS_630:
-  case SIS_730:
-      	AdapterMemorySize = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
-      	AdapterMemorySize++;
-      	AdapterMemorySize *= (1024*1024);
-	break;
+#ifndef LINUX_XF86  /* We never lock registers in XF86 */
+   if(KeepLockReg == 0xA1) SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
+   else SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x00);
 #endif
-  default:
-        break;
-  }
 
-  return AdapterMemorySize;
+   return TRUE;
 }
-#endif
 
-#ifndef LINUX_XF86
-void
-SiS_ClearBuffer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
+/*********************************************/
+/*          XFree86: SiSBIOSSetMode()        */
+/*           for non-Dual-Head mode          */
+/*********************************************/
+
+#ifdef LINUX_XF86
+BOOLEAN
+SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn,
+               DisplayModePtr mode, BOOLEAN IsCustom)
 {
-  PVOID   VideoMemoryAddress = (PVOID)HwDeviceExtension->pjVideoMemoryAddress;
-  ULONG   AdapterMemorySize  = (ULONG)HwDeviceExtension->ulVideoMemorySize;
-  PUSHORT pBuffer;
-  int i;
+   SISPtr  pSiS = SISPTR(pScrn);
+   UShort  ModeNo=0;
+   
+   SiS_Pr->UseCustomMode = FALSE;
 
-  if (SiS_Pr->SiS_ModeType>=ModeEGA) {
-    if(ModeNo > 0x13) {
-      AdapterMemorySize = GetDRAMSize(SiS_Pr, HwDeviceExtension);
-      SiS_SetMemory(VideoMemoryAddress,AdapterMemorySize,0);
-    } else {
-      pBuffer = VideoMemoryAddress;
-      for(i=0; i<0x4000; i++)
-         pBuffer[i] = 0x0000;
-    }
-  } else {
-    pBuffer = VideoMemoryAddress;
-    if (SiS_Pr->SiS_ModeType < ModeCGA) {
-      for(i=0; i<0x4000; i++)
-         pBuffer[i] = 0x0720;
-    } else {
-      SiS_SetMemory(VideoMemoryAddress,0x8000,0);
-    }
-  }
-}
-#endif
+   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
 
-void
-SiS_DisplayOn(SiS_Private *SiS_Pr)
-{
-   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x01,0xDF,0x00);
-}
+         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting custom mode %dx%d\n",
+	 	SiS_Pr->CHDisplay,
+		(mode->Flags & V_INTERLACE ? SiS_Pr->CVDisplay * 2 :
+		   (mode->Flags & V_DBLSCAN ? SiS_Pr->CVDisplay / 2 :
+		      SiS_Pr->CVDisplay)));
 
-void
-SiS_DisplayOff(SiS_Private *SiS_Pr)
-{
-   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x01,0xDF,0x20);
-}
+	 return(SiSSetMode(SiS_Pr, HwInfo, pScrn, ModeNo, TRUE));
 
+   }
 
-/* ========================================== */
-/*  SR CRTC GR */
-void
-SiS_SetReg1(USHORT port, USHORT index, USHORT data)
-{
-   OutPortByte(port,index);
-   OutPortByte(port+1,data);
-}
+   ModeNo = SiS_CalcModeIndex(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes);
+   if(!ModeNo) return FALSE;
 
-/* ========================================== */
-/*  AR(3C0) */
-void
-SiS_SetReg2(SiS_Private *SiS_Pr, USHORT port, USHORT index, USHORT data)
-{
-   InPortByte(port+0x3da-0x3c0);
-   OutPortByte(SiS_Pr->SiS_P3c0,index);
-   OutPortByte(SiS_Pr->SiS_P3c0,data);
-   OutPortByte(SiS_Pr->SiS_P3c0,0x20);
-}
+   xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x\n", ModeNo);
 
-void
-SiS_SetReg3(USHORT port, USHORT data)
-{
-   OutPortByte(port,data);
+   return(SiSSetMode(SiS_Pr, HwInfo, pScrn, ModeNo, TRUE));
 }
 
-void
-SiS_SetReg4(USHORT port, ULONG data)
+/*********************************************/
+/*       XFree86: SiSBIOSSetModeCRT2()       */
+/*           for Dual-Head modes             */
+/*********************************************/
+BOOLEAN
+SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn,
+               DisplayModePtr mode, BOOLEAN IsCustom)
 {
-   OutPortLong(port,data);
-}
+   ULONG   temp;
+   USHORT  ModeIdIndex;
+   UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
+   SISIOADDRESS BaseAddr = HwInfo->ulIOAddress;
+   UShort  ModeNo   = 0;
+   unsigned char tempr1, tempr2, backupreg=0;
+   SISPtr  pSiS     = SISPTR(pScrn);
+#ifdef SISDUALHEAD
+   SISEntPtr pSiSEnt = pSiS->entityPrivate;
+#endif
 
-void
-SiS_SetReg5(USHORT port, USHORT data)
-{
-   OutPortWord(port,data);
-}
+   SiS_Pr->UseCustomMode = FALSE;
 
-UCHAR SiS_GetReg1(USHORT port, USHORT index)
-{
-   UCHAR   data;
+   /* Remember: Custom modes for CRT2 are ONLY supported
+    * 		-) on 315/330 series,
+    *           -) on the 30x/B/C, and
+    *           -) if CRT2 is LCD or VGA
+    */
 
-   OutPortByte(port,index);
-   data = InPortByte(port+1);
+   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
 
-   return(data);
-}
+	 ModeNo = 0xfe;
 
-UCHAR
-SiS_GetReg2(USHORT port)
-{
-   UCHAR   data;
+   } else {
+
+         BOOLEAN havecustommodes = pSiS->HaveCustomModes;
 
-   data= InPortByte(port);
+#ifdef SISMERGED
+	 if(pSiS->MergedFB) havecustommodes = pSiS->HaveCustomModes2;
+#endif
 
-   return(data);
-}
+         ModeNo = SiS_CalcModeIndex(pScrn, mode, pSiS->VBFlags, havecustommodes);
+         if(!ModeNo) return FALSE;
 
-ULONG
-SiS_GetReg3(USHORT port)
-{
-   ULONG   data;
+   }
 
-   data = InPortLong(port);
+   SiSRegInit(SiS_Pr, BaseAddr);
 
-   return(data);
-}
+   SiSInitPtr(SiS_Pr, HwInfo);
 
-USHORT
-SiS_GetReg4(USHORT port)
-{
-   ULONG   data;
+   SiS_GetSysFlags(SiS_Pr, HwInfo);
 
-   data = InPortWord(port);
+   SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
 
-   return(data);
-}
+   SiSInitPCIetc(SiS_Pr, HwInfo);
 
-void
-SiS_ClearDAC(SiS_Private *SiS_Pr, ULONG port)
-{
-   int i;
+   SiSSetLVDSetc(SiS_Pr, HwInfo);
 
-   OutPortByte(port, 0);
-   port++;
-   for (i=0; i < (256 * 3); i++) {
-      OutPortByte(port, 0);
+   SiSDetermineROMUsage(SiS_Pr, HwInfo);
+
+   /* Save mode info so we can set it from within SetMode for CRT1 */
+#ifdef SISDUALHEAD
+   if(pSiS->DualHeadMode) {
+      pSiSEnt->CRT2ModeNo = ModeNo;
+      pSiSEnt->CRT2DMode = mode;
+      pSiSEnt->CRT2IsCustom = IsCustom;
+      pSiSEnt->CRT2CR30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+      pSiSEnt->CRT2CR31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31);
+      pSiSEnt->CRT2CR35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+      pSiSEnt->CRT2CR38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+#if 0
+      /* We can't set CRT2 mode before CRT1 mode is set */
+      if(pSiSEnt->CRT1ModeNo == -1) {
+    	 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+		"Setting CRT2 mode delayed until after setting CRT1 mode\n");
+   	 return TRUE;
+      }
+#endif      
+      pSiSEnt->CRT2ModeSet = TRUE;
    }
+#endif
+
+   /* We don't clear the buffer under X */
+   SiS_Pr->SiS_flag_clearbuffer=0;
 
-}
+   if(SiS_Pr->UseCustomMode) {
 
-#if 0  /* TW: Unused */
-void
-SiS_SetInterlace(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT RefreshRateTableIndex)
-{
-  ULONG Temp;
-  USHORT data,Temp2;
+      USHORT temptemp = SiS_Pr->CVDisplay;
 
-  if (ModeNo<=0x13) return;
+      if(SiS_Pr->CModeFlag & DoubleScanMode)     temptemp >>= 1;
+      else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
 
-  Temp = (ULONG)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x01);
-  Temp++;
-  Temp <<= 3;
+      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+	  "Setting custom mode %dx%d on CRT2\n",
+	  SiS_Pr->CHDisplay, temptemp);
 
-  if(Temp == 1024) data = 0x0035;
-  else if(Temp == 1280) data = 0x0048;
-  else data = 0x0000;
+   } else {
 
-  Temp2 = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
-  Temp2 &= InterlaceMode;
-  if(Temp2 == 0) data=0x0000;
+      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+   	  "Setting standard mode 0x%x on CRT2\n", ModeNo);
 
-  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x19,data);
+   }
 
-  Temp = (ULONG)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x1A);
-  Temp = (USHORT)(Temp & 0xFC);
-  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x1A,(USHORT)Temp);
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
 
-  Temp = (ULONG)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x0f);
-  Temp2 = (USHORT)Temp & 0xBF;
-  if(ModeNo==0x37) Temp2 |= 0x40;
-  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x1A,(USHORT)Temp2);
-}
-#endif
+   SiS_UnLockCRT2(SiS_Pr, HwInfo);
 
-#ifdef SIS315H
-void
-SiS_SetCRT1FIFO_310(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-  USHORT modeflag;
+   if(!SiS_Pr->UseCustomMode) {
+      if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
+   } else {
+      ModeIdIndex = 0;
+   }
 
-  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE);  /* disable auto-threshold */
+   SiS_GetVBType(SiS_Pr, HwInfo);
 
-  if(ModeNo > 0x13) {
-    if(SiS_Pr->UseCustomMode) {
-       modeflag = SiS_Pr->CModeFlag;
-    } else {
-       modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    }       
-    if( (!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,0x34);
-       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
-       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
-    } else {
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,0xAE);
-       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
-    }
-  } else {
-    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,0xAE);
-    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
-  }
-}
-#endif
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(HwInfo->jChipType >= SIS_315H) {
+         SiS_UnLockCRT2(SiS_Pr,HwInfo);
+         if(ROMAddr && SiS_Pr->SiS_UseROM) {
+	    if(HwInfo->jChipType < SIS_330) {
+               temp = ROMAddr[VB310Data_1_2_Offset];
+	       temp |= 0x40;
+               SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
+            }
+	    if(HwInfo->jChipType > SIS_330) {
+	       temp = ROMAddr[0x7e];
+	       if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x7b) >= 100) temp |= 0x40;
+	       SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
+	    }
+	 }
+	 SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
 
-#ifdef SIS300
-void
-SiS_SetCRT1FIFO_300(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                    USHORT RefreshRateTableIndex)
-{
-  USHORT  ThresholdLow = 0;
-  USHORT  index, VCLK, MCLK, colorth=0;
-  USHORT  tempah, temp;
+	 SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c);
 
-  if(ModeNo > 0x13) {
+         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+      } else {
+         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+      }
+   }
 
-     if(SiS_Pr->UseCustomMode) {
-        VCLK = SiS_Pr->CSRClock;
-     } else {
-        index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-        index &= 0x3F;
-        VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;             /* Get VCLK  */
-     }
+   /* Get VB information (connectors, connected devices) */
+   if(!SiS_Pr->UseCustomMode) {
+      SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, 1);
+   } else {
+      /* If this is a custom mode, we don't check the modeflag for CRT2Mode */
+      SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, 0);
+   }
+   SiS_SetYPbPr(SiS_Pr, HwInfo);
+   SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo);
 
-     switch (SiS_Pr->SiS_ModeType - ModeEGA) {     /* Get half colordepth */
-        case 0 : colorth = 1; break;
-        case 1 : colorth = 1; break;
-        case 2 : colorth = 2; break;
-        case 3 : colorth = 2; break;
-        case 4 : colorth = 3; break;
-        case 5 : colorth = 4; break;
-     }
+   /* Set mode on CRT2 */
+   if( (SiS_Pr->SiS_VBType & VB_SISVB)    ||
+       (SiS_Pr->SiS_IF_DEF_LVDS     == 1) ||
+       (SiS_Pr->SiS_IF_DEF_CH70xx   != 0) ||
+       (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) {
+      SiS_SetCRT2Group(SiS_Pr, HwInfo, ModeNo);
+   }
 
-     index = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A);
-     index &= 0x07;
-     MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;           /* Get MCLK  */
+   SiS_StrangeStuff(SiS_Pr, HwInfo);
 
-     tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x35);
-     tempah &= 0xc3;
-     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3c,tempah);
+   SiS_DisplayOn(SiS_Pr);
+   SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
 
-     do {
-        ThresholdLow = SiS_CalcDelay(SiS_Pr, ROMAddr, VCLK, colorth, MCLK);
-        ThresholdLow++;
-        if(ThresholdLow < 0x13) break;
-        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x16,0xfc);
-        ThresholdLow = 0x13;
-        tempah = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
-        tempah >>= 6;
-        if(!(tempah)) break;
-        tempah--;
-        tempah <<= 6;
-        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3f,tempah);
-     } while(0);
+   if(HwInfo->jChipType >= SIS_315H) {
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+         if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) {
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
+	 }
+      }
+   }
 
-  } else ThresholdLow = 2;
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(HwInfo->jChipType >= SIS_315H) {
+         if(HwInfo->jChipType < SIS_661) {
+	    if(SiS_IsVAMode(SiS_Pr,HwInfo)) {
+	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
+	    } else {
+	       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE);
+	    }
+	 }
 
-  /* Write CRT/CPU threshold low, CRT/Engine threshold high */
-  temp = (ThresholdLow << 4) | 0x0f;
-  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,temp);
+	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
 
-  temp = (ThresholdLow & 0x10) << 1;
-  if(ModeNo > 0x13) temp |= 0x40;
-  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0f,0x9f,temp);
+	 tempr1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+	 tempr2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00);
+	 if(tempr1 & SetCRT2ToAVIDEO) tempr2 &= 0xF7;
+	 else			      tempr2 |= 0x08;
+	 if(tempr1 & SetCRT2ToSVIDEO) tempr2 &= 0xFB;
+	 else			      tempr2 |= 0x04;
+	 SiS_SetReg(SiS_Pr->SiS_Part2Port,0x00,tempr2);
 
-  /* What is this? */
-  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x3B,0x09);
+	 if(tempr1 & SetCRT2ToLCD) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc);
+	 }
+      } else if((HwInfo->jChipType == SIS_630) ||
+                (HwInfo->jChipType == SIS_730)) {
+         SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
+      }
+   }
 
-  /* Write CRT/CPU threshold high */
-  temp = ThresholdLow + 3;
-  if(temp > 0x0f) temp = 0x0f;
-  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x09,temp);
+   /* SetPitch: Adapt to virtual size & position */
+   SiS_SetPitchCRT2(SiS_Pr, pScrn);
+
+   return TRUE;
 }
 
-USHORT
-SiS_CalcDelay(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT VCLK, USHORT colordepth, USHORT MCLK)
+/*********************************************/
+/*       XFree86: SiSBIOSSetModeCRT1()       */
+/*           for Dual-Head modes             */
+/*********************************************/
+
+BOOLEAN
+SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn,
+                   DisplayModePtr mode, BOOLEAN IsCustom)
 {
-  USHORT tempax, tempbx;
+   SISPtr  pSiS = SISPTR(pScrn);
+   SISIOADDRESS BaseAddr = HwInfo->ulIOAddress;
+   USHORT  ModeIdIndex, ModeNo=0;
+   UCHAR backupreg=0;
+#ifdef SISDUALHEAD
+   SISEntPtr pSiSEnt = pSiS->entityPrivate;
+   UCHAR backupcr30, backupcr31, backupcr38, backupcr35, backupp40d=0;
+   BOOLEAN backupcustom;
+#endif
 
-  tempbx = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 0);
-  tempax = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 1);
-  if(tempax < 4) tempax = 4;
-  tempax -= 4;
-  if(tempbx < tempax) tempbx = tempax;
-  return(tempbx);
-}
+   SiS_Pr->UseCustomMode = FALSE;
 
-USHORT
-SiS_DoCalcDelay(SiS_Private *SiS_Pr, USHORT MCLK, USHORT VCLK, USHORT colordepth, USHORT key)
-{
-  const UCHAR ThLowA[]   = { 61, 3,52, 5,68, 7,100,11,
-                             43, 3,42, 5,54, 7, 78,11,
-                             34, 3,37, 5,47, 7, 67,11 };
+   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
 
-  const UCHAR ThLowB[]   = { 81, 4,72, 6,88, 8,120,12,
-                             55, 4,54, 6,66, 8, 90,12,
-                             42, 4,45, 6,55, 8, 75,12 };
+         USHORT temptemp = SiS_Pr->CVDisplay;
 
-  const UCHAR ThTiming[] = {  1, 2, 2, 3, 0, 1,  1, 2 };
+         if(SiS_Pr->CModeFlag & DoubleScanMode)     temptemp >>= 1;
+         else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
 
-  USHORT tempah, tempal, tempcl, tempbx, temp;
-  ULONG  longtemp;
+         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+	 	"Setting custom mode %dx%d on CRT1\n",
+	 	SiS_Pr->CHDisplay, temptemp);
+	 ModeNo = 0xfe;
 
-  tempah = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
-  tempah &= 0x62;
-  tempah >>= 1;
-  tempal = tempah;
-  tempah >>= 3;
-  tempal |= tempah;
-  tempal &= 0x07;
-  tempcl = ThTiming[tempal];
-  tempbx = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
-  tempbx >>= 6;
-  tempah = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
-  tempah >>= 4;
-  tempah &= 0x0c;
-  tempbx |= tempah;
-  tempbx <<= 1;
-  if(key == 0) {
-     tempal = ThLowA[tempbx + 1];
-     tempal *= tempcl;
-     tempal += ThLowA[tempbx];
-  } else {
-     tempal = ThLowB[tempbx + 1];
-     tempal *= tempcl;
-     tempal += ThLowB[tempbx];
-  }
-  longtemp = tempal * VCLK * colordepth;
-  temp = longtemp % (MCLK * 16);
-  longtemp /= (MCLK * 16);
-  if(temp) longtemp++;
-  return((USHORT)longtemp);
-}
+   } else {
 
-void
-SiS_SetCRT1FIFO_630(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
- 		    PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                    USHORT RefreshRateTableIndex)
-{
-  USHORT  i,index,data,VCLK,MCLK,colorth=0;
-  ULONG   B,eax,bl,data2;
-  USHORT  ThresholdLow=0;
-  UCHAR   FQBQData[]= { 
-  	0x01,0x21,0x41,0x61,0x81,
-        0x31,0x51,0x71,0x91,0xb1,
-        0x00,0x20,0x40,0x60,0x80,
-        0x30,0x50,0x70,0x90,0xb0,
-	0xFF
-  };
-  UCHAR   FQBQData730[]= {
-        0x34,0x74,0xb4,
-	0x23,0x63,0xa3,
-	0x12,0x52,0x92,
-	0x01,0x41,0x81,
-	0x00,0x40,0x80,
-	0xff
-  };
+         ModeNo = SiS_CalcModeIndex(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes);
+         if(!ModeNo) return FALSE;
 
-  i=0;
-  if(ModeNo > 0x13) {
-    if(SiS_Pr->UseCustomMode) {
-       VCLK = SiS_Pr->CSRClock;
-    } else {
-       index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-       index &= 0x3F;
-       VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;          /* Get VCLK  */
-    }       
+         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+	 	"Setting standard mode 0x%x on CRT1\n", ModeNo);
+   }
 
-    index = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
-    index &= 0x07;
-    MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;           /* Get MCLK  */
+   SiSInitPtr(SiS_Pr, HwInfo);
 
-    data2 = SiS_Pr->SiS_ModeType - ModeEGA;	  /* Get half colordepth */
-    switch (data2) {
-        case 0 : colorth = 1; break;
-        case 1 : colorth = 1; break;
-        case 2 : colorth = 2; break;
-        case 3 : colorth = 2; break;
-        case 4 : colorth = 3; break;
-        case 5 : colorth = 4; break;
-    }
+   SiSRegInit(SiS_Pr, BaseAddr);
 
-    if(HwDeviceExtension->jChipType == SIS_730) {
-    
-       do {
-          B = SiS_CalcDelay2(SiS_Pr, ROMAddr, FQBQData730[i], HwDeviceExtension) * VCLK * colorth;
-	  bl = B / (MCLK * 16);
+   SiS_GetSysFlags(SiS_Pr, HwInfo);
 
-          if(B == bl * 16 * MCLK) {
-             bl = bl + 1;
-          } else {
-             bl = bl + 2;
-          }
+   SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
 
-          if(bl > 0x13) {
-             if(FQBQData730[i+1] == 0xFF) {
-                ThresholdLow = 0x13;
-                break;
-             }
-             i++;
-          } else {
-             ThresholdLow = bl;
-             break;
-          }
-       } while(FQBQData730[i] != 0xFF);
-       
-    } else {
-    
-       do {
-          B = SiS_CalcDelay2(SiS_Pr, ROMAddr, FQBQData[i], HwDeviceExtension) * VCLK * colorth;
-          bl = B / (MCLK * 16);
+   SiSInitPCIetc(SiS_Pr, HwInfo);
+
+   SiSSetLVDSetc(SiS_Pr, HwInfo);
+
+   SiSDetermineROMUsage(SiS_Pr, HwInfo);
+
+   /* We don't clear the buffer under X */
+   SiS_Pr->SiS_flag_clearbuffer = 0;
 
-          if(B == bl * 16 * MCLK) {
-             bl = bl + 1;
-          } else {
-             bl = bl + 2;
-          }
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
 
-          if(bl > 0x13) {
-             if(FQBQData[i+1] == 0xFF) {
-                ThresholdLow = 0x13;
-                break;
-             }
-             i++;
-          } else {
-             ThresholdLow = bl;
-             break;
-          }
-       } while(FQBQData[i] != 0xFF);
-    }
-  }
-  else {
-    if(HwDeviceExtension->jChipType == SIS_730) { 
-    } else {
-      i = 9;
-    }
-    ThresholdLow = 0x02;
-  }
+   SiS_UnLockCRT2(SiS_Pr, HwInfo);
 
-  /* Write foreground and background queue */
-  if(HwDeviceExtension->jChipType == SIS_730) {  
-   
-     data2 = FQBQData730[i];
-     data2 = (data2 & 0xC0) >> 5;
-     data2 <<= 8;
+   if(!SiS_Pr->UseCustomMode) {
+      if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
+   } else {
+      ModeIdIndex = 0;
+   }
 
-#ifndef LINUX_XF86
-     SiS_SetReg4(0xcf8,0x80000050);
-     eax = SiS_GetReg3(0xcfc);
-     eax &= 0xfffff9ff;
-     eax |= data2;
-     SiS_SetReg4(0xcfc,eax);
-#else
-     /* We use pci functions X offers. We use pcitag 0, because
-      * we want to read/write to the host bridge (which is always
-      * 00:00.0 on 630, 730 and 540), not the VGA device.
-      */
-     eax = pciReadLong(0x00000000, 0x50);
-     eax &= 0xfffff9ff;
-     eax |= data2;
-     pciWriteLong(0x00000000, 0x50, eax);
+   /* Determine VBType */
+   SiS_GetVBType(SiS_Pr, HwInfo);
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(HwInfo->jChipType >= SIS_315H) {
+         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+      } else {
+         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+      }
+   }
+
+   /* Get VB information (connectors, connected devices) */
+   /* (We don't care if the current mode is a CRT2 mode) */
+   SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, 0);
+   SiS_SetYPbPr(SiS_Pr, HwInfo);
+   SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo);
+
+   if(HwInfo->jChipType >= SIS_315H) {
+#if 0
+      if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
+         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+            if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= SetDOSMode;
+         } else if((IS_SIS651) && (SiS_Pr->SiS_VBType & VB_NoLCD)) {
+            SiS_Pr->SiS_SetFlag |= SetDOSMode;
+         }
+      }
 #endif
 
-     /* Write GUI grant timer (PCI config 0xA3) */
-     data2 = FQBQData730[i] << 8;
-     data2 = (data2 & 0x0f00) | ((data2 & 0x3000) >> 8);
-     data2 <<= 20;
-     
-#ifndef LINUX_XF86
-     SiS_SetReg4(0xcf8,0x800000A0);
-     eax = SiS_GetReg3(0xcfc);
-     eax &= 0x00ffffff;
-     eax |= data2;
-     SiS_SetReg4(0xcfc,eax);
-#else
-     eax = pciReadLong(0x00000000, 0xA0);
-     eax &= 0x00ffffff;
-     eax |= data2;
-     pciWriteLong(0x00000000, 0xA0, eax);
-#endif          
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+         if(IS_SIS650) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
+	    if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20);
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
+	 } else if(IS_SIS661741660760) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef);
+	 }
+      }
+   }
 
-  } else {
-  
-     data2 = FQBQData[i];
-     data2 = (data2 & 0xf0) >> 4;
-     data2 <<= 24;
+   /* Set mode on CRT1 */
+   SiS_SetCRT1Group(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+      SiS_SetCRT2Group(SiS_Pr, HwInfo, ModeNo);
+   }
 
-#ifndef LINUX_XF86
-     SiS_SetReg4(0xcf8,0x80000050);
-     eax = SiS_GetReg3(0xcfc);
-     eax &= 0xf0ffffff;
-     eax |= data2;
-     SiS_SetReg4(0xcfc,eax);
-#else
-     eax = pciReadLong(0x00000000, 0x50);
-     eax &= 0xf0ffffff;
-     eax |= data2;
-     pciWriteLong(0x00000000, 0x50, eax);
+   /* SetPitch: Adapt to virtual size & position */
+   SiS_SetPitchCRT1(SiS_Pr, pScrn);
+
+#ifdef SISDUALHEAD
+   if(pSiS->DualHeadMode) {
+      pSiSEnt->CRT1ModeNo = ModeNo;
+      pSiSEnt->CRT1DMode = mode;
+   }
 #endif
 
-     /* Write GUI grant timer (PCI config 0xA3) */
-     data2 = FQBQData[i];
-     data2 &= 0x0f;
-     data2 <<= 24;
+   if(SiS_Pr->UseCustomMode) {
+      SiS_Pr->CRT1UsesCustomMode = TRUE;
+      SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
+      SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
+   } else {
+      SiS_Pr->CRT1UsesCustomMode = FALSE;
+   }
 
-#ifndef LINUX_XF86
-     SiS_SetReg4(0xcf8,0x800000A0);
-     eax = SiS_GetReg3(0xcfc);
-     eax &= 0xf0ffffff;
-     eax |= data2;
-     SiS_SetReg4(0xcfc,eax);
-#else
-     eax = pciReadLong(0x00000000, 0xA0);
-     eax &= 0xf0ffffff;
-     eax |= data2;
-     pciWriteLong(0x00000000, 0xA0, eax);
+   /* Reset CRT2 if changing mode on CRT1 */
+#ifdef SISDUALHEAD
+   if(pSiS->DualHeadMode) {
+      if(pSiSEnt->CRT2ModeNo != -1) {
+         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+				"(Re-)Setting mode for CRT2\n");
+	 backupcustom = SiS_Pr->UseCustomMode;
+	 backupcr30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+	 backupcr31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31);
+	 backupcr35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+	 backupcr38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+	 if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	    /* Backup LUT-enable */
+	    if(pSiSEnt->CRT2ModeSet) {
+	       backupp40d = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0d) & 0x08;
+	    }
+	 }
+	 if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,pSiSEnt->CRT2CR30);
+	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,pSiSEnt->CRT2CR31);
+	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,pSiSEnt->CRT2CR35);
+	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,pSiSEnt->CRT2CR38);
+	 }
+	 SiSBIOSSetModeCRT2(SiS_Pr, HwInfo, pSiSEnt->pScrn_1,
+			    pSiSEnt->CRT2DMode, pSiSEnt->CRT2IsCustom);
+         SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,backupcr30);
+	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,backupcr31);
+	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupcr35);
+	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupcr38);
+	 if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	    SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d, ~0x08, backupp40d);
+	 }
+	 SiS_Pr->UseCustomMode = backupcustom;
+      }
+   }
 #endif
-     
-  }
 
-  /* Write CRT/CPU threshold low, CRT/Engine threshold high */
-  data = ((ThresholdLow & 0x0f) << 4) | 0x0f;
-  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,data);
+   /* Warning: From here, the custom mode entries in SiS_Pr are
+    * possibly overwritten
+    */
 
-  data = (ThresholdLow & 0x10) << 1;
-  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xDF,data);
+   SiS_HandleCRT1(SiS_Pr);
 
-  /* What is this? */
-  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x3B,0x09);
+   SiS_StrangeStuff(SiS_Pr, HwInfo);
 
-  /* Write CRT/CPU threshold high (gap = 3) */
-  data = ThresholdLow + 3;
-  if(data > 0x0f) data = 0x0f;
-  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data);
-}
+   SiS_DisplayOn(SiS_Pr);
+   SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
 
-USHORT
-SiS_CalcDelay2(SiS_Private *SiS_Pr, UCHAR *ROMAddr,UCHAR key, PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-  USHORT data,index;
-  const UCHAR  LatencyFactor[] = { 
-   	97, 88, 86, 79, 77, 00,       /*; 64  bit    BQ=2   */
-        00, 87, 85, 78, 76, 54,       /*; 64  bit    BQ=1   */
-        97, 88, 86, 79, 77, 00,       /*; 128 bit    BQ=2   */
-        00, 79, 77, 70, 68, 48,       /*; 128 bit    BQ=1   */
-        80, 72, 69, 63, 61, 00,       /*; 64  bit    BQ=2   */
-        00, 70, 68, 61, 59, 37,       /*; 64  bit    BQ=1   */
-        86, 77, 75, 68, 66, 00,       /*; 128 bit    BQ=2   */
-        00, 68, 66, 59, 57, 37        /*; 128 bit    BQ=1   */
-  };
-  const UCHAR  LatencyFactor730[] = {
-         69, 63, 61, 
-	 86, 79, 77,
-	103, 96, 94,
-	120,113,111,
-	137,130,128,    /* --- Table ends with this entry, data below */
-	137,130,128,	/* to avoid using illegal values              */
-	137,130,128,
-	137,130,128,
-	137,130,128,
-	137,130,128,
-	137,130,128,
-	137,130,128,
-	137,130,128,
-	137,130,128,
-	137,130,128,
-	137,130,128,
-  };
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(HwInfo->jChipType >= SIS_315H) {
+	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
+      } else if((HwInfo->jChipType == SIS_630) ||
+                (HwInfo->jChipType == SIS_730)) {
+         SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
+      }
+   }
 
-  if(HwDeviceExtension->jChipType == SIS_730) {
-     index = ((key & 0x0f) * 3) + ((key & 0xC0) >> 6);
-     data = LatencyFactor730[index];
-  } else {			    
-     index = (key & 0xE0) >> 5;
-     if(key & 0x10) index +=6;
-     if(!(key & 0x01)) index += 24;
-     data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
-     if(data & 0x0080) index += 12;
-     data = LatencyFactor[index];
-  }
-  return(data);
+   /* Backup/Set ModeNo in BIOS scratch area */
+   SiS_GetSetModeID(pScrn,ModeNo);
+
+   return TRUE;
 }
-#endif
+#endif /* Linux_XF86 */
+
 
 #ifdef LINUX_XF86
 BOOLEAN
-SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
   const USHORT PanelTypeTable300[16] = {
       0xc101, 0xc117, 0x0121, 0xc135, 0xc142, 0xc152, 0xc162, 0xc072,
@@ -3596,65 +4255,68 @@
       0xc111, 0xc122, 0xc133, 0xc144, 0xc155, 0xc166, 0xc177, 0xc188,
       0xc199, 0xc0aa, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
   };
-  USHORT tempax,tempbx,tempah,temp;
+  USHORT tempax,tempbx,temp;
 
-  if(HwDeviceExtension->jChipType < SIS_315H) {
+  if(HwInfo->jChipType < SIS_315H) {
 
-    tempax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
-    tempbx = tempax & 0x0F;
-    if(!(tempax & 0x10)){
-      if(SiS_Pr->SiS_IF_DEF_LVDS == 1){
-        tempbx = 0;
-        temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x38);
-        if(temp & 0x40) tempbx |= 0x08;
-        if(temp & 0x20) tempbx |= 0x02;
-        if(temp & 0x01) tempbx |= 0x01;
-        temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x39);
-        if(temp & 0x80) tempbx |= 0x04;
-      } else {
-        return 0;
-      }
-    }
-    tempbx = PanelTypeTable300[tempbx];
-    tempbx |= LCDSync;
-    temp = tempbx & 0x00FF;
-    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,temp);
-    temp = (tempbx & 0xFF00) >> 8;
-    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp);
+     tempax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18);
+     tempbx = tempax & 0x0F;
+     if(!(tempax & 0x10)){
+        if(SiS_Pr->SiS_IF_DEF_LVDS == 1){
+           tempbx = 0;
+           temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x38);
+           if(temp & 0x40) tempbx |= 0x08;
+           if(temp & 0x20) tempbx |= 0x02;
+           if(temp & 0x01) tempbx |= 0x01;
+           temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x39);
+           if(temp & 0x80) tempbx |= 0x04;
+        } else {
+           return 0;
+        }
+     }
+     tempbx = PanelTypeTable300[tempbx];
+     tempbx |= LCDSync;
+     temp = tempbx & 0x00FF;
+     SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,temp);
+     temp = (tempbx & 0xFF00) >> 8;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp);
 
   } else {
 
-    tempax = tempah = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1a);
-    tempax &= 0x1e;
-    tempax >>= 1;
-    if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-       if(tempax == 0) {
+     if(HwInfo->jChipType >= SIS_661) return 0;
+
+     tempax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1a);
+     tempax &= 0x1e;
+     tempax >>= 1;
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+        if(tempax == 0) {
            /* TODO: Include HUGE detection routine
 	            (Probably not worth bothering)
 	    */
            return 0;
-       }
-       temp = tempax & 0xff;
-       tempax--;
-       tempbx = PanelTypeTable310LVDS[tempax];
-    } else {
-       tempbx = PanelTypeTable31030x[tempax];
-       temp = tempbx & 0xff;
-    }
-    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,temp);
-    tempbx = (tempbx & 0xff00) >> 8;
-    temp = tempbx & 0xc1;
-    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp);
-    if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
-       temp = tempbx & 0x04;
-       SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x39,0xfb,temp);
-    }
+        }
+        temp = tempax & 0xff;
+        tempax--;
+        tempbx = PanelTypeTable310LVDS[tempax];
+     } else {
+        tempbx = PanelTypeTable31030x[tempax];
+        temp = tempbx & 0xff;
+     }
+     SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,temp);
+     tempbx = (tempbx & 0xff00) >> 8;
+     temp = tempbx & 0xc1;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp);
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+        temp = tempbx & 0x04;
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x39,0xfb,temp);
+     }
 
   }
   return 1;
 }
 #endif
 
+
 /* ================ XFREE86 ================= */
 
 /* Helper functions */
@@ -3691,17 +4353,17 @@
    pSiS->SiS_Pr->CFlags = mode->Flags;
 
    if(pSiS->SiS_Pr->CFlags & V_INTERLACE) {
-         pSiS->SiS_Pr->CVDisplay >>= 1;
-	 pSiS->SiS_Pr->CVSyncStart >>= 1;
-	 pSiS->SiS_Pr->CVSyncEnd >>= 1;
-	 pSiS->SiS_Pr->CVTotal >>= 1;
+      pSiS->SiS_Pr->CVDisplay >>= 1;
+      pSiS->SiS_Pr->CVSyncStart >>= 1;
+      pSiS->SiS_Pr->CVSyncEnd >>= 1;
+      pSiS->SiS_Pr->CVTotal >>= 1;
    }
    if(pSiS->SiS_Pr->CFlags & V_DBLSCAN) {
-         /* pSiS->SiS_Pr->CDClock <<= 1; */
-	 pSiS->SiS_Pr->CVDisplay <<= 1;
-	 pSiS->SiS_Pr->CVSyncStart <<= 1;
-	 pSiS->SiS_Pr->CVSyncEnd <<= 1;
-	 pSiS->SiS_Pr->CVTotal <<= 1;
+      /* pSiS->SiS_Pr->CDClock <<= 1; */
+      pSiS->SiS_Pr->CVDisplay <<= 1;
+      pSiS->SiS_Pr->CVSyncStart <<= 1;
+      pSiS->SiS_Pr->CVSyncEnd <<= 1;
+      pSiS->SiS_Pr->CVTotal <<= 1;
    }
 
    pSiS->SiS_Pr->CHBlankStart = pSiS->SiS_Pr->CHDisplay;
@@ -3807,21 +4469,26 @@
    }	
    
    if(pSiS->SiS_Pr->CFlags & V_DBLSCAN) 
-   	pSiS->SiS_Pr->CModeFlag |= DoubleScanMode;
-   if((pSiS->SiS_Pr->CVDisplay >= 1024)	|| 
-      (pSiS->SiS_Pr->CVTotal >= 1024)   || 
+      pSiS->SiS_Pr->CModeFlag |= DoubleScanMode;
+
+   if((pSiS->SiS_Pr->CVDisplay >= 1024)	||
+      (pSiS->SiS_Pr->CVTotal >= 1024)   ||
       (pSiS->SiS_Pr->CHDisplay >= 1024))
-	pSiS->SiS_Pr->CModeFlag |= LineCompareOff;
+      pSiS->SiS_Pr->CModeFlag |= LineCompareOff;
+
    if(pSiS->SiS_Pr->CFlags & V_CLKDIV2)
-        pSiS->SiS_Pr->CModeFlag |= HalfDCLK;
+      pSiS->SiS_Pr->CModeFlag |= HalfDCLK;
 
    pSiS->SiS_Pr->CInfoFlag = 0x0007;
+
    if(pSiS->SiS_Pr->CFlags & V_NHSYNC)
-   	pSiS->SiS_Pr->CInfoFlag |= 0x4000;
-   if(pSiS->SiS_Pr->CFlags & V_NVSYNC) 
-   	pSiS->SiS_Pr->CInfoFlag |= 0x8000;
-   if(pSiS->SiS_Pr->CFlags & V_INTERLACE)	
-	pSiS->SiS_Pr->CInfoFlag |= InterlaceMode;
+      pSiS->SiS_Pr->CInfoFlag |= 0x4000;
+
+   if(pSiS->SiS_Pr->CFlags & V_NVSYNC)
+      pSiS->SiS_Pr->CInfoFlag |= 0x8000;
+
+   if(pSiS->SiS_Pr->CFlags & V_INTERLACE)
+      pSiS->SiS_Pr->CInfoFlag |= InterlaceMode;
 
    pSiS->SiS_Pr->UseCustomMode = TRUE;
 #ifdef TWDEBUG
@@ -3856,7 +4523,7 @@
    return 1;
 }
 
-/* TW: Build a list of supported modes */
+/* Build a list of supported modes */
 DisplayModePtr
 SiSBuildBuiltInModeList(ScrnInfoPtr pScrn, BOOLEAN includelcdmodes, BOOLEAN isfordvi)
 {
@@ -3879,15 +4546,15 @@
    /* Initialize our pointers */
    if(pSiS->VGAEngine == SIS_300_VGA) {
 #ifdef SIS300
-	InitTo300Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext);
+      InitTo300Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext);
 #else
-	return NULL;
+      return NULL;
 #endif
    } else if(pSiS->VGAEngine == SIS_315_VGA) {
 #ifdef SIS315H
-       	InitTo310Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext);
+      InitTo310Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext);
 #else
-	return NULL;
+      return NULL;
 #endif
    } else return NULL;
 
@@ -3895,9 +4562,6 @@
    while(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag != 0xFFFF) {
 
       index = pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRT1CRTC;
-#if 0 /* Not any longer */    
-      if(pSiS->VGAEngine == SIS_300_VGA) index &= 0x3F;
-#endif      
 
       /* 0x5a (320x240) is a pure FTSN mode, not DSTN! */
       if((!pSiS->FSTN) &&
@@ -4196,6 +4860,8 @@
 	current->name, (float)current->Clock / 1000,
 	current->HDisplay, current->HSyncStart, current->HSyncEnd, current->HTotal,
 	current->VDisplay, current->VSyncStart, current->VSyncEnd, current->VTotal);
+#else
+        (void)VBS;  (void)HBS;  (void)A;
 #endif
 
       i++;
@@ -4205,8 +4871,10 @@
 
    if(!includelcdmodes) return first;
 
-   xf86DrvMsg(0, X_INFO, "Checking database for vendor %x, product %x\n",
-      pSiS->SiS_Pr->CP_Vendor, pSiS->SiS_Pr->CP_Product);
+   if(pSiS->SiS_Pr->CP_Vendor) {
+      xf86DrvMsg(0, X_INFO, "Checking database for vendor %x, product %x\n",
+         pSiS->SiS_Pr->CP_Vendor, pSiS->SiS_Pr->CP_Product);
+   }
 
    i = 0;
    while((!done) && (SiS_PlasmaTable[i].vendor) && (pSiS->SiS_Pr->CP_Vendor)) {
@@ -4385,78 +5053,106 @@
    return first;
 
 }
+
+/* Build a list of supported modes */
+int
+SiSTranslateToVESA(ScrnInfoPtr pScrn, int modenumber)
+{
+   SISPtr         pSiS = SISPTR(pScrn);
+   int i;
+
+   /* Initialize our pointers */
+   if(pSiS->VGAEngine == SIS_300_VGA) {
+#ifdef SIS300
+	InitTo300Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext);
+#else
+	return -1;
 #endif
+   } else if(pSiS->VGAEngine == SIS_315_VGA) {
+#ifdef SIS315H
+       	InitTo310Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext);
+#else
+	return -1;
+#endif
+   } else return -1;
+
+   if(modenumber <= 0x13) return modenumber;
+
+   i = 0;
+   while(pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID != 0xff) {
+      if(pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID == modenumber) {
+         return (int)pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID;
+      }
+      i++;
+   }
+   return -1;
+}
+#endif  /* Xfree86 */
 
 #ifdef LINUX_KERNEL
 int
-sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
 			  unsigned char modeno, unsigned char rateindex)
 {
     USHORT ModeNo = modeno;
     USHORT ModeIdIndex = 0, ClockIndex = 0;
     USHORT RefreshRateTableIndex = 0;
-    UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
-    ULONG  temp = 0;
     int    Clock;
 
-    if(HwDeviceExtension->jChipType < SIS_315H) {
+    if(HwInfo->jChipType < SIS_315H) {
 #ifdef SIS300
-       InitTo300Pointer(SiS_Pr, HwDeviceExtension);
+       InitTo300Pointer(SiS_Pr, HwInfo);
 #else
-       return 65 * 1000 * 1000;
+       return 65 * 1000;
 #endif
     } else {
 #ifdef SIS315H
-       InitTo310Pointer(SiS_Pr, HwDeviceExtension);
+       InitTo310Pointer(SiS_Pr, HwInfo);
 #else
-       return 65 * 1000 * 1000;
+       return 65 * 1000;
 #endif
     }
 
-    temp = SiS_SearchModeID(SiS_Pr, ROMAddr, &ModeNo, &ModeIdIndex);
-    if(!temp) {
+    if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {;
     	printk(KERN_ERR "Could not find mode %x\n", ModeNo);
-    	return 65 * 1000 * 1000;
+    	return 65 * 1000;
     }
-    
+
     RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
     RefreshRateTableIndex += (rateindex - 1);
     ClockIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-    if(HwDeviceExtension->jChipType < SIS_315H) {
+    if(HwInfo->jChipType < SIS_315H) {
        ClockIndex &= 0x3F;
     }
-    Clock = SiS_Pr->SiS_VCLKData[ClockIndex].CLOCK * 1000 * 1000;
+    Clock = SiS_Pr->SiS_VCLKData[ClockIndex].CLOCK * 1000;
     
     return(Clock);
 }
 
 BOOLEAN
-sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
 		       unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex)
 {
     USHORT ModeNo = modeno;
     USHORT ModeIdIndex = 0, CRT1Index = 0;
     USHORT RefreshRateTableIndex = 0;
-    UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
-    ULONG  temp = 0;
     unsigned char  sr_data, cr_data, cr_data2;
 
-    if(HwDeviceExtension->jChipType < SIS_315H) {
+    if(HwInfo->jChipType < SIS_315H) {
 #ifdef SIS300
-       InitTo300Pointer(SiS_Pr, HwDeviceExtension);
+       InitTo300Pointer(SiS_Pr, HwInfo);
 #else
        return FALSE;
 #endif
     } else {
 #ifdef SIS315H
-       InitTo310Pointer(SiS_Pr, HwDeviceExtension);
+       InitTo310Pointer(SiS_Pr, HwInfo);
 #else
        return FALSE;
 #endif
     }
 
-    temp = SiS_SearchModeID(SiS_Pr, ROMAddr, &ModeNo, &ModeIdIndex);
-    if(!temp) return FALSE;
+    if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
 
     RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
     RefreshRateTableIndex += (rateindex - 1);
@@ -4481,7 +5177,7 @@
 }
 
 int
-sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
 			 unsigned char modeno, unsigned char rateindex,
 			 ULONG *left_margin, ULONG *right_margin, 
 			 ULONG *upper_margin, ULONG *lower_margin,
@@ -4491,29 +5187,27 @@
     USHORT ModeNo = modeno;
     USHORT ModeIdIndex = 0, index = 0;
     USHORT RefreshRateTableIndex = 0;
-    UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
     unsigned short VRE, VBE, VRS, VBS, VDE, VT;
     unsigned short HRE, HBE, HRS, HBS, HDE, HT;
     unsigned char  sr_data, cr_data, cr_data2, cr_data3;
     int            A, B, C, D, E, F, temp, j;
    
-    if(HwDeviceExtension->jChipType < SIS_315H) {
+    if(HwInfo->jChipType < SIS_315H) {
 #ifdef SIS300
-       InitTo300Pointer(SiS_Pr, HwDeviceExtension);
+       InitTo300Pointer(SiS_Pr, HwInfo);
 #else
        return 0;
 #endif
     } else {
 #ifdef SIS315H
-       InitTo310Pointer(SiS_Pr, HwDeviceExtension);
+       InitTo310Pointer(SiS_Pr, HwInfo);
 #else
        return 0;
 #endif
     }
     
-    temp = SiS_SearchModeID(SiS_Pr, ROMAddr, &ModeNo, &ModeIdIndex);
-    if(!temp) return 0;
-    
+    if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return 0;
+
     RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
     RefreshRateTableIndex += (rateindex - 1);
     index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
@@ -4660,7 +5354,7 @@
     else
        *sync |= FB_SYNC_HOR_HIGH_ACT;
 		
-    *vmode = FB_VMODE_NONINTERLACED;       
+    *vmode = FB_VMODE_NONINTERLACED;
     if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x0080)
        *vmode = FB_VMODE_INTERLACED;
     else {

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)