## Automatically generated incremental diff
## From:   linux-2.4.15-pre3
## To:     linux-2.4.15-pre4
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.4.15-pre3/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.4.15-pre3/Documentation/Configure.help	Mon Dec  3 23:28:48 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 23:28:58 2001
@@ -3524,25 +3524,30 @@
   and ds.o.  If you want to compile it as a module, say M here and
   read <file:Documentation/modules.txt>.
 
-CardBus support
+CardBus card and (Yenta) bridge support
 CONFIG_CARDBUS
   CardBus is a bus mastering architecture for PC-cards, which allows
   for 32 bit PC-cards (the original PCMCIA standard specifies only
   a 16 bit wide bus). Many newer PC-cards are actually CardBus cards.
 
+  This option enables support for CardBus PC Cards, as well as support
+  for CardBus host bridges.  Virtually all modern PCMCIA bridges are
+  CardBus compatible.  A "bridge" is the hardware inside your computer
+  that PCMCIA cards are plugged into.
+
   To use your PC-cards, you will need supporting software from David
   Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
   for location).
 
   If unsure, say Y.
 
-i82365 compatible bridge support
+i82365 compatible host bridge support
 CONFIG_I82365
-  Say Y here to include support for PCMCIA bridges that are register
-  compatible with the Intel i82365 specification: this includes
-  virtually all common PCMCIA bridges that are not 'Yenta' Cardbus
-  bridges.  "Bridge" is the name used for the hardware inside your
-  computer that PCMCIA cards are plugged into.  If unsure, say Y.
+  Say Y here to include support for ISA-bus PCMCIA host bridges that
+  are register compatible with the Intel i82365.  These are found on
+  older laptops and ISA-bus card readers for desktop systems.  A
+  "bridge" is the hardware inside your computer that PCMCIA cards are
+  plugged into. If unsure, say N.
 
 Databook TCIC host bridge support
 CONFIG_TCIC
@@ -12729,8 +12734,9 @@
 CONFIG_USB_SERIAL_FTDI_SIO
   Say Y here if you want to use a FTDI SIO single port USB to serial
   converter device. The implementation I have is called the USC-1000.
+  This driver has also be tested with the 245 and 232 devices.
 
-  See <http://reality.sgi.com/bryder_wellington/ftdi_sio> for more
+  See  http://ftdi-usb-sio.sourceforge.net for more
   information on this driver and the device.
 
   This code is also available as a module ( = code which can be
diff -urN linux-2.4.15-pre3/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt
--- linux-2.4.15-pre3/Documentation/usb/usb-serial.txt	Wed Jun 27 13:59:32 2001
+++ linux/Documentation/usb/usb-serial.txt	Mon Dec  3 23:28:58 2001
@@ -44,28 +44,33 @@
   device, including providing a unit to test with. This driver will end up
   being fully supported.
 
-Current status:
-  The device's firmware is downloaded on connection, the new firmware 
-  runs properly and all four ports are successfully recognized and connected.
-  Data can be sent and received through the device on all ports.
-  Hardware flow control needs to be implemented.
+  Current status:
+    The device's firmware is downloaded on connection, the new firmware 
+    runs properly and all four ports are successfully recognized and connected.
+    Data can be sent and received through the device on all ports.
+    Hardware flow control needs to be implemented.
 
+  For any questions or problems with this driver, please contact Greg
+  Kroah-Hartman at greg@kroah.com
 
-HandSpring Visor USB docking station
-
-Current status:
-  Only when the Visor tries to connect to the host, does the docking
-  station show up as a valid USB device. When this happens, the device is
+
+HandSpring Visor, Palm USB, and Clié USB driver
+
+  This driver works with all HandSpring USB, Palm USB, and Sony Clié USB
+  devices.
+
+  Only when the device tries to connect to the host, will the device show
+  up to the host as a valid USB device. When this happens, the device is
   properly enumerated, assigned a port, and then communication _should_ be
   possible. The driver cleans up properly when the device is removed, or
-  the connection is canceled on the Visor.
+  the connection is canceled on the device.
 
   NOTE:
-    This means that in order to talk to the Visor, the sync button must be
-    pressed BEFORE trying to get any program to communicate to the Visor.
+    This means that in order to talk to the device, the sync button must be
+    pressed BEFORE trying to get any program to communicate to the device.
     This goes against the current documentation for pilot-xfer and other
     packages, but is the only way that it will work due to the hardware
-    in the Visor.
+    in the device.
   
   When the device is connected, try talking to it on the second port
   (this is usually /dev/ttyUSB1 if you do not have any other usb-serial
@@ -73,37 +78,49 @@
   the port to use for the HotSync transfer. The "Generic" port can be used
   for other device communication, such as a PPP link.
 
+  For some Sony Clié devices, /dev/ttyUSB0 must be used to talk to the
+  device.  This is true for all OS version 3.5 devices, and most devices
+  that have had a flash upgrade to a newer version of the OS.  See the
+  kernel system log for information on which is the correct port to use.
+
   If after pressing the sync button, nothing shows up in the system log,
-  try resetting the Visor, first a hot reset, and then a cold reset if
-  necessary.  Some Visors need this before they can talk to the USB port
+  try resetting the device, first a hot reset, and then a cold reset if
+  necessary.  Some devices need this before they can talk to the USB port
   properly.
   
-  There is a webpage and mailing lists for this portion of the driver at: 
+  There is a webpage and mailing lists for this portion of the driver at:
   http://usbvisor.sourceforge.net/
 
+  For any questions or problems with this driver, please contact Greg
+  Kroah-Hartman at greg@kroah.com
+
 
 Keyspan PDA Serial Adapter
 
   Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly
   sold in Macintosh catalogs, comes in a translucent white/green dongle).
   Fairly simple device. Firmware is homebrew.
+  This driver also works for the Xircom/Entrgra single port serial adapter.
 
-Current status:
- Things that work:
-   basic input/output (tested with 'cu')
-   blocking write when serial line can't keep up
-   changing baud rates (up to 115200)
-   getting/setting modem control pins (TIOCM{GET,SET,BIS,BIC})
-   sending break (although duration looks suspect)
- Things that don't:
-   device strings (as logged by kernel) have trailing binary garbage
-   device ID isn't right, might collide with other Keyspan products
-   changing baud rates ought to flush tx/rx to avoid mangled half characters
- Big Things on the todo list:
-   parity, 7 vs 8 bits per char, 1 or 2 stop bits
-   HW flow control
-   not all of the standard USB descriptors are handled: Get_Status, Set_Feature
-   O_NONBLOCK, select()
+  Current status:
+   Things that work:
+     basic input/output (tested with 'cu')
+     blocking write when serial line can't keep up
+     changing baud rates (up to 115200)
+     getting/setting modem control pins (TIOCM{GET,SET,BIS,BIC})
+     sending break (although duration looks suspect)
+   Things that don't:
+     device strings (as logged by kernel) have trailing binary garbage
+     device ID isn't right, might collide with other Keyspan products
+     changing baud rates ought to flush tx/rx to avoid mangled half characters
+   Big Things on the todo list:
+     parity, 7 vs 8 bits per char, 1 or 2 stop bits
+     HW flow control
+     not all of the standard USB descriptors are handled: Get_Status, Set_Feature
+     O_NONBLOCK, select()
+
+  For any questions or problems with this driver, please contact Brian
+  Warner at warner@lothar.com 
 
 
 Keyspan USA-series Serial Adapters
@@ -111,19 +128,22 @@
   Single, Dual and Quad port adapters - driver uses Keyspan supplied 
   firmware and is being developed with their support.
   
-Current status:
-  The USA-18X, USA-28X, USA-19, USA-19W and USA-49W are supported and
-  have been pretty throughly tested at various baud rates with 8-N-1
-  character settings.  Other character lengths and parity setups are
-  presently untested.
-
-  The USA-28 isn't yet supported though doing so should be pretty
-  straightforward.  Contact the maintainer if you require this
-  functionality.
+  Current status:
+    The USA-18X, USA-28X, USA-19, USA-19W and USA-49W are supported and
+    have been pretty throughly tested at various baud rates with 8-N-1
+    character settings.  Other character lengths and parity setups are
+    presently untested.
+
+    The USA-28 isn't yet supported though doing so should be pretty
+    straightforward.  Contact the maintainer if you require this
+    functionality.
   
   More information is available at:
-        http://www.linuxcare.com.au/hugh/keyspan.html
+        http://misc.nu/hugh/keyspan.html
    
+  For any questions or problems with this driver, please contact Hugh
+  Blemings at hugh@misc.nu
+
 
 FTDI Single Port Serial Driver
 
@@ -131,6 +151,9 @@
   device and the Linux driver can be found at:
 	http://reality.sgi.com/bryder_wellington/ftdi_sio/
 
+  For any questions or problems with this driver, please contact Bill Ryder
+  at bryder@sgi.com
+
 
 ZyXEL omni.net lcd plus ISDN TA
 
@@ -162,65 +185,71 @@
 Belkin USB Serial Adapter F5U103
 
   Single port DB-9/PS-2 serial adapter from Belkin with firmware by eTEK Labs.
-  The Peracom single port serial adapter also works with this driver.
+  The Peracom single port serial adapter also works with this driver, as
+  well as the GoHubs adapter.
+
+  Current status:
+    The following have been tested and work:
+      Baud rate    300-230400               
+      Data bits    5-8
+      Stop bits    1-2
+      Parity       N,E,O,M,S
+      Handshake    None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR)*
+      Break        Set and clear
+      Line contrl  Input/Output query and control **
+
+      *  Hardware input flow control is only enabled for firmware
+         levels above 2.06.  Read source code comments describing Belkin
+         firmware errata.  Hardware output flow control is working for all
+         firmware versions.
+      ** Queries of inputs (CTS,DSR,CD,RI) show the last
+         reported state.  Queries of outputs (DTR,RTS) show the last
+         requested state and may not reflect current state as set by
+         automatic hardware flow control.
+
+  TO DO List:
+    -- Add true modem contol line query capability.  Currently tracks the
+       states reported by the interrupt and the states requested.
+    -- Add error reporting back to application for UART error conditions.
+    -- Add support for flush ioctls.
+    -- Add everything else that is missing :)
 
-Current status:
-  The following have been tested and work:
-    Baud rate    300-230400               
-    Data bits    5-8
-    Stop bits    1-2
-    Parity       N,E,O,M,S
-    Handshake    None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR)*
-    Break        Set and clear
-    Line contrl  Input/Output query and control **
-
-    *  Hardware input flow control is only enabled for firmware
-       levels above 2.06.  Read source code comments describing Belkin
-       firmware errata.  Hardware output flow control is working for all
-       firmware versions.
-    ** Queries of inputs (CTS,DSR,CD,RI) show the last
-       reported state.  Queries of outputs (DTR,RTS) show the last
-       requested state and may not reflect current state as set by
-       automatic hardware flow control.
-
-TO DO List:
-  -- Add true modem contol line query capability.  Currently tracks the
-     states reported by the interrupt and the states requested.
-  -- Add error reporting back to application for UART error conditions.
-  -- Add support for flush ioctls.
-  -- Add everything else that is missing :)
+  For any questions or problems with this driver, please contact William
+  Greathouse at wgreathouse@smva.com
 
 
-Empeg empeg-car Mark I/II Driver (empeg.c)
+Empeg empeg-car Mark I/II Driver
 
   This is an experimental driver to provide connectivity support for the
   client synchronization tools for an Empeg empeg-car mp3 player.
 
   Tips:
-
     * Don't forget to create the device nodes for ttyUSB{0,1,2,...}
     * modprobe empeg (modprobe is your friend)
     * emptool --usb /dev/ttyUSB0 (or whatever you named your device node)
 
-  The driver is still pretty new, so some testing 'in the wild' would be
-  helpful. :)
+  For any questions or problems with this driver, please contact Gary
+  Brubaker at xavyer@ix.netcom.com
 
 
 MCT USB Single Port Serial Adapter U232
 
- This driver is for the MCT USB-RS232 Converter (25 pin, Model No.
- U232-P25) from Magic Control Technology Corp. (there is also a 9 pin
- Model No. U232-P9). More information about this device can be found
- at the manufacture's web-site: http://www.mct.com.tw.
-
- The driver is generally working, though it still needs some more
- testing. It is derived from the Belkin USB Serial Adapter F5U103
- driver and its TODO list is valid for this driver as well.
-
- This driver has also been found to work for other products, which have 
- the same Vendor ID but different Product IDs. Sitecom's U232-P25 
- serial converter uses Product ID 0x230 and Vendor ID 0x711 and works with 
- this driver. Also, D-Link's DU-H3SP USB BAY also works with this driver.
+  This driver is for the MCT USB-RS232 Converter (25 pin, Model No.
+  U232-P25) from Magic Control Technology Corp. (there is also a 9 pin
+  Model No. U232-P9). More information about this device can be found at
+  the manufacture's web-site: http://www.mct.com.tw.
+
+  The driver is generally working, though it still needs some more testing.
+  It is derived from the Belkin USB Serial Adapter F5U103 driver and its
+  TODO list is valid for this driver as well.
+
+  This driver has also been found to work for other products, which have
+  the same Vendor ID but different Product IDs. Sitecom's U232-P25 serial
+  converter uses Product ID 0x230 and Vendor ID 0x711 and works with this
+  driver. Also, D-Link's DU-H3SP USB BAY also works with this driver.
+
+  For any questions or problems with this driver, please contact Wolfgang
+  Grandegger at wolfgang@ces.ch
 
 
 Inside Out Networks Edgeport Driver
@@ -244,17 +273,34 @@
        Edgeport/4 DIN
        Edgeport/16 Dual
 
+  For any questions or problems with this driver, please contact Greg
+  Kroah-Hartman at greg@kroah.com
+
 
 REINER SCT cyberJack pinpad/e-com USB chipcard reader
    
   Interface to ISO 7816 compatible contactbased chipcards, e.g. GSM SIMs.
   
-Current status:
-  This is the kernel part of the driver for this USB card reader.
-  There is also a user part for a CT-API driver available. A site
-  for downloading is TBA. For now, you can request it from the
-  maintainer (linux-usb@sii.li).
+  Current status:
+    This is the kernel part of the driver for this USB card reader.
+    There is also a user part for a CT-API driver available. A site
+    for downloading is TBA. For now, you can request it from the
+    maintainer (linux-usb@sii.li).
+
+  For any questions or problems with this driver, please contact
+  linux-usb@sii.li
+
 
+Prolific PL2303 Driver
+
+  This driver support any device that has the PL2303 chip from Prolific
+  in it.  This includes a number of single port USB to serial
+  converters and USB GPS devices.  Devices from Aten (the UC-232) and
+  IO-Data work with this driver.
+
+  For any questions or problems with this driver, please contact Greg
+  Kroah-Hartman at greg@kroah.com
+  
 
 Generic Serial driver
 
@@ -275,13 +321,17 @@
   development board, providing a way to develop USB firmware without
   having to write a custom driver.
 
+  For any questions or problems with this driver, please contact Greg
+  Kroah-Hartman at greg@kroah.com
+
 
 CONTACT:
 
