patch-2.4.26 linux-2.4.26/drivers/video/sis/sis_main.c

Next file: linux-2.4.26/drivers/video/sis/sis_main.h
Previous file: linux-2.4.26/drivers/video/sis/sis_accel.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.25/drivers/video/sis/sis_main.c linux-2.4.26/drivers/video/sis/sis_main.c
@@ -47,9 +47,7 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 #include <linux/vmalloc.h>
-#endif
 #include <linux/vt_kern.h>
 #include <linux/capability.h>
 #include <linux/fs.h>
@@ -87,14 +85,18 @@
 #include "sis.h"
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-#error "This version of sisfb requires at least 2.6.0"
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
+#error "This version of sisfb requires at least 2.6.3"
+#else
+#if 0
+#define NEWFBDEV		/* Define this as soon as sysfs support has returned */
+#endif
 #endif
 #endif
 
 /* -------------------- Macro definitions ---------------------------- */
 
-#undef SISFBDEBUG 	/* TW: no debugging */
+#undef SISFBDEBUG 	/* no debugging */
 
 #ifdef SISFBDEBUG
 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
@@ -118,170 +120,23 @@
 
 /* --------------- Hardware Access Routines -------------------------- */
 
-void sisfb_set_reg4(u16 port, unsigned long data)
-{
-	outl((u32) (data & 0xffffffff), port);
-}
-
-u32 sisfb_get_reg3(u16 port)
-{
-	u32 data;
-
-	data = inl(port);
-	return (data);
-}
-
-/* ------------ Interface for init & mode switching code ------------- */
-
-BOOLEAN
-sisfb_query_VGA_config_space(PSIS_HW_INFO psishw_ext,
-	unsigned long offset, unsigned long set, unsigned long *value)
+/* These are used on x86 hardware during probe only */
+static void __devinit
+sisfb_set_reg4(u16 port, u32 data)
 {
-	static struct pci_dev *pdev = NULL;
-	static unsigned char init = 0, valid_pdev = 0;
-
-	if (!set)
-		DPRINTK("sisfb: Get VGA offset 0x%lx\n", offset);
-	else
-		DPRINTK("sisfb: Set offset 0x%lx to 0x%lx\n", offset, *value);
-
-	if (!init) {
-		init = TRUE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
-		pci_for_each_dev(pdev) {
-#else
-		while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
-#endif
-			DPRINTK("sisfb: Current: 0x%x, target: 0x%x\n",
-			         pdev->device, ivideo.chip_id);
-			if ((pdev->vendor == PCI_VENDOR_ID_SI)
-			           && (pdev->device == ivideo.chip_id)) {
-				valid_pdev = TRUE;
-				break;
-			}
-		}
-	}
-
-	if (!valid_pdev) {
-		printk(KERN_DEBUG "sisfb: Can't find SiS %d VGA device.\n",
-				ivideo.chip_id);
-		return FALSE;
-	}
-
-	if (set == 0)
-		pci_read_config_dword(pdev, offset, (u32 *)value);
-	else
-		pci_write_config_dword(pdev, offset, (u32)(*value));
-
-	return TRUE;
+	outl((u32)(data & 0xffffffff), port);
 }
 
-BOOLEAN sisfb_query_north_bridge_space(PSIS_HW_INFO psishw_ext,
-	unsigned long offset, unsigned long set, unsigned long *value)
+static u32 __devinit
+sisfb_get_reg3(u16 port)
 {
-	static struct pci_dev *pdev = NULL;
-	static unsigned char init = 0, valid_pdev = 0;
-	u16 nbridge_id = 0;
-
-	if (!init) {
-		init = TRUE;
-		switch (ivideo.chip) {
-#ifdef CONFIG_FB_SIS_300
-		case SIS_540:
-			nbridge_id = PCI_DEVICE_ID_SI_540;
-			break;
-		case SIS_630:
-			nbridge_id = PCI_DEVICE_ID_SI_630;
-			break;
-		case SIS_730:
-			nbridge_id = PCI_DEVICE_ID_SI_730;
-			break;
-#endif
-#ifdef CONFIG_FB_SIS_315
-		case SIS_550:
-			nbridge_id = PCI_DEVICE_ID_SI_550;
-			break;
-		case SIS_650:
-			nbridge_id = PCI_DEVICE_ID_SI_650;
-			break;
-		case SIS_740:
-			nbridge_id = PCI_DEVICE_ID_SI_740;
-			break;
-		case SIS_661:
-			nbridge_id = PCI_DEVICE_ID_SI_660;
-			break;
-		case SIS_741:
-			nbridge_id = PCI_DEVICE_ID_SI_741;
-			break;
-		case SIS_660:
-			nbridge_id = PCI_DEVICE_ID_SI_660;
-			break;
-		case SIS_760:
-			nbridge_id = PCI_DEVICE_ID_SI_760;
-			break;
-#endif
-		default:
-			nbridge_id = 0;
-			break;
-		}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
-		pci_for_each_dev(pdev) {
-#else
-		while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
-#endif
-			DPRINTK("Current: 0x%x, target: 0x%x\n",
-					pdev->device, ivideo.chip_id);
-			if ((pdev->vendor == PCI_VENDOR_ID_SI)
-					&& (pdev->device == nbridge_id)) {
-				valid_pdev = TRUE;
-				break;
-			}
-		}
-	}
-
-	if (!valid_pdev) {
-		printk(KERN_DEBUG "sisfb: Can't find SiS %d North Bridge device.\n",
-				nbridge_id);
-		return FALSE;
-	}
-
-	if (set == 0)
-		pci_read_config_dword(pdev, offset, (u32 *)value);
-	else
-		pci_write_config_dword(pdev, offset, (u32)(*value));
-
-	return TRUE;
+	return((u32)inl(port));
 }
 
 /* ------------------ Internal helper routines ----------------- */
 
-static BOOLEAN sisfb_verify_rate(struct sisfb_monitor *monitor, int mode_idx, int rate_idx, int rate)
-{
-	int htotal, vtotal;
-	unsigned int dclock, hsync;
-
-	if(!monitor->datavalid) return TRUE;
-
-	if(mode_idx < 0) return FALSE;
-
-	if(rate < (monitor->vmin - 1)) return FALSE;
-	if(rate > (monitor->vmax + 1)) return FALSE;
-
-	if(sisfb_gettotalfrommode(&SiS_Pr, &sishw_ext, sisbios_mode[mode_idx].mode_no,
-	                          &htotal, &vtotal, rate_idx)) {
-		dclock = (htotal * vtotal * rate) / 1000;
-		if(dclock > (monitor->dclockmax + 1000)) return FALSE;
-		hsync = dclock / htotal;
-		if(hsync < (monitor->hmin - 1)) return FALSE;
-		if(hsync > (monitor->hmax + 1)) return FALSE;
-        } else {
-	  	return FALSE;
-	}
-	return TRUE;
-};
-
-static BOOLEAN sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
+static BOOLEAN __devinit
+sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
 {
 	int i, j, xres, yres, refresh, index;
 	u32 emodes;
@@ -381,7 +236,8 @@
  	return(monitor->datavalid);
 }
 
-static void sisfb_handle_ddc(struct sisfb_monitor *monitor, int crtno)
+static void __devinit
+sisfb_handle_ddc(struct sisfb_monitor *monitor, int crtno)
 {
 	USHORT  temp, i, realcrtno = crtno;
    	u8      buffer[256];
@@ -396,7 +252,7 @@
 
 	if((sisfb_crt1off) && (!crtno)) return;
 
-    	temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine, realcrtno, 0, &buffer[0]);
+    	temp = SiS_HandleDDC(&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);
 	   return;
@@ -411,7 +267,7 @@
       	   if(temp & 0x02) {
 	      i = 3;  /* Number of retrys */
 	      do {
-	    	 temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine,
+	    	 temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, ivideo.sisvga_engine,
 				     realcrtno, 1, &buffer[0]);
 	      } while((temp) && i--);
               if(!temp) {
@@ -431,7 +287,8 @@
 	}
 }
 
-static void sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
+static void __init
+sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
 {
 	int i = 0, j = 0;
 
@@ -467,7 +324,8 @@
 	if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
 }
 
-static void sisfb_search_mode(char *name, BOOLEAN quiet)
+static void __init
+sisfb_search_mode(char *name, BOOLEAN quiet)
 {
 	int i = 0;
 	unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
@@ -538,17 +396,145 @@
 
 }
 
