--- xc/programs/Xserver/hw/xfree86/etc/scanpci.c.336	Fri Dec  3 10:43:47 1999
+++ xc/programs/Xserver/hw/xfree86/etc/scanpci.c	Mon Jul 17 11:51:20 2000
@@ -1253,10 +1253,15 @@
                             { 0x8A13, "Trio3D/2X", NF },
                             { 0x8A20, "Savage3D", NF },
                             { 0x8A21, "Savage3D S3 (Macrovision Support)", NF },
+                            { 0x8A25, "Savage/NB", NF },
                             { 0x8A22, "Savage4", NF },
                             { 0x8C01, "ViRGE/MX", NF },
                             { 0x8C02, "ViRGE/MX+", NF },
                             { 0x8C03, "ViRGE/MX+MV", NF },
+                            { 0x8C10, "Savage/MX-MV", NF },
+                            { 0x8C11, "Savage/MX", NF },
+                            { 0x8C12, "Savage/IX-MV", NF },
+                            { 0x8C13, "Savage/IX", NF },
                             { 0x9102, "Savage2000", NF },
                             { 0x0000, (char *)NULL, NF } } },
         { 0x8086, "Intel", {
--- xc/programs/Xserver/hw/xfree86/vga256/vga/vgaPCI.h.336	Sat Jan  8 19:27:07 2000
+++ xc/programs/Xserver/hw/xfree86/vga256/vga/vgaPCI.h	Mon Jul 17 11:56:42 2000
@@ -288,6 +288,11 @@
 #define PCI_CHIP_SAVAGE3D_M	0x8A21
 #define PCI_CHIP_SAVAGE4	0x8A22
 #define PCI_CHIP_SAVAGE2000	0x9102
+#define PCI_CHIP_SAVAGE_MX_MV	0x8C10
+#define PCI_CHIP_SAVAGE_MX	0x8C11
+#define PCI_CHIP_SAVAGE_IX_MV	0x8C12
+#define PCI_CHIP_SAVAGE_IX	0x8C13
+#define PCI_CHIP_SAVAGE_370	0x8A25
 #define PCI_CHIP_868		0x8880
 #define PCI_CHIP_928		0x88B0
 #define PCI_CHIP_864_0		0x88C0
@@ -589,6 +594,11 @@
 				{PCI_CHIP_SAVAGE3D_M,	"Savage3D (Macrovision Support)"},
 				{PCI_CHIP_SAVAGE4,	"Savage4"},
 				{PCI_CHIP_SAVAGE2000,	"Savage2000"},
+				{PCI_CHIP_SAVAGE_MX_MV,	"Savage/MX-MV"},
+				{PCI_CHIP_SAVAGE_MX,	"Savage/MX"},
+				{PCI_CHIP_SAVAGE_IX_MV,	"Savage/IX-MV"},
+				{PCI_CHIP_SAVAGE_IX,	"Savage/IX"},
+				{PCI_CHIP_SAVAGE_370,	"Savage/NB"},
 				{PCI_CHIP_868,		"868"},
 				{PCI_CHIP_928,		"928"},
 				{PCI_CHIP_864_0,	"864"},
--- xc/programs/Xserver/hw/xfree86/SuperProbe/PCI.h.336	Thu Nov 18 16:52:49 1999
+++ xc/programs/Xserver/hw/xfree86/SuperProbe/PCI.h	Mon Jul 17 17:11:25 2000
@@ -362,6 +362,12 @@
 #define PCI_CHIP_SAVAGE3D_M	0x8A21
 #define PCI_CHIP_SAVAGE4	0x8A22
 #define PCI_CHIP_SAVAGE2000	0x9102
+#define PCI_CHIP_SAVAGE_MX_MV	0x8C10
+#define PCI_CHIP_SAVAGE_MX	0x8C11
+#define PCI_CHIP_SAVAGE_IX_MV	0x8C12
+#define PCI_CHIP_SAVAGE_IX	0x8C13
+#define PCI_CHIP_SAVAGE_NB	0x8A25
+#define PCI_CHIP_SAVAGE_MX_MV	0x8C10
 
 /* ARK Logic */
 #define PCI_CHIP_1000PV		0xA091
--- xc/programs/Xserver/hw/xfree86/SuperProbe/Probe.h.336	Thu Nov 18 16:52:49 1999
+++ xc/programs/Xserver/hw/xfree86/SuperProbe/Probe.h	Mon Jul 17 17:10:07 2000
@@ -611,6 +611,11 @@
 #define CHIP_S3_Trio3D_2X	SVGA_TYPE(V_S3,40)	/* S3 Trio3D/2X	*/
 #define CHIP_S3_Savage4 SVGA_TYPE(V_S3,41)	/* S3 Savage4		*/
 #define CHIP_S3_Savage2000 SVGA_TYPE(V_S3,42)	/* S3 Savage2000        */
+#define CHIP_S3_SavageMX_MV SVGA_TYPE(V_S3,43)	/* S3 Savage/MX-MV      */
+#define CHIP_S3_SavageMX SVGA_TYPE(V_S3,44)	/* S3 Savage/MX         */
+#define CHIP_S3_SavageIX_MV SVGA_TYPE(V_S3,45)	/* S3 Savage/IX-MV      */
+#define CHIP_S3_SavageIX SVGA_TYPE(V_S3,46)	/* S3 Savage/IX         */
+#define CHIP_S3_SavageNB SVGA_TYPE(V_S3,47)	/* S3 Savage/NB         */
 #define CHIP_TVGA_UNK	SVGA_TYPE(V_TRIDENT,0)	/* Trident unknown	*/
 #define CHIP_TVGA8200	SVGA_TYPE(V_TRIDENT,1)	/* Trident LX8200	*/
 #define CHIP_TVGA8800BR	SVGA_TYPE(V_TRIDENT,2)	/* Trident 8800BR	*/
--- xc/programs/Xserver/hw/xfree86/SuperProbe/Print.c.336	Thu Nov 18 16:52:49 1999
+++ xc/programs/Xserver/hw/xfree86/SuperProbe/Print.c	Mon Jul 17 12:05:17 2000
@@ -149,6 +149,11 @@
 		  "S3 Trio3D/2X",
 		  "S3 Savage4",
 		  "S3 Savage2000",
+		  "S3 Savage/MX-MV",
+		  "S3 Savage/MX",
+		  "S3 Savage/IX-MV",
+		  "S3 Savage/IX",
+		  "S3 Savage/NB",
 	       },
 /* Trident */	{ "Trident (chipset unknown)",
 		  "Trident LX8200",
--- xc/programs/Xserver/hw/xfree86/SuperProbe/S3.c.336	Fri Dec  3 10:41:34 1999
+++ xc/programs/Xserver/hw/xfree86/SuperProbe/S3.c	Mon Jul 17 17:11:04 2000
@@ -194,6 +194,26 @@
 			        PCIProbed = TRUE;
 				*Chipset = CHIP_S3_Savage2000;
 				break;
+			case PCI_CHIP_SAVAGE_MX_MV:
+			        PCIProbed = TRUE;
+				*Chipset = CHIP_S3_SavageMX_MV;
+				break;
+			case PCI_CHIP_SAVAGE_MX:
+			        PCIProbed = TRUE;
+				*Chipset = CHIP_S3_SavageMX;
+				break;
+			case PCI_CHIP_SAVAGE_IX_MV:
+			        PCIProbed = TRUE;
+				*Chipset = CHIP_S3_SavageIX_MV;
+				break;
+			case PCI_CHIP_SAVAGE_IX:
+			        PCIProbed = TRUE;
+				*Chipset = CHIP_S3_SavageIX;
+				break;
+			case PCI_CHIP_SAVAGE_NB:
+			        PCIProbed = TRUE;
+				*Chipset = CHIP_S3_SavageNB;
+				break;
 #if 0  /* use port probing then... */
 			default:
 			        PCIProbed = TRUE;
@@ -428,6 +448,21 @@
                            case PCI_CHIP_SAVAGE2000:
                               *Chipset = CHIP_S3_Savage2000;
 			      break;
+                           case PCI_CHIP_SAVAGE_MX_MV:
+                              *Chipset = CHIP_S3_SavageMX_MV;
+			      break;
+                           case PCI_CHIP_SAVAGE_MX:
+                              *Chipset = CHIP_S3_SavageMX;
+			      break;
+                           case PCI_CHIP_SAVAGE_IX_MV:
+                              *Chipset = CHIP_S3_SavageIX_MV;
+			      break;
+                           case PCI_CHIP_SAVAGE_IX:
+                              *Chipset = CHIP_S3_SavageIX;
+			      break;
+                           case PCI_CHIP_SAVAGE_NB:
+                              *Chipset = CHIP_S3_SavageNB;
+			      break;
 			   default:
 			     Chip_data = rev;
 			     Chip_data = (Chip_data << 16) | chip_id;
@@ -547,6 +582,19 @@
 			else if (Chipset == CHIP_S3_Savage2000)
 			{  
 			  int memsize[] = { 2, 4, 8, 12, 16, 32, 64, 32 };
+			  int sel = (config & 0xE0) >> 5;
+			  Mem = memsize[sel] * 1024;
+			}
+			else if (Chipset == CHIP_S3_SavageMX_MV || Chipset == CHIP_S3_SavageMX ||
+				 Chipset == CHIP_S3_SavageIX_MV || Chipset == CHIP_S3_SavageIX)
+			{  
+			  int memsize[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
+			  int sel = (config & 0x0E) >> 1;
+			  Mem = memsize[sel] * 1024;
+			}
+			else if (Chipset == CHIP_S3_SavageNB)
+			{  
+			  int memsize[] = { 0, 2, 4, 8, 16, 32, 2, 2 };
 			  int sel = (config & 0xE0) >> 5;
 			  Mem = memsize[sel] * 1024;
 			}
diff -u xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/lrmi.c xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/lrmi.c
--- xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/lrmi.c	Fri Jul 30 13:21:25 1999
+++ xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/lrmi.c	Wed Jan 26 01:44:42 2000
@@ -11,10 +11,10 @@
 */
 /* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/lrmi.c,v 1.1.2.1 1999/07/30 11:21:25 hohndel Exp $ */
 
-#if defined(linux) && defined(__i386__)
-
 #include <stdio.h>
 #include <string.h>
+
+#if defined(linux) && defined(__i386__)
 #include <asm/vm86.h>
 
 #ifdef USE_LIBC_VM86
diff -u xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/newmmio.h xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/newmmio.h
--- xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/newmmio.h	Fri Dec  3 10:46:00 1999
+++ xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/newmmio.h	Wed Jan 26 01:44:43 2000
@@ -1,4 +1,4 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/newmmio.h,v 1.1.2.2 1999/12/01 12:49:32 hohndel Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/newmmio.h,v 1.1.2.1 1999/07/30 11:21:27 hohndel Exp $ */
 
 /* Copied over from accel/s3_virge */
 
@@ -409,9 +409,9 @@
  */
 #define IN_SUBSYS_STAT() 	((((mmtr)s3savMmioMem)->subsys_regs.regs.subsystem_csr))
 #define SET_SUBSYS_CRTL(val) 	do { write_mem_barrier(); ((((mmtr)s3savMmioMem)->subsys_regs.regs.subsystem_csr)) = (val); write_mem_barrier(); } while (0)
-#define STATUS_WORD0            (*(volatile unsigned int*)(((char*)s3savMmioMem) + 0x48C00))
+#define STATUS_WORD0            S3_IN32(0x48C00)
 /* Savage4 Rev B only: */
-#define ALT_STATUS_WORD0        (*(volatile unsigned int*)(((char*)s3savMmioMem) + 0x48C60))
+#define ALT_STATUS_WORD0        S3_IN32(0x48C60)
 
 
 #define SET_DAC_W_INDEX(index)  outb(DAC_W_INDEX, index)
diff -u xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/regs3sav.h xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/regs3sav.h
--- xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/regs3sav.h	Fri Dec  3 10:46:00 1999
+++ xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/regs3sav.h	Thu Feb 10 21:21:14 2000
@@ -1,4 +1,4 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/regs3sav.h,v 1.1.2.2 1999/12/01 12:49:32 hohndel Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/regs3sav.h,v 1.1.2.1 1999/07/30 11:21:28 hohndel Exp $ */
 
 /* regs3v.h
  *
@@ -55,6 +55,25 @@
        }\
 }
 
+#if defined(__alpha__)
+#define mb() __asm__ __volatile__("mb": : :"memory")
+#define S3_IN8(addr)  xf86ReadSparse8(s3savMmioMemSparse, (addr))
+#define S3_IN16(addr) xf86ReadSparse16(s3savMmioMemSparse, (addr))
+#define S3_IN32(addr) *(volatile CARD32 *)((char*)s3savMmioMem + (addr))
+#define S3_OUT8(addr, val)  do { xf86WriteSparse8((val),s3savMmioMemSparse,(addr)); \
+				mb();} while(0)
+#define S3_OUT16(addr, val) do { xf86WriteSparse16((val),s3savMmioMemSparse,(addr)); \
+				mb();} while(0)
+#define S3_OUT32(addr, val) do { *(volatile CARD32 *)((char*)s3savMmioMem + (addr)) = (val); \
+				mb();} while(0)
+#else /* __alpha__ */
+#define S3_IN8(addr)  *(volatile CARD8 *)((char*)s3savMmioMem + (addr))
+#define S3_IN16(addr) *(volatile CARD16 *)((char*)s3savMmioMem + (addr))
+#define S3_IN32(addr) *(volatile CARD32 *)((char*)s3savMmioMem + (addr))
+#define S3_OUT8(addr, val)  *(volatile CARD8 *)((char*)s3savMmioMem + (addr)) = (val)
+#define S3_OUT16(addr, val) *(volatile CARD16 *)((char*)s3savMmioMem + (addr)) = (val)
+#define S3_OUT32(addr, val) *(volatile CARD32 *)((char*)s3savMmioMem + (addr)) = (val)
+#endif /* __alpha__ */
 
 #define S3_ViRGE_SERIES(chip)     ((chip&0xfff0)==0x31e0)
 #define S3_ViRGE_GX2_SERIES(chip) (chip == S3_ViRGE_GX2)
@@ -66,18 +85,9 @@
 #define S3_ANY_SERIES(chip)       (    S3_ViRGE_SERIES(chip)		\
 				    || S3_ViRGE_VX_SERIES(chip))
 
-#define S3_SAVAGE3D_SERIES(chip)  ((chip == S3_SAVAGE3D_MV) ||\
-				   (chip == S3_SAVAGE3D))
-#define	S3_SAVAGE_MX_SERIES(chip)  ((chip == S3_SAVAGE_MX_MV) ||\
-				   (chip == S3_SAVAGE_MX))
-#define	S3_SAVAGE_IX_SERIES(chip) ((chip == S3_SAVAGE_IX_MV) ||\
-				   (chip == S3_SAVAGE_IX))
-#define S3_SAVAGE_MXIX(chip)	  (S3_SAVAGE_MX_SERIES(chip) || \
-				   S3_SAVAGE_IX_SERIES(chip))
-
-#define S3_SAVAGE_SERIES(chip)    (((chip&0xfff0)==0x8a20) || \
-				   (chip==0x9102) || \
-				   S3_SAVAGE_MXIX(chip))
+#define S3_SAVAGE3D_SERIES(chip)  ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
+
+#define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
 
 /* PCI data */
 #define PCI_S3_VENDOR_ID	0x5333
