## Automatically generated incremental diff
## From:   linux-2.4.22-bk4
## To:     linux-2.4.22-bk5
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.4.22-bk4/Documentation/Configure.help linux-2.4.22-bk5/Documentation/Configure.help
--- linux-2.4.22-bk4/Documentation/Configure.help	2003-08-30 02:51:13.000000000 -0700
+++ linux-2.4.22-bk5/Documentation/Configure.help	2003-08-30 02:51:16.000000000 -0700
@@ -2037,6 +2037,17 @@
   The board uses the R4300 and a R5230 CPUs.  For more information
   about this board see <http://www.algor.co.uk/>.
 
+SGI SN2 L1 serial port support
+CONFIG_SGI_L1_SERIAL
+  If you have an SGI SN2 and you want to use the serial port connected
+  to the system controller (you want this!), say Y.  Otherwise, say N.
+
+SGI SN2 L1 serial console support
+CONFIG_SGI_L1_SERIAL_CONSOLE
+  If you have an SGI SN2 and you would like to use the system
+  controller serial port as your console (you want this!), say Y.
+  Otherwise, say N.
+
 Support for BAGET MIPS series
 CONFIG_BAGET_MIPS
   This enables support for the Baget, a Russian embedded system.  For
diff -urN linux-2.4.22-bk4/Documentation/networking/00-INDEX linux-2.4.22-bk5/Documentation/networking/00-INDEX
--- linux-2.4.22-bk4/Documentation/networking/00-INDEX	2003-06-13 07:51:29.000000000 -0700
+++ linux-2.4.22-bk5/Documentation/networking/00-INDEX	2003-08-30 02:51:16.000000000 -0700
@@ -97,8 +97,8 @@
 sis900.txt
 	- SiS 900/7016 Fast Ethernet device driver info.
 sk98lin.txt
-	- SysKonnect SK-98xx and SK-98xx Gigabit Ethernet Adapter family 
-	  driver info.
+	- Marvell Yukon Chipset / SysKonnect SK-98xx compliant Gigabit
+	  Ethernet Adapter family driver info
 skfp.txt
 	- SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info.
 smc9.txt
diff -urN linux-2.4.22-bk4/Documentation/wolfson-touchscreen.txt linux-2.4.22-bk5/Documentation/wolfson-touchscreen.txt
--- linux-2.4.22-bk4/Documentation/wolfson-touchscreen.txt	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk5/Documentation/wolfson-touchscreen.txt	2003-08-30 02:51:16.000000000 -0700
@@ -0,0 +1,178 @@
+
+Wolfson Microelectronics WM9705 and WM9712 Touchscreen Controllers
+===================================================================
+
+The WM9705 and WM9712 are high performance AC97 audio codecs with built
+in touchscreen controllers that are mainly found in portable devices.
+i.e. Dell Axim and Toshiba e740. 
+
+This driver uses the AC97 link controller for all communication with the 
+codec and can be either built into the kernel or built as a module. 
+
+Build Instructions
+==================
+
+The driver will be built into the kernel if "sound card support" = y and
+"wolfson AC97 touchscreen support" = y in the kernel sound configuration.
+
+To build as a module, "wolfson AC97 touchscreen support" = m
+in the kernel sound configuration.
+
+
+Driver Features
+===============
+
+ * supports WM9705, WM9712
+ * polling mode
+ * coordinate polling
+ * adjustable rpu/dpp settings
+ * adjustable pressure current
+ * adjustable sample settle delay
+ * 4 and 5 wire touchscreens (5 wire is WM9712 only)
+ * pen down detection
+ * power management
+ * AUX ADC sampling
+
+
+Driver Usage
+============
+
+In order to use this driver, a char device called wm97xx with a major
+number of 10 and minor number 16 will have to be created under 
+/dev/touchscreen.
+  
+e.g.
+mknod /dev/touchscreen/wm97xx c 10 16
+
+
+Driver Parameters
+=================
+The driver can accept several parameters for fine tuning the touchscreen. 
+However, the syntax is different between module options and passing the 
+options in the kernel command line.
+
+e.g.
+
+rpu=1   (module)
+rpu:1   (kernel command line)
+
+
+1. Codec sample mode. (mode)
+ 
+   The WM9712 can sample touchscreen data in 3 different operating
+   modes. i.e. polling, coordinate and continous.
+  
+   Polling:-     The driver polls the codec and issues 3 seperate commands
+                 over the AC97 link to read X,Y and pressure.
+   
+   Coordinate: - The driver polls the codec and only issues 1 command over
+                 the AC97 link to read X,Y and pressure. This mode has
+                 strict timing requirements and may drop samples if 
+                 interrupted. However, it is less demanding on the AC97
+                 link. Note: this mode requires a larger delay than polling
+                 mode.
+  
+   Continuous:-  The codec automatically samples X,Y and pressure and then
+                 sends the data over the AC97 link in slots. This is then
+                 same method used by the codec when recording audio.
+ 
+   Set mode = 0 for polling, 1 for coordinate and 2 for continuous.
+             
+   Default mode = 0
+   
+   
+
+2. WM9712 Internal pull up for pen detect. (rpu) 
+  
+   Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
+   i.e. pull up resistance = 64k Ohms / rpu.
+   
+   Adjust this value if you are having problems with pen detect not 
+   detecting any down events.
+   
+   Set rpu = value
+
+   Default rpu = 1
+   
+   
+
+3. WM9705 Pen detect comparator threshold. (pdd) 
+   
+   0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold
+   i.e. 1 =  Vmid/15 threshold
+        15 =  Vmid/1 threshold
+   
+   Adjust this value if you are having problems with pen detect not 
+   detecting any down events.
+   
+   Set pdd = value
+
+   Default pdd = 0
+
+
+ 
+4. Set current used for pressure measurement. (pil)
+ 
+   Set pil = 2 to use 400uA 
+       pil = 1 to use 200uA and
+       pil = 0 to disable pressure measurement.
+  
+   This is used to increase the range of values returned by the adc
+   when measureing touchpanel pressure. 
+   
+   Default pil = 0
+  
+
+
+5. WM9712 Set 5 wire touchscreen mode. (five_wire)
+
+   Set five_wire = 1 to enable 5 wire mode on the WM9712.
+   
+   Default five_wire = 0
+   
+   NOTE: Five wire mode does not allow for readback of pressure.
+
+
+
+6. ADC sample delay. (delay)
+  
+   For accurate touchpanel measurements, some settling time may be
+   required between the switch matrix applying a voltage across the
+   touchpanel plate and the ADC sampling the signal.
+  
+   This delay can be set by setting delay = n, where n is the array
+   position of the delay in the array delay_table below.
+   Long delays > 1ms are supported for completeness, but are not
+   recommended.
+   
+   Default delay = 4
+ 
+    wm_delay     uS     AC97 link frames
+    ====================================
+       0	      21          1
+       1	      42          2
+       2          84          4
+       3         167          8
+       4         333         16
+       5         667         32
+       6        1000         48
+       7        1333         64
+       8        2000         96
+       9        2667        128
+      10        3333        160
+      11        4000        192
+      12        4667        224
+      13        5333        256
+      14        6000        288
+      15           0          0 (No delay, switch matrix always on)
+
+
+
+Contact
+=======
+
+Further information about the WM9705 and WM9712 can be found on the 
+Wolfson Website. http://www.wolfsonmicro.com
+
+Please report bugs to liam.girdwood@wolfsonmicro.com or 
+                      linux@wolfsonmicro.com
diff -urN linux-2.4.22-bk4/Makefile linux-2.4.22-bk5/Makefile
--- linux-2.4.22-bk4/Makefile	2003-08-30 02:51:13.000000000 -0700
+++ linux-2.4.22-bk5/Makefile	2003-08-30 02:51:16.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 22
-EXTRAVERSION = -bk4
+EXTRAVERSION = -bk5
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.22-bk4/arch/i386/kernel/dmi_scan.c linux-2.4.22-bk5/arch/i386/kernel/dmi_scan.c
--- linux-2.4.22-bk4/arch/i386/kernel/dmi_scan.c	2003-08-30 02:51:13.000000000 -0700
+++ linux-2.4.22-bk5/arch/i386/kernel/dmi_scan.c	2003-08-30 02:51:16.000000000 -0700
@@ -400,37 +400,6 @@
 }
 
 /*
- * The Intel 440GX hall of shame. 
- *
- * On many (all we have checked) of these boxes the $PIRQ table is wrong.
- * The MP1.4 table is right however and so SMP kernels tend to work. 
- */
- 
-#ifdef CONFIG_PCI
-extern int broken_440gx_bios;
-extern unsigned int pci_probe;
-#endif
-static __init int broken_pirq(struct dmi_blacklist *d)
-{
-	printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n");
-	printk(KERN_INFO " *** Many BIOSes matching this signature have incorrect IRQ routing tables.\n");
-	printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n");
-	printk(KERN_INFO " *** contact your hardware vendor and ask about updates.\n");
-	printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n");
-#ifdef CONFIG_X86_IO_APIC
-	{
-		extern int skip_ioapic_setup; 
-		skip_ioapic_setup = 0;
-	}
-#endif
-#ifdef CONFIG_PCI
-	broken_440gx_bios = 1;
-	pci_probe |= PCI_BIOS_IRQ_SCAN;
-#endif
-	return 0;
-}
-
-/*
  * ASUS K7V-RM has broken ACPI table defining sleep modes
  */
 
@@ -824,77 +793,17 @@
 			NO_MATCH, NO_MATCH
 			} },
 