-  If anyone has any problems using this driver, with any of the above
-  specified products, please contact me, or join the Linux-USB mailing
-  list (information on joining the mailing list, as well as a link to its
-  searchable archive is at http://www.linux-usb.org/ )
+  If anyone has any problems using these drivers, with any of the above
+  specified products, please contact the specific driver's author listed
+  above, or join the Linux-USB mailing list (information on joining the
+  mailing list, as well as a link to its searchable archive is at
+  http://www.linux-usb.org/ )
 
 
 Greg Kroah-Hartman
diff -urN linux-2.4.15-pre3/Makefile linux/Makefile
--- linux-2.4.15-pre3/Makefile	Mon Dec  3 23:28:48 2001
+++ linux/Makefile	Mon Dec  3 23:28:58 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 15
-EXTRAVERSION =-pre3
+EXTRAVERSION =-pre4
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -183,6 +183,7 @@
 DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
 DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
 DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o
+DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o
 
 DRIVERS := $(DRIVERS-y)
 
diff -urN linux-2.4.15-pre3/arch/i386/boot/compressed/misc.c linux/arch/i386/boot/compressed/misc.c
--- linux-2.4.15-pre3/arch/i386/boot/compressed/misc.c	Thu Oct  4 18:42:54 2001
+++ linux/arch/i386/boot/compressed/misc.c	Mon Dec  3 23:28:58 2001
@@ -9,6 +9,7 @@
  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  */
 
+#include <linux/linkage.h>
 #include <linux/vmalloc.h>
 #include <linux/tty.h>
 #include <asm/io.h>
@@ -304,7 +305,7 @@
 	short b;
 	} stack_start = { & user_stack [STACK_SIZE] , __KERNEL_DS };
 
-void setup_normal_output_buffer(void)
+static void setup_normal_output_buffer(void)
 {
 #ifdef STANDARD_MEMORY_BIOS_CALL
 	if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n");
@@ -320,7 +321,7 @@
 	uch *high_buffer_start; int hcount;
 };
 
-void setup_output_buffer_if_we_run_high(struct moveparams *mv)
+static void setup_output_buffer_if_we_run_high(struct moveparams *mv)
 {
 	high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
 #ifdef STANDARD_MEMORY_BIOS_CALL
@@ -342,7 +343,7 @@
 	mv->high_buffer_start = high_buffer_start;
 }
 
-void close_output_buffer_if_we_run_high(struct moveparams *mv)
+static void close_output_buffer_if_we_run_high(struct moveparams *mv)
 {
 	if (bytes_out > low_buffer_size) {
 		mv->lcount = low_buffer_size;
@@ -355,7 +356,7 @@
 }
 
 
-int decompress_kernel(struct moveparams *mv, void *rmode)
+asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode)
 {
 	real_mode = rmode;
 
diff -urN linux-2.4.15-pre3/arch/i386/defconfig linux/arch/i386/defconfig
--- linux-2.4.15-pre3/arch/i386/defconfig	Mon Dec  3 23:28:48 2001
+++ linux/arch/i386/defconfig	Mon Dec  3 23:28:58 2001
@@ -469,6 +469,7 @@
 # CONFIG_PCMCIA_NMCLAN is not set
 # CONFIG_PCMCIA_SMC91C92 is not set
 # CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_AXNET is not set
 # CONFIG_ARCNET_COM20020_CS is not set
 # CONFIG_PCMCIA_IBMTR is not set
 # CONFIG_PCMCIA_XIRCOM is not set
@@ -644,6 +645,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 # CONFIG_ROOT_NFS is not set
diff -urN linux-2.4.15-pre3/arch/i386/kernel/acpitable.c linux/arch/i386/kernel/acpitable.c
--- linux-2.4.15-pre3/arch/i386/kernel/acpitable.c	Mon Dec  3 23:28:48 2001
+++ linux/arch/i386/kernel/acpitable.c	Mon Dec  3 23:28:58 2001
@@ -25,6 +25,7 @@
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
+ * $Id: acpitable.c,v 1.7 2001/11/04 12:21:18 fenrus Exp $
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -40,244 +41,13 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
-#define SELF_CONTAINED_ACPI
-
-#ifdef SELF_CONTAINED_ACPI
-/*
- * The following codes are cut&pasted from drivers/acpi. Part of the code
- * there can be not updated or delivered yet.
- * To avoid conflicts when CONFIG_ACPI is defined, the following codes are
- * modified so that they are self-contained in this file.
- * -- jun
- */
-#define dprintk printk
-typedef unsigned int ACPI_TBLPTR;
-
-#define AE_CODE_ENVIRONMENTAL           0x0000
-#define AE_OK				(u32) 0x0000
-#define AE_ERROR			(u32) (0x0001 | AE_CODE_ENVIRONMENTAL)
-#define AE_NO_ACPI_TABLES		(u32) (0x0002 | AE_CODE_ENVIRONMENTAL)
-#define AE_NOT_FOUND                    (u32) (0x0005 | AE_CODE_ENVIRONMENTAL)
-
-typedef struct {		/* ACPI common table header */
-	char signature[4];	/* identifies type of table */
-	u32 length;		/* length of table,
-				   in bytes, * including header */
-	u8 revision;		/* specification minor version # */
-	u8 checksum;		/* to make sum of entire table == 0 */
-	char oem_id[6];		/* OEM identification */
-	char oem_table_id[8];	/* OEM table identification */
-	u32 oem_revision;	/* OEM revision number */
-	char asl_compiler_id[4];	/* ASL compiler vendor ID */
-	u32 asl_compiler_revision;	/* ASL compiler revision number */
-} acpi_table_header __attribute__ ((packed));;
-
-enum {
-	ACPI_APIC = 0,
-	ACPI_BOOT,
-	ACPI_DBGP,
-	ACPI_DSDT,
-	ACPI_ECDT,
-	ACPI_ETDT,
-	ACPI_FACP,
-	ACPI_FACS,
-	ACPI_OEMX,
-	ACPI_PSDT,
-	ACPI_SBST,
-	ACPI_SLIT,
-	ACPI_SPCR,
-	ACPI_SRAT,
-	ACPI_SSDT,
-	ACPI_SPMI,
-	ACPI_XSDT,
-	ACPI_TABLE_COUNT
-};
-
-static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
-	"APIC",
-	"BOOT",
-	"DBGP",
-	"DSDT",
-	"ECDT",
-	"ETDT",
-	"FACP",
-	"FACS",
-	"OEM",
-	"PSDT",
-	"SBST",
-	"SLIT",
-	"SPCR",
-	"SRAT",
-	"SSDT",
-	"SPMI",
-	"XSDT"
-};
-
-struct acpi_table_madt {
-	acpi_table_header header;
-	u32 lapic_address;
-	struct {
-		u32 pcat_compat:1;
-		u32 reserved:31;
-	} flags __attribute__ ((packed));
-} __attribute__ ((packed));;
-
-enum {
-	ACPI_MADT_LAPIC = 0,
-	ACPI_MADT_IOAPIC,
-	ACPI_MADT_INT_SRC_OVR,
-	ACPI_MADT_NMI_SRC,
-	ACPI_MADT_LAPIC_NMI,
-	ACPI_MADT_LAPIC_ADDR_OVR,
-	ACPI_MADT_IOSAPIC,
-	ACPI_MADT_LSAPIC,
-	ACPI_MADT_PLAT_INT_SRC,
-	ACPI_MADT_ENTRY_COUNT
-};
-
-#define RSDP_SIG			"RSD PTR "
-#define RSDT_SIG 			"RSDT"
-
-#define ACPI_DEBUG_PRINT(pl)
-
-#define ACPI_MEMORY_MODE                0x01
-#define ACPI_LOGICAL_ADDRESSING         0x00
-#define ACPI_PHYSICAL_ADDRESSING        0x01
-
-#define LO_RSDP_WINDOW_BASE         	0	/* Physical Address */
-#define HI_RSDP_WINDOW_BASE         	0xE0000	/* Physical Address */
-#define LO_RSDP_WINDOW_SIZE         	0x400
-#define HI_RSDP_WINDOW_SIZE         	0x20000
-#define RSDP_SCAN_STEP			16
-#define RSDP_CHECKSUM_LENGTH		20
-
-typedef int (*acpi_table_handler) (acpi_table_header * header, unsigned long);
+#include "acpitable.h"
 
 static acpi_table_handler acpi_boot_ops[ACPI_TABLE_COUNT];
 
-struct acpi_table_rsdp {
-	char signature[8];
-	u8 checksum;
-	char oem_id[6];
-	u8 revision;
-	u32 rsdt_address;
-} __attribute__ ((packed));
-
-struct acpi_table_rsdt {
-	acpi_table_header header;
-	u32 entry[ACPI_TABLE_COUNT];
-} __attribute__ ((packed));
-
-typedef struct {
-	u8 type;
-	u8 length;
-} acpi_madt_entry_header __attribute__ ((packed));
-
-typedef struct {
-	u16 polarity:2;
-	u16 trigger:2;
-	u16 reserved:12;
-} acpi_madt_int_flags __attribute__ ((packed));
-
-struct acpi_table_lapic {
-	acpi_madt_entry_header header;
-	u8 acpi_id;
-	u8 id;
-	struct {
-		u32 enabled:1;
-		u32 reserved:31;
-	} flags __attribute__ ((packed));
-} __attribute__ ((packed));
-
-struct acpi_table_ioapic {
-	acpi_madt_entry_header header;
-	u8 id;
-	u8 reserved;
-	u32 address;
-	u32 global_irq_base;
-} __attribute__ ((packed));
-
-struct acpi_table_int_src_ovr {
-	acpi_madt_entry_header header;
-	u8 bus;
-	u8 bus_irq;
-	u32 global_irq;
-	acpi_madt_int_flags flags;
-} __attribute__ ((packed));
-
-struct acpi_table_nmi_src {
-	acpi_madt_entry_header header;
-	acpi_madt_int_flags flags;
-	u32 global_irq;
-} __attribute__ ((packed));
-
-struct acpi_table_lapic_nmi {
-	acpi_madt_entry_header header;
-	u8 acpi_id;
-	acpi_madt_int_flags flags;
-	u8 lint;
-} __attribute__ ((packed));
-
-struct acpi_table_lapic_addr_ovr {
-	acpi_madt_entry_header header;
-	u8 reserved[2];
-	u64 address;
-} __attribute__ ((packed));
-
-struct acpi_table_iosapic {
-	acpi_madt_entry_header header;
-	u8 id;
-	u8 reserved;
-	u32 global_irq_base;
-	u64 address;
-} __attribute__ ((packed));
-
-struct acpi_table_lsapic {
-	acpi_madt_entry_header header;
-	u8 acpi_id;
-	u8 id;
-	u8 eid;
-	u8 reserved[3];
-	struct {
-		u32 enabled:1;
-		u32 reserved:31;
-	} flags;
-} __attribute__ ((packed));
-
-struct acpi_table_plat_int_src {
-	acpi_madt_entry_header header;
-	acpi_madt_int_flags flags;
-	u8 type;
-	u8 id;
-	u8 eid;
-	u8 iosapic_vector;
-	u32 global_irq;
-	u32 reserved;
-} __attribute__ ((packed));
-
-/*
- * ACPI Table Descriptor.  One per ACPI table
- */
-typedef struct acpi_table_desc {
-	struct acpi_table_desc *prev;
-	struct acpi_table_desc *next;
-	struct acpi_table_desc *installed_desc;
-	acpi_table_header *pointer;
-	void *base_pointer;
-	u8 *aml_pointer;
-	u64 physical_address;
-	u32 aml_length;
-	u32 length;
-	u32 count;
-	u16 table_id;
-	u8 type;
-	u8 allocation;
-	u8 loaded_into_namespace;
-
-} acpi_table_desc __attribute__ ((packed));;
 
 static unsigned char __init
-acpi_tb_checksum(void *buffer, int length)
+acpi_checksum(void *buffer, int length)
 {
 	int i;
 	unsigned char *bytebuffer;
@@ -294,24 +64,6 @@
 	return sum;
 }
 
-static int __init
-acpi_table_checksum(acpi_table_header * header)
-{
-	u8 *p = (u8 *) header;
-	int length = 0;
-	int sum = 0;
-
-	if (!header)
-		return -EINVAL;
-
-	length = header->length;
-
-	while (length--)
-		sum += *p++;
-
-	return sum & 0xFF;
-}
-
 static void __init
 acpi_print_table_header(acpi_table_header * header)
 {
@@ -328,19 +80,19 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    Acpi_tb_scan_memory_for_rsdp
+ * FUNCTION:    acpi_tb_scan_memory_for_rsdp
  *
- * PARAMETERS:  Start_address       - Starting pointer for search
- *              Length              - Maximum length to search
+ * PARAMETERS:  address       - Starting pointer for search
+ *              length        - Maximum length to search
  *
- * RETURN:      Pointer to the RSDP if found, otherwise NULL.
+ * RETURN:      Pointer to the RSDP if found and valid, otherwise NULL.
  *
  * DESCRIPTION: Search a block of memory for the RSDP signature
  *
  ******************************************************************************/
 
-static unsigned char *__init
-acpi_tb_scan_memory_for_rsdp(unsigned char *address, int length)
+static void *__init
+acpi_tb_scan_memory_for_rsdp(void *address, int length)
 {
 	u32 offset;
 
@@ -354,10 +106,9 @@
 	while (offset < length) {
 		/* The signature must match and the checksum must be correct */
 		if (strncmp(address, RSDP_SIG, sizeof(RSDP_SIG) - 1) == 0 &&
-		    acpi_tb_checksum(address, RSDP_CHECKSUM_LENGTH) == 0) {
+		    acpi_checksum(address, RSDP_CHECKSUM_LENGTH) == 0) {
 			/* If so, we have found the RSDP */
-			printk(KERN_INFO
-			       "ACPI: RSDP located at physical address %p\n",
+			printk(KERN_INFO "ACPI: RSDP located at physical address %p\n",
 			       address);
 			return address;
 		}
@@ -372,13 +123,11 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_find_rsdp
+ * FUNCTION:    acpi_find_root_pointer
  *
- * PARAMETERS:  *Table_info             - Where the table info is returned
- *              Flags                   - Current memory mode (logical vs.
- *                                        physical addressing)
+ * PARAMETERS:  none
  *
- * RETURN:      Status
+ * RETURN:      physical address of the RSDP 
  *
  * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
  *              pointer structure.  If it is found, set *RSDP to point to it.
@@ -389,80 +138,38 @@
  *
  ******************************************************************************/
 
-static int __init
-acpi_tb_find_rsdp(acpi_table_desc * table_info, u32 flags)
+static struct acpi_table_rsdp * __init
+acpi_find_root_pointer(void)
 {
-	unsigned char *address;
+	struct acpi_table_rsdp * rsdp;
 
 	/*
-	 * Physical address is given.
+	 * Physical address is given
 	 */
 	/*
 	 * Region 1) Search EBDA (low memory) paragraphs
 	 */
-	address =
-	    acpi_tb_scan_memory_for_rsdp(__va(LO_RSDP_WINDOW_BASE),
+	rsdp = acpi_tb_scan_memory_for_rsdp(__va(LO_RSDP_WINDOW_BASE),
 					 LO_RSDP_WINDOW_SIZE);
 
-	if (address) {
-		/* Found it, return the physical address */
-		table_info->physical_address = (ACPI_TBLPTR) __pa(address);
-		return AE_OK;
-	}
+	if (rsdp)
+		return rsdp;
 
 	/*
 	 * Region 2) Search upper memory: 16-byte boundaries in E0000h-F0000h
 	 */
-	address = acpi_tb_scan_memory_for_rsdp(__va(HI_RSDP_WINDOW_BASE),
+	rsdp = acpi_tb_scan_memory_for_rsdp(__va(HI_RSDP_WINDOW_BASE),
 					       HI_RSDP_WINDOW_SIZE);
-	if (address) {
-		/* Found it, return the physical address */
-		table_info->physical_address = (ACPI_TBLPTR) __pa(address);
-		return AE_OK;
-	}
 
-	/* RSDP signature was not found */
-	return AE_NOT_FOUND;
-}
-
-static unsigned long __init
-acpi_find_root_pointer(u32 flags)
-{
-	acpi_table_desc table_info;
-	int status;
-
-	/* Get the RSDP */
-
-	status = acpi_tb_find_rsdp(&table_info, flags);
-	if (status)
-		return 0;
+	
+					     
+	if (rsdp)
+		return rsdp;
 
-	return table_info.physical_address;
+	printk(KERN_ERR "ACPI: System description tables not found\n");
+	return NULL;
 }
 
-static unsigned long __init
-acpi_os_get_root_pointer(u32 flags)
-{
-	unsigned long address;
-
-#ifndef CONFIG_ACPI_EFI
-
-	address = acpi_find_root_pointer(flags);
-
-#else
-	if (efi.acpi20)
-		address = (unsigned long) efi.acpi20;
-	else if (efi.acpi)
-		address = (unsigned long) efi.acpi;
-	else
-		address = 0;
-#endif				/*CONFIG_ACPI_EFI */
-
-	if (address == 0)
-		printk(KERN_ERR "ACPI: System description tables not found\n");
-
-	return address;
-}
 
 /*
  * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_0,
@@ -506,29 +213,23 @@
 static int __init acpi_tables_init(void)
 {
 	int result = -ENODEV;
-	int status = AE_OK;
-	unsigned long rsdp_addr = 0;
 	acpi_table_header *header = NULL;
 	struct acpi_table_rsdp *rsdp = NULL;
-#ifndef CONFIG_IA64
 	struct acpi_table_rsdt *rsdt = NULL;
 	struct acpi_table_rsdt saved_rsdt;
-#else
-	struct acpi071_table_rsdt *rsdt = NULL;
-#endif
 	int tables = 0;
 	int type = 0;
 	int i = 0;
 
-	rsdp_addr = acpi_os_get_root_pointer(ACPI_PHYSICAL_ADDRESSING);
-
-	if (!rsdp_addr)
-		return -ENODEV;
 
-	rsdp = (struct acpi_table_rsdp *) rsdp_addr;
+	rsdp = (struct acpi_table_rsdp *) acpi_find_root_pointer();
 
+	if (!rsdp)
+		return -ENODEV;
+		
 	printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision,
 	       rsdp->oem_id);
+	       
 	if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) {
 		printk(KERN_WARNING "RSDP table signature incorrect\n");
 		return -EINVAL;
@@ -537,54 +238,53 @@
 	rsdt = (struct acpi_table_rsdt *)
 	    __va_range(rsdp->rsdt_address, sizeof(struct acpi_table_rsdt));
 
-	if (rsdt) {
-		header = (acpi_table_header *) & rsdt->header;
-		acpi_print_table_header(header);
-		if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) {
-			printk(KERN_WARNING "ACPI: RSDT signature incorrect\n");
-			rsdt = NULL;
-		} else {
-			/* 
-			 * The number of tables is computed by taking the 
-			 * size of all entries (header size minus total 
-			 * size of RSDT) divided by the size of each entry
-			 * (4-byte table pointers).
-			 */
-			tables =
-			    (header->length - sizeof(acpi_table_header)) / 4;
-		}
-	}
-
 	if (!rsdt) {
-		printk(KERN_WARNING
-		       "ACPI: Invalid root system description tables (RSDT)\n");
+		printk(KERN_WARNING "ACPI: Invalid root system description tables (RSDT)\n");
 		return -ENODEV;
 	}
-
+	
+	header = & rsdt->header;
+	acpi_print_table_header(header);
+	
+	if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) {
+		printk(KERN_WARNING "ACPI: RSDT signature incorrect\n");
+		return -ENODEV;
+	}
+		
+	/* 
+	 * The number of tables is computed by taking the 
+	 * size of all entries (header size minus total 
+	 * size of RSDT) divided by the size of each entry
+	 * (4-byte table pointers).
+	 */
+	tables = (header->length - sizeof(acpi_table_header)) / 4;
+		    
 	memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt));
 
 	if (saved_rsdt.header.length > sizeof(saved_rsdt)) {
-		printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n",
-		       saved_rsdt.header.length);
+		printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", saved_rsdt.header.length);
 		return -ENODEV;
 	}
 
 	for (i = 0; i < tables; i++) {
 
-		if (rsdt) {
-			header = (acpi_table_header *)
+		header = (acpi_table_header *)
 			    __va_range(saved_rsdt.entry[i],
 				       sizeof(acpi_table_header));
-		}
 
 		if (!header)
 			break;
 
 		acpi_print_table_header(header);
-
+		
+		if (acpi_checksum(header,header->length)) {
+			printk(KERN_WARNING "ACPI %s has invalid checksum\n", 
+				acpi_table_signatures[i]);
+			continue;
+		}
+		
 		for (type = 0; type < ACPI_TABLE_COUNT; type++)
-			if (!strncmp
-			    ((char *) &header->signature,
+			if (!strncmp((char *) &header->signature,
 			     acpi_table_signatures[type],strlen(acpi_table_signatures[type])))
 				break;
 
@@ -594,22 +294,17 @@
 			continue;
 		}
 
-		if (acpi_table_checksum(header)) {
-			printk(KERN_WARNING "ACPI %s has invalid checksum\n",
-			       acpi_table_signatures[i]);
-			continue;
-		}
 
-		if (acpi_boot_ops && acpi_boot_ops[type])
-			result =
-			    acpi_boot_ops[type] (header,
+		if (!acpi_boot_ops[type])
+			continue;
+			
+		result = acpi_boot_ops[type] (header,
 						 (unsigned long) saved_rsdt.
 						 entry[i]);
 	}
 
 	return result;
 }
-#endif				/* SELF_CONTAINED_ACPI */
 
 static int total_cpus __initdata = 0;
 int have_acpi_tables;
@@ -625,10 +320,10 @@
 	if (!local_apic)
 		return;
 
-	dprintk(KERN_INFO "LAPIC (acpi_id[0x%04x] id[0x%x] enabled[%d])\n",
+	printk(KERN_INFO "LAPIC (acpi_id[0x%04x] id[0x%x] enabled[%d])\n",
 		local_apic->acpi_id, local_apic->id, local_apic->flags.enabled);
 
-	dprintk("CPU %d (0x%02x00)", total_cpus, local_apic->id);
+	printk(KERN_INFO "CPU %d (0x%02x00)", total_cpus, local_apic->id);
 
 	if (local_apic->flags.enabled) {
 		printk(" enabled");
@@ -652,9 +347,9 @@
 			proc_entry.mpc_cpuflag |= CPU_BOOTPROCESSOR;
 		}
 		proc_entry.mpc_cpufeature =
-		    (boot_cpu_data.x86 << 8) | (boot_cpu_data.
-						x86_model << 4) | boot_cpu_data.
-		    x86_mask;
+		    (boot_cpu_data.x86 << 8) | 
+		    (boot_cpu_data.x86_model << 4) | 
+		     boot_cpu_data.x86_mask;
 		proc_entry.mpc_featureflag = boot_cpu_data.x86_capability[0];
 		proc_entry.mpc_reserved[0] = 0;
 		proc_entry.mpc_reserved[1] = 0;
@@ -684,18 +379,17 @@
 		printk(KERN_WARNING
 		       "Max # of I/O APICs (%d) exceeded (found %d).\n",
 		       MAX_IO_APICS, nr_ioapics);
-		panic("Recompile kernel with bigger MAX_IO_APICS!\n");
+/*		panic("Recompile kernel with bigger MAX_IO_APICS!\n");   */
 	}
 }
 
+
+/* Interrupt source overrides inform the machine about exceptions
+   to the normal "PIC" mode interrupt routing */
+   
 static void __init
 acpi_parse_int_src_ovr(struct acpi_table_int_src_ovr *intsrc)
 {
-	/*
-	   static int first_time_switch = 0;
-	   struct mpc_config_intsrc my_intsrc;
-	   int i;
-	 */
 	if (!intsrc)
 		return;
 
@@ -743,33 +437,6 @@
 
 }
 
-#ifdef CONFIG_IA64
-static void __init
-acpi_parse_iosapic(struct acpi_table_iosapic *iosapic)
-{
-	if (!iosapic)
-		return;
-
-	printk(KERN_INFO "IOSAPIC (id[%x] global_irq_base[%x] address[%lx])\n",
-	       iosapic->id, iosapic->global_irq_base,
-	       (unsigned long) iosapic->address);
-
-	return 0;
-}
-static void __init
-acpi_parse_lsapic(struct acpi_table_lsapic *lsapic)
-{
-	if (!lsapic)
-		return;
-
-	printk(KERN_INFO
-	       "LSAPIC (acpi_id[0x%04x] id[0x%x] eid[0x%x] enabled[%d])\n",
-	       lsapic->acpi_id, lsapic->id, lsapic->eid, lsapic->flags.enabled);
-
-	if (!lsapic->flags.enabled)
-		return;
-}
-#endif
 static void __init
 acpi_parse_plat_int_src(struct acpi_table_plat_int_src *plintsrc)
 {
@@ -786,10 +453,11 @@
 acpi_parse_madt(acpi_table_header * header, unsigned long phys)
 {
 
-	struct acpi_table_madt *madt =
-	    (struct acpi_table_madt *) __va_range(phys, header->length);
-	acpi_madt_entry_header *entry_header = NULL;
-	int table_size = 0;
+	struct acpi_table_madt *madt;	    
+	acpi_madt_entry_header *entry_header;
+	int table_size;
+	
+	madt = (struct acpi_table_madt *) __va_range(phys, header->length);
 
 	if (!madt)
 		return -EINVAL;
@@ -825,16 +493,6 @@
 						   acpi_table_lapic_addr_ovr *)
 						  entry_header);
 			break;
-#ifdef CONFIG_IA64
-		case ACPI_MADT_IOSAPIC:
-			acpi_parse_iosapic((struct acpi_table_iosapic *)
-					   entry_header);
-			break;
-		case ACPI_MADT_LSAPIC:
-			acpi_parse_lsapic((struct acpi_table_lsapic *)
-					  entry_header);
-			break;
-#endif
 		case ACPI_MADT_PLAT_INT_SRC:
 			acpi_parse_plat_int_src((struct acpi_table_plat_int_src
 						 *) entry_header);
@@ -877,20 +535,15 @@
 void __init
 config_acpi_tables(void)
 {
-	int result = 0;
+
+	memset(&acpi_boot_ops, 0, sizeof(acpi_boot_ops));
+	acpi_boot_ops[ACPI_APIC] = acpi_parse_madt;
 
 	/*
 	 * Only do this when requested, either because of CPU/Bios type or from the command line
 	 */
-	if (!enable_acpi_smp_table) {
-		return;
-	}
-
-	memset(&acpi_boot_ops, 0, sizeof(acpi_boot_ops));
-	acpi_boot_ops[ACPI_APIC] = acpi_parse_madt;
-	result = acpi_tables_init();
 
-	if (!result) {
+	if (enable_acpi_smp_table && !acpi_tables_init()) {
 		have_acpi_tables = 1;
 		printk("Enabling the CPU's according to the ACPI table\n");
 	}
diff -urN linux-2.4.15-pre3/arch/i386/kernel/acpitable.h linux/arch/i386/kernel/acpitable.h
--- linux-2.4.15-pre3/arch/i386/kernel/acpitable.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/kernel/acpitable.h	Mon Dec  3 23:28:58 2001
@@ -0,0 +1,260 @@
+/*
+ *  acpitable.c - IA32-specific ACPI boot-time initialization (Revision: 1)
+ *
+ *  Copyright (C) 1999 Andrew Henroid
+ *  Copyright (C) 2001 Richard Schaal
+ *  Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *  Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
+ *  Copyright (C) 2001 Arjan van de Ven <arjanv@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * $Id: acpitable.h,v 1.3 2001/11/03 22:41:34 fenrus Exp $
+ */
+
+/*
+ * The following codes are cut&pasted from drivers/acpi. Part of the code
+ * there can be not updated or delivered yet.
+ * To avoid conflicts when CONFIG_ACPI is defined, the following codes are
+ * modified so that they are self-contained in this file.
+ * -- jun
+ */
+ 
+#ifndef _HEADER_ACPITABLE_H_
+#define _HEADER_ACPITABLE_H_
+
+#define dprintk printk
+typedef unsigned int ACPI_TBLPTR;
+
+typedef struct {		/* ACPI common table header */
+	char signature[4];	/* identifies type of table */
+	u32 length;		/* length of table,
+				   in bytes, * including header */
+	u8 revision;		/* specification minor version # */
+	u8 checksum;		/* to make sum of entire table == 0 */
+	char oem_id[6];		/* OEM identification */
+	char oem_table_id[8];	/* OEM table identification */
+	u32 oem_revision;	/* OEM revision number */
+	char asl_compiler_id[4];	/* ASL compiler vendor ID */
+	u32 asl_compiler_revision;	/* ASL compiler revision number */
+} acpi_table_header __attribute__ ((packed));;
+
+enum {
+	ACPI_APIC = 0,
+	ACPI_BOOT,
+	ACPI_DBGP,
+	ACPI_DSDT,
+	ACPI_ECDT,
+	ACPI_ETDT,
+	ACPI_FACP,
+	ACPI_FACS,
+	ACPI_OEMX,
+	ACPI_PSDT,
+	ACPI_SBST,
+	ACPI_SLIT,
+	ACPI_SPCR,
+	ACPI_SRAT,
+	ACPI_SSDT,
+	ACPI_SPMI,
+	ACPI_XSDT,
+	ACPI_TABLE_COUNT
+};
+
+static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
+	"APIC",
+	"BOOT",
+	"DBGP",
+	"DSDT",
+	"ECDT",
+	"ETDT",
+	"FACP",
+	"FACS",
+	"OEM",
+	"PSDT",
+	"SBST",
+	"SLIT",
+	"SPCR",
+	"SRAT",
+	"SSDT",
+	"SPMI",
+	"XSDT"
+};
+
+struct acpi_table_madt {
+	acpi_table_header header;
+	u32 lapic_address;
+	struct {
+		u32 pcat_compat:1;
+		u32 reserved:31;
+	} flags __attribute__ ((packed));
+} __attribute__ ((packed));;
+
+enum {
+	ACPI_MADT_LAPIC = 0,
+	ACPI_MADT_IOAPIC,
+	ACPI_MADT_INT_SRC_OVR,
+	ACPI_MADT_NMI_SRC,
+	ACPI_MADT_LAPIC_NMI,
+	ACPI_MADT_LAPIC_ADDR_OVR,
+	ACPI_MADT_IOSAPIC,
+	ACPI_MADT_LSAPIC,
+	ACPI_MADT_PLAT_INT_SRC,
+	ACPI_MADT_ENTRY_COUNT
+};
+
+#define RSDP_SIG			"RSD PTR "
+#define RSDT_SIG 			"RSDT"
+
+#define ACPI_DEBUG_PRINT(pl)
+
+#define ACPI_MEMORY_MODE                0x01
+#define ACPI_LOGICAL_ADDRESSING         0x00
+#define ACPI_PHYSICAL_ADDRESSING        0x01
+
+#define LO_RSDP_WINDOW_BASE         	0	/* Physical Address */
+#define HI_RSDP_WINDOW_BASE         	0xE0000	/* Physical Address */
+#define LO_RSDP_WINDOW_SIZE         	0x400
+#define HI_RSDP_WINDOW_SIZE         	0x20000
+#define RSDP_SCAN_STEP			16
+#define RSDP_CHECKSUM_LENGTH		20
+
+typedef int (*acpi_table_handler) (acpi_table_header * header, unsigned long);
+
+struct acpi_table_rsdp {
+	char signature[8];
+	u8 checksum;
+	char oem_id[6];
+	u8 revision;
+	u32 rsdt_address;
+} __attribute__ ((packed));
+
+struct acpi_table_rsdt {
+	acpi_table_header header;
+	u32 entry[ACPI_TABLE_COUNT];
+} __attribute__ ((packed));
+
+typedef struct {
+	u8 type;
+	u8 length;
+} acpi_madt_entry_header __attribute__ ((packed));
+
+typedef struct {
+	u16 polarity:2;
+	u16 trigger:2;
+	u16 reserved:12;
+} acpi_madt_int_flags __attribute__ ((packed));
+
+struct acpi_table_lapic {
+	acpi_madt_entry_header header;
+	u8 acpi_id;
+	u8 id;
+	struct {
+		u32 enabled:1;
+		u32 reserved:31;
+	} flags __attribute__ ((packed));
+} __attribute__ ((packed));
+
+struct acpi_table_ioapic {
+	acpi_madt_entry_header header;
+	u8 id;
+	u8 reserved;
+	u32 address;
+	u32 global_irq_base;
+} __attribute__ ((packed));
+
+struct acpi_table_int_src_ovr {
+	acpi_madt_entry_header header;
+	u8 bus;
+	u8 bus_irq;
+	u32 global_irq;
+	acpi_madt_int_flags flags;
+} __attribute__ ((packed));
+
+struct acpi_table_nmi_src {
+	acpi_madt_entry_header header;
+	acpi_madt_int_flags flags;
+	u32 global_irq;
+} __attribute__ ((packed));
+
+struct acpi_table_lapic_nmi {
+	acpi_madt_entry_header header;
+	u8 acpi_id;
+	acpi_madt_int_flags flags;
+	u8 lint;
+} __attribute__ ((packed));
+
+struct acpi_table_lapic_addr_ovr {
+	acpi_madt_entry_header header;
+	u8 reserved[2];
+	u64 address;
+} __attribute__ ((packed));
+
+struct acpi_table_iosapic {
+	acpi_madt_entry_header header;
+	u8 id;
+	u8 reserved;
+	u32 global_irq_base;
+	u64 address;
+} __attribute__ ((packed));
+
+struct acpi_table_lsapic {
+	acpi_madt_entry_header header;
+	u8 acpi_id;
+	u8 id;
+	u8 eid;
+	u8 reserved[3];
+	struct {
+		u32 enabled:1;
+		u32 reserved:31;
+	} flags;
+} __attribute__ ((packed));
+
+struct acpi_table_plat_int_src {
+	acpi_madt_entry_header header;
+	acpi_madt_int_flags flags;
+	u8 type;
+	u8 id;
+	u8 eid;
+	u8 iosapic_vector;
+	u32 global_irq;
+	u32 reserved;
+} __attribute__ ((packed));
+
+/*
+ * ACPI Table Descriptor.  One per ACPI table
+ */
+typedef struct acpi_table_desc {
+	struct acpi_table_desc *prev;
+	struct acpi_table_desc *next;
+	struct acpi_table_desc *installed_desc;
+	acpi_table_header *pointer;
+	void *base_pointer;
+	u8 *aml_pointer;
+	u64 physical_address;
+	u32 aml_length;
+	u32 length;
+	u32 count;
+	u16 table_id;
+	u8 type;
+	u8 allocation;
+	u8 loaded_into_namespace;
+
+} acpi_table_desc __attribute__ ((packed));;
+
+#endif
diff -urN linux-2.4.15-pre3/arch/i386/kernel/bluesmoke.c linux/arch/i386/kernel/bluesmoke.c
--- linux-2.4.15-pre3/arch/i386/kernel/bluesmoke.c	Thu Oct 11 09:04:57 2001
+++ linux/arch/i386/kernel/bluesmoke.c	Mon Dec  3 23:28:58 2001
@@ -100,11 +100,11 @@
 
 /*
  *	Call the installed machine check handler for this CPU setup.
- */ 
- 
+ */
+
 static void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
 
-void do_machine_check(struct pt_regs * regs, long error_code)
+asmlinkage void do_machine_check(struct pt_regs * regs, long error_code)
 {
 	machine_check_vector(regs, error_code);
 }
diff -urN linux-2.4.15-pre3/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- linux-2.4.15-pre3/arch/i386/kernel/setup.c	Mon Dec  3 23:28:48 2001
+++ linux/arch/i386/kernel/setup.c	Mon Dec  3 23:28:58 2001
@@ -98,6 +98,7 @@
 #endif
 #include <linux/highmem.h>
 #include <linux/bootmem.h>
+#include <linux/seq_file.h>
 #include <asm/processor.h>
 #include <linux/console.h>
 #include <asm/mtrr.h>
@@ -2686,11 +2687,8 @@
 /*
  *	Get CPU information for use by the procfs.
  */
-
-int get_cpuinfo(char * buffer)
+static int show_cpuinfo(struct seq_file *m, void *v)
 {
-	char *p = buffer;
-
 	/* 
 	 * These flag bits must match the definitions in <asm/cpufeature.h>.
 	 * NULL means this bit is undefined or reserved; either way it doesn't
@@ -2724,75 +2722,88 @@
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 	};
-	struct cpuinfo_x86 *c = cpu_data;
-	int i, n;
+	struct cpuinfo_x86 *c = v;
+	int i, n = c - cpu_data;
+	int fpu_exception;
 
-	for (n = 0; n < NR_CPUS; n++, c++) {
-		int fpu_exception;
 #ifdef CONFIG_SMP
-		if (!(cpu_online_map & (1<<n)))
-			continue;
+	if (!(cpu_online_map & (1<<n)))
+		return 0;
 #endif
-		/* Stupid hack */
-		if (p - buffer > (3*PAGE_SIZE)/4)
-			break;
+	seq_printf(m, "processor\t: %d\n"
+		"vendor_id\t: %s\n"
+		"cpu family\t: %d\n"
+		"model\t\t: %d\n"
+		"model name\t: %s\n",
+		n,
+		c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
+		c->x86,
+		c->x86_model,
+		c->x86_model_id[0] ? c->x86_model_id : "unknown");
 
-		p += sprintf(p,"processor\t: %d\n"
-			"vendor_id\t: %s\n"
-			"cpu family\t: %d\n"
-			"model\t\t: %d\n"
-			"model name\t: %s\n",
-			n,
-			c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
-			c->x86,
-			c->x86_model,
-			c->x86_model_id[0] ? c->x86_model_id : "unknown");
+	if (c->x86_mask || c->cpuid_level >= 0)
+		seq_printf(m, "stepping\t: %d\n", c->x86_mask);
+	else
+		seq_printf(m, "stepping\t: unknown\n");
 
-		if (c->x86_mask || c->cpuid_level >= 0)
-			p += sprintf(p, "stepping\t: %d\n", c->x86_mask);
-		else
-			p += sprintf(p, "stepping\t: unknown\n");
+	if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) {
+		seq_printf(m, "cpu MHz\t\t: %lu.%03lu\n",
+			cpu_khz / 1000, (cpu_khz % 1000));
+	}
 
-		if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) {
-			p += sprintf(p, "cpu MHz\t\t: %lu.%03lu\n",
-				cpu_khz / 1000, (cpu_khz % 1000));
-		}
+	/* Cache size */
+	if (c->x86_cache_size >= 0)
+		seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
+	
+	/* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */
+	fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu);
+	seq_printf(m, "fdiv_bug\t: %s\n"
+			"hlt_bug\t\t: %s\n"
+			"f00f_bug\t: %s\n"
+			"coma_bug\t: %s\n"
+			"fpu\t\t: %s\n"
+			"fpu_exception\t: %s\n"
+			"cpuid level\t: %d\n"
+			"wp\t\t: %s\n"
+			"flags\t\t:",
+		     c->fdiv_bug ? "yes" : "no",
+		     c->hlt_works_ok ? "no" : "yes",
+		     c->f00f_bug ? "yes" : "no",
+		     c->coma_bug ? "yes" : "no",
+		     c->hard_math ? "yes" : "no",
+		     fpu_exception ? "yes" : "no",
+		     c->cpuid_level,
+		     c->wp_works_ok ? "yes" : "no");
+
+	for ( i = 0 ; i < 32*NCAPINTS ; i++ )
+		if ( test_bit(i, &c->x86_capability) &&
+		     x86_cap_flags[i] != NULL )
+			seq_printf(m, " %s", x86_cap_flags[i]);
+
+	seq_printf(m, "\nbogomips\t: %lu.%02lu\n\n",
+		     c->loops_per_jiffy/(500000/HZ),
+		     (c->loops_per_jiffy/(5000/HZ)) % 100);
+	return 0;
+}
 
-		/* Cache size */
-		if (c->x86_cache_size >= 0)
-			p += sprintf(p, "cache size\t: %d KB\n", c->x86_cache_size);
-		
-		/* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */
-		fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu);
-		p += sprintf(p, "fdiv_bug\t: %s\n"
-			        "hlt_bug\t\t: %s\n"
-			        "f00f_bug\t: %s\n"
-			        "coma_bug\t: %s\n"
-			        "fpu\t\t: %s\n"
-			        "fpu_exception\t: %s\n"
-			        "cpuid level\t: %d\n"
-			        "wp\t\t: %s\n"
-			        "flags\t\t:",
-			     c->fdiv_bug ? "yes" : "no",
-			     c->hlt_works_ok ? "no" : "yes",
-			     c->f00f_bug ? "yes" : "no",
-			     c->coma_bug ? "yes" : "no",
-			     c->hard_math ? "yes" : "no",
-			     fpu_exception ? "yes" : "no",
-			     c->cpuid_level,
-			     c->wp_works_ok ? "yes" : "no");
-
-		for ( i = 0 ; i < 32*NCAPINTS ; i++ )
-			if ( test_bit(i, &c->x86_capability) &&
-			     x86_cap_flags[i] != NULL )
-				p += sprintf(p, " %s", x86_cap_flags[i]);
-
-		p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n",
-			     c->loops_per_jiffy/(500000/HZ),
-			     (c->loops_per_jiffy/(5000/HZ)) % 100);
-	}
-	return p - buffer;
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos < NR_CPUS ? &cpu_data[*pos] : NULL;
 }
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return c_start(m, pos);
+}
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+struct seq_operations cpuinfo_op = {
+	start:	c_start,
+	next:	c_next,
+	stop:	c_stop,
+	show:	show_cpuinfo,
+};
 
 unsigned long cpu_initialized __initdata = 0;
 
diff -urN linux-2.4.15-pre3/arch/i386/math-emu/fpu_proto.h linux/arch/i386/math-emu/fpu_proto.h
--- linux-2.4.15-pre3/arch/i386/math-emu/fpu_proto.h	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/fpu_proto.h	Mon Dec  3 23:28:58 2001
@@ -53,7 +53,7 @@
 extern void fst_i_(void);
 extern void fstp_i(void);
 /* fpu_entry.c */
-extern void math_emulate(long arg);
+asmlinkage extern void math_emulate(long arg);
 extern void math_abort(struct info *info, unsigned int signal);
 /* fpu_etc.c */
 extern void FPU_etc(void);
diff -urN linux-2.4.15-pre3/drivers/char/Config.in linux/drivers/char/Config.in
--- linux-2.4.15-pre3/drivers/char/Config.in	Thu Oct 25 14:01:51 2001
+++ linux/drivers/char/Config.in	Mon Dec  3 23:28:58 2001
@@ -16,6 +16,9 @@
       tristate '   Dual serial port support' CONFIG_DUALSP_SERIAL
    fi
 fi
+if [ "$CONFIG_ACPI" = "y" ]; then
+   bool '  Support for serial ports defined by ACPI tables' CONFIG_SERIAL_ACPI
+fi
 dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL
 if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
    bool '  Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
@@ -155,17 +158,18 @@
    tristate '  Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
    tristate '  Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
    tristate '  Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT
-   tristate '  IB700 SBC Watchdog Timer' CONFIG_IB700_WDT
-   tristate '  SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
-   tristate '  W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT
-   tristate '  Mixcom Watchdog' CONFIG_MIXCOMWD 
-   tristate '  Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO
    if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
       tristate '  DC21285 watchdog' CONFIG_21285_WATCHDOG
       if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
          tristate '  NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG
       fi
    fi
+   tristate '  Eurotech CPU-1220/1410 Watchdog Timer' CONFIG_EUROTECH_WDT
+   tristate '  IB700 SBC Watchdog Timer' CONFIG_IB700_WDT
+   tristate '  Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO
+   tristate '  Mixcom Watchdog' CONFIG_MIXCOMWD 
+   tristate '  SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
+   tristate '  W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT
    tristate '  ZF MachZ Watchdog' CONFIG_MACHZ_WDT
 fi
 endmenu
diff -urN linux-2.4.15-pre3/drivers/isdn/isdnloop/isdnloop.c linux/drivers/isdn/isdnloop/isdnloop.c
--- linux-2.4.15-pre3/drivers/isdn/isdnloop/isdnloop.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/isdnloop/isdnloop.c	Mon Dec  3 23:28:58 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.c,v 1.11.6.6 2001/09/23 22:24:56 kai Exp $
+/* $Id: isdnloop.c,v 1.11.6.7 2001/11/11 19:54:31 kai Exp $
  *
  * ISDN low-level module implementing a dummy loop driver.
  *
@@ -14,7 +14,7 @@
 #include <linux/init.h>
 #include "isdnloop.h"
 
-static char *revision = "$Revision: 1.11.6.6 $";
+static char *revision = "$Revision: 1.11.6.7 $";
 static char *isdnloop_id;
 
 MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card");
@@ -1542,7 +1542,11 @@
 	} else
 		strcpy(rev, " ??? ");
 	printk(KERN_NOTICE "isdnloop-ISDN-driver Rev%s\n", rev);
-	return (isdnloop_addcard(isdnloop_id));
+
+	if (isdnloop_id)
+		return (isdnloop_addcard(isdnloop_id));
+
+	return 0;
 }
 
 static void __exit
diff -urN linux-2.4.15-pre3/drivers/md/lvm-snap.c linux/drivers/md/lvm-snap.c
--- linux-2.4.15-pre3/drivers/md/lvm-snap.c	Mon Dec  3 23:28:48 2001
+++ linux/drivers/md/lvm-snap.c	Mon Dec  3 23:28:58 2001
@@ -500,10 +500,9 @@
 int lvm_snapshot_alloc(lv_t * lv_snap)
 {
 	int ret, max_sectors;
-	int nbhs = KIO_MAX_SECTORS;
 
 	/* allocate kiovec to do chunk io */