@@ -89,6 +99,7 @@
 #define PCI_SAVAGE_MX		0x8C11
 #define PCI_SAVAGE_IX_MV	0x8C12
 #define PCI_SAVAGE_IX		0x8C13
+#define PCI_SAVAGE_370		0x8A25
 
 #define PCI_ViRGE		0x5631
 #define PCI_ViRGE_VX		0x883D
@@ -101,12 +112,10 @@
 #define S3_UNKNOWN		 0
 #define S3_SAVAGE3D              1
 #define S3_SAVAGE3D_MV           2
-#define S3_SAVAGE4               3
-#define S3_SAVAGE2000            4
-#define S3_SAVAGE_MX_MV		 5
-#define S3_SAVAGE_MX		 6
-#define S3_SAVAGE_IX_MV		 7
-#define S3_SAVAGE_IX		 8
+#define S3_SAVAGE_MX		 3
+#define S3_SAVAGE4               4
+#define S3_SAVAGE_370		 5
+#define S3_SAVAGE2000            6
 
 #define S3_ViRGE		 1
 #define S3_ViRGE_VX		 2
@@ -403,48 +412,48 @@
 }
 LUTENTRY;
 
-#define MAXLOOP 0xffffff /* timeout value for engine waits, ~6 secs */
+#define MAXLOOP 0xfffff /* timeout value for engine waits, ~6 secs */
 /*
  * The correct value for MAXFIFO actually depends on the size of the 
  * command-overflow-buffer in MM48C14.  We happen to use 32K always.
  */
-#define MAXFIFO 0x80C0  /* Number of on-chip and off-chip FIFO slots */
-void S3VGEReset(int from_timeout, int line, char *file);
+#define MAXFIFO 0x7f00  /* Number of on-chip and off-chip FIFO slots */
+void S3SAVGEReset(int from_timeout, int line, char *file);
 
 /* Wait until "v" queue entries are free */
 
 #define WaitQueue(v) \
   if( s3vPriv.NoPCIRetry ) { \
     if( (*s3vPriv.WaitQueue)(v) ) \
-      S3VGEReset(1,__LINE__,__FILE__); \
+      S3SAVGEReset(1,__LINE__,__FILE__); \
   }
 
 /* Wait until GP is idle and queue is empty */
 
 #define WaitIdleEmpty() \
   if( (*s3vPriv.WaitIdleEmpty)() ) { \
-   /*S3VGEReset(1,__LINE__,__FILE__);*/ \
+   /*S3SAVGEReset(1,__LINE__,__FILE__);*/ \
   }
 
 /* Wait until GP is idle */
 
 #define WaitIdle() \
   if( s3vPriv.WaitIdle() ) { \
-    /*S3VGEReset(1,__LINE__,__FILE__);*/ \
+    /*S3SAVGEReset(1,__LINE__,__FILE__);*/ \
   }
 
 /* Wait until Command FIFO is empty */
 
 #define WaitCommandEmpty() \
   if( s3vPriv.WaitCommandEmpty() ) { \
-    /* S3VGEReset(1,__LINE__,__FILE__); */ \
+    /* S3SAVGEReset(1,__LINE__,__FILE__); */ \
   }
 
 /* Wait until a DMA transfer is done */ 
 #define WaitDMAEmpty() \
   do { int loop=0; mem_barrier(); \
        while  (((((mmtr)s3savMmioMem)->dma_regs.regs.cmd.write_pointer) != (((mmtr)s3savMmioMem)->dma_regs.regs.cmd.read_pointer)) && (loop++<MAXLOOP)); \
-       if (loop >= MAXLOOP) S3VGEReset(1,__LINE__,__FILE__); \
+       if (loop >= MAXLOOP) S3SAVGEReset(1,__LINE__,__FILE__); \
   } while(0)
 
 #ifndef NULL
diff -u xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3bci.h xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3bci.h
--- xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3bci.h	Fri Dec  3 10:46:00 1999
+++ xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3bci.h	Thu Feb  3 03:19:00 2000
@@ -1,4 +1,4 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3bci.h,v 1.1.2.2 1999/12/01 12:49:33 hohndel Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3bci.h,v 1.1.2.1 1999/07/30 11:21:28 hohndel Exp $ */
 
 #ifndef _S3BCI_H_
 #define _S3BCI_H_
@@ -10,10 +10,11 @@
     dword |= (temp & 0xFF0000) >> 8; \
     dword |= (temp & 0xFF000000) >> 24; }
 
-#define BCI_GET_PTR unsigned int * bci_ptr = s3vPriv.BciMem
+#define BCI_GET_PTR volatile unsigned int * bci_ptr = s3vPriv.BciMem
+#define BCI_RESET bci_ptr = s3vPriv.BciMem
 
 #if 1
-#define BCI_SEND(dw)   ((*(unsigned int*)(bci_ptr++)) = (unsigned int)(dw))
+#define BCI_SEND(dw)   (*bci_ptr++ = (unsigned int)(dw))
 #else
 __inline__ void BCI_SEND_DEBUG(unsigned int * bci_base,
     unsigned int * bci_ptr, unsigned int dw)
@@ -49,7 +50,7 @@
 #define BCI_CMD_DEST_SBD             0x00001000
 #define BCI_CMD_DEST_SBD_NEW         0x00001400
 
-#define BCI_CMD_SRC_TRANSPARENT      0x00000100
+#define BCI_CMD_SRC_TRANSPARENT      0x00000200
 #define BCI_CMD_SRC_SOLID            0x00000000
 #define BCI_CMD_SRC_GBD              0x00000020
 #define BCI_CMD_SRC_COLOR            0x00000040