-	/* Problem Intel 440GX bioses */
-
-	{ broken_pirq, "SABR1 Bios", {			/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"SABR1"),
-			NO_MATCH, NO_MATCH
-			} },
-	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0066.P07"),
-			NO_MATCH, NO_MATCH
-                        } },
-	{ broken_pirq, "IBM xseries 370", {        		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "IBM"),
-			MATCH(DMI_BIOS_VERSION,"MMKT33AUS"),
-			NO_MATCH, NO_MATCH
-                        } },
-	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0094.P10"),
-			NO_MATCH, NO_MATCH
-                        } },
-	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0115.P12"),
-			NO_MATCH, NO_MATCH
-                        } },
-	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0120.P12"),
-			NO_MATCH, NO_MATCH
-                        } },
-	{ broken_pirq, "l44GX Bios", {		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0125.P13"),
-			NO_MATCH, NO_MATCH
-			} },
-	{ broken_pirq, "l44GX Bios", {		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"C440GX0.86B"),
-			NO_MATCH, NO_MATCH
-			} },
-	{ broken_pirq, "l44GX Bios", {		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0133.P14"),
-			NO_MATCH, NO_MATCH
-			} },
-	{ broken_pirq, "l44GX Bios", {		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0"),
-			NO_MATCH, NO_MATCH
-			} },
-                        
-	/* Intel in disgiuse - In this case they can't hide and they don't run
-	   too well either... */
-	{ broken_pirq, "Dell PowerEdge 8450", {		/* Bad $PIR */
-			MATCH(DMI_PRODUCT_NAME, "Dell PowerEdge 8450"),
+	{ init_ints_after_s1, "Toshiba Satellite 4030cdt", { /* Reinitialization of 8259 is needed after S1 resume */
+			MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
 			NO_MATCH, NO_MATCH, NO_MATCH
 			} },
-			
+
 	{ broken_acpi_Sx, "ASUS K7V-RM", {		/* Bad ACPI Sx table */
 			MATCH(DMI_BIOS_VERSION,"ASUS K7V-RM ACPI BIOS Revision 1003A"),
 			MATCH(DMI_BOARD_NAME, "<K7V-RM>"),
 			NO_MATCH, NO_MATCH
 			} },
 			
-	{ init_ints_after_s1, "Toshiba Satellite 4030cdt", { /* Reinitialization of 8259 is needed after S1 resume */
-			MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
-			NO_MATCH, NO_MATCH, NO_MATCH
-			} },
-
 	{ print_if_true, KERN_WARNING "IBM T23 - BIOS 1.03b+ and controller firmware 1.02+ may be needed for Linux APM.", {
 			MATCH(DMI_SYS_VENDOR, "IBM"),
 			MATCH(DMI_BIOS_VERSION, "1AET38WW (1.01b)"),
diff -urN linux-2.4.22-bk4/arch/i386/kernel/pci-irq.c linux-2.4.22-bk5/arch/i386/kernel/pci-irq.c
--- linux-2.4.22-bk4/arch/i386/kernel/pci-irq.c	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.22-bk5/arch/i386/kernel/pci-irq.c	2003-08-30 02:51:16.000000000 -0700
@@ -23,7 +23,6 @@
 #define PIRQ_VERSION 0x0100
 
 int broken_hp_bios_irq9;
-int broken_440gx_bios;
 
 static struct irq_routing_table *pirq_table;
 
@@ -46,6 +45,11 @@
 	int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new);
 };
 
+struct irq_router_handler {
+	u16 vendor;
+	int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device);
+};
+
 /*
  *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
  */
@@ -257,111 +261,221 @@
 }
 
 /*
- *	PIRQ routing for SiS 85C503 router used in several SiS chipsets
- *	According to the SiS 5595 datasheet (preliminary V1.0, 12/24/1997)
- *	the related registers work as follows:
- *	
- *	general: one byte per re-routable IRQ,
+ *	PIRQ routing for SiS 85C503 router used in several SiS chipsets.
+ *	We have to deal with the following issues here:
+ *	- vendors have different ideas about the meaning of link values
+ *	- some onboard devices (integrated in the chipset) have special
+ *	  links and are thus routed differently (i.e. not via PCI INTA-INTD)
+ *	- different revision of the router have a different layout for
+ *	  the routing registers, particularly for the onchip devices
+ *
+ *	For all routing registers the common thing is we have one byte
+ *	per routeable link which is defined as:
  *		 bit 7      IRQ mapping enabled (0) or disabled (1)
- *		 bits [6:4] reserved
+ *		 bits [6:4] reserved (sometimes used for onchip devices)
  *		 bits [3:0] IRQ to map to
  *		     allowed: 3-7, 9-12, 14-15
  *		     reserved: 0, 1, 2, 8, 13
  *
- *	individual registers in device config space:
+ *	The config-space registers located at 0x41/0x42/0x43/0x44 are
+ *	always used to route the normal PCI INT A/B/C/D respectively.
+ *	Apparently there are systems implementing PCI routing table using
+ *	link values 0x01-0x04 and others using 0x41-0x44 for PCI INTA..D.
+ *	We try our best to handle both link mappings.
+ *	
+ *	Currently (2003-05-21) it appears most SiS chipsets follow the
+ *	definition of routing registers from the SiS-5595 southbridge.
+ *	According to the SiS 5595 datasheets the revision id's of the
+ *	router (ISA-bridge) should be 0x01 or 0xb0.
  *
- *	0x41/0x42/0x43/0x44:	PCI INT A/B/C/D - bits as in general case
+ *	Furthermore we've also seen lspci dumps with revision 0x00 and 0xb1.
+ *	Looks like these are used in a number of SiS 5xx/6xx/7xx chipsets.
+ *	They seem to work with the current routing code. However there is
+ *	some concern because of the two USB-OHCI HCs (original SiS 5595
+ *	had only one). YMMV.
  *
- *	0x61:			IDEIRQ: bits as in general case - but:
- *				bits [6:5] must be written 01
- *				bit 4 channel-select primary (0), secondary (1)
+ *	Onchip routing for router rev-id 0x01/0xb0 and probably 0x00/0xb1:
  *
- *	0x62:			USBIRQ: bits as in general case - but:
- *				bit 4 OHCI function disabled (0), enabled (1)
+ *	0x61:	IDEIRQ:
+ *		bits [6:5] must be written 01
+ *		bit 4 channel-select primary (0), secondary (1)
+ *
+ *	0x62:	USBIRQ:
+ *		bit 6 OHCI function disabled (0), enabled (1)
  *	
- *	0x6a:			ACPI/SCI IRQ - bits as in general case
+ *	0x6a:	ACPI/SCI IRQ: bits 4-6 reserved
+ *
+ *	0x7e:	Data Acq. Module IRQ - bits 4-6 reserved
+ *
+ *	We support USBIRQ (in addition to INTA-INTD) and keep the
+ *	IDE, ACPI and DAQ routing untouched as set by the BIOS.
+ *
+ *	Currently the only reported exception is the new SiS 65x chipset
+ *	which includes the SiS 69x southbridge. Here we have the 85C503
+ *	router revision 0x04 and there are changes in the register layout
+ *	mostly related to the different USB HCs with USB 2.0 support.
  *
- *	0x7e:			Data Acq. Module IRQ - bits as in general case
+ *	Onchip routing for router rev-id 0x04 (try-and-error observation)
  *
- *	Apparently there are systems implementing PCI routing table using both
- *	link values 0x01-0x04 and 0x41-0x44 for PCI INTA..D, but register offsets
- *	like 0x62 as link values for USBIRQ e.g. So there is no simple
- *	"register = offset + pirq" relation.
- *	Currently we support PCI INTA..D and USBIRQ and try our best to handle
- *	both link mappings.
- *	IDE/ACPI/DAQ mapping is currently unsupported (left untouched as set by BIOS).
+ *	0x60/0x61/0x62/0x63:	1xEHCI and 3xOHCI (companion) USB-HCs
+ *				bit 6-4 are probably unused, not like 5595
  */
 
-static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+#define PIRQ_SIS_IRQ_MASK	0x0f
+#define PIRQ_SIS_IRQ_DISABLE	0x80
+#define PIRQ_SIS_USB_ENABLE	0x40
+#define PIRQ_SIS_DETECT_REGISTER 0x40
+
+/* return value:
+ * -1 on error
+ * 0 for PCI INTA-INTD
+ * 0 or enable bit mask to check or set for onchip functions
+ */
+static inline int pirq_sis5595_onchip(int pirq, int *reg)
 {
-	u8 x;
-	int reg = pirq;
+	int ret = -1;
 
+	*reg = pirq;
 	switch(pirq) {
-		case 0x01:
-		case 0x02:
-		case 0x03:
-		case 0x04:
-			reg += 0x40;
-		case 0x41:
-		case 0x42:
-		case 0x43:
-		case 0x44:
-		case 0x62:
-			pci_read_config_byte(router, reg, &x);
-			if (reg != 0x62)
-				break;
-			if (!(x & 0x40))
-				return 0;
-			break;
-		case 0x61:
-		case 0x6a:
-		case 0x7e:
-			printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n");
-			return 0;
-		default:			
-			printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
-			return 0;
+	case 0x01:
+	case 0x02:
+	case 0x03:
+	case 0x04:
+		*reg += 0x40;
+	case 0x41:
+	case 0x42:
+	case 0x43:
+	case 0x44:
+		ret = 0;
+		break;
+
+	case 0x62:
+		ret = PIRQ_SIS_USB_ENABLE;	/* documented for 5595 */
+		break;
+
+	case 0x61:
+	case 0x6a:
+	case 0x7e:
+		printk(KERN_INFO "SiS pirq: IDE/ACPI/DAQ mapping not implemented: (%u)\n",
+		       (unsigned) pirq);
+		/* fall thru */
+	default:
+		printk(KERN_INFO "SiS router unknown request: (%u)\n",
+		       (unsigned) pirq);
+		break;
+	}
+	return ret;
+}		
+
+/* return value:
+ * -1 on error
+ * 0 for PCI INTA-INTD
+ * 0 or enable bit mask to check or set for onchip functions
+ */
+static inline int pirq_sis96x_onchip(int pirq, int *reg)
+{
+	int ret = -1;
+
+	*reg = pirq;
+	switch(pirq) {
+	case 0x01:
+	case 0x02:
+	case 0x03:
+	case 0x04:
+		*reg += 0x40;
+	case 0x41:
+	case 0x42:
+	case 0x43:
+	case 0x44:
+	case 0x60:
+	case 0x61:
+	case 0x62:
+	case 0x63:
+		ret = 0;
+		break;
+
+	default:
+		printk(KERN_INFO "SiS router unknown request: (%u)\n",
+		       (unsigned) pirq);
+		break;
 	}
-	return (x & 0x80) ? 0 : (x & 0x0f);
+	return ret;
+}		
+
+
+static int pirq_sis5595_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	u8 x;
+	int reg, check;
+
+	check = pirq_sis5595_onchip(pirq, &reg);
+	if (check < 0)
+		return 0;
+
+	pci_read_config_byte(router, reg, &x);
+	if (check != 0  &&  !(x & check))
+		return 0;
+
+	return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK);
 }
 