-	ret = alloc_kiovec_sz(1, &lv_snap->lv_iobuf, &nbhs);
+	ret = alloc_kiovec(1, &lv_snap->lv_iobuf);
 	if (ret) goto out;
 
 	max_sectors = KIO_MAX_SECTORS << (PAGE_SHIFT-9);
@@ -512,7 +511,7 @@
 	if (ret) goto out_free_kiovec;
 
 	/* allocate kiovec to do exception table io */
-	ret = alloc_kiovec_sz(1, &lv_snap->lv_COW_table_iobuf, &nbhs);
+	ret = alloc_kiovec(1, &lv_snap->lv_COW_table_iobuf);
 	if (ret) goto out_free_kiovec;
 
 	ret = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_COW_table_iobuf,
@@ -528,12 +527,12 @@
 
 out_free_both_kiovecs:
 	unmap_kiobuf(lv_snap->lv_COW_table_iobuf);
-	free_kiovec_sz(1, &lv_snap->lv_COW_table_iobuf, &nbhs);
+	free_kiovec(1, &lv_snap->lv_COW_table_iobuf);
 	lv_snap->lv_COW_table_iobuf = NULL;
 
 out_free_kiovec:
 	unmap_kiobuf(lv_snap->lv_iobuf);
-	free_kiovec_sz(1, &lv_snap->lv_iobuf, &nbhs);
+	free_kiovec(1, &lv_snap->lv_iobuf);
 	lv_snap->lv_iobuf = NULL;
 	if (lv_snap->lv_snapshot_hash_table != NULL)
 		vfree(lv_snap->lv_snapshot_hash_table);
@@ -560,14 +559,14 @@
 	{
 	        kiobuf_wait_for_io(lv->lv_iobuf);
 		unmap_kiobuf(lv->lv_iobuf);
-		free_kiovec_sz(1, &lv->lv_iobuf, &nbhs);
+		free_kiovec(1, &lv->lv_iobuf);
 		lv->lv_iobuf = NULL;
 	}
 	if (lv->lv_COW_table_iobuf)
 	{
                kiobuf_wait_for_io(lv->lv_COW_table_iobuf);
                unmap_kiobuf(lv->lv_COW_table_iobuf);
-               free_kiovec_sz(1, &lv->lv_COW_table_iobuf, &nbhs);
+               free_kiovec(1, &lv->lv_COW_table_iobuf);
                lv->lv_COW_table_iobuf = NULL;
 	}
 }
diff -urN linux-2.4.15-pre3/drivers/md/multipath.c linux/drivers/md/multipath.c
--- linux-2.4.15-pre3/drivers/md/multipath.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/md/multipath.c	Mon Dec  3 23:28:58 2001
@@ -7,10 +7,7 @@
  *
  * MULTIPATH management functions.
  *
- * Better read-balancing code written by Mika Kuoppala <miku@iki.fi>, 2000
- *
- * Fixes to reconstruction by Jakob Østergaard" <jakob@ostenfeld.dk>
- * Various fixes by Neil Brown <neilb@cse.unsw.edu.au>
+ * derived from raid1.c.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -33,6 +30,9 @@
 
 #define MAX_WORK_PER_DISK 128
 
+#define	NR_RESERVED_BUFS	32
+
+
 /*
  * The following can be used to debug the driver
  */
@@ -53,147 +53,55 @@
 
 static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state);
 
-struct buffer_head *multipath_alloc_bh(multipath_conf_t *conf, int cnt)
-{
-	/* return a linked list of "cnt" struct buffer_heads.
-	 * don't take any off the free list unless we know we can
-	 * get all we need, otherwise we could deadlock
-	 */
-	struct buffer_head *bh=NULL;
-
-	while(cnt) {
-		struct buffer_head *t;
-		md_spin_lock_irq(&conf->device_lock);
-		if (conf->freebh_cnt >= cnt)
-			while (cnt) {
-				t = conf->freebh;
-				conf->freebh = t->b_next;
-				t->b_next = bh;
-				bh = t;
-				t->b_state = 0;
-				conf->freebh_cnt--;
-				cnt--;
-			}
-		md_spin_unlock_irq(&conf->device_lock);
-		if (cnt == 0)
-			break;
-		t = (struct buffer_head *)kmalloc(sizeof(struct buffer_head), GFP_NOIO);
-		if (t) {
-			memset(t, 0, sizeof(*t));
-			t->b_next = bh;
-			bh = t;
-			cnt--;
-		} else {
-			PRINTK("waiting for %d bh\n", cnt);
-			wait_event(conf->wait_buffer, conf->freebh_cnt >= cnt);
-		}
-	}
-	return bh;
-}
-
-static inline void multipath_free_bh(multipath_conf_t *conf, struct buffer_head *bh)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&conf->device_lock, flags);
-	while (bh) {
-		struct buffer_head *t = bh;
-		bh=bh->b_next;
-		if (t->b_pprev == NULL)
-			kfree(t);
-		else {
-			t->b_next= conf->freebh;
-			conf->freebh = t;
-			conf->freebh_cnt++;
-		}
-	}
-	spin_unlock_irqrestore(&conf->device_lock, flags);
-	wake_up(&conf->wait_buffer);
-}
-
-static int multipath_grow_bh(multipath_conf_t *conf, int cnt)
-{
-	/* allocate cnt buffer_heads, possibly less if kalloc fails */
-	int i = 0;
-
-	while (i < cnt) {
-		struct buffer_head *bh;
-		bh = kmalloc(sizeof(*bh), GFP_KERNEL);
-		if (!bh) break;
-		memset(bh, 0, sizeof(*bh));
-
-		md_spin_lock_irq(&conf->device_lock);
-		bh->b_pprev = &conf->freebh;
-		bh->b_next = conf->freebh;
-		conf->freebh = bh;
-		conf->freebh_cnt++;
-		md_spin_unlock_irq(&conf->device_lock);
-
-		i++;
-	}
-	return i;
-}
-
-static int multipath_shrink_bh(multipath_conf_t *conf, int cnt)
-{
-	/* discard cnt buffer_heads, if we can find them */
-	int i = 0;
 
-	md_spin_lock_irq(&conf->device_lock);
-	while ((i < cnt) && conf->freebh) {
-		struct buffer_head *bh = conf->freebh;
-		conf->freebh = bh->b_next;
-		kfree(bh);
-		i++;
-		conf->freebh_cnt--;
-	}
-	md_spin_unlock_irq(&conf->device_lock);
-	return i;
-}
-		
 
 static struct multipath_bh *multipath_alloc_mpbh(multipath_conf_t *conf)
 {
-	struct multipath_bh *r1_bh = NULL;
+	struct multipath_bh *mp_bh = NULL;
 
 	do {
 		md_spin_lock_irq(&conf->device_lock);
-		if (conf->freer1) {
-			r1_bh = conf->freer1;
-			conf->freer1 = r1_bh->next_r1;
-			r1_bh->next_r1 = NULL;
-			r1_bh->state = 0;
-			r1_bh->bh_req.b_state = 0;
+		if (!conf->freer1_blocked && conf->freer1) {
+			mp_bh = conf->freer1;
+			conf->freer1 = mp_bh->next_mp;
+			conf->freer1_cnt--;
+			mp_bh->next_mp = NULL;
+			mp_bh->state = (1 << MPBH_PreAlloc);
+			mp_bh->bh_req.b_state = 0;
 		}
 		md_spin_unlock_irq(&conf->device_lock);
-		if (r1_bh)
-			return r1_bh;
-		r1_bh = (struct multipath_bh *) kmalloc(sizeof(struct multipath_bh),
+		if (mp_bh)
+			return mp_bh;
+		mp_bh = (struct multipath_bh *) kmalloc(sizeof(struct multipath_bh),
 					GFP_NOIO);
-		if (r1_bh) {
-			memset(r1_bh, 0, sizeof(*r1_bh));
-			return r1_bh;
-		}
-		wait_event(conf->wait_buffer, conf->freer1);
+		if (mp_bh) {
+			memset(mp_bh, 0, sizeof(*mp_bh));
+			return mp_bh;
+		}
+		conf->freer1_blocked = 1;
+		wait_disk_event(conf->wait_buffer,
+				!conf->freer1_blocked ||
+				conf->freer1_cnt > NR_RESERVED_BUFS/2
+		    );
+		conf->freer1_blocked = 0;
 	} while (1);
 }
 
-static inline void multipath_free_mpbh(struct multipath_bh *r1_bh)
+static inline void multipath_free_mpbh(struct multipath_bh *mp_bh)
 {
-	struct buffer_head *bh = r1_bh->multipath_bh_list;
-	multipath_conf_t *conf = mddev_to_conf(r1_bh->mddev);
-
-	r1_bh->multipath_bh_list = NULL;
+	multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev);
 
-	if (test_bit(MPBH_PreAlloc, &r1_bh->state)) {
+	if (test_bit(MPBH_PreAlloc, &mp_bh->state)) {
 		unsigned long flags;
 		spin_lock_irqsave(&conf->device_lock, flags);
-		r1_bh->next_r1 = conf->freer1;
-		conf->freer1 = r1_bh;
+		mp_bh->next_mp = conf->freer1;
+		conf->freer1 = mp_bh;
+		conf->freer1_cnt++;
 		spin_unlock_irqrestore(&conf->device_lock, flags);
+		wake_up(&conf->wait_buffer);
 	} else {
-		kfree(r1_bh);
+		kfree(mp_bh);
 	}
-	multipath_free_bh(conf, bh);
 }
 
 static int multipath_grow_mpbh (multipath_conf_t *conf, int cnt)
@@ -201,18 +109,15 @@
 	int i = 0;
 
 	while (i < cnt) {
-		struct multipath_bh *r1_bh;
-		r1_bh = (struct multipath_bh*)kmalloc(sizeof(*r1_bh), GFP_KERNEL);
-		if (!r1_bh)
+		struct multipath_bh *mp_bh;
+		mp_bh = (struct multipath_bh*)kmalloc(sizeof(*mp_bh), GFP_KERNEL);
+		if (!mp_bh)
 			break;
-		memset(r1_bh, 0, sizeof(*r1_bh));
-
-		md_spin_lock_irq(&conf->device_lock);
-		set_bit(MPBH_PreAlloc, &r1_bh->state);
-		r1_bh->next_r1 = conf->freer1;
-		conf->freer1 = r1_bh;
-		md_spin_unlock_irq(&conf->device_lock);
+		memset(mp_bh, 0, sizeof(*mp_bh));
+		set_bit(MPBH_PreAlloc, &mp_bh->state);
+		mp_bh->mddev = conf->mddev;	       
 
+		multipath_free_mpbh(mp_bh);
 		i++;
 	}
 	return i;
@@ -222,29 +127,15 @@
 {
 	md_spin_lock_irq(&conf->device_lock);
 	while (conf->freer1) {
-		struct multipath_bh *r1_bh = conf->freer1;
-		conf->freer1 = r1_bh->next_r1;
-		kfree(r1_bh);
+		struct multipath_bh *mp_bh = conf->freer1;
+		conf->freer1 = mp_bh->next_mp;
+		conf->freer1_cnt--;
+		kfree(mp_bh);
 	}
 	md_spin_unlock_irq(&conf->device_lock);
 }
 
 
-
-static inline void multipath_free_buf(struct multipath_bh *r1_bh)
-{
-	unsigned long flags;
-	struct buffer_head *bh = r1_bh->multipath_bh_list;
-	multipath_conf_t *conf = mddev_to_conf(r1_bh->mddev);
-	r1_bh->multipath_bh_list = NULL;
-	
-	spin_lock_irqsave(&conf->device_lock, flags);
-	r1_bh->next_r1 = conf->freebuf;
-	conf->freebuf = r1_bh;
-	spin_unlock_irqrestore(&conf->device_lock, flags);
-	multipath_free_bh(conf, bh);
-}
-
 static int multipath_map (mddev_t *mddev, kdev_t *rdev)
 {
 	multipath_conf_t *conf = mddev_to_conf(mddev);
@@ -266,77 +157,45 @@
 	return (-1);
 }
 
-static void multipath_reschedule_retry (struct multipath_bh *r1_bh)
+static void multipath_reschedule_retry (struct multipath_bh *mp_bh)
 {
 	unsigned long flags;
-	mddev_t *mddev = r1_bh->mddev;
+	mddev_t *mddev = mp_bh->mddev;
 	multipath_conf_t *conf = mddev_to_conf(mddev);
 
 	md_spin_lock_irqsave(&retry_list_lock, flags);
 	if (multipath_retry_list == NULL)
 		multipath_retry_tail = &multipath_retry_list;
-	*multipath_retry_tail = r1_bh;
-	multipath_retry_tail = &r1_bh->next_r1;
-	r1_bh->next_r1 = NULL;
+	*multipath_retry_tail = mp_bh;
+	multipath_retry_tail = &mp_bh->next_mp;
+	mp_bh->next_mp = NULL;
 	md_spin_unlock_irqrestore(&retry_list_lock, flags);
 	md_wakeup_thread(conf->thread);
 }
 
 
-static void inline io_request_done(unsigned long sector, multipath_conf_t *conf, int phase)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&conf->segment_lock, flags);
-	if (sector < conf->start_active)
-		conf->cnt_done--;
-	else if (sector >= conf->start_future && conf->phase == phase)
-		conf->cnt_future--;
-	else if (!--conf->cnt_pending)
-		wake_up(&conf->wait_ready);
-
-	spin_unlock_irqrestore(&conf->segment_lock, flags);
-}
-
-static void inline sync_request_done (unsigned long sector, multipath_conf_t *conf)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&conf->segment_lock, flags);
-	if (sector >= conf->start_ready)
-		--conf->cnt_ready;
-	else if (sector >= conf->start_active) {
-		if (!--conf->cnt_active) {
-			conf->start_active = conf->start_ready;
-			wake_up(&conf->wait_done);
-		}
-	}
-	spin_unlock_irqrestore(&conf->segment_lock, flags);
-}
-
 /*
  * multipath_end_bh_io() is called when we have finished servicing a multipathed
  * operation and are ready to return a success/failure code to the buffer
  * cache layer.
  */
-static void multipath_end_bh_io (struct multipath_bh *r1_bh, int uptodate)
+static void multipath_end_bh_io (struct multipath_bh *mp_bh, int uptodate)
 {
-	struct buffer_head *bh = r1_bh->master_bh;
-
-	io_request_done(bh->b_rsector, mddev_to_conf(r1_bh->mddev),
-			test_bit(MPBH_SyncPhase, &r1_bh->state));
+	struct buffer_head *bh = mp_bh->master_bh;
 
 	bh->b_end_io(bh, uptodate);
-	multipath_free_mpbh(r1_bh);
+	multipath_free_mpbh(mp_bh);
 }
 
 void multipath_end_request (struct buffer_head *bh, int uptodate)
 {
-	struct multipath_bh * r1_bh = (struct multipath_bh *)(bh->b_private);
+	struct multipath_bh * mp_bh = (struct multipath_bh *)(bh->b_private);
 
 	/*
 	 * this branch is our 'one multipath IO has finished' event handler:
 	 */
 	if (!uptodate)
-		md_error (r1_bh->mddev, bh->b_dev);
+		md_error (mp_bh->mddev, bh->b_dev);
 	else
 		/*
 		 * Set MPBH_Uptodate in our master buffer_head, so that
@@ -347,11 +206,11 @@
 		 * user-side. So if something waits for IO, then it will
 		 * wait for the 'master' buffer_head.
 		 */
-		set_bit (MPBH_Uptodate, &r1_bh->state);
+		set_bit (MPBH_Uptodate, &mp_bh->state);
 
 		
 	if (uptodate) {
-		multipath_end_bh_io(r1_bh, uptodate);
+		multipath_end_bh_io(mp_bh, uptodate);
 		return;
 	}
 	/*
@@ -359,20 +218,13 @@
 	 */
 	printk(KERN_ERR "multipath: %s: rescheduling block %lu\n", 
 		 partition_name(bh->b_dev), bh->b_blocknr);
-	multipath_reschedule_retry(r1_bh);
+	multipath_reschedule_retry(mp_bh);
 	return;
 }
 
 /*
  * This routine returns the disk from which the requested read should
- * be done. It bookkeeps the last read position for every disk
- * in array and when new read requests come, the disk which last
- * position is nearest to the request, is chosen.
- *
- * TODO: now if there are 2 multipaths in the same 2 devices, performance
- * degrades dramatically because position is multipath, not device based.
- * This should be changed to be device based. Also atomic sequential
- * reads should be somehow balanced.
+ * be done.
  */
 
 static int multipath_read_balance (multipath_conf_t *conf)
@@ -391,7 +243,7 @@
 {
 	multipath_conf_t *conf = mddev_to_conf(mddev);
 	struct buffer_head *bh_req;
-	struct multipath_bh * r1_bh;
+	struct multipath_bh * mp_bh;
 	struct multipath_info *multipath;
 
 	if (!buffer_locked(bh))
@@ -406,45 +258,25 @@
 	if (rw == READA)
 		rw = READ;
 
-	r1_bh = multipath_alloc_mpbh (conf);
-
-	spin_lock_irq(&conf->segment_lock);
-	wait_event_lock_irq(conf->wait_done,
-			bh->b_rsector < conf->start_active ||
-			bh->b_rsector >= conf->start_future,
-			conf->segment_lock);
-	if (bh->b_rsector < conf->start_active) 
-		conf->cnt_done++;
-	else {
-		conf->cnt_future++;
-		if (conf->phase)
-			set_bit(MPBH_SyncPhase, &r1_bh->state);
-	}
-	spin_unlock_irq(&conf->segment_lock);
-	
-	/*
-	 * i think the read and write branch should be separated completely,
-	 * since we want to do read balancing on the read side for example.
-	 * Alternative implementations? :) --mingo
-	 */
+	mp_bh = multipath_alloc_mpbh (conf);
 
-	r1_bh->master_bh = bh;
-	r1_bh->mddev = mddev;
-	r1_bh->cmd = rw;
+	mp_bh->master_bh = bh;
+	mp_bh->mddev = mddev;
+	mp_bh->cmd = rw;
 
 	/*
 	 * read balancing logic:
 	 */
 	multipath = conf->multipaths + multipath_read_balance(conf);
 
-	bh_req = &r1_bh->bh_req;
+	bh_req = &mp_bh->bh_req;
 	memcpy(bh_req, bh, sizeof(*bh));
 	bh_req->b_blocknr = bh->b_rsector;
 	bh_req->b_dev = multipath->dev;
 	bh_req->b_rdev = multipath->dev;
 /*	bh_req->b_rsector = bh->n_rsector; */
 	bh_req->b_end_io = multipath_end_request;
-	bh_req->b_private = r1_bh;
+	bh_req->b_private = mp_bh;
 	generic_make_request (rw, bh_req);
 	return 0;
 }
@@ -540,12 +372,10 @@
 			mdp_disk_t *spare;
 			mdp_super_t *sb = mddev->sb;
 
-//			MD_BUG();
 			spare = get_spare(mddev);
 			if (spare) {
 				err = multipath_diskop(mddev, &spare, DISKOP_SPARE_WRITE);
 				printk("got DISKOP_SPARE_WRITE err: %d. (spare_faulty(): %d)\n", err, disk_faulty(spare));
-//				MD_BUG();
 			}
 			if (!err && !disk_faulty(spare)) {
 				multipath_diskop(mddev, &spare, DISKOP_SPARE_ACTIVE);
@@ -553,7 +383,6 @@
 				mark_disk_active(spare);
 				sb->active_disks++;
 				sb->spare_disks--;
-//				MD_BUG();
 			}
 		}
 	}
@@ -697,7 +526,6 @@
 	case DISKOP_SPARE_WRITE:
 		sdisk = conf->multipaths + spare_disk;
 		sdisk->operational = 1;
-		sdisk->write_only = 1;
 		break;
 	/*
 	 * Deactivate a spare disk:
@@ -705,7 +533,6 @@
 	case DISKOP_SPARE_INACTIVE:
 		sdisk = conf->multipaths + spare_disk;
 		sdisk->operational = 0;
-		sdisk->write_only = 0;
 		break;
 	/*
 	 * Activate (mark read-write) the (now sync) spare disk,
@@ -757,10 +584,6 @@
 		spare_rdev = find_rdev_nr(mddev, spare_desc->number);
 		failed_rdev = find_rdev_nr(mddev, failed_desc->number);
 		xchg_values(spare_rdev->desc_nr, failed_rdev->desc_nr);
-//		if (failed_rdev->alias_device)
-//			MD_BUG();
-//		if (!spare_rdev->alias_device)
-//			MD_BUG();
 		spare_rdev->alias_device = 0;
 		failed_rdev->alias_device = 1;
 
@@ -788,7 +611,6 @@
 		 * this really activates the spare.
 		 */
 		fdisk->spare = 0;
-		fdisk->write_only = 0;
 
 		/*
 		 * if we activate a spare, we definitely replace a
@@ -828,10 +650,8 @@
 		adisk->dev = MKDEV(added_desc->major,added_desc->minor);
 
 		adisk->operational = 0;
-		adisk->write_only = 0;
 		adisk->spare = 1;
 		adisk->used_slot = 1;
-		adisk->head_position = 0;
 		conf->nr_disks++;
 
 		break;
@@ -865,7 +685,7 @@
 
 static void multipathd (void *data)
 {
-	struct multipath_bh *r1_bh;
+	struct multipath_bh *mp_bh;
 	struct buffer_head *bh;
 	unsigned long flags;
 	mddev_t *mddev;
@@ -874,31 +694,31 @@
 
 	for (;;) {
 		md_spin_lock_irqsave(&retry_list_lock, flags);
-		r1_bh = multipath_retry_list;
-		if (!r1_bh)
+		mp_bh = multipath_retry_list;
+		if (!mp_bh)
 			break;
-		multipath_retry_list = r1_bh->next_r1;
+		multipath_retry_list = mp_bh->next_mp;
 		md_spin_unlock_irqrestore(&retry_list_lock, flags);
 
-		mddev = r1_bh->mddev;
+		mddev = mp_bh->mddev;
 		if (mddev->sb_dirty) {
 			printk(KERN_INFO "dirty sb detected, updating.\n");
 			mddev->sb_dirty = 0;
 			md_update_sb(mddev);
 		}
-		bh = &r1_bh->bh_req;
+		bh = &mp_bh->bh_req;
 		dev = bh->b_dev;
 		
 		multipath_map (mddev, &bh->b_dev);
 		if (bh->b_dev == dev) {
 			printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr);
-			multipath_end_bh_io(r1_bh, 0);
+			multipath_end_bh_io(mp_bh, 0);
 		} else {
 			printk (REDIRECT_SECTOR,
 				partition_name(bh->b_dev), bh->b_blocknr);
 			bh->b_rdev = bh->b_dev;
 			bh->b_rsector = bh->b_blocknr;
-			generic_make_request (r1_bh->cmd, bh);
+			generic_make_request (mp_bh->cmd, bh);
 		}
 	}
 	md_spin_unlock_irqrestore(&retry_list_lock, flags);
@@ -1016,7 +836,7 @@
 	mdp_disk_t *desc, *desc2;
 	mdk_rdev_t *rdev, *def_rdev = NULL;
 	struct md_list_head *tmp;
-	int start_recovery = 0, num_rdevs = 0;
+	int num_rdevs = 0;
 
 	MOD_INC_USE_COUNT;
 
@@ -1072,12 +892,9 @@
 		disk->number = desc->number;
 		disk->raid_disk = desc->raid_disk;
 		disk->dev = rdev->dev;
-		disk->sect_limit = MAX_WORK_PER_DISK;
 		disk->operational = 0;
-		disk->write_only = 0;
 		disk->spare = 1;
 		disk->used_slot = 1;
-		disk->head_position = 0;
 		mark_disk_sync(desc);
 
 		if (disk_active(desc)) {
@@ -1135,10 +952,7 @@
 	conf->mddev = mddev;
 	conf->device_lock = MD_SPIN_LOCK_UNLOCKED;
 
-	conf->segment_lock = MD_SPIN_LOCK_UNLOCKED;
 	init_waitqueue_head(&conf->wait_buffer);
-	init_waitqueue_head(&conf->wait_done);
-	init_waitqueue_head(&conf->wait_ready);
 
 	if (!conf->working_disks) {
 		printk(NONE_OPERATIONAL, mdidx(mddev));
@@ -1150,17 +964,17 @@
 	 * As a minimum, 1 mpbh and raid_disks buffer_heads
 	 * would probably get us by in tight memory situations,
 	 * but a few more is probably a good idea.
-	 * For now, try 16 mpbh and 16*raid_disks bufferheads
-	 * This will allow at least 16 concurrent reads or writes
-	 * even if kmalloc starts failing
+	 * For now, try NR_RESERVED_BUFS mpbh and
+	 * NR_RESERVED_BUFS*raid_disks bufferheads
+	 * This will allow at least NR_RESERVED_BUFS concurrent
+	 * reads or writes even if kmalloc starts failing
 	 */