diff -u xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3bitmap.c xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3bitmap.c
--- xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3bitmap.c	Fri Dec 31 18:20:59 1999
+++ xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3bitmap.c	Wed Jan 26 01:44:45 2000
@@ -1,4 +1,4 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3bitmap.c,v 1.1.2.4 1999/12/28 12:14:04 hohndel Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3bitmap.c,v 1.1.2.1 1999/07/30 11:21:30 hohndel Exp $ */
 
 void SavageWriteBitmapScreenToScreenColorExpand
 (
@@ -13,7 +13,7 @@
 {
     BCI_GET_PTR;
     unsigned int cmd;
-    unsigned int bd_offset;
+    unsigned char * bd_offset;
     unsigned int bd;
     
     cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
@@ -25,11 +25,11 @@
     bd |= BCI_BD_BW_DISABLE;
     BCI_BD_SET_BPP(bd, 1);
     BCI_BD_SET_STRIDE(bd, srcwidth);
-    bd_offset = srcwidth * srcy + (srcx >> 3) + (int) src;
+    bd_offset = srcwidth * srcy + (srcx >> 3) + src;
 
     WaitQueue(10);
     BCI_SEND(cmd);
-    BCI_SEND(bd_offset);
+    BCI_SEND((unsigned int)bd_offset);
     BCI_SEND(bd);
     BCI_SEND(fg);
     BCI_SEND((bg != -1) ? bg : 0);
@@ -62,7 +62,7 @@
     cmd |= s3vAlu[rop];
 
     if( !srcwidth )
-        return;
+	return;
 
     BCI_SEND(cmd);
     BCI_SEND(BCI_CLIP_LR(x, x+w-1));
@@ -84,19 +84,19 @@
     
     for (j = 0; j < h; j ++) {
         BCI_SEND(BCI_X_Y(x, y+j));
-	BCI_SEND(BCI_W_H(w, 1));
-	srcp = (unsigned int*) src;
-	for (i = count; i > 0; srcp ++, i --) {
-	    /* We have to invert the bits in each byte. */
-	    unsigned long u = *srcp;
-	    u = ((u & 0x0f0f0f0f) << 4) | ((u & 0xf0f0f0f0) >> 4);
-	    u = ((u & 0x33333333) << 2) | ((u & 0xcccccccc) >> 2);
-	    u = ((u & 0x55555555) << 1) | ((u & 0xaaaaaaaa) >> 1);
-	    BCI_SEND(u);
-	}
-	src += srcwidth;
+        BCI_SEND(BCI_W_H(w, 1));
+        srcp = (unsigned int*) src;
+        for (i = count; i > 0; srcp ++, i --) {
+            /* We have to invert the bits in each byte. */
+            unsigned long u = *srcp;
+            u = ((u & 0x0f0f0f0f) << 4) | ((u & 0xf0f0f0f0) >> 4);
+            u = ((u & 0x33333333) << 2) | ((u & 0xcccccccc) >> 2);
+            u = ((u & 0x55555555) << 1) | ((u & 0xaaaaaaaa) >> 1);
+            BCI_SEND(u);
+        }
+        src += srcwidth;
         if( !--reset ) {
-            bci_ptr = s3vPriv.BciMem;
+	    BCI_RESET;
             reset = 65536 / srcwidth;
         }
     }
@@ -144,6 +144,6 @@
     }
 
     for (i = count; i > 0; srcp ++, i --) {
-	BCI_SEND(*srcp);
+        BCI_SEND(*srcp);
     }
 }
diff -u xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3sav_accel.c xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_accel.c
--- xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3sav_accel.c	Fri Dec  3 10:46:01 1999
+++ xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_accel.c	Thu Feb 10 21:35:48 2000
@@ -1,4 +1,4 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_accel.c,v 1.1.2.4 1999/12/02 12:30:36 hohndel Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_accel.c,v 1.1.2.1 1999/07/30 11:21:31 hohndel Exp $ */
 
 /*
  *
@@ -7,7 +7,7 @@
  */
 
 /*
- * The accel file for the ViRGE driver.  
+ * The accel file for the Savage driver.  
  * 
  * Created 20/03/97 by Sebastien Marineau
  * Revision: 
@@ -38,6 +38,9 @@
 
 /* Globals used in driver */
 extern pointer s3savMmioMem;
+#ifdef __alpha__
+extern pointer s3savMmioMemSparse;
+#endif
 static int s3DummyTransferArea;
 static int s3LineHWClipSet = 0;
 