-static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+static int pirq_sis96x_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
 {
 	u8 x;
-	int reg = pirq;
+	int reg, check;
+
+	check = pirq_sis96x_onchip(pirq, &reg);
+	if (check < 0)
+		return 0;
+
+	pci_read_config_byte(router, reg, &x);
+	if (check != 0  &&  !(x & check))
+		return 0;
+
+	return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK);
+}
+
+static int pirq_sis5595_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	u8 x;
+	int reg, set;
+
+	set = pirq_sis5595_onchip(pirq, &reg);
+	if (set < 0)
+		return 0;
+
+	x = (irq & PIRQ_SIS_IRQ_MASK);
+	if (x == 0)
+		x = PIRQ_SIS_IRQ_DISABLE;
+	else
+		x |= set;
 
-	switch(pirq) {
-		case 0x01:
-		case 0x02:
-		case 0x03:
-		case 0x04:
-			reg += 0x40;
-		case 0x41:
-		case 0x42:
-		case 0x43:
-		case 0x44:
-		case 0x62:
-			x = (irq&0x0f) ? (irq&0x0f) : 0x80;
-			if (reg != 0x62)
-				break;
-			/* always mark OHCI enabled, as nothing else knows about this */
-			x |= 0x40;
-			break;
-		case 0x61:
-		case 0x6a:
-		case 0x7e:
-			printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n");
-			return 0;
-		default:			
-			printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
-			return 0;
-	}
 	pci_write_config_byte(router, reg, x);
 
 	return 1;
 }
 
+static int pirq_sis96x_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	u8 x;
+	int reg, set;
+
+	set = pirq_sis96x_onchip(pirq, &reg);
+	if (set < 0)
+		return 0;
+
+	x = (irq & PIRQ_SIS_IRQ_MASK);
+	if (x == 0)
+		x = PIRQ_SIS_IRQ_DISABLE;
+	else
+		x |= set;
+
+	pci_write_config_byte(router, reg, x);
+
+	return 1;
+}
+
+
 /*
  * VLSI: nibble offset 0x74 - educated guess due to routing table and
  *       config space of VLSI 82C534 PCI-bridge/router (1004:0102)
@@ -454,96 +568,262 @@
 	return pcibios_set_irq_routing(bridge, pin, irq);
 }
 
-static struct irq_router pirq_bios_router =
-	{ "BIOS", 0, 0, NULL, pirq_bios_set };
-
 #endif
 
-static struct irq_router pirq_routers[] = {
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_0, pirq_piix_get, pirq_piix_set },
-
-	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
-
-	{ "ITE", PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8330G_0, pirq_ite_get, pirq_ite_set },
-
-	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
-	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
-	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
-
-	{ "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set },
-
-	{ "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },
-	{ "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set },
-	{ "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
-	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4,
-	  pirq_serverworks_get, pirq_serverworks_set },
-	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5,
-	  pirq_serverworks_get, pirq_serverworks_set },
-	{ "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B,
-		pirq_amd756_get, pirq_amd756_set },
-	{ "AMD766", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413,
-		pirq_amd756_get, pirq_amd756_set },
-	{ "AMD768", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7443,
-		pirq_amd756_get, pirq_amd756_set },
 
-	{ "default", 0, 0, NULL, NULL }
-};
+static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	/* We must not touch 440GX even if we have tables. 440GX has
+	   different IRQ routing weirdness */
+	if(pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82450GX, NULL))
+		return 0;
+	switch(device)
+	{
+		case PCI_DEVICE_ID_INTEL_82371FB_0:
+		case PCI_DEVICE_ID_INTEL_82371SB_0:
+		case PCI_DEVICE_ID_INTEL_82371AB_0:
+		case PCI_DEVICE_ID_INTEL_82371MX:
+		case PCI_DEVICE_ID_INTEL_82443MX_0:
+		case PCI_DEVICE_ID_INTEL_82801AA_0:
+		case PCI_DEVICE_ID_INTEL_82801AB_0:
+		case PCI_DEVICE_ID_INTEL_82801BA_0:
+		case PCI_DEVICE_ID_INTEL_82801BA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_0:
+		case PCI_DEVICE_ID_INTEL_82801CA_12:
+		case PCI_DEVICE_ID_INTEL_82801DB_0:
+		case PCI_DEVICE_ID_INTEL_82801E_0:
+		case PCI_DEVICE_ID_INTEL_82801EB_0:
+		case PCI_DEVICE_ID_INTEL_ESB_0:
+			r->name = "PIIX/ICH";
+			r->get = pirq_piix_get;
+			r->set = pirq_piix_set;
+			return 1;
+	}
+	return 0;
+}
 
-static struct irq_router *pirq_router;
+static __init int via_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	/* FIXME: We should move some of the quirk fixup stuff here */
+	switch(device)
+	{
+		case PCI_DEVICE_ID_VIA_82C586_0:
+		case PCI_DEVICE_ID_VIA_82C596:
+		case PCI_DEVICE_ID_VIA_82C686:
+		/* FIXME: add new ones for 8233/5 */
+			r->name = "VIA";
+			r->get = pirq_via_get;
+			r->set = pirq_via_set;
+			return 1;
+	}
+	return 0;
+}
+
+static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_VLSI_82C534:
+			r->name = "VLSI 82C534";
+			r->get = pirq_vlsi_get;
+			r->set = pirq_vlsi_set;
+			return 1;
+	}
+	return 0;
+}
+
+
+static __init int serverworks_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_SERVERWORKS_OSB4:
+		case PCI_DEVICE_ID_SERVERWORKS_CSB5:
+			r->name = "ServerWorks";
+			r->get = pirq_serverworks_get;
+			r->set = pirq_serverworks_set;
+			return 1;
+	}
+	return 0;
+}
+
+static __init int sis_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	u8 reg;
+	u16 devid;
+
+	if (device != PCI_DEVICE_ID_SI_503)
+		return 0;
+		
+	/*
+	 * In case of SiS south bridge, we need to detect the two
+	 * kinds of routing tables we have seen so far (5595 and 96x). 
+	 * Since the maintain the same device ID, we need to do poke 
+	 * the PCI configuration space to find the router type we are
+	 * dealing with.
+	 */
+
+	/*
+	 * Factoid: writing bit6 of register 0x40 of the router config space
+	 * will make the SB to show up 0x096x inside the device id. Note,
+	 * we need to restore register 0x40 after the device id poke.
+	 */
+
+	pci_read_config_byte(router, PIRQ_SIS_DETECT_REGISTER, &reg);
+	pci_write_config_byte(router, PIRQ_SIS_DETECT_REGISTER, reg | (1 << 6));
+	pci_read_config_word(router, PCI_DEVICE_ID, &devid);
+	pci_write_config_byte(router, PIRQ_SIS_DETECT_REGISTER, reg);
+
+	if ((devid & 0xfff0) == 0x0960) {
+		r->name = "SIS96x";
+		r->get = pirq_sis96x_get;
+		r->set = pirq_sis96x_set;
+		DBG("PCI: Detecting SiS router at %02x:%02x : SiS096x detected\n",
+		    rt->rtr_bus, rt->rtr_devfn);
+	} else {
+		r->name = "SIS5595";
+		r->get = pirq_sis5595_get;
+		r->set = pirq_sis5595_set;
+		DBG("PCI: Detecting SiS router at %02x:%02x : SiS5595 detected\n",
+		    rt->rtr_bus, rt->rtr_devfn);
+	}
+	return 1;
+}
+
+static __init int cyrix_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_CYRIX_5520:
+			r->name = "NatSemi";
+			r->get = pirq_cyrix_get;
+			r->set = pirq_cyrix_set;
+			return 1;
+	}
+	return 0;
+}
+
+static __init int opti_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_OPTI_82C700:
+			r->name = "OPTI";
+			r->get = pirq_opti_get;
+			r->set = pirq_opti_set;
+			return 1;
+	}
+	return 0;
+}
+
+static __init int ite_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_ITE_IT8330G_0:
+			r->name = "ITE";
+			r->get = pirq_ite_get;
+			r->set = pirq_ite_set;
+			return 1;
+	}
+	return 0;
+}
+
+static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_AL_M1533:
+			r->name = "ALI";
+			r->get = pirq_ali_get;
+			r->set = pirq_ali_set;
+			return 1;
+		/* Should add 156x some day */
+	}
+	return 0;
+}
+
+static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_AMD_VIPER_740B:
+			r->name = "AMD756";
+			break;
+		case PCI_DEVICE_ID_AMD_VIPER_7413:
+			r->name = "AMD766";
+			break;
+		case PCI_DEVICE_ID_AMD_VIPER_7443:
+			r->name = "AMD768";
+			break;
+		default:
+			return 0;
+	}
+	r->get = pirq_amd756_get;
+	r->set = pirq_amd756_set;
+	return 1;
+}
+		
+static __initdata struct irq_router_handler pirq_routers[] = {
+	{ PCI_VENDOR_ID_INTEL, intel_router_probe },
+	{ PCI_VENDOR_ID_AL, ali_router_probe },
+	{ PCI_VENDOR_ID_ITE, ite_router_probe },
+	{ PCI_VENDOR_ID_VIA, via_router_probe },
+	{ PCI_VENDOR_ID_OPTI, opti_router_probe },
+	{ PCI_VENDOR_ID_SI, sis_router_probe },
+	{ PCI_VENDOR_ID_CYRIX, cyrix_router_probe },
+	{ PCI_VENDOR_ID_VLSI, vlsi_router_probe },
+	{ PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe },
+	{ PCI_VENDOR_ID_AMD, amd_router_probe },
+	/* Someone with docs needs to add the ATI Radeon IGP */
+	{ 0, NULL }
+};
+static struct irq_router pirq_router;
 static struct pci_dev *pirq_router_dev;
 