-	if (multipath_grow_mpbh(conf, 16) < 16 ||
-	    multipath_grow_bh(conf, 16*conf->raid_disks)< 16*conf->raid_disks) {
+	if (multipath_grow_mpbh(conf, NR_RESERVED_BUFS) < NR_RESERVED_BUFS) {
 		printk(MEM_ERROR, mdidx(mddev));
 		goto out_free_conf;
 	}
 
-	if (!start_recovery && (sb->state & (1 << MD_SB_CLEAN))) {
+	if ((sb->state & (1 << MD_SB_CLEAN))) {
 		/*
 		 * we do sanity checks even if the device says
 		 * it's clean ...
@@ -1202,7 +1016,6 @@
 
 out_free_conf:
 	multipath_shrink_mpbh(conf);
-	multipath_shrink_bh(conf, conf->freebh_cnt);
 	kfree(conf);
 	mddev->private = NULL;
 out:
@@ -1228,7 +1041,6 @@
 
 	md_unregister_thread(conf->thread);
 	multipath_shrink_mpbh(conf);
-	multipath_shrink_bh(conf, conf->freebh_cnt);
 	kfree(conf);
 	mddev->private = NULL;
 	MOD_DEC_USE_COUNT;
diff -urN linux-2.4.15-pre3/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- linux-2.4.15-pre3/drivers/net/eepro100.c	Mon Dec  3 23:28:48 2001
+++ linux/drivers/net/eepro100.c	Mon Dec  3 23:28:58 2001
@@ -499,6 +499,9 @@
 	unsigned short phy[2];				/* PHY media interfaces available. */
 	unsigned short advertising;			/* Current PHY advertised caps. */
 	unsigned short partner;				/* Link partner caps. */
+#ifdef CONFIG_PM
+	u32 pm_state[16];
+#endif
 };
 
 /* The parameters for a CmdConfigure operation.
@@ -2193,8 +2196,11 @@
 static int eepro100_suspend(struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
+	pci_save_state(pdev, sp->pm_state);
+
 	if (!netif_running(dev))
 		return 0;
 
@@ -2210,6 +2216,8 @@
 	struct net_device *dev = pci_get_drvdata (pdev);
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	long ioaddr = dev->base_addr;
+
+	pci_restore_state(pdev, sp->pm_state);
 
 	if (!netif_running(dev))
 		return 0;
diff -urN linux-2.4.15-pre3/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in
--- linux-2.4.15-pre3/drivers/net/pcmcia/Config.in	Mon Sep 17 22:52:35 2001
+++ linux/drivers/net/pcmcia/Config.in	Mon Dec  3 23:28:58 2001
@@ -14,6 +14,7 @@
    dep_tristate '  New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA
    dep_tristate '  SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA
    dep_tristate '  Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA
+   dep_tristate '  broken NS8390-cards support' CONFIG_PCMCIA_AXNET $CONFIG_PCMCIA
    dep_tristate '  COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA
    if [ "$CONFIG_IBMTR" != "y" ]; then
       dep_tristate '  IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA
diff -urN linux-2.4.15-pre3/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile
--- linux-2.4.15-pre3/drivers/net/pcmcia/Makefile	Mon Sep 17 22:52:35 2001
+++ linux/drivers/net/pcmcia/Makefile	Mon Dec  3 23:28:58 2001
@@ -23,6 +23,7 @@
 obj-$(CONFIG_PCMCIA_SMC91C92)	+= smc91c92_cs.o
 obj-$(CONFIG_PCMCIA_XIRC2PS)	+= xirc2ps_cs.o
 obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o
+obj-$(CONFIG_PCMCIA_AXNET)	+= axnet_cs.o
 
 # 16-bit wireless client drivers
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
diff -urN linux-2.4.15-pre3/drivers/net/pcmcia/ax8390.h linux/drivers/net/pcmcia/ax8390.h
--- linux-2.4.15-pre3/drivers/net/pcmcia/ax8390.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/ax8390.h	Mon Dec  3 23:28:58 2001
@@ -0,0 +1,193 @@
+/* Generic NS8390 register definitions. */
+/* This file is part of Donald Becker's 8390 drivers, and is distributed
+   under the same license. Auto-loading of 8390.o only in v2.2 - Paul G.
+   Some of these names and comments originated from the Crynwr
+   packet drivers, which are distributed under the GPL. */
+
+#ifndef _8390_h
+#define _8390_h
+
+#include <linux/config.h>
+#include <linux/if_ether.h>
+#include <linux/ioport.h>
+#include <linux/skbuff.h>
+
+#define TX_2X_PAGES 12
+#define TX_1X_PAGES 6
+
+/* Should always use two Tx slots to get back-to-back transmits. */
+#define EI_PINGPONG
+
+#ifdef EI_PINGPONG
+#define TX_PAGES TX_2X_PAGES
+#else
+#define TX_PAGES TX_1X_PAGES
+#endif
+
+#define ETHER_ADDR_LEN 6
+
+/* The 8390 specific per-packet-header format. */
+struct e8390_pkt_hdr {
+  unsigned char status; /* status */
+  unsigned char next;   /* pointer to next packet. */
+  unsigned short count; /* header + packet length in bytes */
+};
+
+#ifdef notdef
+extern int ei_debug;
+#else
+#define ei_debug 1
+#endif
+
+#ifndef HAVE_AUTOIRQ
+/* From auto_irq.c */
+extern void autoirq_setup(int waittime);
+extern unsigned long autoirq_report(int waittime);
+#endif
+
+static int ethdev_init(struct net_device *dev);
+static void NS8390_init(struct net_device *dev, int startp);
+static int ei_open(struct net_device *dev);
+static int ei_close(struct net_device *dev);
+static void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+/* Most of these entries should be in 'struct net_device' (or most of the
+   things in there should be here!) */
+/* You have one of these per-board */
+struct ei_device {
+	const char *name;
+	void (*reset_8390)(struct net_device *);
+	void (*get_8390_hdr)(struct net_device *, struct e8390_pkt_hdr *, int);
+	void (*block_output)(struct net_device *, int, const unsigned char *, int);
+	void (*block_input)(struct net_device *, int, struct sk_buff *, int);
+	unsigned char mcfilter[8];
+	unsigned open:1;
+	unsigned word16:1;  		/* We have the 16-bit (vs 8-bit) version of the card. */
+	unsigned txing:1;		/* Transmit Active */
+	unsigned irqlock:1;		/* 8390's intrs disabled when '1'. */
+	unsigned dmaing:1;		/* Remote DMA Active */
+	unsigned char tx_start_page, rx_start_page, stop_page;
+	unsigned char current_page;	/* Read pointer in buffer  */
+	unsigned char interface_num;	/* Net port (AUI, 10bT.) to use. */
+	unsigned char txqueue;		/* Tx Packet buffer queue length. */
+	short tx1, tx2;			/* Packet lengths for ping-pong tx. */
+	short lasttx;			/* Alpha version consistency check. */
+	unsigned char reg0;		/* Register '0' in a WD8013 */
+	unsigned char reg5;		/* Register '5' in a WD8013 */
+	unsigned char saved_irq;	/* Original dev->irq value. */
+	struct net_device_stats stat;	/* The new statistics table. */
+	u32 *reg_offset;		/* Register mapping table */
+	spinlock_t page_lock;		/* Page register locks */
+	unsigned long priv;		/* Private field to store bus IDs etc. */
+};
+
+/* The maximum number of 8390 interrupt service routines called per IRQ. */
+#define MAX_SERVICE 12
+
+/* The maximum time waited (in jiffies) before assuming a Tx failed. (20ms) */
+#define TX_TIMEOUT (20*HZ/100)
+
+#define ei_status (*(struct ei_device *)(dev->priv))
+
+/* Some generic ethernet register configurations. */
+#define E8390_TX_IRQ_MASK	0xa	/* For register EN0_ISR */
+#define E8390_RX_IRQ_MASK	0x5
+#define E8390_RXCONFIG		0x44	/* EN0_RXCR: broadcasts, no multicast,errors */
+#define E8390_RXOFF		0x20	/* EN0_RXCR: Accept no packets */
+#define E8390_TXCONFIG		0x00	/* EN0_TXCR: Normal transmit mode */
+#define E8390_TXOFF		0x02	/* EN0_TXCR: Transmitter off */
+
+/*  Register accessed at EN_CMD, the 8390 base addr.  */
+#define E8390_STOP	0x01	/* Stop and reset the chip */
+#define E8390_START	0x02	/* Start the chip, clear reset */
+#define E8390_TRANS	0x04	/* Transmit a frame */
+#define E8390_RREAD	0x08	/* Remote read */
+#define E8390_RWRITE	0x10	/* Remote write  */
+#define E8390_NODMA	0x20	/* Remote DMA */
+#define E8390_PAGE0	0x00	/* Select page chip registers */
+#define E8390_PAGE1	0x40	/* using the two high-order bits */
+#define E8390_PAGE2	0x80	/* Page 3 is invalid. */
+
+/*
+ *	Only generate indirect loads given a machine that needs them.
+ */
+ 
+#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \
+    defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \
+    defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE)
+#define EI_SHIFT(x)	(ei_local->reg_offset[x])
+#else
+#define EI_SHIFT(x)	(x)
+#endif
+
+#define E8390_CMD	EI_SHIFT(0x00)  /* The command register (for all pages) */
+/* Page 0 register offsets. */
+#define EN0_CLDALO	EI_SHIFT(0x01)	/* Low byte of current local dma addr  RD */
+#define EN0_STARTPG	EI_SHIFT(0x01)	/* Starting page of ring bfr WR */
+#define EN0_CLDAHI	EI_SHIFT(0x02)	/* High byte of current local dma addr  RD */
+#define EN0_STOPPG	EI_SHIFT(0x02)	/* Ending page +1 of ring bfr WR */
+#define EN0_BOUNDARY	EI_SHIFT(0x03)	/* Boundary page of ring bfr RD WR */
+#define EN0_TSR		EI_SHIFT(0x04)	/* Transmit status reg RD */
+#define EN0_TPSR	EI_SHIFT(0x04)	/* Transmit starting page WR */
+#define EN0_NCR		EI_SHIFT(0x05)	/* Number of collision reg RD */
+#define EN0_TCNTLO	EI_SHIFT(0x05)	/* Low  byte of tx byte count WR */
+#define EN0_FIFO	EI_SHIFT(0x06)	/* FIFO RD */
+#define EN0_TCNTHI	EI_SHIFT(0x06)	/* High byte of tx byte count WR */
+#define EN0_ISR		EI_SHIFT(0x07)	/* Interrupt status reg RD WR */
+#define EN0_CRDALO	EI_SHIFT(0x08)	/* low byte of current remote dma address RD */
+#define EN0_RSARLO	EI_SHIFT(0x08)	/* Remote start address reg 0 */
+#define EN0_CRDAHI	EI_SHIFT(0x09)	/* high byte, current remote dma address RD */
+#define EN0_RSARHI	EI_SHIFT(0x09)	/* Remote start address reg 1 */
+#define EN0_RCNTLO	EI_SHIFT(0x0a)	/* Remote byte count reg WR */
+#define EN0_RCNTHI	EI_SHIFT(0x0b)	/* Remote byte count reg WR */
+#define EN0_RSR		EI_SHIFT(0x0c)	/* rx status reg RD */
+#define EN0_RXCR	EI_SHIFT(0x0c)	/* RX configuration reg WR */
+#define EN0_TXCR	EI_SHIFT(0x0d)	/* TX configuration reg WR */
+#define EN0_COUNTER0	EI_SHIFT(0x0d)	/* Rcv alignment error counter RD */
+#define EN0_DCFG	EI_SHIFT(0x0e)	/* Data configuration reg WR */
+#define EN0_COUNTER1	EI_SHIFT(0x0e)	/* Rcv CRC error counter RD */
+#define EN0_IMR		EI_SHIFT(0x0f)	/* Interrupt mask reg WR */
+#define EN0_COUNTER2	EI_SHIFT(0x0f)	/* Rcv missed frame error counter RD */
+
+/* Bits in EN0_ISR - Interrupt status register */
+#define ENISR_RX	0x01	/* Receiver, no error */
+#define ENISR_TX	0x02	/* Transmitter, no error */
+#define ENISR_RX_ERR	0x04	/* Receiver, with error */
+#define ENISR_TX_ERR	0x08	/* Transmitter, with error */
+#define ENISR_OVER	0x10	/* Receiver overwrote the ring */
+#define ENISR_COUNTERS	0x20	/* Counters need emptying */
+#define ENISR_RDC	0x40	/* remote dma complete */
+#define ENISR_RESET	0x80	/* Reset completed */
+#define ENISR_ALL	0x3f	/* Interrupts we will enable */
+
+/* Bits in EN0_DCFG - Data config register */
+#define ENDCFG_WTS	0x01	/* word transfer mode selection */
+
+/* Page 1 register offsets. */
+#define EN1_PHYS   EI_SHIFT(0x01)	/* This board's physical enet addr RD WR */
+#define EN1_PHYS_SHIFT(i)  EI_SHIFT(i+1) /* Get and set mac address */
+#define EN1_CURPAG EI_SHIFT(0x07)	/* Current memory page RD WR */
+#define EN1_MULT   EI_SHIFT(0x08)	/* Multicast filter mask array (8 bytes) RD WR */
+#define EN1_MULT_SHIFT(i)  EI_SHIFT(8+i) /* Get and set multicast filter */
+
+/* Bits in received packet status byte and EN0_RSR*/
+#define ENRSR_RXOK	0x01	/* Received a good packet */
+#define ENRSR_CRC	0x02	/* CRC error */
+#define ENRSR_FAE	0x04	/* frame alignment error */
+#define ENRSR_FO	0x08	/* FIFO overrun */
+#define ENRSR_MPA	0x10	/* missed pkt */
+#define ENRSR_PHY	0x20	/* physical/multicast address */
+#define ENRSR_DIS	0x40	/* receiver disable. set in monitor mode */
+#define ENRSR_DEF	0x80	/* deferring */
+
+/* Transmitted packet status, EN0_TSR. */
+#define ENTSR_PTX 0x01	/* Packet transmitted without error */
+#define ENTSR_ND  0x02	/* The transmit wasn't deferred. */
+#define ENTSR_COL 0x04	/* The transmit collided at least once. */
+#define ENTSR_ABT 0x08  /* The transmit collided 16 times, and was deferred. */
+#define ENTSR_CRS 0x10	/* The carrier sense was lost. */
+#define ENTSR_FU  0x20  /* A "FIFO underrun" occurred during transmit. */
+#define ENTSR_CDH 0x40	/* The collision detect "heartbeat" signal was lost. */
+#define ENTSR_OWC 0x80  /* There was an out-of-window collision. */
+
+#endif /* _8390_h */
diff -urN linux-2.4.15-pre3/drivers/net/pcmcia/axnet_cs.c linux/drivers/net/pcmcia/axnet_cs.c
--- linux-2.4.15-pre3/drivers/net/pcmcia/axnet_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/axnet_cs.c	Mon Dec  3 23:28:58 2001
@@ -0,0 +1,1958 @@
+/*======================================================================
+
+    A PCMCIA ethernet driver for Asix AX88190-based cards
+
+    The Asix AX88190 is a NS8390-derived chipset with a few nasty
+    idiosyncracies that make it very inconvenient to support with a
+    standard 8390 driver.  This driver is based on pcnet_cs, with the
+    tweaked 8390 code grafted on the end.  Much of what I did was to
+    clean up and update a similar driver supplied by Asix, which was
+    adapted by William Lee, william@asix.com.tw.
+
+    Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net
+
+    axnet_cs.c 1.11 2001/06/12 12:42:40
+    
+    The network driver code is based on Donald Becker's NE2000 code:
+
+    Written 1992,1993 by Donald Becker.
+    Copyright 1993 United States Government as represented by the
+    Director, National Security Agency.  This software may be used and
+    distributed according to the terms of the GNU General Public License,
+    incorporated herein by reference.
+    Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov
+
+======================================================================*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+
+#include <linux/netdevice.h>
+#include "ax8390.h"
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#define AXNET_CMD	0x00
+#define AXNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
+#define AXNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
+#define AXNET_MISC	0x18	/* For IBM CCAE and Socket EA cards */
+#define AXNET_MII_EEP	0x14	/* Offset of MII access port */
+
+#define AXNET_START_PG	0x40	/* First page of TX buffer */
+#define AXNET_STOP_PG	0x80	/* Last page +1 of RX ring */
+
+#define AXNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"axnet_cs.c 1.11 2001/06/12 12:42:40 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb);
+#define skb_tx_check(dev, skb)
+#define add_rx_bytes(stats, n) (stats)->rx_bytes += n;
+#define add_tx_bytes(stats, n) (stats)->tx_bytes += n;
+#define netif_mark_up(dev)	do { } while (0)
+#define netif_mark_down(dev)	do { } while (0)
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+
+/* Bit map of interrupts to choose from */
+INT_MODULE_PARM(irq_mask,	0xdeb8);
+static int irq_list[4] = { -1 };
+MODULE_PARM(irq_list, "1-4i");
+
+/* Ugh!  Let the user hardwire the hardware address for queer cards */
+static int hw_addr[6] = { 0, /* ... */ };
+MODULE_PARM(hw_addr, "6i");
+
+/*====================================================================*/
+
+static void axnet_config(dev_link_t *link);
+static void axnet_release(u_long arg);
+static int axnet_event(event_t event, int priority,
+		       event_callback_args_t *args);
+static int axnet_open(struct net_device *dev);
+static int axnet_close(struct net_device *dev);
+static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
+static void ei_watchdog(u_long arg);
+static void axnet_reset_8390(struct net_device *dev);
+
+static int mdio_read(ioaddr_t addr, int phy_id, int loc);
+static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value);
+
+static void get_8390_hdr(struct net_device *,
+			 struct e8390_pkt_hdr *, int);
+static void block_input(struct net_device *dev, int count,
+			struct sk_buff *skb, int ring_offset);
+static void block_output(struct net_device *dev, int count,
+			 const u_char *buf, const int start_page);
+
+static dev_link_t *axnet_attach(void);
+static void axnet_detach(dev_link_t *);
+
+static dev_info_t dev_info = "axnet_cs";
+static dev_link_t *dev_list;
+
+/*====================================================================*/
+
+typedef struct axnet_dev_t {
+    struct net_device	dev;	/* so &dev == &axnet_dev_t */
+    dev_link_t		link;
+    dev_node_t		node;
+    caddr_t		base;
+    struct timer_list	watchdog;
+    int			stale, fast_poll;
+    u_short		link_status;
+    u_char		duplex_flag;
+    int			phy_id;
+} axnet_dev_t;
+
+/*======================================================================
+
+    This bit of code is used to avoid unregistering network devices
+    at inappropriate times.  2.2 and later kernels are fairly picky
+    about when this can happen.
+    
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    axnet_detach(link);
+    }
+}
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    We never need to do anything when a axnet device is "initialized"
+    by the net software, because we only register already-found cards.
+
+======================================================================*/
+
+static int axnet_init(struct net_device *dev)
+{
+    return 0;
+}
+
+/*======================================================================
+
+    axnet_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *axnet_attach(void)
+{
+    axnet_dev_t *info;
+    dev_link_t *link;
+    struct net_device *dev;
+    client_reg_t client_reg;
+    int i, ret;
+
+    DEBUG(0, "axnet_attach()\n");
+    flush_stale_links();
+
+    /* Create new ethernet device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; dev = &info->dev;
+    link->priv = info;
+    
+    link->release.function = &axnet_release;
+    link->release.data = (u_long)link;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+
+    ethdev_init(dev);
+    dev->init = &axnet_init;
+    dev->open = &axnet_open;
+    dev->stop = &axnet_close;
+    dev->do_ioctl = &axnet_ioctl;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &axnet_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	axnet_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* axnet_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void axnet_detach(dev_link_t *link)
+{
+    axnet_dev_t *info = link->priv;
+    dev_link_t **linkp;
+
+    DEBUG(0, "axnet_detach(0x%p)\n", link);
+
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	axnet_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    if (link->dev)
+	unregister_netdev(&info->dev);
+    kfree(info);
+
+} /* axnet_detach */
+
+/*======================================================================
+
+    This probes for a card's hardware address by reading the PROM.
+
+======================================================================*/
+
+static int get_prom(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int i, j;
+
+    /* This is based on drivers/net/ne.c */
+    struct {
+	u_char value, offset;
+    } program_seq[] = {
+	{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+	{0x01,	EN0_DCFG},	/* Set word-wide access. */
+	{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
+	{0x00,	EN0_RCNTHI},
+	{0x00,	EN0_IMR},	/* Mask completion irq. */
+	{0xFF,	EN0_ISR},
+	{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
+	{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
+	{0x10,	EN0_RCNTLO},
+	{0x00,	EN0_RCNTHI},
+	{0x00,	EN0_RSARLO},	/* DMA starting at 0x0400. */
+	{0x04,	EN0_RSARHI},
+	{E8390_RREAD+E8390_START, E8390_CMD},
+    };
+
+    /* Not much of a test, but the alternatives are messy */
+    if (link->conf.ConfigBase != 0x03c0)
+	return 0;
+
+    axnet_reset_8390(dev);
+    mdelay(10);
+
+    for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+	outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
+
+    for (i = 0; i < 6; i += 2) {
+	j = inw(ioaddr + AXNET_DATAPORT);
+	dev->dev_addr[i] = j & 0xff;
+	dev->dev_addr[i+1] = j >> 8;
+    }
+    return 1;
+} /* get_prom */
+
+/*======================================================================
+
+    This should be totally unnecessary... but when we can't figure
+    out the hardware address any other way, we'll let the user hard
+    wire it when the module is initialized.
+
+======================================================================*/
+
+static int get_hwired(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    int i;
+
+    for (i = 0; i < 6; i++)
+	if (hw_addr[i] != 0) break;
+    if (i == 6)
+	return 0;
+
+    for (i = 0; i < 6; i++)
+	dev->dev_addr[i] = hw_addr[i];
+
+    return 1;
+} /* get_hwired */
+
+/*======================================================================
+
+    axnet_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static int try_io_port(dev_link_t *link)
+{
+    int j, ret;
+    if (link->io.NumPorts1 == 32) {
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	if (link->io.NumPorts2 > 0) {
+	    /* for master/slave multifunction cards */
+	    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+	    link->irq.Attributes = 
+		IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+	}
+    } else {
+	/* This should be two 16-port windows */
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
+    }
+    if (link->io.BasePort1 == 0) {
+	link->io.IOAddrLines = 16;
+	for (j = 0; j < 0x400; j += 0x20) {
+	    link->io.BasePort1 = j ^ 0x300;
+	    link->io.BasePort2 = (j ^ 0x300) + 0x10;
+	    ret = CardServices(RequestIO, link->handle, &link->io);
+	    if (ret == CS_SUCCESS) return ret;
+	}
+	return ret;
+    } else {
+	return CardServices(RequestIO, link->handle, &link->io);
+    }
+}
+
+static void axnet_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    axnet_dev_t *info = link->priv;
+    struct net_device *dev = &info->dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    int i, j, last_ret, last_fn;
+    u_short buf[64];
+    config_info_t conf;
+
+    DEBUG(0, "axnet_config(0x%p)\n", link);
+
+    tuple.Attributes = 0;
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.TupleOffset = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Look up current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    link->conf.Vcc = conf.Vcc;
+
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    tuple.Attributes = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (last_ret == CS_SUCCESS) {
+	cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+	cistpl_io_t *io = &(parse.cftable_entry.io);
+	
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+	if ((cfg->index == 0) || (cfg->io.nwin == 0))
+	    goto next_entry;
+	
+	link->conf.ConfigIndex = cfg->index;
+	/* For multifunction cards, by convention, we configure the
+	   network function with window 0, and serial with window 1 */
+	if (io->nwin > 1) {
+	    i = (io->win[1].len > io->win[0].len);
+	    link->io.BasePort2 = io->win[1-i].base;
+	    link->io.NumPorts2 = io->win[1-i].len;
+	} else {
+	    i = link->io.NumPorts2 = 0;
+	}
+	link->io.BasePort1 = io->win[i].base;
+	link->io.NumPorts1 = io->win[i].len;
+	link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) {
+	    last_ret = try_io_port(link);
+	    if (last_ret == CS_SUCCESS) break;
+	}
+    next_entry:
+	last_ret = CardServices(GetNextTuple, handle, &tuple);
+    }
+    if (last_ret != CS_SUCCESS) {
+	cs_error(handle, RequestIO, last_ret);
+	goto failed;
+    }
+
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    
+    if (link->io.NumPorts2 == 8) {
+	link->conf.Attributes |= CONF_ENABLE_SPKR;
+	link->conf.Status = CCSR_AUDIO_ENA;
+    }
+    
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+    dev->irq = link->irq.AssignedIRQ;
+    dev->base_addr = link->io.BasePort1;
+    if (register_netdev(dev) != 0) {
+	printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n");
+	goto failed;
+    }
+
+    if (!get_prom(link) && !get_hwired(link)) {
+	printk(KERN_NOTICE "axnet_cs: unable to read hardware net"
+	       " address for io base %#3lx\n", dev->base_addr);
+	unregister_netdev(dev);
+	goto failed;
+    }
+
+    ei_status.name = "AX88190";
+    ei_status.word16 = 1;
+    ei_status.tx_start_page = AXNET_START_PG;
+    ei_status.rx_start_page = AXNET_START_PG + TX_PAGES;
+    ei_status.stop_page = AXNET_STOP_PG;
+    ei_status.reset_8390 = &axnet_reset_8390;
+    ei_status.get_8390_hdr = &get_8390_hdr;
+    ei_status.block_input = &block_input;
+    ei_status.block_output = &block_output;
+
+    strcpy(info->node.dev_name, dev->name);
+    link->dev = &info->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    printk(KERN_INFO "%s: Asix AX88190: io %#3lx, irq %d, hw_addr ",
+	   dev->name, dev->base_addr, dev->irq);
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+
+    for (i = 0; i < 32; i++) {
+	j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
+	if ((j != 0) && (j != 0xffff)) break;
+    }
+    info->phy_id = (i < 32) ? i : -1;
+    if (i < 32) {
+	DEBUG(0, "  MII transceiver at index %d, status %x.\n", i, j);
+    } else {
+	printk(KERN_NOTICE "  No MII transceivers found!\n");
+    }
+
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    axnet_release((u_long)link);
+    return;
+} /* axnet_config */
+
+/*======================================================================
+
+    After a card is removed, axnet_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+
+======================================================================*/
+
+static void axnet_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+
+    DEBUG(0, "axnet_release(0x%p)\n", link);
+
+    if (link->open) {
+	DEBUG(1, "axnet_cs: release postponed, '%s' still open\n",
+	      info->node.dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+    link->state &= ~DEV_CONFIG;
+
+} /* axnet_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+======================================================================*/
+
+static int axnet_event(event_t event, int priority,
+		       event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    axnet_dev_t *info = link->priv;
+
+    DEBUG(2, "axnet_event(0x%06x)\n", event);
+
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    netif_device_detach(&info->dev);
+	    mod_timer(&link->release, jiffies + HZ/20);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT;
+	axnet_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG) {
+	    if (link->open)
+		netif_device_detach(&info->dev);
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (link->open) {
+		axnet_reset_8390(&info->dev);
+		NS8390_init(&info->dev, 1);
+		netif_device_attach(&info->dev);
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* axnet_event */
+
+/*======================================================================
+
+    MII interface support
+
+======================================================================*/
+
+#define MDIO_SHIFT_CLK		0x01
+#define MDIO_DATA_WRITE0	0x00
+#define MDIO_DATA_WRITE1	0x08
+#define MDIO_DATA_READ		0x04
+#define MDIO_MASK		0x0f
+#define MDIO_ENB_IN		0x02
+
+static void mdio_sync(ioaddr_t addr)
+{
+    int bits;
+    for (bits = 0; bits < 32; bits++) {
+	outb_p(MDIO_DATA_WRITE1, addr);
+	outb_p(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
+    }
+}
+
+static int mdio_read(ioaddr_t addr, int phy_id, int loc)
+{
+    u_int cmd = (0xf6<<10)|(phy_id<<5)|loc;
+    int i, retval = 0;
+
+    mdio_sync(addr);
+    for (i = 14; i >= 0; i--) {
+	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+	outb_p(dat, addr);
+	outb_p(dat | MDIO_SHIFT_CLK, addr);
+    }
+    for (i = 19; i > 0; i--) {
+	outb_p(MDIO_ENB_IN, addr);
+	retval = (retval << 1) | ((inb_p(addr) & MDIO_DATA_READ) != 0);
+	outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr);
+    }
+    return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value)
+{
+    u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
+    int i;
+
+    mdio_sync(addr);
+    for (i = 31; i >= 0; i--) {
+	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+	outb_p(dat, addr);
+	outb_p(dat | MDIO_SHIFT_CLK, addr);
+    }
+    for (i = 1; i >= 0; i--) {
+	outb_p(MDIO_ENB_IN, addr);
+	outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr);
+    }
+}
+
+/*====================================================================*/
+
+static int axnet_open(struct net_device *dev)
+{
+    axnet_dev_t *info = (axnet_dev_t *)dev;
+    dev_link_t *link = &info->link;
+    
+    DEBUG(2, "axnet_open('%s')\n", dev->name);
+
+    if (!DEV_OK(link))
+	return -ENODEV;
+
+    link->open++;
+    MOD_INC_USE_COUNT;
+
+    request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev);
+
+    info->link_status = 0x00;
+    info->watchdog.function = &ei_watchdog;
+    info->watchdog.data = (u_long)info;
+    info->watchdog.expires = jiffies + HZ;
+    add_timer(&info->watchdog);
+
+    return ei_open(dev);
+} /* axnet_open */
+
+/*====================================================================*/
+
+static int axnet_close(struct net_device *dev)
+{
+    axnet_dev_t *info = (axnet_dev_t *)dev;
+    dev_link_t *link = &info->link;
+
+    DEBUG(2, "axnet_close('%s')\n", dev->name);
+
+    free_irq(dev->irq, dev);
+    
+    link->open--;
+    netif_stop_queue(dev);
+    netif_mark_down(dev);
+    del_timer(&info->watchdog);
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
+
+    MOD_DEC_USE_COUNT;
+
+    return 0;
+} /* axnet_close */
+
+/*======================================================================
+
+    Hard reset the card.  This used to pause for the same period that
+    a 8390 reset command required, but that shouldn't be necessary.
+
+======================================================================*/
+
+static void axnet_reset_8390(struct net_device *dev)
+{
+    ioaddr_t nic_base = dev->base_addr;
+    int i;
+
+    ei_status.txing = ei_status.dmaing = 0;
+
+    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD);
+
+    outb(inb(nic_base + AXNET_RESET), nic_base + AXNET_RESET);
+
+    for (i = 0; i < 100; i++) {
+	if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0)
+	    break;
+	udelay(100);
+    }
+    outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
+    
+    if (i == 100)
+	printk(KERN_ERR "%s: axnet_reset_8390() did not complete.\n",
+	       dev->name);
+    
+} /* axnet_reset_8390 */
+
+/*====================================================================*/
+
+static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs)
+{
+    axnet_dev_t *info = dev_id;
+    info->stale = 0;
+    ei_interrupt(irq, dev_id, regs);
+}
+
+static void ei_watchdog(u_long arg)
+{
+    axnet_dev_t *info = (axnet_dev_t *)(arg);
+    struct net_device *dev = &info->dev;
+    ioaddr_t nic_base = dev->base_addr;
+    ioaddr_t mii_addr = nic_base + AXNET_MII_EEP;
+    u_short link;
+
+    if (!netif_device_present(dev)) goto reschedule;
+
+    /* Check for pending interrupt with expired latency timer: with
+       this, we can limp along even if the interrupt is blocked */
+    if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
+	if (!info->fast_poll)
+	    printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+	ei_irq_wrapper(dev->irq, dev, NULL);
+	info->fast_poll = HZ;
+    }
+    if (info->fast_poll) {
+	info->fast_poll--;
+	info->watchdog.expires = jiffies + 1;
+	add_timer(&info->watchdog);
+	return;
+    }
+
+    if (info->phy_id < 0)
+	goto reschedule;
+    link = mdio_read(mii_addr, info->phy_id, 1);
+    if (!link || (link == 0xffff)) {
+	printk(KERN_INFO "%s: MII is missing!\n", dev->name);
+	info->phy_id = -1;
+	goto reschedule;
+    }
+
+    link &= 0x0004;
+    if (link != info->link_status) {
+	u_short p = mdio_read(mii_addr, info->phy_id, 5);
+	printk(KERN_INFO "%s: %s link beat\n", dev->name,
+	       (link) ? "found" : "lost");
+	if (link) {
+	    info->duplex_flag = (p & 0x0140) ? 0x80 : 0x00;
+	    if (p)
+		printk(KERN_INFO "%s: autonegotiation complete: "
+		       "%sbaseT-%cD selected\n", dev->name,
+		       ((p & 0x0180) ? "100" : "10"),
+		       ((p & 0x0140) ? 'F' : 'H'));
+	    else
+		printk(KERN_INFO "%s: link partner did not autonegotiate\n",
+		       dev->name);
+	    NS8390_init(dev, 1);
+	}
+	info->link_status = link;
+    }
+
+reschedule:
+    info->watchdog.expires = jiffies + HZ;
+    add_timer(&info->watchdog);
+}
+
+/*====================================================================*/
+
+static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+    axnet_dev_t *info = (axnet_dev_t *)dev;
+    u16 *data = (u16 *)&rq->ifr_data;
+    ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP;
+    switch (cmd) {
+    case SIOCDEVPRIVATE:
+	data[0] = info->phy_id;
+    case SIOCDEVPRIVATE+1:
+	data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f);
+	return 0;
+    case SIOCDEVPRIVATE+2:
+	if (!capable(CAP_NET_ADMIN))
+	    return -EPERM;
+	mdio_write(mii_addr, data[0], data[1] & 0x1f, data[2]);
+	return 0;
+    }
+    return -EOPNOTSUPP;
+}
+
+/*====================================================================*/
+
+static void get_8390_hdr(struct net_device *dev,
+			 struct e8390_pkt_hdr *hdr,
+			 int ring_page)
+{
+    ioaddr_t nic_base = dev->base_addr;
+
+    outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
+    outb_p(ring_page, nic_base + EN0_RSARHI);
+    outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD);
+
+    insw(nic_base + AXNET_DATAPORT, hdr,
+	    sizeof(struct e8390_pkt_hdr)>>1);
+    /* Fix for big endian systems */
+    hdr->count = le16_to_cpu(hdr->count);
+
+}
+
+/*====================================================================*/
+
+static void block_input(struct net_device *dev, int count,
+			struct sk_buff *skb, int ring_offset)
+{
+    ioaddr_t nic_base = dev->base_addr;
+    int xfer_count = count;
+    char *buf = skb->data;
+
+#ifdef PCMCIA_DEBUG
+    if ((ei_debug > 4) && (count != 4))
+	printk(KERN_DEBUG "%s: [bi=%d]\n", dev->name, count+4);
+#endif
+    outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
+    outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
+    outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD);
+
+    insw(nic_base + AXNET_DATAPORT,buf,count>>1);
+    if (count & 0x01)
+	buf[count-1] = inb(nic_base + AXNET_DATAPORT), xfer_count++;
+
+}
+
+/*====================================================================*/
+
+static void block_output(struct net_device *dev, int count,
+			 const u_char *buf, const int start_page)
+{
+    ioaddr_t nic_base = dev->base_addr;
+
+#ifdef PCMCIA_DEBUG
+    if (ei_debug > 4)
+	printk(KERN_DEBUG "%s: [bo=%d]\n", dev->name, count);
+#endif
+
+    /* Round the count up for word writes.  Do we need to do this?
+       What effect will an odd byte count have on the 8390?
+       I should check someday. */
+    if (count & 0x01)
+	count++;
+
+    outb_p(0x00, nic_base + EN0_RSARLO);
+    outb_p(start_page, nic_base + EN0_RSARHI);
+    outb_p(E8390_RWRITE+E8390_START, nic_base + AXNET_CMD);
+    outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
+}
+
+/*====================================================================*/
+
+static int __init init_axnet_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "axnet_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &axnet_attach, &axnet_detach);
+    return 0;
+}
+
+static void __exit exit_axnet_cs(void)
+{
+    DEBUG(0, "axnet_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	axnet_detach(dev_list);
+}
+
+module_init(init_axnet_cs);
+module_exit(exit_axnet_cs);
+
+/*====================================================================*/
+
+/* 8390.c: A general NS8390 ethernet driver core for linux. */
+/*
+	Written 1992-94 by Donald Becker.
+  
+	Copyright 1993 United States Government as represented by the
+	Director, National Security Agency.
+
+	This software may be used and distributed according to the terms
+	of the GNU General Public License, incorporated herein by reference.
+
+	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+	Center of Excellence in Space Data and Information Sciences
+	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+  
+  This is the chip-specific code for many 8390-based ethernet adaptors.
+  This is not a complete driver, it must be combined with board-specific
+  code such as ne.c, wd.c, 3c503.c, etc.
+
+  Seeing how at least eight drivers use this code, (not counting the
+  PCMCIA ones either) it is easy to break some card by what seems like
+  a simple innocent change. Please contact me or Donald if you think
+  you have found something that needs changing. -- PG
+
+
+  Changelog:
+
+  Paul Gortmaker	: remove set_bit lock, other cleanups.
+  Paul Gortmaker	: add ei_get_8390_hdr() so we can pass skb's to 
+			  ei_block_input() for eth_io_copy_and_sum().
+  Paul Gortmaker	: exchange static int ei_pingpong for a #define,
+			  also add better Tx error handling.
+  Paul Gortmaker	: rewrite Rx overrun handling as per NS specs.
+  Alexey Kuznetsov	: use the 8390's six bit hash multicast filter.
+  Paul Gortmaker	: tweak ANK's above multicast changes a bit.
+  Paul Gortmaker	: update packet statistics for v2.1.x
+  Alan Cox		: support arbitary stupid port mappings on the
+  			  68K Macintosh. Support >16bit I/O spaces
+  Paul Gortmaker	: add kmod support for auto-loading of the 8390
+			  module by all drivers that require it.
+  Alan Cox		: Spinlocking work, added 'BUG_83C690'
+  Paul Gortmaker	: Separate out Tx timeout code from Tx path.
+
+  Sources:
+  The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
+
+  */
+
+static const char *version =
+    "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/irq.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/interrupt.h>
+
+#include <linux/etherdevice.h>
+
+#define BUG_83C690
+
+/* These are the operational function interfaces to board-specific
+   routines.
+	void reset_8390(struct net_device *dev)
+		Resets the board associated with DEV, including a hardware reset of
+		the 8390.  This is only called when there is a transmit timeout, and
+		it is always followed by 8390_init().
+	void block_output(struct net_device *dev, int count, const unsigned char *buf,
+					  int start_page)
+		Write the COUNT bytes of BUF to the packet buffer at START_PAGE.  The
+		"page" value uses the 8390's 256-byte pages.
+	void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring_page)
+		Read the 4 byte, page aligned 8390 header. *If* there is a
+		subsequent read, it will be of the rest of the packet.
+	void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+		Read COUNT bytes from the packet buffer into the skb data area. Start 
+		reading from RING_OFFSET, the address as the 8390 sees it.  This will always
+		follow the read of the 8390 header. 
+*/
+#define ei_reset_8390 (ei_local->reset_8390)
+#define ei_block_output (ei_local->block_output)
+#define ei_block_input (ei_local->block_input)
+#define ei_get_8390_hdr (ei_local->get_8390_hdr)
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef ei_debug
+int ei_debug = 1;
+#endif
+
+/* Index to functions. */
+static void ei_tx_intr(struct net_device *dev);
+static void ei_tx_err(struct net_device *dev);
+static void ei_tx_timeout(struct net_device *dev);
+static void ei_receive(struct net_device *dev);
+static void ei_rx_overrun(struct net_device *dev);
+
+/* Routines generic to NS8390-based boards. */
+static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
+								int start_page);
+static void set_multicast_list(struct net_device *dev);
+static void do_set_multicast_list(struct net_device *dev);
+
+/*
+ *	SMP and the 8390 setup.
+ *
+ *	The 8390 isnt exactly designed to be multithreaded on RX/TX. There is
+ *	a page register that controls bank and packet buffer access. We guard
+ *	this with ei_local->page_lock. Nobody should assume or set the page other
+ *	than zero when the lock is not held. Lock holders must restore page 0
+ *	before unlocking. Even pure readers must take the lock to protect in 
+ *	page 0.
+ *
+ *	To make life difficult the chip can also be very slow. We therefore can't
+ *	just use spinlocks. For the longer lockups we disable the irq the device
+ *	sits on and hold the lock. We must hold the lock because there is a dual
+ *	processor case other than interrupts (get stats/set multicast list in
+ *	parallel with each other and transmit).
+ *
+ *	Note: in theory we can just disable the irq on the card _but_ there is
+ *	a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
+ *	enter lock, take the queued irq. So we waddle instead of flying.
+ *
+ *	Finally by special arrangement for the purpose of being generally 
+ *	annoying the transmit function is called bh atomic. That places
+ *	restrictions on the user context callers as disable_irq won't save
+ *	them.
+ */
+ 
+
+
+/**
+ * ei_open - Open/initialize the board.
+ * @dev: network device to initialize
+ *
+ * This routine goes all-out, setting everything
+ * up anew at each open, even though many of these registers should only
+ * need to be set once at boot.
+ */
+static int ei_open(struct net_device *dev)
+{
+	unsigned long flags;
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+
+	/* This can't happen unless somebody forgot to call ethdev_init(). */
+	if (ei_local == NULL) 
+	{
+		printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name);
+		return -ENXIO;
+	}
+
+#ifdef HAVE_TX_TIMEOUT
+	/* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout
+	    wrapper that does e.g. media check & then calls ei_tx_timeout. */
+	if (dev->tx_timeout == NULL)
+		 dev->tx_timeout = ei_tx_timeout;
+	if (dev->watchdog_timeo <= 0)
+		 dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+
+	/*
+	 *	Grab the page lock so we own the register set, then call
+	 *	the init function.
+	 */
+      
+      	spin_lock_irqsave(&ei_local->page_lock, flags);
+	NS8390_init(dev, 1);
+	/* Set the flag before we drop the lock, That way the IRQ arrives
+	   after its set and we get no silly warnings */
+	netif_mark_up(dev);
+	netif_start_queue(dev);
+      	spin_unlock_irqrestore(&ei_local->page_lock, flags);
+	ei_local->irqlock = 0;
+	return 0;
+}
+
+/**
+ * ei_close - shut down network device
+ * @dev: network device to close
+ *
+ * Opposite of ei_open(). Only used when "ifconfig <devname> down" is done.
+ */
+static int ei_close(struct net_device *dev)
+{
+	unsigned long flags;
+
+	/*
+	 *	Hold the page lock during close
+	 */
+
+	spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags);
+	NS8390_init(dev, 0);
+	spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags);
+	netif_stop_queue(dev);
+	return 0;
+}
+
+/**
+ * ei_tx_timeout - handle transmit time out condition
+ * @dev: network device which has apparently fallen asleep
+ *
+ * Called by kernel when device never acknowledges a transmit has
+ * completed (or failed) - i.e. never posted a Tx related interrupt.
+ */
+
+void ei_tx_timeout(struct net_device *dev)
+{
+	long e8390_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	int txsr, isr, tickssofar = jiffies - dev->trans_start;
+	unsigned long flags;
+
+	ei_local->stat.tx_errors++;
+
+	spin_lock_irqsave(&ei_local->page_lock, flags);
+	txsr = inb(e8390_base+EN0_TSR);
+	isr = inb(e8390_base+EN0_ISR);
+	spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+	printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
+		dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
+		(isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
+
+	if (!isr && !ei_local->stat.tx_packets) 
+	{
+		/* The 8390 probably hasn't gotten on the cable yet. */
+		ei_local->interface_num ^= 1;   /* Try a different xcvr.  */
+	}
+
+	/* Ugly but a reset can be slow, yet must be protected */
+		
+	disable_irq_nosync(dev->irq);
+	spin_lock(&ei_local->page_lock);
+		
+	/* Try to restart the card.  Perhaps the user has fixed something. */
+	ei_reset_8390(dev);
+	NS8390_init(dev, 1);
+		
+	spin_unlock(&ei_local->page_lock);
+	enable_irq(dev->irq);
+	netif_wake_queue(dev);
+}
+    
+/**
+ * ei_start_xmit - begin packet transmission
+ * @skb: packet to be sent
+ * @dev: network device to which packet is sent
+ *
+ * Sends a packet to an 8390 network device.
+ */
+ 
+static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	long e8390_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	int length, send_length, output_page;
+	unsigned long flags;
+
+	netif_stop_queue(dev);
+	skb_tx_check(dev, skb);
+
+	length = skb->len;
+
+	/* Mask interrupts from the ethercard. 
+	   SMP: We have to grab the lock here otherwise the IRQ handler
+	   on another CPU can flip window and race the IRQ mask set. We end
+	   up trashing the mcast filter not disabling irqs if we dont lock */
+	   
+	spin_lock_irqsave(&ei_local->page_lock, flags);
+	outb_p(0x00, e8390_base + EN0_IMR);
+	spin_unlock_irqrestore(&ei_local->page_lock, flags);
+	
+	
+	/*
+	 *	Slow phase with lock held.
+	 */
+	 
+	disable_irq_nosync(dev->irq);
+	
+	spin_lock(&ei_local->page_lock);
+	
+	ei_local->irqlock = 1;
+
+	send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
+    
+#ifdef EI_PINGPONG
+
+	/*
+	 * We have two Tx slots available for use. Find the first free
+	 * slot, and then perform some sanity checks. With two Tx bufs,
+	 * you get very close to transmitting back-to-back packets. With
+	 * only one Tx buf, the transmitter sits idle while you reload the
+	 * card, leaving a substantial gap between each transmitted packet.
+	 */
+
+	if (ei_local->tx1 == 0) 
+	{
+		output_page = ei_local->tx_start_page;
+		ei_local->tx1 = send_length;
+		if (ei_debug  &&  ei_local->tx2 > 0)
+			printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
+				dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
+	}
+	else if (ei_local->tx2 == 0) 
+	{
+		output_page = ei_local->tx_start_page + TX_1X_PAGES;
+		ei_local->tx2 = send_length;
+		if (ei_debug  &&  ei_local->tx1 > 0)
+			printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
+				dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);
+	}
+	else
+	{	/* We should never get here. */
+		if (ei_debug)
+			printk(KERN_DEBUG "%s: No Tx buffers free! tx1=%d tx2=%d last=%d\n",
+				dev->name, ei_local->tx1, ei_local->tx2, ei_local->lasttx);
+		ei_local->irqlock = 0;
+		netif_stop_queue(dev);
+		outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+		spin_unlock(&ei_local->page_lock);
+		enable_irq(dev->irq);
+		ei_local->stat.tx_errors++;
+		return 1;
+	}
+
+	/*
+	 * Okay, now upload the packet and trigger a send if the transmitter
+	 * isn't already sending. If it is busy, the interrupt handler will
+	 * trigger the send later, upon receiving a Tx done interrupt.
+	 */
+
+	ei_block_output(dev, length, skb->data, output_page);
+	if (! ei_local->txing) 
+	{
+		ei_local->txing = 1;
+		NS8390_trigger_send(dev, send_length, output_page);
+		dev->trans_start = jiffies;
+		if (output_page == ei_local->tx_start_page) 
+		{
+			ei_local->tx1 = -1;
+			ei_local->lasttx = -1;
+		}
+		else 
+		{
+			ei_local->tx2 = -1;
+			ei_local->lasttx = -2;
+		}
+	}
+	else ei_local->txqueue++;
+
+	if (ei_local->tx1  &&  ei_local->tx2)
+		netif_stop_queue(dev);
+	else
+		netif_start_queue(dev);
+
+#else	/* EI_PINGPONG */
+
+	/*
+	 * Only one Tx buffer in use. You need two Tx bufs to come close to
+	 * back-to-back transmits. Expect a 20 -> 25% performance hit on
+	 * reasonable hardware if you only use one Tx buffer.
+	 */
+
+	ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
+	ei_local->txing = 1;
+	NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
+	dev->trans_start = jiffies;
+	netif_stop_queue(dev);
+
+#endif	/* EI_PINGPONG */
+
+	/* Turn 8390 interrupts back on. */
+	ei_local->irqlock = 0;
+	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+	
+	spin_unlock(&ei_local->page_lock);
+	enable_irq(dev->irq);
+
+	DEV_KFREE_SKB (skb);
+	add_tx_bytes(&ei_local->stat, send_length);
+    
+	return 0;
+}
+
+/**
+ * ei_interrupt - handle the interrupts from an 8390
+ * @irq: interrupt number
+ * @dev_id: a pointer to the net_device
+ * @regs: unused
+ *
+ * Handle the ether interface interrupts. We pull packets from
+ * the 8390 via the card specific functions and fire them at the networking
+ * stack. We also handle transmit completions and wake the transmit path if
+ * neccessary. We also update the counters and do other housekeeping as
+ * needed.
+ */
+
+static void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct net_device *dev = dev_id;
+	long e8390_base;
+	int interrupts, nr_serviced = 0, i;
+	struct ei_device *ei_local;
+    
+	if (dev == NULL) 
+	{
+		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+    
+	e8390_base = dev->base_addr;
+	ei_local = (struct ei_device *) dev->priv;
+
+	/*
+	 *	Protect the irq test too.
+	 */
+	 
+	spin_lock(&ei_local->page_lock);
+
+	if (ei_local->irqlock) 
+	{
+#if 1 /* This might just be an interrupt for a PCI device sharing this line */
+		/* The "irqlock" check is only for testing. */
+		printk(ei_local->irqlock
+			   ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"
+			   : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",
+			   dev->name, inb_p(e8390_base + EN0_ISR),
+			   inb_p(e8390_base + EN0_IMR));
+#endif
+		spin_unlock(&ei_local->page_lock);
+		return;
+	}
+    
+	if (ei_debug > 3)
+		printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,
+			   inb_p(e8390_base + EN0_ISR));
+
+	outb_p(0x00, e8390_base + EN0_ISR);
+	ei_local->irqlock = 1;
+   
+	/* !!Assumption!! -- we stay in page 0.	 Don't break this. */
+	while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
+		   && ++nr_serviced < MAX_SERVICE) 
+	{
+		if (!netif_running(dev) || (interrupts == 0xff)) {
+			if (ei_debug > 1)
+				printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
+			outb_p(interrupts, e8390_base + EN0_ISR);
+			interrupts = 0;
+			break;
+		}
+		/* AX88190 bug fix. */
+		outb_p(interrupts, e8390_base + EN0_ISR);
+		for (i = 0; i < 10; i++) {
+			if (!(inb(e8390_base + EN0_ISR) & interrupts))
+				break;
+			outb_p(0, e8390_base + EN0_ISR);
+			outb_p(interrupts, e8390_base + EN0_ISR);
+		}
+		if (interrupts & ENISR_OVER) 
+			ei_rx_overrun(dev);
+		else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) 
+		{
+			/* Got a good (?) packet. */
+			ei_receive(dev);
+		}
+		/* Push the next to-transmit packet through. */
+		if (interrupts & ENISR_TX)
+			ei_tx_intr(dev);
+		else if (interrupts & ENISR_TX_ERR)
+			ei_tx_err(dev);
+
+		if (interrupts & ENISR_COUNTERS) 
+		{
+			ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
+			ei_local->stat.rx_crc_errors   += inb_p(e8390_base + EN0_COUNTER1);
+			ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
+		}
+	}
+    
+	if (interrupts && ei_debug) 
+	{
+		if (nr_serviced >= MAX_SERVICE) 
+		{
+			/* 0xFF is valid for a card removal */
+			if(interrupts!=0xFF)
+				printk(KERN_WARNING "%s: Too much work at interrupt, status %#2.2x\n",
+				   dev->name, interrupts);
+			outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
+		} else {
+			printk(KERN_WARNING "%s: unknown interrupt %#2x\n", dev->name, interrupts);
+			outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
+		}
+	}
+
+	/* Turn 8390 interrupts back on. */
+	ei_local->irqlock = 0;
+	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+
+	spin_unlock(&ei_local->page_lock);
+	return;
+}
+
+/**
+ * ei_tx_err - handle transmitter error
+ * @dev: network device which threw the exception
+ *
+ * A transmitter error has happened. Most likely excess collisions (which
+ * is a fairly normal condition). If the error is one where the Tx will
+ * have been aborted, we try and send another one right away, instead of
+ * letting the failed packet sit and collect dust in the Tx buffer. This
+ * is a much better solution as it avoids kernel based Tx timeouts, and
+ * an unnecessary card reset.
+ *
+ * Called with lock held.
+ */
+
+static void ei_tx_err(struct net_device *dev)
+{
+	long e8390_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	unsigned char txsr = inb_p(e8390_base+EN0_TSR);
+	unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
+
+#ifdef VERBOSE_ERROR_DUMP
+	printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
+	if (txsr & ENTSR_ABT)
+		printk("excess-collisions ");
+	if (txsr & ENTSR_ND)
+		printk("non-deferral ");
+	if (txsr & ENTSR_CRS)
+		printk("lost-carrier ");
+	if (txsr & ENTSR_FU)
+		printk("FIFO-underrun ");
+	if (txsr & ENTSR_CDH)
+		printk("lost-heartbeat ");
+	printk("\n");
+#endif
+
+	if (tx_was_aborted)
+		ei_tx_intr(dev);
+	else 
+	{
+		ei_local->stat.tx_errors++;
+		if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
+		if (txsr & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
+		if (txsr & ENTSR_OWC) ei_local->stat.tx_window_errors++;
+	}
+}
+
+/**
+ * ei_tx_intr - transmit interrupt handler
+ * @dev: network device for which tx intr is handled
+ *
+ * We have finished a transmit: check for errors and then trigger the next
+ * packet to be sent. Called with lock held.
+ */
+
+static void ei_tx_intr(struct net_device *dev)
+{
+	long e8390_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	int status = inb(e8390_base + EN0_TSR);
+    
+#ifdef EI_PINGPONG
+
+	/*
+	 * There are two Tx buffers, see which one finished, and trigger
+	 * the send of another one if it exists.
+	 */
+	ei_local->txqueue--;
+
+	if (ei_local->tx1 < 0) 
+	{
+		if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
+			printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n",
+				ei_local->name, ei_local->lasttx, ei_local->tx1);
+		ei_local->tx1 = 0;
+		if (ei_local->tx2 > 0) 
+		{
+			ei_local->txing = 1;
+			NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
+			dev->trans_start = jiffies;
+			ei_local->tx2 = -1,
+			ei_local->lasttx = 2;
+		}
+		else ei_local->lasttx = 20, ei_local->txing = 0;	
+	}
+	else if (ei_local->tx2 < 0) 
+	{
+		if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)
+			printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
+				ei_local->name, ei_local->lasttx, ei_local->tx2);
+		ei_local->tx2 = 0;
+		if (ei_local->tx1 > 0) 
+		{
+			ei_local->txing = 1;
+			NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
+			dev->trans_start = jiffies;
+			ei_local->tx1 = -1;
+			ei_local->lasttx = 1;
+		}
+		else
+			ei_local->lasttx = 10, ei_local->txing = 0;
+	}
+//	else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n",
+//			dev->name, ei_local->lasttx);
+
+#else	/* EI_PINGPONG */
+	/*
+	 *  Single Tx buffer: mark it free so another packet can be loaded.
+	 */
+	ei_local->txing = 0;
+#endif
+
+	/* Minimize Tx latency: update the statistics after we restart TXing. */
+	if (status & ENTSR_COL)
+		ei_local->stat.collisions++;
+	if (status & ENTSR_PTX)
+		ei_local->stat.tx_packets++;
+	else 
+	{
+		ei_local->stat.tx_errors++;
+		if (status & ENTSR_ABT) 
+		{
+			ei_local->stat.tx_aborted_errors++;
+			ei_local->stat.collisions += 16;
+		}
+		if (status & ENTSR_CRS) 
+			ei_local->stat.tx_carrier_errors++;
+		if (status & ENTSR_FU) 
+			ei_local->stat.tx_fifo_errors++;
+		if (status & ENTSR_CDH)
+			ei_local->stat.tx_heartbeat_errors++;
+		if (status & ENTSR_OWC)
+			ei_local->stat.tx_window_errors++;
+	}
+	netif_wake_queue(dev);
+}
+
+/**
+ * ei_receive - receive some packets
+ * @dev: network device with which receive will be run
+ *
+ * We have a good packet(s), get it/them out of the buffers. 
+ * Called with lock held.
+ */
+
+static void ei_receive(struct net_device *dev)
+{
+	long e8390_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	unsigned char rxing_page, this_frame, next_frame;
+	unsigned short current_offset;
+	int rx_pkt_count = 0;
+	struct e8390_pkt_hdr rx_frame;
+    
+	while (++rx_pkt_count < 10) 
+	{
+		int pkt_len, pkt_stat;
+		
+		/* Get the rx page (incoming packet pointer). */
+		rxing_page = inb_p(e8390_base + EN1_CURPAG -1);
+		
+		/* Remove one frame from the ring.  Boundary is always a page behind. */
+		this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
+		if (this_frame >= ei_local->stop_page)
+			this_frame = ei_local->rx_start_page;
+		
+		/* Someday we'll omit the previous, iff we never get this message.
+		   (There is at least one clone claimed to have a problem.)  
+		   
+		   Keep quiet if it looks like a card removal. One problem here
+		   is that some clones crash in roughly the same way.
+		 */
+		if (ei_debug > 0  &&  this_frame != ei_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF))
+			printk(KERN_ERR "%s: mismatched read page pointers %2x vs %2x.\n",
+				   dev->name, this_frame, ei_local->current_page);
+		
+		if (this_frame == rxing_page)	/* Read all the frames? */
+			break;				/* Done for now */
+		
+		current_offset = this_frame << 8;
+		ei_get_8390_hdr(dev, &rx_frame, this_frame);
+		
+		pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
+		pkt_stat = rx_frame.status;
+		
+		next_frame = this_frame + 1 + ((pkt_len+4)>>8);
+		
+		if (pkt_len < 60  ||  pkt_len > 1518) 
+		{
+			if (ei_debug)
+				printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
+					   dev->name, rx_frame.count, rx_frame.status,
+					   rx_frame.next);
+			ei_local->stat.rx_errors++;
+			ei_local->stat.rx_length_errors++;
+		}
+		 else if ((pkt_stat & 0x0F) == ENRSR_RXOK) 
+		{
+			struct sk_buff *skb;
+			
+			skb = dev_alloc_skb(pkt_len+2);
+			if (skb == NULL) 
+			{
+				if (ei_debug > 1)
+					printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
+						   dev->name, pkt_len);
+				ei_local->stat.rx_dropped++;
+				break;
+			}
+			else
+			{
+				skb_reserve(skb,2);	/* IP headers on 16 byte boundaries */
+				skb->dev = dev;
+				skb_put(skb, pkt_len);	/* Make room */
+				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
+				skb->protocol=eth_type_trans(skb,dev);
+				netif_rx(skb);
+				dev->last_rx = jiffies;
+				ei_local->stat.rx_packets++;
+				add_rx_bytes(&ei_local->stat, pkt_len);
+				if (pkt_stat & ENRSR_PHY)
+					ei_local->stat.multicast++;
+			}
+		} 
+		else 
+		{
+			if (ei_debug)
+				printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
+					   dev->name, rx_frame.status, rx_frame.next,
+					   rx_frame.count);
+			ei_local->stat.rx_errors++;
+			/* NB: The NIC counts CRC, frame and missed errors. */
+			if (pkt_stat & ENRSR_FO)
+				ei_local->stat.rx_fifo_errors++;
+		}
+		next_frame = rx_frame.next;
+		
+		/* This _should_ never happen: it's here for avoiding bad clones. */
+		if (next_frame >= ei_local->stop_page) {
+			printk("%s: next frame inconsistency, %#2x\n", dev->name,
+				   next_frame);
+			next_frame = ei_local->rx_start_page;
+		}
+		ei_local->current_page = next_frame;
+		outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
+	}
+
+	return;
+}
+
+/**
+ * ei_rx_overrun - handle receiver overrun
+ * @dev: network device which threw exception
+ *
+ * We have a receiver overrun: we have to kick the 8390 to get it started
+ * again. Problem is that you have to kick it exactly as NS prescribes in
+ * the updated datasheets, or "the NIC may act in an unpredictable manner."
+ * This includes causing "the NIC to defer indefinitely when it is stopped
+ * on a busy network."  Ugh.
+ * Called with lock held. Don't call this with the interrupts off or your
+ * computer will hate you - it takes 10ms or so. 
+ */
+
+static void ei_rx_overrun(struct net_device *dev)
+{
+	axnet_dev_t *info = (axnet_dev_t *)dev;
+	long e8390_base = dev->base_addr;
+	unsigned char was_txing, must_resend = 0;
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+    
+	/*
+	 * Record whether a Tx was in progress and then issue the
+	 * stop command.
+	 */
+	was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
+	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+    
+	if (ei_debug > 1)
+		printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
+	ei_local->stat.rx_over_errors++;
+    
+	/* 
+	 * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
+	 * Early datasheets said to poll the reset bit, but now they say that
+	 * it "is not a reliable indicator and subsequently should be ignored."
+	 * We wait at least 10ms.
+	 */
+
+	mdelay(10);
+
+	/*
+	 * Reset RBCR[01] back to zero as per magic incantation.
+	 */
+	outb_p(0x00, e8390_base+EN0_RCNTLO);
+	outb_p(0x00, e8390_base+EN0_RCNTHI);
+
+	/*
+	 * See if any Tx was interrupted or not. According to NS, this
+	 * step is vital, and skipping it will cause no end of havoc.
+	 */
+
+	if (was_txing)
+	{ 
+		unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
+		if (!tx_completed)
+			must_resend = 1;
+	}
+
+	/*
+	 * Have to enter loopback mode and then restart the NIC before
+	 * you are allowed to slurp packets up off the ring.
+	 */
+	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
+	outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
+
+	/*
+	 * Clear the Rx ring of all the debris, and ack the interrupt.
+	 */
+	ei_receive(dev);
+
+	/*
+	 * Leave loopback mode, and resend any packet that got stopped.
+	 */
+	outb_p(E8390_TXCONFIG | info->duplex_flag, e8390_base + EN0_TXCR); 
+	if (must_resend)
+    		outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
+}
+
+/*
+ *	Collect the stats. This is called unlocked and from several contexts.
+ */
+ 
+static struct net_device_stats *get_stats(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	unsigned long flags;
+    
+	/* If the card is stopped, just return the present stats. */
+	if (!netif_running(dev))
+		return &ei_local->stat;
+
+	spin_lock_irqsave(&ei_local->page_lock,flags);
+	/* Read the counter registers, assuming we are in page 0. */
+	ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
+	ei_local->stat.rx_crc_errors   += inb_p(ioaddr + EN0_COUNTER1);
+	ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
+	spin_unlock_irqrestore(&ei_local->page_lock, flags);
+    
+	return &ei_local->stat;
+}
+
+/**
+ * do_set_multicast_list - set/clear multicast filter
+ * @dev: net device for which multicast filter is adjusted
+ *
+ *	Set or clear the multicast filter for this adaptor. May be called
+ *	from a BH in 2.1.x. Must be called with lock held. 
+ */
+ 
+static void do_set_multicast_list(struct net_device *dev)
+{
+	long e8390_base = dev->base_addr;
+
+  	if(dev->flags&IFF_PROMISC)
+  		outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
+	else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
+  		outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
+  	else
+  		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+}
+
+/*
+ *	Called without lock held. This is invoked from user context and may
+ *	be parallel to just about everything else. Its also fairly quick and
+ *	not called too often. Must protect against both bh and irq users
+ */
+ 
+static void set_multicast_list(struct net_device *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags);
+	do_set_multicast_list(dev);
+	spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags);
+}	
+
+/**
+ * ethdev_init - init rest of 8390 device struct
+ * @dev: network device structure to init
+ *
+ * Initialize the rest of the 8390 device structure.  Do NOT __init
+ * this, as it is used by 8390 based modular drivers too.
+ */
+
+static int ethdev_init(struct net_device *dev)
+{
+	if (ei_debug > 1)
+		printk(version);
+    
+	if (dev->priv == NULL) 
+	{
+		struct ei_device *ei_local;
+		
+		dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
+		if (dev->priv == NULL)
+			return -ENOMEM;
+		memset(dev->priv, 0, sizeof(struct ei_device));
+		ei_local = (struct ei_device *)dev->priv;
+		spin_lock_init(&ei_local->page_lock);
+	}
+    
+	dev->hard_start_xmit = &ei_start_xmit;
+	dev->get_stats	= get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+
+	ether_setup(dev);
+        
+	return 0;
+}
+
+
+
+/* This page of functions should be 8390 generic */
+/* Follow National Semi's recommendations for initializing the "NIC". */
+
+/**
+ * NS8390_init - initialize 8390 hardware
+ * @dev: network device to initialize
+ * @startp: boolean.  non-zero value to initiate chip processing
+ *
+ *	Must be called with lock held.
+ */
+
+static void NS8390_init(struct net_device *dev, int startp)
+{
+	axnet_dev_t *info = (axnet_dev_t *)dev;
+	long e8390_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	int i;
+	int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
+    
+	if(sizeof(struct e8390_pkt_hdr)!=4)
+    		panic("8390.c: header struct mispacked\n");    
+	/* Follow National Semi's recommendations for initing the DP83902. */
+	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
+	outb_p(endcfg, e8390_base + EN0_DCFG);	/* 0x48 or 0x49 */
+	/* Clear the remote byte count registers. */
+	outb_p(0x00,  e8390_base + EN0_RCNTLO);
+	outb_p(0x00,  e8390_base + EN0_RCNTHI);
+	/* Set to monitor and loopback mode -- this is vital!. */
+	outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
+	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
+	/* Set the transmit page and receive ring. */
+	outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
+	ei_local->tx1 = ei_local->tx2 = 0;
+	outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
+	outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY);	/* 3c503 says 0x3f,NS0x26*/
+	ei_local->current_page = ei_local->rx_start_page;		/* assert boundary+1 */
+	outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
+	/* Clear the pending interrupts and mask. */
+	outb_p(0xFF, e8390_base + EN0_ISR);
+	outb_p(0x00,  e8390_base + EN0_IMR);
+    
+	/* Copy the station address into the DS8390 registers. */
+
+	outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
+	for(i = 0; i < 6; i++) 
+	{
+		outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
+		if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
+			printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
+	}
+	/*
+	 * Initialize the multicast list to accept-all.  If we enable multicast
+	 * the higher levels can do the filtering.
+	 */
+	for (i = 0; i < 8; i++)
+		outb_p(0xff, e8390_base + EN1_MULT + i);
+
+	outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
+	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+
+	netif_start_queue(dev);
+	ei_local->tx1 = ei_local->tx2 = 0;
+	ei_local->txing = 0;
+
+	if (startp) 
+	{
+		outb_p(0xff,  e8390_base + EN0_ISR);
+		outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
+		outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
+		outb_p(E8390_TXCONFIG | info->duplex_flag,
+		       e8390_base + EN0_TXCR); /* xmit on. */
+		/* 3c503 TechMan says rxconfig only after the NIC is started. */
+		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on,  */
+		do_set_multicast_list(dev);	/* (re)load the mcast table */
+	}
+}
+
+/* Trigger a transmit start, assuming the length is valid. 
+   Always called with the page lock held */
+   
+static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
+								int start_page)
+{
+	long e8390_base = dev->base_addr;
+ 	struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) dev->priv;
+    
+	if (inb_p(e8390_base) & E8390_TRANS) 
+	{
+		printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
+			dev->name);
+		return;
+	}
+	outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
+	outb_p(length >> 8, e8390_base + EN0_TCNTHI);
+	outb_p(start_page, e8390_base + EN0_TPSR);
+	outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD);
+}
diff -urN linux-2.4.15-pre3/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog
--- linux-2.4.15-pre3/drivers/parport/ChangeLog	Mon Dec  3 23:28:49 2001
+++ linux/drivers/parport/ChangeLog	Mon Dec  3 23:28:58 2001
@@ -1,3 +1,7 @@
+2001-11-12  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c (init_module): Warn when parameters are ignored.
+
 2001-11-01  Damian Gruszka  <damian.gruszka@VisionSystems.de>
 
 	* parport_serial.c (serial_register): Set base_baud before
