Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / video / sis / sis_main.c
index 6982660..8adf5bf 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * SiS 300/305/540/630(S)/730(S)
- * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760
+ * SiS 300/540/630[S]/730[S],
+ * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
+ * XGI V3XT/V5/V8, Z7
  * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
  *
- * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
+ * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
  *
  * 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
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
  *
- * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
  *
  * Author of (practically wiped) code base:
  *             SiS (www.sis.com)
- *             Copyright (C) 1999 Silicon Integrated Systems, Inc.
+ *             Copyright (C) 1999 Silicon Integrated Systems, Inc.
  *
  * See http://www.winischhofer.net/ for more information and updates
  *
 #include <linux/mm.h>
 #include <linux/tty.h>
 #include <linux/slab.h>
-#include <linux/delay.h>
 #include <linux/fb.h>
-#include <linux/console.h>
 #include <linux/selection.h>
-#include <linux/smp_lock.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 #include <linux/vt_kern.h>
+#endif
 #include <linux/capability.h>
 #include <linux/fs.h>
 #include <linux/types.h>
@@ -94,71 +94,75 @@ extern struct display_switch fbcon_sis32;
 #endif
 #endif
 
+static void sisfb_handle_command(struct sis_video_info *ivideo,
+                                struct sisfb_cmd *sisfb_command);
+
 /* ------------------ Internal helper routines ----------------- */
 
 static void __init
 sisfb_setdefaultparms(void)
 {
-       sisfb_off               = 0;
-       sisfb_parm_mem          = 0;
-       sisfb_accel             = -1;
-       sisfb_ypan              = -1;
-       sisfb_max               = -1;
-       sisfb_userom            = -1;
-        sisfb_useoem           = -1;
+       sisfb_off               = 0;
+       sisfb_parm_mem          = 0;
+       sisfb_accel             = -1;
+       sisfb_ypan              = -1;
+       sisfb_max               = -1;
+       sisfb_userom            = -1;
+       sisfb_useoem            = -1;
 #ifdef MODULE
        /* Module: "None" for 2.4, default mode for 2.5+ */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-       sisfb_mode_idx          = -1;
+       sisfb_mode_idx          = -1;
 #else
-       sisfb_mode_idx          = MODE_INDEX_NONE;
+       sisfb_mode_idx          = MODE_INDEX_NONE;
 #endif
 #else
        /* Static: Default mode */
-       sisfb_mode_idx          = -1;
-#endif
-       sisfb_parm_rate         = -1;
-       sisfb_crt1off           = 0;
-       sisfb_forcecrt1         = -1;
-       sisfb_crt2type          = -1;
-       sisfb_crt2flags         = 0;
-       sisfb_pdc               = 0xff;
-       sisfb_pdca              = 0xff;
-       sisfb_scalelcd          = -1;
+       sisfb_mode_idx          = -1;
+#endif
+       sisfb_parm_rate         = -1;
+       sisfb_crt1off           = 0;
+       sisfb_forcecrt1         = -1;
+       sisfb_crt2type          = -1;
+       sisfb_crt2flags         = 0;
+       sisfb_pdc               = 0xff;
+       sisfb_pdca              = 0xff;
+       sisfb_scalelcd          = -1;
        sisfb_specialtiming     = CUT_NONE;
-       sisfb_lvdshl            = -1;
-       sisfb_dstn              = 0;
-       sisfb_fstn              = 0;
-       sisfb_tvplug            = -1;
-       sisfb_tvstd             = -1;
-       sisfb_tvxposoffset      = 0;
-       sisfb_tvyposoffset      = 0;
-       sisfb_filter            = -1;
-       sisfb_nocrt2rate        = 0;
+       sisfb_lvdshl            = -1;
+       sisfb_dstn              = 0;
+       sisfb_fstn              = 0;
+       sisfb_tvplug            = -1;
+       sisfb_tvstd             = -1;
+       sisfb_tvxposoffset      = 0;
+       sisfb_tvyposoffset      = 0;
+       sisfb_nocrt2rate        = 0;
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-       sisfb_inverse           = 0;
-       sisfb_fontname[0]       = 0;
+       sisfb_inverse           = 0;
+       sisfb_fontname[0]       = 0;
 #endif
 #if !defined(__i386__) && !defined(__x86_64__)
-       sisfb_resetcard         = 0;
-       sisfb_videoram          = 0;
+       sisfb_resetcard         = 0;
+       sisfb_videoram          = 0;
 #endif
 }
 
+/* ------------- Parameter parsing -------------- */
+
 static void __devinit
 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
 {
        int i = 0, j = 0;
 
-       /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+       /* We don't know the hardware specs yet and there is no ivideo */
 
        if(vesamode == 0) {
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
                sisfb_mode_idx = MODE_INDEX_NONE;
 #else
-               if(!quiet) {
-                  printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
-               }
+               if(!quiet)
+                       printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
+
                sisfb_mode_idx = DEFAULT_MODE;
 #endif
                return;
@@ -169,95 +173,102 @@ sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
        while(sisbios_mode[i++].mode_no[0] != 0) {
                if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
                    (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
-                   if(sisfb_fstn) {
-                      if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
-                         sisbios_mode[i-1].mode_no[1] == 0x56 ||
-                         sisbios_mode[i-1].mode_no[1] == 0x53) continue;
-                   } else {
-                      if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
-                         sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
-                   }
-                   sisfb_mode_idx = i - 1;
-                   j = 1;
-                   break;
+                       if(sisfb_fstn) {
+                               if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
+                                  sisbios_mode[i-1].mode_no[1] == 0x56 ||
+                                  sisbios_mode[i-1].mode_no[1] == 0x53)
+                                       continue;
+                       } else {
+                               if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
+                                  sisbios_mode[i-1].mode_no[1] == 0x5b)
+                                       continue;
+                       }
+                       sisfb_mode_idx = i - 1;
+                       j = 1;
+                       break;
                }
        }
-       if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
+       if((!j) && !quiet)
+               printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
 }
 
-static void
+static void __devinit
 sisfb_search_mode(char *name, BOOLEAN quiet)
 {
-       int i = 0;
        unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
+       int i = 0;
        char strbuf[16], strbuf1[20];
        char *nameptr = name;
 
-       /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+       /* We don't know the hardware specs yet and there is no ivideo */
 
        if(name == NULL) {
-          if(!quiet) {
-             printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
-          }
-          sisfb_mode_idx = DEFAULT_MODE;
-          return;
+               if(!quiet)
+                       printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
+
+               sisfb_mode_idx = DEFAULT_MODE;
+               return;
        }
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-        if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
-          if(!quiet) {
-             printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
-          }
-          sisfb_mode_idx = DEFAULT_MODE;
-          return;
+       if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
+               if(!quiet)
+                       printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
+
+               sisfb_mode_idx = DEFAULT_MODE;
+               return;
        }
 #endif
        if(strlen(name) <= 19) {
-          strcpy(strbuf1, name);
-          for(i=0; i<strlen(strbuf1); i++) {
-             if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
-          }
+               strcpy(strbuf1, name);
+               for(i = 0; i < strlen(strbuf1); i++) {
+                       if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
+               }
 
-          /* This does some fuzzy mode naming detection */
-          if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
-             if((rate <= 32) || (depth > 32)) {
-                j = rate; rate = depth; depth = j;
-             }
-             sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
-             nameptr = strbuf;
-             sisfb_parm_rate = rate;
-          } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
-             sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
-             nameptr = strbuf;
-          } else {
-             xres = 0;
-             if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
-                sprintf(strbuf, "%ux%ux8", xres, yres);
-                nameptr = strbuf;
-             } else {
-                sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
-                return;
-             }
-          }
+               /* This does some fuzzy mode naming detection */
+               if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
+                       if((rate <= 32) || (depth > 32)) {
+                               j = rate; rate = depth; depth = j;
+                       }
+                       sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
+                       nameptr = strbuf;
+                       sisfb_parm_rate = rate;
+               } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
+                       sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
+                       nameptr = strbuf;
+               } else {
+                       xres = 0;
+                       if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
+                               sprintf(strbuf, "%ux%ux8", xres, yres);
+                               nameptr = strbuf;
+                       } else {
+                               sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
+                               return;
+                       }
+               }
        }
 
        i = 0; j = 0;
        while(sisbios_mode[i].mode_no[0] != 0) {
                if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
-                       if(sisfb_fstn) {
-                               if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
-                                  sisbios_mode[i-1].mode_no[1] == 0x56 ||
-                                  sisbios_mode[i-1].mode_no[1] == 0x53) continue;
-                       } else {
-                               if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
-                                  sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
-                       }
-                       sisfb_mode_idx = i - 1;
-                       j = 1;
-                       break;
-               }
-       }
-       if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
+                       if(sisfb_fstn) {
+                               if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
+                                  sisbios_mode[i-1].mode_no[1] == 0x56 ||
+                                  sisbios_mode[i-1].mode_no[1] == 0x53)
+                                       continue;
+                       } else {
+                               if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
+                                  sisbios_mode[i-1].mode_no[1] == 0x5b)
+                                       continue;
+                       }
+                       sisfb_mode_idx = i - 1;
+                       j = 1;
+                       break;
+               }
+       }
+
+       if((!j) && !quiet)
+               printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
 }
 
 #ifndef MODULE
@@ -265,7 +276,7 @@ static void __devinit
 sisfb_get_vga_mode_from_kernel(void)
 {
 #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
-       char mymode[32];
+       char mymode[32];
        int  mydepth = screen_info.lfb_depth;
 
        if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
@@ -274,15 +285,17 @@ sisfb_get_vga_mode_from_kernel(void)
            (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
            (mydepth >= 8) && (mydepth <= 32) ) {
 
-           if(mydepth == 24) mydepth = 32;
+               if(mydepth == 24) mydepth = 32;
 
-           sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
-                                       screen_info.lfb_height,
+               sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
+                                       screen_info.lfb_height,
                                        mydepth);
 
-           printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode);
+               printk(KERN_DEBUG
+                       "sisfb: Using vga mode %s pre-set by kernel as default\n",
+                       mymode);
 
-           sisfb_search_mode(mymode, TRUE);
+               sisfb_search_mode(mymode, TRUE);
        }
 #endif
        return;
@@ -294,26 +307,25 @@ sisfb_search_crt2type(const char *name)
 {
        int i = 0;
 
-       /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+       /* We don't know the hardware specs yet and there is no ivideo */
 
        if(name == NULL) return;
 
        while(sis_crt2type[i].type_no != -1) {
-               if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
-                       sisfb_crt2type = sis_crt2type[i].type_no;
-                       sisfb_tvplug = sis_crt2type[i].tvplug_no;
-                       sisfb_crt2flags = sis_crt2type[i].flags;
-                       break;
-               }
-               i++;
+               if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
+                       sisfb_crt2type = sis_crt2type[i].type_no;
+                       sisfb_tvplug = sis_crt2type[i].tvplug_no;
+                       sisfb_crt2flags = sis_crt2type[i].flags;
+                       break;
+               }
+               i++;
        }
 
        sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
        sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
 
-       if(sisfb_crt2type < 0) {
+       if(sisfb_crt2type < 0)
                printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
-       }
 }
 
 static void __init
@@ -321,16 +333,17 @@ sisfb_search_tvstd(const char *name)
 {
        int i = 0;
 
-       /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+       /* We don't know the hardware specs yet and there is no ivideo */
 
-       if(name == NULL) return;
+       if(name == NULL)
+               return;
 
        while(sis_tvtype[i].type_no != -1) {
-               if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
-                       sisfb_tvstd = sis_tvtype[i].type_no;
-                       break;
-               }
-               i++;
+               if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
+                       sisfb_tvstd = sis_tvtype[i].type_no;
+                       break;
+               }
+               i++;
        }
 }
 
@@ -340,38 +353,101 @@ sisfb_search_specialtiming(const char *name)
        int i = 0;
        BOOLEAN found = FALSE;
 
-       /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+       /* We don't know the hardware specs yet and there is no ivideo */
 
-       if(name == NULL) return;
+       if(name == NULL)
+               return;
 
        if(!strnicmp(name, "none", 4)) {
-               sisfb_specialtiming = CUT_FORCENONE;
+               sisfb_specialtiming = CUT_FORCENONE;
                printk(KERN_DEBUG "sisfb: Special timing disabled\n");
        } else {
-          while(mycustomttable[i].chipID != 0) {
-             if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {
-                sisfb_specialtiming = mycustomttable[i].SpecialID;
-                found = TRUE;
-                printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
-                       mycustomttable[i].vendorName, mycustomttable[i].cardName,
-                       mycustomttable[i].optionName);
-                break;
-             }
-             i++;
-          }
-          if(!found) {
-             printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
-             printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
-             i = 0;
-             while(mycustomttable[i].chipID != 0) {
-                printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
-                    mycustomttable[i].optionName,
-                    mycustomttable[i].vendorName,
-                    mycustomttable[i].cardName);
-                i++;
-             }
-           }
-       }
+               while(mycustomttable[i].chipID != 0) {
+                       if(!strnicmp(name,mycustomttable[i].optionName,
+                          strlen(mycustomttable[i].optionName))) {
+                               sisfb_specialtiming = mycustomttable[i].SpecialID;
+                               found = TRUE;
+                               printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
+                                       mycustomttable[i].vendorName,
+                                       mycustomttable[i].cardName,
+                                       mycustomttable[i].optionName);
+                               break;
+                       }
+                       i++;
+               }
+               if(!found) {
+                       printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
+                       printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
+                       i = 0;
+                       while(mycustomttable[i].chipID != 0) {
+                               printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
+                                       mycustomttable[i].optionName,
+                                       mycustomttable[i].vendorName,
+                                       mycustomttable[i].cardName);
+                               i++;
+                       }
+               }
+       }
+}
+
+/* ----------- Various detection routines ----------- */
+
+static void __devinit
+sisfb_detect_custom_timing(struct sis_video_info *ivideo)
+{
+       unsigned char *biosver = NULL;
+       unsigned char *biosdate = NULL;
+       BOOLEAN footprint;
+       u32 chksum = 0;
+       int i, j;
+
+       if(ivideo->SiS_Pr.UseROM) {
+               biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
+               biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
+               for(i = 0; i < 32768; i++)
+                       chksum += ivideo->SiS_Pr.VirtualRomBase[i];
+       }
+
+       i = 0;
+       do {
+               if( (mycustomttable[i].chipID == ivideo->chip)                  &&
+                   ((!strlen(mycustomttable[i].biosversion)) ||
+                    (ivideo->SiS_Pr.UseROM &&
+                     (!strncmp(mycustomttable[i].biosversion, biosver,
+                               strlen(mycustomttable[i].biosversion)))))       &&
+                   ((!strlen(mycustomttable[i].biosdate)) ||
+                    (ivideo->SiS_Pr.UseROM &&
+                     (!strncmp(mycustomttable[i].biosdate, biosdate,
+                               strlen(mycustomttable[i].biosdate)))))          &&
+                   ((!mycustomttable[i].bioschksum) ||
+                    (ivideo->SiS_Pr.UseROM &&
+                     (mycustomttable[i].bioschksum == chksum)))                &&
+                   (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
+                   (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
+                       footprint = TRUE;
+                       for(j = 0; j < 5; j++) {
+                               if(mycustomttable[i].biosFootprintAddr[j]) {
+                                       if(ivideo->SiS_Pr.UseROM) {
+                                               if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
+                                                       mycustomttable[i].biosFootprintData[j]) {
+                                                       footprint = FALSE;
+                                               }
+                                       } else
+                                               footprint = FALSE;
+                               }
+                       }
+                       if(footprint) {
+                               ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
+                               printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
+                                       mycustomttable[i].vendorName,
+                               mycustomttable[i].cardName);
+                               printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
+                                       mycustomttable[i].optionName);
+                               break;
+                       }
+               }
+               i++;
+       } while(mycustomttable[i].chipID);
 }
 
 static BOOLEAN __devinit
@@ -384,22 +460,23 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
           buffer[2] != 0xff || buffer[3] != 0xff ||
           buffer[4] != 0xff || buffer[5] != 0xff ||
           buffer[6] != 0xff || buffer[7] != 0x00) {
-          printk(KERN_DEBUG "sisfb: Bad EDID header\n");
-          return FALSE;
+               printk(KERN_DEBUG "sisfb: Bad EDID header\n");
+               return FALSE;
        }
 
        if(buffer[0x12] != 0x01) {
-          printk(KERN_INFO "sisfb: EDID version %d not supported\n",
-               buffer[0x12]);
-          return FALSE;
+               printk(KERN_INFO "sisfb: EDID version %d not supported\n",
+                       buffer[0x12]);
+               return FALSE;
        }
 
        monitor->feature = buffer[0x18];
 
        if(!buffer[0x14] & 0x80) {
-          if(!(buffer[0x14] & 0x08)) {
-             printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n");
-          }
+               if(!(buffer[0x14] & 0x08)) {
+                       printk(KERN_INFO
+                               "sisfb: WARNING: Monitor does not support separate syncs\n");
+               }
        }
 
        if(buffer[0x13] >= 0x01) {
@@ -409,7 +486,7 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
            j = 0x36;
            for(i=0; i<4; i++) {
               if(buffer[j]     == 0x00 && buffer[j + 1] == 0x00 &&
-                 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
+                 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
                  buffer[j + 4] == 0x00) {
                  monitor->hmin = buffer[j + 7];
                  monitor->hmax = buffer[j + 8];
@@ -435,7 +512,7 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
           emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
           for(i = 0; i < 13; i++) {
              if(emodes & sisfb_ddcsmodes[i].mask) {
-                if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
+                if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
                 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
                 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
                 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
@@ -446,80 +523,81 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
           for(i = 0; i < 8; i++) {
              xres = (buffer[index] + 31) * 8;
              switch(buffer[index + 1] & 0xc0) {
-                case 0xc0: yres = (xres * 9) / 16; break;
-                case 0x80: yres = (xres * 4) /  5; break;
-                case 0x40: yres = (xres * 3) /  4; break;
-                default:   yres = xres;            break;
+                case 0xc0: yres = (xres * 9) / 16; break;
+                case 0x80: yres = (xres * 4) /  5; break;
+                case 0x40: yres = (xres * 3) /  4; break;
+                default:   yres = xres;            break;
              }
              refresh = (buffer[index + 1] & 0x3f) + 60;
              if((xres >= 640) && (yres >= 480)) {
-                 for(j = 0; j < 8; j++) {
-                   if((xres == sisfb_ddcfmodes[j].x) &&
-                      (yres == sisfb_ddcfmodes[j].y) &&
+                for(j = 0; j < 8; j++) {
+                   if((xres == sisfb_ddcfmodes[j].x) &&
+                      (yres == sisfb_ddcfmodes[j].y) &&
                       (refresh == sisfb_ddcfmodes[j].v)) {
                      if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
                      if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
                      if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
                      if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
-                     if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
-                   }
-                }
+                     if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
+                   }
+                }
              }
              index += 2;
-           }
+          }
           if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
              monitor->datavalid = TRUE;
           }
        }
 
-       return(monitor->datavalid);
+       return monitor->datavalid;
 }
 
 static void __devinit
 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
 {
-       USHORT  temp, i, realcrtno = crtno;
-       u8      buffer[256];
+       unsigned short temp, i, realcrtno = crtno;
+       unsigned char  buffer[256];
 
        monitor->datavalid = FALSE;
 
        if(crtno) {
-                  if(ivideo->vbflags & CRT2_LCD)      realcrtno = 1;
-          else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
-          else return;
-       }
+          if(ivideo->vbflags & CRT2_LCD)      realcrtno = 1;
+          else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
+          else return;
+       }
 
-       if((ivideo->sisfb_crt1off) && (!crtno)) return;
+       if((ivideo->sisfb_crt1off) && (!crtno))
+               return;
 
-       temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
-                               realcrtno, 0, &buffer[0]);
-       if((!temp) || (temp == 0xffff)) {
-          printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
+       temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
+                               realcrtno, 0, &buffer[0], ivideo->vbflags2);
+       if((!temp) || (temp == 0xffff)) {
+          printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
           return;
-       } else {
-          printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
-          printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
-               crtno + 1,
-               (temp & 0x1a) ? "" : "[none of the supported]",
-               (temp & 0x02) ? "2 " : "",
-               (temp & 0x08) ? "D&P" : "",
-               (temp & 0x10) ? "FPDI-2" : "");
-          if(temp & 0x02) {
+       } else {
+          printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
+          printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
+               crtno + 1,
+               (temp & 0x1a) ? "" : "[none of the supported]",
+               (temp & 0x02) ? "2 " : "",
+               (temp & 0x08) ? "D&P" : "",
+               (temp & 0x10) ? "FPDI-2" : "");
+          if(temp & 0x02) {
              i = 3;  /* Number of retrys */
              do {
-                temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
-                                    realcrtno, 1, &buffer[0]);
+                temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
+                                    realcrtno, 1, &buffer[0], ivideo->vbflags2);
              } while((temp) && i--);
-              if(!temp) {
-                if(sisfb_interpret_edid(monitor, &buffer[0])) {
+             if(!temp) {
+                if(sisfb_interpret_edid(monitor, &buffer[0])) {
                    printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
-                       monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
+                       monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
                        monitor->dclockmax / 1000);
                 } else {
-                   printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
-                }
+                   printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
+                }
              } else {
-                printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
+                printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
              }
           } else {
              printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
@@ -527,6 +605,8 @@ sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, i
        }
 }
 
+/* -------------- Mode validation --------------- */
+
 static BOOLEAN
 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
                int mode_idx, int rate_idx, int rate)
@@ -534,42 +614,49 @@ sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
        int htotal, vtotal;
        unsigned int dclock, hsync;
 
-       if(!monitor->datavalid) return TRUE;
+       if(!monitor->datavalid)
+               return TRUE;
 
-       if(mode_idx < 0) return FALSE;
+       if(mode_idx < 0)
+               return FALSE;
 
        /* Skip for 320x200, 320x240, 640x400 */
-       switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
-       case 0x59:
-       case 0x41:
-       case 0x4f:
-       case 0x50:
-       case 0x56:
-       case 0x53:
-       case 0x2f:
-       case 0x5d:
-       case 0x5e:
-               return TRUE;
+       switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
+       case 0x59:
+       case 0x41:
+       case 0x4f:
+       case 0x50:
+       case 0x56:
+       case 0x53:
+       case 0x2f:
+       case 0x5d:
+       case 0x5e:
+               return TRUE;
 #ifdef CONFIG_FB_SIS_315
        case 0x5a:
        case 0x5b:
                if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
 #endif
-       }
+       }
 
-       if(rate < (monitor->vmin - 1)) return FALSE;
-       if(rate > (monitor->vmax + 1)) return FALSE;
+       if(rate < (monitor->vmin - 1))
+               return FALSE;
+       if(rate > (monitor->vmax + 1))
+               return FALSE;
 
-       if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, &ivideo->sishw_ext,
+       if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
                                  sisbios_mode[mode_idx].mode_no[ivideo->mni],
-                                 &htotal, &vtotal, rate_idx)) {
+                                 &htotal, &vtotal, rate_idx)) {
                dclock = (htotal * vtotal * rate) / 1000;
-               if(dclock > (monitor->dclockmax + 1000)) return FALSE;
+               if(dclock > (monitor->dclockmax + 1000))
+                       return FALSE;
                hsync = dclock / htotal;
-               if(hsync < (monitor->hmin - 1)) return FALSE;
-               if(hsync > (monitor->hmax + 1)) return FALSE;
+               if(hsync < (monitor->hmin - 1))
+                       return FALSE;
+               if(hsync > (monitor->hmax + 1))
+                       return FALSE;
         } else {
-               return FALSE;
+               return FALSE;
        }
        return TRUE;
 }
@@ -577,82 +664,79 @@ sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
 static int
 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
 {
-   u16 xres=0, yres, myres;
+       u16 xres=0, yres, myres;
 
 #ifdef CONFIG_FB_SIS_300
-   if(ivideo->sisvga_engine == SIS_300_VGA) {
-      if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1);
-   }
+       if(ivideo->sisvga_engine == SIS_300_VGA) {
+               if(!(sisbios_mode[myindex].chipset & MD_SIS300))
+                       return -1 ;
+       }
 #endif
 #ifdef CONFIG_FB_SIS_315
-   if(ivideo->sisvga_engine == SIS_315_VGA) {
-      if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1);
-   }
+       if(ivideo->sisvga_engine == SIS_315_VGA) {
+               if(!(sisbios_mode[myindex].chipset & MD_SIS315))
+                       return -1;
+       }
 #endif
 
-   myres = sisbios_mode[myindex].yres;
+       myres = sisbios_mode[myindex].yres;
 
-   switch(vbflags & VB_DISPTYPE_DISP2) {
+       switch(vbflags & VB_DISPTYPE_DISP2) {
 
-     case CRT2_LCD:
+       case CRT2_LCD:
+               xres = ivideo->lcdxres; yres = ivideo->lcdyres;
 
-        xres = ivideo->lcdxres; yres = ivideo->lcdyres;
-
-       if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) {
-               if(sisbios_mode[myindex].xres > xres) return(-1);
-               if(myres > yres) return(-1);
-       }
+               if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
+                  (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
+                       if(sisbios_mode[myindex].xres > xres)
+                               return -1;
+                       if(myres > yres)
+                               return -1;
+               }
 
-       if(vbflags & (VB_LVDS | VB_30xBDH)) {
-          if(sisbios_mode[myindex].xres == 320) {
-             if((myres == 240) || (myres == 480)) {
-                if(!ivideo->sisfb_fstn) {
-                   if(sisbios_mode[myindex].mode_no[1] == 0x5a ||
-                      sisbios_mode[myindex].mode_no[1] == 0x5b)
-                      return(-1);
-                } else {
-                   if(sisbios_mode[myindex].mode_no[1] == 0x50 ||
-                      sisbios_mode[myindex].mode_no[1] == 0x56 ||
-                      sisbios_mode[myindex].mode_no[1] == 0x53)
-                      return(-1);
-                }
-             }
-          }
-       }
+               if(ivideo->sisfb_fstn) {
+                       if(sisbios_mode[myindex].xres == 320) {
+                               if(myres == 240) {
+                                       switch(sisbios_mode[myindex].mode_no[1]) {
+                                               case 0x50: myindex = MODE_FSTN_8;  break;
+                                               case 0x56: myindex = MODE_FSTN_16; break;
+                                               case 0x53: return -1;
+                                       }
+                               }
+                       }
+               }
 
-       if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
-                            sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
-                            ivideo->SiS_Pr.SiS_CustomT, xres, yres) < 0x14) {
-               return(-1);
-       }
-       break;
+               if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+                               sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
+                               ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
+                       return -1;
+               }
+               break;
 
-     case CRT2_TV:
-       if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
-                           sisbios_mode[myindex].yres, 0) < 0x14) {
-               return(-1);
-       }
-       break;
+       case CRT2_TV:
+               if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+                               sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
+                       return -1;
+               }
+               break;
 
-     case CRT2_VGA:
-        if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
-                             sisbios_mode[myindex].yres, 0) < 0x14) {
-               return(-1);
+       case CRT2_VGA:
+               if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+                               sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
+                       return -1;
+               }
+               break;
        }
-       break;
-     }
 
-     return(myindex);
+       return myindex;
 }
 
 static u8
 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
 {
-       u16 xres, yres;
        int i = 0;
-
-       xres = sisbios_mode[mode_idx].xres;
-       yres = sisbios_mode[mode_idx].yres;
+       u16 xres = sisbios_mode[mode_idx].xres;
+       u16 yres = sisbios_mode[mode_idx].yres;
 
        ivideo->rate_idx = 0;
        while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
@@ -672,14 +756,14 @@ sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int
                                                rate, sisfb_vrate[i-1].refresh);
                                        ivideo->rate_idx = sisfb_vrate[i-1].idx;
                                        ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
-                               } 
+                               }
                                break;
                        } else if((rate - sisfb_vrate[i].refresh) <= 2) {
                                DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
                                                rate, sisfb_vrate[i].refresh);
-                               ivideo->rate_idx = sisfb_vrate[i].idx;
-                               break;
-                       }
+                               ivideo->rate_idx = sisfb_vrate[i].idx;
+                               break;
+                       }
                }
                i++;
        }
@@ -695,252 +779,321 @@ sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int
 static BOOLEAN
 sisfb_bridgeisslave(struct sis_video_info *ivideo)
 {
-   unsigned char P1_00;
+       unsigned char P1_00;
 
-   if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE;
+       if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
+               return FALSE;
 
-   inSISIDXREG(SISPART1,0x00,P1_00);
-   if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
-       ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
-          return TRUE;
-   } else {
-           return FALSE;
-   }
+       inSISIDXREG(SISPART1,0x00,P1_00);
+       if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
+           ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
+               return TRUE;
+       } else {
+               return FALSE;
+       }
 }
 
 static BOOLEAN
 sisfballowretracecrt1(struct sis_video_info *ivideo)
 {
-   u8 temp;
+       u8 temp;
 
-   inSISIDXREG(SISCR,0x17,temp);
-   if(!(temp & 0x80)) return FALSE;
+       inSISIDXREG(SISCR,0x17,temp);
+       if(!(temp & 0x80))
+               return FALSE;
 
-   inSISIDXREG(SISSR,0x1f,temp);
-   if(temp & 0xc0) return FALSE;
+       inSISIDXREG(SISSR,0x1f,temp);
+       if(temp & 0xc0)
+               return FALSE;
 
-   return TRUE;
+       return TRUE;
 }
 
 static BOOLEAN
 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
 {
-   if(!sisfballowretracecrt1(ivideo)) return FALSE;
+       if(!sisfballowretracecrt1(ivideo))
+               return FALSE;
 
-   if(inSISREG(SISINPSTAT) & 0x08) return TRUE;
-   else                           return FALSE;
+       if(inSISREG(SISINPSTAT) & 0x08)
+               return TRUE;
+       else
+               return FALSE;
 }
 
 static void
 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
 {
-   int watchdog;
+       int watchdog;
 
-   if(!sisfballowretracecrt1(ivideo)) return;
+       if(!sisfballowretracecrt1(ivideo))
+               return;
 
-   watchdog = 65536;
-   while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
-   watchdog = 65536;
-   while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
+       watchdog = 65536;
+       while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
+       watchdog = 65536;
+       while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
 }
 
 static BOOLEAN
 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
 {
-   unsigned char temp, reg;
+       unsigned char temp, reg;
 
-   switch(ivideo->sisvga_engine) {
-   case SIS_300_VGA: reg = 0x25; break;
-   case SIS_315_VGA: reg = 0x30; break;
-   default:          return FALSE;
-   }
+       switch(ivideo->sisvga_engine) {
+       case SIS_300_VGA: reg = 0x25; break;
+       case SIS_315_VGA: reg = 0x30; break;
+       default:          return FALSE;
+       }
 
-   inSISIDXREG(SISPART1, reg, temp);
-   if(temp & 0x02) return TRUE;
-   else           return FALSE;
+       inSISIDXREG(SISPART1, reg, temp);
+       if(temp & 0x02)
+               return TRUE;
+       else
+               return FALSE;
 }
 
 static BOOLEAN
 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
 {
-   if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
-      if(sisfb_bridgeisslave(ivideo)) {
-         return(sisfbcheckvretracecrt1(ivideo));
-      } else {
-         return(sisfbcheckvretracecrt2(ivideo));
-      }
-   } 
-   return(sisfbcheckvretracecrt1(ivideo));
+       if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
+               if(!sisfb_bridgeisslave(ivideo)) {
+                       return sisfbcheckvretracecrt2(ivideo);
+               }
+       }
+       return sisfbcheckvretracecrt1(ivideo);
 }
 
 static u32
 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
 {
-   u8 idx, reg1, reg2, reg3, reg4;
-   u32 ret = 0;
-
-   (*vcount) = (*hcount) = 0;
-
-   if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
-      ret |= (FB_VBLANK_HAVE_VSYNC  |
-             FB_VBLANK_HAVE_HBLANK |
-              FB_VBLANK_HAVE_VBLANK |
-             FB_VBLANK_HAVE_VCOUNT |
-             FB_VBLANK_HAVE_HCOUNT);
-      switch(ivideo->sisvga_engine) {
-         case SIS_300_VGA: idx = 0x25; break;
-        default:
-         case SIS_315_VGA: idx = 0x30; break;
-      }
-      inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
-      inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
-      inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
-      inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
-      if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
-      if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
-      if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
-      (*vcount) = reg3 | ((reg4 & 0x70) << 4);
-      (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
-   } else if(sisfballowretracecrt1(ivideo)) {
-      ret |= (FB_VBLANK_HAVE_VSYNC  |
-              FB_VBLANK_HAVE_VBLANK |
-             FB_VBLANK_HAVE_VCOUNT |
-             FB_VBLANK_HAVE_HCOUNT);
-      reg1 = inSISREG(SISINPSTAT);
-      if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
-      if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
-      inSISIDXREG(SISCR,0x20,reg1);
-      inSISIDXREG(SISCR,0x1b,reg1);
-      inSISIDXREG(SISCR,0x1c,reg2);
-      inSISIDXREG(SISCR,0x1d,reg3);
-      (*vcount) = reg2 | ((reg3 & 0x07) << 8);
-      (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
-   }
-   return ret;
+       u8 idx, reg1, reg2, reg3, reg4;
+       u32 ret = 0;
+
+       (*vcount) = (*hcount) = 0;
+
+       if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
+
+               ret |= (FB_VBLANK_HAVE_VSYNC  |
+                       FB_VBLANK_HAVE_HBLANK |
+                       FB_VBLANK_HAVE_VBLANK |
+                       FB_VBLANK_HAVE_VCOUNT |
+                       FB_VBLANK_HAVE_HCOUNT);
+               switch(ivideo->sisvga_engine) {
+                       case SIS_300_VGA: idx = 0x25; break;
+                       default:
+                       case SIS_315_VGA: idx = 0x30; break;
+               }
+               inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
+               inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
+               inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
+               inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
+               if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
+               if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
+               if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
+               (*vcount) = reg3 | ((reg4 & 0x70) << 4);
+               (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
+
+       } else if(sisfballowretracecrt1(ivideo)) {
+
+               ret |= (FB_VBLANK_HAVE_VSYNC  |
+                       FB_VBLANK_HAVE_VBLANK |
+                       FB_VBLANK_HAVE_VCOUNT |
+                       FB_VBLANK_HAVE_HCOUNT);
+               reg1 = inSISREG(SISINPSTAT);
+               if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
+               if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
+               inSISIDXREG(SISCR,0x20,reg1);
+               inSISIDXREG(SISCR,0x1b,reg1);
+               inSISIDXREG(SISCR,0x1c,reg2);
+               inSISIDXREG(SISCR,0x1d,reg3);
+               (*vcount) = reg2 | ((reg3 & 0x07) << 8);
+               (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
+       }
+
+       return ret;
 }
 
 static int
 sisfb_myblank(struct sis_video_info *ivideo, int blank)
 {
-   u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
-   BOOLEAN backlight = TRUE;
-
-   switch(blank) {
-   case FB_BLANK_UNBLANK:      /* on */
-      sr01  = 0x00;
-      sr11  = 0x00;
-      sr1f  = 0x00;
-      cr63  = 0x00;
-      p2_0  = 0x20;
-      p1_13 = 0x00;
-      backlight = TRUE;
-      break;
-   case FB_BLANK_NORMAL:       /* blank */
-      sr01  = 0x20;
-      sr11  = 0x00;
-      sr1f  = 0x00;
-      cr63  = 0x00;
-      p2_0  = 0x20;
-      p1_13 = 0x00;
-      backlight = TRUE;
-      break;
-   case FB_BLANK_VSYNC_SUSPEND:        /* no vsync */
-      sr01  = 0x20;
-      sr11  = 0x08;
-      sr1f  = 0x80;
-      cr63  = 0x40;
-      p2_0  = 0x40;
-      p1_13 = 0x80;
-      backlight = FALSE;
-      break;
-   case FB_BLANK_HSYNC_SUSPEND:        /* no hsync */
-      sr01  = 0x20;
-      sr11  = 0x08;
-      sr1f  = 0x40;
-      cr63  = 0x40;
-      p2_0  = 0x80;
-      p1_13 = 0x40;
-      backlight = FALSE;
-      break;
-   case FB_BLANK_POWERDOWN:    /* off */
-      sr01  = 0x20;
-      sr11  = 0x08;
-      sr1f  = 0xc0;
-      cr63  = 0x40;
-      p2_0  = 0xc0;
-      p1_13 = 0xc0;
-      backlight = FALSE;
-      break;
-   default:
-      return 1;
-   }
-
-   if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
-
-      if( (!ivideo->sisfb_thismonitor.datavalid) ||
-          ((ivideo->sisfb_thismonitor.datavalid) &&
-           (ivideo->sisfb_thismonitor.feature & 0xe0))) {
-
-        if(ivideo->sisvga_engine == SIS_315_VGA) {
-           setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
-        }
-
-        if(!(sisfb_bridgeisslave(ivideo))) {
-           setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
-           setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
-        }
-      }
-
-   }
-
-   if(ivideo->currentvbflags & CRT2_LCD) {
-
-      if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
-        if(backlight) {
-           SiS_SiS30xBLOn(&ivideo->SiS_Pr, &ivideo->sishw_ext);
-        } else {
-           SiS_SiS30xBLOff(&ivideo->SiS_Pr, &ivideo->sishw_ext);
-        }
-      } else if(ivideo->sisvga_engine == SIS_315_VGA) {
-        if(ivideo->vbflags & VB_CHRONTEL) {
-           if(backlight) {
-              SiS_Chrontel701xBLOn(&ivideo->SiS_Pr,&ivideo->sishw_ext);
-           } else {
-              SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
-           }
-        }
-      }
-
-      if(((ivideo->sisvga_engine == SIS_300_VGA) &&
-          (ivideo->vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
-         ((ivideo->sisvga_engine == SIS_315_VGA) &&
-          ((ivideo->vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
-          setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
-      }
-
-      if(ivideo->sisvga_engine == SIS_300_VGA) {
-         if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
-            (!(ivideo->vbflags & VB_30xBDH))) {
-           setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
-        }
-      } else if(ivideo->sisvga_engine == SIS_315_VGA) {
-         if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
-            (!(ivideo->vbflags & VB_30xBDH))) {
-           setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
-        }
-      }
-
-   } else if(ivideo->currentvbflags & CRT2_VGA) {
-
-      if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) {
-         setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
-      }
-
-   }
-
-   return(0);
+       u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
+       BOOLEAN backlight = TRUE;
+
+       switch(blank) {
+               case FB_BLANK_UNBLANK:  /* on */
+                       sr01  = 0x00;
+                       sr11  = 0x00;
+                       sr1f  = 0x00;
+                       cr63  = 0x00;
+                       p2_0  = 0x20;
+                       p1_13 = 0x00;
+                       backlight = TRUE;
+                       break;
+               case FB_BLANK_NORMAL:   /* blank */
+                       sr01  = 0x20;
+                       sr11  = 0x00;
+                       sr1f  = 0x00;
+                       cr63  = 0x00;
+                       p2_0  = 0x20;
+                       p1_13 = 0x00;
+                       backlight = TRUE;
+                       break;
+               case FB_BLANK_VSYNC_SUSPEND:    /* no vsync */
+                       sr01  = 0x20;
+                       sr11  = 0x08;
+                       sr1f  = 0x80;
+                       cr63  = 0x40;
+                       p2_0  = 0x40;
+                       p1_13 = 0x80;
+                       backlight = FALSE;
+                       break;
+               case FB_BLANK_HSYNC_SUSPEND:    /* no hsync */
+                       sr01  = 0x20;
+                       sr11  = 0x08;
+                       sr1f  = 0x40;
+                       cr63  = 0x40;
+                       p2_0  = 0x80;
+                       p1_13 = 0x40;
+                       backlight = FALSE;
+                       break;
+               case FB_BLANK_POWERDOWN:        /* off */
+                       sr01  = 0x20;
+                       sr11  = 0x08;
+                       sr1f  = 0xc0;
+                       cr63  = 0x40;
+                       p2_0  = 0xc0;
+                       p1_13 = 0xc0;
+                       backlight = FALSE;
+                       break;
+               default:
+                       return 1;
+       }
+
+       if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
+
+               if( (!ivideo->sisfb_thismonitor.datavalid) ||
+                   ((ivideo->sisfb_thismonitor.datavalid) &&
+                    (ivideo->sisfb_thismonitor.feature & 0xe0))) {
+
+                       if(ivideo->sisvga_engine == SIS_315_VGA) {
+                               setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
+                       }
+
+                       if(!(sisfb_bridgeisslave(ivideo))) {
+                               setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
+                               setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
+                       }
+               }
+
+       }
+
+       if(ivideo->currentvbflags & CRT2_LCD) {
+
+               if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
+                       if(backlight) {
+                               SiS_SiS30xBLOn(&ivideo->SiS_Pr);
+                       } else {
+                               SiS_SiS30xBLOff(&ivideo->SiS_Pr);
+                       }
+               } else if(ivideo->sisvga_engine == SIS_315_VGA) {
+#ifdef CONFIG_FB_SIS_315
+                       if(ivideo->vbflags2 & VB2_CHRONTEL) {
+                               if(backlight) {
+                                       SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
+                               } else {
+                                       SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
+                               }
+                       }
+#endif
+               }
+
+               if(((ivideo->sisvga_engine == SIS_300_VGA) &&
+                   (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
+                  ((ivideo->sisvga_engine == SIS_315_VGA) &&
+                   ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
+                       setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
+               }
+
+               if(ivideo->sisvga_engine == SIS_300_VGA) {
+                       if((ivideo->vbflags2 & VB2_30xB) &&
+                          (!(ivideo->vbflags2 & VB2_30xBDH))) {
+                               setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
+                       }
+               } else if(ivideo->sisvga_engine == SIS_315_VGA) {
+                       if((ivideo->vbflags2 & VB2_30xB) &&
+                          (!(ivideo->vbflags2 & VB2_30xBDH))) {
+                               setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
+                       }
+               }
+
+       } else if(ivideo->currentvbflags & CRT2_VGA) {
+
+               if(ivideo->vbflags2 & VB2_30xB) {
+                       setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
+               }
+
+       }
+
+       return 0;
+}
+
+/* ------------- Callbacks from init.c/init301.c  -------------- */
+
+#ifdef CONFIG_FB_SIS_300
+unsigned int
+sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
+{
+   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
+   u32 val = 0;
+
+   pci_read_config_dword(ivideo->nbridge, reg, &val);
+   return (unsigned int)val;
+}
+
+void
+sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
+{
+   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
+
+   pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
+}
+
+unsigned int
+sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
+{
+   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
+   u32 val = 0;
+
+   if(!ivideo->lpcdev) return 0;
+
+   pci_read_config_dword(ivideo->lpcdev, reg, &val);
+   return (unsigned int)val;
+}
+#endif
+
+#ifdef CONFIG_FB_SIS_315
+void
+sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
+{
+   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
+
+   pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
 }
 
+unsigned int
+sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
+{
+   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
+   u16 val = 0;
+
+   if(!ivideo->lpcdev) return 0;
+
+   pci_read_config_word(ivideo->lpcdev, reg, &val);
+   return (unsigned int)val;
+}
+#endif
+
 /* ----------- FBDev related routines for all series ----------- */
 
 static int
@@ -952,7 +1105,7 @@ sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
 static void
 sisfb_set_vparms(struct sis_video_info *ivideo)
 {
-       switch(ivideo->video_bpp) {
+       switch(ivideo->video_bpp) {
        case 8:
                ivideo->DstColor = 0x0000;
                ivideo->SiS310_AccelDepth = 0x00000000;
@@ -972,14 +1125,13 @@ sisfb_set_vparms(struct sis_video_info *ivideo)
                ivideo->video_cmap_len = 16;
                printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
                ivideo->accel = 0;
-               break;
-       }
+       }
 }
 
 static int
 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
 {
-       int maxyres = ivideo->heapstart / (var->xres_virtual * (var->bits_per_pixel >> 3));
+       int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
 
        if(maxyres > 32767) maxyres = 32767;
 
@@ -996,30 +1148,29 @@ sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
                        ivideo->scrnpitchCRT1 <<= 1;
                }
        }
-
 }
 
 static void
 sisfb_set_pitch(struct sis_video_info *ivideo)
 {
-       BOOLEAN isslavemode = FALSE;
+       BOOLEAN isslavemode = FALSE;
        unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
        unsigned short HDisplay2 = ivideo->video_linelength >> 3;
 
-       if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
+       if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
 
-       /* We need to set pitch for CRT1 if bridge is in slave mode, too */
-       if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
-               outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
-               setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
+       /* We need to set pitch for CRT1 if bridge is in slave mode, too */
+       if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
+               outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
+               setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
        }
 
-       /* We must not set the pitch for CRT2 if bridge is in slave mode */
-       if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
+       /* We must not set the pitch for CRT2 if bridge is in slave mode */
+       if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
                orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
-               outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
-               setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
-       }
+               outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
+               setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
+       }
 }
 
 static void
@@ -1055,13 +1206,42 @@ sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
        }
 }
 
+static int
+sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
+{
+       unsigned short modeno = ivideo->mode_no;
+
+       /* >=2.6.12's fbcon clears the screen anyway */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
+       if(!clrscrn) modeno |= 0x80;
+#else
+       modeno |= 0x80;
+#endif
+
+       outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+
+       sisfb_pre_setmode(ivideo);
+
+       if(SiSSetMode(&ivideo->SiS_Pr, modeno) == 0) {
+               printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
+               return -EINVAL;
+       }
+
+       outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+
+       sisfb_post_setmode(ivideo);
+
+       return 0;
+}
+
+
 static int
 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
 {
        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
        unsigned int htotal = 0, vtotal = 0;
        unsigned int drate = 0, hrate = 0;
-       int found_mode = 0;
+       int found_mode = 0, ret;
        int old_mode;
        u32 pixclock;
 
@@ -1088,11 +1268,11 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in
        }
 
        if(pixclock && htotal && vtotal) {
-               drate = 1000000000 / pixclock;
-               hrate = (drate * 1000) / htotal;
-               ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
+               drate = 1000000000 / pixclock;
+               hrate = (drate * 1000) / htotal;
+               ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
        } else {
-               ivideo->refresh_rate = 60;
+               ivideo->refresh_rate = 60;
        }
 
        old_mode = ivideo->sisfb_mode_idx;
@@ -1113,6 +1293,7 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in
        if(found_mode) {
                ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
                                ivideo->sisfb_mode_idx, ivideo->currentvbflags);
+               ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
        } else {
                ivideo->sisfb_mode_idx = -1;
        }
@@ -1131,10 +1312,10 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
        if(ivideo->sisfb_thismonitor.datavalid) {
-          if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
+               if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
                                 ivideo->rate_idx, ivideo->refresh_rate)) {
-             printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
-          }
+                       printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
+               }
        }
 #endif
 
@@ -1143,24 +1324,9 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in
 #else
        if(isactive) {
 #endif
-               sisfb_pre_setmode(ivideo);
-
-               if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
-                       printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
-                       return -EINVAL;
-               }
-
-               outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
-
-               sisfb_post_setmode(ivideo);
-
-               ivideo->video_bpp    = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
-               ivideo->video_width  = sisbios_mode[ivideo->sisfb_mode_idx].xres;
-               ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
-
-               sisfb_calc_pitch(ivideo, var);
-               sisfb_set_pitch(ivideo);
-
+               /* If acceleration to be used? Need to know
+                * before pre/post_set_mode()
+                */
                ivideo->accel = 0;
 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
 #ifdef STUPID_ACCELF_TEXT_SHIT
@@ -1175,6 +1341,17 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in
                if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
 #endif
 
+               if((ret = sisfb_set_mode(ivideo, 1))) {
+                       return ret;
+               }
+
+               ivideo->video_bpp    = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
+               ivideo->video_width  = sisbios_mode[ivideo->sisfb_mode_idx].xres;
+               ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
+
+               sisfb_calc_pitch(ivideo, var);
+               sisfb_set_pitch(ivideo);
+
                sisfb_set_vparms(ivideo);
 
                ivideo->current_width = ivideo->video_width;
@@ -1186,1105 +1363,652 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in
                ivideo->current_pixclock = var->pixclock;
                ivideo->current_refresh_rate = ivideo->refresh_rate;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-                ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
+               ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
 #endif
        }
 
        return 0;
 }
 
-static int
-sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
+static void
+sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
 {
-       unsigned int base;
-
-       if(var->xoffset > (var->xres_virtual - var->xres)) {
-               return -EINVAL;
-       }
-       if(var->yoffset > (var->yres_virtual - var->yres)) {
-               return -EINVAL;
-       }
-
-       base = (var->yoffset * var->xres_virtual) + var->xoffset;
-
-        /* calculate base bpp dep. */
-        switch(var->bits_per_pixel) {
-       case 32:
-               break;
-        case 16:
-               base >>= 1;
-               break;
-       case 8:
-        default:
-               base >>= 2;
-               break;
-        }
-       
        outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
-        outSISIDXREG(SISCR, 0x0D, base & 0xFF);
+       outSISIDXREG(SISCR, 0x0D, base & 0xFF);
        outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
        outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
        if(ivideo->sisvga_engine == SIS_315_VGA) {
                setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
        }
-        if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
+}
+
+static void
+sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
+{
+       if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
                orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
-               outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
-               outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
-               outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
+               outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
+               outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
+               outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
                if(ivideo->sisvga_engine == SIS_315_VGA) {
                        setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
                }
-        }
-       return 0;
+       }
 }
 
-/* ------------ FBDev related routines for 2.4 series ----------- */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-
-static void
-sisfb_crtc_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
+static int
+sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
 {
-       u16 VRE, VBE, VRS, VBS, VDE, VT;
-       u16 HRE, HBE, HRS, HBS, HDE, HT;
-       u8  sr_data, cr_data, cr_data2, cr_data3, mr_data;
-       int A, B, C, D, E, F, temp;
-       unsigned int hrate, drate, maxyres;
-
-       inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
+       if(var->xoffset > (var->xres_virtual - var->xres)) {
+               return -EINVAL;
+       }
+       if(var->yoffset > (var->yres_virtual - var->yres)) {
+               return -EINVAL;
+       }
 
-       if(sr_data & SIS_INTERLACED_MODE)
-          var->vmode = FB_VMODE_INTERLACED;
-       else
-          var->vmode = FB_VMODE_NONINTERLACED;
+       ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
 
-       switch((sr_data & 0x1C) >> 2) {
-       case SIS_8BPP_COLOR_MODE:
-               var->bits_per_pixel = 8;
+       /* calculate base bpp dep. */
+       switch(var->bits_per_pixel) {
+       case 32:
                break;
-       case SIS_16BPP_COLOR_MODE:
-               var->bits_per_pixel = 16;
+       case 16:
+               ivideo->current_base >>= 1;
                break;
-       case SIS_32BPP_COLOR_MODE:
-               var->bits_per_pixel = 32;
+       case 8:
+       default:
+               ivideo->current_base >>= 2;
                break;
        }
 
-       sisfb_bpp_to_var(ivideo, var);
-       
-       inSISIDXREG(SISSR, 0x0A, sr_data);
-        inSISIDXREG(SISCR, 0x06, cr_data);
-        inSISIDXREG(SISCR, 0x07, cr_data2);
-
-       VT = (cr_data & 0xFF) |
-            ((u16) (cr_data2 & 0x01) << 8) |
-            ((u16) (cr_data2 & 0x20) << 4) |
-            ((u16) (sr_data  & 0x01) << 10);
-       A = VT + 2;
-
-       inSISIDXREG(SISCR, 0x12, cr_data);
-
-       VDE = (cr_data & 0xff) |
-             ((u16) (cr_data2 & 0x02) << 7) |
-             ((u16) (cr_data2 & 0x40) << 3) |
-             ((u16) (sr_data  & 0x02) << 9);
-       E = VDE + 1;
-
-       inSISIDXREG(SISCR, 0x10, cr_data);
-
-       VRS = (cr_data & 0xff) |
-             ((u16) (cr_data2 & 0x04) << 6) |
-             ((u16) (cr_data2 & 0x80) << 2) |
-             ((u16) (sr_data  & 0x08) << 7);
-       F = VRS + 1 - E;
-
-       inSISIDXREG(SISCR, 0x15, cr_data);
-       inSISIDXREG(SISCR, 0x09, cr_data3);
-
-       if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE;
-
-       VBS = (cr_data & 0xff) |
-             ((u16) (cr_data2 & 0x08) << 5) |
-             ((u16) (cr_data3 & 0x20) << 4) |
-             ((u16) (sr_data & 0x04) << 8);
-
-       inSISIDXREG(SISCR, 0x16, cr_data);
-
-       VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
-       temp = VBE - ((E - 1) & 511);
-       B = (temp > 0) ? temp : (temp + 512);
-
-       inSISIDXREG(SISCR, 0x11, cr_data);
-
-       VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
-       temp = VRE - ((E + F - 1) & 31);
-       C = (temp > 0) ? temp : (temp + 32);
-
-       D = B - F - C;
-
-        var->yres = E;
-       var->upper_margin = D;
-       var->lower_margin = F;
-       var->vsync_len = C;
-
-       if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
-          var->yres <<= 1;
-          var->upper_margin <<= 1;
-          var->lower_margin <<= 1;
-          var->vsync_len <<= 1;
-       } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
-          var->yres >>= 1;
-          var->upper_margin >>= 1;
-          var->lower_margin >>= 1;
-          var->vsync_len >>= 1;
-       }
-
-       inSISIDXREG(SISSR, 0x0b, sr_data);
-       inSISIDXREG(SISCR, 0x00, cr_data);
-
-       HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
-       A = HT + 5;
-
-       inSISIDXREG(SISCR, 0x01, cr_data);
-
-       HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
-       E = HDE + 1;
-
-       inSISIDXREG(SISCR, 0x04, cr_data);
-
-       HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
-       F = HRS - E - 3;
-
-       inSISIDXREG(SISCR, 0x02, cr_data);
+       ivideo->current_base += (ivideo->video_offset >> 2);
 
-       HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
+       sisfb_set_base_CRT1(ivideo, ivideo->current_base);
+       sisfb_set_base_CRT2(ivideo, ivideo->current_base);
 
-       inSISIDXREG(SISSR, 0x0c, sr_data);
-       inSISIDXREG(SISCR, 0x03, cr_data);
-       inSISIDXREG(SISCR, 0x05, cr_data2);
-
-       HBE = (cr_data & 0x1f) |
-             ((u16) (cr_data2 & 0x80) >> 2) |
-             ((u16) (sr_data  & 0x03) << 6);
-       HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
-
-       temp = HBE - ((E - 1) & 255);
-       B = (temp > 0) ? temp : (temp + 256);
-
-       temp = HRE - ((E + F + 3) & 63);
-       C = (temp > 0) ? temp : (temp + 64);
-
-       D = B - F - C;
-
-       var->xres = E * 8;
-       if(var->xres_virtual < var->xres) {
-               var->xres_virtual = var->xres;
-       }
-
-       if((var->xres == 320) &&
-          (var->yres == 200 || var->yres == 240)) {
-               /* Terrible hack, but the correct CRTC data for
-                * these modes only produces a black screen...
-                */
-                       var->left_margin = (400 - 376);
-                       var->right_margin = (328 - 320);
-                       var->hsync_len = (376 - 328);
-       } else {
-               var->left_margin = D * 8;
-               var->right_margin = F * 8;
-               var->hsync_len = C * 8;
-       }
-       var->activate = FB_ACTIVATE_NOW;
+       return 0;
+}
 
-       var->sync = 0;
+/* ------------ FBDev related routines for 2.4 series ----------- */
 
-       mr_data = inSISREG(SISMISCR);
-       if(mr_data & 0x80)
-          var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
-       else
-          var->sync |= FB_SYNC_VERT_HIGH_ACT;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 
-       if(mr_data & 0x40)
-          var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
-       else
-          var->sync |= FB_SYNC_HOR_HIGH_ACT;
+#include "sisfb_fbdev_2_4.h"
 
-       VT += 2;
-       VT <<= 1;
-       HT = (HT + 5) * 8;
+#endif
 
-       if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
-          VT <<= 1;
-       }
-       hrate = ivideo->refresh_rate * VT / 2;
-       drate = (hrate * HT) / 1000;
-       var->pixclock = (u32) (1000000000 / drate);
+/* ------------ FBDev related routines for 2.6 series ----------- */
 
-       if(ivideo->sisfb_ypan) {
-          maxyres = sisfb_calc_maxyres(ivideo, var);
-          if(ivideo->sisfb_max) {
-             var->yres_virtual = maxyres;
-          } else {
-             if(var->yres_virtual > maxyres) {
-                var->yres_virtual = maxyres;
-             }
-          }
-          if(var->yres_virtual <= var->yres) {
-             var->yres_virtual = var->yres;
-          }
-       } else {
-          var->yres_virtual = var->yres;
-       }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 
+static int
+sisfb_open(struct fb_info *info, int user)
+{
+       return 0;
 }
 
 static int
-sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
-                        unsigned *transp, struct fb_info *info)
+sisfb_release(struct fb_info *info, int user)
 {
-       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
-
-       if(regno >= ivideo->video_cmap_len) return 1;
-
-       *red   = ivideo->sis_palette[regno].red;
-       *green = ivideo->sis_palette[regno].green;
-       *blue  = ivideo->sis_palette[regno].blue;
-       *transp = 0;
-
        return 0;
 }
 
 static int
 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
-                           unsigned transp, struct fb_info *info)
+               unsigned transp, struct fb_info *info)
 {
        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 
-       if(regno >= ivideo->video_cmap_len) return 1;
-
-       ivideo->sis_palette[regno].red   = red;
-       ivideo->sis_palette[regno].green = green;
-       ivideo->sis_palette[regno].blue  = blue;
+       if(regno >= sisfb_get_cmap_len(&info->var))
+               return 1;
 
-       switch(ivideo->video_bpp) {
-#ifdef FBCON_HAS_CFB8
+       switch(info->var.bits_per_pixel) {
        case 8:
-               outSISREG(SISDACA, regno);
+               outSISREG(SISDACA, regno);
                outSISREG(SISDACD, (red >> 10));
                outSISREG(SISDACD, (green >> 10));
                outSISREG(SISDACD, (blue >> 10));
                if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
-                       outSISREG(SISDAC2A, regno);
+                       outSISREG(SISDAC2A, regno);
                        outSISREG(SISDAC2D, (red >> 8));
                        outSISREG(SISDAC2D, (green >> 8));
                        outSISREG(SISDAC2D, (blue >> 8));
                }
                break;
-#endif
-#ifdef FBCON_HAS_CFB16
        case 16:
-               ivideo->sis_fbcon_cmap.cfb16[regno] =
-                   ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+               ((u32 *)(info->pseudo_palette))[regno] =
+                               (red & 0xf800)          |
+                               ((green & 0xfc00) >> 5) |
+                               ((blue & 0xf800) >> 11);
                break;
-#endif
-#ifdef FBCON_HAS_CFB32
        case 32:
-               red   >>= 8;
+               red >>= 8;
                green >>= 8;
-               blue  >>= 8;
-               ivideo->sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
+               blue >>= 8;
+               ((u32 *)(info->pseudo_palette))[regno] =
+                               (red << 16) | (green << 8) | (blue);
                break;
-#endif
        }
-
        return 0;
 }
 
-static void
-sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info)
-{
-       struct sis_video_info    *ivideo = (struct sis_video_info *)info->par;
-       struct display           *display;
-       struct display_switch    *sw;
-       struct fb_fix_screeninfo fix;
-       long   flags;
-
-       display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
-
-       sisfb_get_fix(&fix, con, info);
-
-       display->var = *var;
-       display->screen_base = (char *)ivideo->video_vbase;
-       display->visual = fix.visual;
-       display->type = fix.type;
-       display->type_aux = fix.type_aux;
-       display->ypanstep = fix.ypanstep;
-       display->ywrapstep = fix.ywrapstep;
-       display->line_length = fix.line_length;
-       display->can_soft_blank = 1;
-       display->inverse = ivideo->sisfb_inverse;
-       display->next_line = fix.line_length;
-
-       save_flags(flags);
-
-       switch(ivideo->video_bpp) {
-#ifdef FBCON_HAS_CFB8
-       case 8: sw = ivideo->accel ? &fbcon_sis8 : &fbcon_cfb8;
-               break;
-#endif
-#ifdef FBCON_HAS_CFB16
-       case 16:sw = ivideo->accel ? &fbcon_sis16 : &fbcon_cfb16;
-               display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb16;
-               break;
-#endif
-#ifdef FBCON_HAS_CFB32
-       case 32:sw = ivideo->accel ? &fbcon_sis32 : &fbcon_cfb32;
-               display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb32;
-               break;
-#endif
-       default:sw = &fbcon_dummy;
-               break;
-       }
-       memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw));
-       display->dispsw = &ivideo->sisfb_sw;
-
-       restore_flags(flags);
-
-        if(ivideo->sisfb_ypan) {
-           /* display->scrollmode = 0;  */
-       } else {
-           display->scrollmode = SCROLL_YREDRAW;
-           ivideo->sisfb_sw.bmove = fbcon_redraw_bmove;
-       }
-}
-
-static void
-sisfb_do_install_cmap(int con, struct fb_info *info)
-{
-       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
-
-        if(con != ivideo->currcon) return;
-
-        if(fb_display[con].cmap.len) {
-               fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
-        } else {
-               int size = sisfb_get_cmap_len(&fb_display[con].var);
-               fb_set_cmap(fb_default_cmap(size), 1, sisfb_setcolreg, info);
-       }
-}
-
 static int
-sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+sisfb_set_par(struct fb_info *info)
 {
-       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
-
-       if(con == -1) {
-               memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo));
-       } else {
-               *var = fb_display[con].var;
-       }
+       int err;
 
-       if(ivideo->sisfb_fstn) {
-               if(var->xres == 320 && var->yres == 480) var->yres = 240;
-        }
+       if((err = sisfb_do_set_var(&info->var, 1, info)))
+               return err;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+       sisfb_get_fix(&info->fix, info->currcon, info);
+#else
+       sisfb_get_fix(&info->fix, -1, info);
+#endif
        return 0;
 }
 
 static int
-sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
-       int err;
+       unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
+       unsigned int drate = 0, hrate = 0, maxyres;
+       int found_mode = 0;
+       int refresh_rate, search_idx, tidx;
+       BOOLEAN recalc_clock = FALSE;
+       u32 pixclock;
 
-       fb_display[con].var.activate = FB_ACTIVATE_NOW;
+       htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
 
-        if(sisfb_do_set_var(var, con == ivideo->currcon, info)) {
-               sisfb_crtc_to_var(ivideo, var);
-               return -EINVAL;
-       }
+       vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
 
-       sisfb_crtc_to_var(ivideo, var);
+       pixclock = var->pixclock;
 
-       sisfb_set_disp(con, var, info);
+       if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
+               vtotal += var->yres;
+               vtotal <<= 1;
+       } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+               vtotal += var->yres;
+               vtotal <<= 2;
+       } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+               vtotal += var->yres;
+               vtotal <<= 1;
+       } else
+               vtotal += var->yres;
 
-       if(info->changevar) {
-               (*info->changevar)(con);
+       if(!(htotal) || !(vtotal)) {
+               SISFAIL("sisfb: no valid timing data");
        }
 
-       if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) {
-               return err;
+       search_idx = 0;
+       while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
+              (sisbios_mode[search_idx].xres <= var->xres) ) {
+               if( (sisbios_mode[search_idx].xres == var->xres) &&
+                   (sisbios_mode[search_idx].yres == var->yres) &&
+                   (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
+                       if((tidx = sisfb_validate_mode(ivideo, search_idx,
+                                               ivideo->currentvbflags)) > 0) {
+                               found_mode = 1;
+                               search_idx = tidx;
+                               break;
+                       }
+               }
+               search_idx++;
        }
 
-       sisfb_do_install_cmap(con, info);
+       if(!found_mode) {
+               search_idx = 0;
+               while(sisbios_mode[search_idx].mode_no[0] != 0) {
+                  if( (var->xres <= sisbios_mode[search_idx].xres) &&
+                      (var->yres <= sisbios_mode[search_idx].yres) &&
+                      (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
+                       if((tidx = sisfb_validate_mode(ivideo,search_idx,
+                                               ivideo->currentvbflags)) > 0) {
+                               found_mode = 1;
+                               search_idx = tidx;
+                               break;
+                       }
+                  }
+                  search_idx++;
+               }
+               if(found_mode) {
+                       printk(KERN_DEBUG
+                               "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
+                               var->xres, var->yres, var->bits_per_pixel,
+                               sisbios_mode[search_idx].xres,
+                               sisbios_mode[search_idx].yres,
+                               var->bits_per_pixel);
+                       var->xres = sisbios_mode[search_idx].xres;
+                       var->yres = sisbios_mode[search_idx].yres;
+               } else {
+                       printk(KERN_ERR
+                               "sisfb: Failed to find supported mode near %dx%dx%d\n",
+                               var->xres, var->yres, var->bits_per_pixel);
+                       return -EINVAL;
+               }
+       }
 
-#if 0  /* Why was this called here? */
-       unsigned int cols, rows;
-       cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
-       rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
-       vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
-#endif
-       return 0;
-}
+       if( ((ivideo->vbflags2 & VB2_LVDS) ||
+            ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
+           (var->bits_per_pixel == 8) ) {
+               /* Slave modes on LVDS and 301B-DH */
+               refresh_rate = 60;
+               recalc_clock = TRUE;
+       } else if( (ivideo->current_htotal == htotal) &&
+                  (ivideo->current_vtotal == vtotal) &&
+                  (ivideo->current_pixclock == pixclock) ) {
+               /* x=x & y=y & c=c -> assume depth change */
+               drate = 1000000000 / pixclock;
+               hrate = (drate * 1000) / htotal;
+               refresh_rate = (unsigned int) (hrate * 2 / vtotal);
+       } else if( ( (ivideo->current_htotal != htotal) ||
+                    (ivideo->current_vtotal != vtotal) ) &&
+                  (ivideo->current_pixclock == var->pixclock) ) {
+               /* x!=x | y!=y & c=c -> invalid pixclock */
+               if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
+                       refresh_rate =
+                               ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
+               } else if(ivideo->sisfb_parm_rate != -1) {
+                       /* Sic, sisfb_parm_rate - want to know originally desired rate here */
+                       refresh_rate = ivideo->sisfb_parm_rate;
+               } else {
+                       refresh_rate = 60;
+               }
+               recalc_clock = TRUE;
+       } else if((pixclock) && (htotal) && (vtotal)) {
+               drate = 1000000000 / pixclock;
+               hrate = (drate * 1000) / htotal;
+               refresh_rate = (unsigned int) (hrate * 2 / vtotal);
+       } else if(ivideo->current_refresh_rate) {
+               refresh_rate = ivideo->current_refresh_rate;
+               recalc_clock = TRUE;
+       } else {
+               refresh_rate = 60;
+               recalc_clock = TRUE;
+       }
 
-static int
-sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
-{
-       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
-       struct display *display;
+       myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
 
-       display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
+       /* Eventually recalculate timing and clock */
+       if(recalc_clock) {
+               if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
+               var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
+                                               sisbios_mode[search_idx].mode_no[ivideo->mni],
+                                               myrateindex));
+               sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
+                                       sisbios_mode[search_idx].mode_no[ivideo->mni],
+                                       myrateindex, var);
+               if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+                       var->pixclock <<= 1;
+               }
+       }
 
-        if(con == ivideo->currcon) {
+       if(ivideo->sisfb_thismonitor.datavalid) {
+               if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
+                               myrateindex, refresh_rate)) {
+                       printk(KERN_INFO
+                               "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
+               }
+       }
 
-               return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
+       /* Adapt RGB settings */
+       sisfb_bpp_to_var(ivideo, var);
 
-       } else if(display->cmap.len) {
+       /* Sanity check for offsets */
+       if(var->xoffset < 0) var->xoffset = 0;
+       if(var->yoffset < 0) var->yoffset = 0;
 
-               fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2);
+       if(var->xres > var->xres_virtual)
+               var->xres_virtual = var->xres;
 
+       if(ivideo->sisfb_ypan) {
+               maxyres = sisfb_calc_maxyres(ivideo, var);
+               if(ivideo->sisfb_max) {
+                       var->yres_virtual = maxyres;
+               } else {
+                       if(var->yres_virtual > maxyres) {
+                               var->yres_virtual = maxyres;
+                       }
+               }
+               if(var->yres_virtual <= var->yres) {
+                       var->yres_virtual = var->yres;
+               }
        } else {
-
-               int size = sisfb_get_cmap_len(&display->var);
-               fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
-
+               if(var->yres != var->yres_virtual) {
+                       var->yres_virtual = var->yres;
+               }
+               var->xoffset = 0;
+               var->yoffset = 0;
        }
 
-       return 0;
-}
-
-static int
-sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
-{
-       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
-       struct display *display;
-       int err, size;
-
-       display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
-
-       size = sisfb_get_cmap_len(&display->var);
-       if(display->cmap.len != size) {
-               err = fb_alloc_cmap(&display->cmap, size, 0);
-               if(err) return err;
+       /* Truncate offsets to maximum if too high */
+       if(var->xoffset > var->xres_virtual - var->xres) {
+               var->xoffset = var->xres_virtual - var->xres - 1;
        }
-        
-       if(con == ivideo->currcon) {
-               return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
-       } else {
-               fb_copy_cmap(cmap, &display->cmap, kspc ? 0 : 1);
+
+       if(var->yoffset > var->yres_virtual - var->yres) {
+               var->yoffset = var->yres_virtual - var->yres - 1;
        }
 
+       /* Set everything else to 0 */
+       var->red.msb_right =
+               var->green.msb_right =
+               var->blue.msb_right =
+               var->transp.offset =
+               var->transp.length =
+               var->transp.msb_right = 0;
+
        return 0;
 }
 
 static int
-sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info)
+sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
 {
        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
        int err;
 
-       if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
+       if(var->xoffset > (var->xres_virtual - var->xres))
+               return -EINVAL;
 
-       if((var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual) ||
-          (var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)) {
+       if(var->yoffset > (var->yres_virtual - var->yres))
                return -EINVAL;
-       }
 
-        if(con == ivideo->currcon) {
-               if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
-       }
+       if(var->vmode & FB_VMODE_YWRAP)
+               return -EINVAL;
+
+       if(var->xoffset + info->var.xres > info->var.xres_virtual ||
+          var->yoffset + info->var.yres > info->var.yres_virtual)
+               return -EINVAL;
 
-       fb_display[con].var.xoffset = var->xoffset;
-       fb_display[con].var.yoffset = var->yoffset;
+       if((err = sisfb_pan_var(ivideo, var)) < 0)
+               return err;
+
+       info->var.xoffset = var->xoffset;
+       info->var.yoffset = var->yoffset;
 
        return 0;
 }
 
 static int
-sisfb_update_var(int con, struct fb_info *info)
+sisfb_blank(int blank, struct fb_info *info)
 {
        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 
-        return(sisfb_pan_var(ivideo, &fb_display[con].var));
+       return sisfb_myblank(ivideo, blank);
 }
 
-static int
-sisfb_switch(int con, struct fb_info *info)
-{
-       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
-       int cols, rows;
+#endif
 
-        if(fb_display[ivideo->currcon].cmap.len) {
-               fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info);
-       }
+/* ----------- FBDev related routines for all series ---------- */
 
-       fb_display[con].var.activate = FB_ACTIVATE_NOW;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+static int     sisfb_ioctl(struct fb_info *info, unsigned int cmd,
+                           unsigned long arg)
+#else
+static int     sisfb_ioctl(struct inode *inode, struct file *file,
+                               unsigned int cmd, unsigned long arg,
+                               struct fb_info *info)
+#endif
+{
+       struct sis_video_info   *ivideo = (struct sis_video_info *)info->par;
+       struct sis_memreq       sismemreq;
+       struct fb_vblank        sisvbblank;
+       u32                     gpu32 = 0;
+#ifndef __user
+#define __user
+#endif
+       u32 __user              *argp = (u32 __user *)arg;
 
-       if(!memcmp(&fb_display[con].var, &fb_display[ivideo->currcon].var,
-                                       sizeof(struct fb_var_screeninfo))) {
-               ivideo->currcon = con;
-               return 1;
-       }
+       switch(cmd) {
+          case FBIO_ALLOC:
+               if(!capable(CAP_SYS_RAWIO))
+                       return -EPERM;
 
-       ivideo->currcon = con;
+               if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
+                       return -EFAULT;
 
-       sisfb_do_set_var(&fb_display[con].var, 1, info);
+               sis_malloc(&sismemreq);
 
-       sisfb_set_disp(con, &fb_display[con].var, info);
+               if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
+                       sis_free((u32)sismemreq.offset);
+                       return -EFAULT;
+               }
+               break;
 
-       sisfb_do_install_cmap(con, info);
+          case FBIO_FREE:
+               if(!capable(CAP_SYS_RAWIO))
+                       return -EPERM;
 
-       cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
-       rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
-       vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+               if(get_user(gpu32, argp))
+                       return -EFAULT;
 
-       sisfb_update_var(con, info);
+               sis_free(gpu32);
+               break;
 
-       return 1;
-}
+          case FBIOGET_VBLANK:
+               sisvbblank.count = 0;
+               sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
 
-static void
-sisfb_blank(int blank, struct fb_info *info)
-{
-       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+               if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
+                       return -EFAULT;
 
-       sisfb_myblank(ivideo, blank);
-}
-#endif
+               break;
 
-/* ------------ FBDev related routines for 2.6 series ----------- */
+          case SISFB_GET_INFO_SIZE:
+               return put_user(sizeof(struct sisfb_info), argp);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+          case SISFB_GET_INFO_OLD:
+               if(ivideo->warncount++ < 10)
+                       printk(KERN_INFO
+                               "sisfb: Deprecated ioctl call received - update your application!\n");
+          case SISFB_GET_INFO:  /* For communication with X driver */
+               ivideo->sisfb_infoblock.sisfb_id         = SISFB_ID;
+               ivideo->sisfb_infoblock.sisfb_version    = VER_MAJOR;
+               ivideo->sisfb_infoblock.sisfb_revision   = VER_MINOR;
+               ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
+               ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
+               ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
+               ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
+               ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
+               if(ivideo->modechanged) {
+                       ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
+               } else {
+                       ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
+               }
+               ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
+               ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
+               ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
+               ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
+               ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
+               ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
+               ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
+               ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
+               ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
+               ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
+               ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
+               ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
+               ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
+               ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
+               ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
+               ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
+               ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
+               ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
+               ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
+               ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
+               ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
+               ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
+               ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
+               ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
+               ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
+               ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
+               ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
+               ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
+
+               if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
+                                               sizeof(ivideo->sisfb_infoblock)))
+                       return -EFAULT;
 
-static int
-sisfb_open(struct fb_info *info, int user)
-{
-       return 0;
-}
+               break;
 
-static int
-sisfb_release(struct fb_info *info, int user)
-{
-       return 0;
-}
+          case SISFB_GET_VBRSTATUS_OLD:
+               if(ivideo->warncount++ < 10)
+                       printk(KERN_INFO
+                               "sisfb: Deprecated ioctl call received - update your application!\n");
+          case SISFB_GET_VBRSTATUS:
+               if(sisfb_CheckVBRetrace(ivideo))
+                       return put_user((u32)1, argp);
+               else
+                       return put_user((u32)0, argp);
 
-static int
-sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
-               unsigned transp, struct fb_info *info)
-{
-       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+          case SISFB_GET_AUTOMAXIMIZE_OLD:
+               if(ivideo->warncount++ < 10)
+                       printk(KERN_INFO
+                               "sisfb: Deprecated ioctl call received - update your application!\n");
+          case SISFB_GET_AUTOMAXIMIZE:
+               if(ivideo->sisfb_max)
+                       return put_user((u32)1, argp);
+               else
+                       return put_user((u32)0, argp);
 
-       if(regno >= sisfb_get_cmap_len(&info->var)) return 1;
+          case SISFB_SET_AUTOMAXIMIZE_OLD:
+               if(ivideo->warncount++ < 10)
+                       printk(KERN_INFO
+                               "sisfb: Deprecated ioctl call received - update your application!\n");
+          case SISFB_SET_AUTOMAXIMIZE:
+               if(get_user(gpu32, argp))
+                       return -EFAULT;
 
-       switch(info->var.bits_per_pixel) {
-       case 8:
-               outSISREG(SISDACA, regno);
-               outSISREG(SISDACD, (red >> 10));
-               outSISREG(SISDACD, (green >> 10));
-               outSISREG(SISDACD, (blue >> 10));
-               if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
-                       outSISREG(SISDAC2A, regno);
-                       outSISREG(SISDAC2D, (red >> 8));
-                       outSISREG(SISDAC2D, (green >> 8));
-                       outSISREG(SISDAC2D, (blue >> 8));
-               }
+               ivideo->sisfb_max = (gpu32) ? 1 : 0;
                break;
-       case 16:
-               ((u32 *)(info->pseudo_palette))[regno] =
-                   ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+
+          case SISFB_SET_TVPOSOFFSET:
+               if(get_user(gpu32, argp))
+                       return -EFAULT;
+
+               sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
+               sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
                break;
-       case 32:
-               red >>= 8;
-               green >>= 8;
-               blue >>= 8;
-               ((u32 *)(info->pseudo_palette))[regno] =
-                               (red << 16) | (green << 8) | (blue);
+
+          case SISFB_GET_TVPOSOFFSET:
+               return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
+                                                       argp);
+
+          case SISFB_COMMAND:
+               if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
+                                                       sizeof(struct sisfb_cmd)))
+                       return -EFAULT;
+
+               sisfb_handle_command(ivideo, &ivideo->sisfb_command);
+
+               if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
+                                                       sizeof(struct sisfb_cmd)))
+                       return -EFAULT;
+
                break;
-       }
-       return 0;
-}
 
-static int
-sisfb_set_par(struct fb_info *info)
-{
-       int err;
+          case SISFB_SET_LOCK:
+               if(get_user(gpu32, argp))
+                       return -EFAULT;
 
-        if((err = sisfb_do_set_var(&info->var, 1, info))) {
-               return err;
-       }
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-       sisfb_get_fix(&info->fix, info->currcon, info);
+               ivideo->sisfblocked = (gpu32) ? 1 : 0;
+               break;
+
+          default:
+#ifdef SIS_NEW_CONFIG_COMPAT
+               return -ENOIOCTLCMD;
 #else
-       sisfb_get_fix(&info->fix, -1, info);
+               return -EINVAL;
 #endif
+       }
        return 0;
 }
 
 static int
-sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
 {
        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
-       unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
-       unsigned int drate = 0, hrate = 0, maxyres;
-       int found_mode = 0;
-       int refresh_rate, search_idx;
-       BOOLEAN recalc_clock = FALSE;
-       u32 pixclock;
-
-       htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
-
-       vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
 
-       pixclock = var->pixclock;
+       memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
-       if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
-               vtotal += var->yres;
-               vtotal <<= 1;
-       } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
-               vtotal += var->yres;
-               vtotal <<= 2;
-       } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
-               vtotal += var->yres;
-               vtotal <<= 1;
-       } else  vtotal += var->yres;
+       strcpy(fix->id, ivideo->myid);
 
-       if(!(htotal) || !(vtotal)) {
-               SISFAIL("sisfb: no valid timing data");
+       fix->smem_start  = ivideo->video_base + ivideo->video_offset;
+       fix->smem_len    = ivideo->sisfb_mem;
+       fix->type        = FB_TYPE_PACKED_PIXELS;
+       fix->type_aux    = 0;
+       fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+       fix->xpanstep    = 1;
+       fix->ypanstep    = (ivideo->sisfb_ypan) ? 1 : 0;
+       fix->ywrapstep   = 0;
+       fix->line_length = ivideo->video_linelength;
+       fix->mmio_start  = ivideo->mmio_base;
+       fix->mmio_len    = ivideo->mmio_size;
+       if(ivideo->sisvga_engine == SIS_300_VGA) {
+               fix->accel = FB_ACCEL_SIS_GLAMOUR;
+       } else if((ivideo->chip == SIS_330) ||
+                 (ivideo->chip == SIS_760) ||
+                 (ivideo->chip == SIS_761)) {
+               fix->accel = FB_ACCEL_SIS_XABRE;
+       } else if(ivideo->chip == XGI_20) {
+               fix->accel = FB_ACCEL_XGI_VOLARI_Z;
+       } else if(ivideo->chip >= XGI_40) {
+               fix->accel = FB_ACCEL_XGI_VOLARI_V;
+       } else {
+               fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
        }
 
-       search_idx = 0;
-       while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
-              (sisbios_mode[search_idx].xres <= var->xres) ) {
-               if( (sisbios_mode[search_idx].xres == var->xres) &&
-                   (sisbios_mode[search_idx].yres == var->yres) &&
-                   (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
-                       if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) {
-                          found_mode = 1;
-                          break;
-                       }
-               }
-               search_idx++;
-       }
+       return 0;
+}
 
-       if(!found_mode) {
-                search_idx = 0;
-               while(sisbios_mode[search_idx].mode_no[0] != 0) {
-                  if( (var->xres <= sisbios_mode[search_idx].xres) &&
-                      (var->yres <= sisbios_mode[search_idx].yres) &&
-                      (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
-                         if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) {
-                            found_mode = 1;
-                            break;
-                         }
-                  }
-                  search_idx++;
-               }
-               if(found_mode) {
-                       printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
-                               var->xres, var->yres, var->bits_per_pixel,
-                               sisbios_mode[search_idx].xres,
-                               sisbios_mode[search_idx].yres,
-                               var->bits_per_pixel);
-                       var->xres = sisbios_mode[search_idx].xres;
-                       var->yres = sisbios_mode[search_idx].yres;
+/* ----------------  fb_ops structures ----------------- */
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static struct fb_ops sisfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_get_fix     = sisfb_get_fix,
+       .fb_get_var     = sisfb_get_var,
+       .fb_set_var     = sisfb_set_var,
+       .fb_get_cmap    = sisfb_get_cmap,
+       .fb_set_cmap    = sisfb_set_cmap,
+       .fb_pan_display = sisfb_pan_display,
+       .fb_ioctl       = sisfb_ioctl
+};
+#endif
 
-               } else {
-                       printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n",
-                               var->xres, var->yres, var->bits_per_pixel);
-                       return -EINVAL;
-               }
-       }
-
-       if( ((ivideo->vbflags & VB_LVDS) ||                     /* Slave modes on LVDS and 301B-DH */
-            ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
-           (var->bits_per_pixel == 8) ) {
-               refresh_rate = 60;
-               recalc_clock = TRUE;
-       } else if( (ivideo->current_htotal == htotal) &&        /* x=x & y=y & c=c -> assume depth change */
-                  (ivideo->current_vtotal == vtotal) &&
-                  (ivideo->current_pixclock == pixclock) ) {
-               drate = 1000000000 / pixclock;
-               hrate = (drate * 1000) / htotal;
-               refresh_rate = (unsigned int) (hrate * 2 / vtotal);
-       } else if( ( (ivideo->current_htotal != htotal) ||      /* x!=x | y!=y & c=c -> invalid pixclock */
-                    (ivideo->current_vtotal != vtotal) ) &&
-                  (ivideo->current_pixclock == var->pixclock) ) {
-               if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
-                       refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
-               } else if(ivideo->sisfb_parm_rate != -1) {
-                       /* Sic, sisfb_parm_rate - want to know originally desired rate here */
-                       refresh_rate = ivideo->sisfb_parm_rate;
-               } else {
-                       refresh_rate = 60;
-               }
-               recalc_clock = TRUE;
-       } else if((pixclock) && (htotal) && (vtotal)) {
-               drate = 1000000000 / pixclock;
-               hrate = (drate * 1000) / htotal;
-               refresh_rate = (unsigned int) (hrate * 2 / vtotal);
-       } else if(ivideo->current_refresh_rate) {
-               refresh_rate = ivideo->current_refresh_rate;
-               recalc_clock = TRUE;
-       } else {
-               refresh_rate = 60;
-               recalc_clock = TRUE;
-       }
-
-       myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
-
-       /* Eventually recalculate timing and clock */
-       if(recalc_clock) {
-          if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
-          var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
-                                               &ivideo->sishw_ext,
-                                               sisbios_mode[search_idx].mode_no[ivideo->mni],
-                                               myrateindex));
-          sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
-                                   sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex, var);
-          if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
-             var->pixclock <<= 1;
-          }
-       }
-
-       if(ivideo->sisfb_thismonitor.datavalid) {
-          if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
-                                myrateindex, refresh_rate)) {
-             printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
-          }
-       }
-
-       /* Adapt RGB settings */
-       sisfb_bpp_to_var(ivideo, var);
-       
-       /* Sanity check for offsets */
-       if(var->xoffset < 0) var->xoffset = 0;
-       if(var->yoffset < 0) var->yoffset = 0;
-
-       if(var->xres > var->xres_virtual) {
-          var->xres_virtual = var->xres;
-       }
-
-       if(ivideo->sisfb_ypan) {
-          maxyres = sisfb_calc_maxyres(ivideo, var);
-          if(ivideo->sisfb_max) {
-             var->yres_virtual = maxyres;
-          } else {
-             if(var->yres_virtual > maxyres) {
-                var->yres_virtual = maxyres;
-             }
-          }
-          if(var->yres_virtual <= var->yres) {
-             var->yres_virtual = var->yres;
-          }
-       } else {
-          if(var->yres != var->yres_virtual) {
-             var->yres_virtual = var->yres;
-          }
-          var->xoffset = 0;
-          var->yoffset = 0;
-       }
-       
-       /* Truncate offsets to maximum if too high */
-       if(var->xoffset > var->xres_virtual - var->xres) {
-          var->xoffset = var->xres_virtual - var->xres - 1;
-       }
-
-       if(var->yoffset > var->yres_virtual - var->yres) {
-          var->yoffset = var->yres_virtual - var->yres - 1;
-       }
-       
-       /* Set everything else to 0 */
-       var->red.msb_right = 
-       var->green.msb_right =
-       var->blue.msb_right =
-       var->transp.offset =
-       var->transp.length =
-       var->transp.msb_right = 0;
-
-       return 0;
-}
-
-static int
-sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
-{
-       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
-       int err;
-
-       if(var->xoffset > (var->xres_virtual - var->xres)) {
-               return -EINVAL;
-       }
-       if(var->yoffset > (var->yres_virtual - var->yres)) {
-               return -EINVAL;
-       }
-
-       if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
-
-       if(var->xoffset + info->var.xres > info->var.xres_virtual ||
-          var->yoffset + info->var.yres > info->var.yres_virtual) {
-               return -EINVAL;
-       }
-
-       if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
-
-       info->var.xoffset = var->xoffset;
-       info->var.yoffset = var->yoffset;
-
-       return 0;
-}
-
-static int
-sisfb_blank(int blank, struct fb_info *info)
-{
-       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
-
-       return(sisfb_myblank(ivideo, blank));
-}
-
-#endif
-
-/* ----------- FBDev related routines for all series ---------- */
-
-static int
-sisfb_ioctl(struct inode *inode, struct file *file,
-            unsigned int cmd, unsigned long arg,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-           int con,
-#endif
-           struct fb_info *info)
-{
-       struct sis_video_info   *ivideo = (struct sis_video_info *)info->par;
-       struct sis_memreq       sismemreq;
-       struct fb_vblank        sisvbblank;
-       sisfb_info              x;
-       u32                     gpu32 = 0;
-#ifndef __user
-#define __user
-#endif
-       u32 __user              *argp = (u32 __user *)arg;
-
-       switch (cmd) {
-          case FBIO_ALLOC:
-               if(!capable(CAP_SYS_RAWIO)) {
-                       return -EPERM;
-               }
-               if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq))) {
-                       return -EFAULT;
-               }
-               sis_malloc(&sismemreq);
-               if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
-                       sis_free((u32)sismemreq.offset);
-                       return -EFAULT;
-               }
-               break;
-
-          case FBIO_FREE:
-               if(!capable(CAP_SYS_RAWIO)) {
-                       return -EPERM;
-               }
-               if(get_user(gpu32, argp)) {
-                       return -EFAULT;
-               }
-               sis_free(gpu32);
-               break;
-
-          case FBIOGET_VBLANK:
-               sisvbblank.count = 0;
-               sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
-               if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank))) {
-                       return -EFAULT;
-               }
-               break;
-
-          case SISFB_GET_INFO_SIZE:
-               return put_user(sizeof(sisfb_info), argp);
-
-          case SISFB_GET_INFO_OLD:
-               if(ivideo->warncount++ < 50) {
-                  printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
-               }
-          case SISFB_GET_INFO:  /* For communication with X driver */
-               x.sisfb_id         = SISFB_ID;
-               x.sisfb_version    = VER_MAJOR;
-               x.sisfb_revision   = VER_MINOR;
-               x.sisfb_patchlevel = VER_LEVEL;
-               x.chip_id = ivideo->chip_id;
-               x.memory = ivideo->video_size / 1024;
-               x.heapstart = ivideo->heapstart / 1024;
-               if(ivideo->modechanged) {
-                  x.fbvidmode = ivideo->mode_no;
-               } else {
-                  x.fbvidmode = ivideo->modeprechange;
-               }
-               x.sisfb_caps = ivideo->caps;
-               x.sisfb_tqlen = 512; /* yet fixed */
-               x.sisfb_pcibus = ivideo->pcibus;
-               x.sisfb_pcislot = ivideo->pcislot;
-               x.sisfb_pcifunc = ivideo->pcifunc;
-               x.sisfb_lcdpdc = ivideo->detectedpdc;
-               x.sisfb_lcdpdca = ivideo->detectedpdca;
-               x.sisfb_lcda = ivideo->detectedlcda;
-               x.sisfb_vbflags = ivideo->vbflags;
-               x.sisfb_currentvbflags = ivideo->currentvbflags;
-               x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
-               x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
-               x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
-               x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
-               x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
-               x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
-               x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
-               x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
-               x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
-               x.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
-
-               if(copy_to_user((void __user *)arg, &x, sizeof(x))) {
-                       return -EFAULT;
-               }
-               break;
-
-          case SISFB_GET_VBRSTATUS_OLD:
-               if(ivideo->warncount++ < 50) {
-                  printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
-               }
-          case SISFB_GET_VBRSTATUS:
-               if(sisfb_CheckVBRetrace(ivideo)) {
-                       return put_user((u32)1, argp);
-               } else {
-                       return put_user((u32)0, argp);
-               }
-
-          case SISFB_GET_AUTOMAXIMIZE_OLD:
-               if(ivideo->warncount++ < 50) {
-                  printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
-               }
-          case SISFB_GET_AUTOMAXIMIZE:
-               if(ivideo->sisfb_max)   return put_user((u32)1, argp);
-               else                    return put_user((u32)0, argp);
-
-          case SISFB_SET_AUTOMAXIMIZE_OLD:
-               if(ivideo->warncount++ < 50) {
-                  printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
-               }
-          case SISFB_SET_AUTOMAXIMIZE:
-               if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
-                       return -EFAULT;
-               }
-               ivideo->sisfb_max = (gpu32) ? 1 : 0;
-               break;
-
-          case SISFB_SET_TVPOSOFFSET:
-               if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
-                       return -EFAULT;
-               }
-               sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
-               sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
-               break;
-
-          case SISFB_GET_TVPOSOFFSET:
-               return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
-                               argp);
-
-          case SISFB_SET_LOCK:
-               if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
-                       return -EFAULT;
-               }
-               ivideo->sisfblocked = (gpu32) ? 1 : 0;
-               break;
-
-          default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-#ifdef CONFIG_COMPAT
-static long sisfb_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg, struct fb_info *info)
-{
-       int ret;
-       lock_kernel();
-       ret = sisfb_ioctl(NULL, f, cmd, arg, info);
-       unlock_kernel();
-       return ret;
-}
-#endif
-
-static int
-sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
-{
-       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
-
-       memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-
-       strcpy(fix->id, ivideo->myid);
-
-       fix->smem_start  = ivideo->video_base;
-       fix->smem_len    = ivideo->sisfb_mem;
-       fix->type        = FB_TYPE_PACKED_PIXELS;
-       fix->type_aux    = 0;
-       fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
-       fix->xpanstep    = 1;
-       fix->ypanstep    = (ivideo->sisfb_ypan) ? 1 : 0;
-       fix->ywrapstep   = 0;
-       fix->line_length = ivideo->video_linelength;
-       fix->mmio_start  = ivideo->mmio_base;
-       fix->mmio_len    = ivideo->mmio_size;
-       if(ivideo->sisvga_engine == SIS_300_VGA) {
-          fix->accel    = FB_ACCEL_SIS_GLAMOUR;
-       } else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) {
-          fix->accel    = FB_ACCEL_SIS_XABRE;
-       } else {
-          fix->accel    = FB_ACCEL_SIS_GLAMOUR_2;
-       }
-
-       return 0;
-}
-
-/* ----------------  fb_ops structures ----------------- */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-static struct fb_ops sisfb_ops = {
-       .owner          = THIS_MODULE,
-       .fb_get_fix     = sisfb_get_fix,
-       .fb_get_var     = sisfb_get_var,
-       .fb_set_var     = sisfb_set_var,
-       .fb_get_cmap    = sisfb_get_cmap,
-       .fb_set_cmap    = sisfb_set_cmap,
-        .fb_pan_display = sisfb_pan_display,
-       .fb_ioctl       = sisfb_ioctl
-};
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-static struct fb_ops sisfb_ops = {
-       .owner          = THIS_MODULE,
-       .fb_open        = sisfb_open,
-       .fb_release     = sisfb_release,
-       .fb_check_var   = sisfb_check_var,
-       .fb_set_par     = sisfb_set_par,
-       .fb_setcolreg   = sisfb_setcolreg,
-        .fb_pan_display = sisfb_pan_display,
-        .fb_blank       = sisfb_blank,
-       .fb_fillrect    = fbcon_sis_fillrect,
-       .fb_copyarea    = fbcon_sis_copyarea,
-       .fb_imageblit   = cfb_imageblit,
-       .fb_cursor      = soft_cursor,
-       .fb_sync        = fbcon_sis_sync,
-       .fb_ioctl       = sisfb_ioctl,
-#ifdef CONFIG_COMPAT
-       .fb_compat_ioctl = sisfb_compat_ioctl,
-#endif
-};
-#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static struct fb_ops sisfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_open        = sisfb_open,
+       .fb_release     = sisfb_release,
+       .fb_check_var   = sisfb_check_var,
+       .fb_set_par     = sisfb_set_par,
+       .fb_setcolreg   = sisfb_setcolreg,
+       .fb_pan_display = sisfb_pan_display,
+       .fb_blank       = sisfb_blank,
+       .fb_fillrect    = fbcon_sis_fillrect,
+       .fb_copyarea    = fbcon_sis_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+#ifdef CONFIG_FB_SOFT_CURSOR
+       .fb_cursor      = soft_cursor,
+#endif
+       .fb_sync        = fbcon_sis_sync,
+#ifdef SIS_NEW_CONFIG_COMPAT
+       .fb_compat_ioctl= sisfb_ioctl,
+#endif
+       .fb_ioctl       = sisfb_ioctl
+};
+#endif
 
 /* ---------------- Chip generation dependent routines ---------------- */
 
-static struct pci_dev * sisfb_get_northbridge(int basechipid)
+static struct pci_dev * __devinit
+sisfb_get_northbridge(int basechipid)
 {
        struct pci_dev *pdev = NULL;
        int nbridgenum, nbridgeidx, i;
-       const unsigned short nbridgeids[] = {
+       static const unsigned short nbridgeids[] = {
                PCI_DEVICE_ID_SI_540,   /* for SiS 540 VGA */
                PCI_DEVICE_ID_SI_630,   /* for SiS 630/730 VGA */
                PCI_DEVICE_ID_SI_730,
@@ -2292,13 +2016,14 @@ static struct pci_dev * sisfb_get_northbridge(int basechipid)
                PCI_DEVICE_ID_SI_650,   /* for SiS 650/651/740 VGA */
                PCI_DEVICE_ID_SI_651,
                PCI_DEVICE_ID_SI_740,
-               PCI_DEVICE_ID_SI_661,   /* for SiS 661/741/660/760 VGA */
+               PCI_DEVICE_ID_SI_661,   /* for SiS 661/741/660/760/761 VGA */
                PCI_DEVICE_ID_SI_741,
                PCI_DEVICE_ID_SI_660,
-               PCI_DEVICE_ID_SI_760
+               PCI_DEVICE_ID_SI_760,
+               PCI_DEVICE_ID_SI_761
        };
 
-       switch(basechipid) {
+       switch(basechipid) {
 #ifdef CONFIG_FB_SIS_300
        case SIS_540:   nbridgeidx = 0; nbridgenum = 1; break;
        case SIS_630:   nbridgeidx = 1; nbridgenum = 2; break;
@@ -2306,35 +2031,40 @@ static struct pci_dev * sisfb_get_northbridge(int basechipid)
 #ifdef CONFIG_FB_SIS_315
        case SIS_550:   nbridgeidx = 3; nbridgenum = 1; break;
        case SIS_650:   nbridgeidx = 4; nbridgenum = 3; break;
-       case SIS_660:   nbridgeidx = 7; nbridgenum = 4; break;
+       case SIS_660:   nbridgeidx = 7; nbridgenum = 5; break;
 #endif
        default:        return NULL;
        }
        for(i = 0; i < nbridgenum; i++) {
-               if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break;
+               if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
+                               nbridgeids[nbridgeidx+i], NULL)))
+                       break;
        }
        return pdev;
 }
 
-static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
+static int __devinit
+sisfb_get_dram_size(struct sis_video_info *ivideo)
 {
 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
        u8 reg;
 #endif
 
        ivideo->video_size = 0;
+       ivideo->UMAsize = ivideo->LFBsize = 0;
 
        switch(ivideo->chip) {
 #ifdef CONFIG_FB_SIS_300
        case SIS_300:
-               inSISIDXREG(SISSR, 0x14, reg);
+               inSISIDXREG(SISSR, 0x14, reg);
                ivideo->video_size = ((reg & 0x3F) + 1) << 20;
                break;
        case SIS_540:
        case SIS_630:
        case SIS_730:
-               if(!ivideo->nbridge) return -1;
-               pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
+               if(!ivideo->nbridge)
+                       return -1;
+               pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
                ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
                break;
 #endif
@@ -2342,45 +2072,68 @@ static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
        case SIS_315H:
        case SIS_315PRO:
        case SIS_315:
-               inSISIDXREG(SISSR, 0x14, reg);
+               inSISIDXREG(SISSR, 0x14, reg);
                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
                switch((reg >> 2) & 0x03) {
                case 0x01:
                case 0x03:
-                  ivideo->video_size <<= 1;
-                  break;
+                       ivideo->video_size <<= 1;
+                       break;
                case 0x02:
-                  ivideo->video_size += (ivideo->video_size/2);
+                       ivideo->video_size += (ivideo->video_size/2);
                }
-               break;
+               break;
        case SIS_330:
-               inSISIDXREG(SISSR, 0x14, reg);
+               inSISIDXREG(SISSR, 0x14, reg);
                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
                if(reg & 0x0c) ivideo->video_size <<= 1;
-               break;
+               break;
        case SIS_550:
        case SIS_650:
        case SIS_740:
-               inSISIDXREG(SISSR, 0x14, reg);
+               inSISIDXREG(SISSR, 0x14, reg);
                ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
                break;
        case SIS_661:
        case SIS_741:
-               inSISIDXREG(SISCR, 0x79, reg);
+               inSISIDXREG(SISCR, 0x79, reg);
                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
-               break;
+               break;
        case SIS_660:
        case SIS_760:
+       case SIS_761:
                inSISIDXREG(SISCR, 0x79, reg);
                reg = (reg & 0xf0) >> 4;
-               if(reg) ivideo->video_size = (1 << reg) << 20;
+               if(reg) {
+                       ivideo->video_size = (1 << reg) << 20;
+                       ivideo->UMAsize = ivideo->video_size;
+               }
                inSISIDXREG(SISCR, 0x78, reg);
                reg &= 0x30;
                if(reg) {
-                  if(reg == 0x10) ivideo->video_size += (32 << 20);
-                  else            ivideo->video_size += (64 << 20);
+                       if(reg == 0x10) {
+                               ivideo->LFBsize = (32 << 20);
+                       } else {
+                               ivideo->LFBsize = (64 << 20);
+                       }
+                       ivideo->video_size += ivideo->LFBsize;
+               }
+               break;
+       case SIS_340:
+       case XGI_20:
+       case XGI_40:
+               inSISIDXREG(SISSR, 0x14, reg);
+               ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
+               if(ivideo->chip != XGI_20) {
+                       reg = (reg & 0x0c) >> 2;
+                       if(ivideo->revision_id == 2) {
+                               if(reg & 0x01) reg = 0x02;
+                               else           reg = 0x00;
+                       }
+                       if(reg == 0x02)         ivideo->video_size <<= 1;
+                       else if(reg == 0x03)    ivideo->video_size <<= 2;
                }
-               break;
+               break;
 #endif
        default:
                return -1;
@@ -2390,17 +2143,24 @@ static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
 
 /* -------------- video bridge device detection --------------- */
 
-static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
+static void __devinit
+sisfb_detect_VB_connect(struct sis_video_info *ivideo)
 {
        u8 cr32, temp;
 
+       /* No CRT2 on XGI Z7 */
+       if(ivideo->chip == XGI_20) {
+               ivideo->sisfb_crt1off = 0;
+               return;
+       }
+
 #ifdef CONFIG_FB_SIS_300
        if(ivideo->sisvga_engine == SIS_300_VGA) {
                inSISIDXREG(SISSR, 0x17, temp);
                if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
                        /* PAL/NTSC is stored on SR16 on such machines */
                        if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
-                               inSISIDXREG(SISSR, 0x16, temp);
+                               inSISIDXREG(SISSR, 0x16, temp);
                                if(temp & 0x20)
                                        ivideo->vbflags |= TV_PAL;
                                else
@@ -2435,28 +2195,29 @@ static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
 
        if(ivideo->sisfb_tvplug != -1) {
           if( (ivideo->sisvga_engine != SIS_315_VGA) ||
-              (!(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) ) {
+              (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
              if(ivideo->sisfb_tvplug & TV_YPBPR) {
-                ivideo->sisfb_tvplug = -1;
+                ivideo->sisfb_tvplug = -1;
                 printk(KERN_ERR "sisfb: YPbPr not supported\n");
              }
           }
        }
        if(ivideo->sisfb_tvplug != -1) {
           if( (ivideo->sisvga_engine != SIS_315_VGA) ||
-              (!(ivideo->vbflags & (VB_301|VB_301B|VB_302B))) ) {
+              (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
              if(ivideo->sisfb_tvplug & TV_HIVISION) {
-                ivideo->sisfb_tvplug = -1;
+                ivideo->sisfb_tvplug = -1;
                 printk(KERN_ERR "sisfb: HiVision not supported\n");
              }
           }
        }
        if(ivideo->sisfb_tvstd != -1) {
-          if( (!(ivideo->vbflags & VB_SISBRIDGE)) &&
-              (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags & VB_CHRONTEL))) ) {
+          if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
+              (!((ivideo->sisvga_engine == SIS_315_VGA) &&
+                       (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
              if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
-                ivideo->sisfb_tvstd = -1;
-                printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
+                ivideo->sisfb_tvstd = -1;
+                printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
              }
           }
        }
@@ -2468,7 +2229,7 @@ static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
                if(cr32 & SIS_VB_YPBPR)          ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
                else if(cr32 & SIS_VB_HIVISION)  ivideo->vbflags |= TV_HIVISION;
                else if(cr32 & SIS_VB_SCART)     ivideo->vbflags |= TV_SCART;
-               else {
+               else {
                        if(cr32 & SIS_VB_SVIDEO)    ivideo->vbflags |= TV_SVIDEO;
                        if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
                }
@@ -2485,165 +2246,44 @@ static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
            }
            if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
                if(ivideo->sisvga_engine == SIS_300_VGA) {
-                       inSISIDXREG(SISSR, 0x38, temp);
+                       inSISIDXREG(SISSR, 0x38, temp);
                        if(temp & 0x01) ivideo->vbflags |= TV_PAL;
                        else            ivideo->vbflags |= TV_NTSC;
                } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
-                       inSISIDXREG(SISSR, 0x38, temp);
+                       inSISIDXREG(SISSR, 0x38, temp);
                        if(temp & 0x01) ivideo->vbflags |= TV_PAL;
                        else            ivideo->vbflags |= TV_NTSC;
-               } else {
-                       inSISIDXREG(SISCR, 0x79, temp);
+               } else {
+                       inSISIDXREG(SISCR, 0x79, temp);
                        if(temp & 0x20) ivideo->vbflags |= TV_PAL;
                        else            ivideo->vbflags |= TV_NTSC;
-               }
+               }
            }
        }
 
        /* Copy forceCRT1 option to CRT1off if option is given */
-       if(ivideo->sisfb_forcecrt1 != -1) {
-          ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
-       }
-}
-
-static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo)
-{
-       char stdstr[]    = "sisfb: Detected";
-       char bridgestr[] = "video bridge";
-       u8 vb_chipid;
-       u8 reg;
-
-       inSISIDXREG(SISPART4, 0x00, vb_chipid);
-       switch(vb_chipid) {
-       case 0x01:
-               inSISIDXREG(SISPART4, 0x01, reg);
-               if(reg < 0xb0) {
-                       ivideo->vbflags |= VB_301;
-                       printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
-               } else if(reg < 0xc0) {
-                       ivideo->vbflags |= VB_301B;
-                       inSISIDXREG(SISPART4,0x23,reg);
-                       if(!(reg & 0x02)) {
-                          ivideo->vbflags |= VB_30xBDH;
-                          printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
-                       } else {
-                          printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
-                       }
-               } else if(reg < 0xd0) {
-                       ivideo->vbflags |= VB_301C;
-                       printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
-               } else if(reg < 0xe0) {
-                       ivideo->vbflags |= VB_301LV;
-                       printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
-               } else if(reg <= 0xe1) {
-                       inSISIDXREG(SISPART4,0x39,reg);
-                       if(reg == 0xff) {
-                          ivideo->vbflags |= VB_302LV;
-                          printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
-                       } else {
-                          ivideo->vbflags |= VB_301C;
-                          printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
-#if 0
-                          ivideo->vbflags |= VB_302ELV;
-                          printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
-#endif
-                       }
-               }
-               break;
-       case 0x02:
-               ivideo->vbflags |= VB_302B;
-               printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
-               break;
-       }
-
-       if((!(ivideo->vbflags & VB_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
-               inSISIDXREG(SISCR, 0x37, reg);
-               reg &= SIS_EXTERNAL_CHIP_MASK;
-               reg >>= 1;
-               if(ivideo->sisvga_engine == SIS_300_VGA) {
-#ifdef CONFIG_FB_SIS_300
-                       switch(reg) {
-                          case SIS_EXTERNAL_CHIP_LVDS:
-                               ivideo->vbflags |= VB_LVDS;
-                               break;
-                          case SIS_EXTERNAL_CHIP_TRUMPION:
-                               ivideo->vbflags |= VB_TRUMPION;
-                               break;
-                          case SIS_EXTERNAL_CHIP_CHRONTEL:
-                               ivideo->vbflags |= VB_CHRONTEL;
-                               break;
-                          case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
-                               ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
-                               break;
-                       }
-                       if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 1;
-#endif
-               } else if(ivideo->chip < SIS_661) {
-#ifdef CONFIG_FB_SIS_315
-                       switch (reg) {
-                          case SIS310_EXTERNAL_CHIP_LVDS:
-                               ivideo->vbflags |= VB_LVDS;
-                               break;
-                          case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
-                               ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
-                               break;
-                       }
-                       if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
-#endif
-               } else if(ivideo->chip >= SIS_661) {
-#ifdef CONFIG_FB_SIS_315
-                       inSISIDXREG(SISCR, 0x38, reg);
-                       reg >>= 5;
-                       switch(reg) {
-                          case 0x02:
-                               ivideo->vbflags |= VB_LVDS;
-                               break;
-                          case 0x03:
-                               ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
-                               break;
-                          case 0x04:
-                               ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);
-                               break;
-                       }
-                       if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
-#endif
-               }
-               if(ivideo->vbflags & VB_LVDS) {
-                  printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
-               }
-               if(ivideo->vbflags & VB_TRUMPION) {
-                  printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
-               }
-               if(ivideo->vbflags & VB_CHRONTEL) {
-                  printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
-               }
-               if(ivideo->vbflags & VB_CONEXANT) {
-                  printk(KERN_INFO "%s Conexant external device\n", stdstr);
-               }
-       }
-
-       if(ivideo->vbflags & VB_SISBRIDGE) {
-               SiS_Sense30x(ivideo);
-       } else if(ivideo->vbflags & VB_CHRONTEL) {
-               SiS_SenseCh(ivideo);
+       if(ivideo->sisfb_forcecrt1 != -1) {
+          ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
        }
 }
 
 /* ------------------ Sensing routines ------------------ */
 
-static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo)
+static BOOLEAN __devinit
+sisfb_test_DDC1(struct sis_video_info *ivideo)
 {
     unsigned short old;
     int count = 48;
 
     old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
     do {
-               if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
+       if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
     } while(count--);
     return (count == -1) ? FALSE : TRUE;
 }
 
-static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
+static void __devinit
+sisfb_sense_crt1(struct sis_video_info *ivideo)
 {
     BOOLEAN mustwait = FALSE;
     u8  sr1F, cr17;
@@ -2699,7 +2339,8 @@ static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
     if(temp == 0xffff) {
        i = 3;
        do {
-          temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, 0, 0, NULL);
+         temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
+               ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
        } while(((temp == 0) || (temp == 0xffff)) && i--);
 
        if((temp == 0) || (temp == 0xffff)) {
@@ -2723,7 +2364,96 @@ static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
 }
 
 /* Determine and detect attached devices on SiS30x */
-static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
+static void __devinit
+SiS_SenseLCD(struct sis_video_info *ivideo)
+{
+       unsigned char buffer[256];
+       unsigned short temp, realcrtno, i;
+       u8 reg, cr37 = 0, paneltype = 0;
+       u16 xres, yres;
+
+       ivideo->SiS_Pr.PanelSelfDetected = FALSE;
+
+       /* LCD detection only for TMDS bridges */
+       if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
+               return;
+       if(ivideo->vbflags2 & VB2_30xBDH)
+               return;
+
+       /* If LCD already set up by BIOS, skip it */
+       inSISIDXREG(SISCR, 0x32, reg);
+       if(reg & 0x08)
+               return;
+
+       realcrtno = 1;
+       if(ivideo->SiS_Pr.DDCPortMixup)
+               realcrtno = 0;
+
+       /* Check DDC capabilities */
+       temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
+                               realcrtno, 0, &buffer[0], ivideo->vbflags2);
+
+       if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
+               return;
+
+       /* Read DDC data */
+       i = 3;  /* Number of retrys */
+       do {
+               temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
+                               ivideo->sisvga_engine, realcrtno, 1,
+                               &buffer[0], ivideo->vbflags2);
+       } while((temp) && i--);
+
+       if(temp)
+               return;
+
+       /* No digital device */
+       if(!(buffer[0x14] & 0x80))
+               return;
+
+       /* First detailed timing preferred timing? */
+       if(!(buffer[0x18] & 0x02))
+               return;
+
+       xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
+       yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
+
+       switch(xres) {
+               case 1024:
+                       if(yres == 768)
+                               paneltype = 0x02;
+                       break;
+               case 1280:
+                       if(yres == 1024)
+                               paneltype = 0x03;
+                       break;
+               case 1600:
+                       if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
+                               paneltype = 0x0b;
+                       break;
+       }
+
+       if(!paneltype)
+               return;
+
+       if(buffer[0x23])
+               cr37 |= 0x10;
+
+       if((buffer[0x47] & 0x18) == 0x18)
+               cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
+       else
+               cr37 |= 0xc0;
+
+       outSISIDXREG(SISCR, 0x36, paneltype);
+       cr37 &= 0xf1;
+       setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
+       orSISIDXREG(SISCR, 0x32, 0x08);
+
+       ivideo->SiS_Pr.PanelSelfDetected = TRUE;
+}
+
+static int __devinit
+SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
 {
     int temp, mytest, result, i, j;
 
@@ -2749,10 +2479,11 @@ static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 tes
        }
        if((result == 0) || (result >= 2)) break;
     }
-    return(result);
+    return result;
 }
 
-static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
+static void __devinit
+SiS_Sense30x(struct sis_video_info *ivideo)
 {
     u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
     u16 svhs=0, svhs_c=0;
@@ -2762,36 +2493,51 @@ static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
     char stdstr[] = "sisfb: Detected";
     char tvstr[]  = "TV connected to";
 
-    if(ivideo->vbflags & VB_301) {
+    if(ivideo->vbflags2 & VB2_301) {
        svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
        inSISIDXREG(SISPART4,0x01,myflag);
        if(myflag & 0x04) {
          svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
        }
-    } else if(ivideo->vbflags & (VB_301B | VB_302B)) {
+    } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
        svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
-    } else if(ivideo->vbflags & (VB_301LV | VB_302LV)) {
+    } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
        svhs = 0x0200; cvbs = 0x0100;
-    } else if(ivideo->vbflags & (VB_301C | VB_302ELV)) {
+    } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
        svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
-    } else return;
+    } else
+       return;
 
     vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
-    if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
+    if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
        svhs_c = 0x0408; cvbs_c = 0x0808;
     }
+
     biosflag = 2;
+    if(ivideo->haveXGIROM) {
+       biosflag = ivideo->bios_abase[0x58] & 0x03;
+    } else if(ivideo->newrom) {
+       if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
+    } else if(ivideo->sisvga_engine == SIS_300_VGA) {
+       if(ivideo->bios_abase) {
+          biosflag = ivideo->bios_abase[0xfe] & 0x03;
+       }
+    }
 
     if(ivideo->chip == SIS_300) {
        inSISIDXREG(SISSR,0x3b,myflag);
        if(!(myflag & 0x01)) vga2 = vga2_c = 0;
     }
 
+    if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
+       vga2 = vga2_c = 0;
+    }
+
     inSISIDXREG(SISSR,0x1e,backupSR_1e);
     orSISIDXREG(SISSR,0x1e,0x20);
 
     inSISIDXREG(SISPART4,0x0d,backupP4_0d);
-    if(ivideo->vbflags & VB_301C) {
+    if(ivideo->vbflags2 & VB2_30xC) {
        setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
     } else {
        orSISIDXREG(SISPART4,0x0d,0x04);
@@ -2802,11 +2548,11 @@ static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
     outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
 
     inSISIDXREG(SISPART2,0x4d,backupP2_4d);
-    if(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV)) {
+    if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
        outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
     }
 
-    if(!(ivideo->vbflags & VB_301C)) {
+    if(!(ivideo->vbflags2 & VB2_30xCLV)) {
        SISDoSense(ivideo, 0, 0);
     }
 
@@ -2826,12 +2572,11 @@ static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
 
     andSISIDXREG(SISCR, 0x32, 0x3f);
 
-    if(ivideo->vbflags & VB_301C) {
+    if(ivideo->vbflags2 & VB2_30xCLV) {
        orSISIDXREG(SISPART4,0x0d,0x04);
     }
 
-    if((ivideo->sisvga_engine == SIS_315_VGA) &&
-       (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV))) {
+    if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
        outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
        if((result = SISDoSense(ivideo, svhs, 0x0604))) {
@@ -2864,7 +2609,7 @@ static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
     outSISIDXREG(SISPART4,0x0d,backupP4_0d);
     outSISIDXREG(SISSR,0x1e,backupSR_1e);
 
-    if(ivideo->vbflags & VB_301C) {
+    if(ivideo->vbflags2 & VB2_30xCLV) {
        inSISIDXREG(SISPART2,0x00,biosflag);
        if(biosflag & 0x20) {
           for(myflag = 2; myflag > 0; myflag--) {
@@ -2878,7 +2623,8 @@ static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
 }
 
 /* Determine and detect attached TV's on Chrontel */
-static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
+static void __devinit
+SiS_SenseCh(struct sis_video_info *ivideo)
 {
 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
     u8 temp1, temp2;
@@ -2899,7 +2645,7 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
        /* See Chrontel TB31 for explanation */
        temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
        if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
-         SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b0e);
+         SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
          SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
        }
        temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
@@ -2909,15 +2655,15 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
           /* Read power status */
           temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
           if((temp1 & 0x03) != 0x03) {
-               /* Power all outputs */
-               SiS_SetCH700x(&ivideo->SiS_Pr, 0x0B0E);
+               /* Power all outputs */
+               SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
                SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
           }
           /* Sense connected TV devices */
           for(i = 0; i < 3; i++) {
-              SiS_SetCH700x(&ivideo->SiS_Pr, 0x0110);
+              SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
               SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
-              SiS_SetCH700x(&ivideo->SiS_Pr, 0x0010);
+              SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
               SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
               temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
               if(!(temp1 & 0x08))       test[i] = 0x02;
@@ -2930,7 +2676,7 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
           else if(test[0] == test[2]) temp1 = test[0];
           else if(test[1] == test[2]) temp1 = test[1];
           else {
-               printk(KERN_INFO
+               printk(KERN_INFO
                        "sisfb: TV detection unreliable - test results varied\n");
                temp1 = test[2];
           }
@@ -2945,11 +2691,11 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
                orSISIDXREG(SISCR, 0x32, 0x01);
                andSISIDXREG(SISCR, 0x32, ~0x06);
           } else {
-               SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
+               SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
                andSISIDXREG(SISCR, 0x32, ~0x07);
           }
        } else if(temp1 == 0) {
-         SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
+         SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
          andSISIDXREG(SISCR, 0x32, ~0x07);
        }
        /* Set general purpose IO for Chrontel communication */
@@ -2960,19 +2706,19 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
 
 #ifdef CONFIG_FB_SIS_315
        ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2;           /* Chrontel 7019 */
-        temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
-       SiS_SetCH701x(&ivideo->SiS_Pr, 0x2049);
+       temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
+       SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
        temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
        temp2 |= 0x01;
-       SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
+       SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
        temp2 ^= 0x01;
-       SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
+       SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
        temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
-       SiS_SetCH701x(&ivideo->SiS_Pr, (temp1 << 8) | 0x49);
-        temp1 = 0;
+       SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
+       temp1 = 0;
        if(temp2 & 0x02) temp1 |= 0x01;
        if(temp2 & 0x10) temp1 |= 0x01;
        if(temp2 & 0x04) temp1 |= 0x02;
@@ -2983,18 +2729,18 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
             ivideo->vbflags |= TV_AVIDEO;
             orSISIDXREG(SISCR, 0x32, 0x01);
             andSISIDXREG(SISCR, 0x32, ~0x06);
-             break;
+            break;
        case 0x02:
             printk(KERN_INFO "%s SVIDEO output\n", stdstr);
             ivideo->vbflags |= TV_SVIDEO;
             orSISIDXREG(SISCR, 0x32, 0x02);
             andSISIDXREG(SISCR, 0x32, ~0x05);
-             break;
+            break;
        case 0x04:
             printk(KERN_INFO "%s SCART output\n", stdstr);
             orSISIDXREG(SISCR, 0x32, 0x04);
             andSISIDXREG(SISCR, 0x32, ~0x03);
-             break;
+            break;
        default:
             andSISIDXREG(SISCR, 0x32, ~0x07);
        }
@@ -3002,165 +2748,589 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
     }
 }
 
-/* ------------------------ Heap routines -------------------------- */
-
-static u32 __devinit
-sisfb_getheapstart(struct sis_video_info *ivideo)
+static void __devinit
+sisfb_get_VB_type(struct sis_video_info *ivideo)
 {
-       u32 ret = ivideo->sisfb_parm_mem * 1024;
-       u32 max = ivideo->video_size - ivideo->hwcursor_size;
-       u32 def;
+       char stdstr[]    = "sisfb: Detected";
+       char bridgestr[] = "video bridge";
+       u8 vb_chipid;
+       u8 reg;
 
-       /* Calculate heap start = end of memory for console
-        *
-        * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
-        * C = console, D = heap, H = HWCursor, Q = cmd-queue
-        *
-        * Basically given by "mem" parameter
-        *
-        * maximum = videosize - cmd_queue - hwcursor
-        *           (results in a heap of size 0)
-        * default = SiS 300: depends on videosize
-        *           SiS 315/330: 32k below max
-        */
+       /* No CRT2 on XGI Z7 */
+       if(ivideo->chip == XGI_20)
+               return;
 
-       if(ivideo->sisvga_engine == SIS_300_VGA) {
-          max -= TURBO_QUEUE_AREA_SIZE;
-          if(ivideo->video_size > 0x1000000) {
-             def = 0xc00000;
-          } else if(ivideo->video_size > 0x800000) {
-             def = 0x800000;
-          } else {
-             def = 0x400000;
-          }
-       } else {
-          max -= COMMAND_QUEUE_AREA_SIZE;
-          def = max - 0x8000;
+       inSISIDXREG(SISPART4, 0x00, vb_chipid);
+       switch(vb_chipid) {
+       case 0x01:
+               inSISIDXREG(SISPART4, 0x01, reg);
+               if(reg < 0xb0) {
+                       ivideo->vbflags |= VB_301;      /* Deprecated */
+                       ivideo->vbflags2 |= VB2_301;
+                       printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
+               } else if(reg < 0xc0) {
+                       ivideo->vbflags |= VB_301B;     /* Deprecated */
+                       ivideo->vbflags2 |= VB2_301B;
+                       inSISIDXREG(SISPART4,0x23,reg);
+                       if(!(reg & 0x02)) {
+                          ivideo->vbflags |= VB_30xBDH;        /* Deprecated */
+                          ivideo->vbflags2 |= VB2_30xBDH;
+                          printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
+                       } else {
+                          printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
+                       }
+               } else if(reg < 0xd0) {
+                       ivideo->vbflags |= VB_301C;     /* Deprecated */
+                       ivideo->vbflags2 |= VB2_301C;
+                       printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
+               } else if(reg < 0xe0) {
+                       ivideo->vbflags |= VB_301LV;    /* Deprecated */
+                       ivideo->vbflags2 |= VB2_301LV;
+                       printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
+               } else if(reg <= 0xe1) {
+                       inSISIDXREG(SISPART4,0x39,reg);
+                       if(reg == 0xff) {
+                          ivideo->vbflags |= VB_302LV; /* Deprecated */
+                          ivideo->vbflags2 |= VB2_302LV;
+                          printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
+                       } else {
+                          ivideo->vbflags |= VB_301C;  /* Deprecated */
+                          ivideo->vbflags2 |= VB2_301C;
+                          printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
+#if 0
+                          ivideo->vbflags |= VB_302ELV;        /* Deprecated */
+                          ivideo->vbflags2 |= VB2_302ELV;
+                          printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
+#endif
+                       }
+               }
+               break;
+       case 0x02:
+               ivideo->vbflags |= VB_302B;     /* Deprecated */
+               ivideo->vbflags2 |= VB2_302B;
+               printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
+               break;
        }
 
-        if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) {
-          ret = def;
-        }
+       if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
+               inSISIDXREG(SISCR, 0x37, reg);
+               reg &= SIS_EXTERNAL_CHIP_MASK;
+               reg >>= 1;
+               if(ivideo->sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
+                       switch(reg) {
+                          case SIS_EXTERNAL_CHIP_LVDS:
+                               ivideo->vbflags |= VB_LVDS;     /* Deprecated */
+                               ivideo->vbflags2 |= VB2_LVDS;
+                               break;
+                          case SIS_EXTERNAL_CHIP_TRUMPION:
+                               ivideo->vbflags |= (VB_LVDS | VB_TRUMPION);     /* Deprecated */
+                               ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
+                               break;
+                          case SIS_EXTERNAL_CHIP_CHRONTEL:
+                               ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
+                               ivideo->vbflags2 |= VB2_CHRONTEL;
+                               break;
+                          case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
+                               ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
+                               ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
+                               break;
+                       }
+                       if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
+#endif
+               } else if(ivideo->chip < SIS_661) {
+#ifdef CONFIG_FB_SIS_315
+                       switch (reg) {
+                          case SIS310_EXTERNAL_CHIP_LVDS:
+                               ivideo->vbflags |= VB_LVDS;     /* Deprecated */
+                               ivideo->vbflags2 |= VB2_LVDS;
+                               break;
+                          case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
+                               ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
+                               ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
+                               break;
+                       }
+                       if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
+#endif
+               } else if(ivideo->chip >= SIS_661) {
+#ifdef CONFIG_FB_SIS_315
+                       inSISIDXREG(SISCR, 0x38, reg);
+                       reg >>= 5;
+                       switch(reg) {
+                          case 0x02:
+                               ivideo->vbflags |= VB_LVDS;     /* Deprecated */
+                               ivideo->vbflags2 |= VB2_LVDS;
+                               break;
+                          case 0x03:
+                               ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
+                               ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
+                               break;
+                          case 0x04:
+                               ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);     /* Deprecated */
+                               ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
+                               break;
+                       }
+                       if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
+#endif
+               }
+               if(ivideo->vbflags2 & VB2_LVDS) {
+                  printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
+               }
+               if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
+                  printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
+               }
+               if(ivideo->vbflags2 & VB2_CHRONTEL) {
+                  printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
+               }
+               if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
+                  printk(KERN_INFO "%s Conexant external device\n", stdstr);
+               }
+       }
 
-       return ret;
+       if(ivideo->vbflags2 & VB2_SISBRIDGE) {
+               SiS_SenseLCD(ivideo);
+               SiS_Sense30x(ivideo);
+       } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
+               SiS_SenseCh(ivideo);
+       }
 }
 
-static int __devinit
-sisfb_heap_init(struct sis_video_info *ivideo)
-{
-     SIS_OH *poh;
-
-     ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo);
+/* ---------- Engine initialization routines ------------ */
 
-     ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
-     ivideo->sisfb_heap_end   = ivideo->video_vbase + ivideo->video_size;
+static void
+sisfb_engine_init(struct sis_video_info *ivideo)
+{
 
-     /* Initialize command queue (We use MMIO only) */
+       /* Initialize command queue (we use MMIO only) */
 
-#ifdef CONFIG_FB_SIS_315
-     if(ivideo->sisvga_engine == SIS_315_VGA) {
-        u32 tempq = 0;
-       u8  temp = 0;
+       /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
 
-        ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
+       ivideo->caps &= ~(TURBO_QUEUE_CAP    |
+                         MMIO_CMD_QUEUE_CAP |
+                         VM_CMD_QUEUE_CAP   |
+                         AGP_CMD_QUEUE_CAP);
 
-       outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
-       outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
+#ifdef CONFIG_FB_SIS_300
+       if(ivideo->sisvga_engine == SIS_300_VGA) {
+               u32 tqueue_pos;
+               u8 tq_state;
 
-       tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
-       MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
+               tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
 
-       temp = SIS_CMD_QUEUE_SIZE_512k;
-       temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
-       outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
+               inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
+               tq_state |= 0xf0;
+               tq_state &= 0xfc;
+               tq_state |= (u8)(tqueue_pos >> 8);
+               outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
 
-       tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE);
-       MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
+               outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
 
-       ivideo->caps |= MMIO_CMD_QUEUE_CAP;
-     }
+               ivideo->caps |= TURBO_QUEUE_CAP;
+       }
 #endif
 
+#ifdef CONFIG_FB_SIS_315
+       if(ivideo->sisvga_engine == SIS_315_VGA) {
+               u32 tempq = 0, templ;
+               u8  temp;
+
+               if(ivideo->chip == XGI_20) {
+                       switch(ivideo->cmdQueueSize) {
+                       case (64 * 1024):
+                               temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
+                               break;
+                       case (128 * 1024):
+                       default:
+                               temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
+                       }
+               } else {
+                       switch(ivideo->cmdQueueSize) {
+                       case (4 * 1024 * 1024):
+                               temp = SIS_CMD_QUEUE_SIZE_4M;
+                               break;
+                       case (2 * 1024 * 1024):
+                               temp = SIS_CMD_QUEUE_SIZE_2M;
+                               break;
+                       case (1 * 1024 * 1024):
+                               temp = SIS_CMD_QUEUE_SIZE_1M;
+                               break;
+                       default:
+                       case (512 * 1024):
+                               temp = SIS_CMD_QUEUE_SIZE_512k;
+                       }
+               }
+
+               outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
+               outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
+
+               if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
+                       /* Must disable dual pipe on XGI_40. Can't do
+                        * this in MMIO mode, because it requires
+                        * setting/clearing a bit in the MMIO fire trigger
+                        * register.
+                        */
+                       if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
+
+                               MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
+
+                               outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
+
+                               tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
+                               MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
+
+                               tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
+                               MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
+
+                               writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
+                               writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
+                               writel(0x168F0000, ivideo->video_vbase + tempq + 8);
+                               writel(0x168F0000, ivideo->video_vbase + tempq + 12);
+
+                               MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
+
+                               sisfb_syncaccel(ivideo);
+
+                               outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
+
+                       }
+               }
+
+               tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
+               MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
+
+               temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
+               outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
+
+               tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
+               MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
+
+               ivideo->caps |= MMIO_CMD_QUEUE_CAP;
+       }
+#endif
+
+       ivideo->engineok = 1;
+}
+
+static void __devinit
+sisfb_detect_lcd_type(struct sis_video_info *ivideo)
+{
+       u8 reg;
+       int i;
+
+       inSISIDXREG(SISCR, 0x36, reg);
+       reg &= 0x0f;
+       if(ivideo->sisvga_engine == SIS_300_VGA) {
+               ivideo->CRT2LCDType = sis300paneltype[reg];
+       } else if(ivideo->chip >= SIS_661) {
+               ivideo->CRT2LCDType = sis661paneltype[reg];
+       } else {
+               ivideo->CRT2LCDType = sis310paneltype[reg];
+               if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
+                       if((ivideo->CRT2LCDType != LCD_320x240_2) &&
+                          (ivideo->CRT2LCDType != LCD_320x240_3)) {
+                               ivideo->CRT2LCDType = LCD_320x240;
+                       }
+               }
+       }
+
+       if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
+               /* For broken BIOSes: Assume 1024x768, RGB18 */
+               ivideo->CRT2LCDType = LCD_1024x768;
+               setSISIDXREG(SISCR,0x36,0xf0,0x02);
+               setSISIDXREG(SISCR,0x37,0xee,0x01);
+               printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
+       }
+
+       for(i = 0; i < SIS_LCD_NUMBER; i++) {
+               if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
+                       ivideo->lcdxres = sis_lcd_data[i].xres;
+                       ivideo->lcdyres = sis_lcd_data[i].yres;
+                       ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
+                       break;
+               }
+       }
+
+#ifdef CONFIG_FB_SIS_300
+       if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
+               ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
+               ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
+       } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
+               ivideo->lcdxres =  848; ivideo->lcdyres =  480;
+               ivideo->lcddefmodeidx = DEFAULT_MODE_848;
+       } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
+               ivideo->lcdxres =  856; ivideo->lcdyres =  480;
+               ivideo->lcddefmodeidx = DEFAULT_MODE_856;
+       }
+#endif
+
+       printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
+                       ivideo->lcdxres, ivideo->lcdyres);
+}
+
+static void __devinit
+sisfb_save_pdc_emi(struct sis_video_info *ivideo)
+{
 #ifdef CONFIG_FB_SIS_300
-     if(ivideo->sisvga_engine == SIS_300_VGA) {
-       unsigned long tqueue_pos;
-       u8 tq_state;
+       /* Save the current PanelDelayCompensation if the LCD is currently used */
+       if(ivideo->sisvga_engine == SIS_300_VGA) {
+               if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
+                       int tmp;
+                       inSISIDXREG(SISCR,0x30,tmp);
+                       if(tmp & 0x20) {
+                               /* Currently on LCD? If yes, read current pdc */
+                               inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
+                               ivideo->detectedpdc &= 0x3c;
+                               if(ivideo->SiS_Pr.PDC == -1) {
+                                       /* Let option override detection */
+                                       ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
+                               }
+                               printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
+                                       ivideo->detectedpdc);
+                       }
+                       if((ivideo->SiS_Pr.PDC != -1) &&
+                          (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
+                               printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
+                                       ivideo->SiS_Pr.PDC);
+                       }
+               }
+       }
+#endif
+
+#ifdef CONFIG_FB_SIS_315
+       if(ivideo->sisvga_engine == SIS_315_VGA) {
 
-       ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
+               /* Try to find about LCDA */
+               if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
+                       int tmp;
+                       inSISIDXREG(SISPART1,0x13,tmp);
+                       if(tmp & 0x04) {
+                               ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
+                               ivideo->detectedlcda = 0x03;
+                       }
+               }
 
-       tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
+               /* Save PDC */
+               if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
+                       int tmp;
+                       inSISIDXREG(SISCR,0x30,tmp);
+                       if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
+                               /* Currently on LCD? If yes, read current pdc */
+                               u8 pdc;
+                               inSISIDXREG(SISPART1,0x2D,pdc);
+                               ivideo->detectedpdc  = (pdc & 0x0f) << 1;
+                               ivideo->detectedpdca = (pdc & 0xf0) >> 3;
+                               inSISIDXREG(SISPART1,0x35,pdc);
+                               ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
+                               inSISIDXREG(SISPART1,0x20,pdc);
+                               ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
+                               if(ivideo->newrom) {
+                                       /* New ROM invalidates other PDC resp. */
+                                       if(ivideo->detectedlcda != 0xff) {
+                                               ivideo->detectedpdc = 0xff;
+                                       } else {
+                                               ivideo->detectedpdca = 0xff;
+                                       }
+                               }
+                               if(ivideo->SiS_Pr.PDC == -1) {
+                                       if(ivideo->detectedpdc != 0xff) {
+                                               ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
+                                       }
+                               }
+                               if(ivideo->SiS_Pr.PDCA == -1) {
+                                       if(ivideo->detectedpdca != 0xff) {
+                                               ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
+                                       }
+                               }
+                               if(ivideo->detectedpdc != 0xff) {
+                                       printk(KERN_INFO
+                                               "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
+                                               ivideo->detectedpdc);
+                               }
+                               if(ivideo->detectedpdca != 0xff) {
+                                       printk(KERN_INFO
+                                               "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
+                                               ivideo->detectedpdca);
+                               }
+                       }
 
-       inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
-       tq_state |= 0xf0;
-       tq_state &= 0xfc;
-       tq_state |= (u8)(tqueue_pos >> 8);
-       outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
+                       /* Save EMI */
+                       if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
+                               inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
+                               inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
+                               inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
+                               inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
+                               ivideo->SiS_Pr.HaveEMI = TRUE;
+                               if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
+                                       ivideo->SiS_Pr.HaveEMILCD = TRUE;
+                               }
+                       }
+               }
 
-       outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
+               /* Let user override detected PDCs (all bridges) */
+               if(ivideo->vbflags2 & VB2_30xBLV) {
+                       if((ivideo->SiS_Pr.PDC != -1) &&
+                          (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
+                               printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
+                                       ivideo->SiS_Pr.PDC);
+                       }
+                       if((ivideo->SiS_Pr.PDCA != -1) &&
+                          (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
+                               printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
+                                ivideo->SiS_Pr.PDCA);
+                       }
+               }
 
-       ivideo->caps |= TURBO_QUEUE_CAP;
-     }
+       }
 #endif
+}
+
+/* -------------------- Memory manager routines ---------------------- */
+
+static u32 __devinit
+sisfb_getheapstart(struct sis_video_info *ivideo)
+{
+       u32 ret = ivideo->sisfb_parm_mem * 1024;
+       u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
+       u32 def;
+
+       /* Calculate heap start = end of memory for console
+        *
+        * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
+        * C = console, D = heap, H = HWCursor, Q = cmd-queue
+        *
+        * On 76x in UMA+LFB mode, the layout is as follows:
+        * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
+        * where the heap is the entire UMA area, eventually
+        * into the LFB area if the given mem parameter is
+        * higher than the size of the UMA memory.
+        *
+        * Basically given by "mem" parameter
+        *
+        * maximum = videosize - cmd_queue - hwcursor
+        *           (results in a heap of size 0)
+        * default = SiS 300: depends on videosize
+        *           SiS 315/330/340/XGI: 32k below max
+        */
+
+       if(ivideo->sisvga_engine == SIS_300_VGA) {
+               if(ivideo->video_size > 0x1000000) {
+                       def = 0xc00000;
+               } else if(ivideo->video_size > 0x800000) {
+                       def = 0x800000;
+               } else {
+                       def = 0x400000;
+               }
+       } else if(ivideo->UMAsize && ivideo->LFBsize) {
+               ret = def = 0;
+       } else {
+               def = maxoffs - 0x8000;
+       }
+
+       /* Use default for secondary card for now (FIXME) */
+       if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
+               ret = def;
 
-     /* Reserve memory for the HWCursor */
-     ivideo->sisfb_heap_end -= ivideo->hwcursor_size;
-     ivideo->hwcursor_vbase = ivideo->sisfb_heap_end;
-     ivideo->caps |= HW_CURSOR_CAP;
+       return ret;
+}
+
+static u32 __devinit
+sisfb_getheapsize(struct sis_video_info *ivideo)
+{
+       u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
+       u32 ret = 0;
+
+       if(ivideo->UMAsize && ivideo->LFBsize) {
+               if( (!ivideo->sisfb_parm_mem)                   ||
+                   ((ivideo->sisfb_parm_mem * 1024) > max)     ||
+                   ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
+                       ret = ivideo->UMAsize;
+                       max -= ivideo->UMAsize;
+               } else {
+                       ret = max - (ivideo->sisfb_parm_mem * 1024);
+                       max = ivideo->sisfb_parm_mem * 1024;
+               }
+               ivideo->video_offset = ret;
+               ivideo->sisfb_mem = max;
+       } else {
+               ret = max - ivideo->heapstart;
+               ivideo->sisfb_mem = ivideo->heapstart;
+       }
+
+       return ret;
+}
 
-     ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start;
+static int __devinit
+sisfb_heap_init(struct sis_video_info *ivideo)
+{
+       struct SIS_OH *poh;
 
-     if(ivideo->cardnumber == 0) {
+       ivideo->video_offset = 0;
+       if(ivideo->sisfb_parm_mem) {
+               if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
+                   (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
+                       ivideo->sisfb_parm_mem = 0;
+               }
+       }
 
-       printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
-               (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
+       ivideo->heapstart = sisfb_getheapstart(ivideo);
+       ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
 
-       sisfb_heap.vinfo = ivideo;
+       ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
+       ivideo->sisfb_heap_end   = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
 
-       sisfb_heap.poha_chain = NULL;
-       sisfb_heap.poh_freelist = NULL;
+       printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
+               (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
 
-       poh = sisfb_poh_new_node();
-       if(poh == NULL) return 1;
+       ivideo->sisfb_heap.vinfo = ivideo;
 
-       poh->poh_next = &sisfb_heap.oh_free;
-       poh->poh_prev = &sisfb_heap.oh_free;
-       poh->size = ivideo->sisfb_heap_size;
-       poh->offset = ivideo->heapstart;
+       ivideo->sisfb_heap.poha_chain = NULL;
+       ivideo->sisfb_heap.poh_freelist = NULL;
 
-       sisfb_heap.oh_free.poh_next = poh;
-       sisfb_heap.oh_free.poh_prev = poh;
-       sisfb_heap.oh_free.size = 0;
-       sisfb_heap.max_freesize = poh->size;
+       poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
+       if(poh == NULL)
+               return 1;
 
-       sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
-       sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
-       sisfb_heap.oh_used.size = SENTINEL;
+       poh->poh_next = &ivideo->sisfb_heap.oh_free;
+       poh->poh_prev = &ivideo->sisfb_heap.oh_free;
+       poh->size = ivideo->sisfb_heap_size;
+       poh->offset = ivideo->heapstart;
 
-     } else {
+       ivideo->sisfb_heap.oh_free.poh_next = poh;
+       ivideo->sisfb_heap.oh_free.poh_prev = poh;
+       ivideo->sisfb_heap.oh_free.size = 0;
+       ivideo->sisfb_heap.max_freesize = poh->size;
 
-        printk(KERN_INFO "Skipped heap initialization for secondary cards\n");
+       ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
+       ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
+       ivideo->sisfb_heap.oh_used.size = SENTINEL;
 
-     }
+       if(ivideo->cardnumber == 0) {
+               /* For the first card, make this heap the "global" one
+                * for old DRM (which could handle only one card)
+                */
+               sisfb_heap = &ivideo->sisfb_heap;
+       }
 
-     return 0;
+       return 0;
 }
 
-static SIS_OH *
-sisfb_poh_new_node(void)
+static struct SIS_OH *
+sisfb_poh_new_node(struct SIS_HEAP *memheap)
 {
-       int           i;
-       unsigned long cOhs;
-       SIS_OHALLOC   *poha;
-       SIS_OH        *poh;
+       struct SIS_OHALLOC      *poha;
+       struct SIS_OH           *poh;
+       unsigned long           cOhs;
+       int                     i;
 
-       if(sisfb_heap.poh_freelist == NULL) {
+       if(memheap->poh_freelist == NULL) {
                poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
-               if(!poha) return NULL;
+               if(!poha)
+                       return NULL;
 
-               poha->poha_next = sisfb_heap.poha_chain;
-               sisfb_heap.poha_chain = poha;
+               poha->poha_next = memheap->poha_chain;
+               memheap->poha_chain = poha;
 
-               cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
+               cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
 
                poh = &poha->aoh[0];
                for(i = cOhs - 1; i != 0; i--) {
@@ -3169,32 +3339,32 @@ sisfb_poh_new_node(void)
                }
 
                poh->poh_next = NULL;
-               sisfb_heap.poh_freelist = &poha->aoh[0];
+               memheap->poh_freelist = &poha->aoh[0];
        }
 
-       poh = sisfb_heap.poh_freelist;
-       sisfb_heap.poh_freelist = poh->poh_next;
+       poh = memheap->poh_freelist;
+       memheap->poh_freelist = poh->poh_next;
 
-       return (poh);
+       return poh;
 }
 
-static SIS_OH *
-sisfb_poh_allocate(u32 size)
+static struct SIS_OH *
+sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
 {
-       SIS_OH *pohThis;
-       SIS_OH *pohRoot;
-       int     bAllocated = 0;
+       struct SIS_OH   *pohThis;
+       struct SIS_OH   *pohRoot;
+       int             bAllocated = 0;
 
-       if(size > sisfb_heap.max_freesize) {
+       if(size > memheap->max_freesize) {
                DPRINTK("sisfb: Can't allocate %dk video memory\n",
                        (unsigned int) size / 1024);
-               return (NULL);
+               return NULL;
        }
 
-       pohThis = sisfb_heap.oh_free.poh_next;
+       pohThis = memheap->oh_free.poh_next;
 
-       while(pohThis != &sisfb_heap.oh_free) {
-               if (size <= pohThis->size) {
+       while(pohThis != &memheap->oh_free) {
+               if(size <= pohThis->size) {
                        bAllocated = 1;
                        break;
                }
@@ -3204,18 +3374,16 @@ sisfb_poh_allocate(u32 size)
        if(!bAllocated) {
                DPRINTK("sisfb: Can't allocate %dk video memory\n",
                        (unsigned int) size / 1024);
-               return (NULL);
+               return NULL;
        }
 
        if(size == pohThis->size) {
                pohRoot = pohThis;
                sisfb_delete_node(pohThis);
        } else {
-               pohRoot = sisfb_poh_new_node();
-
-               if(pohRoot == NULL) {
-                       return (NULL);
-               }
+               pohRoot = sisfb_poh_new_node(memheap);
+               if(pohRoot == NULL)
+                       return NULL;
 
                pohRoot->offset = pohThis->offset;
                pohRoot->size = size;
@@ -3224,33 +3392,25 @@ sisfb_poh_allocate(u32 size)
                pohThis->size -= size;
        }
 
-       sisfb_heap.max_freesize -= size;
+       memheap->max_freesize -= size;
 
-       pohThis = &sisfb_heap.oh_used;
+       pohThis = &memheap->oh_used;
        sisfb_insert_node(pohThis, pohRoot);
 
-       return (pohRoot);
+       return pohRoot;
 }
 
 static void
-sisfb_delete_node(SIS_OH *poh)
+sisfb_delete_node(struct SIS_OH *poh)
 {
-       SIS_OH *poh_prev;
-       SIS_OH *poh_next;
-
-       poh_prev = poh->poh_prev;
-       poh_next = poh->poh_next;
-
-       poh_prev->poh_next = poh_next;
-       poh_next->poh_prev = poh_prev;
+       poh->poh_prev->poh_next = poh->poh_next;
+       poh->poh_next->poh_prev = poh->poh_prev;
 }
 
 static void
-sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
+sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
 {
-       SIS_OH *pohTemp;
-
-       pohTemp = pohList->poh_next;
+       struct SIS_OH *pohTemp = pohList->poh_next;
 
        pohList->poh_next = poh;
        pohTemp->poh_prev = poh;
@@ -3259,20 +3419,20 @@ sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
        poh->poh_next = pohTemp;
 }
 
-static SIS_OH *
-sisfb_poh_free(u32 base)
+static struct SIS_OH *
+sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
 {
-       SIS_OH *pohThis;
-       SIS_OH *poh_freed;
-       SIS_OH *poh_prev;
-       SIS_OH *poh_next;
-       u32     ulUpper;
-       u32     ulLower;
-       int     foundNode = 0;
+       struct SIS_OH *pohThis;
+       struct SIS_OH *poh_freed;
+       struct SIS_OH *poh_prev;
+       struct SIS_OH *poh_next;
+       u32    ulUpper;
+       u32    ulLower;
+       int    foundNode = 0;
 
-       poh_freed = sisfb_heap.oh_used.poh_next;
+       poh_freed = memheap->oh_used.poh_next;
 
-       while(poh_freed != &sisfb_heap.oh_used) {
+       while(poh_freed != &memheap->oh_used) {
                if(poh_freed->offset == base) {
                        foundNode = 1;
                        break;
@@ -3281,17 +3441,18 @@ sisfb_poh_free(u32 base)
                poh_freed = poh_freed->poh_next;
        }
 
-       if(!foundNode) return(NULL);
+       if(!foundNode)
+               return NULL;
 
-       sisfb_heap.max_freesize += poh_freed->size;
+       memheap->max_freesize += poh_freed->size;
 
        poh_prev = poh_next = NULL;
        ulUpper = poh_freed->offset + poh_freed->size;
        ulLower = poh_freed->offset;
 
-       pohThis = sisfb_heap.oh_free.poh_next;
+       pohThis = memheap->oh_free.poh_next;
 
-       while(pohThis != &sisfb_heap.oh_free) {
+       while(pohThis != &memheap->oh_free) {
                if(pohThis->offset == ulUpper) {
                        poh_next = pohThis;
                } else if((pohThis->offset + pohThis->size) == ulLower) {
@@ -3305,70 +3466,88 @@ sisfb_poh_free(u32 base)
        if(poh_prev && poh_next) {
                poh_prev->size += (poh_freed->size + poh_next->size);
                sisfb_delete_node(poh_next);
-               sisfb_free_node(poh_freed);
-               sisfb_free_node(poh_next);
-               return(poh_prev);
+               sisfb_free_node(memheap, poh_freed);
+               sisfb_free_node(memheap, poh_next);
+               return poh_prev;
        }
 
        if(poh_prev) {
                poh_prev->size += poh_freed->size;
-               sisfb_free_node(poh_freed);
-               return(poh_prev);
+               sisfb_free_node(memheap, poh_freed);
+               return poh_prev;
        }
 
        if(poh_next) {
                poh_next->size += poh_freed->size;
                poh_next->offset = poh_freed->offset;
-               sisfb_free_node(poh_freed);
-               return(poh_next);
+               sisfb_free_node(memheap, poh_freed);
+               return poh_next;
        }
 
-       sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
+       sisfb_insert_node(&memheap->oh_free, poh_freed);
 
-       return(poh_freed);
+       return poh_freed;
 }
 
 static void
-sisfb_free_node(SIS_OH *poh)
+sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
 {
-       if(poh == NULL) return;
+       if(poh == NULL)
+               return;
 
-       poh->poh_next = sisfb_heap.poh_freelist;
-       sisfb_heap.poh_freelist = poh;
+       poh->poh_next = memheap->poh_freelist;
+       memheap->poh_freelist = poh;
 }
 
-void
-sis_malloc(struct sis_memreq *req)
+static void
+sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
 {
-       struct sis_video_info *ivideo = sisfb_heap.vinfo;
-       SIS_OH *poh = NULL;
+       struct SIS_OH *poh = NULL;
 
-       if((ivideo) && (!ivideo->havenoheap)) {
-          poh = sisfb_poh_allocate((u32)req->size);
-       }
+       if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
+               poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
 
        if(poh == NULL) {
-          req->offset = req->size = 0;
-          DPRINTK("sisfb: Video RAM allocation failed\n");
+               req->offset = req->size = 0;
+               DPRINTK("sisfb: Video RAM allocation failed\n");
        } else {
-          req->offset = poh->offset;
-          req->size = poh->size;
-          DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
-                   (poh->offset + ivideo->video_vbase));
+               req->offset = poh->offset;
+               req->size = poh->size;
+               DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
+                       (poh->offset + ivideo->video_vbase));
        }
 }
 
-/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
+void
+sis_malloc(struct sis_memreq *req)
+{
+       struct sis_video_info *ivideo = sisfb_heap->vinfo;
+
+       if(&ivideo->sisfb_heap == sisfb_heap)
+               sis_int_malloc(ivideo, req);
+       else
+               req->offset = req->size = 0;
+}
 
 void
-sis_free(u32 base)
+sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
+{
+       struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+
+       sis_int_malloc(ivideo, req);
+}
+
+/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
+
+static void
+sis_int_free(struct sis_video_info *ivideo, u32 base)
 {
-       struct sis_video_info *ivideo = sisfb_heap.vinfo;
-       SIS_OH *poh;
+       struct SIS_OH *poh;
 
-       if((!ivideo) || (ivideo->havenoheap)) return;
+       if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
+               return;
 
-       poh = sisfb_poh_free((u32)base);
+       poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
 
        if(poh == NULL) {
                DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
@@ -3376,8 +3555,62 @@ sis_free(u32 base)
        }
 }
 
+void
+sis_free(u32 base)
+{
+       struct sis_video_info *ivideo = sisfb_heap->vinfo;
+
+       sis_int_free(ivideo, base);
+}
+
+void
+sis_free_new(struct pci_dev *pdev, u32 base)
+{
+       struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+
+       sis_int_free(ivideo, base);
+}
+
 /* --------------------- SetMode routines ------------------------- */
 
+static void
+sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
+{
+       u8 cr30, cr31;
+
+       /* Check if MMIO and engines are enabled,
+        * and sync in case they are. Can't use
+        * ivideo->accel here, as this might have
+        * been changed before this is called.
+        */
+       inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
+       inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
+       /* MMIO and 2D/3D engine enabled? */
+       if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
+#ifdef CONFIG_FB_SIS_300
+               if(ivideo->sisvga_engine == SIS_300_VGA) {
+                       /* Don't care about TurboQueue. It's
+                        * enough to know that the engines
+                        * are enabled
+                        */
+                       sisfb_syncaccel(ivideo);
+               }
+#endif
+#ifdef CONFIG_FB_SIS_315
+               if(ivideo->sisvga_engine == SIS_315_VGA) {
+                       /* Check that any queue mode is
+                        * enabled, and that the queue
+                        * is not in the state of "reset"
+                        */
+                       inSISIDXREG(SISSR, 0x26, cr30);
+                       if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
+                               sisfb_syncaccel(ivideo);
+                       }
+               }
+#endif
+       }
+}
+
 static void
 sisfb_pre_setmode(struct sis_video_info *ivideo)
 {
@@ -3386,6 +3619,8 @@ sisfb_pre_setmode(struct sis_video_info *ivideo)
 
        ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
 
+       outSISIDXREG(SISSR, 0x05, 0x86);
+
        inSISIDXREG(SISCR, 0x31, cr31);
        cr31 &= ~0x60;
        cr31 |= 0x04;
@@ -3413,41 +3648,43 @@ sisfb_pre_setmode(struct sis_video_info *ivideo)
 
        SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
        SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
+       ivideo->curFSTN = ivideo->curDSTN = 0;
 
        switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
 
           case CRT2_TV:
              cr38 &= ~0xc0;   /* Clear PAL-M / PAL-N bits */
-             if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) {
+             if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
 #ifdef CONFIG_FB_SIS_315
-                if(ivideo->chip >= SIS_661) {
-                   cr38 |= 0x04;
-                   if(ivideo->vbflags & TV_YPBPR525P)       cr35 |= 0x20;
+                if(ivideo->chip >= SIS_661) {
+                   cr38 |= 0x04;
+                   if(ivideo->vbflags & TV_YPBPR525P)       cr35 |= 0x20;
                    else if(ivideo->vbflags & TV_YPBPR750P)  cr35 |= 0x40;
                    else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
                    cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
                    cr35 &= ~0x01;
                    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
-                } else if(ivideo->sisvga_engine == SIS_315_VGA) {
-                   cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
+                } else if(ivideo->sisvga_engine == SIS_315_VGA) {
+                   cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
                    cr38 |= 0x08;
-                   if(ivideo->vbflags & TV_YPBPR525P)       cr38 |= 0x10;
+                   if(ivideo->vbflags & TV_YPBPR525P)       cr38 |= 0x10;
                    else if(ivideo->vbflags & TV_YPBPR750P)  cr38 |= 0x20;
                    else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
                    cr31 &= ~0x01;
                    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
-                }
-#endif
-             } else if((ivideo->vbflags & TV_HIVISION) && (ivideo->vbflags & (VB_301|VB_301B|VB_302B))) {
-                if(ivideo->chip >= SIS_661) {
-                   cr38 |= 0x04;
-                   cr35 |= 0x60;
-                } else {
-                   cr30 |= 0x80;
-                }
+                }
+#endif
+             } else if((ivideo->vbflags & TV_HIVISION) &&
+                               (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
+                if(ivideo->chip >= SIS_661) {
+                   cr38 |= 0x04;
+                   cr35 |= 0x60;
+                } else {
+                   cr30 |= 0x80;
+                }
                 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
-                cr31 |= 0x01;
-                cr35 |= 0x01;
+                cr31 |= 0x01;
+                cr35 |= 0x01;
                 ivideo->currentvbflags |= TV_HIVISION;
              } else if(ivideo->vbflags & TV_SCART) {
                 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
@@ -3466,8 +3703,8 @@ sisfb_pre_setmode(struct sis_video_info *ivideo)
              }
              cr31 |= SIS_DRIVER_MODE;
 
-             if(ivideo->vbflags & (TV_AVIDEO|TV_SVIDEO)) {
-                if(ivideo->vbflags & TV_PAL) {
+             if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
+                if(ivideo->vbflags & TV_PAL) {
                    cr31 |= 0x01; cr35 |= 0x01;
                    ivideo->currentvbflags |= TV_PAL;
                    if(ivideo->vbflags & TV_PALM) {
@@ -3476,14 +3713,14 @@ sisfb_pre_setmode(struct sis_video_info *ivideo)
                    } else if(ivideo->vbflags & TV_PALN) {
                       cr38 |= 0x80; cr35 |= 0x08;
                       ivideo->currentvbflags |= TV_PALN;
-                   }
-                 } else {
+                   }
+                } else {
                    cr31 &= ~0x01; cr35 &= ~0x01;
                    ivideo->currentvbflags |= TV_NTSC;
                    if(ivideo->vbflags & TV_NTSCJ) {
                       cr38 |= 0x40; cr35 |= 0x02;
                       ivideo->currentvbflags |= TV_NTSCJ;
-                   }
+                   }
                 }
              }
              break;
@@ -3493,6 +3730,8 @@ sisfb_pre_setmode(struct sis_video_info *ivideo)
              cr31 |= SIS_DRIVER_MODE;
              SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
              SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
+             ivideo->curFSTN = ivideo->sisfb_fstn;
+             ivideo->curDSTN = ivideo->sisfb_dstn;
              break;
 
           case CRT2_VGA:
@@ -3525,9 +3764,9 @@ sisfb_pre_setmode(struct sis_video_info *ivideo)
        }
        outSISIDXREG(SISCR, 0x31, cr31);
 
-       if(ivideo->accel) sisfb_syncaccel(ivideo);
-
        ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
+
+       sisfb_check_engine_and_sync(ivideo);
 }
 
 /* Fix SR11 for 661 and later */
@@ -3535,125 +3774,129 @@ sisfb_pre_setmode(struct sis_video_info *ivideo)
 static void
 sisfb_fixup_SR11(struct sis_video_info *ivideo)
 {
-    u8  tmpreg;
-
-    if(ivideo->chip >= SIS_661) {
-       inSISIDXREG(SISSR,0x11,tmpreg);
-       if(tmpreg & 0x20) {
-          inSISIDXREG(SISSR,0x3e,tmpreg);
-         tmpreg = (tmpreg + 1) & 0xff;
-         outSISIDXREG(SISSR,0x3e,tmpreg);
-         inSISIDXREG(SISSR,0x11,tmpreg);
-       }
-       if(tmpreg & 0xf0) {
-          andSISIDXREG(SISSR,0x11,0x0f);
-       }
-    }
+       u8  tmpreg;
+
+       if(ivideo->chip >= SIS_661) {
+               inSISIDXREG(SISSR,0x11,tmpreg);
+               if(tmpreg & 0x20) {
+                       inSISIDXREG(SISSR,0x3e,tmpreg);
+                       tmpreg = (tmpreg + 1) & 0xff;
+                       outSISIDXREG(SISSR,0x3e,tmpreg);
+                       inSISIDXREG(SISSR,0x11,tmpreg);
+               }
+               if(tmpreg & 0xf0) {
+                       andSISIDXREG(SISSR,0x11,0x0f);
+               }
+       }
 }
 #endif
 
-static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
+static void
+sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
 {
-   if(val > 32) val = 32;
-   if(val < -32) val = -32;
-   ivideo->tvxpos = val;
+       if(val > 32) val = 32;
+       if(val < -32) val = -32;
+       ivideo->tvxpos = val;
 
-   if(ivideo->sisfblocked) return;
-   if(!ivideo->modechanged) return;
+       if(ivideo->sisfblocked) return;
+       if(!ivideo->modechanged) return;
 
-   if(ivideo->currentvbflags & CRT2_TV) {
+       if(ivideo->currentvbflags & CRT2_TV) {
 
-      if(ivideo->vbflags & VB_CHRONTEL) {
+               if(ivideo->vbflags2 & VB2_CHRONTEL) {
 
-        int x = ivideo->tvx;
+                       int x = ivideo->tvx;
 
-        switch(ivideo->chronteltype) {
-        case 1:
-            x += val;
-            if(x < 0) x = 0;
-            outSISIDXREG(SISSR,0x05,0x86);
-            SiS_SetCH700x(&ivideo->SiS_Pr, (((x & 0xff) << 8) | 0x0a));
-            SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD);
-            break;
-        case 2:
-            /* Not supported by hardware */
-            break;
-        }
-
-      } else if(ivideo->vbflags & VB_SISBRIDGE) {
-
-        u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
-        unsigned short temp;
-
-        p2_1f = ivideo->p2_1f;
-        p2_20 = ivideo->p2_20;
-        p2_2b = ivideo->p2_2b;
-        p2_42 = ivideo->p2_42;
-        p2_43 = ivideo->p2_43;
-
-        temp = p2_1f | ((p2_20 & 0xf0) << 4);
-        temp += (val * 2);
-        p2_1f = temp & 0xff;
-        p2_20 = (temp & 0xf00) >> 4;
-        p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
-        temp = p2_43 | ((p2_42 & 0xf0) << 4);
-        temp += (val * 2);
-        p2_43 = temp & 0xff;
-        p2_42 = (temp & 0xf00) >> 4;
-        outSISIDXREG(SISPART2,0x1f,p2_1f);
-        setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
-        setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
-        setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
-        outSISIDXREG(SISPART2,0x43,p2_43);
-      }
-   }
+                       switch(ivideo->chronteltype) {
+                       case 1:
+                               x += val;
+                               if(x < 0) x = 0;
+                               outSISIDXREG(SISSR,0x05,0x86);
+                               SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
+                               SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
+                               break;
+                       case 2:
+                               /* Not supported by hardware */
+                               break;
+                       }
+
+               } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
+
+                       u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
+                       unsigned short temp;
+
+                       p2_1f = ivideo->p2_1f;
+                       p2_20 = ivideo->p2_20;
+                       p2_2b = ivideo->p2_2b;
+                       p2_42 = ivideo->p2_42;
+                       p2_43 = ivideo->p2_43;
+
+                       temp = p2_1f | ((p2_20 & 0xf0) << 4);
+                       temp += (val * 2);
+                       p2_1f = temp & 0xff;
+                       p2_20 = (temp & 0xf00) >> 4;
+                       p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
+                       temp = p2_43 | ((p2_42 & 0xf0) << 4);
+                       temp += (val * 2);
+                       p2_43 = temp & 0xff;
+                       p2_42 = (temp & 0xf00) >> 4;
+                       outSISIDXREG(SISPART2,0x1f,p2_1f);
+                       setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
+                       setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
+                       setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
+                       outSISIDXREG(SISPART2,0x43,p2_43);
+               }
+       }
 }
 
-static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
+static void
+sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
 {
-   if(val > 32) val = 32;
-   if(val < -32) val = -32;
-   ivideo->tvypos = val;
-
-   if(ivideo->sisfblocked) return;
-   if(!ivideo->modechanged) return;
-
-   if(ivideo->currentvbflags & CRT2_TV) {
-
-      if(ivideo->vbflags & VB_CHRONTEL) {
-
-        int y = ivideo->tvy;
-
-        switch(ivideo->chronteltype) {
-        case 1:
-           y -= val;
-           if(y < 0) y = 0;
-           outSISIDXREG(SISSR,0x05,0x86);
-           SiS_SetCH700x(&ivideo->SiS_Pr, (((y & 0xff) << 8) | 0x0b));
-           SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, ((y & 0x0100) | 0x08),0xFE);
-           break;
-        case 2:
-           /* Not supported by hardware */
-           break;
-        }
-
-      } else if(ivideo->vbflags & VB_SISBRIDGE) {
-
-        char p2_01, p2_02;
-        val /= 2;
-        p2_01 = ivideo->p2_01;
-        p2_02 = ivideo->p2_02;
-
-        p2_01 += val;
-        p2_02 += val;
-        while((p2_01 <= 0) || (p2_02 <= 0)) {
-           p2_01 += 2;
-           p2_02 += 2;
-        }
-        outSISIDXREG(SISPART2,0x01,p2_01);
-        outSISIDXREG(SISPART2,0x02,p2_02);
-      }
-   }
+       if(val > 32) val = 32;
+       if(val < -32) val = -32;
+       ivideo->tvypos = val;
+
+       if(ivideo->sisfblocked) return;
+       if(!ivideo->modechanged) return;
+
+       if(ivideo->currentvbflags & CRT2_TV) {
+
+               if(ivideo->vbflags2 & VB2_CHRONTEL) {
+
+                       int y = ivideo->tvy;
+
+                       switch(ivideo->chronteltype) {
+                       case 1:
+                               y -= val;
+                               if(y < 0) y = 0;
+                               outSISIDXREG(SISSR,0x05,0x86);
+                               SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
+                               SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
+                               break;
+                       case 2:
+                               /* Not supported by hardware */
+                               break;
+                       }
+
+               } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
+
+                       char p2_01, p2_02;
+                       val /= 2;
+                       p2_01 = ivideo->p2_01;
+                       p2_02 = ivideo->p2_02;
+
+                       p2_01 += val;
+                       p2_02 += val;
+                       if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
+                               while((p2_01 <= 0) || (p2_02 <= 0)) {
+                                       p2_01 += 2;
+                                       p2_02 += 2;
+                               }
+                       }
+                       outSISIDXREG(SISPART2,0x01,p2_01);
+                       outSISIDXREG(SISPART2,0x02,p2_02);
+               }
+       }
 }
 
 static void
@@ -3668,207 +3911,172 @@ sisfb_post_setmode(struct sis_video_info *ivideo)
        u8 reg1;
 #endif
 
-       outSISIDXREG(SISSR,0x05,0x86);
+       outSISIDXREG(SISSR, 0x05, 0x86);
 
 #ifdef CONFIG_FB_SIS_315
        sisfb_fixup_SR11(ivideo);
 #endif
 
        /* Now we actually HAVE changed the display mode */
-        ivideo->modechanged = 1;
+       ivideo->modechanged = 1;
 
        /* We can't switch off CRT1 if bridge is in slave mode */
-       if(ivideo->vbflags & VB_VIDEOBRIDGE) {
+       if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
                if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
-       } else ivideo->sisfb_crt1off = 0;
+       } else
+               ivideo->sisfb_crt1off = 0;
 
 #ifdef CONFIG_FB_SIS_300
        if(ivideo->sisvga_engine == SIS_300_VGA) {
-          if((ivideo->sisfb_crt1off) && (doit)) {
-               crt1isoff = TRUE;
-               reg = 0x00;
-          } else {
-               crt1isoff = FALSE;
-               reg = 0x80;
-          }
-          setSISIDXREG(SISCR, 0x17, 0x7f, reg);
+               if((ivideo->sisfb_crt1off) && (doit)) {
+                       crt1isoff = TRUE;
+                       reg = 0x00;
+               } else {
+                       crt1isoff = FALSE;
+                       reg = 0x80;
+               }
+               setSISIDXREG(SISCR, 0x17, 0x7f, reg);
        }
 #endif
 #ifdef CONFIG_FB_SIS_315
        if(ivideo->sisvga_engine == SIS_315_VGA) {
-          if((ivideo->sisfb_crt1off) && (doit)) {
-               crt1isoff = TRUE;
-               reg  = 0x40;
-               reg1 = 0xc0;
-          } else {
-               crt1isoff = FALSE;
-               reg  = 0x00;
-               reg1 = 0x00;
-
-          }
-          setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
-          setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
+               if((ivideo->sisfb_crt1off) && (doit)) {
+                       crt1isoff = TRUE;
+                       reg  = 0x40;
+                       reg1 = 0xc0;
+               } else {
+                       crt1isoff = FALSE;
+                       reg  = 0x00;
+                       reg1 = 0x00;
+               }
+               setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
+               setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
        }
 #endif
 
        if(crt1isoff) {
-          ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
-          ivideo->currentvbflags |= VB_SINGLE_MODE;
+               ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
+               ivideo->currentvbflags |= VB_SINGLE_MODE;
        } else {
-          ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
-          if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
-               ivideo->currentvbflags |= VB_MIRROR_MODE;
-          } else {
-               ivideo->currentvbflags |= VB_SINGLE_MODE;
-          }
+               ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
+               if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
+                       ivideo->currentvbflags |= VB_MIRROR_MODE;
+               } else {
+                       ivideo->currentvbflags |= VB_SINGLE_MODE;
+               }
        }
 
-        andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
+       andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
 
        if(ivideo->currentvbflags & CRT2_TV) {
-          if(ivideo->vbflags & VB_SISBRIDGE) {
-             inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
-             inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
-             inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
-             inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
-             inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
-             inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
-             inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
-          } else if(ivideo->vbflags & VB_CHRONTEL) {
-             if(ivideo->chronteltype == 1) {
-                ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
-                ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
-                ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
-                ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
-             }
-          }
+               if(ivideo->vbflags2 & VB2_SISBRIDGE) {
+                       inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
+                       inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
+                       inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
+                       inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
+                       inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
+                       inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
+                       inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
+               } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
+                       if(ivideo->chronteltype == 1) {
+                               ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
+                               ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
+                               ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
+                               ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
+                       }
+               }
        }
 
        if(ivideo->tvxpos) {
-          sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
+               sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
        }
        if(ivideo->tvypos) {
-          sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
+               sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
        }
 
-       if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) {  /* Set filter for SiS301 */
+       /* Eventually sync engines */
+       sisfb_check_engine_and_sync(ivideo);
 
-               unsigned char filter_tb = 0;
+       /* (Re-)Initialize chip engines */
+       if(ivideo->accel) {
+               sisfb_engine_init(ivideo);
+       } else {
+               ivideo->engineok = 0;
+       }
+}
 
-               switch (ivideo->video_width) {
-                  case 320:
-                       filter_tb = (ivideo->vbflags & TV_NTSC) ? 4 : 12;
-                       break;
-                  case 640:
-                       filter_tb = (ivideo->vbflags & TV_NTSC) ? 5 : 13;
-                       break;
-                  case 720:
-                       filter_tb = (ivideo->vbflags & TV_NTSC) ? 6 : 14;
-                       break;
-                  case 400:
-                  case 800:
-                       filter_tb = (ivideo->vbflags & TV_NTSC) ? 7 : 15;
-                       break;
-                  default:
-                       ivideo->sisfb_filter = -1;
-                       break;
-               }
+static int
+sisfb_reset_mode(struct sis_video_info *ivideo)
+{
+       if(sisfb_set_mode(ivideo, 0))
+               return 1;
 
-               orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
+       sisfb_set_pitch(ivideo);
+       sisfb_set_base_CRT1(ivideo, ivideo->current_base);
+       sisfb_set_base_CRT2(ivideo, ivideo->current_base);
 
-               if(ivideo->vbflags & TV_NTSC) {
-
-                       andSISIDXREG(SISPART2, 0x3a, 0x1f);
-
-                       if (ivideo->vbflags & TV_SVIDEO) {
-
-                               andSISIDXREG(SISPART2, 0x30, 0xdf);
-
-                       } else if (ivideo->vbflags & TV_AVIDEO) {
-
-                               orSISIDXREG(SISPART2, 0x30, 0x20);
-
-                               switch (ivideo->video_width) {
-                               case 640:
-                                       outSISIDXREG(SISPART2, 0x35, 0xEB);
-                                       outSISIDXREG(SISPART2, 0x36, 0x04);
-                                       outSISIDXREG(SISPART2, 0x37, 0x25);
-                                       outSISIDXREG(SISPART2, 0x38, 0x18);
-                                       break;
-                               case 720:
-                                       outSISIDXREG(SISPART2, 0x35, 0xEE);
-                                       outSISIDXREG(SISPART2, 0x36, 0x0C);
-                                       outSISIDXREG(SISPART2, 0x37, 0x22);
-                                       outSISIDXREG(SISPART2, 0x38, 0x08);
-                                       break;
-                               case 400:
-                               case 800:
-                                       outSISIDXREG(SISPART2, 0x35, 0xEB);
-                                       outSISIDXREG(SISPART2, 0x36, 0x15);
-                                       outSISIDXREG(SISPART2, 0x37, 0x25);
-                                       outSISIDXREG(SISPART2, 0x38, 0xF6);
-                                       break;
-                               }
-                       }
+       return 0;
+}
 
-               } else if(ivideo->vbflags & TV_PAL) {
-
-                       andSISIDXREG(SISPART2, 0x3A, 0x1F);
-
-                       if (ivideo->vbflags & TV_SVIDEO) {
-
-                               andSISIDXREG(SISPART2, 0x30, 0xDF);
-
-                       } else if (ivideo->vbflags & TV_AVIDEO) {
-
-                               orSISIDXREG(SISPART2, 0x30, 0x20);
-
-                               switch (ivideo->video_width) {
-                               case 640:
-                                       outSISIDXREG(SISPART2, 0x35, 0xF1);
-                                       outSISIDXREG(SISPART2, 0x36, 0xF7);
-                                       outSISIDXREG(SISPART2, 0x37, 0x1F);
-                                       outSISIDXREG(SISPART2, 0x38, 0x32);
-                                       break;
-                               case 720:
-                                       outSISIDXREG(SISPART2, 0x35, 0xF3);
-                                       outSISIDXREG(SISPART2, 0x36, 0x00);
-                                       outSISIDXREG(SISPART2, 0x37, 0x1D);
-                                       outSISIDXREG(SISPART2, 0x38, 0x20);
-                                       break;
-                               case 400:
-                               case 800:
-                                       outSISIDXREG(SISPART2, 0x35, 0xFC);
-                                       outSISIDXREG(SISPART2, 0x36, 0xFB);
-                                       outSISIDXREG(SISPART2, 0x37, 0x14);
-                                       outSISIDXREG(SISPART2, 0x38, 0x2A);
-                                       break;
+static void
+sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
+{
+       int mycrt1off;
+
+       switch(sisfb_command->sisfb_cmd) {
+       case SISFB_CMD_GETVBFLAGS:
+               if(!ivideo->modechanged) {
+                       sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
+               } else {
+                       sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
+                       sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
+                       sisfb_command->sisfb_result[2] = ivideo->vbflags2;
+               }
+               break;
+       case SISFB_CMD_SWITCHCRT1:
+               /* arg[0]: 0 = off, 1 = on, 99 = query */
+               if(!ivideo->modechanged) {
+                       sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
+               } else if(sisfb_command->sisfb_arg[0] == 99) {
+                       /* Query */
+                       sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
+                       sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
+               } else if(ivideo->sisfblocked) {
+                       sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
+               } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
+                                       (sisfb_command->sisfb_arg[0] == 0)) {
+                       sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
+               } else {
+                       sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
+                       mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
+                       if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
+                           ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
+                               ivideo->sisfb_crt1off = mycrt1off;
+                               if(sisfb_reset_mode(ivideo)) {
+                                       sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
                                }
                        }
+                       sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
                }
-
-               if((ivideo->sisfb_filter >= 0) && (ivideo->sisfb_filter <= 7)) {
-                  outSISIDXREG(SISPART2,0x35,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][0]));
-                  outSISIDXREG(SISPART2,0x36,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][1]));
-                  outSISIDXREG(SISPART2,0x37,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][2]));
-                  outSISIDXREG(SISPART2,0x38,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][3]));
-               }
-         
+               break;
+       /* more to come */
+       default:
+               sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
+               printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
+                       sisfb_command->sisfb_cmd);
        }
 }
 
 #ifndef MODULE
-SISINITSTATIC int __init sisfb_setup(char *options)
+SISINITSTATIC int __init
+sisfb_setup(char *options)
 {
        char *this_opt;
-       
-       sisfb_setdefaultparms();
 
-        printk(KERN_DEBUG "sisfb: Options %s\n", options);
+       sisfb_setdefaultparms();
 
-       if(!options || !(*options)) {
+       if(!options || !(*options))
                return 0;
-       }
 
        while((this_opt = strsep(&options, ",")) != NULL) {
 
@@ -3880,9 +4088,9 @@ SISINITSTATIC int __init sisfb_setup(char *options)
                        /* Need to check crt2 type first for fstn/dstn */
                        sisfb_search_crt2type(this_opt + 14);
                } else if(!strnicmp(this_opt, "tvmode:",7)) {
-                       sisfb_search_tvstd(this_opt + 7);
-                } else if(!strnicmp(this_opt, "tvstandard:",11)) {
                        sisfb_search_tvstd(this_opt + 7);
+               } else if(!strnicmp(this_opt, "tvstandard:",11)) {
+                       sisfb_search_tvstd(this_opt + 11);
                } else if(!strnicmp(this_opt, "mode:", 5)) {
                        sisfb_search_mode(this_opt + 5, FALSE);
                } else if(!strnicmp(this_opt, "vesa:", 5)) {
@@ -3892,74 +4100,72 @@ SISINITSTATIC int __init sisfb_setup(char *options)
                        sisfb_inverse = 1;
                        /* fb_invert_cmaps(); */
                } else if(!strnicmp(this_opt, "font:", 5)) {
-                       if(strlen(this_opt + 5) < 40) {
+                       if(strlen(this_opt + 5) < 40) {
                           strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
                           sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
                        }
 #endif
                } else if(!strnicmp(this_opt, "rate:", 5)) {
                        sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
-               } else if(!strnicmp(this_opt, "filter:", 7)) {
-                       sisfb_filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
                } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
                        sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
-                } else if(!strnicmp(this_opt, "mem:",4)) {
-                       sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
+               } else if(!strnicmp(this_opt, "mem:",4)) {
+                       sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
                } else if(!strnicmp(this_opt, "pdc:", 4)) {
-                       sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
+                       sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
                } else if(!strnicmp(this_opt, "pdc1:", 5)) {
-                       sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
+                       sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
                } else if(!strnicmp(this_opt, "noaccel", 7)) {
                        sisfb_accel = 0;
                } else if(!strnicmp(this_opt, "accel", 5)) {
                        sisfb_accel = -1;
                } else if(!strnicmp(this_opt, "noypan", 6)) {
-                       sisfb_ypan = 0;
+                       sisfb_ypan = 0;
                } else if(!strnicmp(this_opt, "ypan", 4)) {
-                       sisfb_ypan = -1;
+                       sisfb_ypan = -1;
                } else if(!strnicmp(this_opt, "nomax", 5)) {
-                       sisfb_max = 0;
+                       sisfb_max = 0;
                } else if(!strnicmp(this_opt, "max", 3)) {
-                       sisfb_max = -1;
+                       sisfb_max = -1;
                } else if(!strnicmp(this_opt, "userom:", 7)) {
                        sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
                } else if(!strnicmp(this_opt, "useoem:", 7)) {
                        sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
                } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
                        sisfb_nocrt2rate = 1;
-               } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
-                       unsigned long temp = 2;
-                       temp = simple_strtoul(this_opt + 9, NULL, 0);
-                       if((temp == 0) || (temp == 1)) {
+               } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
+                       unsigned long temp = 2;
+                       temp = simple_strtoul(this_opt + 9, NULL, 0);
+                       if((temp == 0) || (temp == 1)) {
                           sisfb_scalelcd = temp ^ 1;
-                       }
+                       }
                } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
-                       int temp = 0;
-                       temp = (int)simple_strtol(this_opt + 13, NULL, 0);
-                       if((temp >= -32) && (temp <= 32)) {
+                       int temp = 0;
+                       temp = (int)simple_strtol(this_opt + 13, NULL, 0);
+                       if((temp >= -32) && (temp <= 32)) {
                           sisfb_tvxposoffset = temp;
-                       }
+                       }
                } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
-                       int temp = 0;
-                       temp = (int)simple_strtol(this_opt + 13, NULL, 0);
-                       if((temp >= -32) && (temp <= 32)) {
+                       int temp = 0;
+                       temp = (int)simple_strtol(this_opt + 13, NULL, 0);
+                       if((temp >= -32) && (temp <= 32)) {
                           sisfb_tvyposoffset = temp;
-                       }
+                       }
                } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
                        sisfb_search_specialtiming(this_opt + 14);
                } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
-                       int temp = 4;
-                       temp = simple_strtoul(this_opt + 7, NULL, 0);
-                       if((temp >= 0) && (temp <= 3)) {
+                       int temp = 4;
+                       temp = simple_strtoul(this_opt + 7, NULL, 0);
+                       if((temp >= 0) && (temp <= 3)) {
                           sisfb_lvdshl = temp;
-                       }
+                       }
                } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
                        sisfb_search_mode(this_opt, TRUE);
 #if !defined(__i386__) && !defined(__x86_64__)
-               } else if(!strnicmp(this_opt, "resetcard", 9)) {
-                       sisfb_resetcard = 1;
+               } else if(!strnicmp(this_opt, "resetcard", 9)) {
+                       sisfb_resetcard = 1;
                } else if(!strnicmp(this_opt, "videoram:", 9)) {
-                       sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
+                       sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
 #endif
                } else {
                        printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
@@ -3967,819 +4173,1706 @@ SISINITSTATIC int __init sisfb_setup(char *options)
 
        }
 
+       return 0;
+}
+#endif
+
+static int __devinit
+sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
+{
+       SIS_IOTYPE1 *rom;
+       int romptr;
+
+       if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
+               return 0;
+
+       romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
+       if(romptr > (0x10000 - 8))
+               return 0;
+
+       rom = rom_base + romptr;
+
+       if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
+          (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
+               return 0;
+
+       if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
+               return 0;
+
+       if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
+               return 0;
+
+       return 1;
+}
+
+static unsigned char * __devinit
+sisfb_find_rom(struct pci_dev *pdev)
+{
+       struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+       SIS_IOTYPE1 *rom_base;
+       unsigned char *myrombase = NULL;
+       u32 temp;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
+       size_t romsize;
+
+       /* First, try the official pci ROM functions (except
+        * on integrated chipsets which have no ROM).
+        */
+
+       if(!ivideo->nbridge) {
+
+               if((rom_base = pci_map_rom(pdev, &romsize))) {
+
+                       if(sisfb_check_rom(rom_base, ivideo)) {
+
+                               if((myrombase = vmalloc(65536))) {
+
+                                       /* Work around bug in pci/rom.c: Folks forgot to check
+                                        * whether the size retrieved from the BIOS image eventually
+                                        * is larger than the mapped size
+                                        */
+                                       if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
+                                               romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
+
+                                       memcpy_fromio(myrombase, rom_base,
+                                                       (romsize > 65536) ? 65536 : romsize);
+                               }
+                       }
+                       pci_unmap_rom(pdev, rom_base);
+               }
+       }
+
+       if(myrombase) return myrombase;
+#endif
+
+       /* Otherwise do it the conventional way. */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+       for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
+
+               rom_base = ioremap(temp, 65536);
+               if(!rom_base)
+                       continue;
+
+               if(!sisfb_check_rom(rom_base, ivideo)) {
+                       iounmap(rom_base);
+                       continue;
+               }
+
+               if((myrombase = vmalloc(65536)))
+                       memcpy_fromio(myrombase, rom_base, 65536);
+
+               iounmap(rom_base);
+               break;
+
+        }
+
+#else
+
+       pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
+       pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
+                       (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
+
+       rom_base = ioremap(ivideo->video_base, 65536);
+       if(rom_base) {
+               if(sisfb_check_rom(rom_base, ivideo)) {
+                       if((myrombase = vmalloc(65536)))
+                               memcpy_fromio(myrombase, rom_base, 65536);
+               }
+               iounmap(rom_base);
+       }
+
+       pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
+
+#endif
+
+       return myrombase;
+}
+
+static void __devinit
+sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
+                       unsigned int min)
+{
+       ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
+
+       if(!ivideo->video_vbase) {
+               printk(KERN_ERR
+                       "sisfb: Unable to map maximum video RAM for size detection\n");
+               (*mapsize) >>= 1;
+               while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
+                       (*mapsize) >>= 1;
+                       if((*mapsize) < (min << 20))
+                               break;
+               }
+               if(ivideo->video_vbase) {
+                       printk(KERN_ERR
+                               "sisfb: Video RAM size detection limited to %dMB\n",
+                               (int)((*mapsize) >> 20));
+               }
+       }
+}
+
+#ifdef CONFIG_FB_SIS_300
+static int __devinit
+sisfb_post_300_buswidth(struct sis_video_info *ivideo)
+{
+       SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
+       unsigned short temp;
+       unsigned char reg;
+       int i, j;
+
+       andSISIDXREG(SISSR, 0x15, 0xFB);
+       orSISIDXREG(SISSR, 0x15, 0x04);
+       outSISIDXREG(SISSR, 0x13, 0x00);
+       outSISIDXREG(SISSR, 0x14, 0xBF);
+
+       for(i = 0; i < 2; i++) {
+               temp = 0x1234;
+               for(j = 0; j < 4; j++) {
+                       writew(temp, FBAddress);
+                       if(readw(FBAddress) == temp)
+                               break;
+                       orSISIDXREG(SISSR, 0x3c, 0x01);
+                       inSISIDXREG(SISSR, 0x05, reg);
+                       inSISIDXREG(SISSR, 0x05, reg);
+                       andSISIDXREG(SISSR, 0x3c, 0xfe);
+                       inSISIDXREG(SISSR, 0x05, reg);
+                       inSISIDXREG(SISSR, 0x05, reg);
+                       temp++;
+               }
+       }
+
+       writel(0x01234567L, FBAddress);
+       writel(0x456789ABL, (FBAddress + 4));
+       writel(0x89ABCDEFL, (FBAddress + 8));
+       writel(0xCDEF0123L, (FBAddress + 12));
+
+       inSISIDXREG(SISSR, 0x3b, reg);
+       if(reg & 0x01) {
+               if(readl((FBAddress + 12)) == 0xCDEF0123L)
+                       return 4;       /* Channel A 128bit */
+       }
+
+       if(readl((FBAddress + 4)) == 0x456789ABL)
+               return 2;               /* Channel B 64bit */
+
+       return 1;                       /* 32bit */
+}
+
+static int __devinit
+sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
+                       int PseudoRankCapacity, int PseudoAdrPinCount,
+                       unsigned int mapsize)
+{
+       SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
+       unsigned short sr14;
+       unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
+       unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
+       static const unsigned short SiS_DRAMType[17][5] = {
+               {0x0C,0x0A,0x02,0x40,0x39},
+               {0x0D,0x0A,0x01,0x40,0x48},
+               {0x0C,0x09,0x02,0x20,0x35},
+               {0x0D,0x09,0x01,0x20,0x44},
+               {0x0C,0x08,0x02,0x10,0x31},
+               {0x0D,0x08,0x01,0x10,0x40},
+               {0x0C,0x0A,0x01,0x20,0x34},
+               {0x0C,0x09,0x01,0x08,0x32},
+               {0x0B,0x08,0x02,0x08,0x21},
+               {0x0C,0x08,0x01,0x08,0x30},
+               {0x0A,0x08,0x02,0x04,0x11},
+               {0x0B,0x0A,0x01,0x10,0x28},
+               {0x09,0x08,0x02,0x02,0x01},
+               {0x0B,0x09,0x01,0x08,0x24},
+               {0x0B,0x08,0x01,0x04,0x20},
+               {0x0A,0x08,0x01,0x02,0x10},
+               {0x09,0x08,0x01,0x01,0x00}
+       };
+
+        for(k = 0; k <= 16; k++) {
+
+               RankCapacity = buswidth * SiS_DRAMType[k][3];
+
+               if(RankCapacity != PseudoRankCapacity)
+                       continue;
+
+               if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
+                       continue;
+
+               BankNumHigh = RankCapacity * 16 * iteration - 1;
+               if(iteration == 3) {             /* Rank No */
+                       BankNumMid  = RankCapacity * 16 - 1;
+               } else {
+                       BankNumMid  = RankCapacity * 16 * iteration / 2 - 1;
+               }
+
+               PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
+               PhysicalAdrHigh = BankNumHigh;
+               PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
+               PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
+
+               andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
+               orSISIDXREG(SISSR, 0x15, 0x04);  /* Test */
+               sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
+               if(buswidth == 4)      sr14 |= 0x80;
+               else if(buswidth == 2) sr14 |= 0x40;
+               outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
+               outSISIDXREG(SISSR, 0x14, sr14);
+
+               BankNumHigh <<= 16;
+               BankNumMid <<= 16;
+
+               if((BankNumHigh + PhysicalAdrHigh      >= mapsize) ||
+                  (BankNumMid  + PhysicalAdrHigh      >= mapsize) ||
+                  (BankNumHigh + PhysicalAdrHalfPage  >= mapsize) ||
+                  (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
+                       continue;
+
+               /* Write data */
+               writew(((unsigned short)PhysicalAdrHigh),
+                               (FBAddr + BankNumHigh + PhysicalAdrHigh));
+               writew(((unsigned short)BankNumMid),
+                               (FBAddr + BankNumMid  + PhysicalAdrHigh));
+               writew(((unsigned short)PhysicalAdrHalfPage),
+                               (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
+               writew(((unsigned short)PhysicalAdrOtherPage),
+                               (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
+
+               /* Read data */
+               if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static void __devinit
+sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
+{
+       struct  sis_video_info *ivideo = pci_get_drvdata(pdev);
+       int     i, j, buswidth;
+       int     PseudoRankCapacity, PseudoAdrPinCount;
+
+       buswidth = sisfb_post_300_buswidth(ivideo);
+
+       for(i = 6; i >= 0; i--) {
+               PseudoRankCapacity = 1 << i;
+               for(j = 4; j >= 1; j--) {
+                       PseudoAdrPinCount = 15 - j;
+                       if((PseudoRankCapacity * j) <= 64) {
+                               if(sisfb_post_300_rwtest(ivideo,
+                                               j,
+                                               buswidth,
+                                               PseudoRankCapacity,
+                                               PseudoAdrPinCount,
+                                               mapsize))
+                                       return;
+                       }
+               }
+       }
+}
+
+static void __devinit
+sisfb_post_sis300(struct pci_dev *pdev)
+{
+       struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+       unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
+       u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
+       u16 index, rindex, memtype = 0;
+       unsigned int mapsize;
+
+       if(!ivideo->SiS_Pr.UseROM)
+               bios = NULL;
+
+       outSISIDXREG(SISSR, 0x05, 0x86);
+
+       if(bios) {
+               if(bios[0x52] & 0x80) {
+                       memtype = bios[0x52];
+               } else {
+                       inSISIDXREG(SISSR, 0x3a, memtype);
+               }
+               memtype &= 0x07;
+       }
+
+       v3 = 0x80; v6 = 0x80;
+       if(ivideo->revision_id <= 0x13) {
+               v1 = 0x44; v2 = 0x42;
+               v4 = 0x44; v5 = 0x42;
+       } else {
+               v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
+               v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
+               if(bios) {
+                       index = memtype * 5;
+                       rindex = index + 0x54;
+                       v1 = bios[rindex++];
+                       v2 = bios[rindex++];
+                       v3 = bios[rindex++];
+                       rindex = index + 0x7c;
+                       v4 = bios[rindex++];
+                       v5 = bios[rindex++];
+                       v6 = bios[rindex++];
+               }
+       }
+       outSISIDXREG(SISSR, 0x28, v1);
+       outSISIDXREG(SISSR, 0x29, v2);
+       outSISIDXREG(SISSR, 0x2a, v3);
+       outSISIDXREG(SISSR, 0x2e, v4);
+       outSISIDXREG(SISSR, 0x2f, v5);
+       outSISIDXREG(SISSR, 0x30, v6);
+
+       v1 = 0x10;
+       if(bios)
+               v1 = bios[0xa4];
+       outSISIDXREG(SISSR, 0x07, v1);       /* DAC speed */
+
+       outSISIDXREG(SISSR, 0x11, 0x0f);     /* DDC, power save */
+
+       v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
+       v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
+       if(bios) {
+               memtype += 0xa5;
+               v1 = bios[memtype];
+               v2 = bios[memtype + 8];
+               v3 = bios[memtype + 16];
+               v4 = bios[memtype + 24];
+               v5 = bios[memtype + 32];
+               v6 = bios[memtype + 40];
+               v7 = bios[memtype + 48];
+               v8 = bios[memtype + 56];
+       }
+       if(ivideo->revision_id >= 0x80)
+               v3 &= 0xfd;
+       outSISIDXREG(SISSR, 0x15, v1);       /* Ram type (assuming 0, BIOS 0xa5 step 8) */
+       outSISIDXREG(SISSR, 0x16, v2);
+       outSISIDXREG(SISSR, 0x17, v3);
+       outSISIDXREG(SISSR, 0x18, v4);
+       outSISIDXREG(SISSR, 0x19, v5);
+       outSISIDXREG(SISSR, 0x1a, v6);
+       outSISIDXREG(SISSR, 0x1b, v7);
+       outSISIDXREG(SISSR, 0x1c, v8);     /* ---- */
+       andSISIDXREG(SISSR, 0x15 ,0xfb);
+       orSISIDXREG(SISSR, 0x15, 0x04);
+       if(bios) {
+               if(bios[0x53] & 0x02) {
+                       orSISIDXREG(SISSR, 0x19, 0x20);
+               }
+       }
+       v1 = 0x04;                         /* DAC pedestal (BIOS 0xe5) */
+       if(ivideo->revision_id >= 0x80)
+               v1 |= 0x01;
+       outSISIDXREG(SISSR, 0x1f, v1);
+       outSISIDXREG(SISSR, 0x20, 0xa4);     /* linear & relocated io & disable a0000 */
+       v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
+       if(bios) {
+               v1 = bios[0xe8];
+               v2 = bios[0xe9];
+               v3 = bios[0xea];
+       }
+       outSISIDXREG(SISSR, 0x23, v1);
+       outSISIDXREG(SISSR, 0x24, v2);
+       outSISIDXREG(SISSR, 0x25, v3);
+       outSISIDXREG(SISSR, 0x21, 0x84);
+       outSISIDXREG(SISSR, 0x22, 0x00);
+       outSISIDXREG(SISCR, 0x37, 0x00);
+       orSISIDXREG(SISPART1, 0x24, 0x01);   /* unlock crt2 */
+       outSISIDXREG(SISPART1, 0x00, 0x00);
+       v1 = 0x40; v2 = 0x11;
+       if(bios) {
+               v1 = bios[0xec];
+               v2 = bios[0xeb];
+       }
+       outSISIDXREG(SISPART1, 0x02, v1);
+
+       if(ivideo->revision_id >= 0x80)
+               v2 &= ~0x01;
+
+       inSISIDXREG(SISPART4, 0x00, reg);
+       if((reg == 1) || (reg == 2)) {
+               outSISIDXREG(SISCR, 0x37, 0x02);
+               outSISIDXREG(SISPART2, 0x00, 0x1c);
+               v4 = 0x00; v5 = 0x00; v6 = 0x10;
+               if(ivideo->SiS_Pr.UseROM) {
+                       v4 = bios[0xf5];
+                       v5 = bios[0xf6];
+                       v6 = bios[0xf7];
+               }
+               outSISIDXREG(SISPART4, 0x0d, v4);
+               outSISIDXREG(SISPART4, 0x0e, v5);
+               outSISIDXREG(SISPART4, 0x10, v6);
+               outSISIDXREG(SISPART4, 0x0f, 0x3f);
+               inSISIDXREG(SISPART4, 0x01, reg);
+               if(reg >= 0xb0) {
+                       inSISIDXREG(SISPART4, 0x23, reg);
+                       reg &= 0x20;
+                       reg <<= 1;
+                       outSISIDXREG(SISPART4, 0x23, reg);
+               }
+       } else {
+               v2 &= ~0x10;
+       }
+       outSISIDXREG(SISSR, 0x32, v2);
+
+       andSISIDXREG(SISPART1, 0x24, 0xfe);  /* Lock CRT2 */
+
+       inSISIDXREG(SISSR, 0x16, reg);
+       reg &= 0xc3;
+       outSISIDXREG(SISCR, 0x35, reg);
+       outSISIDXREG(SISCR, 0x83, 0x00);
+#if !defined(__i386__) && !defined(__x86_64__)
+       if(sisfb_videoram) {
+               outSISIDXREG(SISSR, 0x13, 0x28);  /* ? */
+               reg = ((sisfb_videoram >> 10) - 1) | 0x40;
+               outSISIDXREG(SISSR, 0x14, reg);
+       } else {
+#endif
+               /* Need to map max FB size for finding out about RAM size */
+               mapsize = 64 << 20;
+               sisfb_post_map_vram(ivideo, &mapsize, 4);
+
+               if(ivideo->video_vbase) {
+                       sisfb_post_300_ramsize(pdev, mapsize);
+                       iounmap(ivideo->video_vbase);
+               } else {
+                       printk(KERN_DEBUG
+                               "sisfb: Failed to map memory for size detection, assuming 8MB\n");
+                       outSISIDXREG(SISSR, 0x13, 0x28);  /* ? */
+                       outSISIDXREG(SISSR, 0x14, 0x47);  /* 8MB, 64bit default */
+               }
+#if !defined(__i386__) && !defined(__x86_64__)
+       }
+#endif
+       if(bios) {
+               v1 = bios[0xe6];
+               v2 = bios[0xe7];
+       } else {
+               inSISIDXREG(SISSR, 0x3a, reg);
+               if((reg & 0x30) == 0x30) {
+                       v1 = 0x04; /* PCI */
+                       v2 = 0x92;
+               } else {
+                       v1 = 0x14; /* AGP */
+                       v2 = 0xb2;
+               }
+       }
+       outSISIDXREG(SISSR, 0x21, v1);
+       outSISIDXREG(SISSR, 0x22, v2);
+
+       /* Sense CRT1 */
+       sisfb_sense_crt1(ivideo);
+
+       /* Set default mode, don't clear screen */
+       ivideo->SiS_Pr.SiS_UseOEM = FALSE;
+       SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
+       SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
+       ivideo->curFSTN = ivideo->curDSTN = 0;
+       ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
+       SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
+
+       outSISIDXREG(SISSR, 0x05, 0x86);
+
+       /* Display off */
+       orSISIDXREG(SISSR, 0x01, 0x20);
+
+       /* Save mode number in CR34 */
+       outSISIDXREG(SISCR, 0x34, 0x2e);
+
+       /* Let everyone know what the current mode is */
+       ivideo->modeprechange = 0x2e;
+}
+#endif
+
+#ifdef CONFIG_FB_SIS_315
+#if 0
+static void __devinit
+sisfb_post_sis315330(struct pci_dev *pdev)
+{
+       /* TODO */
+}
+#endif
+
+static void __devinit
+sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
+{
+       unsigned int i;
+       u8 reg;
+
+       for(i = 0; i <= (delay * 10 * 36); i++) {
+               inSISIDXREG(SISSR, 0x05, reg);
+               reg++;
+       }
+}
+
+static int __devinit
+sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
+                               unsigned short pcivendor)
+{
+       struct pci_dev *pdev = NULL;
+       unsigned short temp;
+       int ret = 0;
+
+       while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
+               temp = pdev->vendor;
+               SIS_PCI_PUT_DEVICE(pdev);
+               if(temp == pcivendor) {
+                       ret = 1;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static int __devinit
+sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
+                       unsigned int enda, unsigned int mapsize)
+{
+       unsigned int pos;
+       int i;
+
+       writel(0, ivideo->video_vbase);
+
+       for(i = starta; i <= enda; i++) {
+               pos = 1 << i;
+               if(pos < mapsize)
+                       writel(pos, ivideo->video_vbase + pos);
+       }
+
+       sisfb_post_xgi_delay(ivideo, 150);
+
+       if(readl(ivideo->video_vbase) != 0)
+               return 0;
+
+       for(i = starta; i <= enda; i++) {
+               pos = 1 << i;
+               if(pos < mapsize) {
+                       if(readl(ivideo->video_vbase + pos) != pos)
+                               return 0;
+               } else
+                       return 0;
+       }
+
+       return 1;
+}
+
+static void __devinit
+sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
+{
+       unsigned int buswidth, ranksize, channelab, mapsize;
+       int i, j, k, l;
+       u8 reg, sr14;
+       static const u8 dramsr13[12 * 5] = {
+               0x02, 0x0e, 0x0b, 0x80, 0x5d,
+               0x02, 0x0e, 0x0a, 0x40, 0x59,
+               0x02, 0x0d, 0x0b, 0x40, 0x4d,
+               0x02, 0x0e, 0x09, 0x20, 0x55,
+               0x02, 0x0d, 0x0a, 0x20, 0x49,
+               0x02, 0x0c, 0x0b, 0x20, 0x3d,
+               0x02, 0x0e, 0x08, 0x10, 0x51,
+               0x02, 0x0d, 0x09, 0x10, 0x45,
+               0x02, 0x0c, 0x0a, 0x10, 0x39,
+               0x02, 0x0d, 0x08, 0x08, 0x41,
+               0x02, 0x0c, 0x09, 0x08, 0x35,
+               0x02, 0x0c, 0x08, 0x04, 0x31
+       };
+       static const u8 dramsr13_4[4 * 5] = {
+               0x02, 0x0d, 0x09, 0x40, 0x45,
+               0x02, 0x0c, 0x09, 0x20, 0x35,
+               0x02, 0x0c, 0x08, 0x10, 0x31,
+               0x02, 0x0b, 0x08, 0x08, 0x21
+       };
+
+       /* Enable linear mode, disable 0xa0000 address decoding */
+       /* We disable a0000 address decoding, because
+        * - if running on x86, if the card is disabled, it means
+        *   that another card is in the system. We don't want
+        *   to interphere with that primary card's textmode.
+        * - if running on non-x86, there usually is no VGA window
+        *   at a0000.
+        */
+       orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
+
+       /* Need to map max FB size for finding out about RAM size */
+       mapsize = 256 << 20;
+       sisfb_post_map_vram(ivideo, &mapsize, 32);
+
+       if(!ivideo->video_vbase) {
+               printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
+               outSISIDXREG(SISSR, 0x13, 0x35);
+               outSISIDXREG(SISSR, 0x14, 0x41);
+               /* TODO */
+               return;
+       }
+
+       /* Non-interleaving */
+       outSISIDXREG(SISSR, 0x15, 0x00);
+       /* No tiling */
+       outSISIDXREG(SISSR, 0x1c, 0x00);
+
+       if(ivideo->chip == XGI_20) {
+
+               channelab = 1;
+               inSISIDXREG(SISCR, 0x97, reg);
+               if(!(reg & 0x01)) {     /* Single 32/16 */
+                       buswidth = 32;
+                       outSISIDXREG(SISSR, 0x13, 0xb1);
+                       outSISIDXREG(SISSR, 0x14, 0x52);
+                       sisfb_post_xgi_delay(ivideo, 1);
+                       sr14 = 0x02;
+                       if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
+                               goto bail_out;
+
+                       outSISIDXREG(SISSR, 0x13, 0x31);
+                       outSISIDXREG(SISSR, 0x14, 0x42);
+                       sisfb_post_xgi_delay(ivideo, 1);
+                       if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
+                               goto bail_out;
+
+                       buswidth = 16;
+                       outSISIDXREG(SISSR, 0x13, 0xb1);
+                       outSISIDXREG(SISSR, 0x14, 0x41);
+                       sisfb_post_xgi_delay(ivideo, 1);
+                       sr14 = 0x01;
+                       if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
+                               goto bail_out;
+                       else
+                               outSISIDXREG(SISSR, 0x13, 0x31);
+               } else {                /* Dual 16/8 */
+                       buswidth = 16;
+                       outSISIDXREG(SISSR, 0x13, 0xb1);
+                       outSISIDXREG(SISSR, 0x14, 0x41);
+                       sisfb_post_xgi_delay(ivideo, 1);
+                       sr14 = 0x01;
+                       if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
+                               goto bail_out;
+
+                       outSISIDXREG(SISSR, 0x13, 0x31);
+                       outSISIDXREG(SISSR, 0x14, 0x31);
+                       sisfb_post_xgi_delay(ivideo, 1);
+                       if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
+                               goto bail_out;
+
+                       buswidth = 8;
+                       outSISIDXREG(SISSR, 0x13, 0xb1);
+                       outSISIDXREG(SISSR, 0x14, 0x30);
+                       sisfb_post_xgi_delay(ivideo, 1);
+                       sr14 = 0x00;
+                       if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
+                               goto bail_out;
+                       else
+                               outSISIDXREG(SISSR, 0x13, 0x31);
+               }
+
+       } else {        /* XGI_40 */
+
+               inSISIDXREG(SISCR, 0x97, reg);
+               if(!(reg & 0x10)) {
+                       inSISIDXREG(SISSR, 0x39, reg);
+                       reg >>= 1;
+               }
+
+               if(reg & 0x01) {        /* DDRII */
+                       buswidth = 32;
+                       if(ivideo->revision_id == 2) {
+                               channelab = 2;
+                               outSISIDXREG(SISSR, 0x13, 0xa1);
+                               outSISIDXREG(SISSR, 0x14, 0x44);
+                               sr14 = 0x04;
+                               sisfb_post_xgi_delay(ivideo, 1);
+                               if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
+                                       goto bail_out;
+
+                               outSISIDXREG(SISSR, 0x13, 0x21);
+                               outSISIDXREG(SISSR, 0x14, 0x34);
+                               if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
+                                       goto bail_out;
+
+                               channelab = 1;
+                               outSISIDXREG(SISSR, 0x13, 0xa1);
+                               outSISIDXREG(SISSR, 0x14, 0x40);
+                               sr14 = 0x00;
+                               if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
+                                       goto bail_out;
+
+                               outSISIDXREG(SISSR, 0x13, 0x21);
+                               outSISIDXREG(SISSR, 0x14, 0x30);
+                       } else {
+                               channelab = 3;
+                               outSISIDXREG(SISSR, 0x13, 0xa1);
+                               outSISIDXREG(SISSR, 0x14, 0x4c);
+                               sr14 = 0x0c;
+                               sisfb_post_xgi_delay(ivideo, 1);
+                               if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
+                                       goto bail_out;
+
+                               channelab = 2;
+                               outSISIDXREG(SISSR, 0x14, 0x48);
+                               sisfb_post_xgi_delay(ivideo, 1);
+                               sr14 = 0x08;
+                               if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
+                                       goto bail_out;
+
+                               outSISIDXREG(SISSR, 0x13, 0x21);
+                               outSISIDXREG(SISSR, 0x14, 0x3c);
+                               sr14 = 0x0c;
+
+                               if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
+                                       channelab = 3;
+                               } else {
+                                       channelab = 2;
+                                       outSISIDXREG(SISSR, 0x14, 0x38);
+                                       sr14 = 0x08;
+                               }
+                       }
+                       sisfb_post_xgi_delay(ivideo, 1);
+
+               } else {        /* DDR */
+
+                       buswidth = 64;
+                       if(ivideo->revision_id == 2) {
+                               channelab = 1;
+                               outSISIDXREG(SISSR, 0x13, 0xa1);
+                               outSISIDXREG(SISSR, 0x14, 0x52);
+                               sisfb_post_xgi_delay(ivideo, 1);
+                               sr14 = 0x02;
+                               if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
+                                       goto bail_out;
+
+                               outSISIDXREG(SISSR, 0x13, 0x21);
+                               outSISIDXREG(SISSR, 0x14, 0x42);
+                       } else {
+                               channelab = 2;
+                               outSISIDXREG(SISSR, 0x13, 0xa1);
+                               outSISIDXREG(SISSR, 0x14, 0x5a);
+                               sisfb_post_xgi_delay(ivideo, 1);
+                               sr14 = 0x0a;
+                               if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
+                                       goto bail_out;
+
+                               outSISIDXREG(SISSR, 0x13, 0x21);
+                               outSISIDXREG(SISSR, 0x14, 0x4a);
+                       }
+                       sisfb_post_xgi_delay(ivideo, 1);
+
+               }
+       }
+
+bail_out:
+       setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
+       sisfb_post_xgi_delay(ivideo, 1);
+
+       j = (ivideo->chip == XGI_20) ? 5 : 9;
+       k = (ivideo->chip == XGI_20) ? 12 : 4;
+
+       for(i = 0; i < k; i++) {
+
+               reg = (ivideo->chip == XGI_20) ?
+                               dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
+               setSISIDXREG(SISSR, 0x13, 0x80, reg);
+               sisfb_post_xgi_delay(ivideo, 50);
+
+               ranksize = (ivideo->chip == XGI_20) ?
+                               dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
+
+               inSISIDXREG(SISSR, 0x13, reg);
+               if(reg & 0x80) ranksize <<= 1;
+
+               if(ivideo->chip == XGI_20) {
+                       if(buswidth == 16)      ranksize <<= 1;
+                       else if(buswidth == 32) ranksize <<= 2;
+               } else {
+                       if(buswidth == 64)      ranksize <<= 1;
+               }
+
+               reg = 0;
+               l = channelab;
+               if(l == 3) l = 4;
+               if((ranksize * l) <= 256) {
+                       while((ranksize >>= 1)) reg += 0x10;
+               }
+
+               if(!reg) continue;
+
+               setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
+               sisfb_post_xgi_delay(ivideo, 1);
+
+               if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
+                       break;
+       }
+
+       iounmap(ivideo->video_vbase);
+}
 
+static void __devinit
+sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
+{
+       u8 v1, v2, v3;
+       int index;
+       static const u8 cs90[8 * 3] = {
+               0x16, 0x01, 0x01,
+               0x3e, 0x03, 0x01,
+               0x7c, 0x08, 0x01,
+               0x79, 0x06, 0x01,
+               0x29, 0x01, 0x81,
+               0x5c, 0x23, 0x01,
+               0x5c, 0x23, 0x01,
+               0x5c, 0x23, 0x01
+       };
+       static const u8 csb8[8 * 3] = {
+               0x5c, 0x23, 0x01,
+               0x29, 0x01, 0x01,
+               0x7c, 0x08, 0x01,
+               0x79, 0x06, 0x01,
+               0x29, 0x01, 0x81,
+               0x5c, 0x23, 0x01,
+               0x5c, 0x23, 0x01,
+               0x5c, 0x23, 0x01
+       };
 
-       return 0;
+       regb = 0;  /* ! */
+
+       index = regb * 3;
+       v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
+       if(ivideo->haveXGIROM) {
+               v1 = ivideo->bios_abase[0x90 + index];
+               v2 = ivideo->bios_abase[0x90 + index + 1];
+               v3 = ivideo->bios_abase[0x90 + index + 2];
+       }
+       outSISIDXREG(SISSR, 0x28, v1);
+       outSISIDXREG(SISSR, 0x29, v2);
+       outSISIDXREG(SISSR, 0x2a, v3);
+       sisfb_post_xgi_delay(ivideo, 0x43);
+       sisfb_post_xgi_delay(ivideo, 0x43);
+       sisfb_post_xgi_delay(ivideo, 0x43);
+       index = regb * 3;
+       v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
+       if(ivideo->haveXGIROM) {
+               v1 = ivideo->bios_abase[0xb8 + index];
+               v2 = ivideo->bios_abase[0xb8 + index + 1];
+               v3 = ivideo->bios_abase[0xb8 + index + 2];
+       }
+       outSISIDXREG(SISSR, 0x2e, v1);
+       outSISIDXREG(SISSR, 0x2f, v2);
+       outSISIDXREG(SISSR, 0x30, v3);
+       sisfb_post_xgi_delay(ivideo, 0x43);
+       sisfb_post_xgi_delay(ivideo, 0x43);
+       sisfb_post_xgi_delay(ivideo, 0x43);
 }
-#endif
 
-static UCHAR * __devinit sis_find_rom(struct pci_dev *pdev)
+static int __devinit
+sisfb_post_xgi(struct pci_dev *pdev)
 {
        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
-       USHORT pciid;
-       int    romptr;
-       UCHAR  *myrombase;
-       u32    temp;
-       SIS_IOTYPE1 *rom_base, *rom;
+       unsigned char *bios = ivideo->bios_abase;
+       struct pci_dev *mypdev = NULL;
+       const u8 *ptr, *ptr2;
+       u8 v1, v2, v3, v4, v5, reg, ramtype;
+       u32 rega, regb, regd;
+       int i, j, k, index;
+       static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
+       static const u8 cs76[2] = { 0xa3, 0xfb };
+       static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
+       static const u8 cs158[8] = {
+               0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       static const u8 cs160[8] = {
+               0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       static const u8 cs168[8] = {
+               0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       static const u8 cs128[3 * 8] = {
+               0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       static const u8 cs148[2 * 8] = {
+               0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       static const u8 cs31a[8 * 4] = {
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       static const u8 cs33a[8 * 4] = {
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       static const u8 cs45a[8 * 2] = {
+               0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       static const u8 cs170[7 * 8] = {
+               0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       static const u8 cs1a8[3 * 8] = {
+               0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       static const u8 cs100[2 * 8] = {
+               0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
 
-       if(!(myrombase = vmalloc(65536))) return NULL;
+       /* VGA enable */
+       reg = inSISREG(SISVGAENABLE) | 0x01;
+       outSISREG(SISVGAENABLE, reg);
 
-#if defined(__i386__) || defined(__x86_64__)
+       /* Misc */
+       reg = inSISREG(SISMISCR) | 0x01;
+       outSISREG(SISMISCW, reg);
 
-        for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
+       /* Unlock SR */
+       outSISIDXREG(SISSR, 0x05, 0x86);
+       inSISIDXREG(SISSR, 0x05, reg);
+       if(reg != 0xa1)
+               return 0;
 
-            rom_base = ioremap(temp, 0x10000);
-           if(!rom_base) continue;
+       /* Clear some regs */
+       for(i = 0; i < 0x22; i++) {
+               if(0x06 + i == 0x20) continue;
+               outSISIDXREG(SISSR, 0x06 + i, 0x00);
+       }
+       for(i = 0; i < 0x0b; i++) {
+               outSISIDXREG(SISSR, 0x31 + i, 0x00);
+       }
+       for(i = 0; i < 0x10; i++) {
+               outSISIDXREG(SISCR, 0x30 + i, 0x00);
+       }
 
-           if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) {
-              iounmap(rom_base);
-               continue;
-           }
+       ptr = cs78;
+       if(ivideo->haveXGIROM) {
+               ptr = (const u8 *)&bios[0x78];
+       }
+       for(i = 0; i < 3; i++) {
+               outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
+       }
 
-           romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
-           if(romptr > (0x10000 - 8)) {
-              iounmap(rom_base);
-              continue;
-           }
+       ptr = cs76;
+       if(ivideo->haveXGIROM) {
+               ptr = (const u8 *)&bios[0x76];
+       }
+       for(i = 0; i < 2; i++) {
+               outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
+       }
 
-           rom = rom_base + romptr;
+       v1 = 0x18; v2 = 0x00;
+       if(ivideo->haveXGIROM) {
+               v1 = bios[0x74];
+               v2 = bios[0x75];
+       }
+       outSISIDXREG(SISSR, 0x07, v1);
+       outSISIDXREG(SISSR, 0x11, 0x0f);
+       outSISIDXREG(SISSR, 0x1f, v2);
+       /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
+       outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
+       outSISIDXREG(SISSR, 0x27, 0x74);
 
-           if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
-              (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) {
-              iounmap(rom_base);
-              continue;
-           }
+       ptr = cs7b;
+       if(ivideo->haveXGIROM) {
+               ptr = (const u8 *)&bios[0x7b];
+       }
+       for(i = 0; i < 3; i++) {
+               outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
+       }
 
-           pciid = readb(rom + 4) | (readb(rom + 5) << 8);
-           if(pciid != 0x1039) {
-              iounmap(rom_base);
-              continue;
-           }
+       if(ivideo->chip == XGI_40) {
+               if(ivideo->revision_id == 2) {
+                       setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
+               }
+               outSISIDXREG(SISCR, 0x7d, 0xfe);
+               outSISIDXREG(SISCR, 0x7e, 0x0f);
+       }
+       if(ivideo->revision_id == 0) {  /* 40 *and* 20? */
+               andSISIDXREG(SISCR, 0x58, 0xd7);
+               inSISIDXREG(SISCR, 0xcb, reg);
+               if(reg & 0x20) {
+                       setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
+               }
+       }
 
-           pciid = readb(rom + 6) | (readb(rom + 7) << 8);
-           if(pciid == ivideo->chip_id) {
-              memcpy_fromio(myrombase, rom_base, 65536);
-              iounmap(rom_base);
-              return myrombase;
-           }
+       reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
+       setSISIDXREG(SISCR, 0x38, 0x1f, reg);
 
-           iounmap(rom_base);
-        }
+       if(ivideo->chip == XGI_20) {
+               outSISIDXREG(SISSR, 0x36, 0x70);
+       } else {
+               outSISIDXREG(SISVID, 0x00, 0x86);
+               outSISIDXREG(SISVID, 0x32, 0x00);
+               outSISIDXREG(SISVID, 0x30, 0x00);
+               outSISIDXREG(SISVID, 0x32, 0x01);
+               outSISIDXREG(SISVID, 0x30, 0x00);
+               andSISIDXREG(SISVID, 0x2f, 0xdf);
+               andSISIDXREG(SISCAP, 0x00, 0x3f);
+
+               outSISIDXREG(SISPART1, 0x2f, 0x01);
+               outSISIDXREG(SISPART1, 0x00, 0x00);
+               outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
+               outSISIDXREG(SISPART1, 0x2e, 0x08);
+               andSISIDXREG(SISPART1, 0x35, 0x7f);
+               andSISIDXREG(SISPART1, 0x50, 0xfe);
+
+               inSISIDXREG(SISPART4, 0x00, reg);
+               if(reg == 1 || reg == 2) {
+                       outSISIDXREG(SISPART2, 0x00, 0x1c);
+                       outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
+                       outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
+                       outSISIDXREG(SISPART4, 0x10, bios[0x81]);
+                       andSISIDXREG(SISPART4, 0x0f, 0x3f);
+
+                       inSISIDXREG(SISPART4, 0x01, reg);
+                       if((reg & 0xf0) >= 0xb0) {
+                               inSISIDXREG(SISPART4, 0x23, reg);
+                               if(reg & 0x20) reg |= 0x40;
+                               outSISIDXREG(SISPART4, 0x23, reg);
+                               reg = (reg & 0x20) ? 0x02 : 0x00;
+                               setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
+                       }
+               }
 
-#else
+               v1 = bios[0x77];
+
+               inSISIDXREG(SISSR, 0x3b, reg);
+               if(reg & 0x02) {
+                       inSISIDXREG(SISSR, 0x3a, reg);
+                       v2 = (reg & 0x30) >> 3;
+                       if(!(v2 & 0x04)) v2 ^= 0x02;
+                       inSISIDXREG(SISSR, 0x39, reg);
+                       if(reg & 0x80) v2 |= 0x80;
+                       v2 |= 0x01;
+
+                       if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
+                               SIS_PCI_PUT_DEVICE(mypdev);
+                               if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
+                                       v2 &= 0xf9;
+                               v2 |= 0x08;
+                               v1 &= 0xfe;
+                       } else {
+                               mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
+                               if(!mypdev)
+                                       mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
+                               if(!mypdev)
+                                       mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
+                               if(mypdev) {
+                                       pci_read_config_dword(mypdev, 0x94, &regd);
+                                       regd &= 0xfffffeff;
+                                       pci_write_config_dword(mypdev, 0x94, regd);
+                                       v1 &= 0xfe;
+                                       SIS_PCI_PUT_DEVICE(mypdev);
+                               } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
+                                       v1 &= 0xfe;
+                               } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
+                                         sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
+                                         sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
+                                         sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
+                                       if((v2 & 0x06) == 4)
+                                               v2 ^= 0x06;
+                                       v2 |= 0x08;
+                               }
+                       }
+                       setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
+               }
+               outSISIDXREG(SISSR, 0x22, v1);
+
+               if(ivideo->revision_id == 2) {
+                       inSISIDXREG(SISSR, 0x3b, v1);
+                       inSISIDXREG(SISSR, 0x3a, v2);
+                       regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
+                       if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
+                               setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
+
+                       if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
+                               /* TODO: set CR5f &0xf1 | 0x01 for version 6570
+                                * of nforce 2 ROM
+                                */
+                               if(0)
+                                       setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
+                               SIS_PCI_PUT_DEVICE(mypdev);
+                       }
+               }
 
-       pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
-       pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
-                       (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
+               v1 = 0x30;
+               inSISIDXREG(SISSR, 0x3b, reg);
+               inSISIDXREG(SISCR, 0x5f, v2);
+               if((!(reg & 0x02)) && (v2 & 0x0e))
+                       v1 |= 0x08;
+               outSISIDXREG(SISSR, 0x27, v1);
 
-       rom_base = ioremap(ivideo->video_base, 65536);
-       if(rom_base) {
-          if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) {
-             romptr = (u16)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
-             if(romptr <= (0x10000 - 8)) {
-                rom = rom_base + romptr;
-                if((readb(rom)     == 'P') && (readb(rom + 1) == 'C') &&
-                   (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) {
-                   pciid = readb(rom + 4) | (readb(rom + 5) << 8);
-                   if(pciid == 0x1039) {
-                      pciid = readb(rom + 6) | (readb(rom + 7) << 8);
-                      if(pciid == ivideo->chip_id) {
-                         memcpy_fromio(myrombase, rom_base, 65536);
-                         iounmap(rom_base);
-                         pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
-                         return myrombase;
-                      }
-                   }
-                }
-             }
-          }
-          iounmap(rom_base);
+               if(bios[0x64] & 0x01) {
+                       setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
+               }
+
+               v1 = bios[0x4f7];
+               pci_read_config_dword(pdev, 0x50, &regd);
+               regd = (regd >> 20) & 0x0f;
+               if(regd == 1) {
+                       v1 &= 0xfc;
+                       orSISIDXREG(SISCR, 0x5f, 0x08);
+               }
+               outSISIDXREG(SISCR, 0x48, v1);
+
+               setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
+               setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
+               setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
+               setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
+               setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
+               outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
+               setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
+               outSISIDXREG(SISCR, 0x74, 0xd0);
+               setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
+               setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
+               setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
+               v1 = bios[0x501];
+               if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
+                       v1 = 0xf0;
+                       SIS_PCI_PUT_DEVICE(mypdev);
+               }
+               outSISIDXREG(SISCR, 0x77, v1);
        }
-        pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
 
-#endif
+       /* RAM type */
 
-               vfree(myrombase);
-        return NULL;
-}
+       regb = 0;       /* ! */
 
-#ifdef CONFIG_FB_SIS_300
-static int __devinit
-sisfb_chkbuswidth300(struct pci_dev *pdev, SIS_IOTYPE1 *FBAddress)
-{
-       struct sis_video_info *ivideo = pci_get_drvdata(pdev);
-       int i, j;
-       USHORT temp;
-       UCHAR reg;
-
-       andSISIDXREG(SISSR,0x15,0xFB);
-       orSISIDXREG(SISSR,0x15,0x04);
-       outSISIDXREG(SISSR,0x13,0x00);
-       outSISIDXREG(SISSR,0x14,0xBF);
-
-       for(i=0; i<2; i++) {
-          temp = 0x1234;
-          for(j=0; j<4; j++) {
-             writew(temp, FBAddress);
-             if(readw(FBAddress) == temp) break;
-             orSISIDXREG(SISSR,0x3c,0x01);
-             inSISIDXREG(SISSR,0x05,reg);
-             inSISIDXREG(SISSR,0x05,reg);
-             andSISIDXREG(SISSR,0x3c,0xfe);
-             inSISIDXREG(SISSR,0x05,reg);
-             inSISIDXREG(SISSR,0x05,reg);
-             temp++;
-          }
+       v1 = 0xff;
+       if(ivideo->haveXGIROM) {
+               v1 = bios[0x140 + regb];
        }
+       outSISIDXREG(SISCR, 0x6d, v1);
 
-       writel(0x01234567L, FBAddress);
-       writel(0x456789ABL, (FBAddress+4));
-       writel(0x89ABCDEFL, (FBAddress+8));
-       writel(0xCDEF0123L, (FBAddress+12));
-       inSISIDXREG(SISSR,0x3b,reg);
-       if(reg & 0x01) {
-          if(readl((FBAddress+12)) == 0xCDEF0123L) return(4);  /* Channel A 128bit */
+       ptr = cs128;
+       if(ivideo->haveXGIROM) {
+               ptr = (const u8 *)&bios[0x128];
        }
-       if(readl((FBAddress+4)) == 0x456789ABL)     return(2);  /* Channel B 64bit */
-       return(1);                                              /* 32bit */
-}
-
-static void __devinit
-sisfb_setramsize300(struct pci_dev *pdev)
-{
-       struct  sis_video_info *ivideo = pci_get_drvdata(pdev);
-       SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
-       SIS_IOTYPE1 *Addr;
-       USHORT  sr13, sr14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0;
-       int     PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
-       int     RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
-       int     PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k;
-       const   USHORT SiS_DRAMType[17][5] = {
-                       {0x0C,0x0A,0x02,0x40,0x39},
-                       {0x0D,0x0A,0x01,0x40,0x48},
-                       {0x0C,0x09,0x02,0x20,0x35},
-                       {0x0D,0x09,0x01,0x20,0x44},
-                       {0x0C,0x08,0x02,0x10,0x31},
-                       {0x0D,0x08,0x01,0x10,0x40},
-                       {0x0C,0x0A,0x01,0x20,0x34},
-                       {0x0C,0x09,0x01,0x08,0x32},
-                       {0x0B,0x08,0x02,0x08,0x21},
-                       {0x0C,0x08,0x01,0x08,0x30},
-                       {0x0A,0x08,0x02,0x04,0x11},
-                       {0x0B,0x0A,0x01,0x10,0x28},
-                       {0x09,0x08,0x02,0x02,0x01},
-                       {0x0B,0x09,0x01,0x08,0x24},
-                       {0x0B,0x08,0x01,0x04,0x20},
-                       {0x0A,0x08,0x01,0x02,0x10},
-                       {0x09,0x08,0x01,0x01,0x00}
-               };
-
-        buswidth = sisfb_chkbuswidth300(pdev, FBAddr);
-
-       MB2Bank = 16;
-       Done = 0;
-       for(i = 6; i >= 0; i--) {
-          if(Done) break;
-          PseudoRankCapacity = 1 << i;
-          for(j = 4; j >= 1; j--) {
-              if(Done) break;
-              PseudoTotalCapacity = PseudoRankCapacity * j;
-              PseudoAdrPinCount = 15 - j;
-              if(PseudoTotalCapacity <= 64) {
-                 for(k = 0; k <= 16; k++) {
-                    if(Done) break;
-                    RankCapacity = buswidth * SiS_DRAMType[k][3];
-                    AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
-                    if(RankCapacity == PseudoRankCapacity)
-                       if(AdrPinCount <= PseudoAdrPinCount) {
-                          if(j == 3) {             /* Rank No */
-                             BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
-                             BankNumMid  = RankCapacity * MB2Bank * 1 - 1;
-                          } else {
-                             BankNumHigh = RankCapacity * MB2Bank * j - 1;
-                             BankNumMid  = RankCapacity * MB2Bank * j / 2 - 1;
-                          }
-                          PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
-                          PhysicalAdrHigh = BankNumHigh;
-                          PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
-                          PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
-                          /* Write data */
-                          andSISIDXREG(SISSR,0x15,0xFB); /* Test */
-                          orSISIDXREG(SISSR,0x15,0x04);  /* Test */
-                          TotalCapacity = SiS_DRAMType[k][3] * buswidth;
-                          sr13 = SiS_DRAMType[k][4];
-                          if(buswidth == 4) sr14 = (TotalCapacity - 1) | 0x80;
-                          if(buswidth == 2) sr14 = (TotalCapacity - 1) | 0x40;
-                          if(buswidth == 1) sr14 = (TotalCapacity - 1) | 0x00;
-                          outSISIDXREG(SISSR,0x13,sr13);
-                          outSISIDXREG(SISSR,0x14,sr14);
-                          Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
-                          /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */
-                         writew(((USHORT)PhysicalAdrHigh), Addr);
-                          Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh;
-                          /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */
-                         writew(((USHORT)BankNumMid), Addr);
-                          Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage;
-                          /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */
-                         writew(((USHORT)PhysicalAdrHalfPage), Addr);
-                          Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage;
-                          /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */
-                         writew(((USHORT)PhysicalAdrOtherPage), Addr);
-                          /* Read data */
-                          Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
-                          data = readw(Addr); /* *((USHORT *)(Addr)); */
-                          if(data == PhysicalAdrHigh) Done = 1;
-                       }  /* if */
-                 }  /* for k */
-              }  /* if */
-          }  /* for j */
-       }  /* for i */
-}
-
-static void __devinit sisfb_post_sis300(struct pci_dev *pdev)
-{
-       struct sis_video_info *ivideo = pci_get_drvdata(pdev);
-       u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
-       u16 index, rindex, memtype = 0;
-
-       outSISIDXREG(SISSR,0x05,0x86);
-
-       if(ivideo->sishw_ext.UseROM) {
-          if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80) {
-             memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
-          } else {
-             inSISIDXREG(SISSR,0x3a,memtype);
-          }
-          memtype &= 0x07;
+       for(i = 0, j = 0; i < 3; i++, j += 8) {
+               outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
        }
 
-       if(ivideo->revision_id <= 0x13) {
-          v1 = 0x44; v2 = 0x42; v3 = 0x80;
-          v4 = 0x44; v5 = 0x42; v6 = 0x80;
-       } else {
-          v1 = 0x68; v2 = 0x43; v3 = 0x80;  /* Assume 125Mhz MCLK */
-          v4 = 0x68; v5 = 0x43; v6 = 0x80;  /* Assume 125Mhz ECLK */
-          if(ivideo->sishw_ext.UseROM) {
-             index = memtype * 5;
-             rindex = index + 0x54;
-             v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
-             v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
-             v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
-             rindex = index + 0x7c;
-             v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
-             v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
-             v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
-          }
+       ptr  = cs31a;
+       ptr2 = cs33a;
+       if(ivideo->haveXGIROM) {
+               index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
+               ptr  = (const u8 *)&bios[index];
+               ptr2 = (const u8 *)&bios[index + 0x20];
        }
-       outSISIDXREG(SISSR,0x28,v1);
-       outSISIDXREG(SISSR,0x29,v2);
-       outSISIDXREG(SISSR,0x2a,v3);
-       outSISIDXREG(SISSR,0x2e,v4);
-       outSISIDXREG(SISSR,0x2f,v5);
-       outSISIDXREG(SISSR,0x30,v6);
-       v1 = 0x10;
-       if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0xa4];
-       outSISIDXREG(SISSR,0x07,v1);       /* DAC speed */
-       outSISIDXREG(SISSR,0x11,0x0f);     /* DDC, power save */
-       v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
-       v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
-       if(ivideo->sishw_ext.UseROM) {
-          memtype += 0xa5;
-          v1 = ivideo->sishw_ext.pjVirtualRomBase[memtype];
-          v2 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 8];
-          v3 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 16];
-          v4 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 24];
-          v5 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 32];
-          v6 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 40];
-          v7 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 48];
-          v8 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 56];
-       }
-       if(ivideo->revision_id >= 0x80) v3 &= 0xfd;
-       outSISIDXREG(SISSR,0x15,v1);       /* Ram type (assuming 0, BIOS 0xa5 step 8) */
-       outSISIDXREG(SISSR,0x16,v2);
-       outSISIDXREG(SISSR,0x17,v3);
-       outSISIDXREG(SISSR,0x18,v4);
-       outSISIDXREG(SISSR,0x19,v5);
-       outSISIDXREG(SISSR,0x1a,v6);
-       outSISIDXREG(SISSR,0x1b,v7);
-       outSISIDXREG(SISSR,0x1c,v8);       /* ---- */
-       andSISIDXREG(SISSR,0x15,0xfb);
-       orSISIDXREG(SISSR,0x15,0x04);
-       if(ivideo->sishw_ext.UseROM) {
-          if(ivideo->sishw_ext.pjVirtualRomBase[0x53] & 0x02) {
-             orSISIDXREG(SISSR,0x19,0x20);
-          }
+       for(i = 0; i < 2; i++) {
+               if(i == 0) {
+                       regd = le32_to_cpu(((u32 *)ptr)[regb]);
+                       rega = 0x6b;
+               } else {
+                       regd = le32_to_cpu(((u32 *)ptr2)[regb]);
+                       rega = 0x6e;
+               }
+               reg = 0x00;
+               for(j = 0; j < 16; j++) {
+                       reg &= 0xf3;
+                       if(regd & 0x01) reg |= 0x04;
+                       if(regd & 0x02) reg |= 0x08;
+                       regd >>= 2;
+                       outSISIDXREG(SISCR, rega, reg);
+                       inSISIDXREG(SISCR, rega, reg);
+                       inSISIDXREG(SISCR, rega, reg);
+                       reg += 0x10;
+               }
        }
-       v1 = 0x04;                         /* DAC pedestal (BIOS 0xe5) */
-       if(ivideo->revision_id >= 0x80) v1 |= 0x01;
-       outSISIDXREG(SISSR,0x1f,v1);
-       outSISIDXREG(SISSR,0x20,0xa0);     /* linear & relocated io */
-       v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
-       if(ivideo->sishw_ext.UseROM) {
-          v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe8];
-          v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe9];
-          v3 = ivideo->sishw_ext.pjVirtualRomBase[0xea];
-       }
-       outSISIDXREG(SISSR,0x23,v1);
-       outSISIDXREG(SISSR,0x24,v2);
-       outSISIDXREG(SISSR,0x25,v3);
-       outSISIDXREG(SISSR,0x21,0x84);
-       outSISIDXREG(SISSR,0x22,0x00);
-       outSISIDXREG(SISCR,0x37,0x00);
-       orSISIDXREG(SISPART1,0x24,0x01);   /* unlock crt2 */
-       outSISIDXREG(SISPART1,0x00,0x00);
-       v1 = 0x40; v2 = 0x11;
-       if(ivideo->sishw_ext.UseROM) {
-          v1 = ivideo->sishw_ext.pjVirtualRomBase[0xec];
-          v2 = ivideo->sishw_ext.pjVirtualRomBase[0xeb];
+
+       andSISIDXREG(SISCR, 0x6e, 0xfc);
+
+       ptr  = NULL;
+       if(ivideo->haveXGIROM) {
+               index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
+               ptr  = (const u8 *)&bios[index];
        }
-       outSISIDXREG(SISPART1,0x02,v1);
-       if(ivideo->revision_id >= 0x80) v2 &= ~0x01;
-       inSISIDXREG(SISPART4,0x00,reg);
-       if((reg == 1) || (reg == 2)) {
-          outSISIDXREG(SISCR,0x37,0x02);
-          outSISIDXREG(SISPART2,0x00,0x1c);
-          v4 = 0x00; v5 = 0x00; v6 = 0x10;
-          if(ivideo->sishw_ext.UseROM) {
-             v4 = ivideo->sishw_ext.pjVirtualRomBase[0xf5];
-             v5 = ivideo->sishw_ext.pjVirtualRomBase[0xf6];
-             v6 = ivideo->sishw_ext.pjVirtualRomBase[0xf7];
-          }
-          outSISIDXREG(SISPART4,0x0d,v4);
-          outSISIDXREG(SISPART4,0x0e,v5);
-          outSISIDXREG(SISPART4,0x10,v6);
-          outSISIDXREG(SISPART4,0x0f,0x3f);
-          inSISIDXREG(SISPART4,0x01,reg);
-          if(reg >= 0xb0) {
-             inSISIDXREG(SISPART4,0x23,reg);
-             reg &= 0x20;
-             reg <<= 1;
-             outSISIDXREG(SISPART4,0x23,reg);
-          }
-       } else {
-          v2 &= ~0x10;
+       for(i = 0; i < 4; i++) {
+               setSISIDXREG(SISCR, 0x6e, 0xfc, i);
+               reg = 0x00;
+               for(j = 0; j < 2; j++) {
+                       regd = 0;
+                       if(ptr) {
+                               regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
+                               ptr += 4;
+                       }
+                       /* reg = 0x00; */
+                       for(k = 0; k < 16; k++) {
+                               reg &= 0xfc;
+                               if(regd & 0x01) reg |= 0x01;
+                               if(regd & 0x02) reg |= 0x02;
+                               regd >>= 2;
+                               outSISIDXREG(SISCR, 0x6f, reg);
+                               inSISIDXREG(SISCR, 0x6f, reg);
+                               inSISIDXREG(SISCR, 0x6f, reg);
+                               reg += 0x08;
+                       }
+               }
        }
-       outSISIDXREG(SISSR,0x32,v2);
-       andSISIDXREG(SISPART1,0x24,0xfe);  /* Lock CRT2 */
-       inSISIDXREG(SISSR,0x16,reg);
-       reg &= 0xc3;
-       outSISIDXREG(SISCR,0x35,reg);
-       outSISIDXREG(SISCR,0x83,0x00);
-#if !defined(__i386__) && !defined(__x86_64__)
-       if(sisfb_videoram) {
-          outSISIDXREG(SISSR,0x13,0x28);  /* ? */
-          reg = ((sisfb_videoram >> 10) - 1) | 0x40;
-          outSISIDXREG(SISSR,0x14,reg);
-       } else {
-#endif
-          /* Need to map max FB size for finding out about RAM size */
-          ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000);
-          if(ivideo->video_vbase) {
-             sisfb_setramsize300(pdev);
-             iounmap(ivideo->video_vbase);
-          } else {
-             printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
-             outSISIDXREG(SISSR,0x13,0x28);  /* ? */
-             outSISIDXREG(SISSR,0x14,0x47);  /* 8MB, 64bit default */
-          }
-#if !defined(__i386__) && !defined(__x86_64__)
+
+       ptr  = cs148;
+       if(ivideo->haveXGIROM) {
+               ptr  = (const u8 *)&bios[0x148];
        }
-#endif
-       if(ivideo->sishw_ext.UseROM) {
-          v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe6];
-          v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe7];
-       } else {
-          inSISIDXREG(SISSR,0x3a,reg);
-          if((reg & 0x30) == 0x30) {
-             v1 = 0x04; /* PCI */
-             v2 = 0x92;
-          } else {
-             v1 = 0x14; /* AGP */
-             v2 = 0xb2;
-          }
+       for(i = 0, j = 0; i < 2; i++, j += 8) {
+               outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
        }
-       outSISIDXREG(SISSR,0x21,v1);
-       outSISIDXREG(SISSR,0x22,v2);
-}
-#endif
-
-#ifdef CONFIG_FB_SIS_315
-static void __devinit sisfb_post_sis315330(struct pci_dev *pdev)
-{
-#ifdef YET_TO_BE_DONE
-       struct sis_video_info *ivideo = pci_get_drvdata(pdev);
-       u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
-       u16 index, rindex, memtype = 0;
-       u32 reg1_32, reg2_32, reg3_32;
-       int i;
 
-       /* Unlock */
-       /* outSISIDXREG(0x3c4,0x05,0x86); */
-       outSISIDXREG(SISSR,0x05,0x86);
+       andSISIDXREG(SISCR, 0x89, 0x8f);
 
-       /* Enable relocated i/o ports */
-       /* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */
-       setSISIDXREG(SISSR,0x20,~0x10,0x20);
+       ptr  = cs45a;
+       if(ivideo->haveXGIROM) {
+               index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
+               ptr  = (const u8 *)&bios[index];
+       }
+       regd = le16_to_cpu(((const u16 *)ptr)[regb]);
+       reg = 0x80;
+       for(i = 0; i < 5; i++) {
+               reg &= 0xfc;
+               if(regd & 0x01) reg |= 0x01;
+               if(regd & 0x02) reg |= 0x02;
+               regd >>= 2;
+               outSISIDXREG(SISCR, 0x89, reg);
+               inSISIDXREG(SISCR, 0x89, reg);
+               inSISIDXREG(SISCR, 0x89, reg);
+               reg += 0x10;
+       }
 
-       /* Clear regs */
-       for(i = 0; i < 0x22; i++) {
-          outSISIDXREG(SISSR,(0x06 + i),0x00);
+       v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
+       if(ivideo->haveXGIROM) {
+               v1 = bios[0x118 + regb];
+               v2 = bios[0xf8 + regb];
+               v3 = bios[0x120 + regb];
+               v4 = bios[0x1ca];
        }
-       v1 = 0x0d;
-       if( is 330) v1 = 0x0b;
-       for(i = 0; i < v1; i++) {
-          outSISIDXREG(SISSR,(0x31 + i),0x00);
+       outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
+       outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
+       orSISIDXREG(SISCR, 0x40, v1 & 0x80);
+       outSISIDXREG(SISCR, 0x41, v2);
+
+       ptr  = cs170;
+       if(ivideo->haveXGIROM) {
+               ptr  = (const u8 *)&bios[0x170];
        }
-       for(i = 0; i < 0x10; i++) {
-          outSISIDXREG(SISCR,(0x30 + i),0x00);
-       }
-
-       /* Reset clocks */
-       reg = inSISREG(SISMISCR);
-       outSISIDXREG(SISSR,0x28,0x81);
-       outSISIDXREG(SISSR,0x2A,0x00);
-       outSISIDXREG(SISSR,0x29,0xE1);
-       outSISREG(SISMISCW,(reg | 0x0c));
-       outSISIDXREG(SISSR,0x2B,0x81);
-       outSISIDXREG(SISSR,0x2D,0x00);
-       outSISIDXREG(SISSR,0x2C,0xE1);
-       outSISIDXREG(SISSR,0x2E,0x81);
-       outSISIDXREG(SISSR,0x30,0x00);
-       outSISIDXREG(SISSR,0x2F,0xE1);
-       SiS_DDC2Delay(....);
-       outSISREG(SISMISCW,reg);
-
-       /* Get memory type */
-       if(ivideo->sishw_ext.UseROM) {
-          if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80)) {
-             memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
-          } else {
-             inSISIDXREG(SISSR,0x3a,memtype);
-          }
-          memtype &= 0x03;
-          if( is 330 ) {
-             if(memtype <= 1) memtype = 0;
-             else {
-                inSISIDXREG(SISCR,0x5F,reg);
-                reg &= 0x30;
-                switch(reg) {
-                case 0x00: memtype = 1; break;
-                case 0x10: memtype = 3; break;
-                case 0x20: memtype = 3; break;
-                default:   memtype = 2;
-                }
-             }
-          }
+       for(i = 0, j = 0; i < 7; i++, j += 8) {
+               outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
        }
 
-       /* Set clocks */
-       v1 = 0x3b; v2 = 0x22; v3 = 0x01;  /* Assume 143Mhz MCLK */
-       v4 = 0x5c; v5 = 0x23; v6 = 0x01;  /* Assume 166Mhz ECLK */
-       if(ivideo->sishw_ext.UseROM) {
-          index = memtype * 5;
-          rindex = index + 0x54;
-          v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
-          v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
-          v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
-          rindex = index + 0x68;
-          v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
-          v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
-          v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
-       }
-       outSISIDXREG(SISSR,0x28,v1);
-       outSISIDXREG(SISSR,0x29,v2);
-       outSISIDXREG(SISSR,0x2a,v3);
-       if( is 330 ) {
-          inSISIDXREG(SISSR,0x3a,reg);
-          reg &= 0x03;
-          if(reg >= 2) {
-             ...
-          }
+       outSISIDXREG(SISCR, 0x59, v3);
+
+       ptr  = cs1a8;
+       if(ivideo->haveXGIROM) {
+               ptr  = (const u8 *)&bios[0x1a8];
+       }
+       for(i = 0, j = 0; i < 3; i++, j += 8) {
+               outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
        }
-       outSISIDXREG(SISSR,0x2e,v4);
-       outSISIDXREG(SISSR,0x2f,v5);
-       outSISIDXREG(SISSR,0x30,v6);
-
-       /* End of comp with 330 */
-
-       v1 = 0x18;
-       if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0x7c];
-       outSISIDXREG(SISSR,0x07,v1);
-       outSISIDXREG(SISSR,0x11,0x0f);
-
-       v1 = 0x00; v2 = 0x0f; v3 = 0xba; v4 = 0xa9;
-       v5 = 0xa0; v6 = 0x00; v7 = 0x30;
-       if(ivideo->sishw_ext.UseROM) {
-          index = memtype + 0x7d;
-          v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
-          v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
-          v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
-          v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
-          v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
-          v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
-          v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
-       }
-       outSISIDXREG(SISSR,0x15,v1);       /* Ram type (assuming 0, BIOS 0x7d step 4) */
-       outSISIDXREG(SISSR,0x16,v2);
-       outSISIDXREG(SISSR,0x17,v3);
-       outSISIDXREG(SISSR,0x18,v4);
-       outSISIDXREG(SISSR,0x19,v5);
-       outSISIDXREG(SISSR,0x1a,v6);
-       outSISIDXREG(SISSR,0x1b,v7);
-       outSISIDXREG(SISSR,0x1c,v8);       /* ---- */
-
-       v1 = 0x77; v2 = 0x77; v3 = 0x00; v4 = 0x5b; v5 = 0x00;
-       if(ivideo->sishw_ext.UseROM) {
-          index = memtype + 0xa2;
-          v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
-          v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
-          v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
-          v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
-          v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
-       }
-       outSISIDXREG(SISCR,0x40,v1);
-       outSISIDXREG(SISCR,0x41,v2);
-       outSISIDXREG(SISCR,0x42,v3);
-       outSISIDXREG(SISCR,0x43,v4);
-       outSISIDXREG(SISCR,0x44,v5);
-
-       if( is 330 ) {
-
-          v1 = 0x;
-          if(ivideo->sishw_ext.UseROM) {
-             v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
-          }
-          outSISIDXREG(SISCR,0x59,v1);
-
-          v1 = 0x; v2 = 0x; v3 = 0x; v4 = 0x;
-          v5 = 0x; v6 = 0x; v7 = 0x; v8 = 0x;
-          if(ivideo->sishw_ext.UseROM) {
-             index = memtype + 0xbe;
-             v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
-             v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
-             v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
-             v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
-             v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
-             v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
-             v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
-             v8 = ivideo->sishw_ext.pjVirtualRomBase[index + 28];
-          }
-          outSISIDXREG(SISCR,0x68,v1);
-          outSISIDXREG(SISCR,0x69,v2);
-          outSISIDXREG(SISCR,0x6a,v3);
-          outSISIDXREG(SISCR,0x6b,v4);
-          outSISIDXREG(SISCR,0x6c,v5);
-          outSISIDXREG(SISCR,0x6d,v6);
-          outSISIDXREG(SISCR,0x6e,v7);
-          outSISIDXREG(SISCR,0x6f,v8);
-
-          v1 = 0x20;
-          inSISIDXREG(SISSR,0x3b,reg);
-
-          if(!(reg & 0x04)) {
-             inSISIDXREG(SISCR,0x5F,reg);
-             reg &= 0x30;
-             if(reg) v1 = 0x23;
-          }
-          outSISIDXREG(SISCR,0x48,v1);
-          outSISIDXREG(SISCR,0x4c,0x20);
-
-          xx= xxx();
-          if(xx >= 1) {
-             v1 = 0x;
-             if(ivideo->sishw_ext.UseROM) {
-                v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
-             }
-             outSISIDXREG(SISCR,0x59,v1);
-          }
 
+       ptr  = cs100;
+       if(ivideo->haveXGIROM) {
+               ptr  = (const u8 *)&bios[0x100];
+       }
+       for(i = 0, j = 0; i < 2; i++, j += 8) {
+               outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
+       }
 
+       outSISIDXREG(SISCR, 0xcf, v4);
 
-       } else {
+       outSISIDXREG(SISCR, 0x83, 0x09);
+       outSISIDXREG(SISCR, 0x87, 0x00);
 
-          outSISIDXREG(SISCR,0x48,0x23);
+       if(ivideo->chip == XGI_40) {
+               if( (ivideo->revision_id == 1) ||
+                   (ivideo->revision_id == 2) ) {
+                       outSISIDXREG(SISCR, 0x8c, 0x87);
+               }
+       }
 
-          andSISIDXREG(SISSR,0x16,0x0f);
-          if(memtype <= 1) {
-             orSISIDXREG(SISSR,0x16,0x80);
-          } else {
-             v1 = 0x0f;
-             if(ivideo->sishw_ext.UseROM) {
-                v1 = ivideo->sishw_ext.pjVirtualRomBase[0x81 + memtype];
-             }
-             if(!(v1 & 0x10)) v2 = 0xc0;
-             else             v2 = 0xd0;
-             orSISIDXREG(SISSR,0x16,v2);
-             andSISIDXREG(SISSR,0x16,0x0f);
-             if(!(v1 & 0x10)) v2 = 0x80;
-             else             v2 = 0xA0;
-             orSISIDXREG(SISSR,0x16,v2);
-          }
-
-          if(memtype >= 2) {
-             const u8 sr3cseq1[] = { 0xc0,0xe0,0xf0,0xe0,0xf0,0xa0,0xb0,0xa0,0xb0,0x90,0xd0 };
-             const u8 sr3cseq2[] = { 0xc0,0xa0,0xb0,0xa0,0xb0,0xe0,0xf0,0xa0,0xb0,0x90,0xd0 };
-             for(i = 0; i < 11; i++) {
-                outSISIDXREG(SISSR,0x3c,sr3cseq1[i]);
-             }
-             outSISIDXREG(SISSR,0x3d,0x00);
-             outSISIDXREG(SISSR,0x3d,0x04);
-             SiS_DDC2Delay(0x200);
-             v1 = inSISIDXREG(SISCR,0xEC);
-             v2 = inSISIDXREG(SISCR,0xED);
-             reg1_32 = (v2 << 8) | v1;
-             outSISIDXREG(SISSR,0x3D,0x00);
-             for(i = 0; i < 11; i++) {
-                outSISIDXREG(SISSR,0x3c,sr3cseq2[i]);
-             }
-             outSISIDXREG(SISSR,0x3d,0x00);
-             outSISIDXREG(SISSR,0x3d,0x04);
-             SiS_DDC2Delay(0x200);
-             v1 = inSISIDXREG(SISCR,0xEC);
-             v2 = inSISIDXREG(SISCR,0xED);
-             reg2_32 = (v2 << 8) | v1;
-             outSISIDXREG(SISSR,0x3D,0x00);
-             reg3_32 = reg2_32 << 1;
-             reg2_32 >>= 1;
-             reg3_32 += reg2_32;
-             v1 = 0x40;
-             if(reg3_32 > reg1_32) v1 = 0x10;
-                outSISIDXREG(SISCR,0x59,v1);
-          }
+       outSISIDXREG(SISSR, 0x17, 0x00);
+       outSISIDXREG(SISSR, 0x1a, 0x87);
 
+       if(ivideo->chip == XGI_20) {
+               outSISIDXREG(SISSR, 0x15, 0x00);
+               outSISIDXREG(SISSR, 0x1c, 0x00);
        }
 
-       v1 = 0x00;
-       if(ivideo->sishw_ext.UseROM) {
-          v1 = ivideo->sishw_ext.pjVirtualRomBase[0x99];
+       ramtype = 0x00; v1 = 0x10;
+       if(ivideo->haveXGIROM) {
+               ramtype = bios[0x62];
+               v1 = bios[0x1d2];
+       }
+       if(!(ramtype & 0x80)) {
+               if(ivideo->chip == XGI_20) {
+                       outSISIDXREG(SISCR, 0x97, v1);
+                       inSISIDXREG(SISCR, 0x97, reg);
+                       if(reg & 0x10) {
+                               ramtype = (reg & 0x01) << 1;
+                       }
+               } else {
+                       inSISIDXREG(SISSR, 0x39, reg);
+                       ramtype = reg & 0x02;
+                       if(!(ramtype)) {
+                               inSISIDXREG(SISSR, 0x3a, reg);
+                               ramtype = (reg >> 1) & 0x01;
+                       }
+               }
        }
-       outSISIDXREG(SISSR,0x1f,v1);
+       ramtype &= 0x07;
+
+       regb = 0;       /* ! */
+
+       switch(ramtype) {
+       case 0:
+               sisfb_post_xgi_setclocks(ivideo, regb);
+               if((ivideo->chip == XGI_20) ||
+                  (ivideo->revision_id == 1)   ||
+                  (ivideo->revision_id == 2)) {
+                       v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
+                       if(ivideo->haveXGIROM) {
+                               v1 = bios[regb + 0x158];
+                               v2 = bios[regb + 0x160];
+                               v3 = bios[regb + 0x168];
+                       }
+                       outSISIDXREG(SISCR, 0x82, v1);
+                       outSISIDXREG(SISCR, 0x85, v2);
+                       outSISIDXREG(SISCR, 0x86, v3);
+               } else {
+                       outSISIDXREG(SISCR, 0x82, 0x88);
+                       outSISIDXREG(SISCR, 0x86, 0x00);
+                       inSISIDXREG(SISCR, 0x86, reg);
+                       outSISIDXREG(SISCR, 0x86, 0x88);
+                       inSISIDXREG(SISCR, 0x86, reg);
+                       outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
+                       outSISIDXREG(SISCR, 0x82, 0x77);
+                       outSISIDXREG(SISCR, 0x85, 0x00);
+                       inSISIDXREG(SISCR, 0x85, reg);
+                       outSISIDXREG(SISCR, 0x85, 0x88);
+                       inSISIDXREG(SISCR, 0x85, reg);
+                       outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
+                       outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
+               }
+               if(ivideo->chip == XGI_40) {
+                       outSISIDXREG(SISCR, 0x97, 0x00);
+               }
+               outSISIDXREG(SISCR, 0x98, 0x01);
+               outSISIDXREG(SISCR, 0x9a, 0x02);
 
-       outSISIDXREG(SISSR,0x20,0x20);
+               outSISIDXREG(SISSR, 0x18, 0x01);
+               if((ivideo->chip == XGI_20) ||
+                  (ivideo->revision_id == 2)) {
+                       outSISIDXREG(SISSR, 0x19, 0x40);
+               } else {
+                       outSISIDXREG(SISSR, 0x19, 0x20);
+               }
+               outSISIDXREG(SISSR, 0x16, 0x00);
+               outSISIDXREG(SISSR, 0x16, 0x80);
+               if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
+                       sisfb_post_xgi_delay(ivideo, 0x43);
+                       sisfb_post_xgi_delay(ivideo, 0x43);
+                       sisfb_post_xgi_delay(ivideo, 0x43);
+                       outSISIDXREG(SISSR, 0x18, 0x00);
+                       if((ivideo->chip == XGI_20) ||
+                          (ivideo->revision_id == 2)) {
+                               outSISIDXREG(SISSR, 0x19, 0x40);
+                       } else {
+                               outSISIDXREG(SISSR, 0x19, 0x20);
+                       }
+               } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
+                       /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
+               }
+               outSISIDXREG(SISSR, 0x16, 0x00);
+               outSISIDXREG(SISSR, 0x16, 0x80);
+               sisfb_post_xgi_delay(ivideo, 4);
+               v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
+               if(ivideo->haveXGIROM) {
+                       v1 = bios[0xf0];
+                       index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
+                       v2 = bios[index];
+                       v3 = bios[index + 1];
+                       v4 = bios[index + 2];
+                       v5 = bios[index + 3];
+               }
+               outSISIDXREG(SISSR, 0x18, v1);
+               outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
+               outSISIDXREG(SISSR, 0x16, v2);
+               outSISIDXREG(SISSR, 0x16, v3);
+               sisfb_post_xgi_delay(ivideo, 0x43);
+               outSISIDXREG(SISSR, 0x1b, 0x03);
+               sisfb_post_xgi_delay(ivideo, 0x22);
+               outSISIDXREG(SISSR, 0x18, v1);
+               outSISIDXREG(SISSR, 0x19, 0x00);
+               outSISIDXREG(SISSR, 0x16, v4);
+               outSISIDXREG(SISSR, 0x16, v5);
+               outSISIDXREG(SISSR, 0x1b, 0x00);
+               break;
+       case 1:
+               outSISIDXREG(SISCR, 0x82, 0x77);
+               outSISIDXREG(SISCR, 0x86, 0x00);
+               inSISIDXREG(SISCR, 0x86, reg);
+               outSISIDXREG(SISCR, 0x86, 0x88);
+               inSISIDXREG(SISCR, 0x86, reg);
+               v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
+               if(ivideo->haveXGIROM) {
+                       v1 = bios[regb + 0x168];
+                       v2 = bios[regb + 0x160];
+                       v3 = bios[regb + 0x158];
+               }
+               outSISIDXREG(SISCR, 0x86, v1);
+               outSISIDXREG(SISCR, 0x82, 0x77);
+               outSISIDXREG(SISCR, 0x85, 0x00);
+               inSISIDXREG(SISCR, 0x85, reg);
+               outSISIDXREG(SISCR, 0x85, 0x88);
+               inSISIDXREG(SISCR, 0x85, reg);
+               outSISIDXREG(SISCR, 0x85, v2);
+               outSISIDXREG(SISCR, 0x82, v3);
+               outSISIDXREG(SISCR, 0x98, 0x01);
+               outSISIDXREG(SISCR, 0x9a, 0x02);
+
+               outSISIDXREG(SISSR, 0x28, 0x64);
+               outSISIDXREG(SISSR, 0x29, 0x63);
+               sisfb_post_xgi_delay(ivideo, 15);
+               outSISIDXREG(SISSR, 0x18, 0x00);
+               outSISIDXREG(SISSR, 0x19, 0x20);
+               outSISIDXREG(SISSR, 0x16, 0x00);
+               outSISIDXREG(SISSR, 0x16, 0x80);
+               outSISIDXREG(SISSR, 0x18, 0xc5);
+               outSISIDXREG(SISSR, 0x19, 0x23);
+               outSISIDXREG(SISSR, 0x16, 0x00);
+               outSISIDXREG(SISSR, 0x16, 0x80);
+               sisfb_post_xgi_delay(ivideo, 1);
+               outSISIDXREG(SISCR, 0x97,0x11);
+               sisfb_post_xgi_setclocks(ivideo, regb);
+               sisfb_post_xgi_delay(ivideo, 0x46);
+               outSISIDXREG(SISSR, 0x18, 0xc5);
+               outSISIDXREG(SISSR, 0x19, 0x23);
+               outSISIDXREG(SISSR, 0x16, 0x00);
+               outSISIDXREG(SISSR, 0x16, 0x80);
+               sisfb_post_xgi_delay(ivideo, 1);
+               outSISIDXREG(SISSR, 0x1b, 0x04);
+               sisfb_post_xgi_delay(ivideo, 1);
+               outSISIDXREG(SISSR, 0x1b, 0x00);
+               sisfb_post_xgi_delay(ivideo, 1);
+               v1 = 0x31;
+               if(ivideo->haveXGIROM) {
+                       v1 = bios[0xf0];
+               }
+               outSISIDXREG(SISSR, 0x18, v1);
+               outSISIDXREG(SISSR, 0x19, 0x06);
+               outSISIDXREG(SISSR, 0x16, 0x04);
+               outSISIDXREG(SISSR, 0x16, 0x84);
+               sisfb_post_xgi_delay(ivideo, 1);
+               break;
+       default:
+               sisfb_post_xgi_setclocks(ivideo, regb);
+               if((ivideo->chip == XGI_40) &&
+                  ((ivideo->revision_id == 1) ||
+                   (ivideo->revision_id == 2))) {
+                       outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
+                       outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
+                       outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
+               } else {
+                       outSISIDXREG(SISCR, 0x82, 0x88);
+                       outSISIDXREG(SISCR, 0x86, 0x00);
+                       inSISIDXREG(SISCR, 0x86, reg);
+                       outSISIDXREG(SISCR, 0x86, 0x88);
+                       outSISIDXREG(SISCR, 0x82, 0x77);
+                       outSISIDXREG(SISCR, 0x85, 0x00);
+                       inSISIDXREG(SISCR, 0x85, reg);
+                       outSISIDXREG(SISCR, 0x85, 0x88);
+                       inSISIDXREG(SISCR, 0x85, reg);
+                       v1 = cs160[regb]; v2 = cs158[regb];
+                       if(ivideo->haveXGIROM) {
+                               v1 = bios[regb + 0x160];
+                               v2 = bios[regb + 0x158];
+                       }
+                       outSISIDXREG(SISCR, 0x85, v1);
+                       outSISIDXREG(SISCR, 0x82, v2);
+               }
+               if(ivideo->chip == XGI_40) {
+                       outSISIDXREG(SISCR, 0x97, 0x11);
+               }
+               if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
+                       outSISIDXREG(SISCR, 0x98, 0x01);
+               } else {
+                       outSISIDXREG(SISCR, 0x98, 0x03);
+               }
+               outSISIDXREG(SISCR, 0x9a, 0x02);
 
-       v1 = 0xf6; v2 = 0x0d; v3 = 0x33;
-       if(ivideo->sishw_ext.UseROM) {
-          v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9c];
-          v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9d];
-          v3 = ivideo->sishw_ext.pjVirtualRomBase[0x9e];
+               if(ivideo->chip == XGI_40) {
+                       outSISIDXREG(SISSR, 0x18, 0x01);
+               } else {
+                       outSISIDXREG(SISSR, 0x18, 0x00);
+               }
+               outSISIDXREG(SISSR, 0x19, 0x40);
+               outSISIDXREG(SISSR, 0x16, 0x00);
+               outSISIDXREG(SISSR, 0x16, 0x80);
+               if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
+                       sisfb_post_xgi_delay(ivideo, 0x43);
+                       sisfb_post_xgi_delay(ivideo, 0x43);
+                       sisfb_post_xgi_delay(ivideo, 0x43);
+                       outSISIDXREG(SISSR, 0x18, 0x00);
+                       outSISIDXREG(SISSR, 0x19, 0x40);
+                       outSISIDXREG(SISSR, 0x16, 0x00);
+                       outSISIDXREG(SISSR, 0x16, 0x80);
+               }
+               sisfb_post_xgi_delay(ivideo, 4);
+               v1 = 0x31;
+               if(ivideo->haveXGIROM) {
+                       v1 = bios[0xf0];
+               }
+               outSISIDXREG(SISSR, 0x18, v1);
+               outSISIDXREG(SISSR, 0x19, 0x01);
+               if(ivideo->chip == XGI_40) {
+                       outSISIDXREG(SISSR, 0x16, bios[0x53e]);
+                       outSISIDXREG(SISSR, 0x16, bios[0x53f]);
+               } else {
+                       outSISIDXREG(SISSR, 0x16, 0x05);
+                       outSISIDXREG(SISSR, 0x16, 0x85);
+               }
+               sisfb_post_xgi_delay(ivideo, 0x43);
+               if(ivideo->chip == XGI_40) {
+                       outSISIDXREG(SISSR, 0x1b, 0x01);
+               } else {
+                       outSISIDXREG(SISSR, 0x1b, 0x03);
+               }
+               sisfb_post_xgi_delay(ivideo, 0x22);
+               outSISIDXREG(SISSR, 0x18, v1);
+               outSISIDXREG(SISSR, 0x19, 0x00);
+               if(ivideo->chip == XGI_40) {
+                       outSISIDXREG(SISSR, 0x16, bios[0x540]);
+                       outSISIDXREG(SISSR, 0x16, bios[0x541]);
+               } else {
+                       outSISIDXREG(SISSR, 0x16, 0x05);
+                       outSISIDXREG(SISSR, 0x16, 0x85);
+               }
+               outSISIDXREG(SISSR, 0x1b, 0x00);
        }
-       outSISIDXREG(SISSR,0x23,v1);
-       outSISIDXREG(SISSR,0x24,v2);
-       outSISIDXREG(SISSR,0x25,v3);
 
-       outSISIDXREG(SISSR,0x21,0x84);
-       outSISIDXREG(SISSR,0x22,0x00);
-       outSISIDXREG(SISSR,0x27,0x1f);
-
-       v1 = 0x00; v2 = 0x00;
-       if(ivideo->sishw_ext.UseROM) {
-          v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9F];
-          v2 = ivideo->sishw_ext.pjVirtualRomBase[0xA1];
-       }
-       outSISIDXREG(SISSR,0x31,v1);
-       outSISIDXREG(SISSR,0x33,v2);
-
-       v1 = 0x11;
-       if(ivideo->sishw_ext.UseROM) {
-          v1 = ivideo->sishw_ext.pjVirtualRomBase[0xA0];
-       }
-       v2 = inSISIDXREG(SISPART4,0x00);
-       if((v2 != 1) && (v2 != 2)) v1 &= 0xef;
-       outSISIDXREG(SISSR,0x32,v1);
-
-       /* AGP */
-       pci_read_config_long(pdev, 0x50, &reg1_32);
-       reg1_32 >>= 20;
-       reg1_32 &= 0x0f;
-       if(reg1_32 == 1) {
-          v1 = 0xAA; v2 = 0x33;
-          if(ivideo->sishw_ext.UseROM) {
-             v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF7];
-             v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9E];
-          }
-       } else {
-          v1 = 0x88; v2 = 0x03;
-          if(ivideo->sishw_ext.UseROM) {
-             v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF8];
-             v2 = ivideo->sishw_ext.pjVirtualRomBase[0xF6];
-          }
+       regb = 0;       /* ! */
+       v1 = 0x03;
+       if(ivideo->haveXGIROM) {
+               v1 = bios[0x110 + regb];
        }
-       outSISIDXREG(SISCR,0x49,v1);
-       outSISIDXREG(SISSR,0x25,v2);
+       outSISIDXREG(SISSR, 0x1b, v1);
 
-       v1 = inSISIDXREG(SISPART4,0x00);
-       if((v1 == 1) || (v1 == 2)) {
-          orSISIDXREG(SISPART1,0x2F,0x01);  /* Unlock CRT2 */
-          outSISIDXREG(SISPART1,0x00,0x00);
-          v1 = 0x00;
-          if(ivideo->sishw_ext.UseROM) {
-             v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb6];
-          }
-          outSISIDXREG(SISPART1,0x02,v1);
-          outSISIDXREG(SISPART1,0x2E,0x08);
-          outSISIDXREG(SISPART2,0x00,0x1c);
-          v1 = 0x40; v2 = 0x00; v3 = 0x80;
-          if(ivideo->sishw_ext.UseROM) {
-             v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb7];
-             v2 = ivideo->sishw_ext.pjVirtualRomBase[0xb8];
-             v3 = ivideo->sishw_ext.pjVirtualRomBase[0xbb];
-          }
-          outSISIDXREG(SISPART4,0x0d,v1);
-          outSISIDXREG(SISPART4,0x0e,v2);
-          outSISIDXREG(SISPART4,0x10,v3);
-          outSISIDXREG(SISPART4,0x0F,0x3F);
-
-          inSISIDXREG(SISPART4,0x01,reg);
-          if(reg >= 0xb0) {
-             inSISIDXREG(SISPART4,0x23,reg);
-             reg &= 0x20;
-             reg <<= 1;
-             outSISIDXREG(SISPART4,0x23,reg);
-          }
+       /* RAM size */
+       v1 = 0x00; v2 = 0x00;
+       if(ivideo->haveXGIROM) {
+               v1 = bios[0x62];
+               v2 = bios[0x63];
        }
-       outSISIDXREG(SISCR,0x37,0x02); /* Why? */
-
-       outSISIDXREG(SISCR,0x83,0x00);
-       outSISIDXREG(SISCR,0x90,0x00);
-       andSISIDXREG(SISSR,0x5B,0xDF);
-       outSISIDXREG(SISVID,0x00,0x86);
-       outSISIDXREG(SISVID,0x32,0x00);
-       outSISIDXREG(SISVID,0x30,0x00);
-       outSISIDXREG(SISVID,0x32,0x01);
-       outSISIDXREG(SISVID,0x30,0x00);
-       orSISIDXREG(SISCR,0x63,0x80);
-       /* End of Init1 */
-
-       /* Set Mode 0x2e */
-
-       /* Ramsize */
-       orSISIDXREG(SISSR,0x16,0x0f);
-       orSISIDXREG(SISSR,0x18,0xA9);
-       orSISIDXREG(SISSR,0x19,0xA0);
-       orSISIDXREG(SISSR,0x1B,0x30);
-       andSISIDXREG(SISSR,0x17,0xF8);
-       orSISIDXREG(SISSR,0x19,0x03);
-       andSIDIDXREG(SISSR,0x13,0x00);
+       regb = 0;       /* ! */
+       regd = 1 << regb;
+       if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
 
-       /* Need to map max FB size for finding out about RAM size */
-       ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000);
-       if(ivideo->video_vbase) {
-          /* Find out about bus width */
-          if(memtype <= 1) {
-             outSISIDXREG(SISSR,0x14,0x02);
-             andSISIDXREG(SISSR,0x16,0x0F);
-             orSISIDXREG(SISSR,0x16,0x80);
+               outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
+               outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
 
-             ...
+       } else {
 
-          } else {
+               /* Set default mode, don't clear screen */
+               ivideo->SiS_Pr.SiS_UseOEM = FALSE;
+               SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
+               SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
+               ivideo->curFSTN = ivideo->curDSTN = 0;
+               ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
+               SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
 
-             ...
+               outSISIDXREG(SISSR, 0x05, 0x86);
 
-          }
+               /* Disable read-cache */
+               andSISIDXREG(SISSR, 0x21, 0xdf);
+               sisfb_post_xgi_ramsize(ivideo);
+               /* Enable read-cache */
+               orSISIDXREG(SISSR, 0x21, 0x20);
 
-          /* Find out about size */
+       }
 
+#if 0
+       printk(KERN_DEBUG "-----------------\n");
+       for(i = 0; i < 0xff; i++) {
+               inSISIDXREG(SISCR, i, reg);
+               printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
+       }
+       for(i = 0; i < 0x40; i++) {
+               inSISIDXREG(SISSR, i, reg);
+               printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
+       }
+       printk(KERN_DEBUG "-----------------\n");
+#endif
 
-          iounmap(ivideo->video_vbase);
+       /* Sense CRT1 */
+       if(ivideo->chip == XGI_20) {
+               orSISIDXREG(SISCR, 0x32, 0x20);
        } else {
-          printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
-          outSISIDXREG(SISSR,0x14,0x??);  /* 8MB, 64bit default */
+               inSISIDXREG(SISPART4, 0x00, reg);
+               if((reg == 1) || (reg == 2)) {
+                       sisfb_sense_crt1(ivideo);
+               } else {
+                       orSISIDXREG(SISCR, 0x32, 0x20);
+               }
        }
 
-       /* AGP (Missing: Checks for VIA and AMD hosts) */
-       v1 = 0xA5; v2 = 0xFB;
-       if(ivideo->sishw_ext.UseROM) {
-          v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9A];
-          v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9B];
+       /* Set default mode, don't clear screen */
+       ivideo->SiS_Pr.SiS_UseOEM = FALSE;
+       SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
+       SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
+       ivideo->curFSTN = ivideo->curDSTN = 0;
+       SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
+
+       outSISIDXREG(SISSR, 0x05, 0x86);
+
+       /* Display off */
+       orSISIDXREG(SISSR, 0x01, 0x20);
+
+       /* Save mode number in CR34 */
+       outSISIDXREG(SISCR, 0x34, 0x2e);
+
+       /* Let everyone know what the current mode is */
+       ivideo->modeprechange = 0x2e;
+
+       if(ivideo->chip == XGI_40) {
+               inSISIDXREG(SISCR, 0xca, reg);
+               inSISIDXREG(SISCR, 0xcc, v1);
+               if((reg & 0x10) && (!(v1 & 0x04))) {
+                       printk(KERN_ERR
+                               "sisfb: Please connect power to the card.\n");
+                       return 0;
+               }
        }
-       outSISIDXREG(SISSR,0x21,v1);
-       outSISIDXREG(SISSR,0x22,v2);
 
-#endif
-       return;
+       return 1;
 }
 #endif
 
-
-static int __devinit sisfb_probe(struct pci_dev *pdev,
-                                const struct pci_device_id *ent)
+static int __devinit
+sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       struct sisfb_chip_info  *chipinfo = &sisfb_chip_info[ent->driver_data];
-       struct sis_video_info   *ivideo = NULL;
-       struct fb_info          *sis_fb_info = NULL;
+       struct sisfb_chip_info  *chipinfo = &sisfb_chip_info[ent->driver_data];
+       struct sis_video_info   *ivideo = NULL;
+       struct fb_info          *sis_fb_info = NULL;
        u16 reg16;
        u8  reg;
-       int sisvga_enabled = 0, i;
+       int i, ret;
 
-       if(sisfb_off) return -ENXIO;
+       if(sisfb_off)
+               return -ENXIO;
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
        sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
-       if(!sis_fb_info) return -ENOMEM;
+       if(!sis_fb_info)
+               return -ENOMEM;
 #else
        sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
-       if(!sis_fb_info) return -ENOMEM;
+       if(!sis_fb_info)
+               return -ENOMEM;
        memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
        sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
 #endif
@@ -4787,27 +5880,34 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
        ivideo = (struct sis_video_info *)sis_fb_info->par;
        ivideo->memyselfandi = sis_fb_info;
 
+       ivideo->sisfb_id = SISFB_ID;
+
        if(card_list == NULL) {
-          ivideo->cardnumber = 0;
+               ivideo->cardnumber = 0;
        } else {
-          struct sis_video_info *countvideo = card_list;
-          ivideo->cardnumber = 1;
-          while((countvideo = countvideo->next) != NULL) ivideo->cardnumber++;
+               struct sis_video_info *countvideo = card_list;
+               ivideo->cardnumber = 1;
+               while((countvideo = countvideo->next) != 0)
+                       ivideo->cardnumber++;
        }
 
        strncpy(ivideo->myid, chipinfo->chip_name, 30);
 
        ivideo->warncount = 0;
        ivideo->chip_id = pdev->device;
+       ivideo->chip_vendor = pdev->vendor;
        pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
-       ivideo->sishw_ext.jChipRevision = ivideo->revision_id;
+       ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
        pci_read_config_word(pdev, PCI_COMMAND, &reg16);
-       sisvga_enabled = reg16 & 0x01;
+       ivideo->sisvga_enabled = reg16 & 0x01;
        ivideo->pcibus = pdev->bus->number;
        ivideo->pcislot = PCI_SLOT(pdev->devfn);
        ivideo->pcifunc = PCI_FUNC(pdev->devfn);
        ivideo->subsysvendor = pdev->subsystem_vendor;
        ivideo->subsysdevice = pdev->subsystem_device;
+#ifdef SIS_OLD_CONFIG_COMPAT
+       ivideo->ioctl32registered = 0;
+#endif
 
 #ifndef MODULE
        if(sisfb_mode_idx == -1) {
@@ -4827,6 +5927,24 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
 
        ivideo->sisfb_thismonitor.datavalid = FALSE;
 
+       ivideo->current_base = 0;
+
+       ivideo->engineok = 0;
+
+       ivideo->sisfb_was_boot_device = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
+       if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
+               if(ivideo->sisvga_enabled)
+                       ivideo->sisfb_was_boot_device = 1;
+               else {
+                       printk(KERN_DEBUG "sisfb: PCI device is disabled, "
+                               "but marked as boot video device ???\n");
+                       printk(KERN_DEBUG "sisfb: I will not accept this "
+                               "as the primary VGA device\n");
+               }
+       }
+#endif
+
        ivideo->sisfb_parm_mem = sisfb_parm_mem;
        ivideo->sisfb_accel = sisfb_accel;
        ivideo->sisfb_ypan = sisfb_ypan;
@@ -4846,7 +5964,6 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
        ivideo->sisfb_tvstd = sisfb_tvstd;
        ivideo->tvxpos = sisfb_tvxposoffset;
        ivideo->tvypos = sisfb_tvyposoffset;
-       ivideo->sisfb_filter = sisfb_filter;
        ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
        ivideo->sisfb_inverse = sisfb_inverse;
@@ -4854,7 +5971,7 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
 
        ivideo->refresh_rate = 0;
        if(ivideo->sisfb_parm_rate != -1) {
-          ivideo->refresh_rate = ivideo->sisfb_parm_rate;
+               ivideo->refresh_rate = ivideo->sisfb_parm_rate;
        }
 
        ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
@@ -4863,8 +5980,8 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
        ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
 
        ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
-        ivideo->SiS_Pr.SiS_CHOverScan = -1;
-        ivideo->SiS_Pr.SiS_ChSW = FALSE;
+       ivideo->SiS_Pr.SiS_CHOverScan = -1;
+       ivideo->SiS_Pr.SiS_ChSW = FALSE;
        ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
        ivideo->SiS_Pr.HaveEMI = FALSE;
        ivideo->SiS_Pr.HaveEMILCD = FALSE;
@@ -4873,12 +5990,13 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
        ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
        ivideo->SiS_Pr.PDC  = -1;
        ivideo->SiS_Pr.PDCA = -1;
+       ivideo->SiS_Pr.DDCPortMixup = FALSE;
 #ifdef CONFIG_FB_SIS_315
        if(ivideo->chip >= SIS_330) {
-          ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
-          if(ivideo->chip >= SIS_661) {
-             ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
-          }
+               ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
+               if(ivideo->chip >= SIS_661) {
+                       ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
+               }
        }
 #endif
 
@@ -4891,9 +6009,9 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
                switch(ivideo->nbridge->device) {
 #ifdef CONFIG_FB_SIS_300
                case PCI_DEVICE_ID_SI_730:
-                       ivideo->chip = SIS_730;
+                       ivideo->chip = SIS_730;
                        strcpy(ivideo->myid, "SiS 730");
-                       break;
+                       break;
 #endif
 #ifdef CONFIG_FB_SIS_315
                case PCI_DEVICE_ID_SI_651:
@@ -4901,22 +6019,28 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
                        strcpy(ivideo->myid, "SiS 651");
                        break;
                case PCI_DEVICE_ID_SI_740:
-                       ivideo->chip = SIS_740;
+                       ivideo->chip = SIS_740;
                        strcpy(ivideo->myid, "SiS 740");
                        break;
                case PCI_DEVICE_ID_SI_661:
-                       ivideo->chip = SIS_661;
+                       ivideo->chip = SIS_661;
                        strcpy(ivideo->myid, "SiS 661");
                        break;
                case PCI_DEVICE_ID_SI_741:
-                       ivideo->chip = SIS_741;
+                       ivideo->chip = SIS_741;
                        strcpy(ivideo->myid, "SiS 741");
                        break;
                case PCI_DEVICE_ID_SI_760:
-                       ivideo->chip = SIS_760;
+                       ivideo->chip = SIS_760;
                        strcpy(ivideo->myid, "SiS 760");
                        break;
+               case PCI_DEVICE_ID_SI_761:
+                       ivideo->chip = SIS_761;
+                       strcpy(ivideo->myid, "SiS 761");
+                       break;
 #endif
+               default:
+                       break;
                }
        }
 
@@ -4924,71 +6048,83 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
        strcpy(sis_fb_info->modename, ivideo->myid);
 #endif
 
-       ivideo->sishw_ext.jChipType = ivideo->chip;
+       ivideo->SiS_Pr.ChipType = ivideo->chip;
+
+       ivideo->SiS_Pr.ivideo = (void *)ivideo;
 
 #ifdef CONFIG_FB_SIS_315
-       if((ivideo->sishw_ext.jChipType == SIS_315PRO) ||
-          (ivideo->sishw_ext.jChipType == SIS_315)) {
-               ivideo->sishw_ext.jChipType = SIS_315H;
+       if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
+          (ivideo->SiS_Pr.ChipType == SIS_315)) {
+               ivideo->SiS_Pr.ChipType = SIS_315H;
        }
 #endif
 
+       if(!ivideo->sisvga_enabled) {
+               if(pci_enable_device(pdev)) {
+                       if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
+                       pci_set_drvdata(pdev, NULL);
+                       kfree(sis_fb_info);
+                       return -EIO;
+               }
+       }
+
        ivideo->video_base = pci_resource_start(pdev, 0);
        ivideo->mmio_base  = pci_resource_start(pdev, 1);
        ivideo->mmio_size  = pci_resource_len(pdev, 1);
-       ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
-       ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
-
-       if(!sisvga_enabled) {
-               if(pci_enable_device(pdev)) {
-                       pci_set_drvdata(pdev, NULL);
-                       kfree(sis_fb_info);
-                       return -EIO;
-               }
-       }
+       ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
+       ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
 
-       SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress);
+       SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
 
 #ifdef CONFIG_FB_SIS_300
        /* Find PCI systems for Chrontel/GPIO communication setup */
        if(ivideo->chip == SIS_630) {
-          i=0;
-           do {
-             if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
-                mychswtable[i].subsysCard   == ivideo->subsysdevice) {
-                ivideo->SiS_Pr.SiS_ChSW = TRUE;
-                printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
-                       mychswtable[i].vendorName, mychswtable[i].cardName);
-                break;
-              }
-              i++;
-           } while(mychswtable[i].subsysVendor != 0);
+               i = 0;
+               do {
+                       if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
+                          mychswtable[i].subsysCard   == ivideo->subsysdevice) {
+                               ivideo->SiS_Pr.SiS_ChSW = TRUE;
+                               printk(KERN_DEBUG "sisfb: Identified [%s %s] "
+                                       "requiring Chrontel/GPIO setup\n",
+                                       mychswtable[i].vendorName,
+                                       mychswtable[i].cardName);
+                               ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
+                               break;
+                       }
+                       i++;
+               } while(mychswtable[i].subsysVendor != 0);
+       }
+#endif
+
+#ifdef CONFIG_FB_SIS_315
+       if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
+               ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
        }
 #endif
 
-        outSISIDXREG(SISSR, 0x05, 0x86);
+       outSISIDXREG(SISSR, 0x05, 0x86);
 
-       if( (!sisvga_enabled)
+       if( (!ivideo->sisvga_enabled)
 #if !defined(__i386__) && !defined(__x86_64__)
-                             || (sisfb_resetcard)
+                             || (sisfb_resetcard)
 #endif
-                                                  ) {
-               for(i = 0x30; i <= 0x3f; i++) {
-                       outSISIDXREG(SISCR,i,0x00);
-               }
+                                                  ) {
+               for(i = 0x30; i <= 0x3f; i++) {
+                       outSISIDXREG(SISCR, i, 0x00);
+               }
        }
 
        /* Find out about current video mode */
        ivideo->modeprechange = 0x03;
-       inSISIDXREG(SISCR,0x34,reg);
+       inSISIDXREG(SISCR, 0x34, reg);
        if(reg & 0x7f) {
                ivideo->modeprechange = reg & 0x7f;
-       } else if(sisvga_enabled) {
+       } else if(ivideo->sisvga_enabled) {
 #if defined(__i386__) || defined(__x86_64__)
-               unsigned char SIS_IOTYPE2 *tt = ioremap(0, 0x1000);
+               unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
                if(tt) {
-                       ivideo->modeprechange = readb(tt + 0x449);
-                       iounmap(tt);
+                       ivideo->modeprechange = readb(tt + 0x49);
+                       iounmap(tt);
                }
 #endif
        }
@@ -4996,219 +6132,221 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 #ifdef MODULE
        if((reg & 0x80) && (reg != 0xff)) {
-          if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) {
-             printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
-             pci_set_drvdata(pdev, NULL);
-             kfree(sis_fb_info);
-             return -EBUSY;
-          }
+               if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
+                                                                       != 0xFF) {
+                       printk(KERN_INFO "sisfb: Cannot initialize display mode, "
+                                        "X server is active\n");
+                       ret = -EBUSY;
+                       goto error_4;
+               }
        }
-#endif 
 #endif
-
-       ivideo->sishw_ext.bIntegratedMMEnabled = TRUE;
-#ifdef CONFIG_FB_SIS_300
-       if(ivideo->sisvga_engine == SIS_300_VGA) {
-          if(ivideo->chip != SIS_300) {
-             inSISIDXREG(SISSR, 0x1a, reg);
-             if(!(reg & 0x10)) {
-                ivideo->sishw_ext.bIntegratedMMEnabled = FALSE;
-             }
-          }
-       }
 #endif
 
+       /* Search and copy ROM image */
        ivideo->bios_abase = NULL;
+       ivideo->SiS_Pr.VirtualRomBase = NULL;
+       ivideo->SiS_Pr.UseROM = FALSE;
+       ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
        if(ivideo->sisfb_userom) {
-           ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
-           ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase;
-           if(ivideo->sishw_ext.pjVirtualRomBase) {
-               printk(KERN_INFO "sisfb: Video ROM found and copied\n");
-               ivideo->sishw_ext.UseROM = TRUE;
-           } else {
-               ivideo->sishw_ext.UseROM = FALSE;
-               printk(KERN_INFO "sisfb: Video ROM not found\n");
-           }
+               ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
+               ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
+               ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
+               printk(KERN_INFO "sisfb: Video ROM %sfound\n",
+                       ivideo->SiS_Pr.UseROM ? "" : "not ");
+               if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
+                  ivideo->SiS_Pr.UseROM = FALSE;
+                  ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
+                  if( (ivideo->revision_id == 2) &&
+                      (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
+                       ivideo->SiS_Pr.DDCPortMixup = TRUE;
+                  }
+               }
        } else {
-           ivideo->sishw_ext.pjVirtualRomBase = NULL;
-           ivideo->sishw_ext.UseROM = FALSE;
-           printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
+               printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
        }
 
-        /* Find systems for special custom timing */
+       /* Find systems for special custom timing */
        if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
-          int j;
-          unsigned char *biosver = NULL;
-           unsigned char *biosdate = NULL;
-          BOOLEAN footprint;
-          u32 chksum = 0;
-
-          if(ivideo->sishw_ext.UseROM) {
-             biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
-             biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
-              for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
-          }
-
-          i=0;
-           do {
-             if( (mycustomttable[i].chipID == ivideo->chip) &&
-                 ((!strlen(mycustomttable[i].biosversion)) ||
-                  (ivideo->sishw_ext.UseROM &&
-                  (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
-                 ((!strlen(mycustomttable[i].biosdate)) ||
-                  (ivideo->sishw_ext.UseROM &&
-                  (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
-                 ((!mycustomttable[i].bioschksum) ||
-                  (ivideo->sishw_ext.UseROM &&
-                  (mycustomttable[i].bioschksum == chksum)))   &&
-                 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
-                 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
-                footprint = TRUE;
-                for(j = 0; j < 5; j++) {
-                   if(mycustomttable[i].biosFootprintAddr[j]) {
-                      if(ivideo->sishw_ext.UseROM) {
-                         if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
-                               mycustomttable[i].biosFootprintData[j]) {
-                            footprint = FALSE;
-                         }
-                      } else footprint = FALSE;
-                   }
-                }
-                if(footprint) {
-                   ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
-                   printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
-                       mycustomttable[i].vendorName,
-                       mycustomttable[i].cardName);
-                   printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
-                       mycustomttable[i].optionName);
-                   break;
-                 }
-             }
-              i++;
-           } while(mycustomttable[i].chipID);
+               sisfb_detect_custom_timing(ivideo);
        }
 
-#ifdef CONFIG_FB_SIS_300
-       if(ivideo->sisvga_engine == SIS_300_VGA) {
-               if( (!sisvga_enabled)
+       /* POST card in case this has not been done by the BIOS */
+       if( (!ivideo->sisvga_enabled)
 #if !defined(__i386__) && !defined(__x86_64__)
-                                     || (sisfb_resetcard)
+                            || (sisfb_resetcard)
 #endif
-                                                          ) {
+                                                ) {
+#ifdef CONFIG_FB_SIS_300
+               if(ivideo->sisvga_engine == SIS_300_VGA) {
                        if(ivideo->chip == SIS_300) {
                                sisfb_post_sis300(pdev);
+                               ivideo->sisfb_can_post = 1;
                        }
                }
-       }
 #endif
 
 #ifdef CONFIG_FB_SIS_315
-       if(ivideo->sisvga_engine == SIS_315_VGA) {
-               if( (!sisvga_enabled)
-#if !defined(__i386__) && !defined(__x86_64__)
-                                    || (sisfb_resetcard)
-#endif
-                                                         ) {
-                       if((ivideo->chip == SIS_315H)   ||
+               if(ivideo->sisvga_engine == SIS_315_VGA) {
+                       int result = 1;
+               /*      if((ivideo->chip == SIS_315H)   ||
                           (ivideo->chip == SIS_315)    ||
                           (ivideo->chip == SIS_315PRO) ||
                           (ivideo->chip == SIS_330)) {
                                sisfb_post_sis315330(pdev);
+                       } else */ if(ivideo->chip == XGI_20) {
+                               result = sisfb_post_xgi(pdev);
+                               ivideo->sisfb_can_post = 1;
+                       } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
+                               result = sisfb_post_xgi(pdev);
+                               ivideo->sisfb_can_post = 1;
+                       } else {
+                               printk(KERN_INFO "sisfb: Card is not "
+                                       "POSTed and sisfb can't do this either.\n");
+                       }
+                       if(!result) {
+                               printk(KERN_ERR "sisfb: Failed to POST card\n");
+                               ret = -ENODEV;
+                               goto error_3;
                        }
                }
-       }
 #endif
+       }
 
+       ivideo->sisfb_card_posted = 1;
+
+       /* Find out about RAM size */
        if(sisfb_get_dram_size(ivideo)) {
-               printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
-               if(ivideo->bios_abase) vfree(ivideo->bios_abase);
-               pci_set_drvdata(pdev, NULL);
-               kfree(sis_fb_info);
-               return -ENODEV;
+               printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
+               ret = -ENODEV;
+               goto error_3;
        }
 
+
+       /* Enable PCI addressing and MMIO */
        if((ivideo->sisfb_mode_idx < 0) ||
           ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
-               /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
-               orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
-                /* Enable 2D accelerator engine */
-               orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
+               /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
+               orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
+               /* Enable 2D accelerator engine */
+               orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
        }
 
        if(sisfb_pdc != 0xff) {
-          if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
-          else                                     sisfb_pdc &= 0x1f;
-          ivideo->SiS_Pr.PDC = sisfb_pdc;
+               if(ivideo->sisvga_engine == SIS_300_VGA)
+                       sisfb_pdc &= 0x3c;
+               else
+                       sisfb_pdc &= 0x1f;
+               ivideo->SiS_Pr.PDC = sisfb_pdc;
        }
 #ifdef CONFIG_FB_SIS_315
        if(ivideo->sisvga_engine == SIS_315_VGA) {
-          if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
+               if(sisfb_pdca != 0xff)
+                       ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
        }
 #endif
 
        if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
-               printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
+               printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
+                               (int)(ivideo->video_size >> 20));
                printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
-               if(ivideo->bios_abase) vfree(ivideo->bios_abase);
-               pci_set_drvdata(pdev, NULL);
-               kfree(sis_fb_info);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto error_3;
        }
 
        if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
                printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
-               release_mem_region(ivideo->video_base, ivideo->video_size);
-               if(ivideo->bios_abase) vfree(ivideo->bios_abase);
-               pci_set_drvdata(pdev, NULL);
-               kfree(sis_fb_info);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto error_2;
        }
 
        ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
-       ivideo->sishw_ext.pjVideoMemoryAddress = ivideo->video_vbase;
+       ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
        if(!ivideo->video_vbase) {
-               printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
-               release_mem_region(ivideo->video_base, ivideo->video_size);
-               release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
-               if(ivideo->bios_abase) vfree(ivideo->bios_abase);
-               pci_set_drvdata(pdev, NULL);
-               kfree(sis_fb_info);
-               return -ENODEV;
+               printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
+               ret = -ENODEV;
+               goto error_1;
        }
 
        ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
        if(!ivideo->mmio_vbase) {
-               printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
-               iounmap(ivideo->video_vbase);
-               release_mem_region(ivideo->video_base, ivideo->video_size);
-               release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
-               if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+               printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
+               ret = -ENODEV;
+error_0:       iounmap(ivideo->video_vbase);
+error_1:       release_mem_region(ivideo->video_base, ivideo->video_size);
+error_2:       release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
+error_3:       vfree(ivideo->bios_abase);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+error_4:
+#endif
+               if(ivideo->lpcdev)
+                       SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
+               if(ivideo->nbridge)
+                       SIS_PCI_PUT_DEVICE(ivideo->nbridge);
                pci_set_drvdata(pdev, NULL);
-               kfree(sis_fb_info);
-               return -ENODEV;
+               if(!ivideo->sisvga_enabled)
+                       pci_disable_device(pdev);
+               kfree(sis_fb_info);
+               return ret;
        }
 
-       printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n",
-               ivideo->video_base, (ULONG)ivideo->video_vbase, ivideo->video_size / 1024);
+       printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
+               ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
+
+       if(ivideo->video_offset) {
+               printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
+                       ivideo->video_offset / 1024);
+       }
 
        printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
-               ivideo->mmio_base, (ULONG)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
+               ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
+
+
+       /* Determine the size of the command queue */
+       if(ivideo->sisvga_engine == SIS_300_VGA) {
+               ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
+       } else {
+               if(ivideo->chip == XGI_20) {
+                       ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
+               } else {
+                       ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
+               }
+       }
 
+       /* Engines are no longer initialized here; this is
+        * now done after the first mode-switch (if the
+        * submitted var has its acceleration flags set).
+        */
+
+       /* Calculate the base of the (unused) hw cursor */
+       ivideo->hwcursor_vbase = ivideo->video_vbase
+                                + ivideo->video_size
+                                - ivideo->cmdQueueSize
+                                - ivideo->hwcursor_size;
+       ivideo->caps |= HW_CURSOR_CAP;
+
+       /* Initialize offscreen memory manager */
        if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
                printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
        }
 
        /* Used for clearing the screen only, therefore respect our mem limit */
-       ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
+       ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
+       ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
 
-       ivideo->mtrr = 0;
+       ivideo->mtrr = -1;
 
        ivideo->vbflags = 0;
        ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
        ivideo->tvdefmodeidx  = DEFAULT_TVMODE;
        ivideo->defmodeidx    = DEFAULT_MODE;
 
-       ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
+       ivideo->newrom = 0;
+       if(ivideo->chip < XGI_20) {
+               if(ivideo->bios_abase) {
+                       ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
+               }
+       }
 
        if((ivideo->sisfb_mode_idx < 0) ||
           ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
@@ -5217,192 +6355,57 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
 
                sisfb_get_VB_type(ivideo);
 
-               if(ivideo->vbflags & VB_VIDEOBRIDGE) {
+               if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
                        sisfb_detect_VB_connect(ivideo);
                }
 
                ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
 
-               if(ivideo->vbflags & VB_VIDEOBRIDGE) {
-                  if(ivideo->sisfb_crt2type != -1) {
-                     if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
-                        ivideo->currentvbflags |= CRT2_LCD;
-                     } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
-                        ivideo->currentvbflags |= ivideo->sisfb_crt2type;
-                     }
-                  } else {
-                     /* Chrontel 700x TV detection often unreliable, therefore use a
-                      * different default order on such machines
-                      */
-                     if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
-                        if(ivideo->vbflags & CRT2_LCD)      ivideo->currentvbflags |= CRT2_LCD;
-                        else if(ivideo->vbflags & CRT2_TV)  ivideo->currentvbflags |= CRT2_TV;
-                        else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
-                     } else {
-                        if(ivideo->vbflags & CRT2_TV)       ivideo->currentvbflags |= CRT2_TV;
-                        else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
-                        else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
-                     }
-                  }
+               /* Decide on which CRT2 device to use */
+               if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
+                       if(ivideo->sisfb_crt2type != -1) {
+                               if((ivideo->sisfb_crt2type == CRT2_LCD) &&
+                                  (ivideo->vbflags & CRT2_LCD)) {
+                                       ivideo->currentvbflags |= CRT2_LCD;
+                               } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
+                                       ivideo->currentvbflags |= ivideo->sisfb_crt2type;
+                               }
+                       } else {
+                               /* Chrontel 700x TV detection often unreliable, therefore
+                                * use a different default order on such machines
+                                */
+                               if((ivideo->sisvga_engine == SIS_300_VGA) &&
+                                  (ivideo->vbflags2 & VB2_CHRONTEL)) {
+                                       if(ivideo->vbflags & CRT2_LCD)
+                                               ivideo->currentvbflags |= CRT2_LCD;
+                                       else if(ivideo->vbflags & CRT2_TV)
+                                               ivideo->currentvbflags |= CRT2_TV;
+                                       else if(ivideo->vbflags & CRT2_VGA)
+                                               ivideo->currentvbflags |= CRT2_VGA;
+                               } else {
+                                       if(ivideo->vbflags & CRT2_TV)
+                                               ivideo->currentvbflags |= CRT2_TV;
+                                       else if(ivideo->vbflags & CRT2_LCD)
+                                               ivideo->currentvbflags |= CRT2_LCD;
+                                       else if(ivideo->vbflags & CRT2_VGA)
+                                               ivideo->currentvbflags |= CRT2_VGA;
+                               }
+                       }
                }
 
                if(ivideo->vbflags & CRT2_LCD) {
-                  inSISIDXREG(SISCR, 0x36, reg);
-                  reg &= 0x0f;
-                  if(ivideo->sisvga_engine == SIS_300_VGA) {
-                     ivideo->CRT2LCDType = sis300paneltype[reg];
-                  } else if(ivideo->chip >= SIS_661) {
-                     ivideo->CRT2LCDType = sis661paneltype[reg];
-                  } else {
-                     ivideo->CRT2LCDType = sis310paneltype[reg];
-                     if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
-                        if((ivideo->CRT2LCDType != LCD_640x480_2) &&
-                           (ivideo->CRT2LCDType != LCD_640x480_3)) {
-                           ivideo->CRT2LCDType = LCD_320x480;
-                        }
-                     }
-                  }
-                  if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
-                     /* For broken BIOSes: Assume 1024x768, RGB18 */
-                     ivideo->CRT2LCDType = LCD_1024x768;
-                     setSISIDXREG(SISCR,0x36,0xf0,0x02);
-                     setSISIDXREG(SISCR,0x37,0xee,0x01);
-                     printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
-                  }
-                  for(i = 0; i < SIS_LCD_NUMBER; i++) {
-                     if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
-                        ivideo->lcdxres = sis_lcd_data[i].xres;
-                        ivideo->lcdyres = sis_lcd_data[i].yres;
-                        ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
-                        break;
-                     }
-                  }
-                  if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
-                       ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
-                  } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
-                       ivideo->lcdxres =  848; ivideo->lcdyres =  480; ivideo->lcddefmodeidx = 47;
-                  }
-                  printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
-                               ivideo->lcdxres, ivideo->lcdyres);
-               }
-
-#ifdef CONFIG_FB_SIS_300
-                /* Save the current PanelDelayCompensation if the LCD is currently used */
-               if(ivideo->sisvga_engine == SIS_300_VGA) {
-                  if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
-                      int tmp;
-                      inSISIDXREG(SISCR,0x30,tmp);
-                      if(tmp & 0x20) {
-                         /* Currently on LCD? If yes, read current pdc */
-                         inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
-                         ivideo->detectedpdc &= 0x3c;
-                         if(ivideo->SiS_Pr.PDC == -1) {
-                            /* Let option override detection */
-                            ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
-                         }
-                         printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
-                                ivideo->detectedpdc);
-                      }
-                      if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
-                         printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
-                                ivideo->SiS_Pr.PDC);
-                      }
-                  }
+                       sisfb_detect_lcd_type(ivideo);
                }
-#endif
-
-#ifdef CONFIG_FB_SIS_315
-               if(ivideo->sisvga_engine == SIS_315_VGA) {
-
-                  /* Try to find about LCDA */
-                  if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
-                     int tmp;
-                     inSISIDXREG(SISPART1,0x13,tmp);
-                     if(tmp & 0x04) {
-                        ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
-                        ivideo->detectedlcda = 0x03;
-                     }
-                  }
-
-                  /* Save PDC */
-                  if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
-                     int tmp;
-                     inSISIDXREG(SISCR,0x30,tmp);
-                     if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
-                        /* Currently on LCD? If yes, read current pdc */
-                        u8 pdc;
-                        inSISIDXREG(SISPART1,0x2D,pdc);
-                        ivideo->detectedpdc  = (pdc & 0x0f) << 1;
-                        ivideo->detectedpdca = (pdc & 0xf0) >> 3;
-                        inSISIDXREG(SISPART1,0x35,pdc);
-                        ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
-                        inSISIDXREG(SISPART1,0x20,pdc);
-                        ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
-                        if(ivideo->newrom) {
-                           /* New ROM invalidates other PDC resp. */
-                           if(ivideo->detectedlcda != 0xff) {
-                              ivideo->detectedpdc = 0xff;
-                           } else {
-                              ivideo->detectedpdca = 0xff;
-                           }
-                        }
-                        if(ivideo->SiS_Pr.PDC == -1) {
-                           if(ivideo->detectedpdc != 0xff) {
-                              ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
-                           }
-                        }
-                        if(ivideo->SiS_Pr.PDCA == -1) {
-                           if(ivideo->detectedpdca != 0xff) {
-                              ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
-                           }
-                        }
-                        if(ivideo->detectedpdc != 0xff) {
-                           printk(KERN_INFO
-                                "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
-                                 ivideo->detectedpdc);
-                        }
-                        if(ivideo->detectedpdca != 0xff) {
-                           printk(KERN_INFO
-                                "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
-                                 ivideo->detectedpdca);
-                        }
-                     }
-
-                     /* Save EMI */
-                     if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
-                        inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
-                        inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
-                        inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
-                        inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
-                        ivideo->SiS_Pr.HaveEMI = TRUE;
-                        if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
-                               ivideo->SiS_Pr.HaveEMILCD = TRUE;
-                        }
-                     }
-                  }
 
-                  /* Let user override detected PDCs (all bridges) */
-                  if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
-                     if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
-                        printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
-                                ivideo->SiS_Pr.PDC);
-                     }
-                     if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
-                        printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
-                                ivideo->SiS_Pr.PDCA);
-                     }
-                  }
-
-               }
-#endif
+               sisfb_save_pdc_emi(ivideo);
 
                if(!ivideo->sisfb_crt1off) {
-                       sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
+                       sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
                } else {
-                       if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
-                          (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
-                               sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
-                       }
+                       if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
+                          (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
+                               sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
+                       }
                }
 
                if(ivideo->sisfb_mode_idx >= 0) {
@@ -5434,7 +6437,8 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
                ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
 
                if(ivideo->refresh_rate != 0) {
-                       sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
+                       sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
+                                               ivideo->sisfb_mode_idx);
                }
 
                if(ivideo->rate_idx == 0) {
@@ -5443,9 +6447,12 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
                }
 
                if(ivideo->sisfb_thismonitor.datavalid) {
-                       if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
-                                             ivideo->rate_idx, ivideo->refresh_rate)) {
-                               printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
+                       if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
+                                               ivideo->sisfb_mode_idx,
+                                               ivideo->rate_idx,
+                                               ivideo->refresh_rate)) {
+                               printk(KERN_INFO "sisfb: WARNING: Refresh rate "
+                                                       "exceeds monitor specs!\n");
                        }
                }
 
@@ -5454,28 +6461,34 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
                ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
 
                sisfb_set_vparms(ivideo);
-               
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) 
 
-               /* ---------------- For 2.4: Now switch the mode ------------------ */          
-               
-               printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
-                       ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+
+               /* ---------------- For 2.4: Now switch the mode ------------------ */
+
+               printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
+                       ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
                        ivideo->refresh_rate);
 
+               /* Determine whether or not acceleration is to be
+                * used. Need to know before pre/post_set_mode()
+                */
+               ivideo->accel = 0;
+               ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
+               if(ivideo->sisfb_accel) {
+                       ivideo->accel = -1;
+                       ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
+               }
+
+               /* Now switch the mode */
                sisfb_pre_setmode(ivideo);
 
-               if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
+               if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
                        printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
                                                                        ivideo->mode_no);
-                       iounmap(ivideo->video_vbase);
+                       ret = -EINVAL;
                        iounmap(ivideo->mmio_vbase);
-                       release_mem_region(ivideo->video_base, ivideo->video_size);
-                       release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
-                       if(ivideo->bios_abase) vfree(ivideo->bios_abase);
-                       pci_set_drvdata(pdev, NULL);
-                       kfree(sis_fb_info);
-                       return -EINVAL;
+                       goto error_0;
                }
 
                outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
@@ -5488,18 +6501,17 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
                /* Force reset of x virtual in crtc_to_var */
                ivideo->default_var.xres_virtual = 0;
 
+               /* Copy mode timing to var */
                sisfb_crtc_to_var(ivideo, &ivideo->default_var);
 
+               /* Find out about screen pitch */
                sisfb_calc_pitch(ivideo, &ivideo->default_var);
                sisfb_set_pitch(ivideo);
 
-               ivideo->accel = 0;
-               if(ivideo->sisfb_accel) {
-                  ivideo->accel = -1;
-                  ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
-               }
+               /* Init the accelerator (does nothing currently) */
                sisfb_initaccel(ivideo);
-               
+
+               /* Init some fbinfo entries */
                sis_fb_info->node  = -1;
                sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
                sis_fb_info->fbops = &sisfb_ops;
@@ -5515,41 +6527,42 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
 #else          /* --------- For 2.6: Setup a somewhat sane default var ------------ */
 
                printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
-                       ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
+                       ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
                        ivideo->refresh_rate);
 
+               /* Set up the default var according to chosen default display mode */
                ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
                ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
                ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
 
                sisfb_bpp_to_var(ivideo, &ivideo->default_var);
-               
+
                ivideo->default_var.pixclock = (u32) (1000000000 /
-                               sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
-                                               ivideo->mode_no, ivideo->rate_idx));
-                                               
-               if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
-                               ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
-                  if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
-                     ivideo->default_var.pixclock <<= 1;
-                  }
-               }
+                       sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
+
+               if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
+                                               ivideo->rate_idx, &ivideo->default_var)) {
+                       if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+                               ivideo->default_var.pixclock <<= 1;
+                       }
+               }
 
                if(ivideo->sisfb_ypan) {
-                  /* Maximize regardless of sisfb_max at startup */
-                  ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var);
-                  if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
-                     ivideo->default_var.yres_virtual = ivideo->default_var.yres;
-                  }
+                       /* Maximize regardless of sisfb_max at startup */
+                       ivideo->default_var.yres_virtual =
+                               sisfb_calc_maxyres(ivideo, &ivideo->default_var);
+                       if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
+                               ivideo->default_var.yres_virtual = ivideo->default_var.yres;
+                       }
                }
 
                sisfb_calc_pitch(ivideo, &ivideo->default_var);
 
                ivideo->accel = 0;
                if(ivideo->sisfb_accel) {
-                  ivideo->accel = -1;
+                       ivideo->accel = -1;
 #ifdef STUPID_ACCELF_TEXT_SHIT
-                  ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
+                       ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
 #endif
                }
                sisfb_initaccel(ivideo);
@@ -5566,21 +6579,21 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
 #endif
                sis_fb_info->var = ivideo->default_var;
                sis_fb_info->fix = ivideo->sisfb_fix;
-               sis_fb_info->screen_base = ivideo->video_vbase;
+               sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
                sis_fb_info->fbops = &sisfb_ops;
 
                sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
                sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
-               
+
                fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
 #endif         /* 2.6 */
 
-               printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
+               printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
 
 #ifdef CONFIG_MTRR
                ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
                                        MTRR_TYPE_WRCOMB, 1);
-               if(!ivideo->mtrr) {
+               if(ivideo->mtrr < 0) {
                        printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
                }
 #endif
@@ -5591,14 +6604,9 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
 
                if(register_framebuffer(sis_fb_info) < 0) {
                        printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
-                       iounmap(ivideo->video_vbase);
+                       ret = -EINVAL;
                        iounmap(ivideo->mmio_vbase);
-                       release_mem_region(ivideo->video_base, ivideo->video_size);
-                       release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
-                       if(ivideo->bios_abase) vfree(ivideo->bios_abase);
-                       pci_set_drvdata(pdev, NULL);
-                       kfree(sis_fb_info);
-                       return -EINVAL;
+                       goto error_0;
                }
 
                ivideo->registered = 1;
@@ -5607,21 +6615,47 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
                ivideo->next = card_list;
                card_list = ivideo;
 
+#ifdef SIS_OLD_CONFIG_COMPAT
+               {
+               int ret;
+               /* Our ioctls are all "32/64bit compatible" */
+               ret =  register_ioctl32_conversion(FBIO_ALLOC,             NULL);
+               ret |= register_ioctl32_conversion(FBIO_FREE,              NULL);
+               ret |= register_ioctl32_conversion(FBIOGET_VBLANK,         NULL);
+               ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE,    NULL);
+               ret |= register_ioctl32_conversion(SISFB_GET_INFO,         NULL);
+               ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET,  NULL);
+               ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET,  NULL);
+               ret |= register_ioctl32_conversion(SISFB_SET_LOCK,         NULL);
+               ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS,    NULL);
+               ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
+               ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
+               ret |= register_ioctl32_conversion(SISFB_COMMAND,          NULL);
+               if(ret)
+                       printk(KERN_ERR
+                               "sisfb: Error registering ioctl32 translations\n");
+               else
+                       ivideo->ioctl32registered = 1;
+               }
+#endif
+
                printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
-                    ivideo->sisfb_accel ? "enabled" : "disabled",
-                    ivideo->sisfb_ypan  ?
-                       (ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
+                       ivideo->sisfb_accel ? "enabled" : "disabled",
+                       ivideo->sisfb_ypan  ?
+                               (ivideo->sisfb_max ? "enabled (auto-max)" :
+                                               "enabled (no auto-max)") :
+                                                                       "disabled");
 
 
-               printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n",
+               printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-                       GET_FB_IDX(sis_fb_info->node),
+                       GET_FB_IDX(sis_fb_info->node),
 #else
-                       sis_fb_info->node,
+                       sis_fb_info->node,
 #endif
                        ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
 
-               printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
+               printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
 
        }       /* if mode = "none" */
 
@@ -5634,26 +6668,62 @@ static int __devinit sisfb_probe(struct pci_dev *pdev,
 
 static void __devexit sisfb_remove(struct pci_dev *pdev)
 {
-       struct sis_video_info *ivideo = pci_get_drvdata(pdev);
-       struct fb_info        *sis_fb_info = ivideo->memyselfandi;
-       int                   registered = ivideo->registered;
+       struct sis_video_info   *ivideo = pci_get_drvdata(pdev);
+       struct fb_info          *sis_fb_info = ivideo->memyselfandi;
+       int                     registered = ivideo->registered;
+       int                     modechanged = ivideo->modechanged;
+
+#ifdef SIS_OLD_CONFIG_COMPAT
+       if(ivideo->ioctl32registered) {
+               int ret;
+               ret =  unregister_ioctl32_conversion(FBIO_ALLOC);
+               ret |= unregister_ioctl32_conversion(FBIO_FREE);
+               ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
+               ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
+               ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
+               ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
+               ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
+               ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
+               ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
+               ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
+               ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
+               ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
+               if(ret)
+                       printk(KERN_ERR
+                            "sisfb: Error unregistering ioctl32 translations\n");
+       }
+#endif
 
        /* Unmap */
-       iounmap(ivideo->video_vbase);
        iounmap(ivideo->mmio_vbase);
-       vfree(ivideo->bios_abase);
+       iounmap(ivideo->video_vbase);
 
        /* Release mem regions */
        release_mem_region(ivideo->video_base, ivideo->video_size);
        release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
 
+       vfree(ivideo->bios_abase);
+
+       if(ivideo->lpcdev)
+               SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
+
+       if(ivideo->nbridge)
+               SIS_PCI_PUT_DEVICE(ivideo->nbridge);
+
 #ifdef CONFIG_MTRR
        /* Release MTRR region */
-       if(ivideo->mtrr) {
+       if(ivideo->mtrr >= 0)
                mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
-       }
 #endif
 
+       pci_set_drvdata(pdev, NULL);
+
+       /* If device was disabled when starting, disable
+        * it when quitting.
+        */
+       if(!ivideo->sisvga_enabled)
+               pci_disable_device(pdev);
+
        /* Unregister the framebuffer */
        if(ivideo->registered) {
                unregister_framebuffer(sis_fb_info);
@@ -5664,7 +6734,7 @@ static void __devexit sisfb_remove(struct pci_dev *pdev)
 #endif
        }
 
-       pci_set_drvdata(pdev, NULL);
+       /* OK, our ivideo is gone for good from here. */
 
        /* TODO: Restore the initial mode
         * This sounds easy but is as good as impossible
@@ -5673,15 +6743,15 @@ static void __devexit sisfb_remove(struct pci_dev *pdev)
         * from machine to machine. Depends on the type
         * of integration between chipset and bridge.
         */
-       if(registered) {
-          printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
-       }
+       if(registered && modechanged)
+               printk(KERN_INFO
+                       "sisfb: Restoring of text mode not supported yet\n");
 };
 
 static struct pci_driver sisfb_driver = {
        .name           = "sisfb",
        .id_table       = sisfb_pci_table,
-       .probe          = sisfb_probe,
+       .probe          = sisfb_probe,
        .remove         = __devexit_p(sisfb_remove)
 };
 
@@ -5693,10 +6763,11 @@ SISINITSTATIC int __init sisfb_init(void)
 
        if(fb_get_options("sisfb", &options))
                return -ENODEV;
+
        sisfb_setup(options);
 #endif
 #endif
-       return(pci_register_driver(&sisfb_driver));
+       return pci_register_driver(&sisfb_driver);
 }
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
@@ -5711,36 +6782,129 @@ module_init(sisfb_init);
 
 #ifdef MODULE
 
-static char         *mode = NULL;
-static int          vesa = -1;
-static unsigned int rate = 0;
-static unsigned int crt1off = 1;
-static unsigned int mem = 0;
-static char         *forcecrt2type = NULL;
-static int          forcecrt1 = -1;
-static int          pdc = -1;
-static int          pdc1 = -1;
-static int          noaccel = -1;
-static int          noypan  = -1;
-static int         nomax = -1;
+static char            *mode = NULL;
+static int             vesa = -1;
+static unsigned int    rate = 0;
+static unsigned int    crt1off = 1;
+static unsigned int    mem = 0;
+static char            *forcecrt2type = NULL;
+static int             forcecrt1 = -1;
+static int             pdc = -1;
+static int             pdc1 = -1;
+static int             noaccel = -1;
+static int             noypan  = -1;
+static int             nomax = -1;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static int             inverse = 0;
+#endif
+static int             userom = -1;
+static int             useoem = -1;
+static char            *tvstandard = NULL;
+static int             nocrt2rate = 0;
+static int             scalelcd = -1;
+static char            *specialtiming = NULL;
+static int             lvdshl = -1;
+static int             tvxposoffset = 0, tvyposoffset = 0;
+#if !defined(__i386__) && !defined(__x86_64__)
+static int             resetcard = 0;
+static int             videoram = 0;
+#endif
+
+static int __init sisfb_init_module(void)
+{
+       sisfb_setdefaultparms();
+
+       if(rate)
+               sisfb_parm_rate = rate;
+
+       if((scalelcd == 0) || (scalelcd == 1))
+               sisfb_scalelcd = scalelcd ^ 1;
+
+       /* Need to check crt2 type first for fstn/dstn */
+
+       if(forcecrt2type)
+               sisfb_search_crt2type(forcecrt2type);
+
+       if(tvstandard)
+               sisfb_search_tvstd(tvstandard);
+
+       if(mode)
+               sisfb_search_mode(mode, FALSE);
+       else if(vesa != -1)
+               sisfb_search_vesamode(vesa, FALSE);
+
+       sisfb_crt1off = (crt1off == 0) ? 1 : 0;
+
+       sisfb_forcecrt1 = forcecrt1;
+       if(forcecrt1 == 1)
+               sisfb_crt1off = 0;
+       else if(forcecrt1 == 0)
+               sisfb_crt1off = 1;
+
+       if(noaccel == 1)
+               sisfb_accel = 0;
+       else if(noaccel == 0)
+               sisfb_accel = 1;
+
+       if(noypan == 1)
+               sisfb_ypan = 0;
+       else if(noypan == 0)
+               sisfb_ypan = 1;
+
+       if(nomax == 1)
+               sisfb_max = 0;
+       else if(nomax == 0)
+               sisfb_max = 1;
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-static int          inverse = 0;
-#endif
-static int          userom = -1;
-static int          useoem = -1;
-static char         *tvstandard = NULL;
-static int         nocrt2rate = 0;
-static int          scalelcd = -1;
-static char        *specialtiming = NULL;
-static int         lvdshl = -1;
-static int         tvxposoffset = 0, tvyposoffset = 0;
-static int         filter = -1;
+       if(inverse) sisfb_inverse = 1;
+#endif
+
+       if(mem)
+               sisfb_parm_mem = mem;
+
+       if(userom != -1)
+               sisfb_userom = userom;
+
+       if(useoem != -1)
+               sisfb_useoem = useoem;
+
+        if(pdc != -1)
+               sisfb_pdc  = (pdc  & 0x7f);
+
+       if(pdc1 != -1)
+               sisfb_pdca = (pdc1 & 0x1f);
+
+       sisfb_nocrt2rate = nocrt2rate;
+
+       if(specialtiming)
+               sisfb_search_specialtiming(specialtiming);
+
+       if((lvdshl >= 0) && (lvdshl <= 3))
+               sisfb_lvdshl = lvdshl;
+
+       sisfb_tvxposoffset = tvxposoffset;
+       sisfb_tvyposoffset = tvyposoffset;
+
 #if !defined(__i386__) && !defined(__x86_64__)
-static int         resetcard = 0;
-static int         videoram = 0;
+       sisfb_resetcard = (resetcard) ? 1 : 0;
+       if(videoram)
+               sisfb_videoram = videoram;
 #endif
 
-MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
+       return sisfb_init();
+}
+
+static void __exit sisfb_remove_module(void)
+{
+       pci_unregister_driver(&sisfb_driver);
+       printk(KERN_DEBUG "sisfb: Module unloaded\n");
+}
+
+module_init(sisfb_init_module);
+module_exit(sisfb_remove_module);
+
+MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
 
@@ -5764,7 +6928,6 @@ MODULE_PARM(lvdshl, "i");
 MODULE_PARM(tvstandard, "s");
 MODULE_PARM(tvxposoffset, "i");
 MODULE_PARM(tvyposoffset, "i");
-MODULE_PARM(filter, "i");
 MODULE_PARM(nocrt2rate, "i");
 MODULE_PARM(inverse, "i");
 #if !defined(__i386__) && !defined(__x86_64__)
@@ -5793,7 +6956,6 @@ module_param(lvdshl, int, 0);
 module_param(tvstandard, charp, 0);
 module_param(tvxposoffset, int, 0);
 module_param(tvyposoffset, int, 0);
-module_param(filter, int, 0);
 module_param(nocrt2rate, int, 0);
 #if !defined(__i386__) && !defined(__x86_64__)
 module_param(resetcard, int, 0);
@@ -5801,25 +6963,35 @@ module_param(videoram, int, 0);
 #endif
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 MODULE_PARM_DESC(mem,
        "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
          "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
          "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
          "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
-         "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
+         "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
          "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
          "for XFree86 4.x/X.org 6.7 and later.\n");
+#else
+MODULE_PARM_DESC(mem,
+       "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
+         "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
+         "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
+         "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
+         "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
+         "The value is to be specified without 'KB'.\n");
+#endif
 
 MODULE_PARM_DESC(noaccel,
-        "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
+       "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
          "(default: 0)\n");
 
 MODULE_PARM_DESC(noypan,
-        "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
-         "will be performed by redrawing the screen. (default: 0)\n");
+       "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
+         "will be performed by redrawing the screen. (default: 0)\n");
 
 MODULE_PARM_DESC(nomax,
-        "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
+       "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
          "memory for the virtual screen in order to optimize scrolling performance. If\n"
          "this is set to anything other than 0, sisfb will not do this and thereby \n"
          "enable the user to positively specify a virtual Y size of the screen using\n"
@@ -5827,30 +6999,30 @@ MODULE_PARM_DESC(nomax,
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 MODULE_PARM_DESC(mode,
-        "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
-          "1024x768x16. Other formats supported include XxY-Depth and\n"
-         "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
+       "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
+         "1024x768x16. Other formats supported include XxY-Depth and\n"
+         "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
          "number, it will be interpreted as a VESA mode number. (default: none if\n"
          "sisfb is a module; this leaves the console untouched and the driver will\n"
          "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
          "is in the kernel)\n");
 MODULE_PARM_DESC(vesa,
-        "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
-          "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
+       "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
+         "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
          "and the driver will only do the video memory management for eg. DRM/DRI;\n"
          "0x0103 if sisfb is in the kernel)\n");
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 MODULE_PARM_DESC(mode,
-       "\nSelects the desired default display mode in the format XxYxDepth,\n"
-         "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
+       "\nSelects the desired default display mode in the format XxYxDepth,\n"
+        "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
         "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
         "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
 
 MODULE_PARM_DESC(vesa,
-       "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
-         "0x117 (default: 0x0103)\n");
+       "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
+        "0x117 (default: 0x0103)\n");
 #endif
 
 MODULE_PARM_DESC(rate,
@@ -5880,16 +7052,16 @@ MODULE_PARM_DESC(scalelcd,
          "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
 
 MODULE_PARM_DESC(pdc,
-        "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
+       "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
          "should detect this correctly in most cases; however, sometimes this is not\n"
          "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
-         "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
-         "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
-         "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
+         "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
+         "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
+         "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
 
 #ifdef CONFIG_FB_SIS_315
 MODULE_PARM_DESC(pdc1,
-        "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
+       "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
          "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
          "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
          "implemented yet.\n");
@@ -5913,17 +7085,13 @@ MODULE_PARM_DESC(tvyposoffset,
        "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
          "Default: 0\n");
 
-MODULE_PARM_DESC(filter,
-       "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
-         "(Possible values 0-7, default: [no filter])\n");
-
 MODULE_PARM_DESC(nocrt2rate,
        "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
          "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 MODULE_PARM_DESC(inverse,
-        "\nSetting this to anything but 0 should invert the display colors, but this\n"
+       "\nSetting this to anything but 0 should invert the display colors, but this\n"
          "does not seem to work. (default: 0)\n");
 #endif
 
@@ -5931,98 +7099,23 @@ MODULE_PARM_DESC(inverse,
 #ifdef CONFIG_FB_SIS_300
 MODULE_PARM_DESC(resetcard,
        "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
-         "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
-         "Default: 0\n");
+         "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
+         "currently). Default: 0\n");
 
 MODULE_PARM_DESC(videoram,
        "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
          "some non-x86 architectures where the memory auto detection fails. Only\n"
-         "relevant if resetcard is set, too. Default: [auto-detect]\n");
-#endif
-#endif
-
-static int __devinit sisfb_init_module(void)
-{
-       sisfb_setdefaultparms();
-
-       if(rate) sisfb_parm_rate = rate;
-
-       if((scalelcd == 0) || (scalelcd == 1)) {
-          sisfb_scalelcd = scalelcd ^ 1;
-       }
-
-       /* Need to check crt2 type first for fstn/dstn */
-
-       if(forcecrt2type)
-               sisfb_search_crt2type(forcecrt2type);
-
-       if(tvstandard)
-               sisfb_search_tvstd(tvstandard);
-
-       if(mode)
-               sisfb_search_mode(mode, FALSE);
-       else if(vesa != -1)
-               sisfb_search_vesamode(vesa, FALSE);
-
-       sisfb_crt1off = (crt1off == 0) ? 1 : 0;
-
-       sisfb_forcecrt1 = forcecrt1;
-       if(forcecrt1 == 1)      sisfb_crt1off = 0;
-       else if(forcecrt1 == 0) sisfb_crt1off = 1;
-
-       if(noaccel == 1)      sisfb_accel = 0;
-       else if(noaccel == 0) sisfb_accel = 1;
-
-       if(noypan == 1)       sisfb_ypan = 0;
-       else if(noypan == 0)  sisfb_ypan = 1;
-
-       if(nomax == 1)        sisfb_max = 0;
-       else if(nomax == 0)   sisfb_max = 1;
-       
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-       if(inverse)           sisfb_inverse = 1;
+         "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
 #endif
-
-       if(mem)               sisfb_parm_mem = mem;
-
-       if(userom != -1)      sisfb_userom = userom;
-       if(useoem != -1)      sisfb_useoem = useoem;
-
-        if(pdc != -1)  sisfb_pdc  = (pdc  & 0x7f);
-       if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
-
-       sisfb_nocrt2rate = nocrt2rate;
-
-       if(specialtiming)
-               sisfb_search_specialtiming(specialtiming);
-
-       if((lvdshl >= 0) && (lvdshl <= 3))  sisfb_lvdshl = lvdshl;
-
-       if(filter != -1) sisfb_filter = filter;
-
-       sisfb_tvxposoffset = tvxposoffset;
-       sisfb_tvyposoffset = tvyposoffset;
-
-#if !defined(__i386__) && !defined(__x86_64__)
-       sisfb_resetcard = (resetcard) ? 1 : 0;
-       if(videoram)    sisfb_videoram = videoram;
 #endif
 
-        return(sisfb_init());
-}
-
-static void __exit sisfb_remove_module(void)
-{
-       pci_unregister_driver(&sisfb_driver);
-       printk(KERN_DEBUG "sisfb: Module unloaded\n");
-}
-
-module_init(sisfb_init_module);
-module_exit(sisfb_remove_module);
-
 #endif            /*  /MODULE  */
 
+/* _GPL only for new symbols. */
 EXPORT_SYMBOL(sis_malloc);
 EXPORT_SYMBOL(sis_free);
+EXPORT_SYMBOL_GPL(sis_malloc_new);
+EXPORT_SYMBOL_GPL(sis_free_new);
+