@@ -103,15 +106,10 @@
 void
 S3SAVInitialize2DEngine()
 {
-    unsigned long cobWater;
-
     outw(vgaCRIndex, 0x0140);
     outb(vgaCRIndex, 0x31);
     outb(vgaCRReg, 0x0c);
 
-#define S3_IN32(off) (*(volatile unsigned int*)(((char*)s3savMmioMem)+(off)))
-#define S3_OUT32(off, val) (*(volatile unsigned int*)(((char*)s3savMmioMem)+(off)) = val)
-#define S3_OUT16(off, val) (*(volatile unsigned short*)(((char*)s3savMmioMem)+(off)) = val)
     /* Setup plane masks */
     S3_OUT32(0x8128, ~0); /* enable all write planes */
     S3_OUT32(0x812C, ~0); /* enable all read planes */
@@ -120,24 +118,18 @@
 
     if( s3vPriv.chip < S3_SAVAGE2000 )
     {
-	/* Sav4 doc shows the smaller value in the upper DWORD. */
-	/* However, that's not what the NT driver does. */
-	if( s3vPriv.chip == S3_SAVAGE4 ) {
-	    cobWater = (cob.Size >> 7) * 0x10001 - 0x01400300;
-	}
-	else {
-	    cobWater = (cob.Size >> 2) * 0x10001 - 0x01C00EC0;
-	}
 	/* Disable BCI */
 	S3_OUT32(0x48C18, S3_IN32(0x48C18) & 0x3FF0);
 	/* Disable shadow status update */
 	S3_OUT32(0x48C0C, 0);
 	/* Setup BCI command overflow buffer */
 	S3_OUT32(0x48C14, (cob.Offset >> 11) | (cob.Index << 29));
-	/* Command overflow buffer HI/LOW watermarks */
-	S3_OUT32(0x48C10, cobWater);
 	/* Enable BCI and command overflow buffer */
-	S3_OUT32(0x48C18, S3_IN32(0x48C18) | 0x0C);
+	if( (s3vPriv.chip == S3_SAVAGE4) || (s3vPriv.chip == S3_SAVAGE_370)  )
+	    /* Disable COB on Savage4 */
+	    S3_OUT32(0x48C18, S3_IN32(0x48C18) | 0x08);
+	else
+	    S3_OUT32(0x48C18, S3_IN32(0x48C18) | 0x0C);
     }
     else
     {
@@ -147,9 +139,6 @@
 	S3_OUT32(0x48A30, 0);
 	/* Setup BCI command overflow buffer */
 	S3_OUT32(0x48C18, (cob.Offset >> 7) | (cob.Index));
-	/* Command overflow buffer HI/LOW watermarks */
-	S3_OUT32(0x48C10, 0x6090);
-	S3_OUT32(0x48C14, 0x70A8);
 	/* Enable BCI and command overflow buffer */
 	S3_OUT32(0x48C18, S3_IN32(0x48C18) | 0x00280000 );
     }
@@ -339,6 +328,7 @@
 
     xf86AccelInfoRec.ColorExpandFlags = SCANLINE_PAD_DWORD |
 					CPU_TRANSFER_PAD_DWORD | 
+					BIT_ORDER_IN_BYTE_MSBFIRST |
 					VIDEO_SOURCE_GRANULARITY_PIXEL |
 					LEFT_EDGE_CLIPPING;
     /* WriteBitmap color expand */
@@ -355,13 +345,12 @@
              S3SAVSubsequentCPUToScreenColorExpand;
 #endif
 
-#if 0
+#if 1
     xf86AccelInfoRec.SetupForCPUToScreenColorExpand =
              S3SAVSetupForCPUToScreenColorExpand;
     xf86AccelInfoRec.SubsequentCPUToScreenColorExpand =
              S3SAVSubsequentCPUToScreenColorExpand;
     xf86AccelInfoRec.CPUToScreenColorExpandBase = s3vPriv.BciMem;
-             (void *) &IMG_TRANS;
     xf86AccelInfoRec.CPUToScreenColorExpandRange = 128 * 1024;
 #endif
 
@@ -405,7 +394,7 @@
      * enabled the PIXMAP_CACHE flag, then these lines can be omitted.
      */
 
-     if( s3vPriv.chip == S3_SAVAGE4 ) {
+     if( (s3vPriv.chip == S3_SAVAGE4) || (s3vPriv.chip == S3_SAVAGE_370) ) {
 	 cob.Index = 2 /*4*/;
 	 cob.Size = 0x8000 << cob.Index;
      }
@@ -438,16 +427,6 @@
 void
 S3SAVAccelSync()
 {
-#if 0
-    BCI_GET_PTR;
-
-    WaitQueue(3);
-    BCI_SEND(BCI_CMD_NOP | BCI_CMD_CLIP_NEW);
-    BCI_SEND(BCI_CLIP_TL(0, 0));
-    BCI_SEND(BCI_CLIP_BR(s3vPriv.ScissB, s3vPriv.Width));
-#endif
-
-    WaitCommandEmpty();
     WaitIdleEmpty();
 }
 
@@ -499,9 +478,11 @@
       switch( s3vPriv.chip ) {
         case S3_SAVAGE3D:
         case S3_SAVAGE3D_MV:
+        case S3_SAVAGE_MX:
 	  success = (STATUS_WORD0 & 0x0008ffff) == 0x00080000;
 	  break;
 	case S3_SAVAGE4:
+	case S3_SAVAGE_370:
 	  success = (ALT_STATUS_WORD0 & 0x0081ffff) == 0x00800000;
 	  break;
 	case S3_SAVAGE2000:
@@ -545,7 +526,7 @@
         ErrorF("ViRGE register cache hits: %d misses: %d\n",
             s3vCacheHit, s3vCacheMiss);    
     s3vCacheHit = 0; s3vCacheMiss = 0;
-
+    S3SAVSetGBD();
 }
 
 
@@ -579,9 +560,7 @@
     BCI_SEND(cmd);
     if (transparency_color != -1) {
         BCI_SEND(transparency_color);
-	ErrorF("CopyRect transparency\n");
     }
-    /*ErrorF("CopyRect command 0x%.8x sent\n", cmd);*/
 #endif
     s3SavedBciCmd = cmd;
     s3SavedBgColor = transparency_color;
@@ -609,13 +588,11 @@
 
 #if BCI_REPEAT
     WaitQueue(4);
-    if (s3SavedBgColor != -1) 
-	BCI_SEND(s3SavedBgColor);
     BCI_SEND(BCI_X_Y(x1, y1));
     BCI_SEND(BCI_X_Y(x2, y2));
     BCI_SEND(BCI_W_H(w, h));
 #else
-    WaitQueue(5);
+    WaitQueue(6);
     BCI_SEND(s3SavedBciCmd);
     if (s3SavedBgColor != -1) 
 	BCI_SEND(s3SavedBgColor);
@@ -643,6 +620,16 @@
         | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
         | BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID;
 
+    /* Don't send a color if we don't have to. */
+
+    if( rop == GXcopy )
+    {
+	if( color == 0 )
+	    rop = GXclear;
+	else if( color == MaxMask[s3vPriv.Bpp] )
+	    rop = GXset;
+    }
+
     if(
       (rop != GXclear) &&
       (rop != GXnoop) &&
@@ -690,7 +677,7 @@
     BCI_SEND(BCI_X_Y(x, y));
     BCI_SEND(BCI_W_H(w, h));
 #else
-    WaitQueue(4);
+    WaitQueue(5);
     BCI_SEND(s3SavedBciCmd);
     if( s3SavedBciCmd & BCI_CMD_SEND_COLOR )
 	BCI_SEND(s3SavedFgColor);
@@ -745,6 +732,7 @@
     int cmd;
 
     cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
+	| BCI_CMD_CLIP_LR
         | BCI_CMD_DEST_GBD | BCI_CMD_SRC_MONO;
 
     if(
@@ -759,7 +747,8 @@
 
     if (bg != -1)
         cmd |= BCI_CMD_SEND_COLOR;
-    else cmd |= BCI_CMD_SRC_TRANSPARENT;
+    else 
+	cmd |= BCI_CMD_SRC_TRANSPARENT;
 
 #if BCI_REPEAT    
     WaitQueue(3);
@@ -783,51 +772,24 @@
     WaitQueue(4);
     BCI_SEND(BCI_X_Y(x, y));
     BCI_SEND(BCI_W_H(w, h));
-    BCI_SEND(((w + 31) / 32) * h);
 #else
+    /* 7 is not enough.  XAA will be sending bitmap data next.  We */
+    /* should probably wait for empty/idle here. */
+
     WaitQueue(7);
-    if ( 0 ) {
+
     BCI_SEND(s3SavedBciCmd);
-#if 0
-    if(skipleft != 0)  
-        BCI_SEND(BCI_CLIP_LR(x + skipleft, s3vPriv.Width)); 
-    else
-        BCI_SEND(BCI_CLIP_LR(0, s3vPriv.Width));
-#endif
-    BCI_SEND(s3SavedFgColor);
-    if (s3SavedBgColor != -1)  
+    BCI_SEND(BCI_CLIP_LR(x, x+w-1));
+    x -= skipleft;
+    w += skipleft;
+    w = (w + 31) & ~31;
+    if( s3SavedBciCmd & BCI_CMD_SEND_COLOR )
+	BCI_SEND(s3SavedFgColor);
+    if( s3SavedBgColor != -1 )
 	BCI_SEND(s3SavedBgColor);
-    else BCI_SEND(0);
     BCI_SEND(BCI_X_Y(x, y));
     BCI_SEND(BCI_W_H(w, h));
-    /*BCI_SEND(((w + 31) / 32) * h);*/
-    } else {
-        int i, j, count;
-	s3SavedBciCmd = 0;
-        BCI_SEND(0x4bcc8060);
-        BCI_SEND(s3SavedFgColor);
-        BCI_SEND(s3SavedBgColor);
-	count = (w + 31) / 32;
-	for (j = 0; j < 1; j ++) {
-	    BCI_SEND(BCI_X_Y(x, y+j));
-	    BCI_SEND(BCI_W_H(w, 1));
-	    for (i = count; i > 0; i--) {
-	        BCI_SEND(0xffffffff);
-	    }
-	}
-    }
 #endif
-
-    if(S3SAVROPHasSrc(s3SavedBciCmd<<1)) {
-       xf86AccelInfoRec.CPUToScreenColorExpandBase = 
-             (void *) bci_ptr;
-       xf86AccelInfoRec.ColorExpandFlags &= (~CPU_TRANSFER_BASE_FIXED); 
-       }
-    else {    /* Fix for XAA bug */
-       xf86AccelInfoRec.CPUToScreenColorExpandBase = 
-             (void *) &s3DummyTransferArea;
-       xf86AccelInfoRec.ColorExpandFlags |= CPU_TRANSFER_BASE_FIXED; 
-       }
 }
 
 
@@ -978,7 +940,7 @@
     dx = x2 - x1;
     dy = y2 - y1;
 
-#if 0
+#ifdef DEBUG_EXTRA
     ErrorF("TwoPointLine, (%4d,%4d)-(%4d,%4d), clr %08x, last pt %s\n",
         x1, y1, x2, y2, s3SavedFgColor, (bias & 0x100)?"NO ":"YES");
 #endif
@@ -1013,9 +975,10 @@
 
     if( s3LineHWClipSet ) {
 	cmd |= BCI_CMD_CLIP_CURRENT;
+	s3LineHWClipSet = FALSE;
     }
 
-    WaitQueue(5); 
+    WaitQueue(5);
     BCI_SEND( cmd );
     if( cmd & BCI_CMD_SEND_COLOR )
 	BCI_SEND( s3SavedFgColor );
@@ -1030,6 +993,10 @@
 {
     BCI_GET_PTR;
     int cmd;
+
+#ifdef DEBUG_EXTRA
+    ErrorF("ClipRect, (%4d,%4d)-(%4d,%4d) \n", x1, y1, x2, y2 );
+#endif
 
     cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
     WaitQueue(3);
diff -u xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3sav_cursor.c xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_cursor.c
--- xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3sav_cursor.c	Fri Dec  3 10:46:01 1999
+++ xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_cursor.c	Thu Mar 30 05:44:55 2000
@@ -1,4 +1,4 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_cursor.c,v 1.1.2.2 1999/12/01 12:49:33 hohndel Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_cursor.c,v 1.1.2.1 1999/07/30 11:21:32 hohndel Exp $ */
 
 /*
  *
@@ -110,8 +110,6 @@
     * buffer.  Savage4 requires 4k alignment for the cursor image.
     */
 
-#define S3_IN32(off) (*(unsigned int*)(((char*)s3savMmioMem)+(off)))
-
    if( s3vPriv.chip < S3_SAVAGE2000) {
       s3vCursorVRAMMemSegment = (S3_IN32(0x48C14) & 0x3FFF) * 2 - 4;
    } else {
@@ -416,16 +414,13 @@
    xColorItem sourceColor, maskColor;
    Bool bNeedExtra = FALSE;
 
-   if( S3_SAVAGE_SERIES(s3vPriv.chip) )
+   /* Clock doubled modes need an extra cursor stack write. */
+   outb(0x3c4, 0x18);
+   if( inb(0x3c5) & 0x80 ) 
    {
-      /* Clock doubled modes need an extra cursor stack write. */
-      outb(0x3c4, 0x18);
-      if( inb(0x3c5) & 0x80 ) 
-      {
-         outb(0x3c4, 0x15);
-	 if( inb(0x3c5) & 0x50 )
-	    bNeedExtra = TRUE;
-      }
+      outb(0x3c4, 0x15);
+      if( inb(0x3c5) & 0x50 )
+	 bNeedExtra = TRUE;
    }
 
    if (!xf86VTSema)
@@ -434,49 +429,31 @@
    if (!displayed)
       return;
 
-   switch (vgaBitsPerPixel) {
-   case 8:
-     if (!(S3_ViRGE_GX2_SERIES(s3vPriv.chip) || S3_ViRGE_MX_SERIES(s3vPriv.chip))) {
-      vgaGetInstalledColormaps(pScr, &pmap);
-      sourceColor.red = pCurs->foreRed;
-      sourceColor.green = pCurs->foreGreen;
-      sourceColor.blue = pCurs->foreBlue;
-      FakeAllocColor(pmap, &sourceColor);
-      maskColor.red = pCurs->backRed;
-      maskColor.green = pCurs->backGreen;
-      maskColor.blue = pCurs->backBlue;
-      FakeAllocColor(pmap, &maskColor);
-      FakeFreeColor(pmap, sourceColor.pixel);
-      FakeFreeColor(pmap, maskColor.pixel);
+   /*
+    * The /MX family is apparently unique among the Savages, in that
+    * the cursor color is always straight RGB.  The rest of the Savages
+    * use palettized values at 8-bit when not clock doubled.
+    */
 
-      outb(vgaCRIndex, 0x45);
-      inb(vgaCRReg);	/* reset stack pointer */
-      outb(vgaCRIndex, 0x4A);
-      outb(vgaCRReg, sourceColor.pixel);
-      outb(vgaCRReg, sourceColor.pixel);
-      outb(vgaCRIndex, 0x45);
-      inb(vgaCRReg);	/* reset stack pointer */
-      outb(vgaCRIndex, 0x4B);
-      outb(vgaCRReg, maskColor.pixel);
-      outb(vgaCRReg, maskColor.pixel);
-      break;
-     }  /* else fall through for ViRGE/MX... */
+   if( s3vPriv.chip == S3_SAVAGE_MX )
+      bNeedExtra = TRUE;
+
+   switch (vgaBitsPerPixel) {
    case 16:
-     if (!(S3_ViRGE_GX2_SERIES(s3vPriv.chip) || S3_ViRGE_MX_SERIES(s3vPriv.chip))) {
-      if (vga256InfoRec.weight.green == 5 && s3vPriv.chip != S3_ViRGE_VX) {
+      if (vga256InfoRec.weight.green == 5) {
 	 packedcolfg = ((pCurs->foreRed   & 0xf800) >>  1)
 	    | ((pCurs->foreGreen & 0xf800) >>  6)
-	       | ((pCurs->foreBlue  & 0xf800) >> 11);
+	    | ((pCurs->foreBlue  & 0xf800) >> 11);
 	 packedcolbg = ((pCurs->backRed   & 0xf800) >>  1)
 	    | ((pCurs->backGreen & 0xf800) >>  6)
-	       | ((pCurs->backBlue  & 0xf800) >> 11);
+	    | ((pCurs->backBlue  & 0xf800) >> 11);
       } else {
 	 packedcolfg = ((pCurs->foreRed   & 0xf800) >>  0)
 	    | ((pCurs->foreGreen & 0xfc00) >>  5)
-	       | ((pCurs->foreBlue  & 0xf800) >> 11);
+	    | ((pCurs->foreBlue  & 0xf800) >> 11);
 	 packedcolbg = ((pCurs->backRed   & 0xf800) >>  0)
 	    | ((pCurs->backGreen & 0xfc00) >>  5)
-	       | ((pCurs->backBlue  & 0xf800) >> 11);
+	    | ((pCurs->backBlue  & 0xf800) >> 11);
       }
       outb(vgaCRIndex, 0x45);
       inb(vgaCRReg);		/* reset stack pointer */
@@ -499,7 +476,35 @@
 	  outb(vgaCRReg, packedcolbg>>8);
       }
       break;
-     }  /* else fall through for ViRGE/MX... */
+   case 8:
+      if( !bNeedExtra )
+      {
+	 vgaGetInstalledColormaps(pScr, &pmap);
+	 sourceColor.red = pCurs->foreRed;
+	 sourceColor.green = pCurs->foreGreen;
+	 sourceColor.blue = pCurs->foreBlue;
+	 FakeAllocColor(pmap, &sourceColor);
+	 maskColor.red = pCurs->backRed;
+	 maskColor.green = pCurs->backGreen;
+	 maskColor.blue = pCurs->backBlue;
+	 FakeAllocColor(pmap, &maskColor);
+	 FakeFreeColor(pmap, sourceColor.pixel);
+	 FakeFreeColor(pmap, maskColor.pixel);
+
+	 outb(vgaCRIndex, 0x45);
+	 inb(vgaCRReg);	/* reset stack pointer */
+	 outb(vgaCRIndex, 0x4A);
+	 outb(vgaCRReg, sourceColor.pixel);
+	 outb(vgaCRReg, sourceColor.pixel);
+	 outb(vgaCRIndex, 0x45);
+	 inb(vgaCRReg);	/* reset stack pointer */
+	 outb(vgaCRIndex, 0x4B);
+	 outb(vgaCRReg, maskColor.pixel);
+	 outb(vgaCRReg, maskColor.pixel);
+	 break;
+      }
+      /* else */
+      /* FALLTHROUGH */
    case 24:
    case 32:
       outb(vgaCRIndex, 0x45);
@@ -513,7 +518,7 @@
       inb(vgaCRReg);		/* reset stack pointer */
       outb(vgaCRIndex, 0x4B);
       outb(vgaCRReg, pCurs->backBlue >>8);
-	 outb(vgaCRReg, pCurs->backGreen>>8);
+      outb(vgaCRReg, pCurs->backGreen>>8);
       outb(vgaCRReg, pCurs->backRed  >>8);
       break;
    }
diff -u xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3sav_driver.c xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_driver.c
--- xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3sav_driver.c	Fri Dec  3 10:46:01 1999
+++ xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_driver.c	Mon Jun 19 22:11:04 2000
@@ -1,4 +1,4 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_driver.c,v 1.1.2.4 1999/12/01 12:49:34 hohndel Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_driver.c,v 1.1.2.1 1999/07/30 11:21:33 hohndel Exp $ */
 
 /*
  *
@@ -13,21 +13,16 @@
  * Tim Roberts, 21-June-1999.
  */
 
-/* This is an intial version of the ViRGE driver for XAA 
+/* This is an intial version of the Savage driver for XAA 
  * Started 09/03/97 by S. Marineau
  *
  * What works: 
- * - Supports PCI hardware, ViRGE and ViRGE/VX, probably ViRGE/DXGX
- * - Supports 8bpp, 16bpp and 24bpp. There is some support for 32bpp.
+ * - Supports PCI or AGP hardware, Savage3D, 4 or 2000.
+ * - Supports 8bpp, 16bpp and 32. There is no support for 24bpp.
  * - VT switching seems to work well, no corruption. 
- * - A whole slew of XConfig options for memory, PCI and acceleration
  * - Acceleration is quite complete
  * 
  * 
- * What does not work:
- * - None of this doublescan stuff
- *
- * 
  * What I attempt to do here:
  *
  *  - Rewrite the init/save functions from the accel server such that they
@@ -78,6 +73,8 @@
 #include "s3sav_driver.h"
 #include "regs3sav.h"
 
+static const char S3SAVVersionId[] = "$Version: s3_savage 1.0.11 $";
+
 /*
  * If the symbol USEBIOS is defined, we try to use the onboard BIOS to do
  * mode switches.  We query the VESA BIOS list, and match the requested
@@ -173,10 +170,8 @@
    { S3_SAVAGE3D_MV,  "Savage3D/MV"},
    { S3_SAVAGE4,      "Savage4"},
    { S3_SAVAGE2000,   "Savage2000"},
-   { S3_SAVAGE_MX_MV, "Savage/MX-MV"},
    { S3_SAVAGE_MX,    "Savage/MX"},
-   { S3_SAVAGE_IX_MV, "Savage/IX-MV"},
-   { S3_SAVAGE_IX,    "Savage/IX"},
+   { S3_SAVAGE_370,   "Savage/NB"},
    { -1,              ""},
    };
 
@@ -189,6 +184,9 @@
 
 int vgaCRIndex, vgaCRReg;
 pointer s3savMmioMem = NULL;   /* MMIO base address */
+#ifdef __alpha__
+pointer s3savMmioMemSparse = NULL;
+#endif
 extern vgaHWCursorRec vgaHWCursor;
 
 #ifdef USEBIOS
@@ -196,7 +194,6 @@
 /* Information about the current BIOS modes. */
 #define iabs(a)	((int)(a)>0?(a):(-(a)))
 S3VMODETABLE * s3vModeTable = NULL;
-unsigned short s3vModeCount = 0;
 
 #endif
 
@@ -222,6 +219,27 @@
  * three chips, and even the idle vs busy state flipped in the Sav2K
  */
 
+static void
+ResetBCI2K()
+{
+    CARD32 cob = S3_IN32( 0x48c18 );
+    /* if BCI is enabled and BCI is busy... */
+
+    if( 
+	(cob & 0x00000008) &&
+	! (ALT_STATUS_WORD0 & 0x00200000)
+    )
+    {
+	ErrorF( "Resetting BCI, stat = %08x...\n", ALT_STATUS_WORD0);
+	/* Turn off BCI */
+	S3_OUT32( 0x48c18, cob & ~8 );
+	usleep(10000);
+	/* Turn it back on */
+	S3_OUT32( 0x48c18, cob );
+	usleep(10000);
+    }
+}
+
 /* Wait until "v" queue entries are free */
 
 static int
@@ -231,6 +249,7 @@
     int slots = MAXFIFO - v;
 
     mem_barrier();
+    loop &= STATUS_WORD0;
     while( ((STATUS_WORD0 & 0x0000ffff) > slots) && (loop++ < MAXLOOP))
 	;
     return loop >= MAXLOOP;
@@ -245,7 +264,7 @@
     if( !s3vPriv.NoPCIRetry )
 	return;
     mem_barrier();
-    while( ((ALT_STATUS_WORD0 & 0x0001ffff) > slots) && (loop++ < MAXLOOP))
+    while( ((ALT_STATUS_WORD0 & 0x001fffff) > slots) && (loop++ < MAXLOOP))
 	;
     return loop >= MAXLOOP;
 }
@@ -261,6 +280,8 @@
     mem_barrier();
     while( ((ALT_STATUS_WORD0 & 0x000fffff) > slots) && (loop++ < MAXLOOP))
 	;
+    if( loop >= MAXLOOP )
+	ResetBCI2K();
     return loop >= MAXLOOP;
 }
 
@@ -271,6 +292,7 @@
 {
     int loop = 0;
     mem_barrier();
+    loop &= STATUS_WORD0;
     while( ((STATUS_WORD0 & 0x0008ffff) != 0x80000) && (loop++ < MAXLOOP) )
 	;
     return loop >= MAXLOOP;
@@ -281,7 +303,7 @@
 {
     int loop = 0;
     mem_barrier();
-    while( ((ALT_STATUS_WORD0 & 0x0081ffff) != 0x00800000) && (loop++ < MAXLOOP) )
+    while( ((ALT_STATUS_WORD0 & 0x00a1ffff) != 0x00a00000) && (loop++ < MAXLOOP) )
 	;
     return loop >= MAXLOOP;
 }
@@ -291,8 +313,13 @@
 {
     int loop = 0;
     mem_barrier();
+    /* CAUTION!  How do we insure this read isn't optimized away? */
+    /* Is the "volatile" enough to do that? */
+    loop &= ALT_STATUS_WORD0;
     while( ((ALT_STATUS_WORD0 & 0x009fffff) != 0) && (loop++ < MAXLOOP) )
 	;
+    if( loop >= MAXLOOP )
+	ResetBCI2K();
     return loop >= MAXLOOP;
 }
 
@@ -323,6 +350,7 @@
 {
     int loop = 0;
     mem_barrier();
+    loop &= ALT_STATUS_WORD0;
     while( (ALT_STATUS_WORD0 & 0x00900000) && (loop++ < MAXLOOP) )
 	;
     return loop >= MAXLOOP;
@@ -355,6 +383,8 @@
     mem_barrier();
     while( (ALT_STATUS_WORD0 & 0x001fffff) && (loop++ < MAXLOOP) )
 	;
+    if( loop >= MAXLOOP )
+	ResetBCI2K();
     return loop >= MAXLOOP;
 }
 
@@ -392,10 +422,12 @@
       outb(vgaCRIndex, 0x38);      /* for register CR38, (REG_LOCK1) */
       outb(vgaCRReg, 0x48);        /* unlock S3 register set for read/write */
       outb(vgaCRIndex, 0x39);    
-      outb(vgaCRReg, 0xa5);
+      outb(vgaCRReg, 0xa0);
+      #if 0
       outb(vgaCRIndex, 0x40);
       tmp = inb(vgaCRReg);
       outb(vgaCRReg, tmp & ~0x01);   /* avoid lockups when reading I/O port 0x92e8 */
+      #endif
       enterCalled = TRUE;
       }
 
@@ -512,49 +544,52 @@
 
 	/* Patch CR79.  These values are magical. */
 
-	outb(vgaCRIndex, 0x6d);
-	cr6d = inb(vgaCRReg);
+	if( s3vPriv.chip != S3_SAVAGE_MX )
+	{
+	    outb(vgaCRIndex, 0x6d);
+	    cr6d = inb(vgaCRReg);
 
-	cr79 = 0x04;
+	    cr79 = 0x04;
 
-	if( vga256InfoRec.displayWidth >= 1024 )
-	{
-	    if( vgaBitsPerPixel == 32 )
+	    if( vga256InfoRec.displayWidth >= 1024 )
 	    {
-		if( restore->refresh >= 130 )
-		    cr79 = 0x03;
-		else if( vga256InfoRec.displayWidth >= 1280 )
-		    cr79 = 0x02;
-		else if(
-		    (vga256InfoRec.displayWidth == 1024) &&
-		    (restore->refresh >= 75)
-		)
+		if( vgaBitsPerPixel == 32 )
 		{
-		    if( cr6d && LCD_ACTIVE )
-			cr79 = 0x05;
-		    else
-			cr79 = 0x08;
+		    if( restore->refresh >= 130 )
+			cr79 = 0x03;
+		    else if( vga256InfoRec.displayWidth >= 1280 )
+			cr79 = 0x02;
+		    else if(
+			(vga256InfoRec.displayWidth == 1024) &&
+			(restore->refresh >= 75)
+		    )
+		    {
+			if( cr6d && LCD_ACTIVE )
+			    cr79 = 0x05;
+			else
+			    cr79 = 0x08;
+		    }
 		}
-	    }
-	    else if( vgaBitsPerPixel == 16)
-	    {
-/* The windows driver uses 0x13 for 16-bit 130Hz, but I see terrible
- * screen artifacts with that value.  Let's keep it low for now.
- *		if( restore->refresh >= 130 )
- *		    cr79 = 0x13;
- *		else
- */
-		if( vga256InfoRec.displayWidth == 1024 )
+		else if( vgaBitsPerPixel == 16)
 		{
-		    if( cr6d && LCD_ACTIVE )
-			cr79 = 0x08;
-		    else
-			cr79 = 0x0e;
+    /* The windows driver uses 0x13 for 16-bit 130Hz, but I see terrible
+     * screen artifacts with that value.  Let's keep it low for now.
+     *		if( restore->refresh >= 130 )
+     *		    cr79 = 0x13;
+     *		else
+     */
+		    if( vga256InfoRec.displayWidth == 1024 )
+		    {
+			if( cr6d && LCD_ACTIVE )
+			    cr79 = 0x08;
+			else
+			    cr79 = 0x0e;
+		    }
 		}
 	    }
 	}
 
-        if( s3vPriv.chip != S3_SAVAGE2000)
+        if( (s3vPriv.chip != S3_SAVAGE2000) && (s3vPriv.chip != S3_SAVAGE_MX) )
 	    outw(vgaCRIndex, (cr79 << 8) | 0x79);
 
 	/* Make sure 16-bit memory access is enabled. */
@@ -584,7 +619,7 @@
 	    outb(vgaCRIndex, 0x73);
 	    outb(vgaCRReg, inb(vgaCRReg) & 0xdf );
 	}
-	else
+	else if( s3vPriv.chip != S3_SAVAGE_MX )
 	{
 	    outb(vgaCRIndex, 0x68);
 	    if( !(inb(vgaCRReg) & 0x80) )
@@ -616,6 +651,18 @@
       S3SAVDisableSTREAMS();     /* If STREAMS was running, disable it */
       }
 
+#ifdef USEBIOS
+   /*
+    * Some Savage/MX and /IX systems go nuts when trying to exit the
+    * server after WindowMaker has displayed a gradient background.  I
+    * haven't been able to find what causes it, but a non-destructive
+    * switch to mode 3 here seems to eliminate the issue.
+    */
+
+   if( s3vPriv.chip == S3_SAVAGE_MX )
+      S3SAVSetTextMode();
+#endif
+
    /* Restore S3 extended regs */
    outb(vgaCRIndex, 0x66);             
    outb(vgaCRReg, restore->CR66);
@@ -623,6 +670,8 @@
    outb(vgaCRReg, restore->CR3A);
    outb(vgaCRIndex, 0x31);    
    outb(vgaCRReg, restore->CR31);
+   outb(vgaCRIndex, 0x32);    
+   outb(vgaCRReg, restore->CR32);
    outb(vgaCRIndex, 0x58);             
    outb(vgaCRReg, restore->CR58);
 
@@ -637,6 +686,19 @@
    outb(0x3c4, 0x15);
    outb(0x3c5, restore->SR15); 
 
+   /* Restore flat panel expansion regsters. */
+   if( s3vPriv.chip == S3_SAVAGE_MX ) {
+      int i;
+      for( i = 0; i < 8; i++ ) {
+         outb(0x3c4, 0x54+i);
+	 outb(0x3c5, restore->SR54[i]);
+      }
+   }
+
+   outb(vgaCRIndex, 0x67);             
+   cr67 = inb(vgaCRReg) & 0xf; /* Possible hardware bug on VX? */
+   outb(vgaCRReg, 0);
+
    /* Restore the standard VGA registers */
    vgaHWRestore((vgaHWPtr)restore);
 
@@ -660,7 +722,9 @@
    /* Restore the desired video mode with CR67 */
         
    outb(vgaCRIndex, 0x67);             
+#if 0
    cr67 = inb(vgaCRReg) & 0xf; /* Possible hardware bug on VX? */
+#endif
    outb(vgaCRReg, 0x50 | cr67); 
    usleep(10000);
    outb(vgaCRIndex, 0x67);             
@@ -703,6 +767,9 @@
    outb(vgaCRIndex, 0xB0); /* Savage4 config3 */
    outb(vgaCRReg, restore->CRB0);
 
+   outb(vgaCRIndex, 0x32);
+   outb(vgaCRReg, restore->CR32);
+
    /* Unlock extended sequencer regs */
    outb(0x3c4, 0x08);
    outb(0x3c5, 0x06); 
@@ -890,13 +957,15 @@
    outb(0x3c5, 0x06); 
 
    /* Now we save all the s3 extended regs we need */
-   outb(vgaCRIndex, 0x31);             
+   outb(vgaCRIndex, 0x31);
    save->CR31 = inb(vgaCRReg);
-   outb(vgaCRIndex, 0x34);             
+   outb(vgaCRIndex, 0x32);
+   save->CR32 = inb(vgaCRReg);
+   outb(vgaCRIndex, 0x34);
    save->CR34 = inb(vgaCRReg);
-   outb(vgaCRIndex, 0x36);             
+   outb(vgaCRIndex, 0x36);
    save->CR36 = inb(vgaCRReg);
-   outb(vgaCRIndex, 0x3a);             
+   outb(vgaCRIndex, 0x3a);
    save->CR3A = inb(vgaCRReg);
    outb(vgaCRIndex, 0x40);
    save->CR40 = inb(vgaCRReg);
@@ -908,15 +977,15 @@
    save->CR50 = inb(vgaCRReg);
    outb(vgaCRIndex, 0x51);
    save->CR51 = inb(vgaCRReg);
-   outb(vgaCRIndex, 0x53);             
+   outb(vgaCRIndex, 0x53);
    save->CR53 = inb(vgaCRReg);
-   outb(vgaCRIndex, 0x58);             
+   outb(vgaCRIndex, 0x58);
    save->CR58 = inb(vgaCRReg);
-   outb(vgaCRIndex, 0x66);             
+   outb(vgaCRIndex, 0x66);
    save->CR66 = inb(vgaCRReg);
-   outb(vgaCRIndex, 0x67);             
+   outb(vgaCRIndex, 0x67);
    save->CR67 = inb(vgaCRReg);
-   outb(vgaCRIndex, 0x68);             
+   outb(vgaCRIndex, 0x68);
    save->CR68 = inb(vgaCRReg);
    outb(vgaCRIndex, 0x69);
    save->CR69 = inb(vgaCRReg);
@@ -971,6 +1040,15 @@
    outb(0x3c4, 0x18);
    save->SR18 = inb(0x3c5);
 
+   /* Save flat panel expansion regsters. */
+
+   if( s3vPriv.chip == S3_SAVAGE_MX ) {
+      int i;
+      for( i = 0; i < 8; i++ ) {
+         outb(0x3c4, 0x54+i);
+	 save->SR54[i] = inb(0x3c5);
+      }
+   }
 
    /* And if streams is to be used, save that as well */
 
@@ -1066,58 +1144,58 @@
 static Bool
 S3SAVProbe()
 {
-S3PCIInformation *pciInfo = NULL;
-unsigned char config1, m, n, n1, n2, cr66, sr8;
-int mclk;
-DisplayModePtr pMode, pEnd;
-
-   if (vga256InfoRec.chipset) {
-      if (StrCaseCmp(vga256InfoRec.chipset,S3SAVIdent(0)))
-      return(FALSE);
-   } 
-
-   /* Start with PCI probing, this should get us quite far already */
-
-   pciInfo = S3SAVGetPCIInfo();
-   if (!pciInfo)
-      return FALSE;
-
-   if (pciInfo && pciInfo->MemBase && !vga256InfoRec.MemBase) {
-      if (pciInfo->ChipType >= S3_SAVAGE4) {
-	 s3vPriv.MmioBase = pciInfo->MemBase + S3_NEWMMIO_REGBASE_S4;
-	 s3vPriv.FrameBufferBase = pciInfo->MemBase1;
-      }
-      else {
+    S3PCIInformation *pciInfo = NULL;
+    unsigned char config1, m, n, n1, n2, cr66, sr8;
+    int mclk;
+    DisplayModePtr pMode, pEnd;
+
+    if (vga256InfoRec.chipset) {
+	if (StrCaseCmp(vga256InfoRec.chipset,S3SAVIdent(0)))
+	    return(FALSE);
+    } 
+
+    /* Start with PCI probing, this should get us quite far already */
+
+    pciInfo = S3SAVGetPCIInfo();
+    if (!pciInfo)
+	return FALSE;
+ 
+    if( !S3_SAVAGE_SERIES(pciInfo->ChipType) ) {
+       if (xf86Verbose > 1)
+	  ErrorF("%s %s: Unsupported (non-Savage) S3 chipset detected!\n", 
+	     XCONFIG_PROBED, vga256InfoRec.name);
+       return FALSE;
+    }
+    else {
+	s3vPriv.chip = pciInfo->ChipType;
+	ErrorF("%s %s: Detected S3 %s\n", XCONFIG_PROBED, vga256InfoRec.name, 
+	    xf86TokenToString(s3savChipTable, s3vPriv.chip));
+	ErrorF("%s %s: using driver for chipset \"%s\"\n",XCONFIG_PROBED, 
+	    vga256InfoRec.name, S3SAVIdent(0));
+    }
+
+    if( vgaBitsPerPixel == 24 ) {
+	ErrorF("%s %s: %s: This server cannot do depth 24.  Use depth 32.",
+	    XCONFIG_GIVEN, vga256InfoRec.name, vga256InfoRec.chipset
+	);
+	return FALSE;
+    }
+ 
+   if( pciInfo->MemBase && !vga256InfoRec.MemBase) {
+      if( S3_SAVAGE3D_SERIES(pciInfo->ChipType) ) {
 	 s3vPriv.MmioBase = pciInfo->MemBase + S3_NEWMMIO_REGBASE_S3;
 	 s3vPriv.FrameBufferBase = pciInfo->MemBase;
       }
-      vga256InfoRec.MemBase = s3vPriv.FrameBufferBase;
-   }
-   if (pciInfo)
-      if(pciInfo->ChipType != S3_SAVAGE3D && 
-	 pciInfo->ChipType != S3_SAVAGE3D_MV &&
-	 pciInfo->ChipType != S3_SAVAGE4 &&
-	 pciInfo->ChipType != S3_SAVAGE2000){
-          if (xf86Verbose > 1)
-             ErrorF("%s %s: Unsupported (non-Savage) S3 chipset detected!\n", 
-                XCONFIG_PROBED, vga256InfoRec.name);
-          return FALSE;
-          }
       else {
-         s3vPriv.chip = pciInfo->ChipType;
-         ErrorF("%s %s: Detected S3 %s\n",XCONFIG_PROBED,
-            vga256InfoRec.name, xf86TokenToString(s3savChipTable, s3vPriv.chip));
-         ErrorF("%s %s: using driver for chipset \"%s\"\n",XCONFIG_PROBED, 
-            vga256InfoRec.name, S3SAVIdent(0));
-	 }
+	 s3vPriv.MmioBase = pciInfo->MemBase + S3_NEWMMIO_REGBASE_S4;
+	 s3vPriv.FrameBufferBase = pciInfo->MemBase1;
+      }
+   }
 
    vga256InfoRec.chipset = S3SAVIdent(0);
 
-#ifdef __alpha__
-   if (xf86bpp > 16)
-     FatalError("%s %s: %d bpp not yet supported for Alpha/AXP\n",
-		XCONFIG_GIVEN, vga256InfoRec.name, xf86bpp);
-#endif
+   if( s3vPriv.FrameBufferBase && !vga256InfoRec.MemBase )
+      vga256InfoRec.MemBase = (CARD32)s3vPriv.FrameBufferBase;
 
    /* Add/enable IO ports to list: call EnterLeave */
    S3SAVEnterLeave(ENTER);
@@ -1139,48 +1217,34 @@
    /* And compute the amount of video memory and offscreen memory */
    s3vPriv.MemOffScreen = 0;
    if (!vga256InfoRec.videoRam) {
-      if( (s3vPriv.ChipId == PCI_SAVAGE4) ||
-      	  (s3vPriv.ChipId == PCI_SAVAGE2000)
-      ) {
-	 switch (config1 >> 5) {
-	 case 0:
-	    vga256InfoRec.videoRam = 2;
-	    break;
-	 case 1:
-	    vga256InfoRec.videoRam = 4;
+      static unsigned char RamSavage3D[] = { 8, 4, 4, 2 };
+      static unsigned char RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 2 };
+      static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
+      static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 };
+
+      switch( s3vPriv.chip ) {
+         case S3_SAVAGE3D:
+         case S3_SAVAGE3D_MV:
+	    vga256InfoRec.videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ];
 	    break;
-	 case 2:
-	    vga256InfoRec.videoRam = 8;
-	    break;
-	 case 3:
-	    vga256InfoRec.videoRam = 12;
-	    break;
-	 case 4:
-	    vga256InfoRec.videoRam = 16;
+
+         case S3_SAVAGE4:
+         case S3_SAVAGE2000:
+	    vga256InfoRec.videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ];
 	    break;
-	 case 5:
-	    vga256InfoRec.videoRam = 32;
+
+	 case S3_SAVAGE_MX:
+	    vga256InfoRec.videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ];
 	    break;
-	 case 6:
-	    vga256InfoRec.videoRam = 64;
+
+	 case S3_SAVAGE_370:
+	    vga256InfoRec.videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ];
 	    break;
+
 	 default:
-	    vga256InfoRec.videoRam = 2;
-         }  
-      }
-      else {
-	 switch((config1 & 0xC0) >> 6) {
-	 case 0:
-	    vga256InfoRec.videoRam = 8;
-	    break;
-	 case 1:
-	 case 2:
-	    vga256InfoRec.videoRam = 4;
+	    /* How did we get here? */
+	    vga256InfoRec.videoRam = 0;
 	    break;
-	 case 3:
-	 default:
-	    vga256InfoRec.videoRam = 2;
-	 }
       }
 
       vga256InfoRec.videoRam *= 1024;
@@ -1217,27 +1281,17 @@
    if (vga256InfoRec.dacSpeeds[3] <= 0 && vga256InfoRec.dacSpeeds[2] > 0)
       vga256InfoRec.dacSpeeds[3] = vga256InfoRec.dacSpeeds[2];
 
-   if (s3vPriv.chip == S3_SAVAGE3D ||
-       s3vPriv.chip == S3_SAVAGE3D_MV ||
-       s3vPriv.chip == S3_SAVAGE4 ||
-       s3vPriv.chip == S3_SAVAGE2000) {
-      if (vga256InfoRec.dacSpeeds[0] <= 0) vga256InfoRec.dacSpeeds[0] = 250000;
-      if (vga256InfoRec.dacSpeeds[1] <= 0) vga256InfoRec.dacSpeeds[1] = 250000;
-      if (vga256InfoRec.dacSpeeds[2] <= 0) vga256InfoRec.dacSpeeds[2] = 220000;
-      if (vga256InfoRec.dacSpeeds[3] <= 0) vga256InfoRec.dacSpeeds[3] = 220000;
-   }
-   else {
-      if (vga256InfoRec.dacSpeeds[0] <= 0) vga256InfoRec.dacSpeeds[0] = 250000;
-      if (vga256InfoRec.dacSpeeds[1] <= 0) vga256InfoRec.dacSpeeds[1] = 250000;
-      if (vga256InfoRec.dacSpeeds[2] <= 0) vga256InfoRec.dacSpeeds[2] = 220000;
-      if (vga256InfoRec.dacSpeeds[3] <= 0) vga256InfoRec.dacSpeeds[3] = 220000;
-   }
+   if (vga256InfoRec.dacSpeeds[0] <= 0) vga256InfoRec.dacSpeeds[0] = 250000;
+   if (vga256InfoRec.dacSpeeds[1] <= 0) vga256InfoRec.dacSpeeds[1] = 250000;
+   if (vga256InfoRec.dacSpeeds[2] <= 0) vga256InfoRec.dacSpeeds[2] = 220000;
+   if (vga256InfoRec.dacSpeeds[3] <= 0) vga256InfoRec.dacSpeeds[3] = 220000;
 
    /* Set status word positions based on chip type. */
 
    switch( s3vPriv.chip ) {
       case S3_SAVAGE3D:
       case S3_SAVAGE3D_MV:
+      case S3_SAVAGE_MX:
          s3vPriv.WaitQueue = WaitQueue3D;
 	 s3vPriv.WaitIdle = WaitIdle3D;
 	 s3vPriv.WaitIdleEmpty = WaitIdleEmpty3D;
@@ -1245,6 +1299,7 @@
 	 break;
 
       case S3_SAVAGE4:
+      case S3_SAVAGE_370:
          s3vPriv.WaitQueue = WaitQueue4;
 	 s3vPriv.WaitIdle = WaitIdle4;
 	 s3vPriv.WaitIdleEmpty = WaitIdleEmpty4;
@@ -1325,7 +1380,7 @@
       s3vPriv.HorizScaleFactor = 1;
       }
    else if (vgaBitsPerPixel == 16){
-      s3vPriv.HorizScaleFactor = 2;
+      s3vPriv.HorizScaleFactor = 1;
       }
    else {     
       s3vPriv.HorizScaleFactor = 1;
@@ -1333,8 +1388,14 @@
 
 
    /* And map MMIO memory, abort if we cannot */
-   s3savMmioMem = xf86MapVidMem(vga256InfoRec.scrnIndex, MMIO_REGION,
-	     (pointer) s3vPriv.MmioBase, S3_NEWMMIO_REGSIZE);
+#ifdef __alpha__
+   s3savMmioMemSparse = xf86MapVidMemSparse(
+      vga256InfoRec.scrnIndex, MMIO_REGION,
+      s3vPriv.MmioBase, S3_NEWMMIO_REGSIZE);
+#endif
+   s3savMmioMem = xf86MapVidMem(
+      vga256InfoRec.scrnIndex, MMIO_REGION,
+      s3vPriv.MmioBase, S3_NEWMMIO_REGSIZE);
    s3vPriv.MmioMem = s3savMmioMem;
    s3vPriv.BciMem = (char*)s3vPriv.MmioMem + 0x10000;
 
@@ -1352,38 +1413,31 @@
 #ifdef	USEBIOS
    /* Go probe the BIOS for all the modes and refreshes at this depth. */
 
-   /*
-    * What I want here is an array of all mode numbers valid for this
-    * depth, and the list of valid refresh rates to go with them.  
-    *
-    * x, y, mode, array[8] of refresh
-    */
-
    if( s3vModeTable )
    {
-      xfree( s3vModeTable );
+      S3SAVFreeBIOSModeTable( &s3vModeTable );
    }
    
-   s3vModeCount = S3SAVGetBIOSModeCount( vgaBitsPerPixel );
+   s3vModeTable = S3SAVGetBIOSModeTable( vgaBitsPerPixel );
 
-   if( !s3vModeCount ) {
+   if( !s3vModeTable || !s3vModeTable->NumModes ) {
      FatalError("%s %s: Failed to fetch any BIOS modes.\n",
        XCONFIG_PROBED, vga256InfoRec.name
      );
    }
 
-   s3vModeTable = (S3VMODETABLE*)xcalloc(sizeof(S3VMODETABLE), s3vModeCount);
-   S3SAVGetBIOSModeTable( vgaBitsPerPixel, s3vModeTable );
-
    if( xf86Verbose )
    {
       int i;
-      S3VMODETABLE* pmt;
+      PS3VMODEENTRY pmt;
 
-      ErrorF("%s %s: Found %d modes at this depth:\n", 
-         XCONFIG_PROBED, vga256InfoRec.name, s3vModeCount);
+      ErrorF( "%s %s: Found %d modes at this depth:\n", 
+         XCONFIG_PROBED, vga256InfoRec.name, s3vModeTable->NumModes);
       
-      for( i = 0, pmt = s3vModeTable; i < s3vModeCount; i++, pmt++ )
+      for(
+	  i = 0, pmt = s3vModeTable->Modes; 
+	  i < s3vModeTable->NumModes; 
+	  i++, pmt++ )
       {
          int j;
          ErrorF( "[%03x] %d x %d", pmt->VesaMode, pmt->Width, pmt->Height );
@@ -1480,9 +1534,7 @@
          ErrorF("%s %s: %s: Horizontal mode timing overflow (%d)\n",
             XCONFIG_PROBED, vga256InfoRec.name,
             vga256InfoRec.chipset, mode->HTotal);
-#ifndef	USEBIOS
          return MODE_BAD;
-#endif
          }
    if (mode->VTotal > 2047) {
       if(verbose)
@@ -1530,7 +1582,8 @@
 unsigned char tmp;
 
    if(s3vPriv.STREAMSRunning == FALSE) {
-      Base = ((y * vga256InfoRec.displayWidth + x)
+      /* We can only adjust to even x's. */
+      Base = ((y * vga256InfoRec.displayWidth + (x & ~1))
 		* (vgaBitsPerPixel / 8)) >> 2;
       if (vgaBitsPerPixel == 24) 
 	Base = Base+2 - (Base+2) % 3;
@@ -1538,8 +1591,7 @@
       /* Now program the start address registers */
       outw(vgaCRIndex, (Base & 0x00FF00) | 0x0C);
       outw(vgaCRIndex, ((Base & 0x00FF) << 8) | 0x0D);
-      outb(vgaCRIndex, 0x69);
-      outb(vgaCRReg, (Base & 0xFF0000) >> 16);   
+      outw(vgaCRIndex, ((Base & 0xFF0000) >> 8) | 0x69);
       }
    else {          /* Change start address for STREAMS case */
       VerticalRetraceWait();
@@ -1643,7 +1695,7 @@
 int i, j;
 unsigned int Refresh;
 #ifdef USEBIOS
-S3VMODETABLE * pmt;
+S3VMODEENTRY * pmt;
 #endif
 
    /* First we adjust the horizontal timings if needed */
@@ -1678,7 +1730,9 @@
    ErrorF( "Desired refresh rate = %dHz\n", Refresh );
 #endif
 
-   for( i = 0, pmt = s3vModeTable; i < s3vModeCount; i++, pmt++ )
+   for( i = 0, pmt = s3vModeTable->Modes; 
+      i < s3vModeTable->NumModes;
+      i++, pmt++ )
    {
       if( (pmt->Width == mode->HDisplay) && (pmt->Height == mode->VDisplay) )
       {
diff -u xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3sav_driver.h xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_driver.h
--- xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3sav_driver.h	Fri Dec  3 10:46:01 1999
+++ xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_driver.h	Mon Jun 19 20:20:50 2000
@@ -1,4 +1,4 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_driver.h,v 1.1.2.2 1999/12/01 12:49:34 hohndel Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_driver.h,v 1.1.2.1 1999/07/30 11:21:34 hohndel Exp $ */
 
 /* Header file for ViRGE server */
 
@@ -19,10 +19,10 @@
    unsigned int refresh;
 
    unsigned char SR8, SR10, SR11, SR12, SR13, SR15, SR18, SR29; /* SR9-SR1C, ext seq. */
-   /*unsigned char SR54, SR55, SR56, SR57;*/
+   unsigned char SR54[8];
    unsigned char Clock;
    unsigned char s3DacRegs[0x101];
-   unsigned char CR31, CR33, CR34, CR36, CR3A, CR3B, CR3C;
+   unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C;
    unsigned char CR40, CR42, CR43, CR45;
    unsigned char CR50, CR51, CR53, CR58, CR5B, CR5D, CR5E;
    unsigned char CR65, CR66, CR67, CR68, CR69, CR6F; /* Video attrib. */
@@ -47,8 +47,8 @@
    int DevID;
    int ChipType;
    int ChipRev;
-   unsigned long MemBase;
-   unsigned long MemBase1;
+   unsigned char * MemBase;
+   unsigned char * MemBase1;
 } S3PCIInformation;
 
 /* Private data structure used for storing all variables needed in driver */
@@ -57,8 +57,8 @@
 typedef struct {
    int chip;
    unsigned short ChipId;
-   unsigned int MmioBase;
-   unsigned int FrameBufferBase;
+   unsigned char * MmioBase;
+   unsigned char * FrameBufferBase;
    pointer MmioMem;
    pointer BciMem;
    int MemOffScreen;
@@ -82,13 +82,20 @@
 /* VESA BIOS Mode information. */
 
 #ifdef USEBIOS
-typedef struct _S3VMODETABLE {
+
+typedef struct _S3VMODEENTRY {
    unsigned short Width;
    unsigned short Height;
    unsigned short VesaMode;
    unsigned char RefreshCount;
-   unsigned char RefreshRate[8];
+   unsigned char * RefreshRate;
+} S3VMODEENTRY, * PS3VMODEENTRY;
+
+typedef struct _S3VMODETABLE {
+   unsigned short NumModes;
+   S3VMODEENTRY Modes[1];
 } S3VMODETABLE, * PS3VMODETABLE;
+
 #endif
 
 /* Function prototypes */
@@ -99,8 +106,8 @@
 extern void S3SAVWarpCursor();
 extern void S3SAVQueryBestSize();
 #ifdef USEBIOS
-extern unsigned short S3SAVGetBIOSModeCount( int );
-extern unsigned short S3SAVGetBIOSModeTable( int, S3VMODETABLE* );
+extern S3VMODETABLE* S3SAVGetBIOSModeTable( int );
+extern void S3SAVFreeBIOSModeTable( S3VMODETABLE** );
 extern void S3SAVSetVESAMode( int, int );
 extern void S3SAVSetTextMode( );
 #endif
diff -u xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3sav_misc.c xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_misc.c
--- xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3sav_misc.c	Mon Dec 20 17:39:33 1999
+++ xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_misc.c	Thu Feb 10 20:45:26 2000
@@ -1,4 +1,4 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_misc.c,v 1.1.2.3 1999/12/20 14:36:28 hohndel Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_misc.c,v 1.1.2.1 1999/07/30 11:21:35 hohndel Exp $ */
 
 /*
  *
@@ -48,10 +48,26 @@
 #include "regs3sav.h"
 #include "s3sav_driver.h"
 
+/** Why isn't all of this included in s3sav_driver.c? **/
+
 extern vgaPCIInformation *vgaPCIInfo;
 extern SymTabRec s3savChipTable[];
 extern S3VPRIV s3vPriv;
 
+static S3PCIInformation Mappings[] = {
+    { PCI_SAVAGE3D,	S3_SAVAGE3D },
+    { PCI_SAVAGE3D_MV,	S3_SAVAGE3D_MV },
+    { PCI_SAVAGE4,	S3_SAVAGE4 },
+    { PCI_SAVAGE2000,	S3_SAVAGE2000 },
+    { PCI_SAVAGE_MX_MV,	S3_SAVAGE_MX },
+    { PCI_SAVAGE_MX,	S3_SAVAGE_MX },
+    { PCI_SAVAGE_IX_MV,	S3_SAVAGE_MX },
+    { PCI_SAVAGE_IX,	S3_SAVAGE_MX },
+    { PCI_SAVAGE_370,	S3_SAVAGE_370 },
+};
+
+#define NMAPPINGS	(sizeof(Mappings)/sizeof(Mappings[0]))
+
 
 /*
  * s3vGetPCIInfo -- probe for PCI information
@@ -68,42 +84,45 @@
 
    if (vgaPCIInfo && vgaPCIInfo->AllCards) {
       while (pcrp = vgaPCIInfo->AllCards[i]) {
-         if (pcrp->_vendor == PCI_S3_VENDOR_ID &&
-	     (pcrp->_base_class == PCI_CLASS_DISPLAY) &&
-	     (pcrp->_sub_class == PCI_SUBCLASS_DISPLAY_VGA) &&
-	     pcrp->_command != 0) {
+         if((pcrp->_vendor == PCI_S3_VENDOR_ID) && 
+	    (pcrp->_base_class == PCI_CLASS_DISPLAY) &&
+	    (pcrp->_sub_class == PCI_SUBCLASS_DISPLAY_VGA) &&
+	    (pcrp->_command != 0)
+	 ) {
 	    int ChipId = pcrp->_device;
+	    int j;
 	    if (vga256InfoRec.chipID) {
 	      ErrorF("%s %s: S3 chipset override, using chip_id = 0x%04x instead of 0x%04x\n",
 		  XCONFIG_GIVEN, vga256InfoRec.name, vga256InfoRec.chipID, ChipId);
 	      ChipId = vga256InfoRec.chipID;
 	    }
 	    found = TRUE;
+	
+	    for( j = 0; j < NMAPPINGS; j++ )
+	    {
+		if( ChipId == Mappings[j].DevID ) {
+		    info.ChipType = Mappings[j].ChipType;
+		    break;
+		}
+	    }
 
-	    switch (ChipId) {
-	    case PCI_SAVAGE3D:
-	       info.ChipType = S3_SAVAGE3D;
-	       break;
-	    case PCI_SAVAGE3D_MV:
-	       info.ChipType = S3_SAVAGE3D_MV;
-	       break;
-	    case PCI_SAVAGE4:
-	       info.ChipType = S3_SAVAGE4;
-	       break;
-	    case PCI_SAVAGE2000:
-	       info.ChipType = S3_SAVAGE2000;
-	       break;
-	    default:
-	       info.ChipType = S3_UNKNOWN;
-	       info.DevID = pcrp->_device;
-	       break;
+	    if( j >= NMAPPINGS )
+	    {
+		info.ChipType = S3_UNKNOWN;
+		info.DevID = pcrp->_device;
 	    }
+
 	    info.ChipRev = pcrp->_rev_id;
-	    if( (ChipId == PCI_SAVAGE4) || (ChipId == PCI_SAVAGE2000) ) {
-	       info.MemBase = pcrp->_base0 & 0xFFFFFFF0;
-	       info.MemBase1 = pcrp->_base1 & 0xFFFFFFF0;
+
+	    info.MemBase = pcrp->_base0 & 0xFFFFFFF0;
+
+	    if(
+		(ChipId == PCI_SAVAGE4) ||
+		(ChipId == PCI_SAVAGE2000) ||
+		(ChipId == PCI_SAVAGE_370)
+	    ) {
+		info.MemBase1 = pcrp->_base1 & 0xFFFFFFF0;
 	    }
-	    else info.MemBase = pcrp->_base0 & 0xFFFFFFF0;
 	    break;
          }
       i++;
diff -u xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3sav_vbe.c xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_vbe.c
--- xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage.336/s3sav_vbe.c	Fri Jul 30 13:21:37 1999
+++ xc/programs/Xserver/hw/xfree86/vga256/drivers/s3_savage/s3sav_vbe.c	Mon Jun 19 22:37:41 2000
@@ -45,6 +45,8 @@
 #include "vbe.h"
 
 #ifdef USEBIOS
+unsigned short
+S3SAVGetBIOSModes( int, S3VMODEENTRY* );
 
 struct
 {
@@ -137,16 +139,24 @@
 void
 S3SAVSetTextMode(void)
 {
-   struct LRMI_regs r;
+    struct LRMI_regs r;
 
-   memset(&r, 0, sizeof(r));
+    ioperm( 0x80, 1, 1 );
+    ioperm( 0x61, 1, 1 );
+    ioperm( 0x40, 4, 1 );
 
-   r.eax = 3;
+    memset(&r, 0, sizeof(r));
+
+    r.eax = 0x83;
+
+    if (!LRMI_int(0x10, &r))
+    {
+	ErrorF("Can't set text mode (vm86 failure)\n");
+    }
 
-   if (!LRMI_int(0x10, &r))
-   {
-      ErrorF("Can't set text mode (vm86 failure)\n");
-   }
+    ioperm( 0x40, 4, 0 );
+    ioperm( 0x61, 1, 0 );
+    ioperm( 0x80, 1, 1 );
 }
 
 
@@ -156,10 +166,12 @@
     struct LRMI_regs r;
 
     /* 
-     * The Savage BIOS also writes to a debug card on port 80h.  It 
-     * shouldn't, but we can work around it here.
+     * The Savage BIOS writes to a debug card on port 80h and to the
+     * timer chip at port 61.
      */
     ioperm( 0x80, 1, 1 );
+    ioperm( 0x61, 1, 1 );
+    ioperm( 0x40, 4, 1 );
 
     /* First, establish the refresh rate for this mode. */
 
@@ -177,13 +189,6 @@
 
     /* Now, make this mode current. */
 
-    /*
-     * The Savage BIOS reprograms the timer chip.  One could argue that
-     * these ports should be virtualized rather than laid wide open.
-     */
-    ioperm( 0x40, 4, 1 );
-    ioperm( 0x61, 1, 1 );
-
     memset(&r, 0, sizeof(r));
 
     r.eax = 0x4f02;
@@ -204,15 +209,43 @@
 }
 
 
-unsigned short
-S3SAVGetBIOSModeCount( int iDepth )
+void
+S3SAVFreeBIOSModeTable( S3VMODETABLE** ppTable )
 {
-    return S3SAVGetBIOSModeTable( iDepth, NULL );
+    int i;
+    PS3VMODEENTRY pMode = (*ppTable)->Modes;
+
+    for( i = (*ppTable)->NumModes; i--; )
+    {
+	if( pMode->RefreshRate )
+	{
+	    xfree( pMode->RefreshRate );
+	    pMode->RefreshRate = NULL;
+	}
+    }
+
+    xfree( *ppTable );
 }
 
+S3VMODETABLE*
+S3SAVGetBIOSModeTable( int iDepth )
+{
+    int nModes = S3SAVGetBIOSModes( iDepth, NULL );
+    PS3VMODETABLE pTable;
+
+    pTable = (PS3VMODETABLE) 
+	xcalloc( 1, sizeof(S3VMODETABLE) + (nModes-1) * sizeof(S3VMODEENTRY) );
+    if( !pTable )
+	return NULL;
+
+    pTable->NumModes = nModes;
+    S3SAVGetBIOSModes( iDepth, pTable->Modes );
+
+    return pTable;
+}
 
 unsigned short
-S3SAVGetBIOSModeTable( int iDepth, S3VMODETABLE* s3vModeTable )
+S3SAVGetBIOSModes( int iDepth, S3VMODEENTRY* s3vModeTable )
 {
     struct LRMI_regs r;
     short int *mode_list;
@@ -325,6 +358,26 @@
 
 		do
 		{
+		    if( (iRefresh % 8) == 0 )
+		    {
+			if( s3vModeTable->RefreshRate )
+			{
+			    s3vModeTable->RefreshRate = (unsigned char *)
+				xrealloc( 
+				    s3vModeTable->RefreshRate,
+				    (iRefresh+8) * sizeof(unsigned char)
+				);
+			}
+			else
+			{
+			    s3vModeTable->RefreshRate = (unsigned char *)
+				xcalloc( 
+				    sizeof(unsigned char),
+				    (iRefresh+8)
+				);
+			}
+		    }
+
 		    r.eax = 0x4f14;
 		    r.ebx = 0x0201;		/* query refresh rates */
 		    if( !LRMI_int(0x10, &r) )