-static void __init pirq_find_router(void)
+/*
+ *	FIXME: should we have an option to say "generic for
+ *	chipset" ?
+ */
+ 
+static void __init pirq_find_router(struct irq_router *r)
 {
 	struct irq_routing_table *rt = pirq_table;
-	struct irq_router *r;
+	struct irq_router_handler *h;
 
 #ifdef CONFIG_PCI_BIOS
 	if (!rt->signature) {
 		printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n");
-		pirq_router = &pirq_bios_router;
+		r->set = pirq_bios_set;
+		r->name = "BIOS";
 		return;
 	}
 #endif
 
+	/* Default unless a driver reloads it */
+	r->name = "default";
+	r->get = NULL;
+	r->set = NULL;
+	
 	DBG("PCI: Attempting to find IRQ router for %04x:%04x\n",
 	    rt->rtr_vendor, rt->rtr_device);
 
-	/* fall back to default router if nothing else found */
-	pirq_router = &pirq_routers[ARRAY_SIZE(pirq_routers) - 1];
-
 	pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
 	if (!pirq_router_dev) {
 		DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
 		return;
 	}
 
-	for(r=pirq_routers; r->vendor; r++) {
-		/* Exact match against router table entry? Use it! */
-		if (r->vendor == rt->rtr_vendor && r->device == rt->rtr_device) {
-			pirq_router = r;
+	for( h = pirq_routers; h->vendor; h++) {
+		/* First look for a router match */
+		if (rt->rtr_vendor == h->vendor && h->probe(r, pirq_router_dev, rt->rtr_device))
+			break;
+		/* Fall back to a device match */
+		if (pirq_router_dev->vendor == h->vendor && h->probe(r, pirq_router_dev, pirq_router_dev->device))
 			break;
-		}
-		/* Match against router device entry? Use it as a fallback */
-		if (r->vendor == pirq_router_dev->vendor && r->device == pirq_router_dev->device) {
-			pirq_router = r;
-		}
 	}
 	printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
-		pirq_router->name,
+		pirq_router.name,
 		pirq_router_dev->vendor,
 		pirq_router_dev->device,
 		pirq_router_dev->slot_name);
@@ -572,7 +852,7 @@
 	int i, pirq, newirq;
 	int irq = 0;
 	u32 mask;
-	struct irq_router *r = pirq_router;
+	struct irq_router *r = &pirq_router;
 	struct pci_dev *dev2;
 	char *msg = NULL;
 
@@ -685,17 +965,14 @@
 void __init pcibios_irq_init(void)
 {
 	DBG("PCI: IRQ init\n");
-	if (broken_440gx_bios)
- 		pirq_table = NULL;	
- 	else
-		pirq_table = pirq_find_routing_table();
+	pirq_table = pirq_find_routing_table();
 #ifdef CONFIG_PCI_BIOS
 	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
 		pirq_table = pcibios_get_irq_routing_table();
 #endif
 	if (pirq_table) {
 		pirq_peer_trick();
-		pirq_find_router();
+		pirq_find_router(&pirq_router);
 		if (pirq_table->exclusive_irqs) {
 			int i;
 			for (i=0; i<16; i++)
diff -urN linux-2.4.22-bk4/drivers/char/Config.in linux-2.4.22-bk5/drivers/char/Config.in
--- linux-2.4.22-bk4/drivers/char/Config.in	2003-08-30 02:51:13.000000000 -0700
+++ linux-2.4.22-bk5/drivers/char/Config.in	2003-08-30 02:51:16.000000000 -0700
@@ -105,6 +105,12 @@
      fi
   fi
 fi
+if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_SGI_SN2" = "y" ] ; then
+  bool 'SGI SN2 l1 serial port support' CONFIG_SGI_L1_SERIAL
+  if [ "$CONFIG_SGI_L1_SERIAL" = "y" ]; then
+    bool '  SGI SN2 l1 Console support' CONFIG_SGI_L1_SERIAL_CONSOLE
+  fi
+fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then
    tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
 fi
diff -urN linux-2.4.22-bk4/drivers/char/Makefile linux-2.4.22-bk5/drivers/char/Makefile
--- linux-2.4.22-bk4/drivers/char/Makefile	2003-08-30 02:51:13.000000000 -0700
+++ linux-2.4.22-bk5/drivers/char/Makefile	2003-08-30 02:51:17.000000000 -0700
@@ -211,6 +211,7 @@
 obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o
 obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
 obj-$(CONFIG_TXX927_SERIAL) += serial_txx927.o
+obj-$(CONFIG_SGI_L1_SERIAL) += sn_serial.o
 
 subdir-$(CONFIG_RIO) += rio
 subdir-$(CONFIG_INPUT) += joystick
diff -urN linux-2.4.22-bk4/drivers/char/amd7xx_tco.c linux-2.4.22-bk5/drivers/char/amd7xx_tco.c
--- linux-2.4.22-bk4/drivers/char/amd7xx_tco.c	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.22-bk5/drivers/char/amd7xx_tco.c	2003-08-30 02:51:17.000000000 -0700
@@ -1,6 +1,6 @@
 /*
  *	AMD 766/768 TCO Timer Driver
- *	(c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>
+ *	(c) Copyright 2002 Zwane Mwaikambo <zwane@holomorphy.com>
  *	All Rights Reserved.
  *
  *	Parts from;
@@ -34,35 +34,48 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 
-#define AMDTCO_MODULE_VER	"build 20020601"
+#define AMDTCO_MODULE_VER	"build 20021116"
 #define AMDTCO_MODULE_NAME	"amd7xx_tco"
 #define PFX			AMDTCO_MODULE_NAME ": "
 
-#define	MAX_TIMEOUT	38	/* max of 38 seconds */
+#define	MAX_TIMEOUT	38	/* max of 38 seconds, although the system will only
+				 * reset itself after the second timeout */
 
 /* pmbase registers */
-#define GLOBAL_SMI_REG	0x2a
-#define TCO_EN		(1 << 1)	/* bit 1 in global SMI register */
 #define TCO_RELOAD_REG	0x40		/* bits 0-5 are current count, 6-7 are reserved */
 #define TCO_INITVAL_REG	0x41		/* bits 0-5 are value to load, 6-7 are reserved */
 #define TCO_TIMEOUT_MASK	0x3f
+#define TCO_STATUS1_REG 0x44
 #define TCO_STATUS2_REG	0x46
 #define NDTO_STS2	(1 << 1)	/* we're interested in the second timeout */ 
 #define BOOT_STS	(1 << 2)	/* will be set if NDTO_STS2 was set before reboot */
 #define TCO_CTRL1_REG	0x48
 #define TCO_HALT	(1 << 11)
+#define NO_REBOOT	(1 << 10)	/* in DevB:3x48 */
 
-static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER;
+static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER "\n";
 static int timeout = 38;
 static u32 pmbase;		/* PMxx I/O base */
 static struct pci_dev *dev;
 static struct semaphore open_sem;
-spinlock_t amdtco_lock;	/* only for device access */
+static spinlock_t amdtco_lock;	/* only for device access */
 static int expect_close = 0;
 
 MODULE_PARM(timeout, "i");
 MODULE_PARM_DESC(timeout, "range is 0-38 seconds, default is 38");
 
+static inline u8 seconds_to_ticks(int seconds)
+{
+	/* the internal timer is stored as ticks which decrement
+	 * every 0.6 seconds */
+	return (seconds * 10) / 6;
+}
+
+static inline int ticks_to_seconds(u8 ticks)
+{
+	return (ticks * 6) / 10;
+}
+
 static inline int amdtco_status(void)
 {
 	u16 reg;
@@ -81,28 +94,19 @@
 
 static inline void amdtco_ping(void)
 {
-	u8 reg;
-
-	spin_lock(&amdtco_lock);
-	reg = inb(pmbase+TCO_RELOAD_REG);
-	outb(1 | reg, pmbase+TCO_RELOAD_REG);
-	spin_unlock(&amdtco_lock);
+	outb(1, pmbase+TCO_RELOAD_REG);
 }
 
 static inline int amdtco_gettimeout(void)
 {
-	return inb(TCO_RELOAD_REG) & TCO_TIMEOUT_MASK;
+	u8 reg = inb(pmbase+TCO_RELOAD_REG) & TCO_TIMEOUT_MASK;
+	return ticks_to_seconds(reg);
 }
 
 static inline void amdtco_settimeout(unsigned int timeout)
 {
-	u8 reg;
-
-	spin_lock(&amdtco_lock);
-	reg = inb(pmbase+TCO_INITVAL_REG);
-	reg |= timeout & TCO_TIMEOUT_MASK;
+	u8 reg = seconds_to_ticks(timeout) & TCO_TIMEOUT_MASK;
 	outb(reg, pmbase+TCO_INITVAL_REG);
-	spin_unlock(&amdtco_lock);
 }
 
 static inline void amdtco_global_enable(void)
@@ -110,9 +114,12 @@
 	u16 reg;
 
 	spin_lock(&amdtco_lock);
-	reg = inw(pmbase+GLOBAL_SMI_REG);
-	reg |= TCO_EN;
-	outw(reg, pmbase+GLOBAL_SMI_REG);
+
+	/* clear NO_REBOOT on DevB:3x48 p97 */
+	pci_read_config_word(dev, 0x48, &reg);
+	reg &= ~NO_REBOOT;
+	pci_write_config_word(dev, 0x48, reg);
+
 	spin_unlock(&amdtco_lock);
 }
 
@@ -150,10 +157,12 @@
 	if (timeout > MAX_TIMEOUT)
 		timeout = MAX_TIMEOUT;
 
+	amdtco_disable();
 	amdtco_settimeout(timeout);	
 	amdtco_global_enable();
+	amdtco_enable();
 	amdtco_ping();
-	printk(KERN_INFO PFX "Watchdog enabled, timeout = %d/%d seconds",
+	printk(KERN_INFO PFX "Watchdog enabled, timeout = %ds of %ds\n",
 		amdtco_gettimeout(), timeout);
 	
 	return 0;
@@ -202,7 +211,7 @@
 
 		case WDIOC_GETTIMEOUT:
 			return put_user(amdtco_gettimeout(), (int *)arg);
-	
+		
 		case WDIOC_SETOPTIONS:
 			if (copy_from_user(&tmp, (int *)arg, sizeof tmp))
                                 return -EFAULT;
@@ -225,7 +234,7 @@
 		printk(KERN_INFO PFX "Watchdog disabled\n");
 	} else {
 		amdtco_ping();
-		printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds)\n", timeout);
+		printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds\n", timeout);
 	}	
 	
 	up(&open_sem);
@@ -253,10 +262,9 @@
 		}
 #endif
 		amdtco_ping();
-		return len;
 	}
 
-	return 0;
+	return len;
 }
 
 
@@ -291,7 +299,6 @@
 };
 
 static struct pci_device_id amdtco_pci_tbl[] __initdata = {
-	/* AMD 766 PCI_IDs here */
 	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, }
 };
@@ -361,6 +368,9 @@
 	if (ints[0] > 0)
 		timeout = ints[1];
 
+	if (!timeout || timeout > 38)
+		timeout = MAX_TIMEOUT;
+
 	return 1;
 }
 