diff -urN linux-2.4.15-pre3/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- linux-2.4.15-pre3/drivers/parport/parport_pc.c	Fri Nov  2 17:13:53 2001
+++ linux/drivers/parport/parport_pc.c	Mon Dec  3 23:28:58 2001
@@ -3047,6 +3047,12 @@
 			case PARPORT_IRQ_NONE:
 			case PARPORT_IRQ_AUTO:
 				irqval[0] = val;
+				break;
+			default:
+				printk (KERN_WARNING
+					"parport_pc: irq specified "
+					"without base address.  Use 'io=' "
+					"to specify one\n");
 			}
 
 		if (dma[0] && !parport_parse_dmas (1, dma, &val))
@@ -3054,6 +3060,12 @@
 			case PARPORT_DMA_NONE:
 			case PARPORT_DMA_AUTO:
 				dmaval[0] = val;
+				break;
+			default:
+				printk (KERN_WARNING
+					"parport_pc: dma specified "
+					"without base address.  Use 'io=' "
+					"to specify one\n");
 			}
 	}
 
diff -urN linux-2.4.15-pre3/drivers/pci/pci.c linux/drivers/pci/pci.c
--- linux-2.4.15-pre3/drivers/pci/pci.c	Mon Dec  3 23:28:49 2001
+++ linux/drivers/pci/pci.c	Mon Dec  3 23:28:58 2001
@@ -684,22 +684,17 @@
 }
 
 /**
- * pci_insert_device - insert a hotplug device
- * @dev: the device to insert
- * @bus: where to insert it
+ * pci_announce_device_to_drivers - tell the drivers a new device has appeared
+ * @dev: the device that has shown up
  *
- * Add a new device to the device lists and notify userspace (/sbin/hotplug).
+ * Notifys the drivers that a new device has appeared, and also notifys
+ * userspace through /sbin/hotplug.
  */
 void
-pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
+pci_announce_device_to_drivers(struct pci_dev *dev)
 {
 	struct list_head *ln;
 
-	list_add_tail(&dev->bus_list, &bus->devices);
-	list_add_tail(&dev->global_list, &pci_devices);
-#ifdef CONFIG_PROC_FS
-	pci_proc_attach_device(dev);
-#endif
 	for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
 		struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
 		if (drv->remove && pci_announce_device(drv, dev))
@@ -710,6 +705,24 @@
 	run_sbin_hotplug(dev, TRUE);
 }
 
+/**
+ * pci_insert_device - insert a hotplug device
+ * @dev: the device to insert
+ * @bus: where to insert it
+ *
+ * Add a new device to the device lists and notify userspace (/sbin/hotplug).
+ */
+void
+pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
+{
+	list_add_tail(&dev->bus_list, &bus->devices);
+	list_add_tail(&dev->global_list, &pci_devices);
+#ifdef CONFIG_PROC_FS
+	pci_proc_attach_device(dev);
+#endif
+	pci_announce_device_to_drivers(dev);
+}
+
 static void
 pci_free_resources(struct pci_dev *dev)
 {
@@ -951,7 +964,7 @@
 	}
 }
 
-void __init pci_read_bridge_bases(struct pci_bus *child)
+void __devinit  pci_read_bridge_bases(struct pci_bus *child)
 {
 	struct pci_dev *dev = child->self;
 	u8 io_base_lo, io_limit_lo;
@@ -1979,6 +1992,14 @@
 EXPORT_SYMBOL(pci_setup_device);
 EXPORT_SYMBOL(pci_insert_device);
 EXPORT_SYMBOL(pci_remove_device);
+EXPORT_SYMBOL(pci_announce_device_to_drivers);
+EXPORT_SYMBOL(pci_add_new_bus);
+EXPORT_SYMBOL(pci_do_scan_bus);
+EXPORT_SYMBOL(pci_scan_slot);
+EXPORT_SYMBOL(pci_proc_attach_device);
+EXPORT_SYMBOL(pci_proc_detach_device);
+EXPORT_SYMBOL(pci_proc_attach_bus);
+EXPORT_SYMBOL(pci_proc_detach_bus);
 #endif
 
 EXPORT_SYMBOL(pci_set_power_state);
diff -urN linux-2.4.15-pre3/drivers/pcmcia/Makefile linux/drivers/pcmcia/Makefile
--- linux-2.4.15-pre3/drivers/pcmcia/Makefile	Thu Oct 25 13:53:48 2001
+++ linux/drivers/pcmcia/Makefile	Mon Dec  3 23:28:58 2001
@@ -10,7 +10,7 @@
 
 O_TARGET := pcmcia.o
 
-export-objs := ds.o cs.o cb_enabler.o yenta.o pci_socket.o
+export-objs := ds.o cs.o yenta.o pci_socket.o
 
 list-multi := pcmcia_core.o yenta_socket.o
 
@@ -24,7 +24,7 @@
 ifeq ($(CONFIG_PCMCIA),y)
   obj-y   := cistpl.o rsrc_mgr.o bulkmem.o ds.o cs.o
   ifeq ($(CONFIG_CARDBUS),y)
-    obj-y += cardbus.o cb_enabler.o yenta.o pci_socket.o
+    obj-y += cardbus.o yenta.o pci_socket.o
   endif
   ifeq ($(CONFIG_I82365),y)
     obj-y += i82365.o
@@ -54,7 +54,7 @@
       obj-m += hd64465_ss.o
     endif
      ifeq ($(CONFIG_CARDBUS),y)
-	obj-m += yenta_socket.o cb_enabler.o
+	obj-m += yenta_socket.o
      endif
   endif
 endif
diff -urN linux-2.4.15-pre3/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c
--- linux-2.4.15-pre3/drivers/pcmcia/cardbus.c	Sat Mar  3 10:49:17 2001
+++ linux/drivers/pcmcia/cardbus.c	Mon Dec  3 23:28:58 2001
@@ -66,7 +66,6 @@
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
-#include "rsrc_mgr.h"
 
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
diff -urN linux-2.4.15-pre3/drivers/pcmcia/cb_enabler.c linux/drivers/pcmcia/cb_enabler.c
--- linux-2.4.15-pre3/drivers/pcmcia/cb_enabler.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/pcmcia/cb_enabler.c	Wed Dec 31 16:00:00 1969
@@ -1,403 +0,0 @@
-/*======================================================================
-
-    CardBus device enabler
-
-    cb_enabler.c 1.31 2000/06/12 21:29:36
-
-    The contents of this file are subject to the Mozilla Public
-    License Version 1.1 (the "License"); you may not use this file
-    except in compliance with the License. You may obtain a copy of
-    the License at http://www.mozilla.org/MPL/
-
-    Software distributed under the License is distributed on an "AS
-    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-    implied. See the License for the specific language governing
-    rights and limitations under the License.
-
-    The initial developer of the original code is David A. Hinds
-    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-
-    Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
-    above.  If you wish to allow the use of your version of this file
-    only under the terms of the GPL and not to allow others to use
-    your version of this file under the MPL, indicate your decision
-    by deleting the provisions above and replace them with the notice
-    and other provisions required by the GPL.  If you do not delete
-    the provisions above, a recipient may use your version of this
-    file under either the MPL or the GPL.
-    
-    The general idea:
-
-    A client driver registers using register_driver().  This module
-    then creates a Card Services pseudo-client and registers it, and
-    configures the socket if this is the first client.  It then
-    invokes the appropriate PCI client routines in response to Card
-    Services events.  
-
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-
-#include <pcmcia/version.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"cb_enabler.c 1.31 2000/06/12 21:29:36 (David Hinds)";
-#else
-#define DEBUG(n, args...) do { } while (0)
-#endif
-
-MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("CardBus stub enabler module");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-/*====================================================================*/
-
-typedef struct driver_info_t {
-    dev_link_t		*(*attach)(void);
-    dev_info_t		dev_info;
-    driver_operations	*ops;
-    dev_link_t		*dev_list;
-} driver_info_t;
-
-static dev_link_t *cb_attach(int n);
-#define MK_ENTRY(fn, n) \
-static dev_link_t *fn(void) { return cb_attach(n); }
-
-#define MAX_DRIVER	4
-
-MK_ENTRY(attach_0, 0);
-MK_ENTRY(attach_1, 1);
-MK_ENTRY(attach_2, 2);
-MK_ENTRY(attach_3, 3);
-
-static driver_info_t driver[4] = {
-    { attach_0 }, { attach_1 }, { attach_2 }, { attach_3 }
-};
-
-typedef struct bus_info_t {
-    u_char		bus;
-    int			flags, ncfg, nuse;
-    dev_link_t		*owner;
-} bus_info_t;
-
-#define DID_REQUEST	1
-#define DID_CONFIG	2
-
-static void cb_release(u_long arg);
-static int cb_event(event_t event, int priority,
-		    event_callback_args_t *args);
-
-static void cb_detach(dev_link_t *);
-
-static bus_info_t bus_table[MAX_DRIVER];
-
-/*====================================================================*/
-
-static void cs_error(client_handle_t handle, int func, int ret)
-{
-    error_info_t err = { func, ret };
-    pcmcia_report_error(handle, &err);
-}
-
-/*====================================================================*/
-
-struct dev_link_t *cb_attach(int n)
-{
-    client_reg_t client_reg;
-    dev_link_t *link;
-    int ret;
-    
-    DEBUG(0, "cb_attach(%d)\n", n);
-
-    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-    if (!link) return NULL;
-
-    MOD_INC_USE_COUNT;
-    memset(link, 0, sizeof(struct dev_link_t));
-    link->conf.IntType = INT_CARDBUS;
-    link->conf.Vcc = 33;
-
-    /* Insert into instance chain for this driver */
-    link->priv = &driver[n];
-    link->next = driver[n].dev_list;
-    driver[n].dev_list = link;
-    
-    /* Register with Card Services */
-    client_reg.dev_info = &driver[n].dev_info;
-    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-    client_reg.event_handler = &cb_event;
-    client_reg.EventMask = CS_EVENT_RESET_PHYSICAL |
-	CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.Version = 0x0210;
-    client_reg.event_callback_args.client_data = link;
-    ret = pcmcia_register_client(&link->handle, &client_reg);
-    if (ret != 0) {
-	cs_error(link->handle, RegisterClient, ret);
-	cb_detach(link);
-	return NULL;
-    }
-    return link;
-}
-
-/*====================================================================*/
-
-static void cb_detach(dev_link_t *link)
-{
-    driver_info_t *dev = link->priv;
-    dev_link_t **linkp;
-    bus_info_t *b = (void *)link->win;
-
-    DEBUG(0, "cb_detach(0x%p)\n", link);
-
-    /* Locate device structure */
-    for (linkp = &dev->dev_list; *linkp; linkp = &(*linkp)->next)
-	if (*linkp == link) break;
-    if (*linkp == NULL)
-	return;
-
-    if (link->state & DEV_CONFIG)
-	cb_release((u_long)link);
-
-    /* Don't drop Card Services connection if we are the bus owner */
-    if (b && (b->flags != 0) && (link == b->owner)) {
-	link->state |= DEV_STALE_LINK;
-	return;
-    }
-
-    if (link->handle)
-	pcmcia_deregister_client(link->handle);
-
-    *linkp = link->next;
-    kfree(link);
-    MOD_DEC_USE_COUNT;
-}
-
-/*====================================================================*/
-
-static void cb_config(dev_link_t *link)
-{
-    client_handle_t handle = link->handle;
-    driver_info_t *drv = link->priv;
-    dev_locator_t loc;
-    bus_info_t *b;
-    config_info_t config;
-    u_char bus, devfn;
-    int i;
-    
-    DEBUG(0, "cb_config(0x%p)\n", link);
-    link->state |= DEV_CONFIG;
-
-    /* Get PCI bus info */
-    pcmcia_get_configuration_info(handle, &config);
-    bus = config.Option; devfn = config.Function;
-
-    /* Is this a new bus? */
-    for (i = 0; i < MAX_DRIVER; i++)
-	if (bus == bus_table[i].bus) break;
-    if (i == MAX_DRIVER) {
-	for (i = 0; i < MAX_DRIVER; i++)
-	    if (bus_table[i].bus == 0) break;
-	b = &bus_table[i]; link->win = (void *)b;
-	b->bus = bus;
-	b->flags = 0;
-	b->ncfg = b->nuse = 1;
-
-	/* Special hook: CS know what to do... */
-	i = pcmcia_request_io(handle, NULL);
-	if (i != CS_SUCCESS) {
-	    cs_error(handle, RequestIO, i);
-	    return;
-	}
-	b->flags |= DID_REQUEST;
-	b->owner = link;
-	i = pcmcia_request_configuration(handle, &link->conf);
-	if (i != CS_SUCCESS) {
-	    cs_error(handle, RequestConfiguration, i);
-	    return;
-	}
-	b->flags |= DID_CONFIG;
-    } else {
-	b = &bus_table[i]; link->win = (void *)b;
-	if (b->flags & DID_CONFIG) {
-	    b->ncfg++; b->nuse++;
-	}
-    }
-    loc.bus = LOC_PCI;
-    loc.b.pci.bus = bus;
-    loc.b.pci.devfn = devfn;
-    link->dev = drv->ops->attach(&loc);
-    
-    link->state &= ~DEV_CONFIG_PENDING;
-}
-
-/*====================================================================*/
-
-static void cb_release(u_long arg)
-{
-    dev_link_t *link = (dev_link_t *)arg;
-    driver_info_t *drv = link->priv;
-    bus_info_t *b = (void *)link->win;
-
-    DEBUG(0, "cb_release(0x%p)\n", link);
-
-    if (link->dev != NULL) {
-	drv->ops->detach(link->dev);
-	link->dev = NULL;
-    }
-    if (link->state & DEV_CONFIG) {
-	/* If we're suspended, config was already released */
-	if (link->state & DEV_SUSPEND)
-	    b->flags &= ~DID_CONFIG;
-	else if ((b->flags & DID_CONFIG) && (--b->ncfg == 0)) {
-	    pcmcia_release_configuration(b->owner->handle);
-	    b->flags &= ~DID_CONFIG;
-	}
-	if ((b->flags & DID_REQUEST) && (--b->nuse == 0)) {
-	    pcmcia_release_io(b->owner->handle, NULL);
-	    b->flags &= ~DID_REQUEST;
-	}
-	if (b->flags == 0) {
-	    if (b->owner && (b->owner->state & DEV_STALE_LINK))
-		cb_detach(b->owner);
-	    b->bus = 0; b->owner = NULL;
-	}
-    }
-    link->state &= ~DEV_CONFIG;
-}
-
-/*====================================================================*/
-
-static int cb_event(event_t event, int priority,
-		    event_callback_args_t *args)
-{
-    dev_link_t *link = args->client_data;
-    driver_info_t *drv = link->priv;
-    bus_info_t *b = (void *)link->win;
-    
-    DEBUG(0, "cb_event(0x%06x)\n", event);
-    
-    switch (event) {
-    case CS_EVENT_CARD_REMOVAL:
-	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG)
-	    cb_release((u_long)link);
-	break;
-    case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	cb_config(link);
-	break;
-    case CS_EVENT_PM_SUSPEND:
-	link->state |= DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_RESET_PHYSICAL:
-	if (link->state & DEV_CONFIG) {
-	    if (drv->ops->suspend != NULL)
-		drv->ops->suspend(link->dev);
-	    b->ncfg--;
-	    if (b->ncfg == 0)
-		pcmcia_release_configuration(link->handle);
-	}
-	break;
-    case CS_EVENT_PM_RESUME:
-	link->state &= ~DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_CARD_RESET:
-	if (link->state & DEV_CONFIG) {
-	    b->ncfg++;
-	    if (b->ncfg == 1)
-		pcmcia_request_configuration(link->handle,
-			     &link->conf);
-	    if (drv->ops->resume != NULL)
-		drv->ops->resume(link->dev);
-	}
-	break;
-    }
-    return 0;
-}
-
-/*====================================================================*/
-
-int register_driver(struct driver_operations *ops)
-{
-    int i;
-    
-    DEBUG(0, "register_driver('%s')\n", ops->name);
-
-    for (i = 0; i < MAX_DRIVER; i++)
-	if (driver[i].ops == NULL) break;
-    if (i == MAX_DRIVER)
-	return -1;
-
-    MOD_INC_USE_COUNT;
-    driver[i].ops = ops;
-    strcpy(driver[i].dev_info, ops->name);
-    register_pccard_driver(&driver[i].dev_info, driver[i].attach,
-			   &cb_detach);
-    return 0;
-}
-
-void unregister_driver(struct driver_operations *ops)
-{
-    int i;
-
-    DEBUG(0, "unregister_driver('%s')\n", ops->name);
-    for (i = 0; i < MAX_DRIVER; i++)
-	if (driver[i].ops == ops) break;
-    if (i < MAX_DRIVER) {
-	unregister_pccard_driver(&driver[i].dev_info);
-	driver[i].ops = NULL;
-	MOD_DEC_USE_COUNT;
-    }
-}
-
-/*====================================================================*/
-
-EXPORT_SYMBOL(register_driver);
-EXPORT_SYMBOL(unregister_driver);
-
-static int __init init_cb_enabler(void)
-{
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    pcmcia_get_card_services_info(&serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "cb_enabler: Card Services release "
-	       "does not match!\n");
-	return -1;
-    }
-    return 0;
-}
-
-static void __exit exit_cb_enabler(void)
-{
-    DEBUG(0, "cb_enabler: unloading\n");
-}
-
-module_init(init_cb_enabler);
-module_exit(exit_cb_enabler);
-
-/*====================================================================*/
-
diff -urN linux-2.4.15-pre3/drivers/pcmcia/cistpl.c linux/drivers/pcmcia/cistpl.c
--- linux-2.4.15-pre3/drivers/pcmcia/cistpl.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/pcmcia/cistpl.c	Mon Dec  3 23:28:58 2001
@@ -2,7 +2,7 @@
 
     PCMCIA Card Information Structure parser
 
-    cistpl.c 1.91 2000/09/16 03:48:28
+    cistpl.c 1.97 2001/10/04 03:33:49
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -19,8 +19,8 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
     your version of this file under the MPL, indicate your decision
@@ -46,6 +46,7 @@
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <asm/io.h>
+#include <asm/byteorder.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/bus_ops.h>
@@ -55,7 +56,6 @@
 #include <pcmcia/cisreg.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
-#include "rsrc_mgr.h"
 
 static const u_char mantissa[] = {
     10, 12, 13, 15, 20, 25, 30, 35,
@@ -644,8 +644,6 @@
 	case 4: device->dev[i].speed = 100; break;
 	case 7:
 	    if (++p == q) return CS_BAD_TUPLE;
-	    if (p == q)
-		return CS_BAD_TUPLE;
 	    device->dev[i].speed = SPEED_CVT(*p);
 	    while (*p & 0x80)
 		if (++p == q) return CS_BAD_TUPLE;
diff -urN linux-2.4.15-pre3/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- linux-2.4.15-pre3/drivers/pcmcia/cs.c	Thu Oct 11 09:43:29 2001
+++ linux/drivers/pcmcia/cs.c	Mon Dec  3 23:28:58 2001
@@ -60,14 +60,6 @@
 #include <pcmcia/cisreg.h>
 #include <pcmcia/bus_ops.h>
 #include "cs_internal.h"
-#include "rsrc_mgr.h"
-
-#ifdef PCMCIA_DEBUG
-int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-static const char *version =
-"cs.c 1.271 2000/10/02 20:27:49 (David Hinds)";
-#endif
 
 #ifdef CONFIG_PCI
 #define PCI_OPT " [pci]"
@@ -93,15 +85,15 @@
 static const char *release = "Linux Kernel Card Services " CS_RELEASE;
 static const char *options = "options: " OPTIONS;
 
+/*====================================================================*/
+
+/* Module parameters */
+
 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
 MODULE_DESCRIPTION("Linux Kernel Card Services " CS_RELEASE
 		   "\n  options:" OPTIONS);
 MODULE_LICENSE("Dual MPL/GPL");	  
 
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 INT_MODULE_PARM(setup_delay,	10);		/* centiseconds */
@@ -126,6 +118,12 @@
 INT_MODULE_PARM(do_apm,		0);
 #endif
 
+#ifdef PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+static const char *version =
+"cs.c 1.279 2001/10/13 00:08:28 (David Hinds)";
+#endif
+ 
 /*====================================================================*/
 
 socket_state_t dead_socket = {
@@ -472,6 +470,15 @@
 	kfree(s->fake_cis);
 	s->fake_cis = NULL;
     }
+    /* Should not the socket be forced quiet as well?  e.g. turn off Vcc */
+    /* Without these changes, the socket is left hot, even though card-services */
+    /* realizes that no card is in place. */
+    s->socket.flags &= ~SS_OUTPUT_ENA;
+    s->socket.Vpp = 0;
+    s->socket.Vcc = 0;
+    s->socket.io_irq = 0;
+    set_socket(s, &s->socket);
+    /* */
 #ifdef CONFIG_CARDBUS
     cb_release_cis_mem(s);
     cb_free(s);
@@ -622,7 +629,7 @@
 
     The central event handler.  Send_event() sends an event to all
     valid clients.  Parse_events() interprets the event bits from
-    a card status change report.  Do_shotdown() handles the high
+    a card status change report.  Do_shutdown() handles the high
     priority stuff associated with a card removal.
     
 ======================================================================*/
@@ -1508,7 +1515,7 @@
     if (!(handle->state & CLIENT_STALE)) {
 	config_t *c = CONFIG(handle);
 	if (--(s->lock_count) == 0) {
-	    s->socket.flags = SS_OUTPUT_ENA;
+	    s->socket.flags = SS_OUTPUT_ENA;   /* Is this correct? */
 	    s->socket.Vpp = 0;
 	    s->socket.io_irq = 0;
 	    set_socket(s, &s->socket);
diff -urN linux-2.4.15-pre3/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-2.4.15-pre3/drivers/pcmcia/ds.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/pcmcia/ds.c	Mon Dec  3 23:28:58 2001
@@ -2,7 +2,7 @@
 
     PC Card Driver Services
     
-    ds.c 1.108 2000/08/07 19:06:15
+    ds.c 1.112 2001/10/13 00:08:28
     
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -19,8 +19,8 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
     your version of this file under the MPL, indicate your decision
@@ -56,20 +56,24 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
+/*====================================================================*/
+
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE);
+MODULE_LICENSE("Dual MPL/GPL");
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+
 #ifdef PCMCIA_DEBUG
-int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
+INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static const char *version =
-"ds.c 1.108 2000/08/07 19:06:15 (David Hinds)";
+"ds.c 1.112 2001/10/13 00:08:28 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
-
-MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE);
-MODULE_LICENSE("Dual MPL/GPL");
-
 
 /*====================================================================*/
 
diff -urN linux-2.4.15-pre3/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c
--- linux-2.4.15-pre3/drivers/pcmcia/i82365.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/pcmcia/i82365.c	Mon Dec  3 23:28:58 2001
@@ -66,11 +66,6 @@
 #include "ricoh.h"
 #include "o2micro.h"
 
-/* PCI-bus controllers */
-#include "old-yenta.h"
-#include "smc34c90.h"
-#include "topic.h"
-
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
 MODULE_PARM(pc_debug, "i");
diff -urN linux-2.4.15-pre3/drivers/pcmcia/old-yenta.h linux/drivers/pcmcia/old-yenta.h
--- linux-2.4.15-pre3/drivers/pcmcia/old-yenta.h	Fri Feb 16 16:02:36 2001
+++ linux/drivers/pcmcia/old-yenta.h	Wed Dec 31 16:00:00 1969
@@ -1,153 +0,0 @@
-/*
- * yenta.h 1.16 1999/10/25 20:03:34
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License. 
- *
- * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
- * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use
- * your version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#ifndef _LINUX_YENTA_H
-#define _LINUX_YENTA_H
-
-/* PCI Configuration Registers */
-
-#define PCI_STATUS_CAPLIST		0x10
-#define PCI_CB_CAPABILITY_POINTER	0x14	/* 8 bit */
-#define PCI_CAPABILITY_ID		0x00	/* 8 bit */
-#define  PCI_CAPABILITY_PM		0x01
-#define PCI_NEXT_CAPABILITY		0x01	/* 8 bit */
-#define PCI_PM_CAPABILITIES		0x02	/* 16 bit */
-#define  PCI_PMCAP_PME_D3COLD		0x8000
-#define  PCI_PMCAP_PME_D3HOT		0x4000
-#define  PCI_PMCAP_PME_D2		0x2000
-#define  PCI_PMCAP_PME_D1		0x1000
-#define  PCI_PMCAP_PME_D0		0x0800
-#define  PCI_PMCAP_D2_CAP		0x0400
-#define  PCI_PMCAP_D1_CAP		0x0200
-#define  PCI_PMCAP_DYN_DATA		0x0100
-#define  PCI_PMCAP_DSI			0x0020
-#define  PCI_PMCAP_AUX_PWR		0x0010
-#define  PCI_PMCAP_PMECLK		0x0008
-#define  PCI_PMCAP_VERSION_MASK		0x0007
-#define PCI_PM_CONTROL_STATUS		0x04	/* 16 bit */
-#define  PCI_PMCS_PME_STATUS		0x8000
-#define  PCI_PMCS_DATASCALE_MASK	0x6000
-#define  PCI_PMCS_DATASCALE_SHIFT	13
-#define  PCI_PMCS_DATASEL_MASK		0x1e00
-#define  PCI_PMCS_DATASEL_SHIFT		9
-#define  PCI_PMCS_PME_ENABLE		0x0100
-#define  PCI_PMCS_PWR_STATE_MASK	0x0003
-#define  PCI_PMCS_PWR_STATE_D0		0x0000
-#define  PCI_PMCS_PWR_STATE_D1		0x0001
-#define  PCI_PMCS_PWR_STATE_D2		0x0002
-#define  PCI_PMCS_PWR_STATE_D3		0x0003
-#define PCI_PM_BRIDGE_EXT		0x06	/* 8 bit */
-#define PCI_PM_DATA			0x07	/* 8 bit */
-
-#define CB_PRIMARY_BUS			0x18	/* 8 bit */
-#define CB_CARDBUS_BUS			0x19	/* 8 bit */
-#define CB_SUBORD_BUS			0x1a	/* 8 bit */
-#define CB_LATENCY_TIMER		0x1b	/* 8 bit */
-
-#define CB_MEM_BASE(m)			(0x1c + 8*(m))
-#define CB_MEM_LIMIT(m)			(0x20 + 8*(m))
-#define CB_IO_BASE(m)			(0x2c + 8*(m))
-#define CB_IO_LIMIT(m)			(0x30 + 8*(m))
-
-#define CB_BRIDGE_CONTROL		0x3e	/* 16 bit */
-#define  CB_BCR_PARITY_ENA		0x0001
-#define  CB_BCR_SERR_ENA		0x0002
-#define  CB_BCR_ISA_ENA			0x0004
-#define  CB_BCR_VGA_ENA			0x0008
-#define  CB_BCR_MABORT			0x0020
-#define  CB_BCR_CB_RESET		0x0040
-#define  CB_BCR_ISA_IRQ			0x0080
-#define  CB_BCR_PREFETCH(m)		(0x0100 << (m))
-#define  CB_BCR_WRITE_POST		0x0400
-
-#define CB_LEGACY_MODE_BASE		0x44
-
-/* Memory mapped registers */
-
-#define CB_SOCKET_EVENT			0x0000
-#define  CB_SE_CSTSCHG			0x00000001
-#define  CB_SE_CCD1			0x00000002
-#define  CB_SE_CCD2			0x00000004
-#define  CB_SE_PWRCYCLE			0x00000008
-
-#define CB_SOCKET_MASK			0x0004
-#define  CB_SM_CSTSCHG			0x00000001
-#define  CB_SM_CCD			0x00000006
-#define  CB_SM_PWRCYCLE			0x00000008
-
-#define CB_SOCKET_STATE			0x0008
-#define  CB_SS_CSTSCHG			0x00000001
-#define  CB_SS_CCD1			0x00000002
-#define  CB_SS_CCD2			0x00000004
-#define  CB_SS_PWRCYCLE			0x00000008
-#define  CB_SS_16BIT			0x00000010
-#define  CB_SS_32BIT			0x00000020
-#define  CB_SS_CINT			0x00000040
-#define  CB_SS_BADCARD			0x00000080
-#define  CB_SS_DATALOST			0x00000100
-#define  CB_SS_BADVCC			0x00000200
-#define  CB_SS_5VCARD			0x00000400
-#define  CB_SS_3VCARD			0x00000800
-#define  CB_SS_XVCARD			0x00001000
-#define  CB_SS_YVCARD			0x00002000
-#define  CB_SS_5VSOCKET			0x10000000
-#define  CB_SS_3VSOCKET			0x20000000
-#define  CB_SS_XVSOCKET			0x40000000
-#define  CB_SS_YVSOCKET			0x80000000
-
-#define CB_SOCKET_FORCE			0x000c
-#define  CB_SF_CVSTEST			0x00004000
-
-#define CB_SOCKET_CONTROL		0x0010
-#define  CB_SC_VPP_MASK			0x00000007
-#define   CB_SC_VPP_OFF			0x00000000
-#define   CB_SC_VPP_12V			0x00000001
-#define   CB_SC_VPP_5V			0x00000002
-#define   CB_SC_VPP_3V			0x00000003
-#define   CB_SC_VPP_XV			0x00000004
-#define   CB_SC_VPP_YV			0x00000005
-#define  CB_SC_VCC_MASK			0x00000070
-#define   CB_SC_VCC_OFF			0x00000000
-#define   CB_SC_VCC_5V			0x00000020
-#define   CB_SC_VCC_3V			0x00000030
-#define   CB_SC_VCC_XV			0x00000040
-#define   CB_SC_VCC_YV			0x00000050
-#define  CB_SC_CCLK_STOP		0x00000080
-
-#define CB_SOCKET_POWER			0x0020
-#define  CB_SP_CLK_CTRL			0x00000001
-#define  CB_SP_CLK_CTRL_ENA		0x00010000
-#define  CB_SP_CLK_MODE			0x01000000
-#define  CB_SP_ACCESS			0x02000000
-
-/* Address bits 31..24 for memory windows for 16-bit cards,
-   accessable only by memory mapping the 16-bit register set */
-#define CB_MEM_PAGE(map)		(0x40 + (map))
-
-#endif /* _LINUX_YENTA_H */
diff -urN linux-2.4.15-pre3/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c
--- linux-2.4.15-pre3/drivers/pcmcia/rsrc_mgr.c	Sun Jul 15 16:22:23 2001
+++ linux/drivers/pcmcia/rsrc_mgr.c	Mon Dec  3 23:28:58 2001
@@ -53,7 +53,6 @@
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
-#include "rsrc_mgr.h"
 
 /*====================================================================*/
 
diff -urN linux-2.4.15-pre3/drivers/pcmcia/rsrc_mgr.h linux/drivers/pcmcia/rsrc_mgr.h
--- linux-2.4.15-pre3/drivers/pcmcia/rsrc_mgr.h	Fri Feb 16 16:02:36 2001
+++ linux/drivers/pcmcia/rsrc_mgr.h	Wed Dec 31 16:00:00 1969
@@ -1,33 +0,0 @@
-/*
- * rsrc_mgr.h 1.20 2000/06/12 21:29:37
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License. 
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
- * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use
- * your version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#ifndef _RSRC_MGR_H
-#define _RSRC_MGR_H
-
-#endif	/* _RSRC_MGR_H */
diff -urN linux-2.4.15-pre3/drivers/pcmcia/smc34c90.h linux/drivers/pcmcia/smc34c90.h
--- linux-2.4.15-pre3/drivers/pcmcia/smc34c90.h	Fri Feb 16 16:02:36 2001
+++ linux/drivers/pcmcia/smc34c90.h	Wed Dec 31 16:00:00 1969
@@ -1,52 +0,0 @@
-/*
- * smc34c90.h 1.7 1999/10/25 20:03:34
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License. 
- *
- * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
- * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use
- * your version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#ifndef _LINUX_SMC34C90_H
-#define _LINUX_SMC34C90_H
-
-#ifndef PCI_VENDOR_ID_SMC
-#define PCI_VENDOR_ID_SMC		0x10b3
-#endif
-
-#ifndef PCI_DEVICE_ID_SMC_34C90
-#define PCI_DEVICE_ID_SMC_34C90		0xb106
-#endif
-
-/* Register definitions for SMC 34C90 PCI-to-CardBus bridge */
-
-/* EEPROM Information Register */
-#define SMC34C90_EEINFO			0x0088
-#define SMC34C90_EEINFO_ONE_SOCKET	0x0001
-#define SMC34C90_EEINFO_5V_ONLY		0x0002
-#define SMC34C90_EEINFO_ISA_IRQ		0x0004
-#define SMC34C90_EEINFO_ZV_PORT		0x0008
-#define SMC34C90_EEINFO_RING		0x0010
-#define SMC34C90_EEINFO_LED		0x0020
-
-#endif /* _LINUX_SMC34C90_H */
diff -urN linux-2.4.15-pre3/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c
--- linux-2.4.15-pre3/drivers/pnp/isapnp.c	Thu Oct 11 09:43:29 2001
+++ linux/drivers/pnp/isapnp.c	Mon Dec  3 23:28:58 2001
@@ -25,6 +25,9 @@
  *  2001-06-03  Added release_region calls to correspond with
  *		request_region calls when a failure occurs.  Also
  *		added KERN_* constants to printk() calls.
+ *  2001-11-07  Added isapnp_{,un}register_driver calls along the lines
+ *              of the pci driver interface
+ *              Kai Germaschewski <kai.germaschewski@gmx.de>
  */
 
 #include <linux/config.h>
@@ -2162,6 +2165,89 @@
 #endif
 }
 