-static int sisfb_validate_mode(int myindex, unsigned long vbflags)
+static void __init
+sisfb_search_crt2type(const char *name)
+{
+	int i = 0;
+
+	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_dstn = (sis_crt2type[i].flags & FL_550_DSTN) ? 1 : 0;
+			sisfb_fstn = (sis_crt2type[i].flags & FL_550_FSTN) ? 1 : 0;
+			break;
+		}
+		i++;
+	}
+	if(sisfb_crt2type < 0)
+		printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
+        if(ivideo.chip != SIS_550) {
+	   sisfb_dstn = sisfb_fstn = 0;
+	}
+}
+
+static void __init
+sisfb_search_queuemode(const char *name)
+{
+	int i = 0;
+
+	if(name == NULL)
+		return;
+
+	while (sis_queuemode[i].type_no != -1) {
+		if (!strnicmp(name, sis_queuemode[i].name, strlen(sis_queuemode[i].name))) {
+			sisfb_queuemode = sis_queuemode[i].type_no;
+			break;
+		}
+		i++;
+	}
+	if (sisfb_queuemode < 0)
+		printk(KERN_ERR "sisfb: Invalid queuemode type: %s\n", name);
+}
+
+static void __init
+sisfb_search_tvstd(const char *name)
+{
+	int i = 0;
+
+	if(name == NULL)
+		return;
+
+	while (sis_tvtype[i].type_no != -1) {
+		if (!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
+		        ivideo.vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN);
+			ivideo.vbflags |= sis_tvtype[i].type_no;
+			break;
+		}
+		i++;
+	}
+}
+
+static void __init
+sisfb_search_specialtiming(const char *name)
+{
+	int i = 0;
+	BOOLEAN found = FALSE;
+
+	if(name == NULL)
+		return;
+
+	if(!strnicmp(name, "none", 4)) {
+	        SiS_Pr.SiS_CustomT = 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))) {
+		 SiS_Pr.SiS_CustomT = 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++;
+	      }
+           }
+ 	}
+}
+
+static BOOLEAN
+sisfb_verify_rate(struct sisfb_monitor *monitor, int mode_idx, int rate_idx, int rate)
+{
+	int htotal, vtotal;
+	unsigned int dclock, hsync;
+
+	if(!monitor->datavalid) return TRUE;
+
+	if(mode_idx < 0) return FALSE;
+
+	if(rate < (monitor->vmin - 1)) return FALSE;
+	if(rate > (monitor->vmax + 1)) return FALSE;
+
+	if(sisfb_gettotalfrommode(&SiS_Pr, &sishw_ext, sisbios_mode[mode_idx].mode_no,
+	                          &htotal, &vtotal, rate_idx)) {
+		dclock = (htotal * vtotal * rate) / 1000;
+		if(dclock > (monitor->dclockmax + 1000)) return FALSE;
+		hsync = dclock / htotal;
+		if(hsync < (monitor->hmin - 1)) return FALSE;
+		if(hsync > (monitor->hmax + 1)) return FALSE;
+        } else {
+	  	return FALSE;
+	}
+	return TRUE;
+}
+
+static int
+sisfb_validate_mode(int myindex, unsigned long vbflags)
 {
-   u16 xres, yres, myres;
+   u16 xres=0, yres, myres;
 
 #ifdef CONFIG_FB_SIS_300
-   if(sisvga_engine == SIS_300_VGA) {
+   if(ivideo.sisvga_engine == SIS_300_VGA) {
       if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1);
    }
 #endif
 #ifdef CONFIG_FB_SIS_315
-   if(sisvga_engine == SIS_315_VGA) {
+   if(ivideo.sisvga_engine == SIS_315_VGA) {
       if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1);
    }
 #endif
@@ -557,7 +543,7 @@
 
    switch (vbflags & VB_DISPTYPE_DISP2) {
      case CRT2_LCD:
-	switch (sishw_ext.ulCRT2LCDType) {
+	switch(sishw_ext.ulCRT2LCDType) {
 	case LCD_640x480:  xres =  640; yres =  480;  break;
 	case LCD_800x600:  xres =  800; yres =  600;  break;
         case LCD_1024x600: xres = 1024; yres =  600;  break;
@@ -571,6 +557,9 @@
 	case LCD_320x480:  xres =  320; yres =  480;  break; /* FSTN (old) */
 	case LCD_640x480_2:
 	case LCD_640x480_3:xres =  640; yres =  480;  break; /* FSTN (new) */
+	case LCD_1680x1050:xres = 1680; yres = 1050;  break;
+	case LCD_1280x800: xres = 1280; yres =  800;  break;
+	case LCD_1280x720: yres = 1280; yres =  720;  break;
 	default:           xres =    0; yres =    0;  break;
 	}
 
@@ -602,21 +591,21 @@
 	   }
 	}
 
-	if(SiS_GetModeID_LCD(sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres,
+	if(SiS_GetModeID_LCD(ivideo.sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres,
 	                     0, sisfb_fstn, SiS_Pr.SiS_CustomT, xres, yres) < 0x14) {
 	   return(-1);
 	}
 	break;
 
-     case CRT2_TV:  
-	if(SiS_GetModeID_TV(sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+     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_VGA:
-        if(SiS_GetModeID_VGA2(sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+        if(SiS_GetModeID_VGA2(ivideo.sisvga_engine, vbflags, sisbios_mode[myindex].xres,
 	                    sisbios_mode[myindex].yres, 0) < 0x14) {
 	   return(-1);
 	}
@@ -626,49 +615,9 @@
      return(myindex);
 }
 
-static void sisfb_search_crt2type(const char *name)
-{
-	int i = 0;
 
-	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_dstn = (sis_crt2type[i].flags & FL_550_DSTN) ? 1 : 0;
-			sisfb_fstn = (sis_crt2type[i].flags & FL_550_FSTN) ? 1 : 0;
-			break;
-		}
-		i++;
-	}
-	if(sisfb_crt2type < 0)
-		printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
-        if(ivideo.chip != SIS_550) {
-	   sisfb_dstn = sisfb_fstn = 0;
-	}
-}
-
-static void sisfb_search_queuemode(const char *name)
-{
-	int i = 0;
-
-	if(name == NULL)
-		return;
-
-	while (sis_queuemode[i].type_no != -1) {
-		if (!strnicmp(name, sis_queuemode[i].name, strlen(sis_queuemode[i].name))) {
-			sisfb_queuemode = sis_queuemode[i].type_no;
-			break;
-		}
-		i++;
-	}
-	if (sisfb_queuemode < 0)
-		printk(KERN_ERR "sisfb: Invalid queuemode type: %s\n", name);
-}
-
-static u8 sisfb_search_refresh_rate(unsigned int rate, int mode_idx)
+static u8
+sisfb_search_refresh_rate(unsigned int rate, int mode_idx)
 {
 	u16 xres, yres;
 	int i = 0;
@@ -676,37 +625,37 @@
 	xres = sisbios_mode[mode_idx].xres;
 	yres = sisbios_mode[mode_idx].yres;
 
-	sisfb_rate_idx = 0;
+	ivideo.rate_idx = 0;
 	while ((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
 		if ((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
 			if (sisfb_vrate[i].refresh == rate) {
-				sisfb_rate_idx = sisfb_vrate[i].idx;
+				ivideo.rate_idx = sisfb_vrate[i].idx;
 				break;
 			} else if (sisfb_vrate[i].refresh > rate) {
 				if ((sisfb_vrate[i].refresh - rate) <= 3) {
 					DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
 						rate, sisfb_vrate[i].refresh);
-					sisfb_rate_idx = sisfb_vrate[i].idx;
+					ivideo.rate_idx = sisfb_vrate[i].idx;
 					ivideo.refresh_rate = sisfb_vrate[i].refresh;
 				} else if (((rate - sisfb_vrate[i-1].refresh) <= 2)
 						&& (sisfb_vrate[i].idx != 1)) {
 					DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
 						rate, sisfb_vrate[i-1].refresh);
-					sisfb_rate_idx = sisfb_vrate[i-1].idx;
+					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);
-	           		sisfb_rate_idx = sisfb_vrate[i].idx;
+	           		ivideo.rate_idx = sisfb_vrate[i].idx;
 		   		break;
 	       		}
 		}
 		i++;
 	}
-	if (sisfb_rate_idx > 0) {
-		return sisfb_rate_idx;
+	if(ivideo.rate_idx > 0) {
+		return ivideo.rate_idx;
 	} else {
 		printk(KERN_INFO
 			"sisfb: Unsupported rate %d for %dx%d\n", rate, xres, yres);
@@ -714,78 +663,27 @@
 	}
 }
 
-static void sisfb_search_tvstd(const char *name)
-{
-	int i = 0;
-
-	if(name == NULL)
-		return;
-
-	while (sis_tvtype[i].type_no != -1) {
-		if (!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
-			ivideo.vbflags |= sis_tvtype[i].type_no;
-			break;
-		}
-		i++;
-	}
-}
-
-static void sisfb_search_specialtiming(const char *name)
-{
-	int i = 0;
-	BOOLEAN found = FALSE;
-
-	if(name == NULL)
-		return;
-
-	if(!strnicmp(name, "none", 4)) {
-	        SiS_Pr.SiS_CustomT = 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))) {
-		 SiS_Pr.SiS_CustomT = 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++;
-	      }
-           }
- 	}
-}
 
-static BOOLEAN sisfb_bridgeisslave(void)
+static BOOLEAN
+sisfb_bridgeisslave(void)
 {
    unsigned char P1_00;
 
    if(!(ivideo.vbflags & VB_VIDEOBRIDGE)) return FALSE;
 
    inSISIDXREG(SISPART1,0x00,P1_00);
-   if( ((sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
-       ((sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
+   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(void)
+static BOOLEAN
+sisfballowretracecrt1(void)
 {
-   unsigned char temp;
+   u8 temp;
 
    inSISIDXREG(SISCR,0x17,temp);
    if(!(temp & 0x80)) return FALSE;
@@ -796,16 +694,17 @@
    return TRUE;
 }
 
-static BOOLEAN sisfbcheckvretracecrt1(void)
+static BOOLEAN
+sisfbcheckvretracecrt1(void)
 {
-
    if(!sisfballowretracecrt1()) return FALSE;
 
    if(inSISREG(SISINPSTAT) & 0x08) return TRUE;
    else 			   return FALSE;
 }
 
-static void sisfbwaitretracecrt1(void)
+static void
+sisfbwaitretracecrt1(void)
 {
    int watchdog;
 
@@ -817,11 +716,12 @@
    while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
 }
 
-static BOOLEAN sisfbcheckvretracecrt2(void)
+static BOOLEAN
+sisfbcheckvretracecrt2(void)
 {
    unsigned char temp, reg;
 
-   switch(sisvga_engine) {
+   switch(ivideo.sisvga_engine) {
    case SIS_300_VGA:
    	reg = 0x25;
 	break;
@@ -837,7 +737,8 @@
    else 	   return TRUE;
 }
 
-static BOOLEAN sisfb_CheckVBRetrace(void)
+static BOOLEAN
+sisfb_CheckVBRetrace(void)
 {
    if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
       if(sisfb_bridgeisslave()) {
@@ -849,7 +750,8 @@
    return(sisfbcheckvretracecrt1());
 }
 
-static int sisfb_myblank(int blank)
+static int
+sisfb_myblank(int blank)
 {
    u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
    BOOLEAN backlight = TRUE;
@@ -912,8 +814,8 @@
           ((sisfb_thismonitor.datavalid) &&
            (sisfb_thismonitor.feature & 0xe0))) {
 
-	 if(sisvga_engine == SIS_315_VGA) {
-	    setSISIDXREG(SISCR, 0x63, 0xbf, cr63);
+	 if(ivideo.sisvga_engine == SIS_315_VGA) {
+	    setSISIDXREG(SISCR, SiS_Pr.SiS_MyCR63, 0xbf, cr63);
 	 }
 
 	 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
@@ -929,7 +831,7 @@
 	 } else {
 	    SiS_SiS30xBLOff(&SiS_Pr, &sishw_ext);
 	 }
-      } else if(sisvga_engine == SIS_315_VGA) {
+      } else if(ivideo.sisvga_engine == SIS_315_VGA) {
 	 if(ivideo.vbflags & VB_CHRONTEL) {
 	    if(backlight) {
 	       SiS_Chrontel701xBLOn(&SiS_Pr,&sishw_ext);
@@ -939,19 +841,19 @@
 	 }
       }
 
-      if(((sisvga_engine == SIS_300_VGA) &&
+      if(((ivideo.sisvga_engine == SIS_300_VGA) &&
           (ivideo.vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
-         ((sisvga_engine == SIS_315_VGA) &&
+         ((ivideo.sisvga_engine == SIS_315_VGA) &&
           ((ivideo.vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
           setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
       }
 
-      if(sisvga_engine == SIS_300_VGA) {
+      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(sisvga_engine == SIS_315_VGA) {
+      } 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);
@@ -971,7 +873,8 @@
 
 /* ----------- FBDev related routines for all series ----------- */
 
-static void sisfb_set_vparms(void)
+static void
+sisfb_set_vparms(void)
 {
    switch(ivideo.video_bpp) {
    case 8:
@@ -997,7 +900,8 @@
    }
 }
 
-static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
+static int
+sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
 		      struct fb_info *info)
 {
 	unsigned int htotal = 0, vtotal = 0; 
@@ -1034,11 +938,6 @@
 	   ivideo.refresh_rate = (unsigned int) (hrate * 2 / vtotal);
 	} else ivideo.refresh_rate = 60;
 
-#if 0
-	printk(KERN_DEBUG "sisfb: Change mode to %dx%dx%d-%dHz\n",
-		var->xres,var->yres,var->bits_per_pixel,ivideo.refresh_rate);
-#endif		
-
 	old_mode = sisfb_mode_idx;
 	sisfb_mode_idx = 0;
 
@@ -1047,7 +946,7 @@
 		if( (sisbios_mode[sisfb_mode_idx].xres == var->xres) &&
 		    (sisbios_mode[sisfb_mode_idx].yres == var->yres) &&
 		    (sisbios_mode[sisfb_mode_idx].bpp == var->bits_per_pixel)) {
-			sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no;
+			ivideo.mode_no = sisbios_mode[sisfb_mode_idx].mode_no;
 			found_mode = 1;
 			break;
 		}
@@ -1067,14 +966,14 @@
 	}
 
 	if(sisfb_search_refresh_rate(ivideo.refresh_rate, sisfb_mode_idx) == 0) {
-		sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
+		ivideo.rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
 		ivideo.refresh_rate = 60;
 	}
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	if(sisfb_thismonitor.datavalid) {
 	   if(!sisfb_verify_rate(&sisfb_thismonitor, sisfb_mode_idx,
-	                         sisfb_rate_idx, ivideo.refresh_rate)) {
+	                         ivideo.rate_idx, ivideo.refresh_rate)) {
 	      printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
 	   }
 	}
@@ -1087,8 +986,8 @@
 #endif
 		sisfb_pre_setmode();
 
-		if(SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
-			printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", sisfb_mode_no);
+		if(SiSSetMode(&SiS_Pr, &sishw_ext, ivideo.mode_no) == 0) {
+			printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo.mode_no);
 			return -EINVAL;
 		}
 
@@ -1114,7 +1013,7 @@
 		ivideo.current_pixclock = var->pixclock;
 		ivideo.current_refresh_rate = ivideo.refresh_rate;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-                sisfb_lastrates[sisfb_mode_no] = ivideo.refresh_rate;
+                sisfb_lastrates[ivideo.mode_no] = ivideo.refresh_rate;
 #endif
 		
 		sisfb_post_setmode();
@@ -1123,7 +1022,8 @@
 	return 0;
 }
 
-static int sisfb_pan_var(struct fb_var_screeninfo *var)
+static int
+sisfb_pan_var(struct fb_var_screeninfo *var)
 {
 	unsigned int base;
 
@@ -1154,22 +1054,23 @@
         outSISIDXREG(SISCR, 0x0D, base & 0xFF);
 	outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
 	outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
-	if(sisvga_engine == SIS_315_VGA) {
+	if(ivideo.sisvga_engine == SIS_315_VGA) {
 		setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
 	}
         if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
-		orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
+		orSISIDXREG(SISPART1, ivideo.CRT2_write_enable, 0x01);
         	outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
         	outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
         	outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
-		if(sisvga_engine == SIS_315_VGA) {
+		if(ivideo.sisvga_engine == SIS_315_VGA) {
 			setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
 		}
         }
 	return 0;
 }
 
-static void sisfb_bpp_to_var(struct fb_var_screeninfo *var)
+static void
+sisfb_bpp_to_var(struct fb_var_screeninfo *var)
 {
 	switch(var->bits_per_pixel) {
 	   case 8:
@@ -1202,7 +1103,8 @@
 	}
 }
 
-void sis_dispinfo(struct ap_data *rec)
+void
+sis_dispinfo(struct ap_data *rec)
 {
 	rec->minfo.bpp      = ivideo.video_bpp;
 	rec->minfo.xres     = ivideo.video_width;
@@ -1228,7 +1130,8 @@
 
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
 
-static void sisfb_crtc_to_var(struct fb_var_screeninfo *var)
+static void
+sisfb_crtc_to_var(struct fb_var_screeninfo *var)
 {
 	u16 VRE, VBE, VRS, VBS, VDE, VT;
 	u16 HRE, HBE, HRS, HBS, HDE, HT;
@@ -1417,10 +1320,11 @@
 
 }
 
-static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
+static int
+sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
 			 unsigned *transp, struct fb_info *fb_info)
 {
-	if (regno >= ivideo.video_cmap_len)
+	if(regno >= ivideo.video_cmap_len)
 		return 1;
 
 	*red = sis_palette[regno].red;
@@ -1430,24 +1334,25 @@
 	return 0;
 }
 
-static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+static int
+sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
                            unsigned transp, struct fb_info *fb_info)
 {
-	if (regno >= ivideo.video_cmap_len)
+	if(regno >= ivideo.video_cmap_len)
 		return 1;
 
 	sis_palette[regno].red = red;
 	sis_palette[regno].green = green;
 	sis_palette[regno].blue = blue;
 
-	switch (ivideo.video_bpp) {
+	switch(ivideo.video_bpp) {
 #ifdef FBCON_HAS_CFB8
 	case 8:
 	        outSISREG(SISDACA, regno);
 		outSISREG(SISDACD, (red >> 10));
 		outSISREG(SISDACD, (green >> 10));
 		outSISREG(SISDACD, (blue >> 10));
-		if (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
+		if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
 		        outSISREG(SISDAC2A, regno);
 			outSISREG(SISDAC2D, (red >> 8));
 			outSISREG(SISDAC2D, (green >> 8));
@@ -1473,7 +1378,8 @@
 	return 0;
 }
 
-static void sisfb_set_disp(int con, struct fb_var_screeninfo *var,
+static void
+sisfb_set_disp(int con, struct fb_var_screeninfo *var,
                            struct fb_info *info)
 {
 	struct fb_fix_screeninfo fix;
@@ -1502,7 +1408,7 @@
 
 	save_flags(flags);
 
-	switch (ivideo.video_bpp) {
+	switch(ivideo.video_bpp) {
 #ifdef FBCON_HAS_CFB8
 	   case 8:
 #ifdef SISFBACCEL
@@ -1548,12 +1454,13 @@
 	}
 }
 
-static void sisfb_do_install_cmap(int con, struct fb_info *info)
+static void
+sisfb_do_install_cmap(int con, struct fb_info *info)
 {
-        if (con != currcon)
+        if(con != currcon)
 		return;
 
-        if (fb_display[con].cmap.len)
+        if(fb_display[con].cmap.len)
 		fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
         else
 		fb_set_cmap(fb_default_cmap(ivideo.video_cmap_len), 1,
@@ -1561,7 +1468,8 @@
 }
 
 
-static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
+static int
+sisfb_get_var(struct fb_var_screeninfo *var, int con,
 			 struct fb_info *info)
 {
 	if(con == -1)
@@ -1577,7 +1485,8 @@
 	return 0;
 }
 
-static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
+static int
+sisfb_set_var(struct fb_var_screeninfo *var, int con,
 			 struct fb_info *info)
 {
 	int err;
@@ -1611,10 +1520,11 @@
 	return 0;
 }
 
-static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+static int
+sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
 			  struct fb_info *info)
 {
-        if (con == currcon)
+        if(con == currcon)
 		return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
 
 	else if (fb_display[con].cmap.len)
@@ -1625,18 +1535,19 @@
 	return 0;
 }
 
-static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+static int
+sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 			  struct fb_info *info)
 {
 	int err;
 
-	if (!fb_display[con].cmap.len) {
+	if(!fb_display[con].cmap.len) {
 		err = fb_alloc_cmap(&fb_display[con].cmap, ivideo.video_cmap_len, 0);
 		if (err)
 			return err;
 	}
         
-	if (con == currcon)
+	if(con == currcon)
 		return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
 
 	else
@@ -1645,17 +1556,18 @@
 	return 0;
 }
 
-static int sisfb_pan_display(struct fb_var_screeninfo *var, int con,
+static int
+sisfb_pan_display(struct fb_var_screeninfo *var, int con,
 			     struct fb_info* info)
 {
 	int err;
 
-	if (var->vmode & FB_VMODE_YWRAP) {
-		if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
+	if(var->vmode & FB_VMODE_YWRAP) {
+		if(var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
 			return -EINVAL;
 	} else {
-		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->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)
 			return -EINVAL;
 	}
 
@@ -1665,7 +1577,7 @@
 
 	fb_display[con].var.xoffset = var->xoffset;
 	fb_display[con].var.yoffset = var->yoffset;
-	if (var->vmode & FB_VMODE_YWRAP)
+	if(var->vmode & FB_VMODE_YWRAP)
 		fb_display[con].var.vmode |= FB_VMODE_YWRAP;
 	else
 		fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
@@ -1673,15 +1585,16 @@
 	return 0;
 }
 
-static int sisfb_mmap(struct fb_info *info, struct file *file,
+static int
+sisfb_mmap(struct fb_info *info, struct file *file,
 		      struct vm_area_struct *vma)
 {
 	struct fb_var_screeninfo var;
 	unsigned long start;
 	unsigned long off;
-	u32 len, mmio_off;
+	unsigned long len, mmio_off;
 
-	if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT))  return -EINVAL;
+	if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL;
 
 	off = vma->vm_pgoff << PAGE_SHIFT;
 
@@ -1701,7 +1614,7 @@
 		if(var.accel_flags) return -EINVAL;
 
 		start = (unsigned long) ivideo.mmio_base;
-		len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);
+		len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.mmio_size);
 	}
 
 	start &= PAGE_MASK;
@@ -1712,18 +1625,19 @@
 	vma->vm_flags |= VM_IO;   /* by Jake Page; is that really needed? */
 
 #if defined(__i386__) || defined(__x86_64__)
-	if (boot_cpu_data.x86 > 3)
+	if(boot_cpu_data.x86 > 3)
 		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
 #endif
         /* RedHat requires vma as the first paramater to the following call */
-	if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
-				vma->vm_page_prot))
+	if(io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot))
 		return -EAGAIN;
 
 	return 0;
 }
 
-static void sis_get_glyph(struct fb_info *info, SIS_GLYINFO *gly)
+static void
+sis_get_glyph(struct fb_info *info, SIS_GLYINFO *gly)
 {
 	struct display *p = &fb_display[currcon];
 	u16 c;
@@ -1737,7 +1651,7 @@
 	widthb = (fontwidth(p) + 7) / 8;
 
 	c = gly->ch & p->charmask;
-	if (fontwidth(p) <= 8)
+	if(fontwidth(p) <= 8)
 		cdat = p->fontdata + c * fontheight(p);
 	else
 		cdat = p->fontdata + (c * fontheight(p) << 1);
@@ -1747,12 +1661,14 @@
 	gly->ngmask = size;
 }
 
-static int sisfb_update_var(int con, struct fb_info *info)
+static int
+sisfb_update_var(int con, struct fb_info *info)
 {
         return(sisfb_pan_var(&fb_display[con].var));
 }
 
-static int sisfb_switch(int con, struct fb_info *info)
+static int
+sisfb_switch(int con, struct fb_info *info)
 {
 	int cols, rows;
 
@@ -1784,7 +1700,8 @@
 	return 1;
 }
 
-static void sisfb_blank(int blank, struct fb_info *info)
+static void
+sisfb_blank(int blank, struct fb_info *info)
 {
 	sisfb_myblank(blank);
 }
@@ -1794,17 +1711,20 @@
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 
-static int sisfb_open(struct fb_info *info, int user)
+static int
+sisfb_open(struct fb_info *info, int user)
 {
     return 0;
 }
 
-static int sisfb_release(struct fb_info *info, int user)
+static int
+sisfb_release(struct fb_info *info, int user)
 {
     return 0;
 }
 
-static int sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
+static int
+sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
 {
 	int rc = 16;		
 
@@ -1820,19 +1740,20 @@
 	return rc;
 }
 
-static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
-                           unsigned transp, struct fb_info *info)
+static int
+sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+		unsigned transp, struct fb_info *info)
 {
-	if (regno >= sisfb_get_cmap_len(&info->var))
+	if(regno >= sisfb_get_cmap_len(&info->var))
 		return 1;
 
-	switch (info->var.bits_per_pixel) {
+	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) {
+		if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
 		        outSISREG(SISDAC2A, regno);
 			outSISREG(SISDAC2D, (red >> 8));
 			outSISREG(SISDAC2D, (green >> 8));
@@ -1854,7 +1775,8 @@
 	return 0;
 }
 
-static int sisfb_set_par(struct fb_info *info)
+static int
+sisfb_set_par(struct fb_info *info)
 {
 	int err;
 
@@ -1866,8 +1788,9 @@
 	return 0;
 }
 
-static int sisfb_check_var(struct fb_var_screeninfo *var,
-                           struct fb_info *info)
+static int
+sisfb_check_var(struct fb_var_screeninfo *var,
+                   struct fb_info *info)
 {
 	unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
 	unsigned int drate = 0, hrate = 0, maxyres;
@@ -1912,7 +1835,6 @@
 	}
 
 	if(!found_mode) {
-
                 search_idx = 0;
 		while(sisbios_mode[search_idx].mode_no != 0) {
 		   if( (var->xres <= sisbios_mode[search_idx].xres) &&
@@ -2051,32 +1973,33 @@
 	return 0;
 }
 
-static int sisfb_pan_display(struct fb_var_screeninfo *var,
-			     struct fb_info* info)
+static int
+sisfb_pan_display(struct fb_var_screeninfo *var,
+		     struct fb_info* info)
 {
 	int err;
 
-	if (var->xoffset > (var->xres_virtual - var->xres))
+	if(var->xoffset > (var->xres_virtual - var->xres))
 		return -EINVAL;
-	if (var->yoffset > (var->yres_virtual - var->yres))
+	if(var->yoffset > (var->yres_virtual - var->yres))
 		return -EINVAL;
 
-	if (var->vmode & FB_VMODE_YWRAP) {
-		if (var->yoffset < 0 ||
-		    var->yoffset >= info->var.yres_virtual ||
-		    var->xoffset)
+	if(var->vmode & FB_VMODE_YWRAP) {
+		if(var->yoffset < 0 ||
+		   var->yoffset >= info->var.yres_virtual ||
+		   var->xoffset)
 		    	return -EINVAL;
 	} else {
-		if (var->xoffset + info->var.xres > info->var.xres_virtual ||
-		    var->yoffset + info->var.yres > info->var.yres_virtual)
+		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(var)) < 0) return err;
 
 	info->var.xoffset = var->xoffset;
 	info->var.yoffset = var->yoffset;
-	if (var->vmode & FB_VMODE_YWRAP)
+	if(var->vmode & FB_VMODE_YWRAP)
 		info->var.vmode |= FB_VMODE_YWRAP;
 	else
 		info->var.vmode &= ~FB_VMODE_YWRAP;
@@ -2084,12 +2007,13 @@
 	return 0;
 }
 
-static int sisfb_mmap(struct fb_info *info, struct file *file,
+static int
+sisfb_mmap(struct fb_info *info, struct file *file,
 		      struct vm_area_struct *vma)
 {
 	unsigned long start;
 	unsigned long off;
-	u32 len, mmio_off;
+	unsigned long len, mmio_off;
 
 	if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT))  return -EINVAL;
 
@@ -2110,7 +2034,7 @@
 		if(info->var.accel_flags) return -EINVAL;
 
 		start = (unsigned long) ivideo.mmio_base;
-		len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);
+		len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.mmio_size);
 	}
 
 	start &= PAGE_MASK;
@@ -2131,7 +2055,8 @@
 	return 0;
 }
 
-static int sisfb_blank(int blank, struct fb_info *info)
+static int
+sisfb_blank(int blank, struct fb_info *info)
 {
 	return(sisfb_myblank(blank));
 }
@@ -2207,8 +2132,8 @@
 		{
 			unsigned long myhwcoffset = 0;
 
-			if(sisfb_caps & HW_CURSOR_CAP)
-				myhwcoffset = sisfb_hwcursor_vbase -
+			if(ivideo.caps & HW_CURSOR_CAP)
+				myhwcoffset = ivideo.hwcursor_vbase -
 				    (unsigned long) ivideo.video_vbase;
 
 			return put_user(myhwcoffset, (unsigned long *)arg);
@@ -2231,14 +2156,19 @@
 			x.chip_id = ivideo.chip_id;
 			x.memory = ivideo.video_size / 1024;
 			x.heapstart = ivideo.heapstart / 1024;
-			x.fbvidmode = sisfb_mode_no;
-			x.sisfb_caps = sisfb_caps;
+			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 = sisfb_detectedpdc;
-			x.sisfb_lcda = sisfb_detectedlcda;
+			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 = SiS_Pr.UsePanelScaler;
@@ -2287,8 +2217,9 @@
 }
 
 
-static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
+static int
+sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+	      struct fb_info *info)
 {
 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
@@ -2301,7 +2232,7 @@
 	fix->smem_start = ivideo.video_base;
 
         if((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
-	    if(sisvga_engine == SIS_300_VGA) {
+	    if(ivideo.sisvga_engine == SIS_300_VGA) {
 	       if(ivideo.video_size > 0x1000000) {
 	          	fix->smem_len = 0xc00000;
 	       } else if(ivideo.video_size > 0x800000)
@@ -2327,8 +2258,8 @@
 	fix->ywrapstep   = 0;
 	fix->line_length = ivideo.video_linelength;
 	fix->mmio_start  = ivideo.mmio_base;
-	fix->mmio_len    = sisfb_mmio_size;
-	if(sisvga_engine == SIS_300_VGA) 
+	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;
@@ -2338,7 +2269,7 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	fix->reserved[0] = ivideo.video_size & 0xFFFF;
 	fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
-	fix->reserved[2] = sisfb_caps;
+	fix->reserved[2] = ivideo.caps;
 #endif
 
 	return 0;
@@ -2386,14 +2317,14 @@
 
 #ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */
 
-static int sisfb_get_dram_size_300(void)
+static int __devinit sisfb_get_dram_size_300(void)
 {
 	struct pci_dev *pdev = NULL;
 	int pdev_valid = 0;
 	u8  pci_data, reg;
 	u16 nbridge_id;
 
-	switch (ivideo.chip) {
+	switch(ivideo.chip) {
 	   case SIS_540:
 		nbridge_id = PCI_DEVICE_ID_SI_540;
 		break;
@@ -2408,7 +2339,7 @@
 		break;
 	}
 
-	if (nbridge_id == 0) {  /* 300 */
+	if(nbridge_id == 0) {   /* 300 */
 
 	        inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE,reg);
 		ivideo.video_size =
@@ -2427,7 +2358,7 @@
 				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
 				ivideo.video_size = (unsigned int)(1 << (pci_data+21));
 				pdev_valid = 1;
-	
+
 				reg = SIS_DATA_BUS_64 << 6;
 				switch (pci_data) {
 				   case BRI_DRAM_SIZE_2MB:
@@ -2464,7 +2395,7 @@
 
 #ifdef CONFIG_FB_SIS_315    /* for SiS 315/550/650/740/330/661/741/760 */
 
-static int sisfb_get_dram_size_315(void)
+static int __devinit sisfb_get_dram_size_315(void)
 {
 	u8  reg = 0;
 
@@ -2480,9 +2411,7 @@
 		return 0;
 
 	} else if(ivideo.chip == SIS_661 ||
-	          ivideo.chip == SIS_741 ||
-		  ivideo.chip == SIS_660 ||
-		  ivideo.chip == SIS_760) {
+	          ivideo.chip == SIS_741) {
 
 		inSISIDXREG(SISCR, 0x79, reg);
 		reg &= 0xf0;
@@ -2490,6 +2419,22 @@
 		ivideo.video_size = (1 << reg) << 20;
 		return 0;
 
+	} else if(ivideo.chip == SIS_660 ||
+		  ivideo.chip == SIS_760) {
+
+		ivideo.video_size = 0;
+		inSISIDXREG(SISCR, 0x79, reg);
+		reg &= 0xf0;
+		reg >>= 4;
+		if(reg)	ivideo.video_size = (1 << reg) << 20;
+		inSISIDXREG(SISCR, 0x78, reg);
+		reg &= 0x30;
+		if(reg) {
+		   if(reg == 0x10) ivideo.video_size += (32 << 20);
+		   else		   ivideo.video_size += (64 << 20);
+		}
+		return 0;
+
 	} else {	/* 315, 330 */
 
 	        inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
@@ -2529,38 +2474,18 @@
 
 /* -------------- video bridge detection --------------- */
 
-static void sisfb_detect_VB_connect()
+static void __devinit sisfb_detect_VB_connect()
 {
 	u8 sr16, sr17, cr32, temp;
 
-	if(sisvga_engine == SIS_300_VGA) {
+	if(ivideo.sisvga_engine == SIS_300_VGA) {
 	
 		inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_17, sr17);
 	      
 		if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) {
-	
-			/* Old BIOSes store the detected CRT2 type in SR17
-		 	 * instead of CR32. However, since our detection
-			 * routines store their results to CR32, we now copy
-			 * the remaining bits (for LCD and VGA) to CR32 for
-			 * unified usage.
-			 * SR17[0] CRT1    [1] LCD     [2] TV    [3] VGA2
-			 *     [4] AVIDEO  [5] SVIDEO
-			 */
-
-#if 0
-			if (sr17 & 0x01) orSISIDXREG(SISCR, 0x32, SIS_CRT1);
-			else		 andSISIDXREG(SISCR, 0x32, ~SIS_CRT1);
-
-			if (sr17 & 0x02) orSISIDXREG(SISCR, 0x32, SIS_VB_LCD);
-			else		 andSISIDXREG(SISCR, 0x32, ~SIS_VB_LCD);
 
-			/* no HiVision and no DVI connector here */
-			andSISIDXREG(SISCR, 0x32, ~0xc0);
-#endif
-		
 			/* PAL/NTSC is stored on SR16 on such machines */
-			if (!(ivideo.vbflags & (TV_PAL | TV_NTSC))) {
+			if (!(ivideo.vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
 		   		inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_16, sr16);
 				if (sr16 & 0x20)
 					ivideo.vbflags |= TV_PAL;
@@ -2574,69 +2499,54 @@
 	
 	inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32);
 
-	if (cr32 & SIS_CRT1)
+	if(cr32 & SIS_CRT1) {
 		sisfb_crt1off = 0;
-	else {
-		if (cr32 & 0x5F)
-			sisfb_crt1off = 1;
-		else
-			sisfb_crt1off = 0;
+	} else {
+		if (cr32 & 0x5F) sisfb_crt1off = 1;
+		else		 sisfb_crt1off = 0;
 	}
 
 	ivideo.vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
 
-	if (cr32 & SIS_VB_TV)
-		ivideo.vbflags |= CRT2_TV;
-	if (cr32 & SIS_VB_LCD)
-		ivideo.vbflags |= CRT2_LCD;
-	if (cr32 & SIS_VB_CRT2)
-		ivideo.vbflags |= CRT2_VGA;
+	if(cr32 & SIS_VB_TV)   ivideo.vbflags |= CRT2_TV;
+	if(cr32 & SIS_VB_LCD)  ivideo.vbflags |= CRT2_LCD;
+	if(cr32 & SIS_VB_CRT2) ivideo.vbflags |= CRT2_VGA;
 		
-	/* TW: Detect/set TV plug & type */
-	if(sisfb_tvplug != -1)
-	        ivideo.vbflags |= sisfb_tvplug;
+	/* Detect/set TV plug & type */
+	if(sisfb_tvplug != -1) ivideo.vbflags |= sisfb_tvplug;
 
-	if (cr32 & SIS_VB_SVIDEO)
-		ivideo.vbflags |= TV_SVIDEO;
-	else if (cr32 & SIS_VB_COMPOSITE)
-		ivideo.vbflags |= TV_AVIDEO;
-	else if (cr32 & SIS_VB_SCART)
-		ivideo.vbflags |= TV_SCART;
-		
-	if (!(ivideo.vbflags & (TV_PAL | TV_NTSC))) {
-		if(sisvga_engine == SIS_300_VGA) {
+	if(cr32 & SIS_VB_SVIDEO)	  ivideo.vbflags |= TV_SVIDEO;
+	else if (cr32 & SIS_VB_COMPOSITE) ivideo.vbflags |= TV_AVIDEO;
+	else if (cr32 & SIS_VB_SCART) {
+		ivideo.vbflags |= (TV_SCART | TV_PAL);
+		ivideo.vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN);
+	}
+
+	if(!(ivideo.vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
+		if(ivideo.sisvga_engine == SIS_300_VGA) {
 	        	inSISIDXREG(SISSR, IND_SIS_POWER_ON_TRAP, temp);
-			if (temp & 0x01)
-				ivideo.vbflags |= TV_PAL;
-			else
-				ivideo.vbflags |= TV_NTSC;
+			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);
-			if(temp & 0x01)
-				ivideo.vbflags |= TV_PAL;
-			else
-				ivideo.vbflags |= TV_NTSC;
-		
+			if(temp & 0x01) ivideo.vbflags |= TV_PAL;
+			else		ivideo.vbflags |= TV_NTSC;
 	    	} else {
-
 	        	inSISIDXREG(SISCR, 0x79, temp);
-			if(temp & 0x20)
-				ivideo.vbflags |= TV_PAL;
-			else
-				ivideo.vbflags |= TV_NTSC;
+			if(temp & 0x20)	ivideo.vbflags |= TV_PAL;
+			else		ivideo.vbflags |= TV_NTSC;
 	    	}
 	}
 
-	/* TW: Copy forceCRT1 option to CRT1off if option is given */
-    	if (sisfb_forcecrt1 != -1) {
+	/* Copy forceCRT1 option to CRT1off if option is given */
+    	if(sisfb_forcecrt1 != -1) {
     		if(sisfb_forcecrt1) sisfb_crt1off = 0;
 		else                sisfb_crt1off = 1;
     	}
 
 }
 
-static void sisfb_get_VB_type(void)
+static void __devinit sisfb_get_VB_type(void)
 {
 	u8 vb_chipid;
 	u8 reg;
@@ -2648,7 +2558,6 @@
 	ivideo.hasVB = HASVB_NONE;
 	sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN;
 	sishw_ext.Is301BDH = FALSE;
-	sishw_ext.usExternalChip = 0;
 
 	inSISIDXREG(SISPART4, 0x00, vb_chipid);
 	switch (vb_chipid) {
@@ -2693,27 +2602,9 @@
 		break;
 	   case 0x02:
 		ivideo.hasVB = HASVB_302;
-		inSISIDXREG(SISPART4, 0x01, reg);
-		if(reg < 0xd0) {
-			ivideo.vbflags |= VB_302B;
-			sishw_ext.ujVBChipID = VB_CHIP_302B;
-			inSISIDXREG(SISPART4,0x23,reg);
-		  	if(!(reg & 0x02)) {
-			   sishw_ext.Is301BDH = TRUE;
-			   ivideo.vbflags |= VB_30xBDH;
-			   printk(KERN_INFO "%s SiS302B-DH %s\n", stdstr, bridgestr);
-			} else {
-			   printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
-			}
-		} else if(reg < 0xe0) {
-		 	ivideo.vbflags |= VB_301LV;
-			sishw_ext.ujVBChipID = VB_CHIP_301LV;
-			printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
-		} else if(reg <= 0xe1) {
-			ivideo.vbflags |= VB_302LV;
-			sishw_ext.ujVBChipID = VB_CHIP_302LV;
-			printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
-		}
+		ivideo.vbflags |= VB_302B;
+		sishw_ext.ujVBChipID = VB_CHIP_302B;
+		printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
 		break;
 	}
 
@@ -2721,49 +2612,70 @@
 		inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg);
 		reg &= SIS_EXTERNAL_CHIP_MASK;
 		reg >>= 1;
-		if(sisvga_engine == SIS_300_VGA) {
+		if(ivideo.sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
 			switch (reg) {
 			   case SIS_EXTERNAL_CHIP_LVDS:
 				ivideo.hasVB = HASVB_LVDS;
 				ivideo.vbflags |= VB_LVDS;
-				sishw_ext.usExternalChip = 0x01;
 				printk(KERN_INFO "%s %s\n", stdstr, lvdsstr);
 				break;
 			   case SIS_EXTERNAL_CHIP_TRUMPION:
 				ivideo.hasVB = HASVB_TRUMPION;
-				sishw_ext.usExternalChip = 0x02;
+				ivideo.vbflags |= VB_TRUMPION;
 				printk(KERN_INFO "%s Trumpion LCD scaler\n", stdstr);
 				break;
 			   case SIS_EXTERNAL_CHIP_CHRONTEL:
 				ivideo.hasVB = HASVB_CHRONTEL;
 				ivideo.vbflags |= VB_CHRONTEL;
-				sishw_ext.usExternalChip = 0x04;
 				printk(KERN_INFO "%s %s\n", stdstr, chrstr);
 				break;
 			   case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
 				ivideo.hasVB = HASVB_LVDS_CHRONTEL;
 				ivideo.vbflags |= (VB_LVDS | VB_CHRONTEL);
-				sishw_ext.usExternalChip = 0x05;
 				printk(KERN_INFO "%s %s and %s\n", stdstr, lvdsstr, chrstr);
 				break;
 			}
+#endif
 		} else if(ivideo.chip < SIS_661) {
+#ifdef CONFIG_FB_SIS_315
 			switch (reg) {
 	 	   	   case SIS310_EXTERNAL_CHIP_LVDS:
 				ivideo.hasVB = HASVB_LVDS;
 				ivideo.vbflags |= VB_LVDS;
-				sishw_ext.usExternalChip = 0x01;
 				printk(KERN_INFO "%s %s\n", stdstr, lvdsstr);
 				break;
 		   	   case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
 				ivideo.hasVB = HASVB_LVDS_CHRONTEL;
 				ivideo.vbflags |= (VB_LVDS | VB_CHRONTEL);
-				sishw_ext.usExternalChip = 0x05;
 				printk(KERN_INFO "%s %s and %s\n", stdstr, lvdsstr, chrstr);
 				break;
 			}
+#endif
+		} else if(ivideo.chip >= SIS_661) {
+#ifdef CONFIG_FB_SIS_315
+			inSISIDXREG(SISCR, 0x38, reg);
+			reg >>= 5;
+			switch(reg) {
+			   case 0x02:
+			   	ivideo.hasVB = HASVB_LVDS;
+				ivideo.vbflags |= VB_LVDS;
+				printk(KERN_INFO "%s %s\n", stdstr, lvdsstr);
+				break;
+			   case 0x03:
+			   	ivideo.hasVB = HASVB_LVDS_CHRONTEL;
+				ivideo.vbflags |= (VB_LVDS | VB_CHRONTEL);
+				printk(KERN_INFO "%s %s and %s\n", stdstr, lvdsstr, chrstr);
+				break;
+			   case 0x04:
+			        ivideo.hasVB = HASVB_NONE;
+				ivideo.vbflags |= (VB_LVDS | VB_CONEXANT);
+				printk(KERN_INFO "%s Conexant video bridge\n", stdstr);
+				break;
+			}
+#endif
 		}
-	
+
 	}
 	
 	if(ivideo.vbflags & VB_SISBRIDGE) {
@@ -2776,8 +2688,7 @@
 
 /* ------------------ Sensing routines ------------------ */
 
-static BOOLEAN
-sisfb_test_DDC1(void)
+static BOOLEAN __devinit sisfb_test_DDC1(void)
 {
     unsigned short old;
     int count = 48;
@@ -2789,8 +2700,7 @@
     return (count == -1) ? FALSE : TRUE;
 }
 
-static void
-sisfb_sense_crt1(void)
+static void __devinit sisfb_sense_crt1(void)
 {
     unsigned char SR1F, CR63=0, CR17;
     unsigned short temp = 0xffff;
@@ -2802,10 +2712,10 @@
     andSISIDXREG(SISSR,0x1F,0x3F);
     if(SR1F & 0xc0) mustwait = TRUE;
 
-    if(sisvga_engine == SIS_315_VGA) {
-       inSISIDXREG(SISCR,0x63,CR63);
+    if(ivideo.sisvga_engine == SIS_315_VGA) {
+       inSISIDXREG(SISCR,SiS_Pr.SiS_MyCR63,CR63);
        CR63 &= 0x40;
-       andSISIDXREG(SISCR,0x63,0xBF);
+       andSISIDXREG(SISCR,SiS_Pr.SiS_MyCR63,0xBF);
     }
 
     inSISIDXREG(SISCR,0x17,CR17);
@@ -2823,7 +2733,7 @@
 
     i = 3;
     do {
-       temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine, 0, 0, NULL);
+       temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, ivideo.sisvga_engine, 0, 0, NULL);
     } while(((temp == 0) || (temp == 0xffff)) && i--);
 
     if((temp == 0) || (temp == 0xffff)) {
@@ -2834,8 +2744,8 @@
        orSISIDXREG(SISCR,0x32,0x20);
     }
 
-    if(sisvga_engine == SIS_315_VGA) {
-       setSISIDXREG(SISCR,0x63,0xBF,CR63);
+    if(ivideo.sisvga_engine == SIS_315_VGA) {
+       setSISIDXREG(SISCR,SiS_Pr.SiS_MyCR63,0xBF,CR63);
     }
 
     setSISIDXREG(SISCR,0x17,0x7F,CR17);
@@ -2844,8 +2754,7 @@
 }
 
 /* Determine and detect attached devices on SiS30x */
-int
-SISDoSense(int tempbl, int tempbh, int tempcl, int tempch)
+static int __devinit SISDoSense(int tempbl, int tempbh, int tempcl, int tempch)
 {
     int temp;
 
@@ -2860,8 +2769,7 @@
     return((temp == tempch));
 }
 
-void
-SiS_Sense30x(void)
+static void __devinit SiS_Sense30x(void)
 {
   u8 backupP4_0d,backupP2_00;
   u8 svhs_bl, svhs_bh;
@@ -2880,7 +2788,7 @@
   inSISIDXREG(SISPART2,0x00,backupP2_00);
   outSISIDXREG(SISPART2,0x00,(backupP2_00 | 0x1c));
 
-  if(sisvga_engine == SIS_300_VGA) {
+  if(ivideo.sisvga_engine == SIS_300_VGA) {
 
 	if(ivideo.vbflags & (VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV)) {
 	   	vga2_bh = 0x01; vga2_bl = 0x90;
@@ -2890,20 +2798,21 @@
 		vga2_bh = 0x00; vga2_bl = 0xd1;
         	svhs_bh = 0x00; svhs_bl = 0xb9;
 		cvbs_bh = 0x00; cvbs_bl = 0xb3;
+		inSISIDXREG(SISPART4,0x01,myflag);
+	        if(myflag & 0x04) {
+	           vga2_bh = 0x00; vga2_bl = 0xfd;
+	           svhs_bh = 0x00; svhs_bl = 0xdd;
+	      	   cvbs_bh = 0x00; cvbs_bl = 0xee;
+	        }
 	}
-	inSISIDXREG(SISPART4,0x01,myflag);
-	if(myflag & 0x04) {
-	   vga2_bh = 0x00; vga2_bl = 0xfd;
-	   svhs_bh = 0x00; svhs_bl = 0xdd;
-	   cvbs_bh = 0x00; cvbs_bl = 0xee;
-	}
+
 	vga2_ch = 0x0e;	vga2_cl = 0x08;
 	svhs_ch = 0x04;	svhs_cl = 0x04;
 	cvbs_ch = 0x08; cvbs_cl = 0x04;
 	if(ivideo.vbflags & (VB_301LV|VB_302LV)) {
 	   	vga2_bh = 0x00; vga2_bl = 0x00;
 	   	vga2_ch = 0x00; vga2_cl = 0x00;
-	 }
+	}
 	if(ivideo.chip == SIS_300) {
 	   inSISIDXREG(SISSR,0x3b,myflag);
 	   if(!(myflag & 0x01)) {
@@ -2968,10 +2877,6 @@
        }
     }
 
-    if(ivideo.vbflags & (VB_301C|VB_302ELV)) {
-       orSISIDXREG(SISPART4,0x0d,0x04);
-    }
-
     haveresult = 0;
     for(j = 0; j < 10; j++) {
        result = 0;
@@ -3014,11 +2919,9 @@
     outSISIDXREG(SISPART4,0x0d,backupP4_0d);
 }
 
-/* TW: Determine and detect attached TV's on Chrontel */
-void
-SiS_SenseCh(void)
+/* Determine and detect attached TV's on Chrontel */
+static void __devinit SiS_SenseCh(void)
 {
-
    u8 temp1, temp2;
 #ifdef CONFIG_FB_SIS_300
    unsigned char test[3];
@@ -3143,16 +3046,17 @@
 
 /* ------------------------ Heap routines -------------------------- */
 
-static int sisfb_heap_init(void)
+static int __devinit
+sisfb_heap_init(void)
 {
 	SIS_OH *poh;
 	u8 temp=0;
 #ifdef CONFIG_FB_SIS_315
 	int            agp_enabled = 1;
 	u32            agp_size;
-	unsigned long *cmdq_baseport = 0;
-	unsigned long *read_port = 0;
-	unsigned long *write_port = 0;
+	unsigned long  *cmdq_baseport = 0;
+	unsigned long  *read_port = 0;
+	unsigned long  *write_port = 0;
 	SIS_CMDTYPE    cmd_type;
 #ifndef AGPOFF
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
@@ -3162,7 +3066,7 @@
 	agp_kern_info  *agp_info;
 	agp_memory     *agp;
 #endif
-	u32            agp_phys;
+	unsigned long  agp_phys;
 #endif
 #endif
 /*     The heap start is either set manually using the "mem" parameter, or
@@ -3179,8 +3083,8 @@
  *     On the 315 and Xabre series, the default is a 1MB heap since DRI is not
  *     supported there.
  */
-     if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
-        if(sisvga_engine == SIS_300_VGA) {
+     if((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
+        if(ivideo.sisvga_engine == SIS_300_VGA) {
            if (ivideo.video_size > 0x1000000) {
 	        ivideo.heapstart = 0xc00000;
 	   } else if (ivideo.video_size > 0x800000) {
@@ -3194,8 +3098,7 @@
      } else {
            ivideo.heapstart = sisfb_mem * 1024;
      }
-     sisfb_heap_start =
-	       (unsigned long) (ivideo.video_vbase + ivideo.heapstart);
+     sisfb_heap_start = (unsigned long) (ivideo.video_vbase + ivideo.heapstart);
      printk(KERN_INFO "sisfb: Memory heap starting at %dK\n",
      					(int)(ivideo.heapstart / 1024));
 
@@ -3203,8 +3106,8 @@
      sisfb_heap_size = sisfb_heap_end - sisfb_heap_start;
 
 #ifdef CONFIG_FB_SIS_315
-     if (sisvga_engine == SIS_315_VGA) {
-        /* Now initialize the 310 series' command queue mode.
+     if(ivideo.sisvga_engine == SIS_315_VGA) {
+        /* Now initialize the 315/330 series' command queue mode.
 	 * On 315, there are three queue modes available which
 	 * are chosen by setting bits 7:5 in SR26:
 	 * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
@@ -3275,12 +3178,11 @@
 	agp_enabled = 0;
 #endif
 
-	/* TW: Now select the queue mode */
+	/* Now select the queue mode */
 
-	if ((agp_enabled) && (sisfb_queuemode == AGP_CMD_QUEUE)) {
+	if((agp_enabled) && (sisfb_queuemode == AGP_CMD_QUEUE)) {
 		cmd_type = AGP_CMD_QUEUE;
 		printk(KERN_INFO "sisfb: Using AGP queue mode\n");
-/*	} else if (sisfb_heap_size >= COMMAND_QUEUE_AREA_SIZE)  */
         } else if (sisfb_queuemode == VM_CMD_QUEUE) {
 		cmd_type = VM_CMD_QUEUE;
 		printk(KERN_INFO "sisfb: Using VRAM queue mode\n");
@@ -3326,7 +3228,7 @@
 
 		*cmdq_baseport = agp_phys;
 
-		sisfb_caps |= AGP_CMD_QUEUE_CAP;
+		ivideo.caps |= AGP_CMD_QUEUE_CAP;
 #endif
 		break;
 
@@ -3345,10 +3247,8 @@
 
 		*cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
 
-		sisfb_caps |= VM_CMD_QUEUE_CAP;
+		ivideo.caps |= VM_CMD_QUEUE_CAP;
 
-		DPRINTK("sisfb: VM Cmd Queue offset = 0x%lx, size is %dK\n",
-			*cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
 		break;
 
 	   default:  /* MMIO */
@@ -3366,18 +3266,16 @@
 
 		*cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
 
-		sisfb_caps |= MMIO_CMD_QUEUE_CAP;
+		ivideo.caps |= MMIO_CMD_QUEUE_CAP;
 
-		DPRINTK("sisfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n",
-			*cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
 		break;
 	}
      } /* sisvga_engine = 315 */
 #endif
 
 #ifdef CONFIG_FB_SIS_300
-     if (sisvga_engine == SIS_300_VGA) {
-  	    /* TW: Now initialize TurboQueue. TB is always located at the very
+     if(ivideo.sisvga_engine == SIS_300_VGA) {
+  	    /* Now initialize TurboQueue. TB is always located at the very
 	     * top of the video RAM. */
 	    if (sisfb_heap_size >= TURBO_QUEUE_AREA_SIZE) {
 		unsigned int  tqueue_pos;
@@ -3396,26 +3294,22 @@
 
 		outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, temp);
 
-		sisfb_caps |= TURBO_QUEUE_CAP;
+		ivideo.caps |= TURBO_QUEUE_CAP;
 
 		sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
 		sisfb_heap_size -= TURBO_QUEUE_AREA_SIZE;
-		DPRINTK("sisfb: TurboQueue start at 0x%lx, size is %dK\n",
-			sisfb_heap_end, TURBO_QUEUE_AREA_SIZE/1024);
+
 	    }
      }
 #endif
-     /* TW: Now reserve memory for the HWCursor. It is always located at the very
-            top of the videoRAM, right below the TB memory area (if used). */
-     if (sisfb_heap_size >= sisfb_hwcursor_size) {
-		sisfb_heap_end -= sisfb_hwcursor_size;
-		sisfb_heap_size -= sisfb_hwcursor_size;
-		sisfb_hwcursor_vbase = sisfb_heap_end;
+     /* Now reserve memory for the HWCursor. It is always located at the very
+        top of the videoRAM, right below the TB memory area (if used). */
+     if(sisfb_heap_size >= ivideo.hwcursor_size) {
+		sisfb_heap_end -= ivideo.hwcursor_size;
+		sisfb_heap_size -= ivideo.hwcursor_size;
+		ivideo.hwcursor_vbase = sisfb_heap_end;
 
-		sisfb_caps |= HW_CURSOR_CAP;
-
-		DPRINTK("sisfb: Hardware Cursor start at 0x%lx, size is %dK\n",
-			sisfb_heap_end, sisfb_hwcursor_size/1024);
+		ivideo.caps |= HW_CURSOR_CAP;
      }
 
      sisfb_heap.poha_chain = NULL;
@@ -3449,14 +3343,15 @@
      return 0;
 }
 
-static SIS_OH *sisfb_poh_new_node(void)
+static SIS_OH *
+sisfb_poh_new_node(void)
 {
 	int           i;
 	unsigned long cOhs;
 	SIS_OHALLOC   *poha;
 	SIS_OH        *poh;
 
-	if (sisfb_heap.poh_freelist == NULL) {
+	if(sisfb_heap.poh_freelist == NULL) {
 		poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
 		if(!poha) return NULL;
 
@@ -3466,7 +3361,7 @@
 		cOhs = (OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
 
 		poh = &poha->aoh[0];
-		for (i = cOhs - 1; i != 0; i--) {
+		for(i = cOhs - 1; i != 0; i--) {
 			poh->poh_next = poh + 1;
 			poh = poh + 1;
 		}
@@ -3481,13 +3376,14 @@
 	return (poh);
 }
 
-static SIS_OH *sisfb_poh_allocate(unsigned long size)
+static SIS_OH *
+sisfb_poh_allocate(unsigned long size)
 {
 	SIS_OH *pohThis;
 	SIS_OH *pohRoot;
 	int     bAllocated = 0;
 
-	if (size > sisfb_heap.max_freesize) {
+	if(size > sisfb_heap.max_freesize) {
 		DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
 			(unsigned int) size / 1024);
 		return (NULL);
@@ -3495,7 +3391,7 @@
 
 	pohThis = sisfb_heap.oh_free.poh_next;
 
-	while (pohThis != &sisfb_heap.oh_free) {
+	while(pohThis != &sisfb_heap.oh_free) {
 		if (size <= pohThis->size) {
 			bAllocated = 1;
 			break;
@@ -3503,19 +3399,19 @@
 		pohThis = pohThis->poh_next;
 	}
 
-	if (!bAllocated) {
+	if(!bAllocated) {
 		DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
 			(unsigned int) size / 1024);
 		return (NULL);
 	}
 
-	if (size == pohThis->size) {
+	if(size == pohThis->size) {
 		pohRoot = pohThis;
 		sisfb_delete_node(pohThis);
 	} else {
 		pohRoot = sisfb_poh_new_node();
 
-		if (pohRoot == NULL) {
+		if(pohRoot == NULL) {
 			return (NULL);
 		}
 
@@ -3534,7 +3430,8 @@
 	return (pohRoot);
 }
 
-static void sisfb_delete_node(SIS_OH *poh)
+static void
+sisfb_delete_node(SIS_OH *poh)
 {
 	SIS_OH *poh_prev;
 	SIS_OH *poh_next;
@@ -3544,10 +3441,10 @@
 
 	poh_prev->poh_next = poh_next;
 	poh_next->poh_prev = poh_prev;
-
 }
 
-static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
+static void
+sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
 {
 	SIS_OH *pohTemp;
 
@@ -3560,7 +3457,8 @@
 	poh->poh_next = pohTemp;
 }
 
-static SIS_OH *sisfb_poh_free(unsigned long base)
+static SIS_OH *
+sisfb_poh_free(unsigned long base)
 {
 	SIS_OH *pohThis;
 	SIS_OH *poh_freed;
@@ -3581,7 +3479,7 @@
 		poh_freed = poh_freed->poh_next;
 	}
 
-	if (!foundNode)  return (NULL);
+	if(!foundNode)  return(NULL);
 
 	sisfb_heap.max_freesize += poh_freed->size;
 
@@ -3591,12 +3489,11 @@
 
 	pohThis = sisfb_heap.oh_free.poh_next;
 
-	while (pohThis != &sisfb_heap.oh_free) {
-		if (pohThis->offset == ulUpper) {
+	while(pohThis != &sisfb_heap.oh_free) {
+		if(pohThis->offset == ulUpper) {
 			poh_next = pohThis;
 		}
-			else if ((pohThis->offset + pohThis->size) ==
-				 ulLower) {
+			else if((pohThis->offset + pohThis->size) == ulLower) {
 			poh_prev = pohThis;
 		}
 		pohThis = pohThis->poh_next;
@@ -3604,42 +3501,43 @@
 
 	sisfb_delete_node(poh_freed);
 
-	if (poh_prev && poh_next) {
+	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);
+		return(poh_prev);
 	}
 
-	if (poh_prev) {
+	if(poh_prev) {
 		poh_prev->size += poh_freed->size;
 		sisfb_free_node(poh_freed);
-		return (poh_prev);
+		return(poh_prev);
 	}
 
-	if (poh_next) {
+	if(poh_next) {
 		poh_next->size += poh_freed->size;
 		poh_next->offset = poh_freed->offset;
 		sisfb_free_node(poh_freed);
-		return (poh_next);
+		return(poh_next);
 	}
 
 	sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
 
-	return (poh_freed);
+	return(poh_freed);
 }
 
-static void sisfb_free_node(SIS_OH *poh)
+static void
+sisfb_free_node(SIS_OH *poh)
 {
 	if(poh == NULL) return;
 
 	poh->poh_next = sisfb_heap.poh_freelist;
 	sisfb_heap.poh_freelist = poh;
-
 }
 
-void sis_malloc(struct sis_memreq *req)
+void
+sis_malloc(struct sis_memreq *req)
 {
 	SIS_OH *poh;
 
@@ -3658,7 +3556,8 @@
 	}
 }
 
-void sis_free(unsigned long base)
+void
+sis_free(unsigned long base)
 {
 	SIS_OH *poh;
 
@@ -3672,7 +3571,8 @@
 
 /* --------------------- SetMode routines ------------------------- */
 
-static void sisfb_pre_setmode(void)
+static void
+sisfb_pre_setmode(void)
 {
 	u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0;
 	
@@ -3682,7 +3582,7 @@
 	cr31 &= ~0x60;
 	cr31 |= 0x04;
 	
-	cr33 = sisfb_rate_idx & 0x0F;
+	cr33 = ivideo.rate_idx & 0x0F;
 
 	SiS_SetEnableDstn(&SiS_Pr, FALSE);
 	SiS_SetEnableFstn(&SiS_Pr, FALSE);
@@ -3733,7 +3633,7 @@
 		if(sisfb_nocrt2rate) {
 			cr33 |= (sisbios_mode[sisfb_mode_idx].rate_idx << 4);
 		} else {
-			cr33 |= ((sisfb_rate_idx & 0x0F) << 4);
+			cr33 |= ((ivideo.rate_idx & 0x0F) << 4);
 		}
 		break;
 	   default:	/* disable CRT2 */
@@ -3751,7 +3651,7 @@
 	outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR33, cr33);
 
 #ifdef CONFIG_FB_SIS_315
-        if(sisvga_engine == SIS_315_VGA) {
+        if(ivideo.sisvga_engine == SIS_315_VGA) {
 	   /* Clear LCDA and PAL-N/M bits */
 	   andSISIDXREG(SISCR,0x38,~0x03);
 	   if(ivideo.chip < SIS_661) {
@@ -3765,29 +3665,39 @@
 	SiS_Pr.SiS_UseOEM = sisfb_useoem;
 }
 
-static void sisfb_post_setmode(void)
+static void
+sisfb_post_setmode(void)
 {
 	u8 reg;
 	BOOLEAN crt1isoff = FALSE;
+	BOOLEAN doit = TRUE;
 #ifdef CONFIG_FB_SIS_315
 	u8 reg1;
 #endif
-#ifdef CONFIG_FB_SIS_300
-	BOOLEAN doit = TRUE;
-#endif
+
+	/* Now we actually HAVE changed the display mode */
+        ivideo.modechanged = 1;
+
 	/* We can't switch off CRT1 if bridge is in slave mode */
 	if(ivideo.vbflags & VB_VIDEOBRIDGE) {
+		inSISIDXREG(SISPART1, 0x00, reg);
 #ifdef CONFIG_FB_SIS_300
-		if(sisvga_engine == SIS_300_VGA) {
-			inSISIDXREG(SISPART1, 0x00, reg);
+		if(ivideo.sisvga_engine == SIS_300_VGA) {
 			if((reg & 0xa0) == 0x20) {
 				doit = FALSE;
 			}
 		}
 #endif
+#ifdef CONFIG_FB_SIS_315
+		if(ivideo.sisvga_engine == SIS_315_VGA) {
+			if((reg & 0x50) == 0x10) {
+				doit = FALSE;
+			}
+		}
+#endif
 	} else sisfb_crt1off = 0;
 
-	if(sisvga_engine == SIS_300_VGA) {
+	if(ivideo.sisvga_engine == SIS_300_VGA) {
 
 #ifdef CONFIG_FB_SIS_300
 	   if((sisfb_crt1off) && (doit)) {
@@ -3803,7 +3713,7 @@
 	} else {
 
 #ifdef CONFIG_FB_SIS_315
-	   if(sisfb_crt1off) {
+	   if((sisfb_crt1off) && (doit)) {
 	        crt1isoff = TRUE;
 		reg  = 0x40;
 		reg1 = 0xc0;
@@ -3813,7 +3723,7 @@
 		reg1 = 0x00;
 
 	   }
-	   setSISIDXREG(SISCR, 0x63, ~0x40, reg);
+	   setSISIDXREG(SISCR, SiS_Pr.SiS_MyCR63, ~0x40, reg);
 	   setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
 #endif
 
@@ -3858,7 +3768,7 @@
 			break;
 		}
 
-		orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
+		orSISIDXREG(SISPART1, ivideo.CRT2_write_enable, 0x01);
 
 		if(ivideo.vbflags & TV_NTSC) {
 
@@ -3931,13 +3841,7 @@
 			}
 		}
 
-		if ((filter >= 0) && (filter <= 7)) {
-			DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter,
-				sis_TV_filter[filter_tb].filter[filter][0],
-				sis_TV_filter[filter_tb].filter[filter][1],
-				sis_TV_filter[filter_tb].filter[filter][2],
-				sis_TV_filter[filter_tb].filter[filter][3]
-			);
+		if((filter >= 0) && (filter <= 7)) {
 			outSISIDXREG(SISPART2, 0x35, (sis_TV_filter[filter_tb].filter[filter][0]));
 			outSISIDXREG(SISPART2, 0x36, (sis_TV_filter[filter_tb].filter[filter][1]));
 			outSISIDXREG(SISPART2, 0x37, (sis_TV_filter[filter_tb].filter[filter][2]));
@@ -3945,11 +3849,10 @@
 		}
 	  
 	}
-
 }
 
 #ifndef MODULE
-int sisfb_setup(char *options)
+int __init sisfb_setup(char *options)
 {
 	char *this_opt;
 	
@@ -3960,76 +3863,85 @@
 	ivideo.refresh_rate = 0;
 	SiS_Pr.SiS_CustomT = CUT_NONE;
 	SiS_Pr.UsePanelScaler = -1;
+	SiS_Pr.CenterScreen = -1;
 	SiS_Pr.LVDSHL = -1;
+#if !defined(__i386__) && !defined(__x86_64__)
+       	sisfb_resetcard = 0;
+	sisfb_videoram = 0;
+#endif
 
         printk(KERN_DEBUG "sisfb: Options %s\n", options);
 
-	if (!options || !*options)
+	if(!options || !(*options))
 		return 0;
 
 	while((this_opt = strsep(&options, ",")) != NULL) {
 
-		if (!*this_opt)	continue;
+		if(!(*this_opt)) continue;
 
-		if (!strnicmp(this_opt, "mode:", 5)) {
+		if(!strnicmp(this_opt, "mode:", 5)) {
 			sisfb_search_mode(this_opt + 5, FALSE);
-		} else if (!strnicmp(this_opt, "vesa:", 5)) {
+		} else if(!strnicmp(this_opt, "vesa:", 5)) {
 			sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-		} else if (!strnicmp(this_opt, "inverse", 7)) {
+		} else if(!strnicmp(this_opt, "inverse", 7)) {
 			sisfb_inverse = 1;
 			/* fb_invert_cmaps(); */
-		} else if (!strnicmp(this_opt, "font:", 5)) {
-			strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
-			sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
+		} else if(!strnicmp(this_opt, "font:", 5)) {
+		        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, "vrate:", 6)) {
+		} else if(!strnicmp(this_opt, "vrate:", 6)) {
 			ivideo.refresh_rate = simple_strtoul(this_opt + 6, NULL, 0);
 			sisfb_parm_rate = ivideo.refresh_rate;
-		} else if (!strnicmp(this_opt, "rate:", 5)) {
+		} else if(!strnicmp(this_opt, "rate:", 5)) {
 			ivideo.refresh_rate = simple_strtoul(this_opt + 5, NULL, 0);
 			sisfb_parm_rate = ivideo.refresh_rate;
-		} else if (!strnicmp(this_opt, "off", 3)) {
+		} else if(!strnicmp(this_opt, "off", 3)) {
 			sisfb_off = 1;
-		} else if (!strnicmp(this_opt, "crt1off", 7)) {
+		} else if(!strnicmp(this_opt, "crt1off", 7)) {
 			sisfb_crt1off = 1;
-		} else if (!strnicmp(this_opt, "filter:", 7)) {
+		} else if(!strnicmp(this_opt, "filter:", 7)) {
 			filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
-		} else if (!strnicmp(this_opt, "forcecrt2type:", 14)) {
+		} else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
 			sisfb_search_crt2type(this_opt + 14);
-		} else if (!strnicmp(this_opt, "forcecrt1:", 10)) {
+		} else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
 			sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
-                } else if (!strnicmp(this_opt, "tvmode:",7)) {
+                } else if(!strnicmp(this_opt, "tvmode:",7)) {
 		        sisfb_search_tvstd(this_opt + 7);
-                } else if (!strnicmp(this_opt, "tvstandard:",11)) {
+                } else if(!strnicmp(this_opt, "tvstandard:",11)) {
 			sisfb_search_tvstd(this_opt + 7);
-                } else if (!strnicmp(this_opt, "mem:",4)) {
+                } else if(!strnicmp(this_opt, "mem:",4)) {
 		        sisfb_mem = simple_strtoul(this_opt + 4, NULL, 0);
-		} else if (!strnicmp(this_opt, "queuemode:", 10)) {
+		} else if(!strnicmp(this_opt, "queuemode:", 10)) {
 			sisfb_search_queuemode(this_opt + 10);
-		} else if (!strnicmp(this_opt, "pdc:", 4)) {
+		} else if(!strnicmp(this_opt, "pdc:", 4)) {
 		        sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
-		} else if (!strnicmp(this_opt, "noaccel", 7)) {
+		} else if(!strnicmp(this_opt, "pdc1:", 5)) {
+		        sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
+		} else if(!strnicmp(this_opt, "noaccel", 7)) {
 			sisfb_accel = 0;
-		} else if (!strnicmp(this_opt, "noypan", 6)) {
+		} else if(!strnicmp(this_opt, "noypan", 6)) {
 		        sisfb_ypan = 0;
-		} else if (!strnicmp(this_opt, "nomax", 5)) {
+		} else if(!strnicmp(this_opt, "nomax", 5)) {
 		        sisfb_max = 0;
-		} else if (!strnicmp(this_opt, "userom:", 7)) {
+		} else if(!strnicmp(this_opt, "userom:", 7)) {
 			sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
-		} else if (!strnicmp(this_opt, "useoem:", 7)) {
+		} else if(!strnicmp(this_opt, "useoem:", 7)) {
 			sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
-		} else if (!strnicmp(this_opt, "nocrt2rate", 10)) {
+		} else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
 			sisfb_nocrt2rate = 1;
-	 	} else if (!strnicmp(this_opt, "scalelcd:", 9)) {
+	 	} else if(!strnicmp(this_opt, "scalelcd:", 9)) {
 		        unsigned long temp = 2;
 		        temp = simple_strtoul(this_opt + 9, NULL, 0);
 		        if((temp == 0) || (temp == 1)) {
 			   SiS_Pr.UsePanelScaler = temp ^ 1;
 		        }
-		} else if (!strnicmp(this_opt, "specialtiming:", 14)) {
+		} else if(!strnicmp(this_opt, "specialtiming:", 14)) {
 			sisfb_search_specialtiming(this_opt + 14);
-		} else if (!strnicmp(this_opt, "lvdshl:", 7)) {
+		} else if(!strnicmp(this_opt, "lvdshl:", 7)) {
 		        unsigned long temp = 4;
 		        temp = simple_strtoul(this_opt + 7, NULL, 0);
 		        if((temp >= 0) && (temp <= 3)) {
@@ -4037,11 +3949,17 @@
 		        }
 		} 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, "videoram:", 9)) {
+		  	sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
+#endif
 		} else {
 			printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
 		}
 
-		/* TW: Acceleration only with MMIO mode */
+		/* Acceleration only with MMIO mode */
 		if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
 			sisfb_accel = 0;
 		}
@@ -4051,177 +3969,448 @@
 }
 #endif
 
-static char *sis_find_rom(void)
+static char * __devinit sis_find_rom(struct pci_dev *pdev)
 {
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
         u32  segstart;
-        unsigned char *rom_base;
-        unsigned char *rom;
-        int  stage;
-        int  i;
-        char sis_rom_sig[] = "Silicon Integrated Systems";
-        char *sis_sig_300[4] = {
-          "300", "540", "630", "730"
-        };
-        char *sis_sig_310[11] = {
-          "315", "315", "315", "5315", "6325", "6325",
-	  "Xabre", "6330", "6330", "6330", "6330"
-        };
-	ushort sis_nums_300[4] = {
-	  SIS_300, SIS_540, SIS_630, SIS_730
-	};
-	unsigned short sis_nums_310[11] = {
-	  SIS_315PRO, SIS_315H, SIS_315, SIS_550, SIS_650, SIS_740,
-	  SIS_330, SIS_661, SIS_741, SIS_660, SIS_760
-	};
+        unsigned char *rom_base, *rom;
+        int  romptr;
+	unsigned short pciid;
 
         for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
 
-                stage = 1;
+                rom_base = (unsigned char *)ioremap(segstart, 0x10000);
+		if(!rom_base) continue;
 
-                rom_base = (char *)ioremap(segstart, 0x1000);
+		if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) {
+		   iounmap(rom_base);
+                   continue;
+		}
 
-                if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa))
-                   stage = 2;
+		romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
+		if(romptr > (0x10000 - 8)) {
+		   iounmap(rom_base);
+		   continue;
+		}
 
-                if (stage != 2) {
-                   iounmap(rom_base);
-                   continue;
-                }
+		rom = rom_base + romptr;
 
+		if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
+		   (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) {
+		   iounmap(rom_base);
+		   continue;
+		}
 
-		rom = rom_base + (unsigned short)(*(rom_base + 0x12) | (*(rom_base + 0x13) << 8));
-                if(strncmp(sis_rom_sig, rom, strlen(sis_rom_sig)) == 0) {
-                    stage = 3;
-		}
-                if(stage != 3) {
-                    iounmap(rom_base);
-                    continue;
-                }
-
-		rom = rom_base + (unsigned short)(*(rom_base + 0x14) | (*(rom_base + 0x15) << 8));
-                for(i = 0;(i < 4) && (stage != 4); i++) {
-                    if(strncmp(sis_sig_300[i], rom, strlen(sis_sig_300[i])) == 0) {
-                        if(sis_nums_300[i] == ivideo.chip) {
-			   stage = 4;
-                           break;
-			}
-                    }
-                }
-		if(stage != 4) {
-                   for(i = 0;(i < 11) && (stage != 4); i++) {
-                      if(strncmp(sis_sig_310[i], rom, strlen(sis_sig_310[i])) == 0) {
-		          if(sis_nums_310[i] == ivideo.chip) {
-                             stage = 4;
-                             break;
-			  }
-                      }
-                   }
+		pciid = readb(rom + 4) | (readb(rom + 5) << 8);
+		if(pciid != 0x1039) {
+		   iounmap(rom_base);
+		   continue;
 		}
 
-                if(stage != 4) {
-                        iounmap(rom_base);
-                        continue;
-                }
+		pciid = readb(rom + 6) | (readb(rom + 7) << 8);
+		if(pciid == ivideo.chip_id) return rom_base;
 
-                return rom_base;
+		iounmap(rom_base);
         }
+#else
+	unsigned char *rom_base, *rom, *myrombase = NULL;
+        int  romptr;
+	unsigned short pciid;
+	u32 backup;
+
+	pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &backup);
+	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((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) {
+	      romptr = (unsigned short)(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) {
+		          if((myrombase = vmalloc(65536))) {
+			     memcpy_fromio(myrombase, rom_base, 65536);
+			  }
+		       }
+		    }
+		 }
+	      }
+	   }
+	   iounmap(rom_base);
+	}
+        pci_write_config_dword(pdev, PCI_ROM_ADDRESS, backup);
+	if(myrombase) return myrombase;
 #endif
         return NULL;
 }
 
+#ifdef SIS300
+static int __devinit
+sisfb_chkbuswidth300(ULONG FBAddress)
+{
+	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++;
+	   }
+	}
 
+	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 void __devinit
+sisfb_setramsize300(void)
+{
+  	ULONG 	FBAddr = (ULONG)sishw_ext.pjVideoMemoryAddress, 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(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(void)
+{
+	u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
+	u16 index, rindex, memtype = 0;
+
+	outSISIDXREG(SISSR,0x05,SIS_PASSWORD);
+
+	if(sishw_ext.UseROM) {
+	   if(sishw_ext.pjVirtualRomBase[0x52] & 0x80) {
+	      memtype = sishw_ext.pjVirtualRomBase[0x52];
+ 	   } else {
+	      inSISIDXREG(SISSR,0x3a,memtype);
+	   }
+	   memtype &= 0x07;
+	}
 
-int __init sisfb_init(void)
+	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(sishw_ext.UseROM) {
+	      index = memtype * 5;
+	      rindex = index + 0x54;
+	      v1 = sishw_ext.pjVirtualRomBase[rindex++];
+	      v2 = sishw_ext.pjVirtualRomBase[rindex++];
+	      v3 = sishw_ext.pjVirtualRomBase[rindex++];
+	      rindex = index + 0x7c;
+	      v4 = sishw_ext.pjVirtualRomBase[rindex++];
+	      v5 = sishw_ext.pjVirtualRomBase[rindex++];
+	      v6 = sishw_ext.pjVirtualRomBase[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(sishw_ext.UseROM) v1 = 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(sishw_ext.UseROM) {
+	   memtype += 0xa5;
+	   v1 = sishw_ext.pjVirtualRomBase[memtype];
+	   v2 = sishw_ext.pjVirtualRomBase[memtype + 8];
+	   v3 = sishw_ext.pjVirtualRomBase[memtype + 16];
+	   v4 = sishw_ext.pjVirtualRomBase[memtype + 24];
+	   v5 = sishw_ext.pjVirtualRomBase[memtype + 32];
+	   v6 = sishw_ext.pjVirtualRomBase[memtype + 40];
+	   v7 = sishw_ext.pjVirtualRomBase[memtype + 48];
+	   v8 = 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(sishw_ext.UseROM) {
+	   if(sishw_ext.pjVirtualRomBase[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,0xa0);     /* linear & relocated io */
+	v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
+	if(sishw_ext.UseROM) {
+	   v1 = sishw_ext.pjVirtualRomBase[0xe8];
+	   v2 = sishw_ext.pjVirtualRomBase[0xe9];
+	   v3 = 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(sishw_ext.UseROM) {
+	   v1 = sishw_ext.pjVirtualRomBase[0xec];
+	   v2 = sishw_ext.pjVirtualRomBase[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(sishw_ext.UseROM) {
+	      v4 = sishw_ext.pjVirtualRomBase[0xf5];
+	      v5 = sishw_ext.pjVirtualRomBase[0xf6];
+	      v6 = 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;
+	}
+	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 */
+	   sishw_ext.pjVideoMemoryAddress = ioremap(ivideo.video_base, 0x4000000);
+	   if(sishw_ext.pjVideoMemoryAddress) {
+	      sisfb_setramsize300();
+	      iounmap(sishw_ext.pjVideoMemoryAddress);
+	   } 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(sishw_ext.UseROM) {
+	   v1 = sishw_ext.pjVirtualRomBase[0xe6];
+	   v2 = sishw_ext.pjVirtualRomBase[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);
+}
+#endif
+
+
+int __devinit sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	struct pci_dev *pdev = NULL;
-	struct board *b;
-	int pdev_valid = 0;
+	struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
 	u32 reg32;
 	u16 reg16;
 	u8  reg;
+	int sisvga_enabled = 0;
 
-#if 0
-	/* for DOC VB */
-	sisfb_set_reg4(0xcf8,0x800000e0);
-	reg32 = sisfb_get_reg3(0xcfc);
-	reg32 = reg32 | 0x00001000;
-	sisfb_set_reg4(0xcfc,reg32);
-	}
-#endif
-
-	if (sisfb_off)
-		return -ENXIO;
+	if(sisfb_off) return -ENXIO;
 
-	sisfb_registered = 0;
 	sisfb_thismonitor.datavalid = FALSE;
 
 	memset(&sishw_ext, 0, sizeof(sishw_ext));
+	
+	memset(&ivideo, 0, sizeof(ivideo));
+	ivideo.detectedpdc  = 0xff;
+	ivideo.detectedpdca = 0xff;
+	ivideo.detectedlcda = 0xff;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
         memset(&sisfb_lastrates[0], 0, 128);
 #endif
-	
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	memset(&sis_disp, 0, sizeof(sis_disp));
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
-	pci_for_each_dev(pdev) {
-#else
-	while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
-#endif
-		for (b = sisdev_list; b->vendor; b++) {
-			if ((b->vendor == pdev->vendor)
-			    && (b->device == pdev->device)) {
-				pdev_valid = 1;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-				sis_fb_info = framebuffer_alloc(0, &pdev->dev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
+	sis_fb_info = framebuffer_alloc(0, &pdev->dev);
 #else
-				sis_fb_info = kmalloc(sizeof(*sis_fb_info), GFP_KERNEL);
+	sis_fb_info = kmalloc(sizeof(*sis_fb_info), GFP_KERNEL);
 #endif
-				if(!sis_fb_info) return -ENOMEM;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-				memset(sis_fb_info, 0, sizeof(*sis_fb_info));
+	if(!sis_fb_info) return -ENOMEM;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3))
+	memset(sis_fb_info, 0, sizeof(*sis_fb_info));
 #endif
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-				strcpy(sis_fb_info->modename, b->name);
-#else				
-				strcpy(myid, b->name);
-#endif				
-				ivideo.chip_id = pdev->device;
-				pci_read_config_byte(pdev, PCI_REVISION_ID,
-				                     &ivideo.revision_id);
-				pci_read_config_word(pdev, PCI_COMMAND, &reg16);
-				sishw_ext.jChipRevision = ivideo.revision_id;
-				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;
-				break;
-			}
-		}
 
-		if (pdev_valid)
-			break;
-	}
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+	strcpy(sis_fb_info->modename, chipinfo->chip_name);
+#else
+	strcpy(myid, chipinfo->chip_name);
+#endif
 
-	if (!pdev_valid)
-		return -ENODEV;
+	ivideo.chip_id = pdev->device;
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo.revision_id);
+	sishw_ext.jChipRevision = ivideo.revision_id;
+	pci_read_config_word(pdev, PCI_COMMAND, &reg16);
+	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;
+
+	ivideo.chip = chipinfo->chip;
+	ivideo.sisvga_engine = chipinfo->vgaengine;
+	ivideo.hwcursor_size = chipinfo->hwcursor_size;
+	ivideo.CRT2_write_enable = chipinfo->CRT2_write_enable;
 
-	switch (ivideo.chip_id) {
+	/* Patch special cases */
+	switch(ivideo.chip_id) {
 #ifdef CONFIG_FB_SIS_300
-	   case PCI_DEVICE_ID_SI_300:
-		ivideo.chip = SIS_300;
-		sisvga_engine = SIS_300_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2;  /* New X driver uses 2 buffers */
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300;
-		break;
 	   case PCI_DEVICE_ID_SI_630_VGA:
 		{
-			ivideo.chip = SIS_630;
 			sisfb_set_reg4(0xCF8, 0x80000000);
 			reg32 = sisfb_get_reg3(0xCFC);
 			if(reg32 == 0x07301039) {
@@ -4232,46 +4421,12 @@
 				strcpy(myid, "SIS 730");
 #endif
 			}
-			sisvga_engine = SIS_300_VGA;
-			sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2;
-			sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300;
 			break;
 		}
-	   case PCI_DEVICE_ID_SI_540_VGA:
-		ivideo.chip = SIS_540;
-		sisvga_engine = SIS_300_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300;
-		break;
 #endif
 #ifdef CONFIG_FB_SIS_315
-	   case PCI_DEVICE_ID_SI_315H:
-		ivideo.chip = SIS_315H;
-		sisvga_engine = SIS_315_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
-		break;
-	   case PCI_DEVICE_ID_SI_315:
-		ivideo.chip = SIS_315;
-		sisvga_engine = SIS_315_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
-		break;
-	   case PCI_DEVICE_ID_SI_315PRO:
-		ivideo.chip = SIS_315PRO;
-		sisvga_engine = SIS_315_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
-		break;
-	   case PCI_DEVICE_ID_SI_550_VGA:
-		ivideo.chip = SIS_550;
-		sisvga_engine = SIS_315_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
-		break;
 	   case PCI_DEVICE_ID_SI_650_VGA:
 	   	{
-			ivideo.chip = SIS_650;  
 			sisfb_set_reg4(0xCF8, 0x80000000);
 			reg32 = sisfb_get_reg3(0xCFC);
 			if(reg32 == 0x07401039) {
@@ -4282,17 +4437,8 @@
 				strcpy(myid, "SIS 740");
 #endif
 			}
-			sisvga_engine = SIS_315_VGA;
-			sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-			sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
 			break;
 		}
-	   case PCI_DEVICE_ID_SI_330:
-		ivideo.chip = SIS_330;
-		sisvga_engine = SIS_315_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
-		break;
 	   case PCI_DEVICE_ID_SI_660_VGA:
 	   	{
 			sisfb_set_reg4(0xCF8, 0x80000000);
@@ -4326,19 +4472,13 @@
 				strcpy(myid, "SIS 661");
 #endif
 			}
-			sisvga_engine = SIS_315_VGA;
-			sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-			sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
 			break;
 		}
 #endif
-           default:
-	   	kfree(sis_fb_info);
-	        return -ENODEV;
 	}
+
 	sishw_ext.jChipType = ivideo.chip;
 
-	/* for Debug */
 	if( (sishw_ext.jChipType == SIS_315PRO) ||
 	    (sishw_ext.jChipType == SIS_315) )
 		sishw_ext.jChipType = SIS_315H;
@@ -4346,16 +4486,16 @@
 	ivideo.video_base = pci_resource_start(pdev, 0);
 	ivideo.mmio_base = pci_resource_start(pdev, 1);
 	sishw_ext.ulIOAddress = SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
-	ivideo.vga_base = (unsigned short) sishw_ext.ulIOAddress;
+	ivideo.vga_base = sishw_ext.ulIOAddress;
 
-	sisfb_mmio_size =  pci_resource_len(pdev, 1);
+	ivideo.mmio_size =  pci_resource_len(pdev, 1);
 
 	if(!sisvga_enabled) {
 	   if(pci_enable_device(pdev)) {
 	      kfree(sis_fb_info);
 	      return -EIO;
 	   }
-	}
+	} 
 
 	SiS_Pr.SiS_Backup70xx = 0xff;
         SiS_Pr.SiS_CHOverScan = -1;
@@ -4364,10 +4504,18 @@
 	SiS_Pr.HaveEMI = FALSE;
 	SiS_Pr.HaveEMILCD = FALSE;
 	SiS_Pr.OverruleEMI = FALSE;
+	SiS_Pr.SiS_SensibleSR11 = FALSE;
+	SiS_Pr.SiS_MyCR63 = 0x63;
+	SiS_Pr.PDC = -1;
+	SiS_Pr.PDCA = -1;
+	if(ivideo.chip >= SIS_661) {
+	   SiS_Pr.SiS_SensibleSR11 = TRUE;
+	   SiS_Pr.SiS_MyCR63 = 0x53;
+	}
 	SiSRegInit(&SiS_Pr, sishw_ext.ulIOAddress);
 
 #ifdef CONFIG_FB_SIS_300
-	/* TW: Find PCI systems for Chrontel/GPIO communication setup */
+	/* Find PCI systems for Chrontel/GPIO communication setup */
 	if(ivideo.chip == SIS_630) {
 	   int i=0;
            do {
@@ -4385,9 +4533,21 @@
 
         outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)		
-#ifdef MODULE
+	if( (!sisvga_enabled)
+#if !defined(__i386__) && !defined(__x86_64__)
+		  	      || (sisfb_resetcard)
+#endif
+			      			   ) {
+	   int i;
+	   for(i = 0x30; i <= 0x3f; i++) {
+	       outSISIDXREG(SISCR,i,0x00);
+	   }
+	}
+
 	inSISIDXREG(SISCR,0x34,reg);
+	ivideo.modeprechange = ((reg & 0x7f)) ? (reg & 0x7f) : 0x03;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)		
+#ifdef MODULE	
 	if((reg & 0x80) && (reg != 0xff)) {
 	   if((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {
 	      printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
@@ -4398,41 +4558,31 @@
 #endif	
 #endif
 
-	if (sisvga_engine == SIS_315_VGA) {
-		switch (ivideo.chip) {
-		   case SIS_315H:
-		   case SIS_315:
-		   case SIS_330:
-			sishw_ext.bIntegratedMMEnabled = TRUE;
-			break;
-		   case SIS_550:
-		   case SIS_650:
-		   case SIS_740:
-		   case SIS_661:
-		   case SIS_741:
-		   case SIS_660:
-		   case SIS_760:
-			sishw_ext.bIntegratedMMEnabled = TRUE;
-			break;
-		   default:
-			break;
-		}
-	} else if (sisvga_engine == SIS_300_VGA) {
-		if (ivideo.chip == SIS_300) {
+	if(ivideo.sisvga_engine == SIS_315_VGA) {
+	   	sishw_ext.bIntegratedMMEnabled = TRUE;
+	} else if(ivideo.sisvga_engine == SIS_300_VGA) {
+		if(ivideo.chip == SIS_300) {
 			sishw_ext.bIntegratedMMEnabled = TRUE;
 		} else {
 		        inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_1A, reg);
-			if (reg & SIS_SCRATCH_REG_1A_MASK)
+			if(reg & SIS_SCRATCH_REG_1A_MASK)
 				sishw_ext.bIntegratedMMEnabled = TRUE;
 			else
 				sishw_ext.bIntegratedMMEnabled = FALSE;
 		}
 	}
 
+	ivideo.bios_vbase = ivideo.bios_abase = NULL;
 	if(sisfb_userom) {
-	    sishw_ext.pjVirtualRomBase = sis_find_rom();
+	    sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
+#if defined(__i386__) || defined(__x86_64__)
+	    ivideo.bios_vbase = sishw_ext.pjVirtualRomBase;	/* mapped */
+#else
+	    ivideo.bios_abase = sishw_ext.pjVirtualRomBase;	/* allocated */
+#endif
 	    if(sishw_ext.pjVirtualRomBase) {
-		printk(KERN_INFO "sisfb: Video ROM found and mapped to %p\n",
+		printk(KERN_INFO "sisfb: Video ROM found and %s to %p\n",
+			ivideo.bios_vbase ? "mapped" : "copied",
 		        sishw_ext.pjVirtualRomBase);
 		sishw_ext.UseROM = TRUE;
 	    } else {
@@ -4445,8 +4595,6 @@
 	    printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
 	}
 	sishw_ext.bSkipDramSizing = 0;
-	sishw_ext.pQueryVGAConfigSpace = &sisfb_query_VGA_config_space;
-	sishw_ext.pQueryNorthBridgeSpace = &sisfb_query_north_bridge_space;
 
         /* Find systems for special custom timing */
 	if(SiS_Pr.SiS_CustomT == CUT_NONE) {
@@ -4502,7 +4650,7 @@
 
 #ifdef CONFIG_FB_SIS_300
 	/* Mode numbers for 1280x768 are different for 300 and 315 series */
-	if(sisvga_engine == SIS_300_VGA) {
+	if(ivideo.sisvga_engine == SIS_300_VGA) {
 		sisbios_mode[MODEINDEX_1280x768].mode_no = 0x55;
 		sisbios_mode[MODEINDEX_1280x768+1].mode_no = 0x5a;
 		sisbios_mode[MODEINDEX_1280x768+2].mode_no = 0x5b;
@@ -4511,36 +4659,38 @@
 #endif
 
 	sishw_ext.pSR = vmalloc(sizeof(SIS_DSReg) * SR_BUFFER_SIZE);
-	if (sishw_ext.pSR == NULL) {
+	if(sishw_ext.pSR == NULL) {
 		printk(KERN_ERR "sisfb: Fatal error: Allocating SRReg space failed.\n");
+		if(ivideo.bios_abase) vfree(ivideo.bios_abase);
 		kfree(sis_fb_info);
 		return -ENODEV;
 	}
 	sishw_ext.pSR[0].jIdx = sishw_ext.pSR[0].jVal = 0xFF;
 
 	sishw_ext.pCR = vmalloc(sizeof(SIS_DSReg) * CR_BUFFER_SIZE);
-	if (sishw_ext.pCR == NULL) {
-	        vfree(sishw_ext.pSR);
+	if(sishw_ext.pCR == NULL) {
 		printk(KERN_ERR "sisfb: Fatal error: Allocating CRReg space failed.\n");
+		if(ivideo.bios_abase) vfree(ivideo.bios_abase);
+		vfree(sishw_ext.pSR);
 		kfree(sis_fb_info);
 		return -ENODEV;
 	}
 	sishw_ext.pCR[0].jIdx = sishw_ext.pCR[0].jVal = 0xFF;
 
 #ifdef CONFIG_FB_SIS_300
-	if(sisvga_engine == SIS_300_VGA) {
-		if(!sisvga_enabled) {
-		        /* Mapping Max FB Size for 300 Init */
-			sishw_ext.pjVideoMemoryAddress
-				= ioremap(ivideo.video_base, 0x4000000);
-			if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) {
-				outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
-			}
+	if(ivideo.sisvga_engine == SIS_300_VGA) {
+		if( (!sisvga_enabled)
+#if !defined(__i386__) && !defined(__x86_64__)
+		    		      || (sisfb_resetcard)
+#endif
+		  					   ) {
+			if(ivideo.chip == SIS_300) sisfb_post_sis300();
 		}
 		if(sisfb_get_dram_size_300()) {
-		        vfree(sishw_ext.pSR);
-			vfree(sishw_ext.pCR);
 			printk(KERN_ERR "sisfb: Fatal error: Unable to determine RAM size\n");
+			if(ivideo.bios_abase) vfree(ivideo.bios_abase);
+			vfree(sishw_ext.pSR);
+			vfree(sishw_ext.pCR);
 			kfree(sis_fb_info);
 			return -ENODEV;
 		}
@@ -4548,12 +4698,16 @@
 #endif
 
 #ifdef CONFIG_FB_SIS_315
-	if (sisvga_engine == SIS_315_VGA) {
-		if (!sisvga_enabled) {
-			/* Mapping Max FB Size for 315 Init */
-			sishw_ext.pjVideoMemoryAddress 
-				= ioremap(ivideo.video_base, 0x8000000);
-			if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) { 
+	if(ivideo.sisvga_engine == SIS_315_VGA) {
+		if( (!sisvga_enabled)
+#if !defined(__i386__) && !defined(__x86_64__)
+		    		     || (sisfb_resetcard)
+#endif
+		  					  ) {
+			if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) {
+				/* TODO: POSTing 315/330 not supported yet */
+				/* Mapping Max FB Size for 315 Init */
+			      	sishw_ext.pjVideoMemoryAddress = ioremap(ivideo.video_base, 0x8000000);
 				outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 				sishw_ext.bSkipDramSizing = TRUE;
 				sishw_ext.pSR[0].jIdx = 0x13;
@@ -4562,12 +4716,14 @@
 				inSISIDXREG(SISSR, 0x13, sishw_ext.pSR[0].jVal);
 				inSISIDXREG(SISSR, 0x14, sishw_ext.pSR[1].jVal);
 				sishw_ext.pSR[2].jVal = 0xFF;
+				iounmap(sishw_ext.pjVideoMemoryAddress);
 			}
 		}
 		if(sisfb_get_dram_size_315()) {
+			printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
+			if(ivideo.bios_abase) vfree(ivideo.bios_abase);
 			vfree(sishw_ext.pSR);
 			vfree(sishw_ext.pCR);
-			printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
 			kfree(sis_fb_info);
 			return -ENODEV;
 		}
@@ -4575,53 +4731,73 @@
 #endif
 
 	if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 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);
-
 	}
 
 	sishw_ext.ulVideoMemorySize = ivideo.video_size;
 
-	if(sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
-	if(sisfb_pdc) {
-	    SiS_Pr.PDC = sisfb_pdc;
-	} else {
-	    SiS_Pr.PDC = 0;
+	if(sisfb_pdc != 0xff) {
+	   if(ivideo.sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
+	   else				           sisfb_pdc &= 0x1f;
+	   SiS_Pr.PDC = sisfb_pdc;
+	}
+	if(ivideo.sisvga_engine == SIS_315_VGA) {
+	   if(sisfb_pdca != 0xff) SiS_Pr.PDCA = sisfb_pdca & 0x1f;
 	}
 
-	if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) {
+	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: Is there another framebuffer driver active?\n");
+		if(ivideo.bios_abase) vfree(ivideo.bios_abase);
 		vfree(sishw_ext.pSR);
 		vfree(sishw_ext.pCR);
 		kfree(sis_fb_info);
 		return -ENODEV;
 	}
 
-	if (!request_mem_region(ivideo.mmio_base, sisfb_mmio_size, "sisfb MMIO")) {
+	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);
 		vfree(sishw_ext.pSR);
 		vfree(sishw_ext.pCR);
 		kfree(sis_fb_info);
 		return -ENODEV;
 	}
 
-	ivideo.video_vbase = sishw_ext.pjVideoMemoryAddress = 
-		ioremap(ivideo.video_base, ivideo.video_size);
-	ivideo.mmio_vbase = ioremap(ivideo.mmio_base, sisfb_mmio_size);
+	ivideo.video_vbase = sishw_ext.pjVideoMemoryAddress = ioremap(ivideo.video_base, ivideo.video_size);
+	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);
+	   	vfree(sishw_ext.pSR);
+	   	vfree(sishw_ext.pCR);
+	   	kfree(sis_fb_info);
+	   	return -ENODEV;
+	}
+
+	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);
+	   	vfree(sishw_ext.pSR);
+	   	vfree(sishw_ext.pCR);
+	   	kfree(sis_fb_info);
+	   	return -ENODEV;
+	}
 
 	printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
-	       ivideo.video_base, ivideo.video_vbase,
-	       ivideo.video_size / 1024);
+	       	ivideo.video_base, ivideo.video_vbase, ivideo.video_size / 1024);
 
 	printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
-	       ivideo.mmio_base, ivideo.mmio_vbase,
-	       sisfb_mmio_size / 1024);
+	       	ivideo.mmio_base, ivideo.mmio_vbase, ivideo.mmio_size / 1024);
 
 	if(sisfb_heap_init()) {
 		printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
@@ -4631,11 +4807,12 @@
 	
 	ivideo.vbflags = 0;
 
+	ivideo.newrom = SiSDetermineROMLayout661(&SiS_Pr, &sishw_ext);
+
 	if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) { 
 	
 		sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN;
 		sishw_ext.Is301BDH = FALSE;
-		sishw_ext.usExternalChip = 0;
 
 		sisfb_sense_crt1();
 	
@@ -4645,7 +4822,7 @@
 			sisfb_detect_VB_connect();
 		}
 		
-		ivideo.currentvbflags = ivideo.vbflags & VB_VIDEOBRIDGE;
+		ivideo.currentvbflags = ivideo.vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
 		
 		if(ivideo.vbflags & VB_VIDEOBRIDGE) {
 		   if(sisfb_crt2type != -1) {
@@ -4658,7 +4835,7 @@
 		      /* Chrontel 700x TV detection often unreliable, therefore use a
 		       * different default order on such machines
 		       */
-		      if((sisvga_engine == SIS_300_VGA) && (ivideo.vbflags & VB_CHRONTEL)) {
+		      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;
@@ -4673,67 +4850,99 @@
 		if(ivideo.vbflags & CRT2_LCD) {
 		   inSISIDXREG(SISCR, IND_SIS_LCD_PANEL, reg);
 		   reg &= 0x0f;
-		   if(sisvga_engine == SIS_300_VGA) {
+		   if(ivideo.sisvga_engine == SIS_300_VGA) {
 		      sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
+		   } else if(ivideo.chip >= SIS_661) {
+		      sishw_ext.ulCRT2LCDType = sis661paneltype[reg];
 		   } else {
 		      sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
 		   }
 		}
-		
-		sisfb_detectedpdc = 0;
-
+	
 #ifdef CONFIG_FB_SIS_300
                 /* Save the current PanelDelayCompensation if the LCD is currently used */
-		if(sisvga_engine == SIS_300_VGA) {
+		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,sisfb_detectedpdc);
-			  sisfb_detectedpdc &= 0x3c;
-			  if(SiS_Pr.PDC == 0) {
+		          inSISIDXREG(SISPART1,0x13,ivideo.detectedpdc);
+			  ivideo.detectedpdc &= 0x3c;
+			  if(SiS_Pr.PDC == -1) {
 			     /* Let option override detection */
-			     SiS_Pr.PDC = sisfb_detectedpdc;
+			     SiS_Pr.PDC = ivideo.detectedpdc;
 			  }
-			  printk(KERN_INFO
-			         "sisfb: Detected LCD PanelDelayCompensation %d\n",
-  			         sisfb_detectedpdc);
+			  printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
+  			         ivideo.detectedpdc);
 		       }
-		       if((SiS_Pr.PDC) && (SiS_Pr.PDC != sisfb_detectedpdc)) {
-		          printk(KERN_INFO
-			         "sisfb: Using LCD PanelDelayCompensation %d\n",
+		       if((SiS_Pr.PDC != -1) && (SiS_Pr.PDC != ivideo.detectedpdc)) {
+		          printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
 				 SiS_Pr.PDC);
 		       }
 	           }
 		}
 #endif
 
-	        sisfb_detectedlcda = 0xff;
-
 #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) {
+		         SiS_Pr.SiS_UseLCDA = TRUE;
+		         ivideo.detectedlcda = 0x03;
+		         printk(KERN_DEBUG
+			        "sisfb: BIOS uses LCDA for low resolution and text modes\n");
+		      }
+	           }
 
-		if(sisvga_engine == SIS_315_VGA) {
 		   /* Save PDC */
 		   if(ivideo.vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
 		      int tmp;
 		      inSISIDXREG(SISCR,0x30,tmp);
-		      if(tmp & 0x20) {
+		      if((tmp & 0x20) || (ivideo.detectedlcda != 0xff)) {
 		         /* Currently on LCD? If yes, read current pdc */
-		         inSISIDXREG(SISPART1,0x2D,sisfb_detectedpdc);
-			 if(SiS_Pr.PDC == 0) {
-			    /* Let option override detection */
-			    SiS_Pr.PDC = sisfb_detectedpdc;
+			 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(SiS_Pr.PDC == -1) {
+			    if(ivideo.detectedpdc != 0xff) {
+			       SiS_Pr.PDC = ivideo.detectedpdc;
+			    }
+			 }
+			 if(SiS_Pr.PDCA == -1) {
+			    if(ivideo.detectedpdca != 0xff) {
+			       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);
 			 }
-			 printk(KERN_INFO
-			        "sisfb: Detected LCD PanelDelayCompensation %d\n",
-  			         sisfb_detectedpdc);
-		      }
-		      if((SiS_Pr.PDC) && (SiS_Pr.PDC != sisfb_detectedpdc)) {
-		         printk(KERN_INFO
-			         "sisfb: Using LCD PanelDelayCompensation %d\n",
-				 SiS_Pr.PDC);
 		      }
+
 		      /* Save EMI */
 		      if(ivideo.vbflags & (VB_302LV | VB_302ELV)) {
 		         inSISIDXREG(SISPART4,0x30,SiS_Pr.EMI_30);
@@ -4741,57 +4950,41 @@
 			 inSISIDXREG(SISPART4,0x32,SiS_Pr.EMI_32);
 			 inSISIDXREG(SISPART4,0x33,SiS_Pr.EMI_33);
 			 SiS_Pr.HaveEMI = TRUE;
-			 if(tmp & 0x20) SiS_Pr.HaveEMILCD = TRUE;
+			 if((tmp & 0x20) || (ivideo.detectedlcda != 0xff)) {
+			  	SiS_Pr.HaveEMILCD = TRUE;
+			 }
 		      }
 		   }
 
-		   /* Try to find about LCDA */
-		   if(ivideo.vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
-		      int tmp;
-		      inSISIDXREG(SISCR,0x34,tmp);
-		      if((tmp <= 0x13) || (tmp == 0xff)) {
-		         /* Currently on LCDA? (Some BIOSes leave CR38) */
-		         inSISIDXREG(SISCR,0x38,tmp);
-			 if((tmp & 0x03) == 0x03)  SiS_Pr.SiS_UseLCDA = TRUE;
-			 else {
-			    /* Currently on LCDA? (Some newer BIOSes set D0 in CR35) */
-			    inSISIDXREG(SISCR,0x35,tmp);
-			    if(tmp & 0x01) SiS_Pr.SiS_UseLCDA = TRUE;
-			    else {
-			       /* Currently on LCD? If so, we can find out
-			        * by peeking the mode register
-				*/
-			       inSISIDXREG(SISCR,0x30,tmp);
-			       if(tmp & 0x20) {
-			          inSISIDXREG(SISPART1,0x13,tmp);
-				  if(tmp & 0x04) SiS_Pr.SiS_UseLCDA = TRUE;
-			       }
-			    }
-			 }
+		   /* Let user override detected PDCs (all bridges) */
+		   if(ivideo.vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
+		      if((SiS_Pr.PDC != -1) && (SiS_Pr.PDC != ivideo.detectedpdc)) {
+		         printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
+				 SiS_Pr.PDC);
 		      }
-		      if(SiS_Pr.SiS_UseLCDA) {
-		         sisfb_detectedlcda = 0x03;
-		         printk(KERN_DEBUG
-			        "sisfb: Bridge uses LCDA for low resolution and text modes\n");
+		      if((SiS_Pr.PDCA != -1) && (SiS_Pr.PDCA != ivideo.detectedpdca)) {
+		         printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
+				 SiS_Pr.PDCA);
 		      }
-	          }
+		   }
+
 		}
 #endif
 
-		if (!sisfb_crt1off) {
+		if(!sisfb_crt1off) {
 		   	sisfb_handle_ddc(&sisfb_thismonitor, 0);
 		} else {
-		   	if ((ivideo.vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
-		      	    (ivideo.vbflags & (CRT2_VGA | CRT2_LCD))) {
+		   	if((ivideo.vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
+		      	   (ivideo.vbflags & (CRT2_VGA | CRT2_LCD))) {
 		      		sisfb_handle_ddc(&sisfb_thismonitor, 1);
 		   	}
 		}
 
-		if (sisfb_mode_idx >= 0)
+		if(sisfb_mode_idx >= 0)
 			sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx, ivideo.currentvbflags);
 
-		if (sisfb_mode_idx < 0) {
-			switch (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
+		if(sisfb_mode_idx < 0) {
+			switch(ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
 			   case CRT2_LCD:
 				sisfb_mode_idx = DEFAULT_LCDMODE;
 				break;
@@ -4804,19 +4997,19 @@
 			}
 		}
 
-		sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no;
+		ivideo.mode_no = sisbios_mode[sisfb_mode_idx].mode_no;
 
-		if (ivideo.refresh_rate != 0)
+		if(ivideo.refresh_rate != 0)
 			sisfb_search_refresh_rate(ivideo.refresh_rate, sisfb_mode_idx);
 
-		if (sisfb_rate_idx == 0) {
-			sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
+		if(ivideo.rate_idx == 0) {
+			ivideo.rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
 			ivideo.refresh_rate = 60;
 		}
 
-		if (sisfb_thismonitor.datavalid) {
+		if(sisfb_thismonitor.datavalid) {
 			if(!sisfb_verify_rate(&sisfb_thismonitor, sisfb_mode_idx,
-			                      sisfb_rate_idx, ivideo.refresh_rate)) {
+			                      ivideo.rate_idx, ivideo.refresh_rate)) {
 				printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
 			}
 		}
@@ -4839,13 +5032,14 @@
 
 		sisfb_pre_setmode();
 
-		if (SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
+		if(SiSSetMode(&SiS_Pr, &sishw_ext, ivideo.mode_no) == 0) {
 			printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
-				sisfb_mode_no);
+				ivideo.mode_no);
+			if(ivideo.bios_abase) vfree(ivideo.bios_abase);
 			vfree(sishw_ext.pSR);
 			vfree(sishw_ext.pCR);
 			release_mem_region(ivideo.video_base, ivideo.video_size);
-			release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
+			release_mem_region(ivideo.mmio_base, ivideo.mmio_size);
 			kfree(sis_fb_info);
 			return -EINVAL;
 		}
@@ -4877,7 +5071,7 @@
 			
 		sisfb_set_disp(-1, &default_var, sis_fb_info);
 		
-#else		/* --------- For 2.5: Setup a somewhat sane default var ------------ */
+#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,
@@ -4891,10 +5085,10 @@
 		
 		default_var.pixclock = (u32) (1000000000 /
 				sisfb_mode_rate_to_dclock(&SiS_Pr, &sishw_ext,
-						sisfb_mode_no, sisfb_rate_idx));
+						ivideo.mode_no, ivideo.rate_idx));
 						
 		if(sisfb_mode_rate_to_ddata(&SiS_Pr, &sishw_ext,
-			 sisfb_mode_no, sisfb_rate_idx,
+			 ivideo.mode_no, ivideo.rate_idx,
 			 &default_var.left_margin, &default_var.right_margin, 
 			 &default_var.upper_margin, &default_var.lower_margin,
 			 &default_var.hsync_len, &default_var.vsync_len,
@@ -4927,23 +5121,24 @@
 		sis_fb_info->par = &ivideo;
 		sis_fb_info->screen_base = ivideo.video_vbase;
 		sis_fb_info->fbops = &sisfb_ops;
+#ifdef NEWFBDEV
 		sis_fb_info->class_dev.dev = &pdev->dev;
+#endif
 		sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
 		sis_fb_info->pseudo_palette = pseudo_palette;
 		
 		fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
 #endif
 
-		printk(KERN_INFO "sisfb: Initial vbflags 0x%lx\n", ivideo.vbflags);
+		printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", ivideo.vbflags);
 
 #ifdef CONFIG_MTRR
 		ivideo.mtrr = mtrr_add((unsigned int) ivideo.video_base,
 				(unsigned int) ivideo.video_size,
 				MTRR_TYPE_WRCOMB, 1);
 		if(ivideo.mtrr) {
-			printk(KERN_INFO "sisfb: Added MTRRs\n");
+			printk(KERN_DEBUG "sisfb: Added MTRRs\n");
 		}
-
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
@@ -4951,41 +5146,110 @@
 #endif
 
 		if(register_framebuffer(sis_fb_info) < 0) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+			if(ivideo.bios_abase) vfree(ivideo.bios_abase);
 			vfree(sishw_ext.pSR);
 			vfree(sishw_ext.pCR);
 			release_mem_region(ivideo.video_base, ivideo.video_size);
-			release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
-#endif
+			release_mem_region(ivideo.mmio_base, ivideo.mmio_size);
 			printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
 			kfree(sis_fb_info);
 			return -EINVAL;
 		}
 
-		sisfb_registered = 1;			
+		ivideo.registered = 1;
+
+		pci_set_drvdata(pdev, sis_fb_info);
 
 		printk(KERN_DEBUG "sisfb: Installed SISFB_GET_INFO ioctl (%x)\n", SISFB_GET_INFO);
 		printk(KERN_DEBUG "sisfb: Installed SISFB_GET_VBRSTATUS ioctl (%x)\n", SISFB_GET_VBRSTATUS);
-		
+
 		printk(KERN_INFO "sisfb: 2D acceleration is %s, scrolling mode %s\n",
 		     sisfb_accel ? "enabled" : "disabled",
 		     sisfb_ypan  ? (sisfb_max ? "ypan (auto-max)" : "ypan (no auto-max)") : "redraw");
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+
 		printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n",
-	       		GET_FB_IDX(sis_fb_info->node), sis_fb_info->modename, VER_MAJOR, VER_MINOR,
-	       		VER_LEVEL);		     
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	       		GET_FB_IDX(sis_fb_info->node), sis_fb_info->modename,
 #else
-		printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n",
-	       		sis_fb_info->node, myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
+	       		sis_fb_info->node, myid,
 #endif
+			VER_MAJOR, VER_MINOR, VER_LEVEL);
 
-		printk(KERN_INFO "sisfb: (C) 2001-2003 Thomas Winischhofer.\n");
+		printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
 
 	}	/* if mode = "none" */
+
 	return 0;
 }
 
+/*****************************************************/
+/*                PCI DEVICE HANDLING                */
+/*****************************************************/
+
+static void __devexit sisfb_remove(struct pci_dev *pdev)
+{
+	/* Unmap */
+	iounmap(ivideo.video_vbase);
+	iounmap(ivideo.mmio_vbase);
+	if(ivideo.bios_vbase) iounmap(ivideo.bios_vbase);
+
+	/* Release mem regions */
+	release_mem_region(ivideo.video_base, ivideo.video_size);
+	release_mem_region(ivideo.mmio_base, ivideo.mmio_size);
+
+#ifdef CONFIG_MTRR
+	/* Release MTRR region */
+	if(ivideo.mtrr) {
+		mtrr_del(ivideo.mtrr,
+		      (unsigned int)ivideo.video_base,
+	              (unsigned int)ivideo.video_size);
+	}
+#endif
+
+	/* Unregister the framebuffer */
+	if(ivideo.registered) {
+		unregister_framebuffer(sis_fb_info);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
+		framebuffer_release(sis_fb_info);
+#else
+		kfree(sis_fb_info);
+#endif
+	}
+
+	if(sishw_ext.pSR) vfree(sishw_ext.pSR);
+	if(sishw_ext.pCR) vfree(sishw_ext.pCR);
+	if(ivideo.bios_abase) vfree(ivideo.bios_abase);
+
+	pci_set_drvdata(pdev, NULL);
+
+	/* TODO: Restore the initial mode
+	 * This sounds easy but is as good as impossible
+	 * on many machines with SiS chip and video bridge
+	 * since text modes are always set up differently
+	 * from machine to machine. Depends on the type
+	 * of integration between chipset and bridge.
+	 */
+	if(ivideo.registered) {
+	   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,
+	.remove 	= __devexit_p(sisfb_remove)
+};
+
+int __init sisfb_init(void)
+{
+	return(pci_module_init(&sisfb_driver));
+}
+
+/*****************************************************/
+/*                      MODULE                       */
+/*****************************************************/
 
 #ifdef MODULE
 
@@ -4997,7 +5261,8 @@
 static char         *forcecrt2type = NULL;
 static int          forcecrt1 = -1;
 static char         *queuemode = NULL;
-static int          pdc = 0;
+static int          pdc = -1;
+static int          pdc1 = -1;
 static int          noaccel = -1;
 static int          noypan  = -1;
 static int	    nomax = -1;
@@ -5011,10 +5276,14 @@
 static int          scalelcd = -1;
 static char	    *specialtiming = NULL;
 static int	    lvdshl = -1;
+#if !defined(__i386__) && !defined(__x86_64__)
+static int	    resetcard = 0;
+static int	    videoram = 0;
+#endif
 
-MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/650/651/661/740/741/330/760 framebuffer driver");
+MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer driver");
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>; SiS; Various others");
+MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>; SiS; Others");
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 MODULE_PARM(mode, "s");
@@ -5068,11 +5337,11 @@
 
 MODULE_PARM(queuemode,   "s");
 MODULE_PARM_DESC(queuemode,
-	"\nSelects the queue mode on 315/550/65x/74x/330/760. Possible choices are AGP, VRAM,\n"
-  	  "MMIO. AGP is only available if the kernel has AGP support. The queue mode is\n"
-	  "important to programs using the 2D/3D accelerator of the SiS chip. The modes\n"
-	  "require a totally different way of programming the engines. If any mode than\n"
-	  "MMIO is selected, sisfb will disable its own 2D acceleration. On\n"
+	"\nSelects the queue mode on 315/550/65x/74x/330/760. Possible choices are AGP,\n"
+  	  "VRAM and MMIO. AGP is only available if the kernel has AGP support. The queue\n"
+	  "mode is important to programs using the 2D/3D accelerator of the SiS chip.\n"
+	  "The modes require a totally different way of programming the engines. If any\n"
+	  "mode than MMIO is selected, sisfb will disable its own 2D acceleration. On\n"
 	  "300/540/630/730, this option is ignored. (default: MMIO)");
 
 /* TW: "Import" the options from the X driver */
@@ -5083,16 +5352,16 @@
 	  "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 is 1MB by default. The\n"
-	  "value is to be specified without 'KB' and should match the MaxXFBMem setting for\n"
-	  "XFree 4.x (x>=2).");
+	  "value is to be specified without 'KB' and should match the MaxXFBMem setting\n"
+	  "for XFree 4.x (x>=2).");
 
 MODULE_PARM(forcecrt2type, "s");
 MODULE_PARM_DESC(forcecrt2type,
 	"\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
 	  "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
 	  "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
-	  "On systems with a 301(B/LV) bridge, parameters SVIDEO, COMPOSITE or SCART can be\n"
-	  "used instead of TV to override the TV detection. (default: [autodetected])");
+	  "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
+	  "be used instead of TV to override the TV detection. (default: [autodetected])");
 
 MODULE_PARM(forcecrt1, "i");
 MODULE_PARM_DESC(forcecrt1,
@@ -5105,9 +5374,14 @@
         "\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; 3 or 51 on a 315 series chipset. If the problem persists,\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"
-	  "and value from 0 to 255). (default: [autodetected])");
+	  "any value from 0 to 31). (default: autodetected, if LCD is active during start)");
+
+MODULE_PARM(pdc1, "i");
+MODULE_PARM_DESC(pdc1,
+        "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315 series\n"
+	  "only. (default: autodetected if LCD is in LCD-via-CRT1 mode during startup)");
 
 MODULE_PARM(noaccel, "i");
 MODULE_PARM_DESC(noaccel,
@@ -5122,9 +5396,10 @@
 MODULE_PARM(nomax, "i");
 MODULE_PARM_DESC(nomax,
         "\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 this\n"
-	  "is set to anything other than 0, sisfb will not do this and thereby enable the user\n"
-	  "to positively specify a virtual Y size of the screen using fbset. (default: 0)\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"
+	  "fbset. (default: 0)\n");
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	
 MODULE_PARM(inverse, "i");
@@ -5156,20 +5431,31 @@
 MODULE_PARM(scalelcd, "i");
 MODULE_PARM_DESC(scalelcd,
 	"\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
-	  "native resolution. Setting it to 0 will disable scaling; if the panel can scale\n"
-	  "by itself, it will probably do this, otherwise you will see a black bar around\n"
-	  "the screen image. Default: [autodetect if panel can scale]");
+	  "native resolution. Setting it to 0 will disable scaling; if the panel can\n"
+	  "scale by itself, it will probably do this, otherwise you will see a black bar\n"
+	  "around the screen image. Default: [autodetect if panel can scale]");
 
 MODULE_PARM(specialtiming, "s");
 
 MODULE_PARM(lvdshl, "i");
 
+#if !defined(__i386__) && !defined(__x86_64__)
+MODULE_PARM(resetcard, "i");
+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");
+MODULE_PARM(videoram, "i");
+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]");
+#endif
 
-int init_module(void)
+int __init sisfb_init_module(void)
 {
-	int err;
-
 	SiS_Pr.UsePanelScaler = -1;
+	SiS_Pr.CenterScreen = -1;
 	SiS_Pr.SiS_CustomT = CUT_NONE;
 	SiS_Pr.LVDSHL = -1;
 
@@ -5230,14 +5516,15 @@
 
 	sisfb_useoem = useoem;
 
-	if (queuemode)        sisfb_search_queuemode(queuemode);
-	
+	if(queuemode)         sisfb_search_queuemode(queuemode);
+
 	/* If other queuemode than MMIO, disable 2D accel and ypan */
 	if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
 	        sisfb_accel = 0;
 	}
 
-        if(pdc) sisfb_pdc = pdc & 0x3c;
+        if(pdc != -1)  sisfb_pdc  = (pdc  & 0x7f);
+	if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
 
 	sisfb_nocrt2rate = nocrt2rate;
 
@@ -5246,55 +5533,30 @@
 
 	if((lvdshl >= 0) && (lvdshl <= 3)) SiS_Pr.LVDSHL = lvdshl;
 
-	if((err = sisfb_init()) < 0) return err;
-
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	/* Release mem regions */
-	release_mem_region(ivideo.video_base, ivideo.video_size);
-	release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
+#if !defined(__i386__) && !defined(__x86_64__)
+        if(resetcard)   sisfb_resetcard = 1;
+	else		sisfb_resetcard = 0;
 
-#ifdef CONFIG_MTRR
-	/* TW: Release MTRR region */
-	if(ivideo.mtrr) {
-		mtrr_del(ivideo.mtrr,
-		      (unsigned int)ivideo.video_base,
-	              (unsigned int)ivideo.video_size);
-	}
+	if(videoram)    sisfb_videoram = videoram;
 #endif
 
-	/* Unregister the framebuffer */
-	if(sisfb_registered) {
-		unregister_framebuffer(sis_fb_info);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-		framebuffer_release(sis_fb_info);
-#else
-		kfree(sis_fb_info);
-#endif
-	}
+        return(sisfb_init());
+}
 
-	if(sishw_ext.pSR) vfree(sishw_ext.pSR);
-	if(sishw_ext.pCR) vfree(sishw_ext.pCR);
-	
-	/* TODO: Restore the initial mode 
-	 * This sounds easy but is as good as impossible
-	 * on many machines with SiS chip and video bridge
-	 * since text modes are always set up differently
-	 * from machine to machine. Depends on the type
-	 * of integration between chipset and bridge.
-	 */
-	
-	printk(KERN_INFO "sisfb: Module unloaded\n");
+static void __exit sisfb_remove_module(void)
+{
+	pci_unregister_driver(&sisfb_driver);
+	printk(KERN_DEBUG "sisfb: Module unloaded\n");
 }
 
-#endif
+module_init(sisfb_init_module);
+module_exit(sisfb_remove_module);
+
+#endif 	   /*  /MODULE  */
 
 EXPORT_SYMBOL(sis_malloc);
 EXPORT_SYMBOL(sis_free);
 EXPORT_SYMBOL(sis_dispinfo);
 
 EXPORT_SYMBOL(ivideo);
-                                                                                           
+

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