@@ -370,7 +380,7 @@
 module_init(amdtco_init);
 module_exit(amdtco_exit);
 
-MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
+MODULE_AUTHOR("Zwane Mwaikambo <zwane@holomorphy.com>");
 MODULE_DESCRIPTION("AMD 766/768 TCO Timer Driver");
 MODULE_LICENSE("GPL");
 EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.22-bk4/drivers/char/i810-tco.c linux-2.4.22-bk5/drivers/char/i810-tco.c
--- linux-2.4.22-bk4/drivers/char/i810-tco.c	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.22-bk5/drivers/char/i810-tco.c	2003-08-30 02:51:17.000000000 -0700
@@ -25,7 +25,8 @@
  *	82801AA & 82801AB  chip : document number 290655-003, 290677-004,
  *	82801BA & 82801BAM chip : document number 290687-002, 298242-005,
  *	82801CA & 82801CAM chip : document number 290716-001, 290718-001,
- *	82801DB & 82801E   chip : document number 290744-001, 273599-001
+ *	82801DB & 82801E   chip : document number 290744-001, 273599-001,
+ *	82801EB & 82801ER  chip : document number 252516-001
  *
  *  20000710 Nils Faerber
  *	Initial Version 0.01
@@ -42,9 +43,11 @@
  *	     clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and
  *	     WDIOC_SETOPTIONS), made i810tco_getdevice __init,
  *	     removed boot_status, removed tco_timer_read,
- *	     added support for 82801DB and 82801E chipset, general cleanup.
+ *	     added support for 82801DB and 82801E chipset,
+ *	     added support for 82801EB and 8280ER chipset,
+ *	     general cleanup.
  */
- 
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -167,7 +170,7 @@
  * Reload (trigger) the timer. Lock is needed so we dont reload it during
  * a reprogramming event
  */