+static int isapnp_announce_device(struct isapnp_driver *drv, 
+				  struct pci_dev *dev)
+{
+	const struct isapnp_device_id *id;
+	int ret = 0;
+
+	if (drv->id_table) {
+		id = isapnp_match_dev(drv->id_table, dev);
+		if (!id) {
+			ret = 0;
+			goto out;
+		}
+	} else
+		id = NULL;
+
+	if (drv->probe(dev, id) >= 0) {
+		dev->driver = (struct pci_driver *) drv;
+		ret = 1;
+	}
+out:
+	return ret;
+}
+
+/**
+ * isapnp_dev_driver - get the isapnp_driver of a device
+ * @dev: the device to query
+ *
+ * Returns the appropriate isapnp_driver structure or %NULL if there is no 
+ * registered driver for the device.
+ */
+static struct isapnp_driver *isapnp_dev_driver(const struct pci_dev *dev)
+{
+	return (struct isapnp_driver *) dev->driver;
+}
+
+static LIST_HEAD(isapnp_drivers);
+
+/**
+ * isapnp_register_driver - register a new ISAPnP driver
+ * @drv: the driver structure to register
+ * 
+ * Adds the driver structure to the list of registered ISAPnP drivers
+ * Returns the number of isapnp devices which were claimed by the driver
+ * during registration.  The driver remains registered even if the
+ * return value is zero.
+ */
+int isapnp_register_driver(struct isapnp_driver *drv)
+{
+	struct pci_dev *dev;
+	int count = 0;
+
+	list_add_tail(&drv->node, &isapnp_drivers);
+
+	isapnp_for_each_dev(dev) {
+		if (!isapnp_dev_driver(dev))
+			count += isapnp_announce_device(drv, dev);
+	}
+	return count;
+}
+
+/**
+ * isapnp_unregister_driver - unregister an isapnp driver
+ * @drv: the driver structure to unregister
+ * 
+ * Deletes the driver structure from the list of registered ISAPnP drivers,
+ * gives it a chance to clean up by calling its remove() function for
+ * each device it was responsible for, and marks those devices as
+ * driverless.
+ */
+void isapnp_unregister_driver(struct isapnp_driver *drv)
+{
+	struct pci_dev *dev;
+
+	list_del(&drv->node);
+	isapnp_for_each_dev(dev) {
+		if (dev->driver == (struct pci_driver *) drv) {
+			if (drv->remove)
+				drv->remove(dev);
+			dev->driver = NULL;
+		}
+	}
+}
+
 EXPORT_SYMBOL(isapnp_cards);
 EXPORT_SYMBOL(isapnp_devices);
 EXPORT_SYMBOL(isapnp_present);
@@ -2183,6 +2269,8 @@
 EXPORT_SYMBOL(isapnp_probe_devs);
 EXPORT_SYMBOL(isapnp_activate_dev);
 EXPORT_SYMBOL(isapnp_resource_change);
+EXPORT_SYMBOL(isapnp_register_driver);
+EXPORT_SYMBOL(isapnp_unregister_driver);
 
 int __init isapnp_init(void)
 {
diff -urN linux-2.4.15-pre3/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c
--- linux-2.4.15-pre3/drivers/sound/ac97_codec.c	Mon Dec  3 23:28:49 2001
+++ linux/drivers/sound/ac97_codec.c	Mon Dec  3 23:28:58 2001
@@ -1019,4 +1019,31 @@
 }
 
 EXPORT_SYMBOL(ac97_set_adc_rate);
+
+int ac97_save_state(struct ac97_codec *codec)
+{
+	return 0;	
+}
+
+EXPORT_SYMBOL(ac97_save_state);
+
+int ac97_restore_state(struct ac97_codec *codec)
+{
+	int i;
+	unsigned int left, right, val;
+
+	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+		if (!supported_mixer(codec, i)) 
+			continue;
+
+		val = codec->mixer_state[i];
+		right = val >> 8;
+		left = val  & 0xff;
+		codec->write_mixer(codec, i, left, right);
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(ac97_restore_state);
+
 MODULE_LICENSE("GPL");
diff -urN linux-2.4.15-pre3/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- linux-2.4.15-pre3/drivers/sound/ymfpci.c	Mon Oct 22 08:38:18 2001
+++ linux/drivers/sound/ymfpci.c	Mon Dec  3 23:28:59 2001
@@ -1824,7 +1824,7 @@
 	}
 
 	unit = NULL;	/* gcc warns */
-	for (list = ymf_devs.next; list != &ymf_devs; list = list->next) {
+	list_for_each(list, &ymf_devs) {
 		unit = list_entry(list, ymfpci_t, ymf_devs);
 		if (((unit->dev_audio ^ minor) & ~0x0F) == 0)
 			break;
@@ -1935,7 +1935,7 @@
 	struct list_head *list;
 	ymfpci_t *unit;
 
-	for (list = ymf_devs.next; list != &ymf_devs; list = list->next) {
+	list_for_each(list, &ymf_devs) {
 		unit = list_entry(list, ymfpci_t, ymf_devs);
 		for (i = 0; i < NR_AC97; i++) {
 			if (unit->ac97_codec[i] != NULL &&
@@ -1990,16 +1990,25 @@
 
 static int ymf_suspend(struct pci_dev *pcidev, u32 unused)
 {
+	int i;
 	struct ymf_unit *unit = pci_get_drvdata(pcidev);
 	unsigned long flags;
 	struct ymf_dmabuf *dmabuf;
 	struct list_head *p;
 	struct ymf_state *state;
+	struct ac97_codec *codec;
 
 	spin_lock_irqsave(&unit->reg_lock, flags);
 
 	unit->suspended = 1;
 
+	for (i = 0; i < NR_AC97; i++) {
+		codec = unit->ac97_codec[i];
+		if (!codec)
+			continue;
+		ac97_save_state(codec);
+	}
+
 	list_for_each(p, &unit->states) {
 		state = list_entry(p, struct ymf_state, chain);
 
@@ -2024,13 +2033,22 @@
 
 static int ymf_resume(struct pci_dev *pcidev)
 {
+	int i;
 	struct ymf_unit *unit = pci_get_drvdata(pcidev);
 	unsigned long flags;
 	struct list_head *p;
 	struct ymf_state *state;
+	struct ac97_codec *codec;
 
 	ymfpci_aclink_reset(unit->pci);
 	ymfpci_codec_ready(unit, 0, 1);		/* prints diag if not ready. */
+
+	for (i = 0; i < NR_AC97; i++) {
+		codec = unit->ac97_codec[i];
+		if (!codec)
+			continue;
+		ac97_restore_state(codec);
+	}
 
 #ifdef CONFIG_SOUND_YMFPCI_LEGACY
 	/* XXX At this time the legacy registers are probably deprogrammed. */
diff -urN linux-2.4.15-pre3/drivers/usb/hub.c linux/drivers/usb/hub.c
--- linux-2.4.15-pre3/drivers/usb/hub.c	Tue Oct  9 15:15:02 2001
+++ linux/drivers/usb/hub.c	Mon Dec  3 23:28:59 2001
@@ -356,7 +356,7 @@
 
 	INIT_LIST_HEAD(&hub->event_list);
 	hub->dev = dev;
-	atomic_set(&hub->refcnt, 1);
+	init_MUTEX(&hub->khubd_sem);
 
 	/* Record the new hub's existence */
 	spin_lock_irqsave(&hub_event_lock, flags);
@@ -385,34 +385,11 @@
 	return NULL;
 }
 
-static void hub_get(struct usb_hub *hub)
-{
-	atomic_inc(&hub->refcnt);
-}
-
-static void hub_put(struct usb_hub *hub)
-{
-	if (atomic_dec_and_test(&hub->refcnt)) {
-		if (hub->descriptor) {
-			kfree(hub->descriptor);
-			hub->descriptor = NULL;
-		}
-
-		kfree(hub);
-	}
-}
-
 static void hub_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct usb_hub *hub = (struct usb_hub *)ptr;
 	unsigned long flags;
 
-	if (hub->urb) {
-		usb_unlink_urb(hub->urb);
-		usb_free_urb(hub->urb);
-		hub->urb = NULL;
-	}
-
 	spin_lock_irqsave(&hub_event_lock, flags);
 
 	/* Delete it and then reset it */
@@ -423,7 +400,22 @@
 
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 
-	hub_put(hub);
+	down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */
+	up(&hub->khubd_sem);
+
+	if (hub->urb) {
+		usb_unlink_urb(hub->urb);
+		usb_free_urb(hub->urb);
+		hub->urb = NULL;
+	}
+
+	if (hub->descriptor) {
+		kfree(hub->descriptor);
+		hub->descriptor = NULL;
+	}
+
+	/* Free the memory */
+	kfree(hub);
 }
 
 static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data)
@@ -534,10 +526,6 @@
 		dbg("port %d, portstatus %x, change %x, %s", port + 1,
 			portstatus, portchange, portspeed (portstatus));
 
-		/* Device went away? */
-		if (!(portstatus & USB_PORT_STAT_CONNECTION))
-			return 1;
-
 		/* bomb out completely if something weird happened */
 		if ((portchange & USB_PORT_STAT_C_CONNECTION))
 			return -1;
@@ -745,7 +733,7 @@
 		list_del(tmp);
 		INIT_LIST_HEAD(tmp);
 
-		hub_get(hub);
+		down(&hub->khubd_sem); /* never blocks, we were on list */
 		spin_unlock_irqrestore(&hub_event_lock, flags);
 
 		if (hub->error) {
@@ -753,8 +741,8 @@
 
 			if (usb_hub_reset(hub)) {
 				err("error resetting hub %d - disconnecting", dev->devnum);
+				up(&hub->khubd_sem);
 				usb_hub_disconnect(dev);
-				hub_put(hub);
 				continue;
 			}
 
@@ -830,7 +818,7 @@
                         	usb_hub_power_on(hub);
 			}
 		}
-		hub_put(hub);
+		up(&hub->khubd_sem);
         } /* end while (1) */
 
 	spin_unlock_irqrestore(&hub_event_lock, flags);
diff -urN linux-2.4.15-pre3/drivers/usb/hub.h linux/drivers/usb/hub.h
--- linux-2.4.15-pre3/drivers/usb/hub.h	Mon Nov  5 12:45:05 2001
+++ linux/drivers/usb/hub.h	Mon Dec  3 23:28:59 2001
@@ -135,7 +135,7 @@
 
 	struct usb_hub_descriptor *descriptor;
 
-	atomic_t refcnt;
+	struct semaphore khubd_sem;
 };
 
-#endif
+#endif /* __LINUX_HUB_H */
diff -urN linux-2.4.15-pre3/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.15-pre3/drivers/usb/serial/ftdi_sio.c	Sat Oct 20 19:13:11 2001
+++ linux/drivers/usb/serial/ftdi_sio.c	Mon Dec  3 23:28:59 2001
@@ -12,9 +12,18 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
- * See http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date testing info
+ * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *     and extra documentation
  * 
+ * (04/Nov/2001) Bill Ryder
+ *     Fixed bug in read_bulk_callback where incorrect urb buffer was used.
+ *     cleaned up write offset calculation
+ *     added write_room since default values can be incorrect for sio
+ *     changed write_bulk_callback to use same queue_task as other drivers
+ *       (the previous version caused panics)
+ *     Removed port iteration code since the device only has one I/O port and it 
+ *       was wrong anyway.
+ * 
  * (31/May/2001) gkh
  *	switched from using spinlock to a semaphore, which fixes lots of problems.
  *
@@ -97,7 +106,6 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/usb.h>
-
 #ifdef CONFIG_USB_SERIAL_DEBUG
 	static int debug = 1;
 #else
@@ -111,7 +119,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.1.0"
+#define DRIVER_VERSION "v1.2.0"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>"
 #define DRIVER_DESC "USB FTDI RS232 Converters Driver"
 
@@ -146,6 +154,7 @@
 struct ftdi_private {
 	ftdi_type_t ftdi_type;
 	__u16 last_set_data_urb_value ; /* the last data state set - needed for doing a break */
+        int write_offset;
 };
 /* function prototypes for a FTDI serial converter */
 static int  ftdi_sio_startup		(struct usb_serial *serial);
@@ -154,6 +163,7 @@
 static int  ftdi_sio_open		(struct usb_serial_port *port, struct file *filp);
 static void ftdi_sio_close		(struct usb_serial_port *port, struct file *filp);
 static int  ftdi_sio_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int  ftdi_sio_write_room		(struct usb_serial_port *port);
 static void ftdi_sio_write_bulk_callback (struct urb *urb);
 static void ftdi_sio_read_bulk_callback	(struct urb *urb);
 static void ftdi_sio_set_termios	(struct usb_serial_port *port, struct termios * old);
@@ -176,6 +186,7 @@
 	open:			ftdi_sio_open,
 	close:			ftdi_sio_close,
 	write:			ftdi_sio_write,
+	write_room:		ftdi_sio_write_room,
 	read_bulk_callback:	ftdi_sio_read_bulk_callback,
 	write_bulk_callback:	ftdi_sio_write_bulk_callback,
 	ioctl:			ftdi_sio_ioctl,
@@ -198,6 +209,7 @@
 	open:			ftdi_sio_open,
 	close:			ftdi_sio_close,
 	write:			ftdi_sio_write,
+	write_room:		ftdi_sio_write_room,
 	read_bulk_callback:	ftdi_sio_read_bulk_callback,
 	write_bulk_callback:	ftdi_sio_write_bulk_callback,
 	ioctl:			ftdi_sio_ioctl,
@@ -252,7 +264,6 @@
 {
 	struct ftdi_private *priv;
 	
-	init_waitqueue_head(&serial->port[0].write_wait);
 	
 	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
 	if (!priv){
@@ -261,6 +272,7 @@
 	}
 
 	priv->ftdi_type = sio;
+	priv->write_offset = 1;
 	
 	return (0);
 }
@@ -270,7 +282,6 @@
 {
 	struct ftdi_private *priv;
  
-	init_waitqueue_head(&serial->port[0].write_wait);
 
 	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
 	if (!priv){
@@ -279,6 +290,7 @@
 	}
 
 	priv->ftdi_type = F8U232AM;
+	priv->write_offset = 0;
 	
 	return (0);
 }
@@ -288,13 +300,14 @@
 	
 	dbg (__FUNCTION__);
 
-	/* Close ports if they are open */
+
+	/* stop reads and writes on all ports */
 	while (serial->port[0].open_count > 0) {
-		ftdi_sio_close (&serial->port[0], NULL);
+	        ftdi_sio_close (&serial->port[0], NULL);
 	}
-	if (serial->port->private){
-		kfree(serial->port->private);
-		serial->port->private = NULL;
+	if (serial->port[0].private){
+		kfree(serial->port[0].private);
+		serial->port[0].private = NULL;
 	}
 }
 
@@ -361,7 +374,7 @@
 
 static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
 { /* ftdi_sio_close */
-	struct usb_serial *serial = port->serial;
+	struct usb_serial *serial = port->serial; /* Checked in usbserial.c */
 	unsigned int c_cflag = port->tty->termios->c_cflag;
 	char buf[1];
 
@@ -393,6 +406,7 @@
 			} /* Note change no line is hupcl is off */
 
 			/* shutdown our bulk reads and writes */
+			/* ***CHECK*** behaviour when there is nothing queued */
 			usb_unlink_urb (port->write_urb);
 			usb_unlink_urb (port->read_urb);
 		}
@@ -403,7 +417,6 @@
 		if (!(port->tty->termios->c_cflag & CLOCAL)){
 			tty_hangup(port->tty);
 		}
-		
 	}
 
 	up (&port->sem);
@@ -423,10 +436,10 @@
 { /* ftdi_sio_write */
 	struct usb_serial *serial = port->serial;
 	struct ftdi_private *priv = (struct ftdi_private *)port->private;
+	unsigned char *first_byte = port->write_urb->transfer_buffer;
+	unsigned char dbug_byte;
 	int data_offset ;
-	int rc; 
 	int result;
-	DECLARE_WAITQUEUE(wait, current);
 	
 	dbg(__FUNCTION__ " port %d, %d bytes", port->number, count);
 
@@ -435,95 +448,70 @@
 		return 0;
 	}
 	
-	if (priv->ftdi_type == sio){
-		data_offset = 1;
-	} else {
-		data_offset = 0;
-	}
+	data_offset = priv->write_offset;
         dbg("data_offset set to %d",data_offset);
 
-	/* only do something if we have a bulk out endpoint */
-	if (serial->num_bulk_out) {
-		unsigned char *first_byte = port->write_urb->transfer_buffer;
-
-		/* Was seeing a race here, got a read callback, then write callback before
-		   hitting interuptible_sleep_on  - so wrapping in a wait_queue */
-
-		add_wait_queue(&port->write_wait, &wait);
-		set_current_state (TASK_INTERRUPTIBLE);
-		while (port->write_urb->status == -EINPROGRESS) {
-			dbg(__FUNCTION__ " write in progress - retrying");
-			if (signal_pending(current)) {
-				set_current_state(TASK_RUNNING);
-				remove_wait_queue(&port->write_wait, &wait);
-				rc = -ERESTARTSYS;
-				goto err;
-			}
-			schedule();
-		}		
-		remove_wait_queue(&port->write_wait, &wait);
-		set_current_state(TASK_RUNNING);
-
-		count += data_offset;
-		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-		if (count == 0) {
-			return 0;
-		}
+	if (port->write_urb->status == -EINPROGRESS) {
+		dbg (__FUNCTION__ " - already writing");
+		return (0);
+	}		
+
+	down(&port->sem);
+
+	count += data_offset;
+	count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 
 		/* Copy in the data to send */
-		if (from_user) {
-			if (copy_from_user(port->write_urb->transfer_buffer + data_offset,
-					   buf, count - data_offset ))
-				return -EFAULT;
-		}
-		else {
-			memcpy(port->write_urb->transfer_buffer + data_offset,
-			       buf, count - data_offset );
-		}  
-
-		first_byte = port->write_urb->transfer_buffer;
-		if (data_offset > 0){
-			/* Write the control byte at the front of the packet*/
-			*first_byte = 1 | ((count-data_offset) << 2) ; 
+	if (from_user) {
+		if (copy_from_user(port->write_urb->transfer_buffer + data_offset,
+				   buf, count - data_offset )){
+			up (&port->sem);
+			return -EFAULT;
 		}
+	} else {
+		memcpy(port->write_urb->transfer_buffer + data_offset,
+		       buf, count - data_offset );
+	}  
+
+	first_byte = port->write_urb->transfer_buffer;
+	if (data_offset > 0){
+		/* Write the control byte at the front of the packet*/
+		*first_byte = 1 | ((count-data_offset) << 2) ; 
+	}
 
-		dbg(__FUNCTION__ " Bytes: %d, First Byte: 0o%03o",count, first_byte[0]);
-		usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte);
+	dbg(__FUNCTION__ " Bytes: %d, First Byte: 0x%02x",count, first_byte[0]);
+	usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte);
 		
-		/* send the data out the bulk port */
-		FILL_BULK_URB(port->write_urb, serial->dev, 
-			      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
-			      port->write_urb->transfer_buffer, count,
-			      ftdi_sio_write_bulk_callback, port);
+	/* send the data out the bulk port */
+	FILL_BULK_URB(port->write_urb, serial->dev, 
+		      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+		      port->write_urb->transfer_buffer, count,
+		      ftdi_sio_write_bulk_callback, port);
 		
-		result = usb_submit_urb(port->write_urb);
-		if (result) {
-			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
-			return 0;
-		}
-
-		dbg(__FUNCTION__ " write returning: %d", count - data_offset);
-		return (count - data_offset);
+	result = usb_submit_urb(port->write_urb);
+	if (result) {
+		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+		up (&port->sem);
+		return 0;
 	}
-	
-	/* no bulk out, so return 0 bytes written */
-	return 0;
- err: /* error exit */
-	return(rc);
+	up (&port->sem);
+
+	dbg(__FUNCTION__ " write returning: %d", count - data_offset);
+	return (count - data_offset);
+
 } /* ftdi_sio_write */
 
 static void ftdi_sio_write_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct usb_serial *serial;
-       	struct tty_struct *tty = port->tty;
 
 	dbg("ftdi_sio_write_bulk_callback");
 
 	if (port_paranoia_check (port, "ftdi_sio_write_bulk_callback")) {
 		return;
 	}
-
+	
 	serial = port->serial;
 	if (serial_paranoia_check (serial, "ftdi_sio_write_bulk_callback")) {
 		return;
@@ -533,16 +521,29 @@
 		dbg("nonzero write bulk status received: %d", urb->status);
 		return;
 	}
+	queue_task(&port->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
 
-	wake_up_interruptible(&port->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-
-	wake_up_interruptible(&tty->write_wait);
-	
 	return;
 } /* ftdi_sio_write_bulk_callback */
 
+
+static int ftdi_sio_write_room( struct usb_serial_port *port )
+{
+	struct ftdi_private *priv = (struct ftdi_private *)port->private;
+	int room;
+	if ( port->write_urb->status == -EINPROGRESS) {
+		/* There is a race here with the _write routines but it won't hurt */
+		room = 0;
+	} else { 
+		room = port->bulk_out_size - priv->write_offset;
+	}
+	return(room);
+
+
+} /* ftdi_sio_write_room */
+
+
 static void ftdi_sio_read_bulk_callback (struct urb *urb)
 { /* ftdi_sio_serial_buld_callback */
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -555,7 +556,7 @@
 	int i;
 	int result;
 
-	dbg(__FUNCTION__);
+	dbg(__FUNCTION__ " - port %d", port->number);
 
 	if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
 		return;
@@ -647,12 +648,12 @@
 #endif
 
 	/* Continue trying to always read  */
-	FILL_BULK_URB(urb, serial->dev, 
+	FILL_BULK_URB(port->read_urb, serial->dev, 
 		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-		      urb->transfer_buffer, urb->transfer_buffer_length,
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
 		      ftdi_sio_read_bulk_callback, port);
 
-	result = usb_submit_urb(urb);
+	result = usb_submit_urb(port->read_urb);
 	if (result)
 		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 
diff -urN linux-2.4.15-pre3/drivers/usb/serial/ir-usb.c linux/drivers/usb/serial/ir-usb.c
--- linux-2.4.15-pre3/drivers/usb/serial/ir-usb.c	Fri Nov  2 17:18:58 2001
+++ linux/drivers/usb/serial/ir-usb.c	Mon Dec  3 23:28:59 2001
@@ -17,9 +17,13 @@
  * Portions of this driver were taken from drivers/net/irda/irda-usb.c, which
  * was written by Roman Weissgaerber <weissg@vienna.at>, Dag Brattli
  * <dag@brattli.net>, and Jean Tourrilhes <jt@hpl.hp.com>
-
+ *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * 2001_Nov_08  greg kh
+ *	Changed the irda_usb_find_class_desc() function based on comments and
+ *	code from Martin Diehl.
+ *
  * 2001_Nov_01	greg kh
  *	Added support for more IrDA USB devices.
  *	Added support for zero packet.  Added buffer override paramater, so
@@ -58,7 +62,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.2"
+#define DRIVER_VERSION "v0.3"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC "USB IR Dongle driver"
 
@@ -128,12 +132,12 @@
  * The class descriptor is some extra info that IrDA USB devices will
  * offer to us, describing their IrDA characteristics. We will use that in
  * irda_usb_init_qos()
+ *
+ * Based on the same function in drivers/net/irda/irda-usb.c
  */
 static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum)
 {
-	struct usb_interface_descriptor *interface;
 	struct irda_class_desc *desc;
-	struct irda_class_desc *ptr;
 	int ret;
 		
 	desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL);
@@ -141,28 +145,27 @@
 		return NULL;
 	memset(desc, 0, sizeof(struct irda_class_desc));
 	
-	ret = usb_get_class_descriptor(dev, ifnum, USB_DT_IRDA, 0, (void *) desc, sizeof(struct irda_class_desc));
-	dbg(__FUNCTION__ " -  ret=%d", ret);
-	if (ret)
-		dbg(__FUNCTION__ " - usb_get_class_descriptor failed (0x%x)", ret);
-
-	/* Check if we found it? */
-	if (desc->bDescriptorType == USB_DT_IRDA)
-		goto exit;
-
-	dbg(__FUNCTION__ " - parsing extra descriptors...");
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
+			IU_REQ_GET_CLASS_DESC,
+			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500));
 	
-	/* Check if the class descriptor is interleaved with standard descriptors */
-	interface = &dev->actconfig->interface[ifnum].altsetting[0];
-	ret = usb_get_extra_descriptor(interface, USB_DT_IRDA, &ptr);
-	if (ret) {
-		kfree(desc);
-		return NULL;
+	dbg(__FUNCTION__ " -  ret=%d", ret);
+	if (ret < sizeof(*desc)) {
+		dbg(__FUNCTION__ " - class descriptor read %s (%d)",
+				(ret<0) ? "failed" : "too short", ret);
+		goto error;
 	}
-	*desc = *ptr;
-exit:
+	if (desc->bDescriptorType != USB_DT_IRDA) {
+		dbg(__FUNCTION__ " - bad class descriptor type");
+		goto error;
+	}
+	
 	irda_usb_dump_class_desc(desc);
 	return desc;
+error:
+	kfree(desc);
+	return NULL;
 }
 
 static int ir_startup (struct usb_serial *serial)