- 
+
 static void tco_timer_reload (void)
 {
 	spin_lock(&tco_lock);
@@ -310,6 +313,7 @@
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl);
diff -urN linux-2.4.22-bk4/drivers/char/i810-tco.h linux-2.4.22-bk5/drivers/char/i810-tco.h
--- linux-2.4.22-bk4/drivers/char/i810-tco.h	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.22-bk5/drivers/char/i810-tco.h	2003-08-30 02:51:17.000000000 -0700
@@ -1,5 +1,5 @@
 /*
- *	i810-tco 0.05:	TCO timer driver for i8xx chipsets
+ *	i810-tco:	TCO timer driver for i8xx chipsets
  *
  *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
  *				http://www.kernelconcepts.de
@@ -8,7 +8,7 @@
  *	modify it under the terms of the GNU General Public License
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
- *	
+ *
  *	Neither kernel concepts nor Nils Faerber admit liability nor provide
  *	warranty for any of this software. This material is provided
  *	"AS-IS" and at no charge.
diff -urN linux-2.4.22-bk4/drivers/char/keyboard.c linux-2.4.22-bk5/drivers/char/keyboard.c
--- linux-2.4.22-bk4/drivers/char/keyboard.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.22-bk5/drivers/char/keyboard.c	2003-08-30 02:51:17.000000000 -0700
@@ -198,6 +198,7 @@
 	unsigned char keycode;
 	char up_flag = down ? 0 : 0200;
 	char raw_mode;
+	char have_keycode;
 
 	pm_access(pm_kbd);
 	add_keyboard_randomness(scancode | up_flag);
@@ -214,16 +215,30 @@
 		tty = NULL;
 	}
 	kbd = kbd_table + fg_console;
-	if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
+	/*
+	 *  Convert scancode to keycode
+	 */
+	raw_mode = (kbd->kbdmode == VC_RAW);
+	have_keycode = kbd_translate(scancode, &keycode, raw_mode);
+	if (raw_mode) {
 		/*
 		 *	The following is a workaround for hardware
 		 *	which sometimes send the key release event twice 
 		 */
 		unsigned char next_scancode = scancode|up_flag;
-		if (up_flag && next_scancode==prev_scancode) {
+		if (have_keycode && up_flag && next_scancode==prev_scancode) {
 			/* unexpected 2nd release event */
 		} else {
-			prev_scancode=next_scancode;
+			/* 
+			 * Only save previous scancode if it was a key-up
+			 * and had a single-byte scancode.  
+			 */
+			if (!have_keycode)
+				prev_scancode = 1;
+			else if (!up_flag || prev_scancode == 1)
+				prev_scancode = 0;
+			else
+				prev_scancode = next_scancode;
 			put_queue(next_scancode);
 		}
 		/* we do not return yet, because we want to maintain
@@ -231,10 +246,7 @@
 		   values when finishing RAW mode or when changing VT's */
 	}
 
-	/*
-	 *  Convert scancode to keycode
-	 */
-	if (!kbd_translate(scancode, &keycode, raw_mode))
+	if (!have_keycode)
 		goto out;
 
 	/*
diff -urN linux-2.4.22-bk4/drivers/char/sn_serial.c linux-2.4.22-bk5/drivers/char/sn_serial.c
--- linux-2.4.22-bk4/drivers/char/sn_serial.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk5/drivers/char/sn_serial.c	2003-08-30 02:51:17.000000000 -0700
@@ -0,0 +1,1190 @@
+/*
+ * C-Brick Serial Port (and console) driver for SGI Altix machines.
+ *
+ * This driver is NOT suitable for talking to the l1-controller for
+ * anything other than 'console activities' --- please use the l1
+ * driver for that.
+ *
+ *
+ * Copyright (c) 2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#endif
+#include <linux/string.h>
+#include <linux/circ_buf.h>
+#include <linux/serial_reg.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/simulator.h>
+#include <asm/sn/sn2/intr.h>
+#include <asm/sn/sn2/sn_private.h>
+#include <asm/sn/clksupport.h>
+
+#ifdef CONFIG_KDB
+#include <linux/kdb.h>
+#include <asm/sn/uart16550.h>
+
+/*
+ * The following KDB configuration info is borrowed from
+ * linux/drivers/char/serial.c:
+ */
+
+/*
+ * "kdb_serial_str[] is the sequence that the user must enter on the serial
+ * console to invoke kdb.  It can be a single character such as "\001"
+ * (control-A) or multiple characters such as "\eKdB".  NOTE: All except the
+ * last character are passed through to the application reading from the serial
+ * console.
+ *
+ * I tried to make the sequence a CONFIG_ option but most of CML1 cannot cope
+ * with '\' in strings, CML2 should be able to do it.  KAO."
+ */
+
+static int  kdb_serial_line = -1;
+static const char kdb_serial_str[] = "\eKDB";
+static char *kdb_serial_ptr = kdb_serial_str;
+#endif /* CONFIG_KDB */
+
+#if defined(CONFIG_SGI_L1_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+static char sysrq_serial_str[] = "\eSYS";
+static char *sysrq_serial_ptr = sysrq_serial_str;
+static unsigned long sysrq_requested;
+#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */
+
+static char *serial_revdate = "2003-07-31";
+
+/* driver subtype - what does this mean? */
+#define SN_SAL_SUBTYPE 1
+
+/* minor device number */
+#define SN_SAL_MINOR 64
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 128
+
+/* number of characters we can transmit to the SAL console at a time */
+#define SN_SAL_MAX_CHARS 120
+
+/* event types for our task queue -- so far just one */
+#define SN_SAL_EVENT_WRITE_WAKEUP 0
+
+#define CONSOLE_RESTART 1
+
+/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to
+ * avoid losing chars, (always has to be a power of 2) */
+#if 1
+#define SN_SAL_BUFFER_SIZE (64 * (1 << 10))
+#else
+#define SN_SAL_BUFFER_SIZE (64)
+#endif
+
+#define SN_SAL_UART_FIFO_DEPTH 16
+#define SN_SAL_UART_FIFO_SPEED_CPS 9600/10
+
+/* we don't kmalloc/get_free_page these as we want them available
+ * before either of those are initialized */
+static volatile char xmit_buff_mem[SN_SAL_BUFFER_SIZE];
+
+struct volatile_circ_buf {
+	volatile char *buf;
+	int head;
+	int tail;
+};
+
+static volatile struct volatile_circ_buf xmit = { .buf = xmit_buff_mem };
+static char sal_tmp_buffer[SN_SAL_BUFFER_SIZE];
+
+static volatile struct tty_struct *sn_sal_tty;
+
+static struct timer_list sn_sal_timer;
+static int sn_sal_event; /* event type for task queue */
+static int sn_sal_refcount;
+
+static volatile int sn_sal_is_asynch;
+static volatile int sn_sal_irq;
+static spinlock_t sn_sal_lock = SPIN_LOCK_UNLOCKED;
+static volatile int tx_count;
+static volatile int rx_count;
+
+static struct tty_struct *sn_sal_table;
+static struct termios *sn_sal_termios;
+static struct termios *sn_sal_termios_locked;
+
+static void sn_sal_tasklet_action(unsigned long data);
+static DECLARE_TASKLET(sn_sal_tasklet, sn_sal_tasklet_action, 0);
+
+static volatile unsigned long interrupt_timeout;
+
+extern u64 master_node_bedrock_address;
+
+int debug_printf(const char *fmt, ...);
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTF(x...) debug_printf(x)
+#else
+#define DPRINTF(x...) do { } while (0)
+#endif
+
+static void intr_transmit_chars(void);
+static void poll_transmit_chars(void);
+static int sn_sal_write(struct tty_struct *tty, int from_user,
+			const unsigned char *buf, int count);
+
+struct sn_sal_ops {
+	int (*puts)(const char *s, int len);
+	int (*getc)(void);
+	int (*input_pending)(void);
+	void (*wakeup_transmit)(void);
+};
+
+static volatile struct sn_sal_ops *sn_sal_ops;
+
+
+/* the console does output in two distinctly different ways:
+ * synchronous and asynchronous (buffered).  initally, early_printk
+ * does synchronous output.  any data written goes directly to the SAL
+ * to be output (incidentally, it is internally buffered by the SAL)
+ * after interrupts and timers are initialized and available for use,
+ * the console init code switches to asynchronous output.  this is
+ * also the earliest opportunity to begin polling for console input.
+ * after console initialization, console output and tty (serial port)
+ * output is buffered and sent to the SAL asynchronously (either by
+ * timer callback or by UART interrupt) */
+
+
+/* routines for running the console in polling mode */
+
+static int hw_puts(const char *s, int len)
+{
+	/* looking at the PROM source code, putb calls the flush
+	 * routine, so if we send characters in FIFO sized chunks, it
+	 * should go out by the next time the timer gets called */
+	return ia64_sn_console_putb(s, len);
+}
+
+static int poll_getc(void)
+{
+	int ch;
+	ia64_sn_console_getc(&ch);
+	return ch;
+}
+
+static int poll_input_pending(void)
+{
+	int status, input;
+
+	status = ia64_sn_console_check(&input);
+	return !status && input;
+}
+
+static struct sn_sal_ops poll_ops = {
+	.puts = hw_puts,
+	.getc = poll_getc,
+	.input_pending = poll_input_pending
+};
+
+
+/* routines for running the console on the simulator */
+
+static int sim_puts(const char *str, int count)
+{
+	int counter = count;
+
+#ifdef FLAG_DIRECT_CONSOLE_WRITES
+	/* This is an easy way to pre-pend the output to know whether the output
+	 * was done via sal or directly */
+	writeb('[', master_node_bedrock_address + (UART_TX << 3));
+	writeb('+', master_node_bedrock_address + (UART_TX << 3));
+	writeb(']', master_node_bedrock_address + (UART_TX << 3));
+	writeb(' ', master_node_bedrock_address + (UART_TX << 3));
+#endif /* FLAG_DIRECT_CONSOLE_WRITES */
+	while (counter > 0) {
+		writeb(*str, master_node_bedrock_address + (UART_TX << 3));
+		counter--;
+		str++;
+	}
+
+	return count;
+}
+
+static int sim_getc(void)
+{
+	return readb(master_node_bedrock_address + (UART_RX << 3));
+}
+
+static int sim_input_pending(void)
+{
+	return readb(master_node_bedrock_address + (UART_LSR << 3)) & UART_LSR_DR;
+}
+
+static struct sn_sal_ops sim_ops = {
+	.puts = sim_puts,
+	.getc = sim_getc,
+	.input_pending = sim_input_pending
+};
+
+
+/* routines for an interrupt driven console (normal) */
+
+static int intr_getc(void)
+{
+	return ia64_sn_console_readc();
+}
+
+static int intr_input_pending(void)
+{
+	return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV;
+}
+
+static struct sn_sal_ops intr_ops = {
+	.puts = hw_puts,
+	.getc = intr_getc,
+	.input_pending = intr_input_pending,
+	.wakeup_transmit = intr_transmit_chars
+};
+
+extern void early_sn_setup(void);
+
+void
+early_printk_sn_sal(const char *s, unsigned count)
+{
+	if (!sn_sal_ops) {
+		if (IS_RUNNING_ON_SIMULATOR())
+			sn_sal_ops = &sim_ops;
+		else
+			sn_sal_ops = &poll_ops;
+
+		early_sn_setup();
+	}
+	sn_sal_ops->puts(s, count);
+}
+
+/* this is as "close to the metal" as we can get, used when the driver
+ * itself may be broken */
+int debug_printf(const char *fmt, ...)
+{
+	static char printk_buf[1024];
+	int printed_len;
+	va_list args;
+	va_start(args, fmt);
+	printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
+	early_printk_sn_sal(printk_buf, printed_len);
+	va_end(args);
+	return printed_len;
+}
+
+/*********************************************************************
+ * Interrupt handling routines.
+ */
+
+static void
+sn_sal_sched_event(int event)
+{
+	sn_sal_event |= (1 << event);
+	tasklet_schedule(&sn_sal_tasklet);
+}
+
+/* receive_chars can be called before sn_sal_tty is initialized.  in
+ * that case, its only use is to trigger sysrq and kdb */
+static void
+receive_chars(struct pt_regs *regs)
+{
+	int ch;
+
+	while (sn_sal_ops->input_pending()) {
+		ch = sn_sal_ops->getc();
+		if (ch < 0) {
+			printk(KERN_ERR "sn_serial: An error occured while "
+			       "obtaining data from the console (0x%0x)\n", ch);
+			break;
+		}
+#ifdef CONFIG_KDB
+		if (kdb_on) {
+			if (ch == *kdb_serial_ptr) {
+				if (!(*++kdb_serial_ptr)) {
+					if (!regs)
+						KDB_ENTER();	/* to get some registers */
+					else
+						kdb(KDB_REASON_KEYBOARD, 0, regs);
+					kdb_serial_ptr = kdb_serial_str;
+					break;
+				}
+			} else
+				kdb_serial_ptr = kdb_serial_str;
+		}
+#endif /* CONFIG_KDB */
+
+#if defined(CONFIG_SGI_L1_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+		if (sysrq_requested) {
+			unsigned long sysrq_timeout = sysrq_requested + HZ*5;
+			sysrq_requested = 0;
+			if (ch && time_before(jiffies, sysrq_timeout)) {
+				spin_unlock(&sn_sal_lock);
+				handle_sysrq(ch, regs, NULL, NULL);
+				spin_lock(&sn_sal_lock);
+				/* don't record this char */
+				continue;
+			}
+		}
+		if (ch == *sysrq_serial_ptr) {
+			if (!(*++sysrq_serial_ptr)) {
+				sysrq_requested = jiffies;
+				sysrq_serial_ptr = sysrq_serial_str;
+			}
+		} else
+			sysrq_serial_ptr = sysrq_serial_str;
+#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */
+
+		/* record the character to pass up to the tty layer */
+		if (sn_sal_tty) {
+			*sn_sal_tty->flip.char_buf_ptr = ch;
+			sn_sal_tty->flip.char_buf_ptr++;
+			sn_sal_tty->flip.count++;
+			if (sn_sal_tty->flip.count == TTY_FLIPBUF_SIZE)
+				break;
+		}
+		rx_count++;
+	}
+
+	if (sn_sal_tty)
+		tty_flip_buffer_push(sn_sal_tty);
+}
+
+
+/* synch_flush_xmit must be called with sn_sal_lock */
+static void
+synch_flush_xmit(void)
+{
+	int xmit_count, tail, head, loops, ii;
+	int result;
+	char *start;
+
+	if (xmit.head == xmit.tail)
+		/* Nothing to do. */
+		return;
+
+	head = xmit.head;
+	tail = xmit.tail;
+	start = &xmit.buf[tail];
+
+	/* twice around gets the tail to the end of the buffer and
+	 * then to the head, if needed */
+	loops = (head < tail) ? 2 : 1;
+
+	for (ii = 0; ii < loops; ii++) {
+		xmit_count = (head < tail) ?
+			(SN_SAL_BUFFER_SIZE - tail) : (head - tail);
+
+		if (xmit_count > 0) {
+			result = sn_sal_ops->puts(start, xmit_count);
+			if (!result)
+				debug_printf("\n*** synch_flush_xmit failed to flush\n");
+			if (result > 0) {
+				xmit_count -= result;
+				tx_count += result;
+				tail += result;
+				tail &= SN_SAL_BUFFER_SIZE - 1;
+				xmit.tail = tail;
+				start = &xmit.buf[tail];
+			}
+		}
+	}
+
+}
+
+/* must be called with a lock protecting the circular buffer and
+ * sn_sal_tty */
+static void
+poll_transmit_chars(void)
+{
+	int xmit_count, tail, head;
+	int result;
+	char *start;
+
+	BUG_ON(!sn_sal_is_asynch);
+
+	if (xmit.head == xmit.tail ||
+	    (sn_sal_tty && (sn_sal_tty->stopped || sn_sal_tty->hw_stopped))) {
+		/* Nothing to do. */
+		return;
+	}
+
+	head = xmit.head;
+	tail = xmit.tail;
+	start = &xmit.buf[tail];
+
+	xmit_count = (head < tail) ?
+		(SN_SAL_BUFFER_SIZE - tail) : (head - tail);
+
+	if (xmit_count == 0)
+		debug_printf("\n*** empty xmit_count\n");
+
+	if (xmit_count > SN_SAL_UART_FIFO_DEPTH)
+		xmit_count = SN_SAL_UART_FIFO_DEPTH;
+	
+	/* use the ops, as we could be on the simulator */
+	result = sn_sal_ops->puts(start, xmit_count);
+	if (!result)
+		debug_printf("\n*** error in synchronous puts\n");
+	/* XXX chadt clean this up */
+	if (result > 0) {
+		xmit_count -= result;
+		tx_count += result;
+		tail += result;
+		tail &= SN_SAL_BUFFER_SIZE - 1;
+		xmit.tail = tail;
+		start = &xmit.buf[tail];
+	}
+
+	/* if there's few enough characters left in the xmit buffer
+	 * that we could stand for the upper layer to send us some
+	 * more, ask for it. */
+	if (sn_sal_tty)
+		if (CIRC_CNT(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE) < WAKEUP_CHARS)
+			sn_sal_sched_event(SN_SAL_EVENT_WRITE_WAKEUP);
+}
+
+
+/* must be called with a lock protecting the circular buffer and
+ * sn_sal_tty */
+static void
+intr_transmit_chars(void)
+{
+	int xmit_count, tail, head, loops, ii;
+	int result;
+	char *start;
+
+	BUG_ON(!sn_sal_is_asynch);
+
+	if (xmit.head == xmit.tail ||
+	    (sn_sal_tty && (sn_sal_tty->stopped || sn_sal_tty->hw_stopped))) {
+		/* Nothing to do. */
+		return;
+	}
+
+	head = xmit.head;
+	tail = xmit.tail;
+	start = &xmit.buf[tail];
+
+	/* twice around gets the tail to the end of the buffer and
+	 * then to the head, if needed */
+	loops = (head < tail) ? 2 : 1;
+
+	for (ii = 0; ii < loops; ii++) {
+		xmit_count = (head < tail) ?
+			(SN_SAL_BUFFER_SIZE - tail) : (head - tail);
+
+		if (xmit_count > 0) {
+			result = ia64_sn_console_xmit_chars(start, xmit_count);
+#ifdef DEBUG
+			if (!result)
+				debug_printf("`");
+#endif
+			if (result > 0) {
+				xmit_count -= result;
+				tx_count += result;
+				tail += result;
+				tail &= SN_SAL_BUFFER_SIZE - 1;
+				xmit.tail = tail;
+				start = &xmit.buf[tail];
+			}
+		}
+	}
+
+	/* if there's few enough characters left in the xmit buffer
+	 * that we could stand for the upper layer to send us some
+	 * more, ask for it. */
+	if (sn_sal_tty)
+		if (CIRC_CNT(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE) < WAKEUP_CHARS)
+			sn_sal_sched_event(SN_SAL_EVENT_WRITE_WAKEUP);
+}
+
+
+static void
+sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* this call is necessary to pass the interrupt back to the
+	 * SAL, since it doesn't intercept the UART interrupts
+	 * itself */
+	int status = ia64_sn_console_intr_status();
+
+	spin_lock(&sn_sal_lock);
+	if (status & SAL_CONSOLE_INTR_RECV)
+		receive_chars(regs);
+	if (status & SAL_CONSOLE_INTR_XMIT)
+		intr_transmit_chars();
+	spin_unlock(&sn_sal_lock);
+}
+
+
+/* returns the console irq if interrupt is successfully registered,
+ * else 0 */
+static int
+sn_sal_connect_interrupt(void)
+{
+	cpuid_t intr_cpuid;
+	unsigned int intr_cpuloc;
+	nasid_t console_nasid;
+	unsigned int console_irq;
+	int result;
+
+	/* if it is an old prom, run in poll mode */
+	if ((sn_sal_rev_major() <= 1) && (sn_sal_rev_minor() <= 3)) {
+		/* before version 1.06 doesn't work */
+		printk(KERN_INFO "sn_serial: old prom version %x.%02x"
+		       " - running in polled mode\n",
+		       sn_sal_rev_major(), sn_sal_rev_minor());
+		return 0;
+	}
+
+	console_nasid = ia64_sn_get_console_nasid();
+	intr_cpuid = NODEPDA(NASID_TO_COMPACT_NODEID(console_nasid))
+		->node_first_cpu;
+	intr_cpuloc = cpu_physical_id(intr_cpuid);
+	console_irq = CPU_VECTOR_TO_IRQ(intr_cpuloc, SGI_UART_VECTOR);
+
+	result = intr_connect_level(intr_cpuid, SGI_UART_VECTOR,
+				    0 /*not used*/, 0 /*not used*/);
+	BUG_ON(result != SGI_UART_VECTOR);
+
+	result = request_irq(console_irq, sn_sal_interrupt,
+			     SA_INTERRUPT,  "SAL console driver", &sn_sal_tty);
+	if (result >= 0)
+		return console_irq;
+
+	printk(KERN_INFO "sn_serial: console proceeding in polled mode\n");
+	return 0;
+}
+
+/*
+ * End of the interrupt routines.
+ *********************************************************************/
+
+
+static void
+sn_sal_tasklet_action(unsigned long data)
+{
+	unsigned long flags;
+
+	if (sn_sal_tty) {
+		spin_lock_irqsave(&sn_sal_lock, flags);
+		if (sn_sal_tty)
+			if (test_and_clear_bit(SN_SAL_EVENT_WRITE_WAKEUP, &sn_sal_event)) {
+				if ((sn_sal_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+				    sn_sal_tty->ldisc.write_wakeup)
+					(sn_sal_tty->ldisc.write_wakeup)(sn_sal_tty);
+				wake_up_interruptible(&sn_sal_tty->write_wait);
+			}
+		spin_unlock_irqrestore(&sn_sal_lock, flags);
+	}
+}
+
+
+/*
+ * This function handles polled mode.
+ */
+static void
+sn_sal_timer_poll(unsigned long dummy)
+{
+	if (!sn_sal_irq) {
+		spin_lock(&sn_sal_lock);
+		receive_chars(NULL);
+		poll_transmit_chars();
+		spin_unlock(&sn_sal_lock);
+		mod_timer(&sn_sal_timer, jiffies + interrupt_timeout);
+	}
+}
+
+static void
+sn_sal_timer_restart(unsigned long dummy)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	sn_sal_interrupt(0, NULL, NULL);
+	local_irq_restore(flags);
+	mod_timer(&sn_sal_timer, jiffies + interrupt_timeout);
+}
+
+/*
+ * End of "sofware interrupt" routines.
+ *********************************************************************/
+
+
+/*********************************************************************
+ * User-level console routines
+ */
+
+static int
+sn_sal_open(struct tty_struct *tty, struct file *filp)
+{
+	unsigned long flags;
+
+	DPRINTF("sn_sal_open: sn_sal_tty = %p, tty = %p, filp = %p\n",
+		sn_sal_tty, tty, filp);
+
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	if (!sn_sal_tty)
+		sn_sal_tty = tty;
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+
+	return 0;
+}
+
+
+/* We're keeping all our resources.  We're keeping interrupts turned
+ * on.  Maybe just let the tty layer finish its stuff...? GMSH
+ */
+static void
+sn_sal_close(struct tty_struct *tty, struct file * filp)
+{
+	if (atomic_read(&tty->count) == 1) {
+		unsigned long flags;
+		tty->closing = 1;
+		if (tty->driver.flush_buffer)
+			tty->driver.flush_buffer(tty);
+		if (tty->ldisc.flush_buffer)
+			tty->ldisc.flush_buffer(tty);
+		tty->closing = 0;
+		spin_lock_irqsave(&sn_sal_lock, flags);
+		sn_sal_tty = NULL;
+		spin_unlock_irqrestore(&sn_sal_lock, flags);
+	}
+}
+
+
+static int
+sn_sal_write(struct tty_struct *tty, int from_user,
+	     const unsigned char *buf, int count)
+{
+	int c, ret = 0;
+	unsigned long flags;
+
+	if (from_user) {
+		while (1) {
+			int c1;
+			c = CIRC_SPACE_TO_END(xmit.head, xmit.tail,
+					      SN_SAL_BUFFER_SIZE);
+
+			if (count < c)
+				c = count;
+			if (c <= 0)
+				break;
+
+			c -= copy_from_user(sal_tmp_buffer, buf, c);
+			if (!c) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+
+			/* Turn off interrupts and see if the xmit buffer has
+			 * moved since the last time we looked.
+			 */
+			spin_lock_irqsave(&sn_sal_lock, flags);
+			c1 = CIRC_SPACE_TO_END(xmit.head, xmit.tail,
+					       SN_SAL_BUFFER_SIZE);
+
+			if (c1 < c)
+				c = c1;
+
+			memcpy(xmit.buf + xmit.head, sal_tmp_buffer, c);
+			xmit.head = ((xmit.head + c) & (SN_SAL_BUFFER_SIZE - 1));
+			spin_unlock_irqrestore(&sn_sal_lock, flags);
+
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+	} else {
+		/* The buffer passed in isn't coming from userland,
+		 * so cut out the middleman (sal_tmp_buffer).
+		 */
+		spin_lock_irqsave(&sn_sal_lock, flags);
+		while (1) {
+			c = CIRC_SPACE_TO_END(xmit.head, xmit.tail,
+					      SN_SAL_BUFFER_SIZE);
+
+			if (count < c)
+				c = count;
+			if (c <= 0) {
+				break;
+			}
+			memcpy(xmit.buf + xmit.head, buf, c);
+			xmit.head = ((xmit.head + c) & (SN_SAL_BUFFER_SIZE - 1));
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		spin_unlock_irqrestore(&sn_sal_lock, flags);
+	}
+
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	if (xmit.head != xmit.tail &&
+	    !(tty && (tty->stopped || tty->hw_stopped)))
+		if (sn_sal_ops->wakeup_transmit)
+			sn_sal_ops->wakeup_transmit();
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+
+	return ret;
+}
+
+
+static void
+sn_sal_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	if (CIRC_SPACE(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE) != 0) {
+		xmit.buf[xmit.head] = ch;
+		xmit.head = (xmit.head + 1) & (SN_SAL_BUFFER_SIZE-1);
+		sn_sal_ops->wakeup_transmit();
+	}
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+}
+
+
+static void
+sn_sal_flush_chars(struct tty_struct *tty)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	if (CIRC_CNT(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE))
+		if (sn_sal_ops->wakeup_transmit)
+			sn_sal_ops->wakeup_transmit();
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+}
+
+
+static int
+sn_sal_write_room(struct tty_struct *tty)
+{
+	unsigned long flags;
+	int space;
+
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	space = CIRC_SPACE(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE);
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+	return space;
+}
+
+
+static int
+sn_sal_chars_in_buffer(struct tty_struct *tty)
+{
+	unsigned long flags;
+	int space;
+
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	space = CIRC_CNT(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE);
+	DPRINTF("<%d>", space);
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+	return space;
+}
+
+
+static int
+sn_sal_ioctl(struct tty_struct *tty, struct file *file,
+	       unsigned int cmd, unsigned long arg)
+{
+	/* nothing supported */
+
+	return -ENOIOCTLCMD;
+}
+
+
+static void
+sn_sal_flush_buffer(struct tty_struct *tty)
+{
+	unsigned long flags;
+
+	/* drop everything */
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	xmit.head = xmit.tail = 0;
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+
+	/* wake up tty level */
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+
+static void
+sn_sal_hangup(struct tty_struct *tty)
+{
+	sn_sal_flush_buffer(tty);
+}
+
+
+static void
+sn_sal_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	/* this is SAL's problem */
+	DPRINTF("<sn_serial: should wait until sent>");
+}
+
+
+/*
+ * sn_sal_read_proc
+ *
+ * Console /proc interface
+ */
+
+static int
+sn_sal_read_proc(char *page, char **start, off_t off, int count,
+		   int *eof, void *data)
+{
+	int len = 0;
+	off_t	begin = 0;
+	extern nasid_t get_console_nasid(void);
+
+	len += sprintf(page, "sn_serial: revision:%s nasid:%d irq:%d tx:%d rx:%d\n",
+		       serial_revdate, get_console_nasid(), sn_sal_irq,
+		       tx_count, rx_count);
+	*eof = 1;
+
+	if (off >= len+begin)
+		return 0;
+	*start = page + (off-begin);
+
+	return count < begin+len-off ? count : begin+len-off;
+}
+
+
+static struct tty_driver sn_sal_driver = {
+	.magic = TTY_DRIVER_MAGIC,
+	.driver_name = "sn_serial",
+#if defined(CONFIG_DEVFS_FS)
+	.name = "tts/%d",
+#else
+	.name = "ttyS",
+#endif
+	.major = TTY_MAJOR,
+	.minor_start = SN_SAL_MINOR,
+	.num = 1,
+	.type = TTY_DRIVER_TYPE_SERIAL,
+	.subtype = SN_SAL_SUBTYPE,
+	.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+	.refcount = &sn_sal_refcount,
+	.table = &sn_sal_table,
+	.termios = &sn_sal_termios,
+	.termios_locked = &sn_sal_termios_locked,
+
+	.open = sn_sal_open,
+	.close = sn_sal_close,
+	.write = sn_sal_write,
+	.put_char = sn_sal_put_char,
+	.flush_chars = sn_sal_flush_chars,
+	.write_room = sn_sal_write_room,
+	.chars_in_buffer = sn_sal_chars_in_buffer,
+	.ioctl = sn_sal_ioctl,
+	.hangup = sn_sal_hangup,
+	.wait_until_sent = sn_sal_wait_until_sent,
+	.read_proc = sn_sal_read_proc,
+};
+
+/* sn_sal_init wishlist:
+ * - allocate sal_tmp_buffer
+ * - fix up the tty_driver struct
+ * - turn on receive interrupts
+ * - do any termios twiddling once and for all
+ */
+
+/*
+ * Boot-time initialization code
+ */
+
+static void __init
+sn_sal_switch_to_asynch(void)
+{
+	debug_printf("sn_serial: about to switch to asynchronous console\n");
+
+	/* without early_printk, we may be invoked late enough to race
+	 * with other cpus doing console IO at this point, however
+	 * console interrupts will never be enabled */
+	spin_lock(&sn_sal_lock);
+
+	/* early_printk invocation may have done this for us */
+	if (!sn_sal_ops) {
+		if (IS_RUNNING_ON_SIMULATOR())
+			sn_sal_ops = &sim_ops;
+		else
+			sn_sal_ops = &poll_ops;
+	}
+
+	/* we can't turn on the console interrupt (as request_irq
+	 * calls kmalloc, which isn't set up yet), so we rely on a
+	 * timer to poll for input and push data from the console
+	 * buffer.
+	 */
+	init_timer(&sn_sal_timer);
+	sn_sal_timer.function = sn_sal_timer_poll;
+
+	if (IS_RUNNING_ON_SIMULATOR())
+		interrupt_timeout = 6;
+	else
+		/* 960cps / 16 char FIFO = 60HZ 
+		   HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */
+		interrupt_timeout = HZ * SN_SAL_UART_FIFO_DEPTH / 
+			SN_SAL_UART_FIFO_SPEED_CPS;
+
+	mod_timer(&sn_sal_timer, jiffies + interrupt_timeout);
+
+	sn_sal_is_asynch = 1;
+	spin_unlock(&sn_sal_lock);
+}
+
+static void __init
+sn_sal_switch_to_interrupts(void)
+{
+	int irq;
+
+	debug_printf("sn_serial: switching to interrupt driven console\n");
+
+	irq = sn_sal_connect_interrupt();
+	if (irq) {
+		unsigned long flags;
+		spin_lock_irqsave(&sn_sal_lock, flags);
+		/* sn_sal_irq is a global variable.  When it's set to
+		 * a non-zero value, we stop polling for input (since
+		 * interrupts should now be enabled). */
+		sn_sal_irq = irq;
+		sn_sal_ops = &intr_ops;
+		/* turn on receive interrupts */
+		ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
+
+		/* the polling timer is already set up, we just change the
+		 * frequency.  if we've successfully enabled interrupts (and
+		 * CONSOLE_RESTART isn't defined) the next timer expiration
+		 * will be the last, otherwise we continue polling */
+		if (CONSOLE_RESTART) {
+			/* kick the console every once in a while in
+			 * case we miss an interrupt */
+			interrupt_timeout = 20*HZ;
+			sn_sal_timer.function = sn_sal_timer_restart;
+			mod_timer(&sn_sal_timer, jiffies + interrupt_timeout);
+		}
+		spin_unlock_irqrestore(&sn_sal_lock, flags);
+	}
+}
+
+static int __init
+sn_sal_module_init(void)
+{
+	int retval;
+
+	printk("sn_serial: sn_sal_module_init\n");
+
+	if (!ia64_platform_is("sn2"))
+		return -ENODEV;
+
+	/* when this driver is compiled in, the console initialization
+	 * will have already switched us into asynchronous operation
+	 * before we get here through the module initcalls */
+	if (!sn_sal_is_asynch)
+		sn_sal_switch_to_asynch();
+
+	/* at this point (module_init) we can try to turn on
+	 * interrupts */
+	if (!IS_RUNNING_ON_SIMULATOR())
+	    sn_sal_switch_to_interrupts();
+
+	sn_sal_driver.init_termios = tty_std_termios;
+	sn_sal_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+	if ((retval = tty_register_driver(&sn_sal_driver))) {
+		printk(KERN_ERR "sn_serial: Unable to register tty driver\n");
+		return retval;
+	}
+
+	tty_register_devfs(&sn_sal_driver, 0, sn_sal_driver.minor_start);
+
+	return 0;
+}
+
+
+static void __exit
+sn_sal_module_exit(void)
+{
+	unsigned long flags;
+	int e;
+
+	del_timer_sync(&sn_sal_timer);
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	if ((e = tty_unregister_driver(&sn_sal_driver)))
+		printk(KERN_ERR "sn_serial: failed to unregister driver (%d)\n", e);
+
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+}
+
+module_init(sn_sal_module_init);
+module_exit(sn_sal_module_exit);
+
+/*
+ * End of user-level console routines.
+ *********************************************************************/
+
+
+/*********************************************************************
+ * Kernel console definitions
+ */
+
+#ifdef CONFIG_SGI_L1_SERIAL_CONSOLE
+/*
+ * Print a string to the SAL console.  The console_lock must be held
+ * when we get here.
+ */
+static void
+sn_sal_console_write(struct console *co, const char *s, unsigned count)
+{
+	BUG_ON(!sn_sal_is_asynch);
+
+	if (count > CIRC_SPACE_TO_END(xmit.head, xmit.tail,
+				      SN_SAL_BUFFER_SIZE))
+		debug_printf("\n*** SN_SAL_BUFFER_SIZE too small, lost chars\n");
+
+	/* somebody really wants this output, might be an
+	 * oops, kdb, panic, etc.  make sure they get it. */
+	if (spin_is_locked(&sn_sal_lock)) {
+		synch_flush_xmit();
+		sn_sal_ops->puts(s, count);
+	} else if (in_interrupt()) {
+		spin_lock(&sn_sal_lock);
+		synch_flush_xmit();
+		spin_unlock(&sn_sal_lock);
+		sn_sal_ops->puts(s, count);
+	} else
+		sn_sal_write(NULL, 0, s, count);
+}
+
+static kdev_t
+sn_sal_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+static int __init
+sn_sal_console_setup(struct console *co, char *options)
+{
+#ifdef CONFIG_KDB
+	/*
+	 * Remember the line number of the first serial
+	 * console.  We'll make this the kdb serial console too.
+	 */
+	if (kdb_serial_line == -1) {
+		kdb_serial_line = co->index;
+	}
+#endif /* CONFIG_KDB */
+
+	return 0;
+}
+
+
+static struct console sal_console = {
+	.name = "ttyS",
+	.write = sn_sal_console_write,
+	.device = sn_sal_console_device,
+	.setup = sn_sal_console_setup,
+	.index = -1
+};
+
+/*
+ * End of kernel console definitions.
+ *********************************************************************/
+
+
+void __init
+sn_sal_serial_console_init(void)
+{
+	if (ia64_platform_is("sn2")) {
+		sn_sal_switch_to_asynch();
+		register_console(&sal_console);
+	}
+}
+
+
+#ifdef	CONFIG_KDB
+int
+l1_control_in_polled(int offset)
+{
+	int sal_call_status = 0, input;
+	int ret = 0;
+
+	if (IS_RUNNING_ON_SIMULATOR()) {
+		ret = readb((unsigned long)master_node_bedrock_address +
+			    (offset<< 3));
+		return(ret);
+	}		
+	if (offset == REG_LSR) {
+		ret = (LSR_XHRE | LSR_XSRE);	/* can send anytime */
+		sal_call_status = ia64_sn_console_check(&input);
+		if (!sal_call_status && input) {
+			/* input pending */
+			ret |= LSR_RCA;
+		}
+	}
+	return ret;
+}
+
+int
+l1_serial_in_polled(void)
+{
+	int ch;
+
+	if (IS_RUNNING_ON_SIMULATOR()) {
+		return readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+	}		
+
+	if (!ia64_sn_console_getc(&ch))
+		return ch;
+	else
+		return 0;
+}
+#endif /* CONFIG_KDB */
+
+#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE */
diff -urN linux-2.4.22-bk4/drivers/char/tty_io.c linux-2.4.22-bk5/drivers/char/tty_io.c
--- linux-2.4.22-bk4/drivers/char/tty_io.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.22-bk5/drivers/char/tty_io.c	2003-08-30 02:51:17.000000000 -0700
@@ -154,6 +154,7 @@
 extern void rs285_console_init(void);
 extern void sa1100_rs_console_init(void);
 extern void sgi_serial_console_init(void);
+extern void sn_sal_serial_console_init(void);
 extern void sci_console_init(void);
 extern void dec_serial_console_init(void);
 extern void tx3912_console_init(void);
@@ -2391,6 +2392,12 @@
 	kbd_init();
 #endif
 
+#ifdef CONFIG_SGI_L1_SERIAL_CONSOLE
+	if (ia64_platform_is("sn2")) {
+		sn_sal_serial_console_init();
+		return; /* only one console right now for SN2 */
+	}
+#endif
 #ifdef CONFIG_ESPSERIAL  /* init ESP before rs, so rs doesn't see the port */
 	espserial_init();
 #endif
diff -urN linux-2.4.22-bk4/drivers/scsi/scsi_scan.c linux-2.4.22-bk5/drivers/scsi/scsi_scan.c
--- linux-2.4.22-bk4/drivers/scsi/scsi_scan.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.22-bk5/drivers/scsi/scsi_scan.c	2003-08-30 02:51:21.000000000 -0700
@@ -114,7 +114,8 @@
 	{"HP", "C2500A", "", BLIST_NOLUN},			/* scanjet iicx */
 	{"HP", "A6188A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7100 Array */
 	{"HP", "A6189A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7400 Array */
-	{"HP", "A6189B", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7410 Array */
+	{"HP", "A6189B", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7110 Array */
+	{"HP", "A6218A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7410 Array */
 	{"YAMAHA", "CDR100", "1.00", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
 	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},		/* Locks up if polled for lun != 0  
 								 * extra reset */