diff -urN linux-2.4.15-pre3/drivers/usb/serial/mct_u232.c linux/drivers/usb/serial/mct_u232.c
--- linux-2.4.15-pre3/drivers/usb/serial/mct_u232.c	Wed Oct 10 23:42:47 2001
+++ linux/drivers/usb/serial/mct_u232.c	Mon Dec  3 23:28:59 2001
@@ -24,6 +24,9 @@
  *   Basic tests have been performed with minicom/zmodem transfers and
  *   modem dialing under Linux 2.4.0-test10 (for me it works fine).
  *
+ * 10-Nov-2001 Wolfgang Grandegger
+ *   - Fixed an endianess problem with the baudrate selection for PowerPC.
+ *
  * 30-May-2001 Greg Kroah-Hartman
  *	switched from using spinlock to a semaphore, which fixes lots of problems.
  *
@@ -263,7 +266,7 @@
 {
 	unsigned int divisor;
         int rc;
-	divisor = mct_u232_calculate_baud_rate(serial, value);
+	divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value));
         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                              MCT_U232_SET_BAUD_RATE_REQUEST,
 			     MCT_U232_SET_REQUEST_TYPE,
diff -urN linux-2.4.15-pre3/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
--- linux-2.4.15-pre3/drivers/usb/serial/visor.c	Wed Oct 10 23:42:47 2001
+++ linux/drivers/usb/serial/visor.c	Mon Dec  3 23:28:59 2001
@@ -12,6 +12,10 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (11/11/2001) gkh
+ *	Added support for the m125 devices, and added check to prevent oopses
+ *	for Clié devices that lie about the number of ports they have.
+ *
  * (08/30/2001) gkh
  *	Added support for the Clie devices, both the 3.5 and 4.0 os versions.
  *	Many thanks to Daniel Burke, and Bryan Payne for helping with this.
@@ -123,9 +127,9 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.4"
+#define DRIVER_VERSION "v1.5"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
-#define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Clie driver"
+#define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Clié driver"
 
 /* function prototypes for a handspring visor */
 static int  visor_open		(struct usb_serial_port *port, struct file *filp);
@@ -148,13 +152,10 @@
 	{ }					/* Terminating entry */
 };
 
-static __devinitdata struct usb_device_id palm_m500_id_table [] = {
+static __devinitdata struct usb_device_id palm_4_0_id_table [] = {
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
-	{ }					/* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id palm_m505_id_table [] = {
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -172,6 +173,7 @@
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ }					/* Terminating entry */
@@ -207,10 +209,10 @@
 	read_bulk_callback:	visor_read_bulk_callback,
 };
 
-/* device info for the Palm M500 */
-struct usb_serial_device_type palm_m500_device = {
-	name:			"Palm M500",
-	id_table:		palm_m500_id_table,
+/* device info for the Palm 4.0 devices */
+struct usb_serial_device_type palm_4_0_device = {
+	name:			"Palm 4.0",
+	id_table:		palm_4_0_id_table,
 	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
 	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
 	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
@@ -233,35 +235,10 @@
 	read_bulk_callback:	visor_read_bulk_callback,
 };
 
-/* device info for the Palm M505 */
-struct usb_serial_device_type palm_m505_device = {
-	name:			"Palm M505",
-	id_table:		palm_m505_id_table,
-	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
-	num_interrupt_in:	0,
-	num_bulk_in:		2,
-	num_bulk_out:		2,
-	num_ports:		2,
-	open:			visor_open,
-	close:			visor_close,
-	throttle:		visor_throttle,
-	unthrottle:		visor_unthrottle,
-	startup:		visor_startup,
-	shutdown:		visor_shutdown,
-	ioctl:			visor_ioctl,
-	set_termios:		visor_set_termios,
-	write:			visor_write,
-	write_room:		visor_write_room,
-	chars_in_buffer:	visor_chars_in_buffer,
-	write_bulk_callback:	visor_write_bulk_callback,
-	read_bulk_callback:	visor_read_bulk_callback,
-};
 
 /* device info for the Sony Clie OS version 3.5 */
 static struct usb_serial_device_type clie_3_5_device = {
-	name:			"Sony Clie 3.5",
+	name:			"Sony Clié 3.5",
 	id_table:		clie_id_3_5_table,
 	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
 	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
@@ -285,7 +262,7 @@
 
 /* device info for the Sony Clie OS version 4.0 */
 static struct usb_serial_device_type clie_4_0_device = {
-	name:			"Sony Clie 4.0",
+	name:			"Sony Clié 4.0",
 	id_table:		clie_id_4_0_table,
 	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
 	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
@@ -330,6 +307,11 @@
 	
 	dbg(__FUNCTION__ " - port %d", port->number);
 
+	if (!port->read_urb) {
+		err ("Device lied about number of ports, please use a lower one.");
+		return -ENODEV;
+	}
+
 	down (&port->sem);
 	
 	++port->open_count;
@@ -819,8 +801,7 @@
 	int i;
 
 	usb_serial_register (&handspring_device);
-	usb_serial_register (&palm_m500_device);
-	usb_serial_register (&palm_m505_device);
+	usb_serial_register (&palm_4_0_device);
 	usb_serial_register (&clie_3_5_device);
 	usb_serial_register (&clie_4_0_device);
 	
@@ -854,8 +835,7 @@
 	unsigned long flags;
 
 	usb_serial_deregister (&handspring_device);
-	usb_serial_deregister (&palm_m500_device);
-	usb_serial_deregister (&palm_m505_device);
+	usb_serial_deregister (&palm_4_0_device);
 	usb_serial_deregister (&clie_3_5_device);
 	usb_serial_deregister (&clie_4_0_device);
 
diff -urN linux-2.4.15-pre3/drivers/usb/serial/visor.h linux/drivers/usb/serial/visor.h
--- linux-2.4.15-pre3/drivers/usb/serial/visor.h	Fri Sep  7 10:59:04 2001
+++ linux/drivers/usb/serial/visor.h	Mon Dec  3 23:28:59 2001
@@ -23,6 +23,7 @@
 #define PALM_VENDOR_ID			0x0830
 #define PALM_M500_ID			0x0001
 #define PALM_M505_ID			0x0002
+#define PALM_M125_ID			0x0040
 
 #define SONY_VENDOR_ID			0x054C
 #define SONY_CLIE_3_5_ID		0x0038
diff -urN linux-2.4.15-pre3/drivers/usb/usb-skeleton.c linux/drivers/usb/usb-skeleton.c
--- linux-2.4.15-pre3/drivers/usb/usb-skeleton.c	Mon Oct  1 13:45:48 2001
+++ linux/drivers/usb/usb-skeleton.c	Mon Dec  3 23:28:59 2001
@@ -1,5 +1,5 @@
 /*
- * USB Skeleton driver - 0.5
+ * USB Skeleton driver - 0.6
  *
  * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
  *
@@ -22,6 +22,8 @@
  *
  * History:
  *
+ * 2001_11_05 - 0.6 - fix minor locking problem in skel_disconnect.
+ *			Thanks to Pete Zaitcev for the fix.
  * 2001_09_04 - 0.5 - fix devfs bug in skel_disconnect. Thanks to wim delvaux
  * 2001_08_21 - 0.4 - more small bug fixes.
  * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel
@@ -604,6 +606,7 @@
 
 	/* if the device is not opened, then we clean up right now */
 	if (!dev->open_count) {
+		up (&dev->sem);
 		skel_delete (dev);
 	} else {
 		dev->udev = NULL;
diff -urN linux-2.4.15-pre3/drivers/video/hgafb.c linux/drivers/video/hgafb.c
--- linux-2.4.15-pre3/drivers/video/hgafb.c	Mon Dec  3 23:28:49 2001
+++ linux/drivers/video/hgafb.c	Mon Dec  3 23:28:59 2001
@@ -312,8 +312,8 @@
 static int __init hga_card_detect(void)
 {
 	int count=0;
-	unsigned char p, p_save;
-	unsigned char q, q_save;
+	unsigned long p, q;
+	unsigned short p_save, q_save;
 
 	hga_vram_base = 0xb0000;
 	hga_vram_len  = 0x08000;
diff -urN linux-2.4.15-pre3/fs/Config.in linux/fs/Config.in
--- linux-2.4.15-pre3/fs/Config.in	Mon Dec  3 23:28:49 2001
+++ linux/fs/Config.in	Mon Dec  3 23:28:59 2001
@@ -92,6 +92,7 @@
    comment 'Network File Systems'
 
    dep_tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS $CONFIG_INET
+   dep_tristate 'InterMezzo file system support (experimental, replicating fs)' CONFIG_INTERMEZZO_FS $CONFIG_INET $CONFIG_EXPERIMENTAL
    dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET
    dep_mbool '  Provide NFSv3 client support' CONFIG_NFS_V3 $CONFIG_NFS_FS
    dep_bool '  Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP
diff -urN linux-2.4.15-pre3/fs/Makefile linux/fs/Makefile
--- linux-2.4.15-pre3/fs/Makefile	Mon Dec  3 23:28:49 2001
+++ linux/fs/Makefile	Mon Dec  3 23:28:59 2001
@@ -33,6 +33,7 @@
 subdir-$(CONFIG_CRAMFS)		+= cramfs
 subdir-$(CONFIG_RAMFS)		+= ramfs
 subdir-$(CONFIG_CODA_FS)	+= coda
+subdir-$(CONFIG_INTERMEZZO_FS)	+= intermezzo
 subdir-$(CONFIG_MINIX_FS)	+= minix
 subdir-$(CONFIG_FAT_FS)		+= fat
 subdir-$(CONFIG_UMSDOS_FS)	+= umsdos
diff -urN linux-2.4.15-pre3/fs/ext2/super.c linux/fs/ext2/super.c
--- linux-2.4.15-pre3/fs/ext2/super.c	Thu Oct 25 00:02:26 2001
+++ linux/fs/ext2/super.c	Mon Dec  3 23:28:59 2001
@@ -640,9 +640,9 @@
 		if (sb->s_root) {
 			dput(sb->s_root);
 			sb->s_root = NULL;
-			printk ("EXT2-fs: corrupt root inode, run e2fsck\n");
+			printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n");
 		} else
-			printk ("EXT2-fs: get root inode failed\n");
+			printk(KERN_ERR "EXT2-fs: get root inode failed\n");
 		goto failed_mount2;
 	}
 	ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
diff -urN linux-2.4.15-pre3/fs/partitions/ldm.c linux/fs/partitions/ldm.c
--- linux-2.4.15-pre3/fs/partitions/ldm.c	Mon Oct  1 20:03:26 2001
+++ linux/fs/partitions/ldm.c	Mon Dec  3 23:28:59 2001
@@ -1,10 +1,8 @@
 /*
- * $Id: ldm.c,v 1.25 2001/07/25 23:32:02 flatcap Exp $
- *
  * ldm - Part of the Linux-NTFS project.
  *
- * Copyright (C) 2001 Richard Russon <ntfs@flatcap.org>
- * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net>
+ * Copyright (C) 2001 Richard Russon <ldm@flatcap.org>
+ * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net> (AIA)
  *
  * Documentation is available at http://linux-ntfs.sf.net/ldm
  *
@@ -22,6 +20,8 @@
  * along with this program (in the main directory of the Linux-NTFS source
  * in the file COPYING); if not, write to the Free Software Foundation,
  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * 28/10/2001 - Added sorting of ldm partitions. (AIA)
  */
 #include <linux/types.h>
 #include <asm/unaligned.h>
@@ -158,6 +158,60 @@
 }
 
 /**
+ * add_partition_to_list - insert partition into a partition list
+ * @pl:		sorted list of partitions
+ * @hd:		gendisk structure to which the data partition belongs
+ * @disk_minor:	minor number of the disk device
+ * @start:	first sector within the disk device
+ * @size:	number of sectors on the partition device
+ *
+ * This sanity checks the partition specified by @start and @size against the
+ * device specified by @hd and inserts the partition into the sorted partition
+ * list @pl if the checks pass.
+ *
+ * On success return 1, otherwise return -1.
+ *
+ * TODO: Add sanity check for overlapping partitions. (AIA)
+ */ 
+static int add_partition_to_list(struct list_head *pl, const struct gendisk *hd,
+		const int disk_minor, const unsigned long start,
+		const unsigned long size)
+{
+	struct ldm_part *lp, *lptmp;
+	struct list_head *tmp;
+
+	if (!hd->part)
+		return -1;
+	if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) {
+		printk(LDM_CRIT "LDM partition exceeds physical disk. "
+				"Skipping.\n");
+		return -1;
+	}
+	lp = (struct ldm_part*)kmalloc(sizeof(struct ldm_part), GFP_KERNEL);
+	if (!lp) {
+		printk(LDM_CRIT "Not enough memory! Aborting LDM partition "
+				"parsing.\n");
+		return -2;
+	}
+	INIT_LIST_HEAD(&lp->part_list);
+	lp->start = start;
+	lp->size = size;
+	list_for_each(tmp, pl) {
+		lptmp = list_entry(tmp, struct ldm_part, part_list);
+		if (start > lptmp->start)
+			continue;
+		if (start < lptmp->start)
+			break;
+		printk(LDM_CRIT "Duplicate LDM partition entry! Skipping.\n");
+		kfree(lp);
+		return -1;
+	}
+	list_add_tail(&lp->part_list, tmp);
+	ldm_debug("Added LDM partition successfully.\n");
+	return 1;
+}
+
+/**
  * create_data_partitions - create the data partition devices
  * @hd:			gendisk structure in which to create the data partitions
  * @first_sector:	first sector within the disk device
@@ -172,7 +226,10 @@
  * the partitions in the database that belong to this disk.
  *
  * For each found partition, we create a corresponding partition device starting
- * with minor number @first_part_minor.
+ * with minor number @first_part_minor. But we do this in such a way that we
+ * actually sort the partitions in order of on-disk position. Any invalid
+ * partitions are completely ignored/skipped (an error is output but that's
+ * all).
  *
  * Return 1 on success and -1 on error.
  */
@@ -182,13 +239,16 @@
 		const struct privhead *ph, const struct ldmdisk *dk,
 		unsigned long base)
 {
-	Sector  sect;
+	Sector sect;
 	unsigned char *data;
 	struct vblk *vb;
+	LIST_HEAD(pl);		/* Sorted list of partitions. */
+	struct ldm_part *lp;
+	struct list_head *tmp;
 	int vblk;
 	int vsize;		/* VBLK size. */
 	int perbuf;		/* VBLKs per buffer. */
-	int buffer, lastbuf, lastofs, err;
+	int buffer, lastbuf, lastofs, err, disk_minor;
 
 	vb = (struct vblk*)kmalloc(sizeof(struct vblk), GFP_KERNEL);
 	if (!vb)
@@ -207,7 +267,11 @@
 	if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
 			ph->config_size * 512)
 		goto err_out;
-	printk(" <");
+	/*
+	 * Get the minor number of the parent device so we can check we don't
+	 * go beyond the end of the device.
+	 */
+	disk_minor = (first_part_minor >> hd->minor_shift) << hd->minor_shift;
 	for (buffer = 0; buffer < lastbuf; buffer++) {
 		data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, &sect);
 		if (!data)
@@ -226,17 +290,34 @@
 				continue;
 			if (dk->obj_id != vb->disk_id)
 				continue;
-			if (create_partition(hd, first_part_minor,
+			/* Ignore invalid partition errors. */
+			if (add_partition_to_list(&pl, hd, disk_minor,
 					first_sector + vb->start_sector +
 					ph->logical_disk_start,
-					vb->num_sectors) == 1)
-				first_part_minor++;
+					vb->num_sectors) < -1)
+				goto brelse_out;
 		}
 		put_dev_sector(sect);
 	}
-	printk(" >\n");
 	err = 1;
 out:
+	/* Finally create the nicely sorted data partitions. */
+	printk(" <");
+	list_for_each(tmp, &pl) {
+		lp = list_entry(tmp, struct ldm_part, part_list);
+		add_gd_partition(hd, first_part_minor++, lp->start, lp->size);
+	}
+	printk(" >\n");
+	if (!list_empty(&pl)) {
+		struct list_head *tmp2;
+
+		/* Cleanup the partition list which is now superfluous. */
+		list_for_each_safe(tmp, tmp2, &pl) {
+			lp = list_entry(tmp, struct ldm_part, part_list);
+			list_del(tmp);
+			kfree(lp);
+		}
+	}
 	kfree(vb);
 	return err;
 brelse_out:
@@ -372,7 +453,10 @@
 			delta = vblk * vsize + 0x18;
 			if (delta >= 512)
 				goto brelse_out;
-			if (block[0x13] != VBLK_DISK)
+			if (block[0x0D] != 0)	/* Extended VBLK, ignore */
+				continue;
+			if ((block[0x13] != VBLK_DSK1) &&
+			    (block[0x13] != VBLK_DSK2))
 				continue;
 			/* Calculate relative offsets. */
 			rel_objid = 1 + block[0x18];
@@ -895,7 +979,7 @@
 	put_dev_sector(sect);
 	return 1;
 not_dynamic_disk:
-	ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n");
+//	ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n");
 no_msdos_partition:
 	put_dev_sector(sect);
 	return 0;
diff -urN linux-2.4.15-pre3/fs/partitions/ldm.h linux/fs/partitions/ldm.h
--- linux-2.4.15-pre3/fs/partitions/ldm.h	Mon Nov  5 12:43:27 2001
+++ linux/fs/partitions/ldm.h	Mon Dec  3 23:28:59 2001
@@ -1,11 +1,9 @@
 #ifndef _FS_PT_LDM_H_
 #define _FS_PT_LDM_H_
 /*
- * $Id: ldm.h,v 1.13 2001/07/23 19:49:49 antona Exp $
- *
  * ldm - Part of the Linux-NTFS project.
  *
- * Copyright (C) 2001 Richard Russon <ntfs@flatcap.org>
+ * Copyright (C) 2001 Richard Russon <ldm@flatcap.org>
  * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net>
  *
  * Documentation is available at http://linux-ntfs.sf.net/ldm
@@ -25,7 +23,7 @@
  * in the file COPYING); if not, write to the Free Software Foundation,
  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#include <asm/types.h>
+#include <linux/types.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 #include <linux/genhd.h>
@@ -45,8 +43,10 @@
 /* The defined vblk types. */
 #define VBLK_COMP		0x32		/* Component */
 #define VBLK_PART		0x33		/* Partition */
-#define VBLK_DISK		0x34		/* Disk */
-#define VBLK_DGRP		0x45		/* Disk Group */
+#define VBLK_DSK1		0x34		/* Disk */
+#define VBLK_DSK2		0x44		/* Disk */
+#define VBLK_DGR1		0x35		/* Disk Group */
+#define VBLK_DGR2		0x45		/* Disk Group */
 #define VBLK_VOLU		0x51		/* Volume */
 
 /* Other constants. */
@@ -142,6 +142,12 @@
 	u64	disk_id;
 	u64	start_sector;
 	u64	num_sectors;
+};
+
+struct ldm_part {
+	struct list_head part_list;
+	unsigned long start;
+	unsigned long size;
 };
 
 int ldm_partition(struct gendisk *hd, struct block_device *bdev,
diff -urN linux-2.4.15-pre3/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c
--- linux-2.4.15-pre3/fs/proc/proc_misc.c	Mon Dec  3 23:28:49 2001
+++ linux/fs/proc/proc_misc.c	Mon Dec  3 23:28:59 2001
@@ -50,7 +50,6 @@
  * have a way to deal with that gracefully. Right now I used straightforward
  * wrappers, but this needs further analysis wrt potential overflows.
  */
-extern int get_cpuinfo(char *);
 extern int get_hardware_list(char *);
 extern int get_stram_list(char *);
 #ifdef CONFIG_DEBUG_MALLOC
@@ -208,12 +207,17 @@
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
-static int cpuinfo_read_proc(char *page, char **start, off_t off,
-				 int count, int *eof, void *data)
+extern struct seq_operations cpuinfo_op;
+static int cpuinfo_open(struct inode *inode, struct file *file)
 {
-	int len = get_cpuinfo(page);
-	return proc_calc_metrics(page, start, off, count, eof, len);
+	return seq_open(file, &cpuinfo_op);
 }
+static struct file_operations proc_cpuinfo_operations = {
+	open:		cpuinfo_open,
+	read:		seq_read,
+	llseek:		seq_lseek,
+	release:	seq_release,
+};
 
 #ifdef CONFIG_PROC_HARDWARE
 static int hardware_read_proc(char *page, char **start, off_t off,
@@ -526,7 +530,6 @@
 		{"uptime",	uptime_read_proc},
 		{"meminfo",	meminfo_read_proc},
 		{"version",	version_read_proc},
-		{"cpuinfo",	cpuinfo_read_proc},
 #ifdef CONFIG_PROC_HARDWARE
 		{"hardware",	hardware_read_proc},
 #endif
@@ -568,9 +571,14 @@
 	entry = create_proc_entry("mounts", 0, NULL);
 	if (entry)
 		entry->proc_fops = &proc_mounts_operations;
+	entry = create_proc_entry("cpuinfo", 0, NULL);
+	if (entry)
+		entry->proc_fops = &proc_cpuinfo_operations;
+#ifdef CONFIG_MODULES
 	entry = create_proc_entry("ksyms", 0, NULL);
 	if (entry)
 		entry->proc_fops = &proc_ksyms_operations;
+#endif
 	proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
 	if (proc_root_kcore) {
 		proc_root_kcore->proc_fops = &proc_kcore_operations;
diff -urN linux-2.4.15-pre3/fs/seq_file.c linux/fs/seq_file.c
--- linux-2.4.15-pre3/fs/seq_file.c	Mon Dec  3 23:28:49 2001
+++ linux/fs/seq_file.c	Mon Dec  3 23:28:59 2001
@@ -5,9 +5,10 @@
  * initial implementation -- AV, Oct 2001.
  */
 
-#include <linux/malloc.h>
 #include <linux/fs.h>
 #include <linux/seq_file.h>
+#include <linux/slab.h>
+
 #include <asm/uaccess.h>
 
 /**
diff -urN linux-2.4.15-pre3/include/linux/ac97_codec.h linux/include/linux/ac97_codec.h
--- linux-2.4.15-pre3/include/linux/ac97_codec.h	Mon Nov  5 12:44:58 2001
+++ linux/include/linux/ac97_codec.h	Mon Dec  3 23:28:59 2001
@@ -239,6 +239,7 @@
 extern int ac97_probe_codec(struct ac97_codec *);
 extern unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate);
 extern unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate);
-
+extern int ac97_save_state(struct ac97_codec *codec);
+extern int ac97_restore_state(struct ac97_codec *codec);
 
 #endif /* _AC97_CODEC_H_ */
diff -urN linux-2.4.15-pre3/include/linux/console.h linux/include/linux/console.h
--- linux-2.4.15-pre3/include/linux/console.h	Mon Nov  5 12:42:13 2001
+++ linux/include/linux/console.h	Mon Dec  3 23:28:59 2001
@@ -112,6 +112,7 @@
 extern void acquire_console_sem(void);
 extern void release_console_sem(void);
 extern void console_conditional_schedule(void);
+extern void console_unblank(void);
 
 /* VESA Blanking Levels */
 #define VESA_NO_BLANKING        0
diff -urN linux-2.4.15-pre3/include/linux/isapnp.h linux/include/linux/isapnp.h
--- linux-2.4.15-pre3/include/linux/isapnp.h	Mon Nov  5 12:43:18 2001
+++ linux/include/linux/isapnp.h	Mon Dec  3 23:28:59 2001
@@ -162,6 +162,14 @@
 	unsigned long driver_data;	/* data private to the driver */
 };
 
+struct isapnp_driver {
+	struct list_head node;
+	char *name;
+	const struct isapnp_device_id *id_table;	/* NULL if wants all devices */
+	int  (*probe)  (struct pci_dev *dev, const struct isapnp_device_id *id);	/* New device inserted */
+	void (*remove) (struct pci_dev *dev);	/* Device removed (NULL if not a hot-plug capable driver) */
+};
+
 #if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
 
 #define __ISAPNP__
@@ -214,6 +222,9 @@
 #define isapnp_for_each_dev(dev) \
 	for(dev = pci_dev_g(isapnp_devices.next); dev != pci_dev_g(&isapnp_devices); dev = pci_dev_g(dev->global_list.next))
 
+int isapnp_register_driver(struct isapnp_driver *drv);
+void isapnp_unregister_driver(struct isapnp_driver *drv);
+
 #else /* !CONFIG_ISAPNP */
 
 /* lowlevel configuration */
@@ -248,6 +259,10 @@
 					  unsigned long start,
 					  unsigned long size) { ; }
 static inline int isapnp_activate_dev(struct pci_dev *dev, const char *name) { return -ENODEV; }
+
+static inline int isapnp_register_driver(struct isapnp_driver *drv) { return 0; }
+
+static inline void isapnp_unregister_driver(struct isapnp_driver *drv) { }
 
 #endif /* CONFIG_ISAPNP */
 
diff -urN linux-2.4.15-pre3/include/linux/kernel.h linux/include/linux/kernel.h
--- linux-2.4.15-pre3/include/linux/kernel.h	Mon Dec  3 23:28:49 2001
+++ linux/include/linux/kernel.h	Mon Dec  3 23:28:59 2001
@@ -51,7 +51,7 @@
 extern struct notifier_block *panic_notifier_list;
 NORET_TYPE void panic(const char * fmt, ...)
 	__attribute__ ((NORET_AND format (printf, 1, 2)));
-NORET_TYPE void do_exit(long error_code)
+asmlinkage NORET_TYPE void do_exit(long error_code)
 	ATTRIB_NORET;
 NORET_TYPE void complete_and_exit(struct completion *, long)
 	ATTRIB_NORET;
diff -urN linux-2.4.15-pre3/include/linux/pci.h linux/include/linux/pci.h
--- linux-2.4.15-pre3/include/linux/pci.h	Mon Nov  5 12:42:33 2001
+++ linux/include/linux/pci.h	Mon Dec  3 23:28:59 2001
@@ -532,6 +532,8 @@
 struct pci_dev *pci_scan_slot(struct pci_dev *temp);
 int pci_proc_attach_device(struct pci_dev *dev);
 int pci_proc_detach_device(struct pci_dev *dev);
+int pci_proc_attach_bus(struct pci_bus *bus);
+int pci_proc_detach_bus(struct pci_bus *bus);
 void pci_name_device(struct pci_dev *dev);
 char *pci_class_name(u32 class);
 void pci_read_bridge_bases(struct pci_bus *child);
@@ -589,6 +591,9 @@
 void pci_remove_device(struct pci_dev *);
 struct pci_driver *pci_dev_driver(const struct pci_dev *);
 const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev);
+void pci_announce_device_to_drivers(struct pci_dev *);
+unsigned int pci_do_scan_bus(struct pci_bus *bus);
+struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr);
 
 /* kmem_cache style wrapper around pci_alloc_consistent() */
 struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev,
diff -urN linux-2.4.15-pre3/include/linux/raid/md_k.h linux/include/linux/raid/md_k.h
--- linux-2.4.15-pre3/include/linux/raid/md_k.h	Fri Sep 14 14:21:51 2001
+++ linux/include/linux/raid/md_k.h	Mon Dec  3 23:28:59 2001
@@ -43,6 +43,7 @@
 static inline int level_to_pers (int level)
 {
 	switch (level) {
+		case -4: return MULTIPATH;
 		case -3: return HSM;
 		case -2: return TRANSLUCENT;
 		case -1: return LINEAR;
diff -urN linux-2.4.15-pre3/include/linux/raid/multipath.h linux/include/linux/raid/multipath.h
--- linux-2.4.15-pre3/include/linux/raid/multipath.h	Fri Sep 14 14:22:18 2001
+++ linux/include/linux/raid/multipath.h	Mon Dec  3 23:28:59 2001
@@ -7,14 +7,11 @@
 	int		number;
 	int		raid_disk;
 	kdev_t		dev;
-	int		sect_limit;
-	int		head_position;
 
 	/*
 	 * State bits:
 	 */
 	int		operational;
-	int		write_only;
 	int		spare;
 
 	int		used_slot;
@@ -36,22 +33,10 @@
 	 * multipath_bh that are pre-allocated have MPBH_PreAlloc set.
 	 * All these variable are protected by device_lock
 	 */
-	struct buffer_head	*freebh;
-	int			freebh_cnt;	/* how many are on the list */
 	struct multipath_bh	*freer1;
-	struct multipath_bh	*freebuf; 	/* each bh_req has a page allocated */
+	int			freer1_blocked;
+	int			freer1_cnt;
 	md_wait_queue_head_t	wait_buffer;
-
-	/* for use when syncing multipaths: */
-	unsigned long	start_active, start_ready,
-		start_pending, start_future;
-	int	cnt_done, cnt_active, cnt_ready,
-		cnt_pending, cnt_future;
-	int	phase;
-	int	window;
-	md_wait_queue_head_t	wait_done;
-	md_wait_queue_head_t	wait_ready;
-	md_spinlock_t		segment_lock;
 };
 
 typedef struct multipath_private_data multipath_conf_t;
@@ -76,9 +61,8 @@
 	unsigned long		state;
 	mddev_t			*mddev;
 	struct buffer_head	*master_bh;
-	struct buffer_head	*multipath_bh_list;
 	struct buffer_head	bh_req;
-	struct multipath_bh	*next_r1;	/* next for retry or in free list */
+	struct multipath_bh	*next_mp; /* next for retry or in free list */
 };
 /* bits for multipath_bh.state */
 #define	MPBH_Uptodate	1
diff -urN linux-2.4.15-pre3/kernel/sched.c linux/kernel/sched.c
--- linux-2.4.15-pre3/kernel/sched.c	Mon Dec  3 23:28:49 2001
+++ linux/kernel/sched.c	Mon Dec  3 23:28:59 2001
@@ -515,7 +515,7 @@
 #endif /* CONFIG_SMP */
 }
 
-void schedule_tail(struct task_struct *prev)
+asmlinkage void schedule_tail(struct task_struct *prev)
 {
 	__schedule_tail(prev);
 }
