diff -u --recursive --new-file v2.4.12/linux/CREDITS linux/CREDITS
--- v2.4.12/linux/CREDITS	Tue Oct  9 17:06:50 2001
+++ linux/CREDITS	Sun Oct 21 10:20:57 2001
@@ -999,6 +999,11 @@
 E: philip@raptor.com
 D: Kernel / timekeeping stuff
   
+N: Jan-Benedict Glaw
+E: jbglaw@lug-owl.de
+D: SRM environment driver (for Alpha systems)
+P: 1024D/8399E1BB 250D 3BCF 7127 0D8C A444  A961 1DBD 5E75 8399 E1BB
+
 N: Richard E. Gooch
 E: rgooch@atnf.csiro.au
 D: parent process death signal to children
@@ -2057,10 +2062,11 @@
 S: USA
 
 N: Patrick Mochel
-E: mochel@transmeta.com
+E: pat@osdl.org
+E: mochelp@infinity.powertie.org
 D: PCI Power Management, ACPI work
-S: 3940 Freedom Circle
-S: Santa Clara, CA 95054
+S: 15275 SW Koll Parkway, Suite H
+S: Beaverton, OR 97006 
 S: USA
 
 N: Eberhard Moenkeberg
diff -u --recursive --new-file v2.4.12/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.4.12/linux/Documentation/Configure.help	Tue Oct  9 17:06:51 2001
+++ linux/Documentation/Configure.help	Sat Oct 20 19:17:19 2001
@@ -2568,6 +2568,31 @@
   a module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
+ACP Modem (Mwave) support
+CONFIG_MWAVE
+  The ACP modem (Mwave) for Linux is a WinModem. It is composed of a
+  kernel driver and a user level application. Together these components
+  support direct attachment to public switched telephone networks (PSTNs)
+  and support selected world wide countries.
+
+  This version of the ACP Modem driver supports the IBM Thinkpad 600E,
+  600, and 770 that include on board ACP modem hardware.
+
+  The modem also supports the standard communications port interface
+  (ttySx) and is compatible with the Hayes AT Command Set.
+
+  The user level application needed to use this driver can be found at
+  the IBM Linux Technology Center (LTC) web site:
+  http://www.ibm.com/linux/ltc/
+
+  If you own one of the above IBM Thinkpads which has the Mwave chipset
+  in it, say Y.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called mwave.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+
 /dev/agpgart (AGP Support) (EXPERIMENTAL)
 CONFIG_AGP
   AGP (Accelerated Graphics Port) is a bus system mainly used to
@@ -7675,15 +7700,6 @@
   Support for these adaptors is so far still incomplete and buggy.
   You have been warned.
 
-Hermes PCMCIA card support
-CONFIG_PCMCIA_HERMES
-  Enable support for PCMCIA 802.11b cards using the Hermes or Intersil
-  HFA384x (Prism 2) chipset.  To use your PC-cards, you will need
-  supporting software from David Hinds' pcmcia-cs package (see the
-  file Documentation/Changes for location). You also want to check out
-  the PCMCIA-HOWTO, available from
-  http://www.linuxdoc.org/docs.html#howto .
-
 Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)
 CONFIG_PCMCIA_HERMES
   A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
@@ -8850,6 +8866,18 @@
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
+RealTek RTL-8139C+ 10/100 PCI Fast Ethernet Adapter support
+CONFIG_8139CP
+  This is a driver for the Fast Ethernet PCI network cards based on
+  the RTL8139C+ chips. If you have one of those, say Y and read
+  the Ethernet-HOWTO, available from
+  http://www.linuxdoc.org/docs.html#howto .
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called 8139cp.o.
+
 RealTek RTL-8139 PCI Fast Ethernet Adapter support
 CONFIG_8139TOO
   This is a driver for the Fast Ethernet PCI network cards based on
@@ -11025,7 +11053,29 @@
   of debug messages to the system log. Select this if you are having a
   problem with USB support and want to see more of what is going on.
 
-UHCI (intel PIIX4, VIA, ...) support?
+USB fetch large config
+CONFIG_USB_LARGE_CONFIG
+  This option changes the initial request for a config descriptor so
+  that some poorly designed devices will still work.  Some APC UPSes
+  need it.  Basically, the usb subsystem sends a request for a short
+  (8 byte) config, just to find out how large the real config is.
+  Incorrectly implemented devices may choke on this small config
+  request.  This option make the initial request for a quite large
+  config (1009 bytes), and things just work.
+
+  If you have an APC UPS, say Y; otherwise say N.
+
+USB long timeout
+CONFIG_USB_LONG_TIMEOUT
+  This option makes the standard time out a bit longer.  Basically,
+  some devices are just slow to respond, so this makes usb more 
+  patient.  There should be no harm in selecting this, but it is
+  needed for some MGE Ellipse UPSes.
+
+  If you have an MGE Ellipse UPS, or you see timeouts in HID
+  transactions, say Y; otherwise say N.
+
+UHCI (intel PIIX4, VIA, ...) support
 CONFIG_USB_UHCI
   The Universal Host Controller Interface is a standard by Intel for
   accessing the USB hardware in the PC (which is also called the USB
@@ -11101,6 +11151,20 @@
   The module will be called hid.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+/dev/usb/hiddev raw HID device support
+CONFIG_USB_HIDDEV
+  Say Y here if you want to support HID devices (from the USB
+  specification standpoint) that aren't strictly user interface
+  devices, like monitor controls and Uninterruptable Power Supplies.
+  It is also used for "consumer keys" on multimedia keyboards and
+  USB speakers.
+
+  This module supports these devices separately using a separate
+  event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
+  This driver requires CONFIG_USB_HID.
+
+  If unsure, say N.
+
 USB HIDBP Keyboard (basic) support
 CONFIG_USB_KBD
   Say Y here if you don't want to use the generic HID driver for your
@@ -11359,8 +11423,7 @@
   and was developed with their support.  You must also include
   firmware to support your particular device(s). 
 
-  See http://www.linuxcare.com.au/hugh/keyspan.html for 
-  more information.
+  See http://misc.nu/hugh/keyspan.html for more information.
  
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -11374,6 +11437,20 @@
 USB Keyspan USA-28X Firmware
 CONFIG_USB_SERIAL_KEYSPAN_USA28X
   Say Y here to include firmware for the USA-28X converter.
+  Be sure you have a USA-28X, there are also 28XA and 28XB
+  models, the label underneath has the actual part number.
+
+USB Keyspan USA-28XA Firmware
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA
+  Say Y here to include firmware for the USA-28XA converter.
+  Be sure you have a USA-28XA, there are also 28X and 28XB
+  models, the label underneath has the actual part number.
+
+USB Keyspan USA-28XB Firmware
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB
+  Say Y here to include firmware for the USA-28XB converter.
+  Be sure you have a USA-28XB, there are also 28X and 28XA
+  models, the label underneath has the actual part number.
 
 USB Keyspan USA-19 Firmware
 CONFIG_USB_SERIAL_KEYSPAN_USA19
@@ -11584,26 +11661,14 @@
   The module will be called se401.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-USB ADMtek Pegasus-based ethernet device support
+Pegasus/Pegasus II based USB-Ethernet device support
 CONFIG_USB_PEGASUS
-  Say Y if you want to use your USB ethernet device. Supported
-  cards until now are:
-    ADMtek AN986 Pegasus (eval. board)
-    ADMtek ADM8511 Pegasus II (eval. board)
-    Accton 10/100
-    Billington USB-100
-    Corega FEter USB-TX
-    MELCO/BUFFALO LUA-TX
-    D-Link DSB-650TX, DSB-650TX-PNA, DSB-650, DU-E10, DU-E100
-    Linksys USB100TX, USB10TX
-    LANEED Ethernet LD-USB/TX
-    SMC 202
-    SOHOware NUB Ethernet
-    
-  Any Pegasus II based board also are supported.
-  If you have devices with vendor IDs other than noted above
-  you should add them in the driver code and send a message
-  to me (petkan@dce.bg) for update.
+  Say Y here if you know you have Pegasus or Pegasus II based adapter.
+  If in doubt then look at linux/drivers/usb/pegasus.h for the complete
+  list of supported devices.
+  If your particular adapter is not in the list and you are _sure_ it
+  is Pegasus or Pegasus II based then send me (pmanolov@lnxw.com) vendor
+  and device IDs.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -11685,6 +11750,10 @@
   The module will be called CDCEther.o.  If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+NetChip 1080-based USB Host-to-Host Link
+CONFIG_USB_NET1080
+  The NetChip 1080 is a USB 1.1 host controller.  NetChip has a web
+  site with technical information at http://www.netchip.com/ .
 
 USB Kodak DC-2xx Camera support
 CONFIG_USB_DC2XX
@@ -11869,6 +11938,12 @@
   and work. SANE 1.0.4 or newer is needed to make use of your scanner.
   This driver can be compiled as a module.
 
+HP 53xx and Minolta Dual Scanner support
+CONFIG_USB_HPUSBSCSI
+  Say Y here if you want support for the HP 53xx series of scanners
+  and the Minolta Scan Dual. This driver is experimental.
+  The scanner will be accessible as a SCSI device.
+
 USB Bluetooth support
 CONFIG_USB_BLUETOOTH
   Say Y here if you want to connect a USB Bluetooth device to your
@@ -14851,6 +14926,17 @@
   The module is called machzwd.o. If you want to compile it as a module,
   say M here and read Documentation/modules.txt.
 
+SuperH 3/4 Watchdog
+CONFIG_SH_WDT
+  This driver adds watchdog support for the integrated watchdog in the
+  SuperH 3 and 4 processors. If you have one of these processors, say Y,
+  otherwise say N.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module is called shwdt.o. If you want to compile it as a module,
+  say M here and read Documentation/modules.txt.
+	      
 Toshiba Laptop support
 CONFIG_TOSHIBA
   This adds a driver to safely access the System Management Mode
@@ -16636,6 +16722,121 @@
   found on many Sun machines. Note that many of the newer Ultras
   actually have pc style hardware instead.
 
+# The following options are for Linux when running on the Hitachi
+# SuperH family of RISC microprocessors.
+
+CPU Selection
+CONFIG_CPU_SUBTYPE_SH7707
+  This is the type of your Hitachi SuperH processor. This information is
+  used for optimizing and configuration purposes.
+
+  - "SH7707" for SH7707
+  - "SH7708" for SH7708, SH7708S, SH7708R
+  - "SH7709" for SH7707, SH7709, SH7709A, and SH7729.
+  - "SH7750" for SH7750, SH7750S
+  - "SH7751" for SH7751
+  - "ST40STB1" for ST40STB1
+
+Target machine selection
+CONFIG_SH_GENERIC
+  This is machine type of your target.
+
+  - "Generic" for Generic kernel which might support all of them
+  - "SolutionEngine" for Hitachi SolutionEngine (7709A, 7750, 7750S)
+  - "SolutionEngine7751" for Hitachi SolutionEngine (7751)
+  - "STB1_Harp" for STMicroelectronics HARP
+  - "STB1_Overdrive" for STMicroelectronics Overdrive
+  - "HP620" for HP 'Jornada' 620
+  - "HP680" for HP 'Jornada' 680
+  - "HP690" for HP 'Jornada' 690
+  - "CqREEK" for CQ Publishing CqREEK SH-4
+  - "DMIDA" for DMIDA, industrial data assistant
+  - "EC3104" for Compaq Aero 8000
+  - "Dreamcast" for SEGA Dreamcast
+  - "CAT68701" for CAT 68701 Evaluation Board (SH7708)
+  - "BigSur" for Big Sur Evaluation Board
+  - "SH2000" for SH2000 Evaluation Board (SH7709A)
+  - "ADX" for A&D ADX
+  - "BareCPU" for Bare CPU board such as CqREEK SH-3
+
+  If unsure, select "BareCPU".
+
+Physical memory start address
+CONFIG_MEMORY_START
+  Computers built with Hitachi SuperH processors always
+  map the ROM starting at address zero.  But the processor
+  does not specify the range that RAM takes.  RAM is usually
+  mapped starting at 0c000000, but it may be elsewhere.
+
+  You should set this value to the address of the lowest
+  RAM location.
+
+  A value of 0c000000 will work for most boards.
+
+Directly Connected Compact Flash support
+CONFIG_CF_ENABLER
+  If your board has "Directly Connected" CompactFlash at area 5 or 6, 
+  you may want to enable this option.  Then, you can use CF as
+  primary IDE drive (only tested for SanDisk).
+
+  If in doubt, press "n".
+
+SuperH RTC support
+CONFIG_SH_RTC
+  Selecting this option will allow the Linux kernel to emulate
+  PC's RTC.
+
+  If unsure, say N.
+
+SuperH DMAC support
+CONFIG_SH_DMA
+  Selecting this option will provide same API as PC's Direct Memory
+  Access Controller(8237A) for SuperH DMAC.
+
+  If unsure, say N.
+
+SuperH SCI (serial) support
+CONFIG_SH_SCI
+  Selecting this option will allow the Linux kernel to transfer
+  data over SCI (Serial Communication Interface) and/or SCIF
+  which are built into the Hitachi SuperH processor.
+
+  If unsure, say N.
+
+Use LinuxSH standard BIOS
+CONFIG_SH_STANDARD_BIOS
+  Say Y here if your target has the gdb-sh-stub package from
+  www.m17n.org (or any conforming standard LinuxSH BIOS) in FLASH
+  or EPROM.  The kernel will use standard BIOS calls during boot
+  for various housekeeping tasks.  Note this does not work with
+  WindowsCE machines.  If unsure, say N.
+
+Early printk support
+CONFIG_SH_EARLY_PRINTK
+  If you say Y here, the kernel printk routine will begin output to
+  the console much earlier in the boot process, before the serial
+  console is initialised, instead of buffering output.  Standard
+  LinuxSH BIOS calls are used for the output.  This helps when
+  debugging fatal problems early in the boot sequence.  This is only
+  useful for kernel hackers.  If unsure, say N.
+  
+National Semiconductor DP83902AV 'ST-NIC' support
+CONFIG_STNIC
+  If you have a network adaptor with National Semiconductor DP83902AV, 
+  say Y or M (for module).
+
+  If unsure, say N.
+
+CompactFlash Connection Area
+CONFIG_CF_AREA5
+  If your board has "Directly Connected" CompactFlash, You should
+  select the area where your CF is connected to.
+  
+  - "Area5" if CompactFlash is connected to Area 5 (0x14000000)
+  - "Area6" if it is connected to Area 6 (0x18000000)
+
+  "Area6" will work for most boards. For ADX, select "Area5".
+
 #
 # m68k-specific kernel options
 # Documented by Chris Lawrence <quango@themall.net> et al.
@@ -18188,6 +18389,11 @@
   It is also possible to say M here to build it as a module (ds1620.o)
   It is recommended to be used on a NetWinder, but it is not a
   necessity.
+
+Debug high memory support
+CONFIG_DEBUG_HIGHMEM
+  This options enables addition error checking for high memory systems.
+  Disable for production systems.
 
 Verbose kernel error messages
 CONFIG_DEBUG_ERRORS
diff -u --recursive --new-file v2.4.12/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt
--- v2.4.12/linux/Documentation/DMA-mapping.txt	Mon Aug 27 12:41:37 2001
+++ linux/Documentation/DMA-mapping.txt	Fri Oct 12 15:35:53 2001
@@ -6,14 +6,15 @@
 		  Jakub Jelinek <jakub@redhat.com>
 
 Most of the 64bit platforms have special hardware that translates bus
-addresses (DMA addresses) to physical addresses similarly to how page
-tables and/or TLB translate virtual addresses to physical addresses.
-This is needed so that e.g. PCI devices can access with a Single Address
-Cycle (32bit DMA address) any page in the 64bit physical address space.
-Previously in Linux those 64bit platforms had to set artificial limits on
-the maximum RAM size in the system, so that the virt_to_bus() static scheme
-works (the DMA address translation tables were simply filled on bootup
-to map each bus address to the physical page __pa(bus_to_virt())).
+addresses (DMA addresses) into physical addresses.  This is similar to
+how page tables and/or a TLB translates virtual addresses to physical
+addresses on a cpu.  This is needed so that e.g. PCI devices can
+access with a Single Address Cycle (32bit DMA address) any page in the
+64bit physical address space.  Previously in Linux those 64bit
+platforms had to set artificial limits on the maximum RAM size in the
+system, so that the virt_to_bus() static scheme works (the DMA address
+translation tables were simply filled on bootup to map each bus
+address to the physical page __pa(bus_to_virt())).
 
 So that Linux can use the dynamic DMA mapping, it needs some help from the
 drivers, namely it has to take into account that DMA addresses should be
@@ -28,9 +29,10 @@
 
 #include <linux/pci.h>
 
-is in your driver. This file will obtain for you the definition of
-the dma_addr_t type which should be used everywhere you hold a DMA
-(bus) address returned from the DMA mapping functions.
+is in your driver. This file will obtain for you the definition of the
+dma_addr_t (which can hold any valid DMA address for the platform)
+type which should be used everywhere you hold a DMA (bus) address
+returned from the DMA mapping functions.
 
 			 What memory is DMA'able?
 
@@ -49,7 +51,8 @@
 _underlying_ memory mapped into a vmalloc() area, but this requires
 walking page tables to get the physical addresses, and then
 translating each of those pages back to a kernel address using
-something like __va().
+something like __va().  [ EDIT: Update this when we integrate
+Gerd Knorr's generic code which does this. ]
 
 This rule also means that you may not use kernel image addresses
 (ie. items in the kernel's data/text/bss segment, or your driver's)
@@ -65,60 +68,96 @@
 
 Does your device have any DMA addressing limitations?  For example, is
 your device only capable of driving the low order 24-bits of address
-on the PCI bus for DMA transfers?  If your device can handle any PCI
-dma address fully, then please skip to the next section, the rest of
-this section does not concern your device.
+on the PCI bus for SAC DMA transfers?  If so, you need to inform the
+PCI layer of this fact.
+
+By default, the kernel assumes that your device can address the full
+32-bits in a SAC cycle.  For a 64-bit DAC capable device, this needs
+to be increased.  And for a device with limitations, as discussed in
+the previous paragraph, it needs to be decreased.
 
 For correct operation, you must interrogate the PCI layer in your
 device probe routine to see if the PCI controller on the machine can
-properly support the DMA addressing limitation your device has.  This
-query is performed via a call to pci_dma_supported():
+properly support the DMA addressing limitation your device has.  It is
+good style to do this even if your device holds the default setting,
+because this shows that you did think about these issues wrt. your
+device.
+
+The query is performed via a call to pci_set_dma_mask():
 
-	int pci_dma_supported(struct pci_dev *pdev, dma_addr_t device_mask)
+	int pci_set_dma_mask(struct pci_dev *pdev, u64 device_mask);
 
 Here, pdev is a pointer to the PCI device struct of your device, and
 device_mask is a bit mask describing which bits of a PCI address your
-device supports.  It returns non-zero if your card can perform DMA
-properly on the machine.  If it returns zero, your device can not
-perform DMA properly on this platform, and attempting to do so will
-result in undefined behavior.
+device supports.  It returns zero if your card can perform DMA
+properly on the machine given the address mask you provided.
 
-In the failure case, you have two options:
-
-1) Use some non-DMA mode for data transfer, if possible.
-2) Ignore this device and do not initialize it.
+If it returns non-zero, your device can not perform DMA properly on
+this platform, and attempting to do so will result in undefined
+behavior.  You must either use a different mask, or not use DMA.
+
+This means that in the failure case, you have three options:
+
+1) Use another DMA mask, if possible (see below).
+2) Use some non-DMA mode for data transfer, if possible.
+3) Ignore this device and do not initialize it.
 
 It is recommended that your driver print a kernel KERN_WARNING message
-when you do one of these two things.  In this manner, if a user of
-your driver reports that performance is bad or that the device is not
-even detected, you can ask him for the kernel messages to find out
+when you end up performing either #2 or #2.  In this manner, if a user
+of your driver reports that performance is bad or that the device is not
+even detected, you can ask them for the kernel messages to find out
 exactly why.
 
-So if, for example, you device can only drive the low 24-bits of
-address during PCI bus mastering you might do something like:
+The standard 32-bit addressing PCI device would do something like
+this:
 
-	if (! pci_dma_supported(pdev, 0x00ffffff))
+	if (pci_set_dma_mask(pdev, 0xffffffff)) {
+		printk(KERN_WARNING
+		       "mydev: No suitable DMA available.\n");
 		goto ignore_this_device;
+	}
 
-When DMA is possible for a given mask, the PCI layer must be informed of the
-mask for later allocation operations on the device.  This is achieved by
-setting the dma_mask member of the pci_dev structure, like so:
-
-#define MY_HW_DMA_MASK 0x00ffffff
-
-	if (! pci_dma_supported(pdev, MY_HW_DMA_MASK))
+Another common scenario is a 64-bit capable device.  The approach
+here is to try for 64-bit DAC addressing, but back down to a
+32-bit mask should that fail.  The PCI platform code may fail the
+64-bit mask not because the platform is not capable of 64-bit
+addressing.  Rather, it may fail in this case simply because
+32-bit SAC addressing is done more efficiently than DAC addressing.
+Sparc64 is one platform which behaves in this way.
+
+Here is how you would handle a 64-bit capable device which can drive
+all 64-bits during a DAC cycle:
+
+	int using_dac;
+
+	if (!pci_set_dma_mask(pdev, 0xffffffffffffffff)) {
+		using_dac = 1;
+	} else if (!pci_set_dma_mask(pdev, 0xffffffff)) {
+		using_dac = 0;
+	} else {
+		printk(KERN_WARNING
+		       "mydev: No suitable DMA available.\n");
 		goto ignore_this_device;
+	}
 
-	pdev->dma_mask = MY_HW_DMA_MASK;
+If your 64-bit device is going to be an enormous consumer of DMA
+mappings, this can be problematic since the DMA mappings are a
+finite resource on many platforms.  Please see the "DAC Addressing
+for Address Space Hungry Devices" setion near the end of this
+document for how to handle this case.
 
-A helper function is provided which performs this common code sequence:
+Finally, if your device can only drive the low 24-bits of
+address during PCI bus mastering you might do something like:
 
-	int pci_set_dma_mask(struct pci_dev *pdev, dma_addr_t device_mask)
+	if (pci_set_dma_mask(pdev, 0x00ffffff)) {
+		printk(KERN_WARNING
+		       "mydev: 24-bit DMA addressing not available.\n");
+		goto ignore_this_device;
+	}
 
-Unlike pci_dma_supported(), this returns -EIO when the PCI layer will not be
-able to DMA with addresses restricted by that mask, and returns 0 when DMA
-transfers are possible.  If the call succeeds, the dma_mask will have been
-updated so that your driver need not worry about it.
+When pci_set_dma_mask() is successful, and returns zero, the PCI layer
+saves away this mask you have provided.  The PCI layer will use this
+information later when you make DMA mappings.
 
 There is a case which we are aware of at this time, which is worth
 mentioning in this documentation.  If your device supports multiple
@@ -169,6 +208,10 @@
 
   Think of "consistent" as "synchronous" or "coherent".
 
+  Consistent DMA mappings are always SAC addressable.  That is
+  to say, consistent DMA addresses given to the driver will always
+  be in the low 32-bits of the PCI bus space.
+
   Good examples of what to use consistent mappings for are:
 
 	- Network card DMA ring descriptors.
@@ -230,15 +273,26 @@
 specific (and often is private to the bus which the device is attached
 to).
 
-Size is the length of the region you want to allocate.
+Size is the length of the region you want to allocate, in bytes.
 
 This routine will allocate RAM for that region, so it acts similarly to
 __get_free_pages (but takes size instead of a page order).  If your
 driver needs regions sized smaller than a page, you may prefer using
 the pci_pool interface, described below.
 
-It returns two values: the virtual address which you can use to access
-it from the CPU and dma_handle which you pass to the card.
+The consistent DMA mapping interfaces, for non-NULL dev, will always
+return a DMA address which is SAC (Single Address Cycle) addressible.
+Even if the device indicates (via PCI dma mask) that it may address
+the upper 32-bits and thus perform DAC cycles, consistent allocation
+will still only return 32-bit PCI addresses for DMA.  This is true
+of the pci_pool interface as well.
+
+In fact, as mentioned above, all consistent memory provided by the
+kernel DMA APIs are always SAC addressable.
+
+pci_alloc_consistent returns two values: the virtual address which you
+can use to access it from the CPU and dma_handle which you pass to the
+card.
 
 The cpu return address and the DMA bus master address are both
 guaranteed to be aligned to the smallest PAGE_SIZE order which
@@ -270,14 +324,15 @@
 
 The "name" is for diagnostics (like a kmem_cache name); dev and size
 are as above.  The device's hardware alignment requirement for this
-type of data is "align" (a power of two).  The flags are SLAB_ flags
-as you'd pass to kmem_cache_create.  Not all flags are understood, but
-SLAB_POISON may help you find driver bugs.  If you call this in a non-
-sleeping context (f.e. in_interrupt is true or while holding SMP
-locks), pass SLAB_ATOMIC.  If your device has no boundary crossing
-restrictions, pass 0 for alloc; passing 4096 says memory allocated
-from this pool must not cross 4KByte boundaries (but at that time it
-may be better to go for pci_alloc_consistent directly instead).
+type of data is "align" (which is expressed in bytes, and must be a
+power of two).  The flags are SLAB_ flags as you'd pass to
+kmem_cache_create.  Not all flags are understood, but SLAB_POISON may
+help you find driver bugs.  If you call this in a non- sleeping
+context (f.e. in_interrupt is true or while holding SMP locks), pass
+SLAB_ATOMIC.  If your device has no boundary crossing restrictions,
+pass 0 for alloc; passing 4096 says memory allocated from this pool
+must not cross 4KByte boundaries (but at that time it may be better to
+go for pci_alloc_consistent directly instead).
 
 Allocate memory from a pci pool like this:
 
@@ -318,6 +373,8 @@
 
 PCI_DMA_TODEVICE means "from main memory to the PCI device"
 PCI_DMA_FROMDEVICE means "from the PCI device to main memory"
+It is the direction in which the data moves during the DMA
+transfer.
 
 You are _strongly_ encouraged to specify this as precisely
 as you possibly can.
@@ -333,13 +390,13 @@
 precise direction, and this will help catch cases where your
 direction tracking logic has failed to set things up properly.
 
-Another advantage of specifying this value precisely (outside
-of potential platform-specific optimizations of such) is for
-debugging.  Some platforms actually have a write permission
-boolean which DMA mappings can be marked with, much like page
-protections in a user program can have.  Such platforms can
-and do report errors in the kernel logs when the PCI controller
-hardware detects violation of the permission setting.
+Another advantage of specifying this value precisely (outside of
+potential platform-specific optimizations of such) is for debugging.
+Some platforms actually have a write permission boolean which DMA
+mappings can be marked with, much like page protections in the user
+program address space.  Such platforms can and do report errors in the
+kernel logs when the PCI controller hardware detects violation of the
+permission setting.
 
 Only streaming mappings specify a direction, consistent mappings
 implicitly have a direction attribute setting of
@@ -362,13 +419,17 @@
 
 		  Using Streaming DMA mappings
 
-The streaming DMA mapping routines can be called from interrupt context.
-There are two versions of each map/unmap, one which map/unmap a single
-memory region, one which map/unmap a scatterlist.
+The streaming DMA mapping routines can be called from interrupt
+context.  There are two versions of each map/unmap, one which will
+map/unmap a single memory region, and one which will map/unmap a
+scatterlist.
 
 To map a single region, you do:
 
+	struct pci_dev *pdev = mydev->pdev;
 	dma_addr_t dma_handle;
+	void *addr = buffer->ptr;
+	size_t size = buffer->len;
 
 	dma_handle = pci_map_single(dev, addr, size, direction);
 
@@ -377,9 +438,29 @@
 	pci_unmap_single(dev, dma_handle, size, direction);
 
 You should call pci_unmap_single when the DMA activity is finished, e.g.
-from interrupt which told you the DMA transfer is done.
+from the interrupt which told you that the DMA transfer is done.
 
-Similarly with scatterlists, you map a region gathered from several regions by:
+Using cpu pointers like this for single mappings has a disadvantage,
+you cannot reference HIGHMEM memory in this way.  Thus, there is a
+map/unmap interface pair akin to pci_{map,unmap}_single.  These
+interfaces deal with page/offset pairs instead of cpu pointers.
+Specifically:
+
+	struct pci_dev *pdev = mydev->pdev;
+	dma_addr_t dma_handle;
+	struct page *page = buffer->page;
+	unsigned long offset = buffer->offset;
+	size_t size = buffer->len;
+
+	dma_handle = pci_map_page(dev, page, offset, size, direction);
+
+	...
+
+	pci_unmap_page(dev, dma_handle, size, direction);
+
+Here, "offset" means byte offset within the given page.
+
+With scatterlists, you map a region gathered from several regions by:
 
 	int i, count = pci_map_sg(dev, sglist, nents, direction);
 	struct scatterlist *sg;
@@ -407,7 +488,7 @@
 
 	pci_unmap_sg(dev, sglist, nents, direction);
 
-Again, make sure DMA activity finished.
+Again, make sure DMA activity has already finished.
 
 PLEASE NOTE:  The 'nents' argument to the pci_unmap_sg call must be
               the _same_ one you passed into the pci_map_sg call,
@@ -421,8 +502,8 @@
 all bus addresses.
 
 If you need to use the same streaming DMA region multiple times and touch
-the data in between the DMA transfers, just map it
-with pci_map_{single,sg}, after each DMA transfer call either:
+the data in between the DMA transfers, just map it with
+pci_map_{single,sg}, and after each DMA transfer call either:
 
 	pci_dma_sync_single(dev, dma_handle, size, direction);
 
@@ -430,9 +511,11 @@
 
 	pci_dma_sync_sg(dev, sglist, nents, direction);
 
-and after the last DMA transfer call one of the DMA unmap routines
+as appropriate.
+
+After the last DMA transfer call one of the DMA unmap routines
 pci_unmap_{single,sg}. If you don't touch the data from the first pci_map_*
-call till pci_unmap_*, then you don't have to call the pci_sync_*
+call till pci_unmap_*, then you don't have to call the pci_dma_sync_*
 routines at all.
 
 Here is pseudo code which shows a situation in which you would need
@@ -492,6 +575,119 @@
 supports dynamic DMA mapping in hardware) in your driver structures and/or
 in the card registers.
 
+All PCI drivers should be using these interfaces with no exceptions.
+It is planned to completely remove virt_to_bus() and bus_to_virt() as
+they are entirely deprecated.  Some ports already do not provide these
+as it is impossible to correctly support them.
+
+		64-bit DMA and DAC cycle support
+
+Do you understand all of the text above?  Great, then you already
+know how to use 64-bit DMA addressing under Linux.  Simply make
+the appropriate pci_set_dma_mask() calls based upon your cards
+capabilities, then use the mapping APIs above.
+
+It is that simple.
+
+Well, not for some odd devices.  See the next section for information
+about that.
+
+	DAC Addressing for Address Space Hungry Devices
+
+There exists a class of devices which do not mesh well with the PCI
+DMA mapping API.  By definition these "mappings" are a finite
+resource.  The number of total available mappings per bus is platform
+specific, but there will always be a reasonable amount.
+
+What is "reasonable"?  Reasonable means that networking and block I/O
+devices need not worry about using too many mappings.
+
+As an example of a problematic device, consider compute cluster cards.
+They can potentially need to access gigabytes of memory at once via
+DMA.  Dynamic mappings are unsuitable for this kind of access pattern.
+
+To this end we've provided a small API by which a device driver
+may use DAC cycles to directly address all of physical memory.
+Not all platforms support this, but most do.  It is easy to determine
+whether the platform will work properly at probe time.
+
+First, understand that there may be a SEVERE performance penalty for
+using these interfaces on some platforms.  Therefore, you MUST only
+use these interfaces if it is absolutely required.  %99 of devices can
+use the normal APIs without any problems.
+
+Note that for streaming type mappings you must either use these
+interfaces, or the dynamic mapping interfaces above.  You may not mix
+usage of both for the same device.  Such an act is illegal and is
+guarenteed to put a banana in your tailpipe.
+
+However, consistent mappings may in fact be used in conjunction with
+these interfaces.  Remember that, as defined, consistent mappings are
+always going to be SAC addressable.
+
+The first thing your driver needs to do is query the PCI platform
+layer with your devices DAC addressing capabilities:
+
+	int pci_dac_set_dma_mask(struct pci_dev *pdev, u64 mask);
+
+This routine behaves identically to pci_set_dma_mask.  You may not
+use the following interfaces if this routine fails.
+
+Next, DMA addresses using this API are kept track of using the
+dma64_addr_t type.  It is guarenteed to be big enough to hold any
+DAC address the platform layer will give to you from the following
+routines.  If you have consistent mappings as well, you still
+use plain dma_addr_t to keep track of those.
+
+All mappings obtained here will be direct.  The mappings are not
+translated, and this is the purpose of this dialect of the DMA API.
+
+All routines work with page/offset pairs.  This is the _ONLY_ way to 
+portably refer to any piece of memory.  If you have a cpu pointer
+(which may be validly DMA'd too) you may easily obtain the page
+and offset using something like this:
+
+	struct page *page = virt_to_page(ptr);
+	unsigned long offset = ((unsigned long)ptr & ~PAGE_MASK);
+
+Here are the interfaces:
+
+	dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
+					 struct page *page,
+					 unsigned long offset,
+					 int direction);
+
+The DAC address for the tuple PAGE/OFFSET are returned.  The direction
+argument is the same as for pci_{map,unmap}_single().  The same rules
+for cpu/device access apply here as for the streaming mapping
+interfaces.  To reiterate:
+
+	The cpu may touch the buffer before pci_dac_page_to_dma.
+	The device may touch the buffer after pci_dac_page_to_dma
+	is made, but the cpu may NOT.
+
+When the DMA transfer is complete, invoke:
+
+	void pci_dac_dma_sync_single(struct pci_dev *pdev,
+				     dma64_addr_t dma_addr,
+				     size_t len, int direction);
+
+This must be done before the CPU looks at the buffer again.
+This interface behaves identically to pci_dma_sync_{single,sg}().
+
+If you need to get back to the PAGE/OFFSET tuple from a dma64_addr_t
+the following interfaces are provided:
+
+	struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
+					 dma64_addr_t dma_addr);
+	unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
+					    dma64_addr_t dma_addr);
+
+This is possible with the DAC interfaces purely because they are
+not translated in any way.
+
+			   Closing
+
 This document, and the API itself, would not be in it's current
 form without the feedback and suggestions from numerous individuals.
 We would like to specifically mention, in no particular order, the
@@ -503,3 +699,6 @@
 	Grant Grundler <grundler@cup.hp.com>
 	Jay Estabrook <Jay.Estabrook@compaq.com>
 	Thomas Sailer <sailer@ife.ee.ethz.ch>
+	Andrea Arcangeli <andrea@suse.de>
+	Jens Axboe <axboe@suse.de>
+	David Mosberger-Tang <davidm@hpl.hp.com>
diff -u --recursive --new-file v2.4.12/linux/Documentation/README.DAC960 linux/Documentation/README.DAC960
--- v2.4.12/linux/Documentation/README.DAC960	Thu Dec  7 17:05:41 2000
+++ linux/Documentation/README.DAC960	Wed Oct 17 14:46:29 2001
@@ -1,17 +1,17 @@
    Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-			Version 2.2.9 for Linux 2.2.17
-			Version 2.4.9 for Linux 2.4.0
+			Version 2.2.11 for Linux 2.2.19
+			Version 2.4.11 for Linux 2.4.12
 
 			      PRODUCTION RELEASE
 
-			       7 September 2000
+				11 October 2001
 
 			       Leonard N. Zubkoff
 			       Dandelion Digital
 			       lnz@dandelion.com
 
-	 Copyright 1998-2000 by Leonard N. Zubkoff <lnz@dandelion.com>
+	 Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
 
 
 				 INTRODUCTION
@@ -20,7 +20,7 @@
 controllers.  Mylex Corporation is located at 34551 Ardenwood Blvd., Fremont,
 California 94555, USA and can be reached at 510.796.6100 or on the World Wide
 Web at http://www.mylex.com.  Mylex Technical Support can be reached by
-electronic mail at support@mylex.com, by voice at 510.608.2400, or by FAX at
+electronic mail at mylexsup@us.ibm.com, by voice at 510.608.2400, or by FAX at
 510.745.7715.  Contact information for offices in Europe and Japan is available
 on their Web site.
 
@@ -120,7 +120,7 @@
 	    100MHz Intel i960RM RISC Processor
 	    16MB/32MB/64MB ECC SDRAM Memory
 
-AcceleRAID 160
+AcceleRAID 160 (AcceleRAID 170LP)
 	    1 Wide Ultra-160 LVD SCSI channel
 	    100MHz Intel i960RS RISC Processor
 	    Built in 16M ECC SDRAM Memory
@@ -170,6 +170,10 @@
 	    Intel i960 RISC Processor
 	    2MB/4MB/8MB/16MB/32MB DRAM Memory
 
+DAC960P	    1/2/3 Wide Fast SCSI-2 Channels
+	    Intel i960 RISC Processor
+	    2MB/4MB/8MB/16MB/32MB DRAM Memory
+
 For the eXtremeRAID 2000/3000 and AcceleRAID 352/170/160, firmware version
 6.00-01 or above is required.
 
@@ -180,36 +184,29 @@
 
 For the DAC960PJ and DAC960PG, firmware version 4.06-0-00 or above is required.
 
-For the DAC960PU, DAC960PD, and DAC960PL, firmware version 3.51-0-04 or above
-is required.
-
-Note that earlier revisions of the DAC960PU, DAC960PD, and DAC960PL controllers
-were delivered with version 2.xx firmware.  Version 2.xx firmware is not
-supported by this driver and no support is envisioned.  Contact Mylex RAID
-Technical Support to inquire about upgrading controllers with version 2.xx
-firmware to version 3.51-0-04.  Upgrading to version 3.xx firmware requires
-installation of higher capacity Flash ROM chips, and not all DAC960PD and
-DAC960PL controllers can be upgraded.
+For the DAC960PU, DAC960PD, DAC960PL, and DAC960P, either firmware version
+3.51-0-04 or above is required (for dual Flash ROM controllers), or firmware
+version 2.73-0-00 or above is required (for single Flash ROM controllers)
 
 Please note that not all SCSI disk drives are suitable for use with DAC960
 controllers, and only particular firmware versions of any given model may
 actually function correctly.  Similarly, not all motherboards have a BIOS that
 properly initializes the AcceleRAID 250, AcceleRAID 200, AcceleRAID 150,
 DAC960PJ, and DAC960PG because the Intel i960RD/RP is a multi-function device.
-If in doubt, contact Mylex RAID Technical Support (support@mylex.com) to verify
-compatibility.  Mylex makes available a hard disk compatibility list by FTP at
-ftp://ftp.mylex.com/pub/dac960/diskcomp.html.
+If in doubt, contact Mylex RAID Technical Support (mylexsup@us.ibm.com) to
+verify compatibility.  Mylex makes available a hard disk compatibility list at
+http://www.mylex.com/support/hdcomp/hd-lists.html.
 
 
 			      DRIVER INSTALLATION
 
-This distribution was prepared for Linux kernel version 2.2.17 or 2.4.0.
+This distribution was prepared for Linux kernel version 2.2.19 or 2.4.12.
 
 To install the DAC960 RAID driver, you may use the following commands,
 replacing "/usr/src" with wherever you keep your Linux kernel source tree:
 
   cd /usr/src
-  tar -xvzf DAC960-2.2.9.tar.gz (or DAC960-2.4.9.tar.gz)
+  tar -xvzf DAC960-2.2.11.tar.gz (or DAC960-2.4.11.tar.gz)
   mv README.DAC960 linux/Documentation
   mv DAC960.[ch] linux/drivers/block
   patch -p0 < DAC960.patch (if DAC960.patch is included)
@@ -374,11 +371,14 @@
 
     The "make-online" command changes the physical drive <channel>:<target-id>
     from status DEAD to status ONLINE.  In cases where multiple physical drives
-    have been killed simultaneously, this command may be used to bring them
-    back online, after which a consistency check is advisable.
+    have been killed simultaneously, this command may be used to bring all but
+    one of them back online, after which a rebuild to the final drive is
+    necessary.
 
     Warning: make-online should only be used on a dead physical drive that is
-    an active part of a drive group, never on a standby drive.
+    an active part of a drive group, never on a standby drive.  The command
+    should never be used on a dead drive that is part of a critical logical
+    drive; rebuild should be used if only a single drive is dead.
 
   make-standby <channel>:<target-id>
 
diff -u --recursive --new-file v2.4.12/linux/Documentation/README.nsp_cs.eng linux/Documentation/README.nsp_cs.eng
--- v2.4.12/linux/Documentation/README.nsp_cs.eng	Wed Jul 25 17:10:16 2001
+++ linux/Documentation/README.nsp_cs.eng	Thu Oct 11 11:17:22 2001
@@ -8,9 +8,9 @@
 for Linux.
 
 2. My Linux environment
-Linux kernel: 2.4.0 / 2.2.18
-pcmcia-cs:    3.1.24
-gcc:          gcc-2.95.2
+Linux kernel: 2.4.7 / 2.2.19
+pcmcia-cs:    3.1.27
+gcc:          gcc-2.95.4
 PC card:      I-O data PCSC-F (NinjaSCSI-3)
               I-O data CBSC-II in 16 bit mode (NinjaSCSI-32Bi)
 SCSI device:  I-O data CDPS-PX24 (CD-ROM drive)
@@ -55,6 +55,8 @@
 [4] Extract this driver's archive somewhere, and edit Makefile, then do make.
 $ tar -zxvf nsp_cs-x.x.tar.gz
 $ cd nsp_cs-x.x
+$ emacs Makefile
+...
 $ make
 
 [5] Copy nsp_cs.o to suitable plase, like /lib/modules/<Kernel version>/pcmcia/ .
@@ -95,7 +97,7 @@
   bind "nsp_cs"
 -------------------------------------
 
-[7] Boot (or reboot) pcmcia-cs.
+[7] Start (or restart) pcmcia-cs.
 # /etc/rc.d/rc.pcmcia start        (BSD style)
 or
 # /etc/init.d/pcmcia start         (SYSV style)
@@ -111,7 +113,8 @@
 your data. Please backup your data when you use this driver.
 
 6. Known Bugs
- Some write error occurs when you use slow device.
+ In 2.4 kernel, you can't use 640MB Optical disk. This error comes from
+high level SCSI driver.
 
 7. Testing
  Please send me some reports(bug reports etc..) of this software.
@@ -124,4 +127,4 @@
  See GPL.
 
 
-2001/02/01 yokota@netlab.is.tsukuba.ac.jp <YOKOTA Hiroshi>
+2001/08/08 yokota@netlab.is.tsukuba.ac.jp <YOKOTA Hiroshi>
diff -u --recursive --new-file v2.4.12/linux/Documentation/arm/README linux/Documentation/arm/README
--- v2.4.12/linux/Documentation/arm/README	Wed Apr 11 19:02:27 2001
+++ linux/Documentation/arm/README	Thu Oct 11 09:04:57 2001
@@ -162,7 +162,7 @@
     <description of your architecture>
 
   Please follow this format - it is an automated system.  You should
-  receive a reply within one day.
+  receive a reply in short order.
 
 ---
 Russell King (26/01/2001)
diff -u --recursive --new-file v2.4.12/linux/Documentation/arm/SA1100/ADSBitsy linux/Documentation/arm/SA1100/ADSBitsy
--- v2.4.12/linux/Documentation/arm/SA1100/ADSBitsy	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/SA1100/ADSBitsy	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,43 @@
+ADS Bitsy Single Board Computer
+(It is different from Bitsy(iPAQ) of Compaq)
+
+For more details, contact Applied Data Systems or see
+http://www.applieddata.net/products.html
+
+The Linux support for this product has been provided by
+Woojung Huh <whuh@applieddata.net>
+
+Use 'make adsbitsy_config' before any 'make config'.
+This will set up defaults for ADS Bitsy support.
+
+The kernel zImage is linked to be loaded and executed at 0xc0400000.
+
+Linux can  be used with the ADS BootLoader that ships with the
+newer rev boards. See their documentation on how to load Linux.
+
+Supported peripherals:
+- SA1100 LCD frame buffer (8/16bpp...sort of)
+- SA1111 USB Master
+- SA1100 serial port
+- pcmcia, compact flash
+- touchscreen(ucb1200)
+- console on LCD screen
+- serial ports (ttyS[0-2])
+  - ttyS0 is default for serial console
+
+To do:
+- everything else!  :-)
+
+Notes:
+
+- The flash on board is divided into 3 partitions.
+  You should be careful to use flash on board.
+  It's partition is different from GraphicsClient Plus and GraphicsMaster
+
+- 16bpp mode requires a different cable than what ships with the board.
+  Contact ADS or look through the manual to wire your own. Currently,
+  if you compile with 16bit mode support and switch into a lower bpp
+  mode, the timing is off so the image is corrupted.  This will be
+  fixed soon.
+
+Any contribution can be sent to nico@cam.org and will be greatly welcome!
diff -u --recursive --new-file v2.4.12/linux/Documentation/arm/SA1100/GraphicsMaster linux/Documentation/arm/SA1100/GraphicsMaster
--- v2.4.12/linux/Documentation/arm/SA1100/GraphicsMaster	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/SA1100/GraphicsMaster	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,53 @@
+ADS GraphicsMaster Single Board Computer
+
+For more details, contact Applied Data Systems or see
+http://www.applieddata.net/products.html
+
+The original Linux support for this product has been provided by
+Nicolas Pitre <nico@cam.org>. Continued development work by
+Woojung Huh <whuh@applieddata.net>
+
+Use 'make graphicsmaster_config' before any 'make config'.
+This will set up defaults for GraphicsMaster support.
+
+The kernel zImage is linked to be loaded and executed at 0xc0400000.
+
+Linux can  be used with the ADS BootLoader that ships with the
+newer rev boards. See their documentation on how to load Linux.
+
+Supported peripherals:
+- SA1100 LCD frame buffer (8/16bpp...sort of)
+- SA1111 USB Master
+- on-board SMC 92C96 ethernet NIC
+- SA1100 serial port
+- flash memory access (MTD/JFFS)
+- pcmcia, compact flash
+- touchscreen(ucb1200)
+- ps/2 keyboard
+- console on LCD screen
+- serial ports (ttyS[0-2])
+  - ttyS0 is default for serial console
+- Smart I/O (ADC, keypad, digital inputs, etc)
+  See http://www.applieddata.com/developers/linux for IOCTL documentation
+  and example user space code. ps/2 keybd is multiplexed through this driver
+
+To do:
+- everything else!  :-)
+
+Notes:
+
+- The flash on board is divided into 3 partitions.  mtd0 is where
+  the zImage is stored.  It's been marked as read-only to keep you
+  from blasting over the bootloader. :)  mtd1 is
+  for the ramdisk.gz image.  mtd2 is user flash space and can be
+  utilized for either JFFS or if you're feeling crazy, running ext2
+  on top of it. If you're not using the ADS bootloader, you're
+  welcome to blast over the mtd1 partition also.
+
+- 16bpp mode requires a different cable than what ships with the board.
+  Contact ADS or look through the manual to wire your own. Currently,
+  if you compile with 16bit mode support and switch into a lower bpp
+  mode, the timing is off so the image is corrupted.  This will be
+  fixed soon.
+
+Any contribution can be sent to nico@cam.org and will be greatly welcome!
diff -u --recursive --new-file v2.4.12/linux/Documentation/arm/SA1100/Pangolin linux/Documentation/arm/SA1100/Pangolin
--- v2.4.12/linux/Documentation/arm/SA1100/Pangolin	Sun Sep 23 11:40:54 2001
+++ linux/Documentation/arm/SA1100/Pangolin	Thu Oct 11 09:04:57 2001
@@ -2,7 +2,7 @@
 by Dialogue Technology (http://www.dialogue.com.tw/).
 It has EISA slots for ease of configuration with SDRAM/Flash
 memory card, USB/Serial/Audio card, Compact Flash card,
-and TFT-LCD card.
+PCMCIA/IDE card and TFT-LCD card.
 
 To compile for Pangolin, you must issue the following commands:
 
@@ -18,3 +18,7 @@
 - UDA1341 sound driver
 - SA1100 LCD controller for 800x600 16bpp TFT-LCD
 - MQ-200 driver for 800x600 16bpp TFT-LCD
+- Penmount(touch panel) driver
+- PCMCIA driver
+- SMC91C94 LAN driver
+- IDE driver (experimental)
diff -u --recursive --new-file v2.4.12/linux/Documentation/cachetlb.txt linux/Documentation/cachetlb.txt
--- v2.4.12/linux/Documentation/cachetlb.txt	Sun Mar 25 18:14:20 2001
+++ linux/Documentation/cachetlb.txt	Sun Oct 21 10:40:36 2001
@@ -326,6 +326,12 @@
 	update_mmu_cache(), a check is made of this flag bit, and if
 	set the flush is done and the flag bit is cleared.
 
+	IMPORTANT NOTE: It is often important, if you defer the flush,
+			that the actual flush occurs on the same CPU
+			as did the cpu stores into the page to make it
+			dirty.  Again, see sparc64 for examples of how
+			to deal with this.
+
   void flush_icache_range(unsigned long start, unsigned long end)
   	When the kernel stores into addresses that it will execute
 	out of (eg when loading modules), this function is called.
diff -u --recursive --new-file v2.4.12/linux/Documentation/cciss.txt linux/Documentation/cciss.txt
--- v2.4.12/linux/Documentation/cciss.txt	Sat Feb  3 12:13:19 2001
+++ linux/Documentation/cciss.txt	Thu Oct 11 09:04:57 2001
@@ -8,8 +8,9 @@
 	* SA 5300
 	* SA 5i 
 	* SA 532
+	* SA 5312
 
-If notes are not already created in the /dev/cciss directory
+If nodes are not already created in the /dev/cciss directory
 
 # mkdev.cciss [ctlrs]
 
@@ -47,3 +48,78 @@
 /dev/cciss/c1d1p1		Controller 1, disk 1, partition 1
 /dev/cciss/c1d1p2		Controller 1, disk 1, partition 2
 /dev/cciss/c1d1p3		Controller 1, disk 1, partition 3
+
+SCSI tape drive and medium changer support
+------------------------------------------
+
+SCSI sequential access devices and medium changer devices are supported and 
+appropriate device nodes are automatically created.  (e.g.  
+/dev/st0, /dev/st1, etc.  See the "st" man page for more details.) 
+You must enable "SCSI tape drive support for Smart Array 5xxx" and 
+"SCSI support" in your kernel configuration to be able to use SCSI
+tape drives with your Smart Array 5xxx controller.
+
+Additionally, note that the driver will not engage the SCSI core at init 
+time.  The driver must be directed to dynamically engage the SCSI core via 
+the /proc filesystem entry which the "block" side of the driver creates as 
+/proc/driver/cciss/cciss* at runtime.  This is because at driver init time, 
+the SCSI core may not yet be initialized (because the driver is a block 
+driver) and attempting to register it with the SCSI core in such a case 
+would cause a hang.  This is best done via an initialization script 
+(typically in /etc/init.d, but could vary depending on distibution). 
+For example:
+
+	for x in /proc/driver/cciss/cciss[0-9]*
+	do
+		echo "engage scsi" > $x
+	done
+
+Once the SCSI core is engaged by the driver, it cannot be disengaged 
+(except by unloading the driver, if it happens to be linked as a module.)
+
+Note also that if no sequential access devices or medium changers are
+detected, the SCSI core will not be engaged by the action of the above
+script.
+
+Hot plug support for SCSI tape drives
+-------------------------------------
+
+Hot plugging of SCSI tape drives is supported, with some caveats.
+The cciss driver must be informed that changes to the SCSI bus
+have been made, in addition to and prior to informing the the SCSI 
+mid layer.  This may be done via the /proc filesystem.  For example:
+
+	echo "rescan" > /proc/scsi/cciss0/1
+
+This causes the adapter to query the adapter about changes to the 
+physical SCSI buses and/or fibre channel arbitrated loop and the 
+driver to make note of any new or removed sequential access devices
+or medium changers.  The driver will output messages indicating what 
+devices have been added or removed and the controller, bus, target and 
+lun used to address the device.  Once this is done, the SCSI mid layer 
+can be informed of changes to the virtual SCSI bus which the driver 
+presents to it in the usual way. For example: 
+
+	echo add-single-device 3 2 1 0 > /proc/scsi/scsi
+ 
+to add a device on controller 3, bus 2, target 1, lun 0.   Note that
+the driver makes an effort to preserve the devices positions
+in the virtual SCSI bus, so if you are only moving tape drives 
+around on the same adapter and not adding or removing tape drives 
+from the adapter, informing the SCSI mid layer may not be necessary.
+
+Note that the naming convention of the /proc filesystem entries 
+contains a number in addition to the driver name.  (E.g. "cciss0" 
+instead of just "cciss" which you might expect.)   This is because 
+of changes to the 2.4 kernel PCI interface related to PCI hot plug
+that imply the driver must register with the SCSI mid layer once per
+adapter instance rather than once per driver.
+
+Note: ONLY sequential access devices and medium changers are presented 
+as SCSI devices to the SCSI mid layer by the cciss driver.  Specifically, 
+physical SCSI disk drives are NOT presented to the SCSI mid layer.  The 
+physical SCSI disk drives are controlled directly by the array controller 
+hardware and it is important to prevent the OS from attempting to directly 
+access these devices too, as if the array controller were merely a SCSI 
+controller in the same way that we are allowing it to access SCSI tape drives.
+
diff -u --recursive --new-file v2.4.12/linux/Documentation/filesystems/devfs/ToDo linux/Documentation/filesystems/devfs/ToDo
--- v2.4.12/linux/Documentation/filesystems/devfs/ToDo	Wed Jul  5 21:36:49 2000
+++ linux/Documentation/filesystems/devfs/ToDo	Mon Oct 15 13:42:14 2001
@@ -32,7 +32,7 @@
 
 - MFM hard drive (drivers/acorn/block/mfmhd.c)
 
-- I2O block device (drivers/i2o/i2o_block.c)
+- I2O block device (drivers/message/i2o/i2o_block.c)
 
 - ST-RAM device (arch/m68k/atari/stram.c)
 
diff -u --recursive --new-file v2.4.12/linux/Documentation/filesystems/udf.txt linux/Documentation/filesystems/udf.txt
--- v2.4.12/linux/Documentation/filesystems/udf.txt	Tue Jul  3 17:08:18 2001
+++ linux/Documentation/filesystems/udf.txt	Fri Oct 12 13:48:42 2001
@@ -1,7 +1,7 @@
 *
 * ./Documentation/filesystems/udf.txt
 *
-UDF Filesystem version 0.9.4
+UDF Filesystem version 0.9.5
 
 If you encounter problems with reading UDF discs using this driver,
 please report them to linux_udf@hpesjro.fc.hp.com, which is the
@@ -23,7 +23,7 @@
 	noadinicb	Don't embed data in the inode
 	shortad		Use short ad's
 	longad		Use long ad's (default)
-	strict		Set strict conformance
+	nostrict	Unset strict conformance
 	iocharset=	Set the NLS character set
 
 The remaining are for debugging and disaster recovery:
@@ -42,8 +42,8 @@
 
 	fileset=	Override the fileset block location. (unused)
 	rootdir=	Override the root directory location. (unused)
-				WARNING: overriding the rootdir to a non-directory may
-					yield highly unpredictable results.
+			WARNING: overriding the rootdir to a non-directory may
+				yield highly unpredictable results.
 -------------------------------------------------------------------------------
 
 
diff -u --recursive --new-file v2.4.12/linux/Documentation/i2c/dev-interface linux/Documentation/i2c/dev-interface
--- v2.4.12/linux/Documentation/i2c/dev-interface	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/i2c/dev-interface	Thu Oct 11 08:05:47 2001
@@ -70,6 +70,9 @@
     /* buf[0] contains the read byte */
   }
 
+IMPORTANT: because of the use of inline functions, you *have* to use
+'-O' or some variation when you compile your program!
+
 
 Full interface description
 ==========================
diff -u --recursive --new-file v2.4.12/linux/Documentation/i2c/summary linux/Documentation/i2c/summary
--- v2.4.12/linux/Documentation/i2c/summary	Thu Dec 16 13:59:38 1999
+++ linux/Documentation/i2c/summary	Thu Oct 11 08:05:47 2001
@@ -1,9 +1,9 @@
-This is an explanation of what i2c is, and what is supported.
+This is an explanation of what i2c is, and what is supported in this package.
 
 I2C and SMBus
 =============
 
-I2C (pronounce: I square C) is a protocol developed by Philips. It is a 
+I2C (pronounce: I squared C) is a protocol developed by Philips. It is a 
 slow two-wire protocol (10-100 kHz), but it suffices for many types of 
 devices.
 
@@ -25,6 +25,7 @@
             Adapter
   Device -> Driver
             Client
+
 An Algorithm driver contains general code that can be used for a whole class
 of I2C adapters. Each specific adapter driver depends on one algorithm
 driver.
@@ -35,29 +36,40 @@
 
 For a given configuration, you will need a driver for your I2C bus (usually
 a separate Adapter and Algorithm driver), and drivers for your I2C devices
-(usually one driver for each device).
+(usually one driver for each device). There are no I2C device drivers
+in this package. See the lm_sensors project http://www.lm-sensors.nu
+for device drivers.
+
 
+Included Bus Drivers
+====================
+Note that not only stable drivers are patched into the kernel by 'mkpatch'.
 
-Included Drivers
-================
 
 Base modules
 ------------
 
 i2c-core: The basic I2C code, including the /proc interface
 i2c-dev:  The /dev interface
+i2c-proc: The /proc interface for device (client) drivers
 
 Algorithm drivers
 -----------------
 
-i2c-algo-bit: A bit-banging algorithm
-i2c-algo-pcf: A PCF 8584 style algorithm
+i2c-algo-8xx:    An algorithm for CPM's I2C device in Motorola 8xx processors (NOT BUILT BY DEFAULT)
+i2c-algo-bit:    A bit-banging algorithm
+i2c-algo-pcf:    A PCF 8584 style algorithm
+i2c-algo-ppc405: An algorithm for the I2C device in IBM 405xx processors (NOT BUILT BY DEFAULT)
 
 Adapter drivers
 ---------------
 
 i2c-elektor:     Elektor ISA card (uses i2c-algo-pcf)
 i2c-elv:         ELV parallel port adapter (uses i2c-algo-bit)
+i2c-pcf-epp:     PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (BROKEN - missing i2c-pcf-epp.h)
 i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit)
+i2c-ppc405:      IBM 405xx processor I2C device (uses i2c-algo-ppc405) (NOT BUILT BY DEFAULT)
+i2c-pport:       Primitive parallel port adapter (uses i2c-algo-bit)
+i2c-rpx:         RPX board Motorola 8xx I2C device (uses i2c-algo-8xx) (NOT BUILT BY DEFAULT)
 i2c-velleman:    Velleman K9000 parallel port adapter (uses i2c-algo-bit)
 
diff -u --recursive --new-file v2.4.12/linux/Documentation/i2c/writing-clients linux/Documentation/i2c/writing-clients
--- v2.4.12/linux/Documentation/i2c/writing-clients	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/i2c/writing-clients	Thu Oct 11 08:05:47 2001
@@ -33,7 +33,7 @@
     /* detach_client  */  &foo_detach_client,
     /* command        */  &foo_command,   /* May be NULL */
     /* inc_use        */  &foo_inc_use,   /* May be NULL */
-    /* dec_use        */  &foo_dev_use    /* May be NULL */
+    /* dec_use        */  &foo_dec_use    /* May be NULL */
   }
  
 The name can be chosen freely, and may be upto 40 characters long. Please
@@ -190,7 +190,7 @@
 detection algorithm.
 
 You do not have to use this parameter interface; but don't try to use
-function i2c_probe() (or sensors_detect()) if you don't.
+function i2c_probe() (or i2c_detect()) if you don't.
 
 NOTE: If you want to write a `sensors' driver, the interface is slightly
       different! See below.
@@ -344,17 +344,17 @@
     return i2c_probe(adapter,&addr_data,&foo_detect_client);
   }
 
-For `sensors' drivers, use the sensors_detect function instead:
+For `sensors' drivers, use the i2c_detect function instead:
   
   int foo_attach_adapter(struct i2c_adapter *adapter)
   { 
-    return sensors_detect(adapter,&addr_data,&foo_detect_client);
+    return i2c_detect(adapter,&addr_data,&foo_detect_client);
   }
 
 Remember, structure `addr_data' is defined by the macros explained above,
 so you do not have to define it yourself.
 
-The i2c_probe or sensors_detect function will call the foo_detect_client
+The i2c_probe or i2c_detect function will call the foo_detect_client
 function only for those i2c addresses that actually have a device on
 them (unless a `force' parameter was used). In addition, addresses that
 are already in use (by some other registered client) are skipped.
@@ -363,9 +363,9 @@
 The detect client function
 --------------------------
 
-The detect client function is called by i2c_probe or sensors_detect.
+The detect client function is called by i2c_probe or i2c_detect.
 The `kind' parameter contains 0 if this call is due to a `force'
-parameter, and 0 otherwise (for sensors_detect, it contains 0 if
+parameter, and 0 otherwise (for i2c_detect, it contains 0 if
 this call is due to the generic `force' parameter, and the chip type
 number if it is due to a specific `force' parameter).
 
@@ -530,7 +530,7 @@
     /* SENSORS ONLY BEGIN */
     /* Register a new directory entry with module sensors. See below for
        the `template' structure. */
-    if ((i = sensors_register_entry(new_client, type_name,
+    if ((i = i2c_register_entry(new_client, type_name,
                                     foo_dir_table_template,THIS_MODULE)) < 0) {
       err = i;
       goto ERROR4;
@@ -574,8 +574,8 @@
     int err,i;
 
     /* SENSORS ONLY START */
-    /* Deregister with the `sensors' module. */
-    sensors_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id);
+    /* Deregister with the `i2c-proc' module. */
+    i2c_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id);
     /* SENSORS ONLY END */
 
     /* Try to detach the client from i2c space */
@@ -772,12 +772,12 @@
 
 First, I will give an example definition.
   static ctl_table foo_dir_table_template[] = {
-    { FOO_SYSCTL_FUNC1, "func1", NULL, 0, 0644, NULL, &sensors_proc_real,
-      &sensors_sysctl_real,NULL,&foo_func },
-    { FOO_SYSCTL_FUNC2, "func2", NULL, 0, 0644, NULL, &sensors_proc_real,
-      &sensors_sysctl_real,NULL,&foo_func },
-    { FOO_SYSCTL_DATA, "data", NULL, 0, 0644, NULL, &sensors_proc_real,
-      &sensors_sysctl_real,NULL,&foo_data },
+    { FOO_SYSCTL_FUNC1, "func1", NULL, 0, 0644, NULL, &i2c_proc_real,
+      &i2c_sysctl_real,NULL,&foo_func },
+    { FOO_SYSCTL_FUNC2, "func2", NULL, 0, 0644, NULL, &i2c_proc_real,
+      &i2c_sysctl_real,NULL,&foo_func },
+    { FOO_SYSCTL_DATA, "data", NULL, 0, 0644, NULL, &i2c_proc_real,
+      &i2c_sysctl_real,NULL,&foo_data },
     { 0 }
   };
 
@@ -791,8 +791,8 @@
 fourth should always be 0. The fifth is the mode of the /proc file;
 0644 is safe, as the file will be owned by root:root. 
 
-The seventh and eighth parameters should be &sensors_proc_real and
-&sensors_sysctl_real if you want to export lists of reals (scaled
+The seventh and eighth parameters should be &i2c_proc_real and
+&i2c_sysctl_real if you want to export lists of reals (scaled
 integers). You can also use your own function for them, as usual.
 Finally, the last parameter is the call-back to gather the data
 (see below) if you use the *_proc_real functions. 
diff -u --recursive --new-file v2.4.12/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt
--- v2.4.12/linux/Documentation/networking/8139too.txt	Tue Oct  9 17:06:51 2001
+++ linux/Documentation/networking/8139too.txt	Fri Oct 19 08:32:28 2001
@@ -183,6 +183,12 @@
 Change History
 --------------
 
+Version 0.9.20 - October 18, 2001
+
+* Print out notice when 8139C+ chip is detected
+* Add id for D-Link DFE690TXD pcmcia cardbus card (Gert Dewit)
+
+
 Version 0.9.19 - October 9, 2001
 
 * Eliminate buffer copy for unaligned Tx's (manfred)
diff -u --recursive --new-file v2.4.12/linux/Documentation/s390/CommonIO linux/Documentation/s390/CommonIO
--- v2.4.12/linux/Documentation/s390/CommonIO	Sun Aug 12 13:27:58 2001
+++ linux/Documentation/s390/CommonIO	Thu Oct 11 09:04:57 2001
@@ -101,6 +101,17 @@
   the device driver will be notified if possible, so the device will become
   available to the system.
 
+  You can also add ranges of devices to be ignored by piping to 
+  /proc/cio_ignore; "add <devnorange>, <devnorange>, ..." will ignore the 
+  specified devices.
+
+  Note: Already known devices cannot be ignored; this also applies to devices
+        which are gone after a machine check.
+
+  For example, if device abcd is already known and all other devices a000-afff 
+  are not known, "echo add 0xa000-0xaccc, 0xaf00-0xafff > /proc/cio_ignore" 
+  will add af00-afff to the list of ignored devices and skip a000-accc.
+
 
 * /proc/s390dbf/cio_*/ (S/390 debug feature)
 
@@ -122,3 +133,7 @@
   /proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on
   the S/390 debug feature (Documentation/s390/s390dbf.txt) for details.
 
+* /proc/irq_count
+
+  This entry counts how many times s390_process_IRQ has been called for each 
+  CPU. This info is in /proc/interrupts on other architectures.
diff -u --recursive --new-file v2.4.12/linux/Documentation/s390/chandev.8 linux/Documentation/s390/chandev.8
--- v2.4.12/linux/Documentation/s390/chandev.8	Sun Aug 12 13:27:58 2001
+++ linux/Documentation/s390/chandev.8	Thu Oct 11 09:04:57 2001
@@ -124,17 +124,16 @@
 .B (ctc|escon|lcs|osad|qeth)<devif_num>, 
 read_devno,write_devno,<data_devno,memory_usage_in_k,port_no/protocol_no,checksum_received_ip_pkts,use_hw_stats>
 .It
-devif_num of -1 indicates you don't care what device interface number is chosen, omitting it indicates this is a range of devices for which you want to force to be detected as a particular type.
-The data_devno field is only valid for qeth devices when not forcing a range of devices.
-all parameters after & including memory_usage_in_k can be set optionally if not set they
+devif_num of -1 indicates you don't care what device interface number is chosen, omitting it indicates this is a range of devices for which you want to force to be detected as a particular type, qeth devices can't be forced as a range as it makes no sense for them.
+The data_devno field is only valid for qeth devices, all parameters including & after memory_usage_in_k can be set optionally, if not set they
 go to default values. memory_usage_in_k ( 0 the default ) means let the driver choose,checksum_received_ip_pkts & use_hw_stats are set to false
 .It
 e.g. ctc0,0x7c00,0x7c01
 .It
 Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( default 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter. This can be used for instance to force a device if it presents bad sense data to the IO layer & thus autodetection fails.
 .It
-qeth,0x7c00,0x7d00,-1,4096
-All devices between 0x7c00 & 7d00 should be detected as gigabit ethernet, let the driver use 4096k for each instance, don't care what port relative adapter number is chosen, don't checksum received ip packets & use hw stats .
+lcs,0x7c00,0x7d00,-1,4096
+All devices between 0x7c00 & 7d00 should be detected as lcs, let the driver use 4096k for each instance, don't care what port relative adapter number is chosen, don't checksum received ip packets & use hw stats .
 .It
 qeth1,0x7c00,0x7c01,0x7c02
 .It
@@ -368,6 +367,12 @@
 Force drivers modules to stay loaded even if no device is found,
 this is useful for debugging & one wishes to examine debug entries in 
 /proc/s390dbf/ to find out why a module failed to load.
+.It
+e.g.
+.It
+persist,-1 forces all devices to persist.
+.It
+persist,0 forces all channel devices to be non persistent.
 .El
 
 .It
diff -u --recursive --new-file v2.4.12/linux/Documentation/s390/s390dbf.txt linux/Documentation/s390/s390dbf.txt
--- v2.4.12/linux/Documentation/s390/s390dbf.txt	Wed Apr 11 19:02:27 2001
+++ linux/Documentation/s390/s390dbf.txt	Thu Oct 11 09:04:57 2001
@@ -336,7 +336,7 @@
 Example:
 
 > ls /proc/s390dbf/dasd
-hex_ascii  level      raw
+flush  hex_ascii  level      raw 
 > cat /proc/s390dbf/dasd/hex_ascii | sort +1
 00 00974733272:680099 2 - 02 0006ad7e  07 ea 4a 90 | ....
 00 00974733272:682210 2 - 02 0006ade6  46 52 45 45 | FREE
@@ -362,6 +362,20 @@
 > echo "5" > /proc/s390dbf/dasd/level
 > cat /proc/s390dbf/dasd/level
 5
+
+Flushing debug areas
+--------------------
+Debug areas can be flushed with piping the number of the desired
+area (0...n) to the proc file "flush". When using "-" all debug areas
+are flushed.
+
+Examples:
+
+1. Flush debug area 0:
+> echo "0" > /proc/s390dbf/dasd/flush  
+
+2. Flush all debug areas:
+> echo "-" > /proc/s390dbf/dasd/flush
 
 lcrash Interface
 ----------------
diff -u --recursive --new-file v2.4.12/linux/Documentation/sonypi.txt linux/Documentation/sonypi.txt
--- v2.4.12/linux/Documentation/sonypi.txt	Mon Aug 27 12:41:37 2001
+++ linux/Documentation/sonypi.txt	Mon Oct 15 08:38:31 2001
@@ -15,6 +15,8 @@
 	- capture button events (only on Vaio Picturebook series)
 	- Fn keys
 	- bluetooth button (only on C1VR model)
+	- back button (PCG-GR7/K model)
+	- lid open/close events (Z600NE model)
 
 Those events (see linux/sonypi.h) can be polled using the character device node
 /dev/sonypi (major 10, minor auto allocated or specified as a option).
@@ -36,6 +38,14 @@
 Module options:
 ---------------
 
+Several options can be passed to the sonypi driver, either by adding them
+to /etc/modules.conf file, when the driver is compiled as a module or by
+adding the following to the kernel command line (in your bootloader):
+
+	sonypi=minor[[[[,camera],fnkeyinit],verbose],compat]
+
+where:
+
 	minor: 		minor number of the misc device /dev/sonypi, 
 			default is -1 (automatic allocation, see /proc/misc
 			or kernel logs)
@@ -45,10 +55,17 @@
 			in order to let the driver access to the camera
 
 	fnkeyinit:	on some Vaios (C1VE, C1VR etc), the Fn key events don't
-			get enabled unless you set this parameter to 1
+			get enabled unless you set this parameter to 1.
+			Do not use this option unless it's actually necessary,
+			some Vaio models don't deal well with this option.
 
 	verbose:	print unknown events from the sonypi device
 
+	compat:		uses some compatibility code for enabling the sonypi
+			events. If the driver worked for you in the past
+			(prior to version 1.5) and does not work anymore,
+			add this option and report to the author.
+
 Module use:
 -----------
 
@@ -56,7 +73,7 @@
 lines in your /etc/modules.conf file:
 
 	alias char-major-10-250 sonypi
-	options sonypi minor=250 fnkeyinit=1
+	options sonypi minor=250
 
 This supposes the use of minor 250 for the sonypi device:
 
diff -u --recursive --new-file v2.4.12/linux/Documentation/usb/error-codes.txt linux/Documentation/usb/error-codes.txt
--- v2.4.12/linux/Documentation/usb/error-codes.txt	Thu Dec  7 16:13:38 2000
+++ linux/Documentation/usb/error-codes.txt	Wed Oct 17 14:34:06 2001
@@ -79,8 +79,7 @@
 -EILSEQ			CRC mismatch
 
 USB_ST_STALL
--EPIPE			a) babble detect
-			b) endpoint stalled
+-EPIPE			endpoint stalled
 
 USB_ST_BUFFEROVERRUN
 -ECOMM			During an IN transfer, the host controller
@@ -95,7 +94,7 @@
 USB_ST_DATAOVERRUN
 -EOVERFLOW		The amount of data returned by the endpoint was
 			greater than either the max packet size of the
-			endpoint or the remaining buffer size
+			endpoint or the remaining buffer size.  "Babble".
 
 USB_ST_DATAUNDERRUN
 -EREMOTEIO		The endpoint returned less than max packet size
diff -u --recursive --new-file v2.4.12/linux/Documentation/usb/philips.txt linux/Documentation/usb/philips.txt
--- v2.4.12/linux/Documentation/usb/philips.txt	Mon Aug 27 12:41:37 2001
+++ linux/Documentation/usb/philips.txt	Wed Oct 17 14:34:06 2001
@@ -22,21 +22,12 @@
 size
    Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or
    'vga', for an image size of resp. 128x96, 160x120, 176x144,
-   320x240, 352x288 and 640x480 (of course, only for those cameras that support these resolutions).
+   320x240, 352x288 and 640x480 (of course, only for those cameras that 
+   support these resolutions).
 
 fps
    Specifies the desired framerate. Is an integer in the range of 4-30.
 
-palette
-   Specifies the desired colour order that should be delivered by read() and
-   mmap(). The string can be one of yuv420 or yuv420p; however, yuv420 will
-   be phased out, leaving only yuv420p, so this option will disappear
-   entirely.
-
-   Only the native yuv420/yuv420p format is supported by the in kernel driver. 
-   If you want to use other formats with in-kernel conversion download the
-   driver from the URL given. [Alan]
-
 fbufs
    This paramter specifies the number of internal buffers to use for storing 
    frames from the cam. This will help if the process that reads images from 
@@ -88,6 +79,26 @@
       
    The compression parameter only applies to the Vesta & ToUCam cameras.
    The 645 and 646 have fixed compression parameters.      
+
+leds
+   This settings takes 2 integers, that define the on/off time for the LED
+   (in milliseconds). One of the interesting things that you can do with
+   this is let the LED blink while the camera is in use. This:
+
+     leds=500,500
+      
+   will blink the LED once every second. But with:
+
+     leds=0,0
+
+   the LED never goes on, making it suitable for silent survaillance.
+
+   By default the camera's LED is on solid while in use, and turned off
+   when the camera is not used anymore.
+
+   This parameter works only with the ToUCam range of cameras (730, 740,
+   750). For other cameras this command is silently ignored, and the LED
+   cannot be controlled.
 
 trace
    In order to better detect problems, it is now possible to turn on a
diff -u --recursive --new-file v2.4.12/linux/Documentation/usb/scanner.txt linux/Documentation/usb/scanner.txt
--- v2.4.12/linux/Documentation/usb/scanner.txt	Fri Jul 28 12:50:52 2000
+++ linux/Documentation/usb/scanner.txt	Sat Oct 20 19:13:11 2001
@@ -1,9 +1,11 @@
-Copyright (C) 1999, 2000 David E. Nelson
+Copyright (C) 1999, 2000 David E. Nelson <dnelson@jump.net>
 
 April 26, 2000
 
 CHANGES
 
+- Amended for linux-2.4.12
+- Updated devfs support
 - Amended for linux-2.3.99-pre6-3
 - Appended hp_scan.c to end of this README
 - Removed most references to HP
@@ -35,11 +37,9 @@
 (Compaq and others) hardware port should work.  At the time of this
 writing, there are two UHCI drivers and one OHCI.
 
-A Linux development kernel (2.3.x) with USB support enabled or a
-backported version to linux-2.2.x.  See http://www.linux-usb.org for
-more information on accomplishing this.
-
-A Linux kernel with USB Scanner support enabled.
+A Linux kernel with USB support enabled or a backported version to
+linux-2.2.x.  See http://www.linux-usb.org for more information on
+accomplishing this.
 
 'lspci' which is only needed to determine the type of USB hardware
 available/installed in your machine.
@@ -75,15 +75,15 @@
 YMMV.
 
 Beginning with version 0.4 of the driver, up to 16 scanners can be
-connected/used simultaneously.  If you intend to use more than
-one scanner at a time:
+connected/used simultaneously.  For devfs support, see next section.
+If you intend to use more than one scanner at a time w/o devfs support:
 
    Add a device for the USB scanner:
 	`mknod /dev/usbscanner0 c 180 48`
 	`mknod /dev/usbscanner1 c 180 49`
                       . 
                       .
-	`mknod /dev/usb/scanner15 180 63`
+	`mknod /dev/usbscanner15 180 63`
 
 
 If you foresee using only one scanner it is best to:
@@ -106,6 +106,32 @@
     modprobe usb-uhci
     modprobe scanner
 
+DEVFS
+
+The later versions of the Linux kernel (2.4.8'ish) included a dynamic
+device filesystem call 'devfs'.  With devfs, there is no need to
+create the device files as explained above; instead, they are
+dynamically created for you.  For USB Scanner, the device is created
+in /dev/usb/scannerX where X can range from 0 to 15 depending on the
+number of scanners connected to the system.
+
+To see if you have devfs, issue the command `cat /proc/filesytems`.
+If devfs is listed you should be ready to go.  You sould also have a
+process running called 'devfsd'.  In order to make sure, issue the
+command `ps aux | grep '[d]evfsd'`.
+
+If you would like to maintain /dev/usbscanner0 in order to maintain
+compatibility with applications, then add the following to
+/etc/devfsd.conf:
+
+REGISTER ^usb/scanner0$ CFUNCTION GLOBAL symlink usb/scanner0 usbscanner0
+UNREGISTER ^usb/scanner0$ CFUNCTION GLOBAL unlink usbscanner0
+
+Then reset the scanner (reseat the USB connector or power cycle). This
+will create the necessary symlinks in /dev to /dev/usb.
+
+CONCLUSION
+
 That's it.  SANE should now be able to access the device.  
 
 There is a small test program (hp_scan.c -- appended below) that can
@@ -121,15 +147,34 @@
 
 MESSAGES
 
-On occasions the message 'usb_control/bulk_msg: timeout' or something
-similar will appear in '/var/adm/messages' or on the console or both,
-depending on how your system is configured.  This is a side effect
-that scanners are sometimes very slow at warming up and/or
-initializing.  In most cases, however, only several of these messages
-should appear and is generally considered to be normal.  If you see
-a message of the type 'excessive NAK's received' then this should
-be considered abnormal and generally indicates that the USB system is
-unable to communicate with the scanner for some particular reason.
+usb_control/bulk_msg: timeout -- On occasions this message will appear
+in '/var/adm/messages', on the console, or both depending on how
+your system is configured.  This is a side effect that scanners are
+sometimes very slow at warming up and/or initializing.  In most cases,
+however, only several of these messages should appear and is generally
+considered to be normal.  
+
+excessive NAK's received -- This message should be considered abnormal
+and generally indicates that the USB system is unable to communicate
+with the scanner for some particular reason.
+
+probe_scanner: Undetected endpoint -- The USB Scanner driver is fairly
+general when it comes to communicating to scanners.  Unfortunately,
+some vendors have designed their scanners in one way or another that
+this driver doesn't account for.
+
+probe_scanner: Endpoint determination failed -- This means that the
+driver is unable to detect a supported configuration for means to
+communicate with the scanner.  See also 'probe_scanner: Undetected
+endpoint'.
+
+funky result -- Most of the time the data flow between the computer
+and the scanner goes smoothly.  However, due to whatever reason,
+whether it be solar flares or stray neutrons, sometimes the
+communications don't work as expected.  The driver tries to handle
+most types of errors but not all.  When this message is seen,
+something weird happened.  Please contact the maintaner listed at the
+top of this file.
 
 SUPPORTED SCANNERS
 
diff -u --recursive --new-file v2.4.12/linux/Documentation/video4linux/README.buz linux/Documentation/video4linux/README.buz
--- v2.4.12/linux/Documentation/video4linux/README.buz	Thu Jan  6 14:46:18 2000
+++ linux/Documentation/video4linux/README.buz	Wed Dec 31 16:00:00 1969
@@ -1,212 +0,0 @@
-Iomega Buz Driver for Linux
-===========================
-
-by Rainer Johanni <Rainer@Johanni.de>
-
-Compiling and Loading the Driver
-================================
-
-You must run a 2.2.x kernel in order to use this driver.
-
-To compile the driver, just type make.
-
-Besides the files in this directory, the driver needs the
-'videodev' and the 'i2c' module from the Linux kernel.
-In order to get these modules available, enable module support
-for VIDEODEV and BTTV (which implies i2c) in your kernel
-configuration. You find these devices in the menu
-"Character Devices" in your Kernel Configuration.
-
-Before you load the driver you must have a video device
-at major device node 81. If you don't have it yet, do the
-following (as root!):
-
-cd /dev
-mknod video0 c 81 0
-ln -s video0 video
-
-Edit the 'update' script if you want to give the driver
-special options and then type (as root)
-
-./update
-
-to insert all the necessary modules into the kernel.
-
-If you want to make full use of the Video for Linux uncompressed
-grabbing facilities, you must either
-
-- obtain and install the "big_physarea patch" for your kernel and
-  set aside the necessary memory during boot time.
-  There seem to be several versions of this patch against
-  various kernel versions floating around in the net,
-  you may obtain one e.g. from:
-  http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz
-  You also have to compile your driver AFTER installing that patch
-  in order to get it working
-
-  or
-
-- start your kernel with the mem=xxx option, where xxx is your
-  real memory minus the memory needed for the buffers.
-  For doing this add an entry in lilo.conf (if you use lilo):
-    append "mem=xxxM"
-  or add a line in your linux.par file (if you use loadlin):
-    mem=xxxM
-
-The second method is by far easier, however it is dangerous
-if more than one driver at a time has the idea to use the memory
-leftover by setting the mem=xxx parameter below the actual
-memory size.
-
-Read also below how to use this memory!
-
-
-
-Driver Options
-==============
-
-You are able to customize the behavior of the driver by giving
-it some options at start time.
-
-default_input, default_norm
----------------------------
-
-As soon as the driver is loaded, the Buz samples video signals
-from one of its input ports and displays it on its output.
-The driver uses the Composite Input and the video norm PAL for this.
-If you want to change this default behavior, set default_input=1
-(for S-VHS input) or default_norm=1 for NTSC.
-
-v4l_nbufs, v4l_bufsize
-----------------------
-
-In order to make to make full use of the Video for Linux picture
-grabbing facilities of the driver (which are needed by many
-Video for Linux applications), the driver needs a set of
-physically contiguous buffers for grabbing. These parameters
-determine how many buffers of which size the driver will
-allocate at open (the open will fail if it is unable to do so!).
-
-These values do not affect the MJPEG grabbing facilities of the driver,
-they are needed for uncompressed image grabbing only!!!
-
-v4l_nbufs is the number of buffers to allocate, a value of 2 (the default)
-should be sufficient in almost all cases. Only special applications
-(streaming captures) will need more buffers and then mostly the
-MJPEG capturing features of the Buz will be more appropriate.
-So leave this parameter at it's default unless you know what you do.
-
-The things for v4l_bufsize are more complicated:
-v4l_bufsize is set by default to 128 [KB] which is the maximum
-amount of physically contiguous memory Linux is able to allocate
-without kernel changes. This is sufficient for grabbing 24 bit color images
-up to sizes of approx. 240x180 pixels (240*180*3 = 129600, 128 KB = 131072).
-
-In order to be able to capture bigger images you have either to
-- obtain and install the "big_physarea patch" and set aside
-  the necessary memory during boot time or
-- start your kernel with the mem=xxx option, where xxx is your
-  real memory minus the memory needed for the buffers.
-In that case, useful settings for v4l_bufsize are
-- 1296 [Kb] for grabbing 24 bit images of max size 768*576
-- 1728 [Kb] for 32bit images of same size (4*768*576 = 1728 Kb!)
-You may reduce these numbers accordingly if you know you are only
-grabbing 720 pixels wide images or NTSC images (max height 480).
-
-In some cases it may happen that Linux isn't even able to obtain
-the default 128 KB buffers. If you don't need uncompressed image
-grabbing at all, set v4l_bufsize to an arbitrary small value (e.g. 4)
-in order to be able to open the video device.
-
-vidmem
-------
-
-The video mem address of the video card.
-The driver has a little database for some videocards
-to determine it from there. If your video card is not in there
-you have either to give it to the driver as a parameter
-or set in in a VIDIOCSFBUF ioctl
-
-The videocard database is contained in the file "videocards.h"
-Gernot Ziegler wants to keep an actual version of that file.
-If your card is not contained in that file, look at
-http://www.lysator.liu.se/~gz/buz/ for an actual version of
-"videocards.h".
-
-triton, natoma
---------------
-
-The driver tries to detect if you have a triton or natome chipset
-in order to take special measures for these chipsets.
-If this detection fails but you are sure you have such a chipset,
-set the corresponding variable to 1.
-This is a very special option and may go away in the future.
-
-
-
-Programming interface
-=====================
-
-This driver should be fully compliant to Video for Linux, so all
-tools working with Video for Linux should work with (hopefully)
-no problems.
-
-A description of the Video for Linux programming interface can be found at:
-http://roadrunner.swansea.linux.org.uk/v4lapi.shtml
-
-Besides the Video for Linux interface, the driver has a "proprietary"
-interface for accessing the Buz's MJPEG capture and playback facilities.
-
-The ioctls for that interface are as follows:
-
-BUZIOC_G_PARAMS
-BUZIOC_S_PARAMS
-
-Get and set the parameters of the buz. The user should always
-do a BUZIOC_G_PARAMS (with a struct buz_params) to obtain the default
-settings, change what he likes and then make a BUZIOC_S_PARAMS call.
-A typical application should at least set the members
-input, norm and decimation of the struct buz_params.
-For a full description of all members see "buz.h"
-
-BUZIOC_REQBUFS
-
-Before being able to capture/playback, the user has to request
-the buffers he is wanting to use. Fill the structure
-buz_requestbuffers with the size (recommended: 256*1024) and
-the number (recommended 32 up to 256). There are no such restrictions
-as for the Video for Linux buffers, you should LEAVE SUFFICIENT
-MEMORY for your system however, else strange things will happen ....
-On return, the buz_requestbuffers structure contains number and
-size of the actually allocated buffers.
-You should use these numbers for doing a mmap of the buffers
-into the user space.
-The BUZIOC_REQBUFS ioctl also makes it happen, that the next mmap
-maps the MJPEG buffer instead of the V4L buffers.
-
-BUZIOC_QBUF_CAPT
-BUZIOC_QBUF_PLAY
-
-Queue a buffer for capture or playback. The first call also starts
-streaming capture. When streaming capture is going on, you may
-only queue further buffers or issue syncs until streaming
-capture is switched off again with a argument of -1 to
-a BUZIOC_QBUF_CAPT/BUZIOC_QBUF_PLAY ioctl.
-
-BUZIOC_SYNC
-
-Issue this ioctl when all buffers are queued. This ioctl will
-block until the first buffer becomes free for saving its
-data to disk (after BUZIOC_QBUF_CAPT) or for reuse (after BUZIOC_QBUF_PLAY).
-
-BUZIOC_G_STATUS
-
-Get the status of the input lines (video source connected/norm).
-This ioctl may be subject to change.
-
-
-
-
-
-See the examples directory delivered with this driver
-for actual coding examples!
diff -u --recursive --new-file v2.4.12/linux/Documentation/video4linux/bttv/CARDLIST linux/Documentation/video4linux/bttv/CARDLIST
--- v2.4.12/linux/Documentation/video4linux/bttv/CARDLIST	Sun Aug 12 13:27:58 2001
+++ linux/Documentation/video4linux/bttv/CARDLIST	Wed Oct 17 14:19:20 2001
@@ -1,15 +1,15 @@
 bttv.o
-  card=0 -  *** UNKNOWN *** 
+  card=0 -  *** UNKNOWN/GENERIC *** 
   card=1 - MIRO PCTV
-  card=2 - Hauppauge old
+  card=2 - Hauppauge (bt848)
   card=3 - STB
   card=4 - Intel
   card=5 - Diamond DTV2000
   card=6 - AVerMedia TVPhone
   card=7 - MATRIX-Vision MV-Delta
-  card=8 - Fly Video II
+  card=8 - Fly Video II (Bt848)
   card=9 - TurboTV
-  card=10 - Hauppauge new (bt878)
+  card=10 - Hauppauge (bt878)
   card=11 - MIRO PCTV pro
   card=12 - ADS Technologies Channel Surfer TV
   card=13 - AVerMedia TVCapture 98
@@ -23,7 +23,7 @@
   card=21 - Lucky Star Image World ConferenceTV
   card=22 - Phoebe Tv Master + FM
   card=23 - Modular Technology MM205 PCTV, bt878
-  card=24 - Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)
+  card=24 - [many vendors] CPH05X/06X (bt878)
   card=25 - Terratec/Vobis TV-Boostar
   card=26 - Newer Hauppauge WinCam (bt878)
   card=27 - MAXI TV Video PCI2
@@ -34,10 +34,10 @@
   card=32 - Intel Create and Share PCI
   card=33 - Terratec TerraTValue
   card=34 - Leadtek WinFast 2000
-  card=35 - Chronos Video Shuttle II
-  card=36 - Typhoon TView TV/FM Tuner
+  card=35 - Flyvideo 98 (LR50Q) / Chronos Video Shuttle II
+  card=36 - Flyvideo 98FM (LR50Q) / Typhoon TView TV/FM Tuner
   card=37 - PixelView PlayTV pro
-  card=38 - TView99 CPH063
+  card=38 - TView99 CPH06X
   card=39 - Pinnacle PCTV Studio/Rave
   card=40 - STB2
   card=41 - AVerMedia TVPhone 98
@@ -49,11 +49,11 @@
   card=47 - Terratec TV/Radio+
   card=48 - Dynalink Magic TView 
   card=49 - GV-BCTV3
-  card=50 - Prolink PV-BT878P+4E (PixelView PlayTV PAK)
+  card=50 - Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP
   card=51 - Eagle Wireless Capricorn2 (bt878A)
   card=52 - Pinnacle PCTV Studio Pro
-  card=53 - Typhoon TView RDS / FM Stereo
-  card=54 - Lifetec LT 9415 TV
+  card=53 - Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS
+  card=54 - Lifetec LT 9415 TV (LR90 Rev.F)
   card=55 - BESTBUY Easy TV
   card=56 - FlyVideo '98/FM
   card=57 - GrandTec 'Grand Video Capture'
@@ -66,6 +66,12 @@
   card=64 - ATI TV-Wonder VE
   card=65 - FlyVideo 2000S
   card=66 - Terratec TValueRadio
+  card=67 - GV-BCTV4/PCI
+  card=68 - 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)
+  card=69 - Active Imaging AIMMS
+  card=70 - PV-BT878P+
+  card=71 - Flyvideo 98EZ (capture only)
+  card=72 - Prolink PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)
 
 tuner.o
   type=0 - Temic PAL (4002 FH5)
@@ -82,7 +88,7 @@
   type=11 - Alps TSBB5
   type=12 - Alps TSBE5
   type=13 - Alps TSBC5
-  type=14 - Temic PAL_I (4006FH5)
+  type=14 - Temic PAL_BG (4006FH5)
   type=15 - Alps TSCH6
   type=16 - Temic PAL_DK (4016 FY5)
   type=17 - Philips NTSC_M (MK2)
@@ -99,3 +105,10 @@
   type=28 - LG PAL_BG+FM (TPI8PSB01D)
   type=29 - LG PAL_BG (TPI8PSB11D)
   type=30 - Temic PAL* auto + FM (4009 FN5)
+  type=31 - SHARP NTSC_JP (2U5JF5540)
+  type=32 - Samsung PAL TCPM9091PD27
+  type=33 - MT2032 universal
+  type=34 - Temic PAL_BG (4106 FH5)
+  type=35 - Temic PAL_DK/SECAM_L (4012 FY5)
+  type=36 - Temic NTSC (4136 FY5)
+  type=37 - LG PAL (newer TAPC series)
diff -u --recursive --new-file v2.4.12/linux/Documentation/video4linux/bttv/Cards linux/Documentation/video4linux/bttv/Cards
--- v2.4.12/linux/Documentation/video4linux/bttv/Cards	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/video4linux/bttv/Cards	Wed Oct 17 14:19:20 2001
@@ -0,0 +1,210 @@
+Suppported cards:
+
+
+Bt848/Bt848a/Bt849/Bt878/Bt879 cards
+------------------------------------
+
+All cards with Bt848/Bt848a/Bt849/Bt878/Bt879 and normal Composite/S-VHS inputs
+are supported.
+Teletext and Intercast support (PAL only) for ALL cards via VBI sample decoding
+in software.
+
+Some cards with additional multiplexing of inputs are only partially 
+supported (unless specifications by the card manufacturer are given).
+
+All other cards only differ by additional components as tuners, sound decoders,
+EEPROMs, teletext decoders ...
+
+
+MATRIX Vision
+-------------
+
+MV-Delta
+- Bt848A
+- 4 Composite inputs, 1 S-VHS input (shared with 4th composite)
+- EEPROM
+
+http://www.matrix-vision.de/
+
+This card has no tuner but supports all 4 composite (1 shared with an
+S-VHS input) of the Bt848A.
+Very nice card if you only have satellite TV but several tuners connected
+to the card via composite.
+
+Many thanks to Matrix-Vision for giving us 2 cards for free which made
+Bt848a/Bt849 single crytal operation support possible!!!
+
+
+
+Miro/Pinnacle PCTV
+------------------
+
+- Bt848 
+  some (all??) come with 2 crystals for PAL/SECAM and NTSC 
+- PAL, SECAM or NTSC TV tuner (Philips or TEMIC)
+- MSP34xx sound decoder on add on board
+  decoder is supported but AFAIK does not yet work 
+  (other sound MUX setting in GPIO port needed??? somebody who fixed this???)
+- 1 tuner, 1 composite and 1 S-VHS input
+- tuner type is autodetected
+
+http://www.miro.de/
+http://www.miro.com/
+
+
+Many thanks for the free card which made first NTSC support possible back
+in 1997!
+
+
+Hauppauge Win/TV pci
+--------------------
+
+There are many different versions of the Hauppauge cards with different 
+tuners (TV+Radio ...), teletext decoders.
+Note that even cards with same model numbers have (depending on the revision)
+different chips on it.
+
+- Bt848 (and others but always in 2 crystal operation???)
+  newer cards have a Bt878
+- PAL, SECAM, NTSC or tuner with or without Radio support
+
+e.g.:
+  PAL: 
+  TDA5737: VHF, hyperband and UHF mixer/oscillator for TV and VCR 3-band tuners
+  TSA5522: 1.4 GHz I2C-bus controlled synthesizer, I2C 0xc2-0xc3
+  
+  NTSC:
+  TDA5731: VHF, hyperband and UHF mixer/oscillator for TV and VCR 3-band tuners
+  TSA5518: no datasheet available on Philips site
+- Philips SAA5246 or SAA5284 ( or no) Teletext decoder chip	
+  with buffer RAM (e.g. Winbond W24257AS-35: 32Kx8 CMOS static RAM)
+  SAA5246 (I2C 0x22) is supported
+- 256 bytes EEPROM: Microchip 24LC02B or Philips 8582E2Y 
+  with configuration information
+  I2C address 0xa0 (24LC02B also responds to 0xa2-0xaf)
+- 1 tuner, 1 composite and (depending on model) 1 S-VHS input
+- 14052B: mux for selection of sound source
+- sound decoder: TDA9800, MSP34xx (stereo cards) 
+
+
+CPH-Series (CPH050, ...)
+------------------------
+Developed by TelSignal(?), OEMed by many vendors (Askey, Typhoon, 
+  Anubis, Dynalink)
+
+  Card series:
+    CPH01x: BT848 capture only
+    CPH03x: BT848
+    CPH05x: BT878 with FM
+    CPH06x: BT878 (w/o FM)
+    CPH07x: BT878 capture only
+ 
+  TV standards:
+     CPH0x0: NTSC-M/M
+     CPH0x1: PAL-B/G
+     CPH0x2: PAL-I/I
+     CPH0x3: PAL-D/K
+     CPH0x4: SECAM-L/L 
+     CPH0x5: SECAM-B/G 
+     CPH0x6: SECAM-D/K 
+     CPH0x7: PAL-N/N 
+     CPH0x8: PAL-B/H 
+     CPH0x9: PAL-M/M
+
+  CPH03x was often sold as "TV capturer".
+
+  Identifying:
+  1) 878 cards can be identified by PCI Subsystem-ID:
+      144f:3000 = CPH06x
+      144F:3002 = CPH05x w/ FM
+      144F:3005 = CPH06x_LC (w/o remote control)
+  1) The cards have a sticker with "CPH"-model on the back.
+  2) These cards have a number printed on the PCB just above the tuner metal box:
+      "80-CP2000300-x" = CPH03X
+      "80-CP2000500-x" = CPH05X
+      "80-CP2000600-x" = CPH06X / CPH06x_LC
+
+  Askey sells these cards as "Magic TView series", Brand "MagicXpress".
+  Other OEM often call these "Tview", "TView99" or else.
+
+Lifeview Flyvideo Series:
+-------------------------
+  The naming of these series differs in time and space.
+
+  Identifying:
+  1) Some models can be identified by PCI subsystem ID:
+      1852:1852 = Flyvideo 98 FM
+      1851:1850 = Flyvideo 98
+      1851:1851 = Flyvideo 98 EZ (capture only)
+  2) There is a print on the PCB:
+      LR25       = Flyvideo (Zoran)
+      LR37 Rev.C = Capture only (ZR36120 + SAA7110)
+      LR50 Rev.Q = Flyvideo 98 (w/eeprom and PCI subsystem ID)
+      LR50 Rev.W = Flyvideo 98 (no eeprom)
+      LR51 Rev.E = Flyvideo 98 EZ (capture only)
+      LR90       = Flyvideo 2000 series
+      LR90 Rev.F = Lifetec/Medion LT 9815
+      LR97       = Flyvideo DVBS
+
+  "Flyvideo II" had been the name for the 848 cards, nowadays (in Germany)
+  this name is re-used for LR50 Rev.W.
+  The Lifeview website has even more names: Flyvideo III,2100,3000,3100.
+  These cards are sold by many OEMs too.
+
+
+Typhoon TV card series:
+-----------------------
+  These can be CPH, Flyvideo, Pixelview or KNC1 series.
+  Typhoon is the brand of Anubis.
+  Model 50680 got re-used, some model no. had different contents over time.
+
+  Models:
+  50680 "TV Tuner PCI Pal BG"(old,red package)=can be CPH03x(bt848) or CPH06x(bt878)
+  50680 "TV Tuner Pal BG" (blue package)= Pixelview PV-BT878P+ (Rev 9B)
+  50681 "TV Tuner PCI Pal I" (variant of 50680)
+  50682 "TView TV/FM Tuner Pal BG"       = Flyvideo 98FM (LR50 Rev.Q)
+         Note: The package has a picture of CPH05x (which would be a real TView)
+  50683 "TV Tuner PCI SECAM" (variant of 50680)
+  50684 "TV Tuner Pal BG"                = Pixelview 878TV(Rev.3D)
+  50686 "TV Tuner"                       = KNC1 TV Station
+  50687 "TV Tuner stereo"                = KNC1 TV Station pro
+  50688 "TV Tuner RDS" (black package)   = KNC1 TV Station RDS
+  50692 "TV/FM Tuner" (small PCB)
+  50868 "TV/FM Tuner Pal I" (variant of 50682)
+  50999 "TV/FM Tuner Secam" (variant of 50682)
+
+
+Guillemot
+---------
+  Maxi TV Video 2 = LR50 Rev.Q (FI1216MF, PAL BG+SECAM)
+  Maxi TV Video 3 = CPH064 (PAL BG + SECAM)
+
+Mentor
+------
+  Mentor TV card ("55-878TV-U1") = Pixelview 878TV(Rev.3F) (w/FM w/Remote)
+
+Prolink
+-------
+   Pixelview Play TV Pro:
+     PV-BT878P+rev.9B (Play TV Pro w/FM w/NICAM)
+     PV-BT878P+rev.8X 
+     PV-BT878P+rev.4C (Play TV Pro) 
+     PV-BT878P+rev.4E (Play TV Pak) 
+     PV-BT878P+rev.2F 
+     PV-BT878TV 
+
+   PixelView Play TV 
+     PV-BT848P+
+
+Dynalink
+--------
+   These are CPH series.
+
+Phoebemicro
+-----------
+   TV Master    = CPH030 or CPH060
+   TV Master FM = CPH050
+
+Genius/Kye
+----------
+   Video Wonder/Genius Internet Video Kit = LR37 Rev.C
diff -u --recursive --new-file v2.4.12/linux/Documentation/video4linux/bttv/Insmod-options linux/Documentation/video4linux/bttv/Insmod-options
--- v2.4.12/linux/Documentation/video4linux/bttv/Insmod-options	Sun Aug 12 13:27:58 2001
+++ linux/Documentation/video4linux/bttv/Insmod-options	Wed Oct 17 14:19:20 2001
@@ -1,6 +1,6 @@
 
 bttv.o
-	the bt848 (grabber chip) driver
+	the bt848/878 (grabber chip) driver
 
 	insmod args:
 		card=n		card type, see CARDLIST for a list.
@@ -10,12 +10,11 @@
 			0: don't use PLL
 			1: 28 MHz crystal installed
 			2: 35 MHz crystal installed
-		triton1=0/1     for Triton1 compatibility
-				Triton1 is automatically recognized
-				but this might also help with other chipsets
-		vsfx=0/1	yet another chipset bug compatibility flag
-				(bt878 docs mentiones via+sis, but no
-				specific chipsets with that problem).
+
+		triton1=0/1     for Triton1 (+others) compatibility
+		vsfx=0/1	yet another chipset bug compatibility bit
+				see README.quirks for details on these two.
+
 		bigendian=n	Set the endianness of the gfx framebuffer.
 				Default is native endian.
 		fieldnr=0/1	Count fields.  Some TV descrambling software
@@ -23,8 +22,8 @@
 				50 useless IRQs/sec.  default is 0 (off).
 		autoload=0/1	autoload helper modules (tuner, audio).
 				default is 1 (on).
-		bttv_verbose=0/1/2  verbose level (at insmod time, while looking
-				at the hardware).  default is 1.
+		bttv_verbose=0/1/2  verbose level (at insmod time, while
+				looking at the hardware).  default is 1.
 		bttv_debug=0/1	debug messages (for capture).
 				default is 0 (off).
 		irq_debug=0/1	irq handler debug messages.
@@ -80,12 +79,32 @@
 		tda9850  = 1	The tea6300 can't be autodetected and is
 		tda9855  = 1	therefore off by default, if you have
 		tda9873  = 1	this one on your card (STB uses these)
-		tea6300  = 0	you have to enable it explicitly.
-		tea6420  = 1	The two tda985x chips use the same i2c
-		pic16c54 = 1	address and can't be disturgished from
-				each other, you might have to disable
+		tda9874a = 1	you have to enable it explicitly.
+		tea6300  = 0	The two tda985x chips use the same i2c
+		tea6420  = 1	address and can't be disturgished from
+		pic16c54 = 1	each other, you might have to disable
 				the wrong one.
 		debug = 1	print debug messages
+
+	insmod args for tda9874a:
+		tda9874a_SIF=1/2	select sound IF input pin (1 or 2)
+					(default is pin 1)
+		tda9874a_STD=n		select TV sound standard (0..8):
+					0 - A2, B/G
+					1 - A2, M (Korea)
+					2 - A2, D/K (1)
+					3 - A2, D/K (2)
+					4 - A2, D/K (3)
+					5 - NICAM, I
+					6 - NICAM, B/G
+					7 - NICAM, D/K (default)
+					8 - NICAM, L
+
+	Note: tda9874a is very similar to tda9874 (without 'A'-suffix), but
+	this driver will not work for the latter device (will not load).
+	Note: tda9874a and tda9875 (which is supported separately by
+	tda9875.o) use the same i2c address so both modules should not be
+	used at the same time.
 
 msp3400.o
 	The driver for the msp34xx sound processor chips. If you have a
diff -u --recursive --new-file v2.4.12/linux/Documentation/video4linux/bttv/README.quirks linux/Documentation/video4linux/bttv/README.quirks
--- v2.4.12/linux/Documentation/video4linux/bttv/README.quirks	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/video4linux/bttv/README.quirks	Wed Oct 17 14:19:20 2001
@@ -0,0 +1,83 @@
+
+Below is what the bt878 data book says about the PCI bug compatibility
+modes of the bt878 chip.
+
+The triton1 insmod option sets the EN_TBFX bit in the control register.
+The vsfx insmod option does the same for EN_VSFX bit.  If you have
+stability problems you can try if one of these options makes your box
+work solid.
+
+drivers/pci/quirks.c knows about these issues, this way these bits are
+enabled automagically for known-buggy chipsets (look at the kernel
+messages, bttv tells you).
+
+HTH,
+
+  Gerd
+
+---------------------------- cut here --------------------------
+
+Normal PCI Mode
+---------------
+
+The PCI REQ signal is the logical-or of the incoming function requests.
+The inter-nal GNT[0:1] signals are gated asynchronously with GNT and
+demultiplexed by the audio request signal. Thus the arbiter defaults to
+the video function at power-up and parks there during no requests for
+bus access. This is desirable since the video will request the bus more
+often. However, the audio will have highest bus access priority. Thus
+the audio will have first access to the bus even when issuing a request
+after the video request but before the PCI external arbiter has granted
+access to the Bt879. Neither function can preempt the other once on the
+bus. The duration to empty the entire video PCI FIFO onto the PCI bus is
+very short compared to the bus access latency the audio PCI FIFO can
+tolerate.
+
+
+430FX Compatibility Mode
+------------------------
+
+When using the 430FX PCI, the following rules will ensure
+compatibility: 
+
+ (1) Deassert REQ at the same time as asserting FRAME. 
+ (2) Do not reassert REQ to request another bus transaction until after
+     finish-ing the previous transaction.
+
+Since the individual bus masters do not have direct control of REQ, a
+simple logical-or of video and audio requests would violate the rules.
+Thus, both the arbiter and the initiator contain 430FX compatibility
+mode logic. To enable 430FX mode, set the EN_TBFX bit as indicated in
+Device Control Register on page 104.
+
+When EN_TBFX is enabled, the arbiter ensures that the two compatibility
+rules are satisfied. Before GNT is asserted by the PCI arbiter, this
+internal arbiter may still logical-or the two requests. However, once
+the GNT is issued, this arbiter must lock in its decision and now route
+only the granted request to the REQ pin. The arbiter decision lock
+happens regardless of the state of FRAME because it does not know when
+FRAME will be asserted (typically - each initiator will assert FRAME on
+the cycle following GNT). When FRAME is asserted, it is the initiator s
+responsibility to remove its request at the same time. It is the
+arbiters responsibility to allow this request to flow through to REQ and
+not allow the other request to hold REQ asserted. The decision lock may
+be removed at the end of the transaction: for example, when the bus is
+idle (FRAME and IRDY). The arbiter decision may then continue
+asynchronously until GNT is again asserted.
+
+
+Interfacing with Non-PCI 2.1 Compliant Core Logic
+-------------------------------------------------
+
+A small percentage of core logic devices may start a bus transaction
+during the same cycle that GNT is de-asserted. This is non PCI 2.1
+compliant. To ensure compatibility when using PCs with these PCI
+controllers, the EN_VSFX bit must be enabled (refer to Device Control
+Register on page 104). When in this mode, the arbiter does not pass GNT
+to the internal functions unless REQ is asserted. This prevents a bus
+transaction from starting the same cycle as GNT is de-asserted. This
+also has the side effect of not being able to take advantage of bus
+parking, thus lowering arbitration performance. The Bt879 drivers must
+query for these non-compliant devices, and set the EN_VSFX bit only if
+required.
+
diff -u --recursive --new-file v2.4.12/linux/Documentation/video4linux/bttv/Sound-FAQ linux/Documentation/video4linux/bttv/Sound-FAQ
--- v2.4.12/linux/Documentation/video4linux/bttv/Sound-FAQ	Sun Aug 12 13:27:58 2001
+++ linux/Documentation/video4linux/bttv/Sound-FAQ	Wed Oct 17 14:19:20 2001
@@ -126,6 +126,7 @@
 tuner_type      - same as tuner= insmod option
 *_modulename    - hint whenever some card needs this or that audio
                   module loaded to work properly.
+has_radio	- whenever this TV card has a radio tuner.
 
 If some config item is specified both from the tvcards array and as
 insmod option, the insmod option takes precedence.
diff -u --recursive --new-file v2.4.12/linux/Documentation/video4linux/bttv/Tuners linux/Documentation/video4linux/bttv/Tuners
--- v2.4.12/linux/Documentation/video4linux/bttv/Tuners	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/video4linux/bttv/Tuners	Wed Oct 17 14:19:20 2001
@@ -0,0 +1,88 @@
+
+SAMSUNG Tuner identification: (e.g. TCPM9091PD27)
+  TCP [ABCJLMNQ] 90[89][125] [DP] [ACD] 27 [ABCD]
+ [ABCJLMNQ]:
+   A= BG+DK
+   B= BG
+   C= I+DK
+   J= NTSC-Japan
+   L= Secam LL
+   M= BG+I+DK
+   N= NTSC 
+   Q= BG+I+DK+LL
+ [125]:
+   2: No FM
+   5: With FM
+ [DP]:
+   D= NTSC
+   P= PAL
+ [ACD]:
+   A= F-connector
+   C= Phono connector
+   D= Din Jack
+ [ABCD]:
+   3-wire/I2C tuning, 2-band/3-band
+
+Philips Tuner identification: (e.g. FM1216MF)
+  F[IRMQ]12[1345]{MF|ME|MP}
+  [IRMQ]:
+   I: Tuner Series
+   R: Tuner + Radio IF
+   M: Tuner + FM
+   Q,MR: specials
+   TD15xx: Digital Tuner ATSC
+  [1345]
+   1: PAL BG
+   3: NTSC
+   4: PAL I
+   5: Pal DK
+  {MF|ME|MP}
+   MF: w/ Secam
+   ME: BD DK I LL
+   MP: BG DK I
+   MR: BG DK M (?)
+   MG: BG DKI M (?)
+
+Temic Tuner identification: (.e.g 4006FH5)
+   4[01][0136][269]F[HYNR]5
+    40x2: Tuner (5V/33V), different I2C programming from Philips !
+    40x6: Tuner 5V
+    41xx: Tuner compact
+    40x9: Tuner+FM compact
+   [0136]
+    0: PAL BG
+    1: Pal DK, Secam LL
+    3: NTSC
+    6: PAL I
+   F[HYNR]5
+    FH5: Pal BG
+    FY5: others
+    FN5: multistandard
+    FR5: w/ FM radio
+   3X xxxx: order number with specific connector
+
+LG Innotek Tuner:
+  TPI8NSR11 : NTSC J/M    (TPI8NSR01 w/FM)  (P,210/497)
+  TPI8PSB11 : PAL B/G     (TPI8PSB01 w/FM)  (P,170/450)
+  TAPC-I701 : PAL I       (TAPC-I001 w/FM)  (P,170/450)
+  TPI8PSB12 : PAL D/K+B/G (TPI8PSB02 w/FM)  (P,170/450)
+  TAPC-H701P: NTSC_JP     (TAPC-H001P w/FM) (L,170/450)
+  TAPC-G701P: PAL B/G     (TAPC-G001P w/FM) (L,170/450)
+  TAPC-W701P: PAL I       (TAPC-W001P w/FM) (L,170/450)
+  TAPC-Q703P: PAL D/K     (TAPC-Q001P w/FM) (L,170/450)
+  TAPC-Q704P: PAL D/K+I   (L,170/450)
+  TAPC-G702P: PAL D/K+B/G (L,170/450)
+
+  TADC-H002F: NTSC (L,175/410?; 2-B, C-W+11, W+12-69)
+  TADC-M201D: PAL D/K+B/G+I (L,143/425)  (sound control at I2C address 0xc8)
+  TADC-T003F: NTSC Taiwan  (L,175/410?; 2-B, C-W+11, W+12-69)
+
+  (API,Lo-Hi-takeover/Hi-UHF-takeover)
+   I2C APIs:
+    L= LG programming (VHF_LO=0x01, VHF_HI=0x02, UHF=0x08, radio=0x04)
+    P= Philips progr. (VHF_LO=0xA0, VHF_HI=0x90, UHF=0x30, radio=0x04)
+    T= Temic progr.   (VHF_LO=0x02, VHF_HI=0x04, UHF=0x01)
+  Suffix: 
+    P= Standard phono female socket
+    D= IEC female socket
+    F= F-connector
diff -u --recursive --new-file v2.4.12/linux/Documentation/video4linux/meye.txt linux/Documentation/video4linux/meye.txt
--- v2.4.12/linux/Documentation/video4linux/meye.txt	Wed Jul 25 17:10:17 2001
+++ linux/Documentation/video4linux/meye.txt	Thu Oct 11 09:04:57 2001
@@ -4,7 +4,10 @@
 	Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
 
 This driver enable the use of video4linux compatible applications with the
-Motion Eye camera.
+Motion Eye camera. This driver requires the "Sony Vaio Programmable I/O 
+Control Device" driver (which can be found in the "Character drivers" 
+section of the kernel configuration utility) to be compiled and installed
+(using its "camera=1" parameter).
 
 It can do at maximum 30 fps @ 320x240 or 15 fps @ 640x480.
 
diff -u --recursive --new-file v2.4.12/linux/MAINTAINERS linux/MAINTAINERS
--- v2.4.12/linux/MAINTAINERS	Tue Oct  9 17:06:51 2001
+++ linux/MAINTAINERS	Sun Oct 21 10:20:57 2001
@@ -1053,6 +1053,12 @@
 L:     linux-net@vger.kernel.org
 S:     Maintained
 
+NINJA SCSI-3 / NINJA SCSI-32Bi PCMCIA SCSI HOST ADAPTER DRIVER
+P:	YOKOTA Hiroshi
+M:	yokota@netlab.is.tsukuba.ac.jp
+W:	http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
+S:	Maintained
+
 NON-IDE/NON-SCSI CDROM DRIVERS [GENERAL] (come on, crew - mark your responsibility)
 P:	Eberhard Moenkeberg
 M:	emoenke@gwdg.de
@@ -1115,6 +1121,12 @@
 W:	http://www.torque.net/linux-pp.html
 S:	Maintained
 
+PERSONALITY HANDLING
+P:	Christoph Hellwig
+M:	hch@caldera.de
+L:	linux-abi-devel@lists.sourceforge.net
+S:	Supported
+
 PCI ID DATABASE
 P:	Jens Maurer
 M:	jmaurer@cck.uni-kl.de
@@ -1286,6 +1298,13 @@
 L:	samba@samba.org
 S:	Maintained
 
+SNA NETWORK LAYER
+P:	Jay Schulist
+M:	jschlst@samba.org
+L:	linux-sna@turbolinux.com
+W:	http://www.linux-sna.org
+S:	Supported
+
 SOFTWARE RAID (Multiple Disks) SUPPORT
 P:	Ingo Molnar
 M:	mingo@redhat.com
@@ -1333,12 +1352,11 @@
 L:	linux-net@vger.kernel.org
 S:	Supported
 
-SNA NETWORK LAYER
-P:	Jay Schulist
-M:	jschlst@samba.org
-L:	linux-sna@turbolinux.com
-W:	http://www.linux-sna.org
-S:	Supported
+SRM (Alpha) environment access
+P:	Jan-Benedict Glaw
+M:	jbglaw@lug-owl.de
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
 
 STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS
 M:	support@stallion.oz.au
@@ -1397,6 +1415,13 @@
 L:	linux-net@vger.kernel.org
 L:	linux-tr@linuxtr.net
 W:	http://www.linuxtr.net
+S:	Maintained
+
+TOSHIBA SMM DRIVER
+P:	Jonathan Buzzard
+M:	jonathan@buzzard.org.uk
+L:	tlinux-users@tce.toshiba-dme.co.jp
+W:	http://www.buzzard.org.uk/toshiba/
 S:	Maintained
 
 TRIDENT 4DWAVE/SIS 7018 PCI AUDIO CORE
diff -u --recursive --new-file v2.4.12/linux/Makefile linux/Makefile
--- v2.4.12/linux/Makefile	Thu Oct 11 08:02:26 2001
+++ linux/Makefile	Sat Oct 20 19:15:54 2001
@@ -1,11 +1,12 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 12
-EXTRAVERSION =
+SUBLEVEL = 13
+EXTRAVERSION =-pre6
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
+KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//")
 
 CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
 	  else if [ -x /bin/bash ]; then echo /bin/bash; \
@@ -176,7 +177,7 @@
 DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a
 DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
 DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
-DRIVERS-$(CONFIG_I2O) += drivers/i2o/i2o.o
+DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o
 DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o
 DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
 DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.4.12/linux/arch/alpha/kernel/alpha_ksyms.c	Sun Sep 23 11:40:54 2001
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Fri Oct 12 15:35:53 2001
@@ -127,10 +127,16 @@
 EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(pci_free_consistent);
 EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(pci_map_page);
 EXPORT_SYMBOL(pci_unmap_single);
+EXPORT_SYMBOL(pci_unmap_page);
 EXPORT_SYMBOL(pci_map_sg);
 EXPORT_SYMBOL(pci_unmap_sg);
 EXPORT_SYMBOL(pci_dma_supported);
+EXPORT_SYMBOL(pci_dac_dma_supported);
+EXPORT_SYMBOL(pci_dac_page_to_dma);
+EXPORT_SYMBOL(pci_dac_dma_to_page);
+EXPORT_SYMBOL(pci_dac_dma_to_offset);
 #endif
 
 EXPORT_SYMBOL(dump_thread);
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c
--- v2.4.12/linux/arch/alpha/kernel/core_cia.c	Sun Sep 23 11:40:55 2001
+++ linux/arch/alpha/kernel/core_cia.c	Sun Oct 21 10:30:58 2001
@@ -321,7 +321,7 @@
  * be purged to make room for the new entries coming in for the garbage page.
  */
 
-#define CIA_BROKEN_TBIA_BASE	0xE0000000
+#define CIA_BROKEN_TBIA_BASE	0x30000000
 #define CIA_BROKEN_TBIA_SIZE	1024
 
 /* Always called with interrupts disabled */
@@ -382,10 +382,10 @@
 	for (i = 0; i < CIA_BROKEN_TBIA_SIZE / sizeof(unsigned long); ++i)
 		ppte[i] = pte;
 
-	*(vip)CIA_IOC_PCI_W3_BASE = CIA_BROKEN_TBIA_BASE | 3;
-	*(vip)CIA_IOC_PCI_W3_MASK = (CIA_BROKEN_TBIA_SIZE*1024 - 1)
+	*(vip)CIA_IOC_PCI_W1_BASE = CIA_BROKEN_TBIA_BASE | 3;
+	*(vip)CIA_IOC_PCI_W1_MASK = (CIA_BROKEN_TBIA_SIZE*1024 - 1)
 				    & 0xfff00000;
-	*(vip)CIA_IOC_PCI_T3_BASE = virt_to_phys(ppte) >> 2;
+	*(vip)CIA_IOC_PCI_T1_BASE = virt_to_phys(ppte) >> 2;
 }
 
 static void __init
@@ -595,6 +595,8 @@
 failed:
 	printk("pci: disabling sg translation window\n");
 	*(vip)CIA_IOC_PCI_W0_BASE = 0;
+	*(vip)CIA_IOC_PCI_W1_BASE = 0;
+	pci_isa_hose->sg_isa = NULL;
 	alpha_mv.mv_pci_tbi = NULL;
 	goto exit;
 }
@@ -635,10 +637,11 @@
 	*(vip)CIA_IOC_HAE_IO = 0;
 
 	/* For PYXIS, we always use BWX bus and i/o accesses.  To that end,
-	   make sure they're enabled on the controller.  */
+	   make sure they're enabled on the controller.  At the same time,
+	   enable the monster window.  */
 	if (is_pyxis) {
 		temp = *(vip)CIA_IOC_CIA_CNFG;
-		temp |= CIA_CNFG_IOA_BWEN;
+		temp |= CIA_CNFG_IOA_BWEN | CIA_CNFG_PCI_MWEN;
 		*(vip)CIA_IOC_CIA_CNFG = temp;
 	}
 
@@ -682,13 +685,9 @@
 	 * Set up the PCI to main memory translation windows.
 	 *
 	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
-	 * Window 1 is direct access 1GB at 1GB
-	 * Window 2 is direct access 1GB at 2GB
-	 *
-	 * We must actually use 2 windows to direct-map the 2GB space,
-	 * because of an idiot-syncrasy of the CYPRESS chip used on 
-	 * many PYXIS systems.  It may respond to a PCI bus address in
-	 * the last 1MB of the 4GB address range.
+	 * Window 1 is scatter-gather 1MB at 768MB (for tbia)
+	 * Window 2 is direct access 2GB at 2GB
+	 * Window 3 is DAC access 4GB at 8GB
 	 *
 	 * ??? NetBSD hints that page tables must be aligned to 32K,
 	 * possibly due to a hardware bug.  This is over-aligned
@@ -698,20 +697,35 @@
 
 	hose->sg_pci = NULL;
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 32768);
-	__direct_map_base = 0x40000000;
+	__direct_map_base = 0x80000000;
 	__direct_map_size = 0x80000000;
 
 	*(vip)CIA_IOC_PCI_W0_BASE = hose->sg_isa->dma_base | 3;
 	*(vip)CIA_IOC_PCI_W0_MASK = (hose->sg_isa->size - 1) & 0xfff00000;
 	*(vip)CIA_IOC_PCI_T0_BASE = virt_to_phys(hose->sg_isa->ptes) >> 2;
 
-	*(vip)CIA_IOC_PCI_W1_BASE = 0x40000000 | 1;
-	*(vip)CIA_IOC_PCI_W1_MASK = (0x40000000 - 1) & 0xfff00000;
-	*(vip)CIA_IOC_PCI_T1_BASE = 0 >> 2;
-
-	*(vip)CIA_IOC_PCI_W2_BASE = 0x80000000 | 1;
-	*(vip)CIA_IOC_PCI_W2_MASK = (0x40000000 - 1) & 0xfff00000;
-	*(vip)CIA_IOC_PCI_T2_BASE = 0x40000000 >> 2;
+	*(vip)CIA_IOC_PCI_W2_BASE = __direct_map_base | 1;
+	*(vip)CIA_IOC_PCI_W2_MASK = (__direct_map_size - 1) & 0xfff00000;
+	*(vip)CIA_IOC_PCI_T2_BASE = 0 >> 2;
+
+	/* On PYXIS we have the monster window, selected by bit 40, so
+	   there is no need for window3 to be enabled.
+
+	   On CIA, we don't have true arbitrary addressing -- bits <39:32>
+	   are compared against W_DAC.  We can, however, directly map 4GB,
+	   which is better than before.  However, due to assumptions made
+	   elsewhere, we should not claim that we support DAC unless that
+	   4GB covers all of physical memory.  */
+	if (is_pyxis || max_low_pfn > (0x100000000 >> PAGE_SHIFT)) {
+		*(vip)CIA_IOC_PCI_W3_BASE = 0;
+	} else {
+		*(vip)CIA_IOC_PCI_W3_BASE = 0x00000000 | 1 | 8;
+		*(vip)CIA_IOC_PCI_W3_MASK = 0xfff00000;
+		*(vip)CIA_IOC_PCI_T3_BASE = 0 >> 2;
+
+		alpha_mv.pci_dac_offset = 0x200000000;
+		*(vip)CIA_IOC_PCI_W_DAC = alpha_mv.pci_dac_offset >> 32;
+	}
 
 	/* Prepare workaround for apparently broken tbia. */
 	cia_prepare_tbia_workaround();
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c
--- v2.4.12/linux/arch/alpha/kernel/core_mcpcia.c	Fri Mar  2 11:12:07 2001
+++ linux/arch/alpha/kernel/core_mcpcia.c	Fri Oct 12 15:35:53 2001
@@ -406,12 +406,12 @@
 	 * Set up the PCI->physical memory translation windows.
 	 *
 	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
-	 * Window 1 is scatter-gather 128MB at 1GB
+	 * Window 1 is scatter-gather (up to) 1GB at 1GB (for pci)
 	 * Window 2 is direct access 2GB at 2GB
-	 * ??? We ought to scale window 1 with memory.
 	 */
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
-	hose->sg_pci = iommu_arena_new(hose, 0x40000000, 0x08000000, 0);
+	hose->sg_pci = iommu_arena_new(hose, 0x40000000,
+				       size_for_memory(0x40000000), 0);
 
 	__direct_map_base = 0x80000000;
 	__direct_map_size = 0x80000000;
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/core_titan.c linux/arch/alpha/kernel/core_titan.c
--- v2.4.12/linux/arch/alpha/kernel/core_titan.c	Fri Mar  2 11:12:07 2001
+++ linux/arch/alpha/kernel/core_titan.c	Sun Oct 21 10:30:58 2001
@@ -20,6 +20,8 @@
 #include <asm/core_titan.h>
 #undef __EXTERN_INLINE
 
+#include <linux/bootmem.h>
+
 #include "proto.h"
 #include "pci_impl.h"
 
@@ -277,6 +279,7 @@
 titan_init_one_pachip_port(titan_pachip_port *port, int index)
 {
 	struct pci_controller *hose;
+	unsigned long sg_size;
 
 	hose = alloc_pci_controller();
 	if (index == 0)
@@ -342,40 +345,35 @@
 	 * Note: Window 3 on Titan is Scatter-Gather ONLY
 	 *
 	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
-	 * Window 1 is direct access 1GB at 1GB
-	 * Window 2 is direct access 1GB at 2GB
-	 * Window 3 is scatter-gather 128MB at 3GB
-	 * ??? We ought to scale window 3 memory.
-	 *
-	 * We must actually use 2 windows to direct-map the 2GB space,
-	 * because of an idiot-syncrasy of the CYPRESS chip.  It may
-	 * respond to a PCI bus address in the last 1MB of the 4GB
-	 * address range.
+	 * Window 1 is scatter-gather (up to) 1GB at 1GB
+	 * Window 2 is direct access 2GB at 2GB
 	 */
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
 	hose->sg_isa->align_entry = 8; /* 64KB for ISA */
 
-	hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0);
+	hose->sg_pci = iommu_arena_new(hose, 0x40000000,
+				       size_for_memory(0x40000000), 0);
 	hose->sg_pci->align_entry = 4; /* Titan caches 4 PTEs at a time */
 
-	__direct_map_base = 0x40000000;
+	__direct_map_base = 0x80000000;
 	__direct_map_size = 0x80000000;
 
 	port->wsba[0].csr = hose->sg_isa->dma_base | 3;
 	port->wsm[0].csr  = (hose->sg_isa->size - 1) & 0xfff00000;
 	port->tba[0].csr  = virt_to_phys(hose->sg_isa->ptes);
 
-	port->wsba[1].csr = 0x40000000 | 1;
-	port->wsm[1].csr  = (0x40000000 - 1) & 0xfff00000;
-	port->tba[1].csr  = 0;
+	port->wsba[1].csr = hose->sg_pci->dma_base | 3;
+	port->wsm[1].csr  = (hose->sg_pci->size - 1) & 0xfff00000;
+	port->tba[1].csr  = virt_to_phys(hose->sg_pci->ptes);
 
 	port->wsba[2].csr = 0x80000000 | 1;
-	port->wsm[2].csr  = (0x40000000 - 1) & 0xfff00000;
-	port->tba[2].csr  = 0x40000000;
+	port->wsm[2].csr  = (0x80000000 - 1) & 0xfff00000;
+	port->tba[2].csr  = 0;
+
+	port->wsba[3].csr = 0;
 
-	port->wsba[3].csr = hose->sg_pci->dma_base | 3;
-	port->wsm[3].csr  = (hose->sg_pci->size - 1) & 0xfff00000;
-	port->tba[3].csr  = virt_to_phys(hose->sg_pci->ptes);
+	/* Enable the Monster Window to make DAC pci64 possible. */
+	port->pctl.csr |= pctl_m_mwin;
 
 	titan_pci_tbi(hose, 0, -1);
 }
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c
--- v2.4.12/linux/arch/alpha/kernel/core_tsunami.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/alpha/kernel/core_tsunami.c	Sun Oct 21 10:30:58 2001
@@ -279,16 +279,6 @@
 #define FN __FUNCTION__
 
 static void __init
-tsunami_monster_window_enable(tsunami_pchip * pchip)
-{
-	volatile unsigned long * csr = &pchip->pctl.csr;
-
-	*csr |= pctl_m_mwin;
-	mb();
-	*csr;
-}
-
-static void __init
 tsunami_init_one_pchip(tsunami_pchip *pchip, int index)
 {
 	struct pci_controller *hose;
@@ -358,47 +348,34 @@
 	 * Note: Window 3 is scatter-gather only
 	 * 
 	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
-	 * Window 1 is direct access 1GB at 1GB
-	 * Window 2 is direct access 1GB at 2GB
-	 * Window 3 is scatter-gather 128MB at 3GB
-	 * ??? We ought to scale window 3 memory.
-	 *
-	 * We must actually use 2 windows to direct-map the 2GB space,
-	 * because of an idiot-syncrasy of the CYPRESS chip.  It may
-	 * respond to a PCI bus address in the last 1MB of the 4GB
-	 * address range.
+	 * Window 1 is scatter-gather (up to) 1GB at 1GB
+	 * Window 2 is direct access 2GB at 2GB
 	 */
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
-	{
-		unsigned long size = 0x08000000;
-		if (max_low_pfn > (0x80000000 >> PAGE_SHIFT))
-			size = 0x40000000;
-		hose->sg_pci = iommu_arena_new(hose, 0xc0000000, size, 0);
-	}
-	
-	__direct_map_base = 0x40000000;
+	hose->sg_pci = iommu_arena_new(hose, 0x40000000,
+				       size_for_memory(0x40000000), 0);
+
+	__direct_map_base = 0x80000000;
 	__direct_map_size = 0x80000000;
 
 	pchip->wsba[0].csr = hose->sg_isa->dma_base | 3;
 	pchip->wsm[0].csr  = (hose->sg_isa->size - 1) & 0xfff00000;
 	pchip->tba[0].csr  = virt_to_phys(hose->sg_isa->ptes);
 
-	pchip->wsba[1].csr = 0x40000000 | 1;
-	pchip->wsm[1].csr  = (0x40000000 - 1) & 0xfff00000;
-	pchip->tba[1].csr  = 0;
+	pchip->wsba[1].csr = hose->sg_pci->dma_base | 3;
+	pchip->wsm[1].csr  = (hose->sg_pci->size - 1) & 0xfff00000;
+	pchip->tba[1].csr  = virt_to_phys(hose->sg_pci->ptes);
 
 	pchip->wsba[2].csr = 0x80000000 | 1;
-	pchip->wsm[2].csr  = (0x40000000 - 1) & 0xfff00000;
-	pchip->tba[2].csr  = 0x40000000;
+	pchip->wsm[2].csr  = (0x80000000 - 1) & 0xfff00000;
+	pchip->tba[2].csr  = 0;
 
-	pchip->wsba[3].csr = hose->sg_pci->dma_base | 3;
-	pchip->wsm[3].csr  = (hose->sg_pci->size - 1) & 0xfff00000;
-	pchip->tba[3].csr  = virt_to_phys(hose->sg_pci->ptes);
-
-	tsunami_pci_tbi(hose, 0, -1);
+	pchip->wsba[3].csr = 0;
 
 	/* Enable the Monster Window to make DAC pci64 possible. */
-	tsunami_monster_window_enable(pchip);
+	pchip->pctl.csr |= pctl_m_mwin;
+
+	tsunami_pci_tbi(hose, 0, -1);
 }
 
 void __init
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c
--- v2.4.12/linux/arch/alpha/kernel/pci.c	Sun Sep 23 11:40:55 2001
+++ linux/arch/alpha/kernel/pci.c	Sun Oct 21 10:30:58 2001
@@ -79,35 +79,30 @@
 static void __init
 quirk_cypress(struct pci_dev *dev)
 {
-/*
- * Notorious Cy82C693 chip. One of its numerous bugs: although
- * Cypress IDE controller doesn't support native mode, it has
- * programmable addresses of IDE command/control registers.
- * This violates PCI specifications, confuses IDE subsystem
- * and causes resource conflict between primary HD_CMD register
- * and floppy controller. Ugh.
- * Fix that.
- */
+	/* The Notorious Cy82C693 chip.  */
+
+	/* The Cypress IDE controller doesn't support native mode, but it
+	   has programmable addresses of IDE command/control registers.
+	   This violates PCI specifications, confuses the IDE subsystem and
+	   causes resource conflicts between the primary HD_CMD register and
+	   the floppy controller.  Ugh.  Fix that.  */
 	if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE) {
 		dev->resource[0].flags = 0;
 		dev->resource[1].flags = 0;
-		return;
 	}
-/*
- * Another "feature": Cypress bridge responds on the PCI bus
- * in the address range 0xffff0000-0xffffffff (conventional
- * x86 BIOS ROM). No way to turn this off, so if we use
- * large SG window, we must avoid these addresses.
- */
-	if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA) {
-		struct pci_controller *hose = dev->sysdata;
-		long overlap;
 
-		if (hose->sg_pci) {
-			overlap = hose->sg_pci->dma_base + hose->sg_pci->size;
-			overlap -= 0xffff0000;
-			if (overlap > 0)
-				hose->sg_pci->size -= overlap;
+	/* The Cypress bridge responds on the PCI bus in the address range
+	   0xffff0000-0xffffffff (conventional x86 BIOS ROM).  There is no
+	   way to turn this off, so if we use a large direct-map window, or
+	   a large SG window, we must avoid this region.  */
+	else if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA) {
+		if (__direct_map_base + __direct_map_size >= 0xffff0000)
+			__direct_map_size = 0xffff0000 - __direct_map_base;
+		else {
+			struct pci_controller *hose = dev->sysdata;
+			struct pci_iommu_arena *pci = hose->sg_pci;
+			if (pci && pci->dma_base + pci->size >= 0xffff0000)
+				pci->size = 0xffff0000 - pci->dma_base;
 		}
 	}
 }
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/pci_impl.h linux/arch/alpha/kernel/pci_impl.h
--- v2.4.12/linux/arch/alpha/kernel/pci_impl.h	Sun Sep 23 11:40:55 2001
+++ linux/arch/alpha/kernel/pci_impl.h	Fri Oct 12 15:35:53 2001
@@ -163,6 +163,8 @@
 extern const char *const pci_mem_names[];
 extern const char pci_hae0_name[];
 
+extern unsigned long size_for_memory(unsigned long max);
+
 extern int iommu_reserve(struct pci_iommu_arena *, long, long);
 extern int iommu_release(struct pci_iommu_arena *, long, long);
 extern int iommu_bind(struct pci_iommu_arena *, long, long, unsigned long *);
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c
--- v2.4.12/linux/arch/alpha/kernel/pci_iommu.c	Sun Sep 23 11:40:55 2001
+++ linux/arch/alpha/kernel/pci_iommu.c	Fri Oct 12 15:35:53 2001
@@ -17,17 +17,18 @@
 
 #define DEBUG_ALLOC 0
 #if DEBUG_ALLOC > 0
-# define DBGA(args...)		printk(KERN_DEBUG ##args)
+# define DBGA(args...)		printk(KERN_DEBUG args)
 #else
 # define DBGA(args...)
 #endif
 #if DEBUG_ALLOC > 1
-# define DBGA2(args...)		printk(KERN_DEBUG ##args)
+# define DBGA2(args...)		printk(KERN_DEBUG args)
 #else
 # define DBGA2(args...)
 #endif
 
 #define DEBUG_NODIRECT 0
+#define DEBUG_FORCEDAC 0
 
 
 static inline unsigned long
@@ -43,6 +44,18 @@
 }
 
 
+/* Return the minimum of MAX or the first power of two larger
+   than main memory.  */
+
+unsigned long
+size_for_memory(unsigned long max)
+{
+	unsigned long mem = max_low_pfn << PAGE_SHIFT;
+	if (mem < max)
+		max = 1UL << ceil_log2(mem);
+	return max;
+}
+
 struct pci_iommu_arena *
 iommu_arena_new(struct pci_controller *hose, dma_addr_t base,
 		unsigned long window_size, unsigned long align)
@@ -163,8 +176,9 @@
    Once the device is given the dma address, the device owns this memory
    until either pci_unmap_single or pci_dma_sync_single is performed.  */
 
-dma_addr_t
-pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction)
+static dma_addr_t
+pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
+		 int dac_allowed)
 {
 	struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose;
 	dma_addr_t max_dma = pdev ? pdev->dma_mask : 0x00ffffff;
@@ -173,10 +187,7 @@
 	unsigned long paddr;
 	dma_addr_t ret;
 
-	if (direction == PCI_DMA_NONE)
-		BUG();
-
-	paddr = virt_to_phys(cpu_addr);
+	paddr = __pa(cpu_addr);
 
 #if !DEBUG_NODIRECT
 	/* First check to see if we can use the direct map window.  */
@@ -184,13 +195,23 @@
 	    && paddr + size <= __direct_map_size) {
 		ret = paddr + __direct_map_base;
 
-		DBGA2("pci_map_single: [%p,%lx] -> direct %x from %p\n",
+		DBGA2("pci_map_single: [%p,%lx] -> direct %lx from %p\n",
 		      cpu_addr, size, ret, __builtin_return_address(0));
 
 		return ret;
 	}
 #endif
 
+	/* Next, use DAC if selected earlier.  */
+	if (dac_allowed) {
+		ret = paddr + alpha_mv.pci_dac_offset;
+
+		DBGA2("pci_map_single: [%p,%lx] -> DAC %lx from %p\n",
+		      cpu_addr, size, ret, __builtin_return_address(0));
+
+		return ret;
+	}
+
 	/* If the machine doesn't define a pci_tbi routine, we have to
 	   assume it doesn't support sg mapping.  */
 	if (! alpha_mv.mv_pci_tbi) {
@@ -217,12 +238,30 @@
 	ret = arena->dma_base + dma_ofs * PAGE_SIZE;
 	ret += (unsigned long)cpu_addr & ~PAGE_MASK;
 
-	DBGA("pci_map_single: [%p,%lx] np %ld -> sg %x from %p\n",
-	     cpu_addr, size, npages, ret, __builtin_return_address(0));
+	DBGA2("pci_map_single: [%p,%lx] np %ld -> sg %lx from %p\n",
+	      cpu_addr, size, npages, ret, __builtin_return_address(0));
 
 	return ret;
 }
 
+dma_addr_t
+pci_map_single(struct pci_dev *pdev, void *cpu_addr, size_t size, int dir)
+{
+	if (dir == PCI_DMA_NONE)
+		BUG();
+	return pci_map_single_1(pdev, cpu_addr, size,
+			        (pdev->dma_mask >> 32) != 0);
+}
+
+dma_addr_t
+pci_map_page(struct pci_dev *pdev, struct page *page, unsigned long offset,
+	     size_t size, int dir)
+{
+	if (dir == PCI_DMA_NONE)
+		BUG();
+	return pci_map_single_1(pdev, (char *)page_address(page) + offset,
+			        size, (pdev->dma_mask >> 32) != 0);
+}
 
 /* Unmap a single streaming mode DMA translation.  The DMA_ADDR and
    SIZE must match what was provided for in a previous pci_map_single
@@ -231,7 +270,7 @@
    wrote there.  */
 
 void
-pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size,
+pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
 		 int direction)
 {
 	unsigned long flags;
@@ -242,17 +281,21 @@
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
-#if !DEBUG_NODIRECT
 	if (dma_addr >= __direct_map_base
 	    && dma_addr < __direct_map_base + __direct_map_size) {
 		/* Nothing to do.  */
 
-		DBGA2("pci_unmap_single: direct [%x,%lx] from %p\n",
+		DBGA2("pci_unmap_single: direct [%lx,%lx] from %p\n",
 		      dma_addr, size, __builtin_return_address(0));
 
 		return;
 	}
-#endif
+
+	if (dma_addr > 0xffffffff) {
+		DBGA2("pci64_unmap_single: DAC [%lx,%lx] from %p\n",
+		      dma_addr, size, __builtin_return_address(0));
+		return;
+	}
 
 	arena = hose->sg_pci;
 	if (!arena || dma_addr < arena->dma_base)
@@ -260,7 +303,7 @@
 
 	dma_ofs = (dma_addr - arena->dma_base) >> PAGE_SHIFT;
 	if (dma_ofs * PAGE_SIZE >= arena->size) {
-		printk(KERN_ERR "Bogus pci_unmap_single: dma_addr %x "
+		printk(KERN_ERR "Bogus pci_unmap_single: dma_addr %lx "
 		       " base %x size %x\n", dma_addr, arena->dma_base,
 		       arena->size);
 		return;
@@ -273,21 +316,24 @@
 
 	iommu_arena_free(arena, dma_ofs, npages);
 
-
-        /*
-	   If we're freeing ptes above the `next_entry' pointer (they
+        /* If we're freeing ptes above the `next_entry' pointer (they
            may have snuck back into the TLB since the last wrap flush),
-           we need to flush the TLB before reallocating the latter.
-	*/
+           we need to flush the TLB before reallocating the latter.  */
 	if (dma_ofs >= arena->next_entry)
 		alpha_mv.mv_pci_tbi(hose, dma_addr, dma_addr + size - 1);
 
 	spin_unlock_irqrestore(&arena->lock, flags);
 
-	DBGA("pci_unmap_single: sg [%x,%lx] np %ld from %p\n",
-	     dma_addr, size, npages, __builtin_return_address(0));
+	DBGA2("pci_unmap_single: sg [%lx,%lx] np %ld from %p\n",
+	      dma_addr, size, npages, __builtin_return_address(0));
 }
 
+void
+pci_unmap_page(struct pci_dev *pdev, dma_addr_t dma_addr,
+	       size_t size, int direction)
+{
+	pci_unmap_single(pdev, dma_addr, size, direction);
+}
 
 /* Allocate and map kernel buffer using consistent mode DMA for PCI
    device.  Returns non-NULL cpu-view pointer to the buffer if
@@ -295,7 +341,7 @@
    else DMA_ADDRP is undefined.  */
 
 void *
-pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp)
+pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp)
 {
 	void *cpu_addr;
 	long order = get_order(size);
@@ -311,8 +357,7 @@
 	}
 	memset(cpu_addr, 0, size);
 
-	*dma_addrp = pci_map_single(pdev, cpu_addr, size,
-				    PCI_DMA_BIDIRECTIONAL);
+	*dma_addrp = pci_map_single_1(pdev, cpu_addr, size, 0);
 	if (*dma_addrp == 0) {
 		free_pages((unsigned long)cpu_addr, order);
 		return NULL;
@@ -324,7 +369,6 @@
 	return cpu_addr;
 }
 
-
 /* Free and unmap a consistent DMA buffer.  CPU_ADDR and DMA_ADDR must
    be values that were returned from pci_alloc_consistent.  SIZE must
    be the same as what as passed into pci_alloc_consistent.
@@ -332,7 +376,7 @@
    DMA_ADDR past this call are illegal.  */
 
 void
-pci_free_consistent(struct pci_dev *pdev, long size, void *cpu_addr,
+pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr,
 		    dma_addr_t dma_addr)
 {
 	pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
@@ -352,27 +396,35 @@
    Write dma_length of each leader with the combined lengths of
    the mergable followers.  */
 
+#define SG_ENT_VIRT_ADDRESS(SG)				\
+	((SG)->address					\
+	 ? (SG)->address				\
+	 : page_address((SG)->page) + (SG)->offset)
+
+#define SG_ENT_PHYS_ADDRESS(SG)	\
+        __pa(SG_ENT_VIRT_ADDRESS(SG))
+
 static void
 sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok)
 {
-	unsigned long next_vaddr;
+	unsigned long next_paddr;
 	struct scatterlist *leader;
 	long leader_flag, leader_length;
 
 	leader = sg;
 	leader_flag = 0;
 	leader_length = leader->length;
-	next_vaddr = (unsigned long)leader->address + leader_length;
+	next_paddr = SG_ENT_PHYS_ADDRESS(leader) + leader_length;
 
 	for (++sg; sg < end; ++sg) {
 		unsigned long addr, len;
-		addr = (unsigned long) sg->address;
+		addr = SG_ENT_PHYS_ADDRESS(sg);
 		len = sg->length;
 
-		if (next_vaddr == addr) {
+		if (next_paddr == addr) {
 			sg->dma_address = -1;
 			leader_length += len;
-		} else if (((next_vaddr | addr) & ~PAGE_MASK) == 0 && virt_ok) {
+		} else if (((next_paddr | addr) & ~PAGE_MASK) == 0 && virt_ok) {
 			sg->dma_address = -2;
 			leader_flag = 1;
 			leader_length += len;
@@ -384,7 +436,7 @@
 			leader_length = len;
 		}
 
-		next_vaddr = addr + len;
+		next_paddr = addr + len;
 	}
 
 	leader->dma_address = leader_flag;
@@ -397,9 +449,9 @@
 static inline int
 sg_fill(struct scatterlist *leader, struct scatterlist *end,
 	struct scatterlist *out, struct pci_iommu_arena *arena,
-	dma_addr_t max_dma)
+	dma_addr_t max_dma, int dac_allowed)
 {
-	unsigned long paddr = virt_to_phys(leader->address);
+	unsigned long paddr = SG_ENT_PHYS_ADDRESS(leader);
 	long size = leader->dma_length;
 	struct scatterlist *sg;
 	unsigned long *ptes;
@@ -414,13 +466,24 @@
 		out->dma_address = paddr + __direct_map_base;
 		out->dma_length = size;
 
-		DBGA("    sg_fill: [%p,%lx] -> direct %x\n",
-		     leader->address, size, out->dma_address);
+		DBGA("    sg_fill: [%p,%lx] -> direct %lx\n",
+		     __va(paddr), size, out->dma_address);
 
 		return 0;
 	}
 #endif
 
+	/* If physically contiguous and DAC is available, use it.  */
+	if (leader->dma_address == 0 && dac_allowed) {
+		out->dma_address = paddr + alpha_mv.pci_dac_offset;
+		out->dma_length = size;
+
+		DBGA("    sg_fill: [%p,%lx] -> DAC %lx\n",
+		     __va(paddr), size, out->dma_address);
+
+		return 0;
+	}
+
 	/* Otherwise, we'll use the iommu to make the pages virtually
 	   contiguous.  */
 
@@ -433,17 +496,16 @@
 			return -1;
 
 		/* Otherwise, break up the remaining virtually contiguous
-		   hunks into individual direct maps.  */
+		   hunks into individual direct maps and retry.  */
 		sg_classify(leader, end, 0);
-		/* Retry.  */
-		return sg_fill(leader, end, out, arena, max_dma);
+		return sg_fill(leader, end, out, arena, max_dma, dac_allowed);
 	}
 
 	out->dma_address = arena->dma_base + dma_ofs*PAGE_SIZE + paddr;
 	out->dma_length = size;
 
-	DBGA("    sg_fill: [%p,%lx] -> sg %x np %ld\n",
-	     leader->address, size, out->dma_address, npages);
+	DBGA("    sg_fill: [%p,%lx] -> sg %lx np %ld\n",
+	     __va(paddr), size, out->dma_address, npages);
 
 	/* All virtually contiguous.  We need to find the length of each
 	   physically contiguous subsegment to fill in the ptes.  */
@@ -455,7 +517,7 @@
 #endif
 
 		size = sg->length;
-		paddr = virt_to_phys(sg->address);
+		paddr = SG_ENT_PHYS_ADDRESS(sg);
 
 		while (sg+1 < end && (int) sg[1].dma_address == -1) {
 			size += sg[1].length;
@@ -470,11 +532,11 @@
 
 #if DEBUG_ALLOC > 0
 		DBGA("    (%ld) [%p,%x] np %ld\n",
-		     last_sg - leader, last_sg->address,
+		     last_sg - leader, SG_ENT_VIRT_ADDRESS(last_sg),
 		     last_sg->length, npages);
 		while (++last_sg <= sg) {
 			DBGA("        (%ld) [%p,%x] cont\n",
-			     last_sg - leader, last_sg->address,
+			     last_sg - leader, SG_ENT_VIRT_ADDRESS(last_sg),
 			     last_sg->length);
 		}
 #endif
@@ -491,15 +553,19 @@
 	struct pci_controller *hose;
 	struct pci_iommu_arena *arena;
 	dma_addr_t max_dma;
+	int dac_allowed;
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
+	dac_allowed = ((pdev->dma_mask >> 32) != 0);
+
 	/* Fast path single entry scatterlists.  */
 	if (nents == 1) {
 		sg->dma_length = sg->length;
 		sg->dma_address
-		  = pci_map_single(pdev, sg->address, sg->length, direction);
+		  = pci_map_single_1(pdev, SG_ENT_VIRT_ADDRESS(sg),
+				     sg->length, dac_allowed);
 		return sg->dma_address != 0;
 	}
 
@@ -527,7 +593,7 @@
 	for (out = sg; sg < end; ++sg) {
 		if ((int) sg->dma_address < 0)
 			continue;
-		if (sg_fill(sg, end, out, arena, max_dma) < 0)
+		if (sg_fill(sg, end, out, arena, max_dma, dac_allowed) < 0)
 			goto error;
 		out++;
 	}
@@ -542,7 +608,7 @@
 
 	return out - start;
 
-error:
+ error:
 	printk(KERN_WARNING "pci_map_sg failed: "
 	       "could not allocate dma page tables\n");
 
@@ -553,7 +619,6 @@
 	return 0;
 }
 
-
 /* Unmap a set of streaming mode DMA translations.  Again, cpu read
    rules concerning calls here are the same as for pci_unmap_single()
    above.  */
@@ -586,7 +651,8 @@
 	spin_lock_irqsave(&arena->lock, flags);
 
 	for (end = sg + nents; sg < end; ++sg) {
-		unsigned long addr, size;
+		dma64_addr_t addr;
+		size_t size;
 		long npages, ofs;
 		dma_addr_t tend;
 
@@ -595,7 +661,13 @@
 		if (!size)
 			break;
 
-#if !DEBUG_NODIRECT
+		if (addr > 0xffffffff) {
+			/* It's a DAC address -- nothing to do.  */
+			DBGA("    (%ld) DAC [%lx,%lx]\n",
+			      sg - end + nents, addr, size);
+			continue;
+		}
+
 		if (addr >= __direct_map_base
 		    && addr < __direct_map_base + __direct_map_size) {
 			/* Nothing to do.  */
@@ -603,7 +675,6 @@
 			      sg - end + nents, addr, size);
 			continue;
 		}
-#endif
 
 		DBGA("    (%ld) sg [%lx,%lx]\n",
 		     sg - end + nents, addr, size);
@@ -617,29 +688,27 @@
 		if (fend < tend) fend = tend;
 	}
 
-        /*
-	   If we're freeing ptes above the `next_entry' pointer (they
+        /* If we're freeing ptes above the `next_entry' pointer (they
            may have snuck back into the TLB since the last wrap flush),
-           we need to flush the TLB before reallocating the latter.
-	*/
+           we need to flush the TLB before reallocating the latter.  */
 	if ((fend - arena->dma_base) >> PAGE_SHIFT >= arena->next_entry)
 		alpha_mv.mv_pci_tbi(hose, fbeg, fend);
 
 	spin_unlock_irqrestore(&arena->lock, flags);
 
-	DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg));
+	DBGA("pci_unmap_sg: %ld entries\n", nents - (end - sg));
 }
 
+
 /* Return whether the given PCI device DMA address mask can be
    supported properly.  */
 
 int
-pci_dma_supported(struct pci_dev *pdev, dma_addr_t mask)
+pci_dma_supported(struct pci_dev *pdev, u64 mask)
 {
 	struct pci_controller *hose;
 	struct pci_iommu_arena *arena;
 
-#if !DEBUG_NODIRECT
 	/* If there exists a direct map, and the mask fits either
 	   MAX_DMA_ADDRESS defined such that GFP_DMA does something
 	   useful, or the total system memory as shifted by the
@@ -648,7 +717,6 @@
 	    && (__direct_map_base + MAX_DMA_ADDRESS-IDENT_ADDR-1 <= mask
 		|| __direct_map_base + (max_low_pfn<<PAGE_SHIFT)-1 <= mask))
 		return 1;
-#endif
 
 	/* Check that we have a scatter-gather arena that fits.  */
 	hose = pdev ? pdev->sysdata : pci_isa_hose;
@@ -758,4 +826,50 @@
 		p[i] = IOMMU_RESERVED_PTE;
 
 	return 0;
+}
+
+/* True if the machine supports DAC addressing, and DEV can
+   make use of it given MASK.  */
+
+int
+pci_dac_dma_supported(struct pci_dev *dev, u64 mask)
+{
+	dma64_addr_t dac_offset = alpha_mv.pci_dac_offset;
+	int ok = 1;
+
+	/* If this is not set, the machine doesn't support DAC at all.  */
+	if (dac_offset == 0)
+		ok = 0;
+
+	/* The device has to be able to address our DAC bit.  */
+	if ((dac_offset & dev->dma_mask) != dac_offset)
+		ok = 0;
+
+	/* If both conditions above are met, we are fine. */
+	DBGA("pci_dac_dma_supported %s from %p\n",
+	     ok ? "yes" : "no", __builtin_return_address(0));
+
+	return ok;
+}
+
+dma64_addr_t
+pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page,
+		    unsigned long offset, int direction)
+{
+	return (alpha_mv.pci_dac_offset
+		+ __pa(page_address(page)) 
+		+ (dma64_addr_t) offset);
+}
+
+struct page *
+pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
+{
+	unsigned long paddr = (dma_addr & PAGE_MASK) - alpha_mv.pci_dac_offset;
+	return virt_to_page(__va(paddr));
+}
+
+unsigned long
+pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
+{
+	return (dma_addr & ~PAGE_MASK);
 }
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/srm_env.c linux/arch/alpha/kernel/srm_env.c
--- v2.4.12/linux/arch/alpha/kernel/srm_env.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/alpha/kernel/srm_env.c	Sun Oct 21 10:20:57 2001
@@ -2,11 +2,11 @@
  * srm_env.c - Access to SRC environment variables through
  *             the linux procfs
  *
- * (C)2001, Jan-Benedict Glaw <jbgaw@lug-owl.de>
+ * (C)2001, Jan-Benedict Glaw <jbglaw@lug-owl.de>
  *
  * This driver is at all a modified version of Erik Mouw's
  * ./linux/Documentation/DocBook/procfs_example.c, so: thanky
- * you, erik! He can be reached via email at
+ * you, Erik! He can be reached via email at
  * <J.A.K.Mouw@its.tudelft.nl>. It is based on an idea
  * provided by DEC^WCompaq's "Jumpstart" CD. They included
  * a patch like this as well. Thanks for idea!
@@ -45,12 +45,13 @@
 #include <asm/uaccess.h>
 
 #define DIRNAME		"srm_environment"	/* Subdir in /proc/	*/
-#define VERSION		"0.0.1"			/* Module version	*/
+#define VERSION		"0.0.2"			/* Module version	*/
 #define NAME		"srm_env"		/* Module name		*/
 #define DEBUG
 
 MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
 MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface");
+MODULE_LICENSE("GPL");
 EXPORT_NO_SYMBOLS;
 
 typedef struct _srm_env {
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/sys_cabriolet.c linux/arch/alpha/kernel/sys_cabriolet.c
--- v2.4.12/linux/arch/alpha/kernel/sys_cabriolet.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/alpha/kernel/sys_cabriolet.c	Fri Oct 12 15:35:53 2001
@@ -407,6 +407,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		PYXIS_DAC_OFFSET,
 
 	nr_irqs:		35,
 	device_interrupt:	cabriolet_device_interrupt,
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c
--- v2.4.12/linux/arch/alpha/kernel/sys_dp264.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/alpha/kernel/sys_dp264.c	Fri Oct 12 15:35:53 2001
@@ -574,6 +574,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		TSUNAMI_DAC_OFFSET,
 
 	nr_irqs:		64,
 	device_interrupt:	dp264_device_interrupt,
@@ -598,6 +599,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		TSUNAMI_DAC_OFFSET,
 
 	nr_irqs:		64,
 	device_interrupt:	dp264_device_interrupt,
@@ -621,6 +623,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		TSUNAMI_DAC_OFFSET,
 
 	nr_irqs:		64,
 	device_interrupt:	dp264_device_interrupt,
@@ -644,6 +647,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		TSUNAMI_DAC_OFFSET,
 
 	nr_irqs:		64,
 	device_interrupt:	dp264_device_interrupt,
@@ -672,6 +676,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		TSUNAMI_DAC_OFFSET,
 
 	nr_irqs:		64,
 	device_interrupt:	dp264_device_interrupt,
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/sys_eiger.c linux/arch/alpha/kernel/sys_eiger.c
--- v2.4.12/linux/arch/alpha/kernel/sys_eiger.c	Fri Mar  2 11:12:07 2001
+++ linux/arch/alpha/kernel/sys_eiger.c	Fri Oct 12 15:35:53 2001
@@ -233,6 +233,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		TSUNAMI_DAC_OFFSET,
 
 	nr_irqs:		128,
 	device_interrupt:	eiger_device_interrupt,
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/sys_miata.c linux/arch/alpha/kernel/sys_miata.c
--- v2.4.12/linux/arch/alpha/kernel/sys_miata.c	Sat May 19 17:43:05 2001
+++ linux/arch/alpha/kernel/sys_miata.c	Fri Oct 12 15:35:53 2001
@@ -256,6 +256,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		PYXIS_DAC_OFFSET,
 
 	nr_irqs:		48,
 	device_interrupt:	pyxis_device_interrupt,
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/sys_rawhide.c linux/arch/alpha/kernel/sys_rawhide.c
--- v2.4.12/linux/arch/alpha/kernel/sys_rawhide.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/alpha/kernel/sys_rawhide.c	Fri Oct 12 15:35:53 2001
@@ -254,6 +254,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	MCPCIA_DEFAULT_MEM_BASE,
+	pci_dac_offset:		MCPCIA_DAC_OFFSET,
 
 	nr_irqs:		128,
 	device_interrupt:	rawhide_srm_device_interrupt,
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/sys_ruffian.c linux/arch/alpha/kernel/sys_ruffian.c
--- v2.4.12/linux/arch/alpha/kernel/sys_ruffian.c	Thu Feb  8 12:56:29 2001
+++ linux/arch/alpha/kernel/sys_ruffian.c	Fri Oct 12 15:35:53 2001
@@ -220,6 +220,7 @@
 	max_dma_address:	ALPHA_RUFFIAN_MAX_DMA_ADDRESS,
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		PYXIS_DAC_OFFSET,
 
 	nr_irqs:		48,
 	device_interrupt:	pyxis_device_interrupt,
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/sys_sx164.c linux/arch/alpha/kernel/sys_sx164.c
--- v2.4.12/linux/arch/alpha/kernel/sys_sx164.c	Fri Oct 27 10:55:01 2000
+++ linux/arch/alpha/kernel/sys_sx164.c	Fri Oct 12 15:35:53 2001
@@ -129,7 +129,9 @@
 	struct percpu_struct *cpu = (struct percpu_struct*)
 		((char*)hwrpb + hwrpb->processor_offset);
 
-	if (alpha_using_srm && (cpu->pal_revision & 0xffff) == 0x117) {
+	if (amask(AMASK_MAX) != 0
+	    && alpha_using_srm
+	    && (cpu->pal_revision & 0xffff) == 0x117) {
 		__asm__ __volatile__(
 		"lda	$16,8($31)\n"
 		"call_pal 9\n"		/* Allow PALRES insns in kernel mode */
@@ -160,6 +162,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		PYXIS_DAC_OFFSET,
 
 	nr_irqs:		48,
 	device_interrupt:	pyxis_device_interrupt,
diff -u --recursive --new-file v2.4.12/linux/arch/alpha/kernel/sys_titan.c linux/arch/alpha/kernel/sys_titan.c
--- v2.4.12/linux/arch/alpha/kernel/sys_titan.c	Fri Mar  2 11:12:07 2001
+++ linux/arch/alpha/kernel/sys_titan.c	Fri Oct 12 15:35:53 2001
@@ -378,6 +378,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		TITAN_DAC_OFFSET,
 
 	nr_irqs:		80,	/* 64 + 16 */
 	device_interrupt:	privateer_device_interrupt,
diff -u --recursive --new-file v2.4.12/linux/arch/arm/Makefile linux/arch/arm/Makefile
--- v2.4.12/linux/arch/arm/Makefile	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/Makefile	Thu Oct 11 09:04:57 2001
@@ -45,8 +45,6 @@
 CFLAGS		+=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float
 AFLAGS		+=$(apcs-y) $(arch-y) -mno-fpu
 
-LIBGCC		:= $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
-
 ifeq ($(CONFIG_CPU_26),y)
 PROCESSOR	 = armo
   ifeq ($(CONFIG_ROM_KERNEL),y)
@@ -123,7 +121,7 @@
 endif
 
 ifeq ($(CONFIG_ARCH_CLPS711X),y)
-TEXTADDR	 = 0xc0018000
+TEXTADDR	 = 0xc0028000
 MACHINE		 = clps711x
 endif
 
@@ -131,7 +129,7 @@
 MACHINE		 = anakin
 endif
 
-export	LIBGCC MACHINE PROCESSOR TEXTADDR GZFLAGS
+export	MACHINE PROCESSOR TEXTADDR GZFLAGS
 
 # Only set INCDIR if its not already defined above
 # Grr, ?= doesn't work as all the other assignment operators do.  Make bug?
@@ -155,7 +153,7 @@
 SUBDIRS		+= arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe \
 		   arch/arm/fastfpe
 CORE_FILES	:= arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
-LIBS		:= arch/arm/lib/lib.a $(LIBS) $(LIBGCC)
+LIBS		:= arch/arm/lib/lib.a $(LIBS)
 
 ifeq ($(CONFIG_FPE_NWFPE),y)
 LIBS		:= arch/arm/nwfpe/math-emu.o $(LIBS)
diff -u --recursive --new-file v2.4.12/linux/arch/arm/boot/Makefile linux/arch/arm/boot/Makefile
--- v2.4.12/linux/arch/arm/boot/Makefile	Tue Jul  3 17:08:18 2001
+++ linux/arch/arm/boot/Makefile	Thu Oct 11 09:04:57 2001
@@ -69,12 +69,21 @@
 ZBSSADDR	 = 0xf03e0000
 endif
 
-ifeq ($(CONFIG_ARCH_P720T),y)
-ZTEXTADDR	 = 0xc0018000
+# The standard locations for stuff on CLPS711x type processors
+ifeq ($(CONFIG_ARCH_CLPS711X),y)
+ZTEXTADDR	 = 0xc0028000
 PARAMS_PHYS	 = 0xc0000100
+endif
+
+# Should probably have some agreement on these...
+ifeq ($(CONFIG_ARCH_P720T),y)
 INITRD_PHYS	 = 0xc0400000
 INITRD_VIRT	 = 0xc0400000
 endif
+ifeq ($(CONFIG_ARCH_CDB89712),y)
+INITRD_PHYS	 = 0x00700000
+INITRD_VIRT	 = 0xc0300000
+endif
 
 ifeq ($(CONFIG_ARCH_SA1100),y)
 ZTEXTADDR	 = 0xc0008000
@@ -89,6 +98,12 @@
 endif
 ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y)
   ZTEXTADDR	 = 0xC0200000
+endif
+ifeq ($(CONFIG_SA1100_GRAPHICSMASTER),y)
+  ZTEXTADDR	 = 0xC0400000
+endif
+ifeq ($(CONFIG_SA1100_ADSBITSY),y)
+  ZTEXTADDR	 = 0xC0400000
 endif
 ifeq ($(CONFIG_SA1100_YOPY),y)
   ZTEXTADDR      = 0x00080000
diff -u --recursive --new-file v2.4.12/linux/arch/arm/boot/bootp/Makefile linux/arch/arm/boot/bootp/Makefile
--- v2.4.12/linux/arch/arm/boot/bootp/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/boot/bootp/Makefile	Thu Oct 11 09:04:57 2001
@@ -3,7 +3,6 @@
 #
 
 ZSYSTEM		=$(TOPDIR)/arch/arm/boot/zImage
-INITRD		=$(ZSYSTEM)
 ZLDFLAGS	=-p -X -T bootp.lds \
 		 --defsym initrd_addr=$(INITRD_PHYS) \
 		 --defsym initrd_virt=$(INITRD_VIRT) \
diff -u --recursive --new-file v2.4.12/linux/arch/arm/boot/bootp/init.S linux/arch/arm/boot/bootp/init.S
--- v2.4.12/linux/arch/arm/boot/bootp/init.S	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/boot/bootp/init.S	Thu Oct 11 09:04:57 2001
@@ -39,7 +39,7 @@
  * method by looking at the first word; this should either indicate a page
  * size of 4K, 16K or 32K.
  */
-		ldmia	r13, {r5-r8}		@ get size and addr of initrd
+		ldmia	r13, {r4-r8}		@ get size and addr of initrd
 						@ r5 = ATAG_INITRD
 						@ r6 = initrd start
 						@ r7 = initrd end
@@ -48,10 +48,25 @@
 		teq	r9, #0x1000		@ 4K?
 		teqne	r9, #0x4000		@ 16K?
 		teqne	r9, #0x8000		@ 32K?
-		beq	no_taglist
+		beq	param_struct
+
+		ldr	r9, [r8, #4]		@ get first tag
+		teq	r9, r4
+		bne	taglist			@ ok, we have a tag list
+
+/*
+ * We didn't find a valid tag list - create one.
+ */
+		str	r4, [r8, #4]
+		mov	r4, #8
+		str	r4, [r8, #0]
+		mov	r4, #0
+		str	r4, [r8, #8]
 
 /*
  * find the end of the tag list, and then add an INITRD tag on the end.
+ * If there is already an INITRD tag, then we ignore it; the last INITRD
+ * tag takes precidence.
  */
 taglist:	ldr	r9, [r8, #0]		@ tag length
 		teq	r9, #0			@ last tag?
@@ -63,7 +78,10 @@
 		stmia	r8, {r4, r5, r6, r7, r9}
 		mov	pc, r12			@ call kernel
 
-no_taglist:	add	r8, r8, #16*4
+/*
+ * We found a param struct.  Modify the param struct for the initrd
+ */
+param_struct:	add	r8, r8, #16*4
 		stmia	r8, {r6,r7}		@ save in param_struct
 		mov	pc, r12			@ call kernel
 
@@ -83,6 +101,7 @@
 		.word	kernel_addr
 		.word	kernel_len
 
+		.word	0x54410001		@ r4 = ATAG_CORE
 		.word	0x54410005		@ r5 = ATAG_INITRD
 		.word	initrd_virt		@ r6
 		.word	initrd_len		@ r7
diff -u --recursive --new-file v2.4.12/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile
--- v2.4.12/linux/arch/arm/boot/compressed/Makefile	Tue Jul  3 17:08:18 2001
+++ linux/arch/arm/boot/compressed/Makefile	Thu Oct 11 09:04:57 2001
@@ -51,7 +51,7 @@
 endif
 
 ifeq ($(CONFIG_ARCH_SA1100),y)
-OBJS		+= head-sa1100.o setup-sa1100.o
+OBJS		+= head-sa1100.o
 ifeq ($(CONFIG_SA1100_NANOENGINE),y)
   OBJS += hw-bse.o
 endif
@@ -64,6 +64,8 @@
 else
 SEDFLAGS	+= s/BSS_START/ALIGN(4)/
 endif
+
+LIBGCC		:= $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
 
 all:		vmlinux
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/boot/compressed/head-sa1100.S linux/arch/arm/boot/compressed/head-sa1100.S
--- v2.4.12/linux/arch/arm/boot/compressed/head-sa1100.S	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/boot/compressed/head-sa1100.S	Thu Oct 11 09:04:57 2001
@@ -17,6 +17,24 @@
 
 		@ Preserve r8/r7 i.e. kernel entry values
 
+#if defined(CONFIG_SA1100_GRAPHICSCLIENT) && !defined(CONFIG_ANGELBOOT)
+		mov	r7, #MACH_TYPE_GRAPHICSCLIENT
+		mov	r8, #0
+#endif
+#if defined(CONFIG_SA1100_GRAPHICSMASTER) && !defined(CONFIG_ANGELBOOT)
+		mov	r7, #MACH_TYPE_GRAPHICSMASTER
+		mov	r8, #0
+#endif
+#if defined(CONFIG_SA1100_ADSBITSY) && !defined(CONFIG_ANGELBOOT)
+		mov	r7, #MACH_TYPE_ADSBITSY
+		mov	r8, #0
+#endif
+
+#ifdef CONFIG_SA1100_PFS168
+		@ REVISIT_PFS168: Temporary until firmware updated to use assigned machine number
+		mov	r7, #MACH_TYPE_PFS168
+#endif
+
 #ifdef CONFIG_SA1100_VICTOR
 		teq	r7, #MACH_TYPE_VICTOR
 		bne	10f
@@ -51,7 +69,6 @@
 		bic	r0, r0, #0x1000		@ clear Icache
 		mcr	p15, 0, r0, c1, c0, 0
 
-#ifdef CONFIG_ANGELBOOT
 /*
  * Pause for a short time so that we give enough time
  * for the host to start a terminal up.
@@ -59,5 +76,4 @@
 		mov	r0, #0x00200000
 1:		subs	r0, r0, #1
 		bne	1b
-#endif
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/boot/compressed/setup-sa1100.S linux/arch/arm/boot/compressed/setup-sa1100.S
--- v2.4.12/linux/arch/arm/boot/compressed/setup-sa1100.S	Tue Jul  3 17:08:18 2001
+++ linux/arch/arm/boot/compressed/setup-sa1100.S	Wed Dec 31 16:00:00 1969
@@ -1,163 +0,0 @@
-/*
- * linux/arch/arm/boot/compressed/setup-sa1100.S
- *
- * Copyright (C) 2000 Nicolas Pitre <nico@cam.org>
- *
- * SA1100 setup routines, to be used after BSS has been cleared.
- *
- * John G Dorsey <john+@cs.cmu.edu>  2000/05/25 :
- *  Runtime test for Neponset added.
- */
-
-#include <linux/linkage.h>
-#include <linux/config.h>
-#include <asm/mach-types.h>
-
-		.text
-
-GPIO_BASE:	.long	0x90040000
-#define GPLR		0x00
-#define GPDR		0x04
-#define GPSR		0x08
-#define GAFR		0x1c
-
-PPC_BASE:	.long	0x90060000
-#define PPAR		0x08
-
-IC_BASE:	.long	0x90050000
-#define ICMR		0x04
-
-UART1_BASE:	.long	0x80010000
-UART3_BASE:	.long	0x80050000
-#define UTCR0           0x00
-#define UTCR1           0x04
-#define UTCR2           0x08
-#define UTCR3           0x0c
-#define UTSR0           0x1c
-#define UTSR1           0x20
-
-#ifndef CONFIG_SA1100_DEFAULT_BAUDRATE
-#define CONFIG_SA1100_DEFAULT_BAUDRATE	9600
-#endif
-
-#define BAUD_DIV	((230400/CONFIG_SA1100_DEFAULT_BAUDRATE)-1)
-
-SCR_loc:	.long	SYMBOL_NAME(SCR_value)
-#define GPIO_2_9	0x3fc
-
-
-/*
- * void sa1100_setup( int arch_id );
- *
- * This is called from decompress_kernel() with the arch_decomp_setup() macro.
- */
-
-ENTRY(sa1100_setup)
-		mov	r3, r0			@ keep machine type in r3
-
-		@ Clear all interrupt sources
-		ldr	r0, IC_BASE
-		mov	r1, #0
-		str	r1, [r0, #ICMR]
-
-@ Read System Configuration "Register" for Assabet.
-@ (taken from "Intel StrongARM SA-1110 Microprocessor Development Board
-@ User's Guide," p.4-9)
-
-		teq	r3, #MACH_TYPE_ASSABET
-		bne	skip_SCR
-
-		ldr	r0, GPIO_BASE
-		ldr	r1, [r0, #GPDR]
-		and	r1, r1, #GPIO_2_9
-		str	r1, [r0, #GPDR]
-		mov	r1, #GPIO_2_9
-		str	r1, [r0, #GPSR]
-		ldr	r1, [r0, #GPDR]
-		bic	r1, r1, #GPIO_2_9
-		str	r1, [r0, #GPDR]
-
-		mov	r2, #100
-1:		ldr	r1, [r0, #GPLR]
-		subs	r2, r2, #1
-		bne	1b
-
-		and	r2, r1, #GPIO_2_9
-		ldr	r1, SCR_loc
-		str	r2, [r1]
-
-		ldr	r1, [r0, #GPDR]
-		and	r1, r1, #GPIO_2_9
-		str	r1, [r0, #GPDR]
-
-skip_SCR:
-
-		@ Initialize UART (if bootloader has not done it yet)...
-		teq	r3, #MACH_TYPE_BRUTUS
-		teqne	r3, #MACH_TYPE_ASSABET
-		teqne   r3, #MACH_TYPE_ITSY
-		teqne   r3, #MACH_TYPE_OMNIMETER
-		teqne   r3, #MACH_TYPE_JORNADA720
-		teqne	r3, #MACH_TYPE_GRAPHICSCLIENT
-		teqne	r3, #MACH_TYPE_FLEXANET
-		bne	skip_uart
-
-		@ UART3 if Assabet is used with Neponset
-		teq	r3, #MACH_TYPE_ASSABET	@ if Assabet 
-		tsteq	r2, #(1 << 9)		@ ... and Neponset present
-		ldreq	r0, UART3_BASE
-		beq	uart_init
-
-		@ UART3 on GraphicsClient
-		teq	r3, #MACH_TYPE_GRAPHICSCLIENT
-		ldreq	r0, UART3_BASE
-		beq	uart_init
-
-		@ At least for Brutus, the UART1 is used through
-		@ the alternate GPIO function...
-		teq	r3, #MACH_TYPE_BRUTUS
-		bne	uart1
-
-alt_GPIO_uart:	ldr	r0, GPIO_BASE
-		ldr	r1, [r0, #GPDR]
-		bic	r1, r1, #1<<15
-		orr	r1, r1, #1<<14
-		str	r1, [r0, #GPDR]
-		ldr	r1, [r0, #GAFR]
-		orr	r1, r1, #(1<<15)|(1<<14)
-		str	r1, [r0, #GAFR]
-		ldr	r0, PPC_BASE
-		ldr	r1, [r0, #PPAR]
-		orr	r1, r1, #1<<12
-		str	r1, [r0, #PPAR]
-
-uart1:		ldr	r0, UART1_BASE
-
-uart_init:
-1:		ldr	r1, [r0, #UTSR1]
-		tst	r1, #1<<0		@ TBY
-		bne	1b
-		mov	r1, #0
-		str	r1, [r0, #UTCR3]
-		mov	r1, #0x08		@ 8N1
-		str	r1, [r0, #UTCR0]
-		mov	r1, #BAUD_DIV
-		str	r1, [r0, #UTCR2]
-		mov	r1, r1, lsr #8
-		str	r1, [r0, #UTCR1]
-		mov	r1, #0x03		@ RXE + TXE
-		str	r1, [r0, #UTCR3]
-		mov	r1, #0xff		@ flush status reg
-		str	r1, [r0, #UTSR0]
-skip_uart:
-
-		@ Extra specific setup calls
-		@ The machine type is passed in r0
-		mov	r0, r3
-#ifdef CONFIG_SA1100_NANOENGINE
-		teq	r0, #MACH_TYPE_NANOENGINE
-		beq	SYMBOL_NAME(bse_setup)
-#endif
-
-out:		mov	pc, lr
-
diff -u --recursive --new-file v2.4.12/linux/arch/arm/config.in linux/arch/arm/config.in
--- v2.4.12/linux/arch/arm/config.in	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/config.in	Thu Oct 11 09:04:57 2001
@@ -11,6 +11,7 @@
 define_bool CONFIG_UID16 y
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+define_bool CONFIG_GENERIC_BUST_SPINLOCK n
 
 
 mainmenu_option next_comment
@@ -68,12 +69,13 @@
 comment 'SA11x0 Implementations'
 dep_bool '  Assabet' CONFIG_SA1100_ASSABET $CONFIG_ARCH_SA1100
 dep_bool '    Include support for Neponset' CONFIG_ASSABET_NEPONSET $CONFIG_SA1100_ASSABET
+dep_bool '  ADS Bitsy' CONFIG_SA1100_ADSBITSY $CONFIG_ARCH_SA1100
 dep_bool '  Brutus' CONFIG_SA1100_BRUTUS $CONFIG_ARCH_SA1100
 dep_bool '  CerfBoard' CONFIG_SA1100_CERF $CONFIG_ARCH_SA1100
 if [ "$CONFIG_SA1100_CERF" = "y" ]; then
    bool '    32MB Cerf support' CONFIG_SA1100_CERF_32MB
 fi
-dep_bool '  Compaq iPAQ H3600 (Bitsy)' CONFIG_SA1100_BITSY $CONFIG_ARCH_SA1100
+dep_bool '  Compaq iPAQ H3600' CONFIG_SA1100_H3600 $CONFIG_ARCH_SA1100
 #dep_bool '  Empeg' CONFIG_SA1100_EMPEG $CONFIG_ARCH_SA1100
 dep_bool '  Extenex HandHeld Theater (Squashtail)' CONFIG_SA1100_EXTENEX1 $CONFIG_ARCH_SA1100
 if [ "$CONFIG_SA1100_EXTENEX1" = "y" ]; then
@@ -82,6 +84,7 @@
 dep_bool '  FlexaNet' CONFIG_SA1100_FLEXANET $CONFIG_ARCH_SA1100
 dep_bool '  FreeBird-v1.1' CONFIG_SA1100_FREEBIRD $CONFIG_ARCH_SA1100
 dep_bool '  GraphicsClient Plus' CONFIG_SA1100_GRAPHICSCLIENT $CONFIG_ARCH_SA1100
+dep_bool '  GraphicsMaster' CONFIG_SA1100_GRAPHICSMASTER $CONFIG_ARCH_SA1100
 dep_bool '  HP Jornada 720' CONFIG_SA1100_JORNADA720 $CONFIG_ARCH_SA1100
 dep_bool '  HuW WebPanel' CONFIG_SA1100_HUW_WEBPANEL $CONFIG_ARCH_SA1100
 dep_bool '  Itsy' CONFIG_SA1100_ITSY $CONFIG_ARCH_SA1100
@@ -101,14 +104,38 @@
 if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \
      "$CONFIG_SA1100_JORNADA720" = "y" -o \
      "$CONFIG_SA1100_PFS168" = "y" -o \
-     "$CONFIG_SA1100_XP860" = "y" ]; then
+     "$CONFIG_SA1100_XP860" = "y" -o \
+     "$CONFIG_SA1100_GRAPHICSMASTER" = "y" -o \
+     "$CONFIG_SA1100_ADSBITSY" = "y" ]; then
    define_bool CONFIG_SA1111 y
+   define_int CONFIG_FORCE_MAX_ZONEORDER 9
 fi
 endmenu
 
 mainmenu_option next_comment
 comment 'CLPS711X/EP721X Implementations'
+dep_bool '  CDB89712' CONFIG_ARCH_CDB89712 $CONFIG_ARCH_CLPS711X
+dep_bool '  CLEP7312' CONFIG_ARCH_CLEP7312 $CONFIG_ARCH_CLPS711X
+dep_bool '  EDB7211' CONFIG_ARCH_EDB7211 $CONFIG_ARCH_CLPS711X
 dep_bool '  P720T' CONFIG_ARCH_P720T $CONFIG_ARCH_CLPS711X
+
+# XXX Maybe these should indicate register compatibility
+# instead of being mutually exclusive.
+if [ "$CONFIG_ARCH_EDB7211" = "y" ]; then
+   define_bool CONFIG_ARCH_EP7211 y
+else
+   define_bool CONFIG_ARCH_EP7211 n
+fi
+if [ "$CONFIG_ARCH_P720T" = "y" ]; then
+   define_bool CONFIG_ARCH_EP7212 y
+else
+   define_bool CONFIG_ARCH_EP7212 n
+fi
+
+if [ "$CONFIG_ARCH_EP7211" = "y" -o \
+     "$CONFIG_ARCH_EP7212" = "y" ]; then
+   bool '  EP72xx ROM boot' CONFIG_EP72XX_ROM_BOOT
+fi
 endmenu
 
 # Definitions to make life easier
@@ -196,7 +223,9 @@
 fi
 
 # ARM720T
-if [ "$CONFIG_ARCH_CLPS711X" = "y" -o "$CONFIG_ARCH_L7200" = "y" ]; then
+if [ "$CONFIG_ARCH_CLPS711X" = "y" -o \
+     "$CONFIG_ARCH_L7200"    = "y" -o \
+     "$CONFIG_ARCH_CDB89712" = "y" ]; then
    define_bool CONFIG_CPU_ARM720T y
 else
    if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
@@ -255,12 +284,13 @@
    define_bool CONFIG_CPU_SA1100 n
 fi
 
-#if [ "$CONFIG_CPU_32" = "y" ]; then
-#   bool 'Support Thumb instructions' CONFIG_ARM_THUMB
-#fi
+if [ "$CONFIG_CPU_32" = "y" ]; then
+   dep_bool 'Support Thumb instructions (experimental)' CONFIG_ARM_THUMB $CONFIG_EXPERIMENTAL
+fi
 
 # Select various configuration options depending on the machine type
-if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+if [ "$CONFIG_ARCH_EDB7211" = "y" -o \
+     "$CONFIG_ARCH_SA1100" = "y" ]; then
    define_bool CONFIG_DISCONTIGMEM y
 else
    define_bool CONFIG_DISCONTIGMEM n
@@ -289,6 +319,8 @@
      "$CONFIG_ARCH_SHARK" = "y" -o \
      "$CONFIG_ARCH_CLPS7500" = "y" -o \
      "$CONFIG_ARCH_EBSA110" = "y" -o \
+     "$CONFIG_ARCH_CDB89712" = "y" -o \
+     "$CONFIG_ARCH_EDB7211" = "y" -o \
      "$CONFIG_ARCH_SA1100" = "y" ]; then
    define_bool CONFIG_ISA y
 else
@@ -318,6 +350,7 @@
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
+comment 'At least one math emulation must be selected'
 tristate 'NWFPE math emulation' CONFIG_FPE_NWFPE
 dep_tristate 'FastFPE math emulation (experimental)' CONFIG_FPE_FASTFPE $CONFIG_EXPERIMENTAL
 choice 'Kernel core (/proc/kcore) format' \
@@ -335,6 +368,7 @@
      "$CONFIG_ARCH_PERSONAL_SERVER" = "y" -o \
      "$CONFIG_ARCH_CATS" = "y" -o            \
      "$CONFIG_ARCH_P720T" = "y" -o	     \
+     "$CONFIG_ARCH_CDB89712" = "y" -o	     \
      "$CONFIG_ARCH_ANAKIN" = "y" ]; then
    string 'Default kernel command string' CONFIG_CMDLINE ""
 fi
@@ -346,6 +380,7 @@
      "$CONFIG_ARCH_CO285" = "y" -o      \
      "$CONFIG_ARCH_SA1100" = "y" -o     \
      "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
+     "$CONFIG_ARCH_CDB89712" = "y" -o   \
      "$CONFIG_ARCH_P720T" = "y" ]; then
    bool 'Timer and CPU usage LEDs' CONFIG_LEDS
    if [ "$CONFIG_LEDS" = "y" ]; then
@@ -429,7 +464,7 @@
 
 source drivers/ieee1394/Config.in
 
-source drivers/i2o/Config.in
+source drivers/message/i2o/Config.in
 
 mainmenu_option next_comment
 comment 'ISDN subsystem'
@@ -509,6 +544,8 @@
    fi
    endmenu
 fi
+
+source drivers/misc/Config.in
 
 source drivers/usb/Config.in
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile
--- v2.4.12/linux/arch/arm/kernel/Makefile	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/kernel/Makefile	Thu Oct 11 09:04:57 2001
@@ -41,7 +41,7 @@
 export-objs	:= armksyms.o dma.o ecard.o fiq.o io.o oldlatches.o time.o
 
 no-irq-arch	:= $(CONFIG_ARCH_INTEGRATOR) $(CONFIG_ARCH_CLPS711X) \
-		   $(CONFIG_ARCH_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \
+		   $(CONFIG_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \
 		   $(CONFIG_ARCH_SA1100)
 
 ifneq ($(findstring y,$(no-irq-arch)),y)
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c
--- v2.4.12/linux/arch/arm/kernel/armksyms.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/kernel/armksyms.c	Thu Oct 11 09:04:57 2001
@@ -54,22 +54,16 @@
  * compiler...  (prototypes are not correct though, but that
  * doesn't really matter since they're not versioned).
  */
-extern void __gcc_bcmp(void);
 extern void __ashldi3(void);
 extern void __ashrdi3(void);
-extern void __cmpdi2(void);
-extern void __divdi3(void);
 extern void __divsi3(void);
 extern void __lshrdi3(void);
-extern void __moddi3(void);
 extern void __modsi3(void);
 extern void __muldi3(void);
-extern void __negdi2(void);
 extern void __ucmpdi2(void);
 extern void __udivdi3(void);
 extern void __udivmoddi4(void);
 extern void __udivsi3(void);
-extern void __umoddi3(void);
 extern void __umodsi3(void);
 
 extern void ret_from_exception(void);
@@ -213,23 +207,27 @@
 EXPORT_SYMBOL(uaccess_user);
 #endif
 
+EXPORT_SYMBOL_NOVERS(__get_user_1);
+EXPORT_SYMBOL_NOVERS(__get_user_2);
+EXPORT_SYMBOL_NOVERS(__get_user_4);
+EXPORT_SYMBOL_NOVERS(__get_user_8);
+
+EXPORT_SYMBOL_NOVERS(__put_user_1);
+EXPORT_SYMBOL_NOVERS(__put_user_2);
+EXPORT_SYMBOL_NOVERS(__put_user_4);
+EXPORT_SYMBOL_NOVERS(__put_user_8);
+
 	/* gcc lib functions */
-EXPORT_SYMBOL_NOVERS(__gcc_bcmp);
 EXPORT_SYMBOL_NOVERS(__ashldi3);
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
-EXPORT_SYMBOL_NOVERS(__cmpdi2);
-EXPORT_SYMBOL_NOVERS(__divdi3);
 EXPORT_SYMBOL_NOVERS(__divsi3);
 EXPORT_SYMBOL_NOVERS(__lshrdi3);
-EXPORT_SYMBOL_NOVERS(__moddi3);
 EXPORT_SYMBOL_NOVERS(__modsi3);
 EXPORT_SYMBOL_NOVERS(__muldi3);
-EXPORT_SYMBOL_NOVERS(__negdi2);
 EXPORT_SYMBOL_NOVERS(__ucmpdi2);
 EXPORT_SYMBOL_NOVERS(__udivdi3);
 EXPORT_SYMBOL_NOVERS(__udivmoddi4);
 EXPORT_SYMBOL_NOVERS(__udivsi3);
-EXPORT_SYMBOL_NOVERS(__umoddi3);
 EXPORT_SYMBOL_NOVERS(__umodsi3);
 
 	/* bitops */
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c
--- v2.4.12/linux/arch/arm/kernel/bios32.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/kernel/bios32.c	Thu Oct 11 09:04:57 2001
@@ -288,8 +288,11 @@
 
 	if (dev) {
 		for (i = 0; i < 3; i++) {
-			bus->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
-			bus->resource[i]->name  = bus->name;
+			if(root->resource[i]) {
+				bus->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+				bus->resource[i]->end  = root->resource[i]->end;
+				bus->resource[i]->name = bus->name;
+			}
 		}
 		bus->resource[0]->flags |= pci_bridge_check_io(dev);
 		bus->resource[1]->flags |= IORESOURCE_MEM;
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/compat.c linux/arch/arm/kernel/compat.c
--- v2.4.12/linux/arch/arm/kernel/compat.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/kernel/compat.c	Thu Oct 11 09:04:57 2001
@@ -8,7 +8,7 @@
  * published by the Free Software Foundation.
  *
  * We keep the old params compatibility cruft in one place (here)
- * so we don't end up with lots of 
+ * so we don't end up with lots of mess around other places.
  */
 #include <linux/config.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/dma-isa.c linux/arch/arm/kernel/dma-isa.c
--- v2.4.12/linux/arch/arm/kernel/dma-isa.c	Mon Sep 18 15:15:24 2000
+++ linux/arch/arm/kernel/dma-isa.c	Thu Oct 11 09:04:57 2001
@@ -148,17 +148,22 @@
 
 void __init isa_init_dma(dma_t *dma)
 {
-	int dmac_found;
-
+	/*
+	 * Try to autodetect presence of an ISA DMA controller.
+	 * We do some minimal initialisation, and check that
+	 * channel 0's DMA address registers are writeable.
+	 */
 	outb(0xff, 0x0d);
 	outb(0xff, 0xda);
 
+	/*
+	 * Write high and low address, and then read them back
+	 * in the same order.
+	 */
 	outb(0x55, 0x00);
 	outb(0xaa, 0x00);
 
-	dmac_found = inb(0x00) == 0x55 && inb(0x00) == 0xaa;
-
-	if (dmac_found) {
+	if (inb(0) == 0x55 && inb(0) == 0xaa) {
 		int channel, i;
 
 		for (channel = 0; channel < 8; channel++) {
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S
--- v2.4.12/linux/arch/arm/kernel/entry-armv.S	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/kernel/entry-armv.S	Thu Oct 11 09:04:57 2001
@@ -404,6 +404,7 @@
 		.endm
 
 #elif defined(CONFIG_ARCH_L7200)
+#include <asm/hardware.h>
 	
 		.equ	irq_base_addr,	IO_BASE_2
 
@@ -625,8 +626,8 @@
  * This routine must not corrupt r9
  */
 #ifdef MULTI_CPU
-		ldr	r2, .LCprocfns
-		mov	lr, pc
+		ldr	r2, .LCprocfns			@ pass r0, r3 to
+		mov	lr, pc				@ processor code
 		ldr	pc, [r2]			@ call processor specific code
 #else
 		bl	cpu_data_abort
@@ -722,16 +723,16 @@
 		.align	5
 __dabt_usr:	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
 		stmia	sp, {r0 - r12}			@ save r0 - r12
-		ldr	r4, .LCabt
-		add	r3, sp, #S_PC
-		ldmia	r4, {r0 - r2}			@ Get USR pc, cpsr
-		stmia	r3, {r0 - r2}			@ Save USR pc, cpsr, old_r0
-		stmdb	r3, {sp, lr}^
-		alignment_trap r4, r7, __temp_abt
+		ldr	r7, .LCabt
+		add	r5, sp, #S_PC
+		ldmia	r7, {r0, r3, r4}		@ Get USR pc, cpsr
+		stmia	r5, {r0, r3, r4}		@ Save USR pc, cpsr, old_r0
+		stmdb	r5, {sp, lr}^
+		alignment_trap r7, r7, __temp_abt
 		zero_fp
 #ifdef MULTI_CPU
-		ldr	r2, .LCprocfns
-		mov	lr, pc
+		ldr	r2, .LCprocfns			@ pass r0, r3 to
+		mov	lr, pc				@ processor code
 		ldr	pc, [r2]			@ call processor specific code
 #else
 		bl	cpu_data_abort
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S
--- v2.4.12/linux/arch/arm/kernel/entry-common.S	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/kernel/entry-common.S	Thu Oct 11 09:04:57 2001
@@ -123,9 +123,8 @@
 	.align	5
 ENTRY(vector_swi)
 	save_user_regs
-	mask_pc	lr, lr
 	zero_fp
-	ldr	scno, [lr, #-4]			@ get SWI instruction
+	get_scno
 	arm710_bug_check scno, ip
 
 #ifdef CONFIG_ALIGNMENT_TRAP
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/entry-header.S linux/arch/arm/kernel/entry-header.S
--- v2.4.12/linux/arch/arm/kernel/entry-header.S	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/kernel/entry-header.S	Thu Oct 11 09:04:57 2001
@@ -75,9 +75,9 @@
 		stmia	sp, {r0 - r12}			@ Calling r0 - r12
 		add	r8, sp, #S_PC
 		stmdb	r8, {sp, lr}^			@ Calling sp, lr
-		mrs	r7, spsr
+		mrs	r8, spsr			@ called from non-FIQ mode, so ok.
 		str	lr, [sp, #S_PC]			@ Save calling PC
-		str	r7, [sp, #S_PSR]		@ Save CPSR
+		str	r8, [sp, #S_PSR]		@ Save CPSR
 		str	r0, [sp, #S_OLD_R0]		@ Save OLD_R0
 		.endm
 
@@ -186,16 +186,34 @@
 
 #endif
 
+
 /*
  * These are the registers used in the syscall handler, and allow us to
- * have in theory up to 7 arguments to a function.  Note that tbl == why
- * is intentional.
+ * have in theory up to 7 arguments to a function - r0 to r6.
+ *
+ * r7 is reserved for the system call number for thumb mode.
+ *
+ * Note that tbl == why is intentional.
  *
  * We must set at least "tsk" and "why" when calling ret_with_reschedule.
  */
-scno	.req	r9				@ syscall number
+scno	.req	r7				@ syscall number
 tbl	.req	r8				@ syscall table pointer
 why	.req	r8				@ Linux syscall (!= 0)
-tsk	.req	r7				@ current task
+tsk	.req	r9				@ current task
+
+/*
+ * Get the system call number.
+ */
+	.macro	get_scno
+#ifdef CONFIG_ARM_THUMB
+	tst	r8, #T_BIT		@ this is SPSR from save_user_regs
+	addne	scno, r7, #OS_NUMBER << 20 @ put OS number in
+	ldreq	scno, [lr, #-4]
 
+#else
+	mask_pc	lr, lr
+	ldr	scno, [lr, #-4]		@ get SWI instruction
+#endif
+	.endm
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S
--- v2.4.12/linux/arch/arm/kernel/head-armv.S	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/kernel/head-armv.S	Thu Oct 11 09:04:57 2001
@@ -418,5 +418,4 @@
 		mov	r7, #0				@ unknown architecture
 		mov	pc, lr
 2:		ldmib	r4, {r5, r6, r7}		@ found, get results
-		mov	r7, r7, lsr #18			@ pagetable byte offset
 		mov	pc, lr
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/init_task.c linux/arch/arm/kernel/init_task.c
--- v2.4.12/linux/arch/arm/kernel/init_task.c	Sun Sep 23 11:40:55 2001
+++ linux/arch/arm/kernel/init_task.c	Thu Oct 11 09:04:57 2001
@@ -9,6 +9,7 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
+static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c
--- v2.4.12/linux/arch/arm/kernel/setup.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/kernel/setup.c	Thu Oct 11 09:04:57 2001
@@ -260,10 +260,10 @@
 	struct resource *res;
 	int i;
 
-	kernel_code.start  = __virt_to_bus(init_mm.start_code);
-	kernel_code.end    = __virt_to_bus(init_mm.end_code - 1);
-	kernel_data.start  = __virt_to_bus(init_mm.end_code);
-	kernel_data.end    = __virt_to_bus(init_mm.brk - 1);
+	kernel_code.start  = __virt_to_phys(init_mm.start_code);
+	kernel_code.end    = __virt_to_phys(init_mm.end_code - 1);
+	kernel_data.start  = __virt_to_phys(init_mm.end_code);
+	kernel_data.end    = __virt_to_phys(init_mm.brk - 1);
 
 	for (i = 0; i < mi->nr_banks; i++) {
 		unsigned long virt_start, virt_end;
@@ -520,9 +520,44 @@
 #endif
 }
 
-int get_cpuinfo(char * buffer)
+static const char *hwcap_str[] = {
+	"swp",
+	"half",
+	"thumb",
+	"26bit",
+	"fastmult",
+	"fpa",
+	"vfp",
+	"edsp",
+	NULL
+};
+
+/*
+ * get_cpuinfo - Get information on one CPU for use by the procfs.
+ *
+ *	Prints info on the next CPU into buffer.  Beware, doesn't check for
+ *	buffer overflow.  Current implementation of procfs assumes that the
+ *	resulting data is <= 1K.
+ *
+ * Args:
+ *	buffer	-- you guessed it, the data buffer
+ *	cpu_np	-- Input: next cpu to get (start at 0).  Output: Updated.
+ *
+ *	Returns number of bytes written to buffer.
+ */
+
+int get_cpuinfo(char *buffer, unsigned *cpu_np)
 {
 	char *p = buffer;
+	unsigned n;
+	int i;
+
+ 	/* No SMP at the moment, so just toggle 0/1 */
+	n = *cpu_np;
+	*cpu_np = 1;
+	if (n != 0) {
+		return (0);
+	}
 
 	p += sprintf(p, "Processor\t: %s %s rev %d (%s)\n",
 		     proc_info.manufacturer, proc_info.cpu_name,
@@ -531,6 +566,15 @@
 	p += sprintf(p, "BogoMIPS\t: %lu.%02lu\n",
 		     loops_per_jiffy / (500000/HZ),
 		     (loops_per_jiffy / (5000/HZ)) % 100);
+
+	/* dump out the processor features */
+	p += sprintf(p, "Features\t: ");
+
+	for (i = 0; hwcap_str[i]; i++)
+		if (elf_hwcap & (1 << i))
+			p += sprintf(p, "%s ", hwcap_str[i]);
+
+	p += sprintf(p, "\n\n");
 
 	p += sprintf(p, "Hardware\t: %s\n", machine_name);
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c
--- v2.4.12/linux/arch/arm/kernel/signal.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/kernel/signal.c	Thu Oct 11 09:04:57 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/kernel/signal.c
  *
- *  Copyright (C) 1995, 1996 Russell King
+ *  Copyright (C) 1995-2001 Russell King
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -19,7 +19,9 @@
 #include <linux/ptrace.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
+#include <linux/personality.h>
 #include <linux/tty.h>
+#include <linux/elf.h>
 
 #include <asm/pgalloc.h>
 #include <asm/ucontext.h>
@@ -29,8 +31,23 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-#define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn))
-#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn))
+/*
+ * For ARM syscalls, we encode the syscall number into the instruction.
+ */
+#define SWI_SYS_SIGRETURN	(0xef000000|(__NR_sigreturn))
+#define SWI_SYS_RT_SIGRETURN	(0xef000000|(__NR_rt_sigreturn))
+
+/*
+ * For Thumb syscalls, we pass the syscall number via r7.  We therefore
+ * need two 16-bit instructions.
+ */
+#define SWI_THUMB_SIGRETURN	(0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE))
+#define SWI_THUMB_RT_SIGRETURN	(0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
+
+static const unsigned long retcodes[4] = {
+	SWI_SYS_SIGRETURN,	SWI_THUMB_SIGRETURN,
+	SWI_SYS_RT_SIGRETURN,	SWI_THUMB_RT_SIGRETURN
+};
 
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
 
@@ -208,11 +225,11 @@
 	sigset_t set;
 
 	/*
-	 * Since we stacked the signal on a word boundary,
+	 * Since we stacked the signal on a 64-bit boundary,
 	 * then 'sp' should be word aligned here.  If it's
 	 * not, then the user is trying to mess with us.
 	 */
-	if (regs->ARM_sp & 3)
+	if (regs->ARM_sp & 7)
 		goto badframe;
 
 	frame = (struct sigframe *)regs->ARM_sp;
@@ -251,11 +268,11 @@
 	sigset_t set;
 
 	/*
-	 * Since we stacked the signal on a word boundary,
+	 * Since we stacked the signal on a 64-bit boundary,
 	 * then 'sp' should be word aligned here.  If it's
 	 * not, then the user is trying to mess with us.
 	 */
-	if (regs->ARM_sp & 3)
+	if (regs->ARM_sp & 7)
 		goto badframe;
 
 	frame = (struct rt_sigframe *)regs->ARM_sp;
@@ -319,8 +336,8 @@
 	return err;
 }
 
-static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
-				 unsigned long framesize)
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize)
 {
 	unsigned long sp = regs->ARM_sp;
 
@@ -331,77 +348,103 @@
 		sp = current->sas_ss_sp + current->sas_ss_size;
 
 	/*
-	 * No matter what happens, 'sp' must be word
-	 * aligned otherwise nasty things could happen
+	 * ATPCS B01 mandates 8-byte alignment
 	 */
-	/* ATPCS B01 mandates 8-byte alignment */
 	return (void *)((sp - framesize) & ~7);
 }
 
-static void setup_frame(int sig, struct k_sigaction *ka,
-			sigset_t *set, struct pt_regs *regs)
+static int
+setup_return(struct pt_regs *regs, struct k_sigaction *ka,
+	     unsigned long *rc, void *frame, int usig)
 {
-	struct sigframe *frame;
+	unsigned long handler = (unsigned long)ka->sa.sa_handler;
 	unsigned long retcode;
-	int err = 0;
-
-	frame = get_sigframe(ka, regs, sizeof(*frame));
-
-	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
-		goto segv_and_exit;
+	int thumb = 0;
+#ifdef CONFIG_CPU_32
+	unsigned long cpsr = regs->ARM_cpsr;
 
-	err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
+	/*
+	 * Maybe we need to deliver a 32-bit signal to a 26-bit task.
+	 */
+	if (ka->sa.sa_flags & SA_THIRTYTWO)
+		cpsr = (cpsr & ~MODE_MASK) | USR_MODE;
 
-	if (_NSIG_WORDS > 1) {
-		err |= __copy_to_user(frame->extramask, &set->sig[1],
-				      sizeof(frame->extramask));
+#ifdef CONFIG_ARM_THUMB
+	if (elf_hwcap & HWCAP_THUMB) {
+		/*
+		 * The LSB of the handler determines if we're going to
+		 * be using THUMB or ARM mode for this signal handler.
+		 */
+		thumb = handler & 1;
+
+		if (thumb)
+			cpsr |= T_BIT;
+		else
+			cpsr &= ~T_BIT;
 	}
+#endif
+#endif
 
-	/* Set up to return from userspace.  If provided, use a stub
-	   already in userspace.  */
 	if (ka->sa.sa_flags & SA_RESTORER) {
 		retcode = (unsigned long)ka->sa.sa_restorer;
 	} else {
-		retcode = (unsigned long)&frame->retcode;
-		__put_user_error(SWI_SYS_SIGRETURN, &frame->retcode, err);
-		flush_icache_range(retcode, retcode + 4);
-	}
+		unsigned int idx = thumb;
 
-	if (err)
-		goto segv_and_exit;
+		if (ka->sa.sa_flags & SA_SIGINFO)
+			idx += 2;
 
-	if (current->exec_domain && current->exec_domain->signal_invmap && sig < 32)
-		regs->ARM_r0 = current->exec_domain->signal_invmap[sig];
-	else
-		regs->ARM_r0 = sig;
+		if (__put_user(retcodes[idx], rc))
+			return 1;
+
+		flush_icache_range((unsigned long)rc,
+				   (unsigned long)(rc + 1));
+
+		retcode = ((unsigned long)rc) + thumb;
+	}
+
+	regs->ARM_r0 = usig;
 	regs->ARM_sp = (unsigned long)frame;
 	regs->ARM_lr = retcode;
-	regs->ARM_pc = (unsigned long)ka->sa.sa_handler;
-#if defined(CONFIG_CPU_32)
-	/* Maybe we need to deliver a 32-bit signal to a 26-bit task. */
-	if (ka->sa.sa_flags & SA_THIRTYTWO)
-		regs->ARM_cpsr = USR_MODE;
+	regs->ARM_pc = handler & (thumb ? ~1 : ~3);
+
+#ifdef CONFIG_CPU_32
+	regs->ARM_cpsr = cpsr;
 #endif
-	if (valid_user_regs(regs))
-		return;
 
-segv_and_exit:
-	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
-	force_sig(SIGSEGV, current);
+	return 0;
 }
 
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-			   sigset_t *set, struct pt_regs *regs)
+static int
+setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs)
 {
-	struct rt_sigframe *frame;
-	unsigned long retcode;
+	struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame));
 	int err = 0;
 
-	frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
+		return 1;
+
+	err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
+
+	if (_NSIG_WORDS > 1) {
+		err |= __copy_to_user(frame->extramask, &set->sig[1],
+				      sizeof(frame->extramask));
+	}
+
+	if (err == 0)
+		err = setup_return(regs, ka, &frame->retcode, frame, usig);
+
+	return err;
+}
+
+static int
+setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
+	       sigset_t *set, struct pt_regs *regs)
+{
+	struct rt_sigframe *frame = get_sigframe(ka, regs, sizeof(*frame));
+	int err = 0;
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
-		goto segv_and_exit;
+		return 1;
 
 	__put_user_error(&frame->info, &frame->pinfo, err);
 	__put_user_error(&frame->uc, &frame->puc, err);
@@ -414,47 +457,20 @@
 				regs, set->sig[0]);
 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
-	/* Set up to return from userspace.  If provided, use a stub
-	   already in userspace.  */
-	if (ka->sa.sa_flags & SA_RESTORER) {
-		retcode = (unsigned long)ka->sa.sa_restorer;
-	} else {
-		retcode = (unsigned long)&frame->retcode;
-		__put_user_error(SWI_SYS_RT_SIGRETURN, &frame->retcode, err);
-		flush_icache_range(retcode, retcode + 4);
-	}
-
-	if (err)
-		goto segv_and_exit;
-
-	if (current->exec_domain && current->exec_domain->signal_invmap && sig < 32)
-		regs->ARM_r0 = current->exec_domain->signal_invmap[sig];
-	else
-		regs->ARM_r0 = sig;
+	if (err == 0)
+		err = setup_return(regs, ka, &frame->retcode, frame, usig);
 
-	/*
-	 * For realtime signals we must also set the second and third
-	 * arguments for the signal handler.
-	 *   -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
-	 */
-	regs->ARM_r1 = (unsigned long)frame->pinfo;
-	regs->ARM_r2 = (unsigned long)frame->puc;
-
-	regs->ARM_sp = (unsigned long)frame;
-	regs->ARM_lr = retcode;
-	regs->ARM_pc = (unsigned long)ka->sa.sa_handler;
-#if defined(CONFIG_CPU_32)
-	/* Maybe we need to deliver a 32-bit signal to a 26-bit task. */
-	if (ka->sa.sa_flags & SA_THIRTYTWO)
-		regs->ARM_cpsr = USR_MODE;
-#endif
-	if (valid_user_regs(regs))
-		return;
+	if (err == 0) {
+		/*
+		 * For realtime signals we must also set the second and third
+		 * arguments for the signal handler.
+		 *   -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
+		 */
+		regs->ARM_r1 = (unsigned long)frame->pinfo;
+		regs->ARM_r2 = (unsigned long)frame->puc;
+	}
 
-segv_and_exit:
-	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
-	force_sig(SIGSEGV, current);
+	return err;
 }
 
 /*
@@ -464,22 +480,47 @@
 handle_signal(unsigned long sig, struct k_sigaction *ka,
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
-	/* Set up the stack frame */
+	struct task_struct *tsk = current;
+	int usig = sig;
+	int ret;
+
+	/*
+	 * translate the signal
+	 */
+	if (usig < 32 && tsk->exec_domain && tsk->exec_domain->signal_invmap)
+		usig = tsk->exec_domain->signal_invmap[usig];
+
+	/*
+	 * Set up the stack frame
+	 */
 	if (ka->sa.sa_flags & SA_SIGINFO)
-		setup_rt_frame(sig, ka, info, oldset, regs);
+		ret = setup_rt_frame(usig, ka, info, oldset, regs);
 	else
-		setup_frame(sig, ka, oldset, regs);
+		ret = setup_frame(usig, ka, oldset, regs);
 
-	if (ka->sa.sa_flags & SA_ONESHOT)
-		ka->sa.sa_handler = SIG_DFL;
+	/*
+	 * Check that the resulting registers are actually sane.
+	 */
+	ret |= !valid_user_regs(regs);
 
-	if (!(ka->sa.sa_flags & SA_NODEFER)) {
-		spin_lock_irq(&current->sigmask_lock);
-		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-		sigaddset(&current->blocked,sig);
-		recalc_sigpending(current);
-		spin_unlock_irq(&current->sigmask_lock);
+	if (ret == 0) {
+		if (ka->sa.sa_flags & SA_ONESHOT)
+			ka->sa.sa_handler = SIG_DFL;
+
+		if (!(ka->sa.sa_flags & SA_NODEFER)) {
+			spin_lock_irq(&tsk->sigmask_lock);
+			sigorsets(&tsk->blocked, &tsk->blocked,
+				  &ka->sa.sa_mask);
+			sigaddset(&tsk->blocked, sig);
+			recalc_sigpending(tsk);
+			spin_unlock_irq(&tsk->sigmask_lock);
+		}
+		return;
 	}
+
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, tsk);
 }
 
 /*
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c
--- v2.4.12/linux/arch/arm/kernel/time.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/kernel/time.c	Thu Oct 11 09:04:57 2001
@@ -33,7 +33,6 @@
 #include <asm/hardware.h>
 
 extern int setup_arm_irq(int, struct irqaction *);
-extern void setup_timer(void);
 extern rwlock_t xtime_lock;
 extern unsigned long wall_jiffies;
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c
--- v2.4.12/linux/arch/arm/kernel/traps.c	Sun Sep 23 11:40:55 2001
+++ linux/arch/arm/kernel/traps.c	Thu Oct 11 09:04:57 2001
@@ -22,6 +22,7 @@
 #include <linux/personality.h>
 #include <linux/ptrace.h>
 #include <linux/elf.h>
+#include <linux/interrupt.h>
 #include <linux/init.h>
 
 #include <asm/atomic.h>
@@ -176,7 +177,7 @@
 	printk("Process %s (pid: %d, stackpage=%08lx)\n",
 		current->comm, current->pid, 4096+(unsigned long)tsk);
 
-	if (!user_mode(regs)) {
+	if (!user_mode(regs) || in_interrupt()) {
 		mm_segment_t fs;
 
 		/*
@@ -209,7 +210,7 @@
 
 asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode)
 {
-	unsigned long addr;
+	unsigned long *pc;
 	siginfo_t info;
 
 	/*
@@ -217,11 +218,11 @@
 	 * whether we're in Thumb mode or not.
 	 */
 	regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
-	addr = instruction_pointer(regs);
+	pc = (unsigned long *)instruction_pointer(regs);
 
 #ifdef CONFIG_DEBUG_USER
-	printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n",
-		current->comm, current->pid, addr);
+	printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
+		current->comm, current->pid, pc);
 	dump_instr(regs);
 #endif
 
@@ -231,7 +232,7 @@
 	info.si_signo = SIGILL;
 	info.si_errno = 0;
 	info.si_code  = ILL_ILLOPC;
-	info.si_addr  = (void *)addr;
+	info.si_addr  = pc;
 
 	force_sig_info(SIGILL, &info, current);
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile
--- v2.4.12/linux/arch/arm/lib/Makefile	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/lib/Makefile	Thu Oct 11 09:04:57 2001
@@ -13,15 +13,20 @@
 		   copy_page.o delay.o findbit.o memchr.o memcpy.o    \
 		   memset.o memzero.o setbit.o strncpy_from_user.o    \
 		   strnlen_user.o strchr.o strrchr.o testchangebit.o  \
-		   testclearbit.o testsetbit.o uaccess.o
+		   testclearbit.o testsetbit.o uaccess.o getuser.o    \
+		   putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o   \
+		   ucmpdi2.o udivdi3.o lib1funcs.o
 obj-m		:=
 obj-n		:=
 
+obj-$(CONFIG_VT)+= kbd.o
+
 obj-arc		:= ecard.o io-acorn.o floppydma.o
 obj-rpc		:= ecard.o io-acorn.o floppydma.o
 obj-clps7500	:= io-acorn.o
 obj-l7200     	:= io-acorn.o
 obj-shark	:= io-shark.o
+obj-edb7211	:= io-acorn.o
 
 obj-y		+= $(obj-$(MACHINE))
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/ashldi3.c linux/arch/arm/lib/ashldi3.c
--- v2.4.12/linux/arch/arm/lib/ashldi3.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/ashldi3.c	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,61 @@
+/* More subroutines needed by GCC output code on some machines.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.
+ */
+/* support functions required by the kernel. based on code from gcc-2.95.3 */
+/* I Molton	29/07/01 */
+
+#include "gcclib.h"
+
+DItype
+__ashldi3 (DItype u, word_type b)
+{
+  DIunion w;
+  word_type bm;
+  DIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      w.s.low = 0;
+      w.s.high = (USItype)uu.s.low << -bm;
+    }
+  else
+    {
+      USItype carries = (USItype)uu.s.low >> bm;
+      w.s.low = (USItype)uu.s.low << b;
+      w.s.high = ((USItype)uu.s.high << b) | carries;
+    }
+
+  return w.ll;
+}
+
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/ashrdi3.c linux/arch/arm/lib/ashrdi3.c
--- v2.4.12/linux/arch/arm/lib/ashrdi3.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/ashrdi3.c	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,61 @@
+/* More subroutines needed by GCC output code on some machines.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.
+ */
+/* support functions required by the kernel. based on code from gcc-2.95.3 */
+/* I Molton     29/07/01 */
+
+#include "gcclib.h"
+
+DItype
+__ashrdi3 (DItype u, word_type b)
+{
+  DIunion w;
+  word_type bm;
+  DIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      /* w.s.high = 1..1 or 0..0 */
+      w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1);
+      w.s.low = uu.s.high >> -bm;
+    }
+  else
+    {
+      USItype carries = (USItype)uu.s.high << bm;
+      w.s.high = uu.s.high >> b;
+      w.s.low = ((USItype)uu.s.low >> b) | carries;
+    }
+
+  return w.ll;
+}
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/gcclib.h linux/arch/arm/lib/gcclib.h
--- v2.4.12/linux/arch/arm/lib/gcclib.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/gcclib.h	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,25 @@
+/* gcclib.h -- definitions for various functions 'borrowed' from gcc-2.95.3 */
+/* I Molton     29/07/01 */
+
+#define BITS_PER_UNIT  8
+#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+
+typedef unsigned int UQItype    __attribute__ ((mode (QI)));
+typedef          int SItype     __attribute__ ((mode (SI)));
+typedef unsigned int USItype    __attribute__ ((mode (SI)));
+typedef          int DItype     __attribute__ ((mode (DI)));
+typedef          int word_type 	__attribute__ ((mode (__word__)));
+typedef unsigned int UDItype    __attribute__ ((mode (DI)));
+
+#if 0 /* FIXME: endian test here!!! */
+  struct DIstruct {SItype high, low;};
+#else
+  struct DIstruct {SItype low, high;};
+#endif
+
+typedef union
+{
+  struct DIstruct s;
+  DItype ll;
+} DIunion;
+
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/getuser.S linux/arch/arm/lib/getuser.S
--- v2.4.12/linux/arch/arm/lib/getuser.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/getuser.S	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,96 @@
+/*
+ *  linux/arch/arm/lib/getuser.S
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Idea from x86 version, (C) Copyright 1998 Linus Torvalds
+ *
+ * These functions have a non-standard call interface to make them more
+ * efficient, especially as they return an error value in addition to
+ * the "real" return value.
+ *
+ * __get_user_X
+ *
+ * Inputs:	r0 contains the address
+ * Outputs:	r0 is the error code
+ *		r1, r2 contains the zero-extended value
+ *		lr corrupted
+ *
+ * No other registers must be altered.  (see include/asm-arm/uaccess.h
+ * for specific ASM register usage).
+ *
+ * Note that ADDR_LIMIT is either 0 or 0xc0000000.
+ * Note also that it is intended that __get_user_bad is not global.
+ */
+#include <asm/constants.h>
+
+	.global	__get_user_1
+__get_user_1:
+	bic	r1, sp, #0x1f00
+	bic	r1, r1, #0x00ff
+	ldr	r1, [r1, #TSK_ADDR_LIMIT]
+	sub	r1, r1, #1
+	cmp	r0, r1
+1:	ldrlsbt	r1, [r0]
+	movls	r0, #0
+	movls	pc, lr
+	b	__get_user_bad
+
+	.global	__get_user_2
+__get_user_2:
+	bic	r2, sp, #0x1f00
+	bic	r2, r2, #0x00ff
+	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+	sub	r2, r2, #2
+	cmp	r0, r2
+2:	ldrlsbt	r1, [r0], #1
+3:	ldrlsbt	r2, [r0]
+	orrls	r1, r1, r2, lsl #8
+	movls	r0, #0
+	movls	pc, lr
+	b	__get_user_bad
+
+	.global	__get_user_4
+__get_user_4:
+	bic	r1, sp, #0x1f00
+	bic	r1, r1, #0x00ff
+	ldr	r1, [r1, #TSK_ADDR_LIMIT]
+	sub	r1, r1, #4
+	cmp	r0, r1
+4:	ldrlst	r1, [r0]
+	movls	r0, #0
+	movls	pc, lr
+	b	__get_user_bad
+
+	.global	__get_user_8
+__get_user_8:
+	bic	r2, sp, #0x1f00
+	bic	r2, r2, #0x00ff
+	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+	sub	r2, r2, #8
+	cmp	r0, r2
+5:	ldrlst	r1, [r0], #4
+6:	ldrlst	r2, [r0]
+	movls	r0, #0
+	movls	pc, lr
+
+	/* fall through */
+
+__get_user_bad:
+	mov	r2, #0
+	mov	r1, #0
+	mov	r0, #-14
+	mov	pc, lr
+
+.section __ex_table, "a"
+	.long	1b, __get_user_bad
+	.long	2b, __get_user_bad
+	.long	3b, __get_user_bad
+	.long	4b, __get_user_bad
+	.long	5b, __get_user_bad
+	.long	6b, __get_user_bad
+.previous
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/kbd.c linux/arch/arm/lib/kbd.c
--- v2.4.12/linux/arch/arm/lib/kbd.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/kbd.c	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,13 @@
+#include <linux/config.h>
+#include <linux/kd.h>
+
+int  (*k_setkeycode)(unsigned int, unsigned int);
+int  (*k_getkeycode)(unsigned int);
+int  (*k_translate)(unsigned char, unsigned char *, char);
+char (*k_unexpected_up)(unsigned char);
+void (*k_leds)(unsigned char);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+int k_sysrq_key;
+unsigned char *k_sysrq_xlate;
+#endif
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/lib1funcs.S linux/arch/arm/lib/lib1funcs.S
--- v2.4.12/linux/arch/arm/lib/lib1funcs.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/lib1funcs.S	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,320 @@
+@ libgcc1 routines for ARM cpu.
+@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk)
+
+/* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
+
+This file 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, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file.  (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file 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; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.
+ */
+/* This code is derived from gcc 2.95.3 */
+/* I Molton     29/07/01 */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_CPU_26
+#define RET	movs
+#define RETc(x)	mov##x##s
+#define RETCOND ^
+#else
+#define RET	mov
+#define RETc(x)	mov##x
+#define RETCOND
+#endif
+
+dividend	.req	r0
+divisor		.req	r1
+result		.req	r2
+overdone        .req    r2
+curbit		.req	r3
+ip		.req	r12
+sp		.req	r13
+lr		.req	r14
+pc		.req	r15
+	
+ENTRY(__udivsi3)
+	cmp	divisor, #0
+	beq	Ldiv0
+	mov	curbit, #1
+	mov	result, #0
+	cmp	dividend, divisor
+	bcc	Lgot_result_udivsi3
+1:
+	@ Unless the divisor is very big, shift it up in multiples of
+	@ four bits, since this is the amount of unwinding in the main
+	@ division loop.  Continue shifting until the divisor is 
+	@ larger than the dividend.
+	cmp	divisor, #0x10000000
+	cmpcc	divisor, dividend
+	movcc	divisor, divisor, lsl #4
+	movcc	curbit, curbit, lsl #4
+	bcc	1b
+
+2:
+	@ For very big divisors, we must shift it a bit at a time, or
+	@ we will be in danger of overflowing.
+	cmp	divisor, #0x80000000
+	cmpcc	divisor, dividend
+	movcc	divisor, divisor, lsl #1
+	movcc	curbit, curbit, lsl #1
+	bcc	2b
+
+3:
+	@ Test for possible subtractions, and note which bits
+	@ are done in the result.  On the final pass, this may subtract
+	@ too much from the dividend, but the result will be ok, since the
+	@ "bit" will have been shifted out at the bottom.
+	cmp	dividend, divisor
+	subcs	dividend, dividend, divisor
+	orrcs	result, result, curbit
+	cmp	dividend, divisor, lsr #1
+	subcs	dividend, dividend, divisor, lsr #1
+	orrcs	result, result, curbit, lsr #1
+	cmp	dividend, divisor, lsr #2
+	subcs	dividend, dividend, divisor, lsr #2
+	orrcs	result, result, curbit, lsr #2
+	cmp	dividend, divisor, lsr #3
+	subcs	dividend, dividend, divisor, lsr #3
+	orrcs	result, result, curbit, lsr #3
+	cmp	dividend, #0			@ Early termination?
+	movnes	curbit, curbit, lsr #4		@ No, any more bits to do?
+	movne	divisor, divisor, lsr #4
+	bne	3b
+Lgot_result_udivsi3:
+	mov	r0, result
+	RET	pc, lr
+
+Ldiv0:
+	str	lr, [sp, #-4]!
+	bl	__div0
+	mov	r0, #0			@ about as wrong as it could be
+	ldmia	sp!, {pc}RETCOND
+
+/* __umodsi3 ----------------------- */
+
+ENTRY(__umodsi3)
+	cmp	divisor, #0
+	beq	Ldiv0
+	mov	curbit, #1
+	cmp	dividend, divisor
+	RETc(cc)	pc, lr
+1:
+	@ Unless the divisor is very big, shift it up in multiples of
+	@ four bits, since this is the amount of unwinding in the main
+	@ division loop.  Continue shifting until the divisor is 
+	@ larger than the dividend.
+	cmp	divisor, #0x10000000
+	cmpcc	divisor, dividend
+	movcc	divisor, divisor, lsl #4
+	movcc	curbit, curbit, lsl #4
+	bcc	1b
+
+2:
+	@ For very big divisors, we must shift it a bit at a time, or
+	@ we will be in danger of overflowing.
+	cmp	divisor, #0x80000000
+	cmpcc	divisor, dividend
+	movcc	divisor, divisor, lsl #1
+	movcc	curbit, curbit, lsl #1
+	bcc	2b
+
+3:
+	@ Test for possible subtractions.  On the final pass, this may 
+	@ subtract too much from the dividend, so keep track of which
+	@ subtractions are done, we can fix them up afterwards...
+	mov	overdone, #0
+	cmp	dividend, divisor
+	subcs	dividend, dividend, divisor
+	cmp	dividend, divisor, lsr #1
+	subcs	dividend, dividend, divisor, lsr #1
+	orrcs	overdone, overdone, curbit, ror #1
+	cmp	dividend, divisor, lsr #2
+	subcs	dividend, dividend, divisor, lsr #2
+	orrcs	overdone, overdone, curbit, ror #2
+	cmp	dividend, divisor, lsr #3
+	subcs	dividend, dividend, divisor, lsr #3
+	orrcs	overdone, overdone, curbit, ror #3
+	mov	ip, curbit
+	cmp	dividend, #0			@ Early termination?
+	movnes	curbit, curbit, lsr #4		@ No, any more bits to do?
+	movne	divisor, divisor, lsr #4
+	bne	3b
+
+	@ Any subtractions that we should not have done will be recorded in
+	@ the top three bits of "overdone".  Exactly which were not needed
+	@ are governed by the position of the bit, stored in ip.
+	@ If we terminated early, because dividend became zero,
+	@ then none of the below will match, since the bit in ip will not be
+	@ in the bottom nibble.
+	ands	overdone, overdone, #0xe0000000
+	RETc(eq)	pc, lr				@ No fixups needed
+	tst	overdone, ip, ror #3
+	addne	dividend, dividend, divisor, lsr #3
+	tst	overdone, ip, ror #2
+	addne	dividend, dividend, divisor, lsr #2
+	tst	overdone, ip, ror #1
+	addne	dividend, dividend, divisor, lsr #1
+	RET	pc, lr
+
+ENTRY(__divsi3)
+	eor	ip, dividend, divisor		@ Save the sign of the result.
+	mov	curbit, #1
+	mov	result, #0
+	cmp	divisor, #0
+	rsbmi	divisor, divisor, #0		@ Loops below use unsigned.
+	beq	Ldiv0
+	cmp	dividend, #0
+	rsbmi	dividend, dividend, #0
+	cmp	dividend, divisor
+	bcc	Lgot_result_divsi3
+
+1:
+	@ Unless the divisor is very big, shift it up in multiples of
+	@ four bits, since this is the amount of unwinding in the main
+	@ division loop.  Continue shifting until the divisor is 
+	@ larger than the dividend.
+	cmp	divisor, #0x10000000
+	cmpcc	divisor, dividend
+	movcc	divisor, divisor, lsl #4
+	movcc	curbit, curbit, lsl #4
+	bcc	1b
+
+2:
+	@ For very big divisors, we must shift it a bit at a time, or
+	@ we will be in danger of overflowing.
+	cmp	divisor, #0x80000000
+	cmpcc	divisor, dividend
+	movcc	divisor, divisor, lsl #1
+	movcc	curbit, curbit, lsl #1
+	bcc	2b
+
+3:
+	@ Test for possible subtractions, and note which bits
+	@ are done in the result.  On the final pass, this may subtract
+	@ too much from the dividend, but the result will be ok, since the
+	@ "bit" will have been shifted out at the bottom.
+	cmp	dividend, divisor
+	subcs	dividend, dividend, divisor
+	orrcs	result, result, curbit
+	cmp	dividend, divisor, lsr #1
+	subcs	dividend, dividend, divisor, lsr #1
+	orrcs	result, result, curbit, lsr #1
+	cmp	dividend, divisor, lsr #2
+	subcs	dividend, dividend, divisor, lsr #2
+	orrcs	result, result, curbit, lsr #2
+	cmp	dividend, divisor, lsr #3
+	subcs	dividend, dividend, divisor, lsr #3
+	orrcs	result, result, curbit, lsr #3
+	cmp	dividend, #0			@ Early termination?
+	movnes	curbit, curbit, lsr #4		@ No, any more bits to do?
+	movne	divisor, divisor, lsr #4
+	bne	3b
+Lgot_result_divsi3:
+	mov	r0, result
+	cmp	ip, #0
+	rsbmi	r0, r0, #0
+	RET	pc, lr
+
+ENTRY(__modsi3)
+	mov	curbit, #1
+	cmp	divisor, #0
+	rsbmi	divisor, divisor, #0		@ Loops below use unsigned.
+	beq	Ldiv0
+	@ Need to save the sign of the dividend, unfortunately, we need
+	@ ip later on; this is faster than pushing lr and using that.
+	str	dividend, [sp, #-4]!
+	cmp	dividend, #0
+	rsbmi	dividend, dividend, #0
+	cmp	dividend, divisor
+	bcc	Lgot_result_modsi3
+
+1:
+	@ Unless the divisor is very big, shift it up in multiples of
+	@ four bits, since this is the amount of unwinding in the main
+	@ division loop.  Continue shifting until the divisor is 
+	@ larger than the dividend.
+	cmp	divisor, #0x10000000
+	cmpcc	divisor, dividend
+	movcc	divisor, divisor, lsl #4
+	movcc	curbit, curbit, lsl #4
+	bcc	1b
+
+2:
+	@ For very big divisors, we must shift it a bit at a time, or
+	@ we will be in danger of overflowing.
+	cmp	divisor, #0x80000000
+	cmpcc	divisor, dividend
+	movcc	divisor, divisor, lsl #1
+	movcc	curbit, curbit, lsl #1
+	bcc	2b
+
+3:
+	@ Test for possible subtractions.  On the final pass, this may 
+	@ subtract too much from the dividend, so keep track of which
+	@ subtractions are done, we can fix them up afterwards...
+	mov	overdone, #0
+	cmp	dividend, divisor
+	subcs	dividend, dividend, divisor
+	cmp	dividend, divisor, lsr #1
+	subcs	dividend, dividend, divisor, lsr #1
+	orrcs	overdone, overdone, curbit, ror #1
+	cmp	dividend, divisor, lsr #2
+	subcs	dividend, dividend, divisor, lsr #2
+	orrcs	overdone, overdone, curbit, ror #2
+	cmp	dividend, divisor, lsr #3
+	subcs	dividend, dividend, divisor, lsr #3
+	orrcs	overdone, overdone, curbit, ror #3
+	mov	ip, curbit
+	cmp	dividend, #0			@ Early termination?
+	movnes	curbit, curbit, lsr #4		@ No, any more bits to do?
+	movne	divisor, divisor, lsr #4
+	bne	3b
+
+	@ Any subtractions that we should not have done will be recorded in
+	@ the top three bits of "overdone".  Exactly which were not needed
+	@ are governed by the position of the bit, stored in ip.
+	@ If we terminated early, because dividend became zero,
+	@ then none of the below will match, since the bit in ip will not be
+	@ in the bottom nibble.
+	ands	overdone, overdone, #0xe0000000
+	beq	Lgot_result_modsi3
+	tst	overdone, ip, ror #3
+	addne	dividend, dividend, divisor, lsr #3
+	tst	overdone, ip, ror #2
+	addne	dividend, dividend, divisor, lsr #2
+	tst	overdone, ip, ror #1
+	addne	dividend, dividend, divisor, lsr #1
+Lgot_result_modsi3:
+	ldr	ip, [sp], #4
+	cmp	ip, #0
+	rsbmi	dividend, dividend, #0
+	RET	pc, lr
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/longlong.h linux/arch/arm/lib/longlong.h
--- v2.4.12/linux/arch/arm/lib/longlong.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/longlong.h	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,184 @@
+/* longlong.h -- based on code from gcc-2.95.3
+
+   definitions for mixed size 32/64 bit arithmetic.
+   Copyright (C) 1991, 92, 94, 95, 96, 1997, 1998 Free Software Foundation, Inc.
+
+   This definition file 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, or (at your option) any later version.
+
+   This definition file 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.  */
+
+/* Borrowed from GCC 2.95.3, I Molton 29/07/01 */
+
+#ifndef SI_TYPE_SIZE
+#define SI_TYPE_SIZE 32
+#endif
+
+#define __BITS4 (SI_TYPE_SIZE / 4)
+#define __ll_B (1L << (SI_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((USItype) (t) % __ll_B)
+#define __ll_highpart(t) ((USItype) (t) / __ll_B)
+
+/* Define auxiliary asm macros.
+
+   1) umul_ppmm(high_prod, low_prod, multipler, multiplicand)
+   multiplies two USItype integers MULTIPLER and MULTIPLICAND,
+   and generates a two-part USItype product in HIGH_PROD and
+   LOW_PROD.
+
+   2) __umulsidi3(a,b) multiplies two USItype integers A and B,
+   and returns a UDItype product.  This is just a variant of umul_ppmm.
+
+   3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+   denominator) divides a two-word unsigned integer, composed by the
+   integers HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and
+   places the quotient in QUOTIENT and the remainder in REMAINDER.
+   HIGH_NUMERATOR must be less than DENOMINATOR for correct operation.
+   If, in addition, the most significant bit of DENOMINATOR must be 1,
+   then the pre-processor symbol UDIV_NEEDS_NORMALIZATION is defined to 1.
+
+   4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+   denominator).  Like udiv_qrnnd but the numbers are signed.  The
+   quotient is rounded towards 0.
+
+   5) count_leading_zeros(count, x) counts the number of zero-bits from
+   the msb to the first non-zero bit.  This is the number of steps X
+   needs to be shifted left to set the msb.  Undefined for X == 0.
+
+   6) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
+   high_addend_2, low_addend_2) adds two two-word unsigned integers,
+   composed by HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and
+   LOW_ADDEND_2 respectively.  The result is placed in HIGH_SUM and
+   LOW_SUM.  Overflow (i.e. carry out) is not stored anywhere, and is
+   lost.
+
+   7) sub_ddmmss(high_difference, low_difference, high_minuend,
+   low_minuend, high_subtrahend, low_subtrahend) subtracts two
+   two-word unsigned integers, composed by HIGH_MINUEND_1 and
+   LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and LOW_SUBTRAHEND_2
+   respectively.  The result is placed in HIGH_DIFFERENCE and
+   LOW_DIFFERENCE.  Overflow (i.e. carry out) is not stored anywhere,
+   and is lost.
+
+   If any of these macros are left undefined for a particular CPU,
+   C macros are used.  */
+
+#if defined (__arm__)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("adds	%1, %4, %5
+	adc	%0, %2, %3"						\
+	   : "=r" ((USItype) (sh)),					\
+	     "=&r" ((USItype) (sl))					\
+	   : "%r" ((USItype) (ah)),					\
+	     "rI" ((USItype) (bh)),					\
+	     "%r" ((USItype) (al)),					\
+	     "rI" ((USItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subs	%1, %4, %5
+	sbc	%0, %2, %3"						\
+	   : "=r" ((USItype) (sh)),					\
+	     "=&r" ((USItype) (sl))					\
+	   : "r" ((USItype) (ah)),					\
+	     "rI" ((USItype) (bh)),					\
+	     "r" ((USItype) (al)),					\
+	     "rI" ((USItype) (bl)))
+#define umul_ppmm(xh, xl, a, b) \
+{register USItype __t0, __t1, __t2;					\
+  __asm__ ("%@ Inlined umul_ppmm
+	mov	%2, %5, lsr #16
+	mov	%0, %6, lsr #16
+	bic	%3, %5, %2, lsl #16
+	bic	%4, %6, %0, lsl #16
+	mul	%1, %3, %4
+	mul	%4, %2, %4
+	mul	%3, %0, %3
+	mul	%0, %2, %0
+	adds	%3, %4, %3
+	addcs	%0, %0, #65536
+	adds	%1, %1, %3, lsl #16
+	adc	%0, %0, %3, lsr #16"					\
+	   : "=&r" ((USItype) (xh)),					\
+	     "=r" ((USItype) (xl)),					\
+	     "=&r" (__t0), "=&r" (__t1), "=r" (__t2)			\
+	   : "r" ((USItype) (a)),					\
+	     "r" ((USItype) (b)));}
+#define UMUL_TIME 20
+#define UDIV_TIME 100
+#endif /* __arm__ */
+
+#define __umulsidi3(u, v) \
+  ({DIunion __w;							\
+    umul_ppmm (__w.s.high, __w.s.low, u, v);				\
+    __w.ll; })
+
+#define __udiv_qrnnd_c(q, r, n1, n0, d) \
+  do {									\
+    USItype __d1, __d0, __q1, __q0;					\
+    USItype __r1, __r0, __m;						\
+    __d1 = __ll_highpart (d);						\
+    __d0 = __ll_lowpart (d);						\
+									\
+    __r1 = (n1) % __d1;							\
+    __q1 = (n1) / __d1;							\
+    __m = (USItype) __q1 * __d0;					\
+    __r1 = __r1 * __ll_B | __ll_highpart (n0);				\
+    if (__r1 < __m)							\
+      {									\
+	__q1--, __r1 += (d);						\
+	if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
+	  if (__r1 < __m)						\
+	    __q1--, __r1 += (d);					\
+      }									\
+    __r1 -= __m;							\
+									\
+    __r0 = __r1 % __d1;							\
+    __q0 = __r1 / __d1;							\
+    __m = (USItype) __q0 * __d0;					\
+    __r0 = __r0 * __ll_B | __ll_lowpart (n0);				\
+    if (__r0 < __m)							\
+      {									\
+	__q0--, __r0 += (d);						\
+	if (__r0 >= (d))						\
+	  if (__r0 < __m)						\
+	    __q0--, __r0 += (d);					\
+      }									\
+    __r0 -= __m;							\
+									\
+    (q) = (USItype) __q1 * __ll_B | __q0;				\
+    (r) = __r0;								\
+  } while (0)
+
+#define UDIV_NEEDS_NORMALIZATION 1
+#define udiv_qrnnd __udiv_qrnnd_c
+
+extern const UQItype __clz_tab[];
+#define count_leading_zeros(count, x) \
+  do {									\
+    USItype __xr = (x);							\
+    USItype __a;							\
+									\
+    if (SI_TYPE_SIZE <= 32)						\
+      {									\
+	__a = __xr < ((USItype)1<<2*__BITS4)				\
+	  ? (__xr < ((USItype)1<<__BITS4) ? 0 : __BITS4)		\
+	  : (__xr < ((USItype)1<<3*__BITS4) ?  2*__BITS4 : 3*__BITS4);	\
+      }									\
+    else								\
+      {									\
+	for (__a = SI_TYPE_SIZE - 8; __a > 0; __a -= 8)			\
+	  if (((__xr >> __a) & 0xff) != 0)				\
+	    break;							\
+      }									\
+									\
+    (count) = SI_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a);		\
+  } while (0)
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/lshrdi3.c linux/arch/arm/lib/lshrdi3.c
--- v2.4.12/linux/arch/arm/lib/lshrdi3.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/lshrdi3.c	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,61 @@
+/* More subroutines needed by GCC output code on some machines.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.
+ */
+/* support functions required by the kernel. based on code from gcc-2.95.3 */
+/* I Molton     29/07/01 */
+
+#include "gcclib.h"
+
+DItype
+__lshrdi3 (DItype u, word_type b)
+{
+  DIunion w;
+  word_type bm;
+  DIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      w.s.high = 0;
+      w.s.low = (USItype)uu.s.high >> -bm;
+    }
+  else
+    {
+      USItype carries = (USItype)uu.s.high << bm;
+      w.s.high = (USItype)uu.s.high >> b;
+      w.s.low = ((USItype)uu.s.low >> b) | carries;
+    }
+
+  return w.ll;
+}
+
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/muldi3.c linux/arch/arm/lib/muldi3.c
--- v2.4.12/linux/arch/arm/lib/muldi3.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/muldi3.c	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,77 @@
+/* More subroutines needed by GCC output code on some machines.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.
+ */
+/* support functions required by the kernel. based on code from gcc-2.95.3 */
+/* I Molton     29/07/01 */
+
+#include "gcclib.h"
+
+#define umul_ppmm(xh, xl, a, b) \
+{register USItype __t0, __t1, __t2;                                     \
+  __asm__ ("%@ Inlined umul_ppmm
+        mov     %2, %5, lsr #16
+        mov     %0, %6, lsr #16
+        bic     %3, %5, %2, lsl #16
+        bic     %4, %6, %0, lsl #16
+        mul     %1, %3, %4
+        mul     %4, %2, %4
+        mul     %3, %0, %3
+        mul     %0, %2, %0
+        adds    %3, %4, %3
+        addcs   %0, %0, #65536
+        adds    %1, %1, %3, lsl #16
+        adc     %0, %0, %3, lsr #16"                                    \
+           : "=&r" ((USItype) (xh)),                                    \
+             "=r" ((USItype) (xl)),                                     \
+             "=&r" (__t0), "=&r" (__t1), "=r" (__t2)                    \
+           : "r" ((USItype) (a)),                                       \
+             "r" ((USItype) (b)));}
+
+
+#define __umulsidi3(u, v) \
+  ({DIunion __w;                                                        \
+    umul_ppmm (__w.s.high, __w.s.low, u, v);                            \
+    __w.ll; })
+
+
+DItype
+__muldi3 (DItype u, DItype v)
+{
+  DIunion w;
+  DIunion uu, vv;
+
+  uu.ll = u,
+  vv.ll = v;
+
+  w.ll = __umulsidi3 (uu.s.low, vv.s.low);
+  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
+               + (USItype) uu.s.high * (USItype) vv.s.low);
+
+  return w.ll;
+}
+
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/putuser.S linux/arch/arm/lib/putuser.S
--- v2.4.12/linux/arch/arm/lib/putuser.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/putuser.S	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,94 @@
+/*
+ *  linux/arch/arm/lib/putuser.S
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Idea from x86 version, (C) Copyright 1998 Linus Torvalds
+ *
+ * These functions have a non-standard call interface to make
+ * them more efficient, especially as they return an error
+ * value in addition to the "real" return value.
+ *
+ * __put_user_X
+ *
+ * Inputs:	r0 contains the address
+ *		r1, r2 contains the value
+ * Outputs:	r0 is the error code
+ *		lr corrupted
+ *
+ * No other registers must be altered.  (see include/asm-arm/uaccess.h
+ * for specific ASM register usage).
+ *
+ * Note that ADDR_LIMIT is either 0 or 0xc0000000
+ * Note also that it is intended that __put_user_bad is not global.
+ */
+#include <asm/constants.h>
+
+	.global	__put_user_1
+__put_user_1:
+	bic	r2, sp, #0x1f00
+	bic	r2, r2, #0x00ff
+	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+	sub	r2, r2, #1
+	cmp	r0, r2
+1:	strlsbt	r1, [r0]
+	movls	r0, #0
+	movls	pc, lr
+	b	__put_user_bad
+
+	.global	__put_user_2
+__put_user_2:
+	bic	r2, sp, #0x1f00
+	bic	r2, r2, #0x00ff
+	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+	sub	r2, r2, #2
+	cmp	r0, r2
+2:	strlsbt	r1, [r0], #1
+	movls	r1, r1, lsr #8
+3:	strlsbt	r1, [r0]
+	movls	r0, #0
+	movls	pc, lr
+	b	__put_user_bad
+
+	.global	__put_user_4
+__put_user_4:
+	bic	r2, sp, #0x1f00
+	bic	r2, r2, #0x00ff
+	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+	sub	r2, r2, #4
+	cmp	r0, r2
+4:	strlst	r1, [r0]
+	movls	r0, #0
+	movls	pc, lr
+	b	__put_user_bad
+
+	.global	__put_user_8
+__put_user_8:
+	bic	ip, sp, #0x1f00
+	bic	ip, ip, #0x00ff
+	ldr	ip, [ip, #TSK_ADDR_LIMIT]
+	sub	ip, ip, #8
+	cmp	r0, ip
+5:	strlst	r1, [r0], #4
+6:	strlst	r2, [r0]
+	movls	r0, #0
+	movls	pc, lr
+
+	/* fall through */
+
+__put_user_bad:
+	mov	r0, #-14
+	mov	pc, lr
+
+.section __ex_table, "a"
+	.long	1b, __put_user_bad
+	.long	2b, __put_user_bad
+	.long	3b, __put_user_bad
+	.long	4b, __put_user_bad
+	.long	5b, __put_user_bad
+	.long	6b, __put_user_bad
+.previous
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/ucmpdi2.c linux/arch/arm/lib/ucmpdi2.c
--- v2.4.12/linux/arch/arm/lib/ucmpdi2.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/ucmpdi2.c	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,51 @@
+/* More subroutines needed by GCC output code on some machines.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.
+ */
+/* support functions required by the kernel. based on code from gcc-2.95.3 */
+/* I Molton     29/07/01 */
+
+#include "gcclib.h"
+
+word_type
+__ucmpdi2 (DItype a, DItype b)
+{
+  DIunion au, bu;
+
+  au.ll = a, bu.ll = b;
+
+  if ((USItype) au.s.high < (USItype) bu.s.high)
+    return 0;
+  else if ((USItype) au.s.high > (USItype) bu.s.high)
+    return 2;
+  if ((USItype) au.s.low < (USItype) bu.s.low)
+    return 0;
+  else if ((USItype) au.s.low > (USItype) bu.s.low)
+    return 2;
+  return 1;
+}
+
diff -u --recursive --new-file v2.4.12/linux/arch/arm/lib/udivdi3.c linux/arch/arm/lib/udivdi3.c
--- v2.4.12/linux/arch/arm/lib/udivdi3.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/udivdi3.c	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,231 @@
+/* More subroutines needed by GCC output code on some machines.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.
+ */
+/* support functions required by the kernel. based on code from gcc-2.95.3 */
+/* I Molton     29/07/01 */
+
+#include "gcclib.h"
+#include "longlong.h"
+
+static const UQItype __clz_tab[] =
+{
+  0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+  6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+};
+
+UDItype
+__udivmoddi4 (UDItype n, UDItype d, UDItype *rp)
+{
+  DIunion ww;
+  DIunion nn, dd;
+  DIunion rr;
+  USItype d0, d1, n0, n1, n2;
+  USItype q0, q1;
+  USItype b, bm;
+
+  nn.ll = n;
+  dd.ll = d;
+
+  d0 = dd.s.low;
+  d1 = dd.s.high;
+  n0 = nn.s.low;
+  n1 = nn.s.high;
+
+  if (d1 == 0)
+    {
+      if (d0 > n1)
+        {
+          /* 0q = nn / 0D */
+
+          count_leading_zeros (bm, d0);
+
+          if (bm != 0)
+            {
+              /* Normalize, i.e. make the most significant bit of the
+                 denominator set.  */
+
+              d0 = d0 << bm;
+              n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm));
+              n0 = n0 << bm;
+            }
+
+          udiv_qrnnd (q0, n0, n1, n0, d0);
+          q1 = 0;
+
+          /* Remainder in n0 >> bm.  */
+        }
+      else
+        {
+          /* qq = NN / 0d */
+
+          if (d0 == 0)
+            d0 = 1 / d0;        /* Divide intentionally by zero.  */
+
+          count_leading_zeros (bm, d0);
+
+          if (bm == 0)
+            {
+              /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
+                 conclude (the most significant bit of n1 is set) /\ (the
+                 leading quotient digit q1 = 1).
+
+                 This special case is necessary, not an optimization.
+                 (Shifts counts of SI_TYPE_SIZE are undefined.)  */
+
+              n1 -= d0;
+              q1 = 1;
+            }
+          else
+            {
+              /* Normalize.  */
+
+              b = SI_TYPE_SIZE - bm;
+
+              d0 = d0 << bm;
+              n2 = n1 >> b;
+              n1 = (n1 << bm) | (n0 >> b);
+              n0 = n0 << bm;
+
+              udiv_qrnnd (q1, n1, n2, n1, d0);
+            }
+
+          /* n1 != d0...  */
+
+          udiv_qrnnd (q0, n0, n1, n0, d0);
+
+          /* Remainder in n0 >> bm.  */
+        }
+
+      if (rp != 0)
+        {
+          rr.s.low = n0 >> bm;
+          rr.s.high = 0;
+          *rp = rr.ll;
+        }
+    }
+  else
+    {
+      if (d1 > n1)
+        {
+          /* 00 = nn / DD */
+
+          q0 = 0;
+          q1 = 0;
+
+          /* Remainder in n1n0.  */
+          if (rp != 0)
+            {
+              rr.s.low = n0;
+              rr.s.high = n1;
+              *rp = rr.ll;
+            }
+        }
+      else
+        {
+          /* 0q = NN / dd */
+
+          count_leading_zeros (bm, d1);
+          if (bm == 0)
+            {
+              /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
+                 conclude (the most significant bit of n1 is set) /\ (the
+                 quotient digit q0 = 0 or 1).
+
+                 This special case is necessary, not an optimization.  */
+
+              /* The condition on the next line takes advantage of that
+                 n1 >= d1 (true due to program flow).  */
+              if (n1 > d1 || n0 >= d0)
+                {
+                  q0 = 1;
+                  sub_ddmmss (n1, n0, n1, n0, d1, d0);
+                }
+              else
+                q0 = 0;
+
+              q1 = 0;
+
+              if (rp != 0)
+                {
+                  rr.s.low = n0;
+                  rr.s.high = n1;
+                  *rp = rr.ll;
+                }
+            }
+          else
+            {
+              USItype m1, m0;
+              /* Normalize.  */
+
+              b = SI_TYPE_SIZE - bm;
+
+              d1 = (d1 << bm) | (d0 >> b);
+              d0 = d0 << bm;
+              n2 = n1 >> b;
+              n1 = (n1 << bm) | (n0 >> b);
+              n0 = n0 << bm;
+
+              udiv_qrnnd (q0, n1, n2, n1, d1);
+              umul_ppmm (m1, m0, q0, d0);
+
+              if (m1 > n1 || (m1 == n1 && m0 > n0))
+                {
+                  q0--;
+                  sub_ddmmss (m1, m0, m1, m0, d1, d0);
+                }
+
+              q1 = 0;
+
+              /* Remainder in (n1n0 - m1m0) >> bm.  */
+              if (rp != 0)
+                {
+                  sub_ddmmss (n1, n0, n1, n0, m1, m0);
+                  rr.s.low = (n1 << b) | (n0 >> bm);
+                  rr.s.high = n1 >> bm;
+                  *rp = rr.ll;
+                }
+            }
+        }
+    }
+
+  ww.s.low = q0;
+  ww.s.high = q1;
+  return ww.ll;
+}
+
+UDItype
+__udivdi3 (UDItype n, UDItype d)
+{
+  return __udivmoddi4 (n, d, (UDItype *) 0);
+}
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-ebsa110/io.c linux/arch/arm/mach-ebsa110/io.c
--- v2.4.12/linux/arch/arm/mach-ebsa110/io.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-ebsa110/io.c	Thu Oct 11 09:04:57 2001
@@ -279,6 +279,9 @@
 	__raw_readsb(ISAIO_BASE + off, from, len);
 }
 
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(insb);
+
 void outsw(unsigned int port, const void *from, int len)
 {
 	u32 off;
@@ -308,6 +311,9 @@
 
 	__raw_readsw(ISAIO_BASE + off, from, len);
 }
+
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(insw);
 
 void outsl(unsigned int port, const void *from, int len)
 {
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-integrator/cpu.c linux/arch/arm/mach-integrator/cpu.c
--- v2.4.12/linux/arch/arm/mach-integrator/cpu.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-integrator/cpu.c	Thu Oct 11 09:04:57 2001
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2001 Deep Blue Solutions Ltd.
  *
- *  $Id: cpu.c,v 1.1 2001/06/17 10:12:37 rmk Exp $
+ *  $Id: cpu.c,v 1.2 2001/09/22 12:11:17 rmk Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -70,7 +70,7 @@
  * Validate the speed in khz.  If it is outside our
  * range, then return the lowest.
  */
-unsigned int cpufreq_validatespeed(unsigned int freq_khz)
+unsigned int integrator_validatespeed(unsigned int freq_khz)
 {
 	struct vco vco;
 
@@ -87,7 +87,7 @@
 	return vco_to_freq(vco, 1);
 }
 
-void cpufreq_setspeed(unsigned int freq_khz)
+void integrator_setspeed(unsigned int freq_khz)
 {
 	struct vco vco = freq_to_vco(freq_khz, 1);
 	u_int cm_osc;
@@ -122,6 +122,7 @@
 
 #ifdef CONFIG_CPU_FREQ
 	cpufreq_init(cpu_freq_khz);
+	cpufreq_setfunctions(integrator_validatespeed, integrator_setspeed);
 #endif
 
 	cm_stat = __raw_readl(CM_STAT);
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-integrator/dma.c linux/arch/arm/mach-integrator/dma.c
--- v2.4.12/linux/arch/arm/mach-integrator/dma.c	Fri Mar  2 18:38:39 2001
+++ linux/arch/arm/mach-integrator/dma.c	Thu Oct 11 09:04:57 2001
@@ -19,7 +19,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mman.h>
 #include <linux/init.h>
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-integrator/pci_v3.c linux/arch/arm/mach-integrator/pci_v3.c
--- v2.4.12/linux/arch/arm/mach-integrator/pci_v3.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-integrator/pci_v3.c	Thu Oct 11 09:04:57 2001
@@ -24,7 +24,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/Makefile linux/arch/arm/mach-sa1100/Makefile
--- v2.4.12/linux/arch/arm/mach-sa1100/Makefile	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/Makefile	Thu Oct 11 09:04:57 2001
@@ -14,31 +14,38 @@
 obj-n :=
 obj-  :=
 
-export-objs :=	assabet.o bitsy.o freebird.o huw_webpanel.o yopy.o \
+export-objs :=	assabet.o h3600.o freebird.o huw_webpanel.o yopy.o \
 		generic.o hwtimer.o irq.o usb_ctl.o usb_recv.o usb_send.o \
-		dma-sa1100.o dma-sa1111.o pcipool.o
+		dma-sa1100.o dma-sa1111.o pcipool.o sa1111-pcibuf.o
 
 # Common support (must be linked before board specific support)
 obj-y += generic.o irq.o dma-sa1100.o
-obj-$(CONFIG_SA1111) += sa1111.o dma-sa1111.o sa1111-pcibuf.o pcipool.o
 
 # This needs to be cleaned up.  We probably need to have SA1100
 # and SA1110 config symbols.
+#
+# We link the CPU support next, so that RAM timings can be tuned.
 ifeq ($(CONFIG_CPU_FREQ),y)
 obj-$(CONFIG_SA1100_ASSABET) += cpu-sa1110.o
 obj-$(CONFIG_SA1100_LART) += cpu-sa1100.o
 endif
 
+# Next, the SA1111 stuff.
+obj-$(CONFIG_SA1111) += sa1111.o dma-sa1111.o
+obj-$(CONFIG_USB_OHCI_SA1111) += sa1111-pcibuf.o pcipool.o
+
 # Specific board support
+obj-$(CONFIG_SA1100_ADSBITSY) += adsbitsy.o
 obj-$(CONFIG_SA1100_ASSABET) += assabet.o
 obj-$(CONFIG_ASSABET_NEPONSET) += neponset.o
-obj-$(CONFIG_SA1100_BITSY) += bitsy.o
 obj-$(CONFIG_SA1100_BRUTUS) += brutus.o
 obj-$(CONFIG_SA1100_CERF) += cerf.o
 obj-$(CONFIG_SA1100_EMPEG) += empeg.o
 obj-$(CONFIG_SA1100_FLEXANET) += flexanet.o
 obj-$(CONFIG_SA1100_FREEBIRD) += freebird.o
 obj-$(CONFIG_SA1100_GRAPHICSCLIENT) += graphicsclient.o
+obj-$(CONFIG_SA1100_GRAPHICSMASTER) += graphicsmaster.o
+obj-$(CONFIG_SA1100_H3600) += h3600.o
 obj-$(CONFIG_SA1100_HUW_WEBPANEL) += huw_webpanel.o
 obj-$(CONFIG_SA1100_ITSY) += itsy.o
 obj-$(CONFIG_SA1100_JORNADA720) += jornada720.o
@@ -63,6 +70,7 @@
 leds-$(CONFIG_SA1100_GRAPHICSCLIENT) += leds-graphicsclient.o
 leds-$(CONFIG_SA1100_LART) += leds-lart.o
 leds-$(CONFIG_SA1100_PFS168) += leds-pfs168.o
+leds-$(CONFIG_SA1100_GRAPHICSMASTER) += leds-graphicsmaster.o
 obj-$(CONFIG_LEDS) += $(leds-y)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/adsbitsy.c linux/arch/arm/mach-sa1100/adsbitsy.c
--- v2.4.12/linux/arch/arm/mach-sa1100/adsbitsy.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-sa1100/adsbitsy.c	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,180 @@
+/*
+ * linux/arch/arm/mach-sa1100/adsbitsy.c
+ *
+ * Author: Woojung Huh
+ *
+ * Pieces specific to the ADS Bitsy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/serial_core.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+
+#include <asm/mach/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/serial_sa1100.h>
+
+#include <asm/arch/irq.h>
+
+#include "generic.h"
+#include "sa1111.h"
+
+static int __init adsbitsy_init(void)
+{
+	int ret;
+
+	if (!machine_is_adsbitsy())
+		return -ENODEV;
+
+	/*
+	 * Ensure that the memory bus request/grant signals are setup,
+	 * and the grant is held in its inactive state
+	 */
+	sa1110_mb_disable();
+
+	/*
+	 * Reset SA1111
+	 */
+	GPCR |= GPIO_GPIO26;
+	udelay(1000);
+	GPSR |= GPIO_GPIO26;
+
+	/*
+	 * Probe for SA1111.
+	 */
+	ret = sa1111_probe();
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * We found it.  Wake the chip up.
+	 */
+	sa1111_wake();
+
+	/*
+	 * The SDRAM configuration of the SA1110 and the SA1111 must
+	 * match.  This is very important to ensure that SA1111 accesses
+	 * don't corrupt the SDRAM.  Note that this ungates the SA1111's
+	 * MBGNT signal, so we must have called sa1110_mb_disable()
+	 * beforehand.
+	 */
+	sa1111_configure_smc(1,
+			     FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
+			     FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
+
+	/*
+	 * Enable PWM control for LCD
+	 */
+	SKPCR |= SKPCR_PWMCLKEN;
+	SKPWM0 = 0x7F;				// VEE
+	SKPEN0 = 1;
+	SKPWM1 = 0x01;				// Backlight
+	SKPEN1 = 1;
+
+	/*
+	 * We only need to turn on DCLK whenever we want to use the
+	 * DMA.  It can otherwise be held firmly in the off position.
+	 */
+	SKPCR |= SKPCR_DCLKEN;
+
+	/*
+	 * Enable the SA1110 memory bus request and grant signals.
+	 */
+	sa1110_mb_enable();
+
+	set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_RISING_EDGE);
+	sa1111_init_irq(SA1100_GPIO_TO_IRQ(0));
+
+	return 0;
+}
+
+__initcall(adsbitsy_init);
+
+static void __init adsbitsy_init_irq(void)
+{
+	/* First the standard SA1100 IRQs */
+	sa1100_init_irq();
+}
+
+
+/*
+ * Initialization fixup
+ */
+
+static void __init
+fixup_adsbitsy(struct machine_desc *desc, struct param_struct *params,
+		     char **cmdline, struct meminfo *mi)
+{
+	SET_BANK( 0, 0xc0000000, 32*1024*1024 );
+	mi->nr_banks = 1;
+
+	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+	setup_ramdisk( 1, 0, 0, 8192 );
+	setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 );
+}
+
+static struct map_desc adsbitsy_io_desc[] __initdata = {
+ /* virtual     physical    length      domain     r  w  c  b */
+  { 0xe8000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
+  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1111 */
+  LAST_DESC
+};
+
+static int adsbitsy_uart_open(struct uart_port *port, struct uart_info *info)
+{
+	if (port->mapbase == _Ser1UTCR0) {
+		Ser1SDCR0 |= SDCR0_UART;
+		// Set RTS Output and High (should be done in the set_mctrl fn)
+		GPDR |= GPIO_GPIO15;
+		GPCR |= GPIO_GPIO15;
+		// Set CTS Input
+		GPDR &= ~GPIO_GPIO14;
+	} else if (port->mapbase == _Ser2UTCR0) {
+		Ser2UTCR4 = Ser2HSCR0 = 0;
+		// Set RTS Output and High (should be done in the set_mctrl fn)
+		GPDR |= GPIO_GPIO17;
+		GPCR |= GPIO_GPIO17;
+		// Set CTS Input
+		GPDR &= ~GPIO_GPIO16;
+	} else if (port->mapbase == _Ser2UTCR0) {
+		// Set RTS Output and High (should be done in the set_mctrl fn)
+		GPDR |= GPIO_GPIO19;
+		GPCR |= GPIO_GPIO19;
+		// Set CTS Input
+		GPDR &= ~GPIO_GPIO18;
+	}
+	return 0;
+}
+
+static struct sa1100_port_fns adsbitsy_port_fns __initdata = {
+	open:	adsbitsy_uart_open,
+};
+
+static void __init adsbitsy_map_io(void)
+{
+	sa1100_map_io();
+	iotable_init(adsbitsy_io_desc);
+
+	sa1110_register_uart_fns(&adsbitsy_port_fns);
+	sa1100_register_uart(0, 3);
+	sa1100_register_uart(1, 1);
+	sa1100_register_uart(2, 2);
+}
+
+MACHINE_START(ADSBITSY, "ADS Bitsy")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	FIXUP(fixup_adsbitsy)
+	MAPIO(adsbitsy_map_io)
+	INITIRQ(adsbitsy_init_irq)
+MACHINE_END
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/assabet.c linux/arch/arm/mach-sa1100/assabet.c
--- v2.4.12/linux/arch/arm/mach-sa1100/assabet.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/assabet.c	Thu Oct 11 09:04:57 2001
@@ -47,6 +47,7 @@
 		 * or BCR_clear().
 		 */
 		BCR = BCR_value = BCR_DB1111;
+		NCR_0 = 0;
 
 #ifndef CONFIG_ASSABET_NEPONSET
 		printk( "Warning: Neponset detected but full support "
@@ -101,6 +102,8 @@
 	SCR_value = scr;
 }
 
+extern void convert_to_tag_list(struct param_struct *params, int mem_init);
+
 static void __init
 fixup_assabet(struct machine_desc *desc, struct param_struct *params,
 	      char **cmdline, struct meminfo *mi)
@@ -114,6 +117,12 @@
 	if (machine_has_neponset())
 		printk("Neponset expansion board detected\n");
 
+	/*
+	 * Apparantly bootldr uses a param_struct.  Groan.
+	 */
+	if (t->hdr.tag != ATAG_CORE)
+		convert_to_tag_list(params, 1);
+
 	if (t->hdr.tag != ATAG_CORE) {
 		t->hdr.tag = ATAG_CORE;
 		t->hdr.size = tag_size(tag_core);
@@ -265,7 +274,6 @@
 	neponset_map_io();
 #endif
 
-	sa1100_register_uart(1, 2);
 	if (machine_has_neponset()) {
 		/*
 		 * When Neponset is attached, the first UART should be
@@ -295,7 +303,7 @@
 	 * excessive power drain.  --rmk
 	 */
 	GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
-	GPCR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
+	GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
 }
 
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/bitsy.c linux/arch/arm/mach-sa1100/bitsy.c
--- v2.4.12/linux/arch/arm/mach-sa1100/bitsy.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/bitsy.c	Wed Dec 31 16:00:00 1969
@@ -1,175 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/bitsy.c
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/tty.h>
-#include <linux/sched.h>
-
-#include <asm/irq.h>
-#include <asm/hardware.h>
-#include <asm/setup.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/serial_sa1100.h>
-#include <linux/serial_core.h>
-
-#include "generic.h"
-
-
-/*
- * Bitsy has extended, write-only memory-mapped GPIO's
- */
-
-static int bitsy_egpio = EGPIO_BITSY_RS232_ON;
-
-void clr_bitsy_egpio(unsigned long x)
-{
-	bitsy_egpio &= ~x;
-	BITSY_EGPIO = bitsy_egpio;
-}
-
-void set_bitsy_egpio(unsigned long x)
-{
-	bitsy_egpio |= x;
-	BITSY_EGPIO = bitsy_egpio;
-}
-
-EXPORT_SYMBOL(clr_bitsy_egpio);
-EXPORT_SYMBOL(set_bitsy_egpio);
-
-
-/*
- * low-level UART features
- */
-
-static void bitsy_uart_set_mctrl(struct uart_port *port, u_int mctrl)
-{
-	if (port->mapbase == _Ser3UTCR0) {
-		if (mctrl & TIOCM_RTS)
-			GPCR = GPIO_BITSY_COM_RTS;
-		else
-			GPSR = GPIO_BITSY_COM_RTS;
-	}
-}
-
-static int bitsy_uart_get_mctrl(struct uart_port *port)
-{
-	int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
-
-	if (port->mapbase == _Ser3UTCR0) {
-		int gplr = GPLR;
-		if (gplr & GPIO_BITSY_COM_DCD)
-			ret &= ~TIOCM_CD;
-		if (gplr & GPIO_BITSY_COM_CTS)
-			ret &= ~TIOCM_CTS;
-	}
-
-	return ret;
-}
-
-static void bitsy_dcd_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct uart_info *info = dev_id;
-	/* Note: should only call this if something has changed */
-	uart_handle_dcd_change(info, GPLR & GPIO_BITSY_COM_DCD);
-}
-
-static void bitsy_cts_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct uart_info *info = dev_id;
-	/* Note: should only call this if something has changed */
-	uart_handle_cts_change(info, GPLR & GPIO_BITSY_COM_CTS);
-}
-
-static void bitsy_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
-{
-	if (port->mapbase == _Ser2UTCR0) {
-		if (state == 0) {
-			set_bitsy_egpio(EGPIO_BITSY_IR_ON);
-		} else {
-			clr_bitsy_egpio(EGPIO_BITSY_IR_ON);
-		}
-	} else if (port->mapbase == _Ser3UTCR0) {
-		if (state == 0) {
-			set_bitsy_egpio(EGPIO_BITSY_RS232_ON);
-		} else {
-			clr_bitsy_egpio(EGPIO_BITSY_RS232_ON);
-		}
-	}
-}
-
-static int bitsy_uart_open(struct uart_port *port, struct uart_info *info)
-{
-	int ret = 0;
-
-	if (port->mapbase == _Ser2UTCR0) {
-		Ser2UTCR4 = UTCR4_HSE;
-		Ser2HSCR0 = 0;
-		Ser2HSSR0 = HSSR0_EIF | HSSR0_TUR |
-			    HSSR0_RAB | HSSR0_FRE;
-	} else if (port->mapbase == _Ser3UTCR0) {
-		GPDR &= ~(GPIO_BITSY_COM_DCD|GPIO_BITSY_COM_CTS);
-		GPDR |= GPIO_BITSY_COM_RTS;
-		set_GPIO_IRQ_edge(GPIO_BITSY_COM_DCD|GPIO_BITSY_COM_CTS,
-				  GPIO_BOTH_EDGES);
-
-		ret = request_irq(IRQ_GPIO_BITSY_COM_DCD, bitsy_dcd_intr,
-				  0, "RS232 DCD", info);
-		if (ret)
-			return ret;
-
-		ret = request_irq(IRQ_GPIO_BITSY_COM_CTS, bitsy_cts_intr,
-				  0, "RS232 CTS", info);
-		if (ret)
-			free_irq(IRQ_GPIO_BITSY_COM_DCD, info);
-	}
-	return ret;
-}
-
-static void bitsy_uart_close(struct uart_port *port, struct uart_info *info)
-{
-	if (port->mapbase == _Ser3UTCR0) {
-		free_irq(IRQ_GPIO_BITSY_COM_DCD, info);
-		free_irq(IRQ_GPIO_BITSY_COM_CTS, info);
-	}
-}
-
-static struct sa1100_port_fns bitsy_port_fns __initdata = {
-	set_mctrl:	bitsy_uart_set_mctrl,
-	get_mctrl:	bitsy_uart_get_mctrl,
-	pm:		bitsy_uart_pm,
-	open:		bitsy_uart_open,
-	close:		bitsy_uart_close,
-};
-
-static struct map_desc bitsy_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x49000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */
-  { 0xf1000000, 0x10000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 */
-  { 0xf3000000, 0x40000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 */
-  LAST_DESC
-};
-
-static void __init bitsy_map_io(void)
-{
-	sa1100_map_io();
-	iotable_init(bitsy_io_desc);
-
-	sa1100_register_uart_fns(&bitsy_port_fns);
-	sa1100_register_uart(0, 3);
-	sa1100_register_uart(1, 1); /* isn't this one driven elsewhere? */
-	sa1100_register_uart(2, 2);
-}
-
-MACHINE_START(BITSY, "Compaq iPAQ")
-	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
-	BOOT_PARAMS(0xc0000100)
-	MAPIO(bitsy_map_io)
-	INITIRQ(sa1100_init_irq)
-MACHINE_END
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/cpu-sa1110.c linux/arch/arm/mach-sa1100/cpu-sa1110.c
--- v2.4.12/linux/arch/arm/mach-sa1100/cpu-sa1110.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/cpu-sa1110.c	Thu Oct 11 09:04:57 2001
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2001 Russell King
  *
- *  $Id: cpu-sa1110.c,v 1.3 2001/08/12 15:41:53 rmk Exp $
+ *  $Id: cpu-sa1110.c,v 1.5 2001/09/10 13:25:58 rmk Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -258,14 +258,13 @@
 {
 	struct sdram_params *sdram = NULL;
 	unsigned int cur_freq = cpufreq_get(smp_processor_id());
-	int ret = -ENODEV;
 
 	if (machine_is_assabet())
 		sdram = &tc59sm716_cl3_params;
 
 	if (sdram) {
 		printk(KERN_DEBUG "SDRAM: tck: %d trcd: %d trp: %d"
-			" twr: %d refresh: %d cas_latency: %d",
+			" twr: %d refresh: %d cas_latency: %d\n",
 			sdram->tck, sdram->trcd, sdram->trp,
 			sdram->twr, sdram->refresh, sdram->cas_latency);
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/dma-sa1100.c linux/arch/arm/mach-sa1100/dma-sa1100.c
--- v2.4.12/linux/arch/arm/mach-sa1100/dma-sa1100.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/dma-sa1100.c	Thu Oct 11 09:04:57 2001
@@ -68,26 +68,30 @@
 {
 	dma_regs_t *regs = dma->regs;
 	int status;
-	int use_bufa;
 
 	status = regs->RdDCSR;
 
 	/* If both DMA buffers are started, there's nothing else we can do. */
-	if ((status & DCSR_STRTA) && (status & DCSR_STRTB)) {
+	if ((status & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) {
 		DPRINTK("start: st %#x busy\n", status);
 		return -EBUSY;
 	}
 
-	use_bufa = (((status & DCSR_BIU) && (status & DCSR_STRTB)) ||
-		    (!(status & DCSR_BIU) && !(status & DCSR_STRTA)));
-	if (use_bufa) {
-		regs->ClrDCSR = DCSR_DONEA | DCSR_STRTA;
+	if (((status & DCSR_BIU) && (status & DCSR_STRTB)) ||
+	    (!(status & DCSR_BIU) && !(status & DCSR_STRTA))) {
+		if (status & DCSR_DONEA) {
+			/* give a chance for the interrupt to be processed */
+			goto irq_pending;
+		}
 		regs->DBSA = dma_ptr;
 		regs->DBTA = size;
 		regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN;
 		DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size);
 	} else {
-		regs->ClrDCSR = DCSR_DONEB | DCSR_STRTB;
+		if (status & DCSR_DONEB) {
+			/* give a chance for the interrupt to be processed */
+			goto irq_pending;
+		}
 		regs->DBSB = dma_ptr;
 		regs->DBTB = size;
 		regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN;
@@ -95,6 +99,9 @@
 	}
 
 	return 0;
+
+irq_pending:
+	return -EAGAIN;
 }
 
 
@@ -204,11 +211,16 @@
 
 	DPRINTK("IRQ: b=%#x st=%#x\n", (int) dma->curr->id, status);
 
-	dma->regs->ClrDCSR = DCSR_ERROR | DCSR_DONEA | DCSR_DONEB;
-	if (!(status & (DCSR_DONEA | DCSR_DONEB)))
-		return;
+	if (status & (DCSR_ERROR)) {
+		printk(KERN_ERR "DMA on \"%s\" caused an error\n", dma->device_id);
+		dma->regs->ClrDCSR = DCSR_ERROR;
+	}
 
-	sa1100_dma_done (dma);
+	dma->regs->ClrDCSR = status & (DCSR_DONEA | DCSR_DONEB);
+	if (status & DCSR_DONEA)
+		sa1100_dma_done (dma);
+	if (status & DCSR_DONEB)
+		sa1100_dma_done (dma);
 }
 
 
@@ -435,7 +447,7 @@
 		dma->curr = NULL;
 	}
 	dma->spin_ref = 0;
-	dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB;
+	dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_DONEA|DCSR_DONEB;
 	process_dma(dma);
 	local_irq_restore(flags);
 	return 0;
@@ -455,7 +467,6 @@
 	if (dma->stopped) {
 		int flags;
 		save_flags_cli(flags);
-		dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_RUN|DCSR_IE;
 		dma->stopped = 0;
 		dma->spin_ref = 0;
 		process_dma(dma);
@@ -478,7 +489,7 @@
 	if (channel_is_sa1111_sac(channel))
 		sa1111_reset_sac_dma(channel);
 	else
-		dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_RUN|DCSR_IE;
+		dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_DONEA|DCSR_DONEB|DCSR_RUN|DCSR_IE;
 	buf = dma->curr;
 	if (!buf)
 		buf = dma->tail;
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/dma-sa1111.c linux/arch/arm/mach-sa1100/dma-sa1111.c
--- v2.4.12/linux/arch/arm/mach-sa1100/dma-sa1111.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/dma-sa1111.c	Thu Oct 11 09:04:57 2001
@@ -314,7 +314,7 @@
 	if(physaddr<(1<<20))
 	  	return 0;
 
-	switch(FExtr(SMCR, SMCR_DRAC)){
+	switch(FExtr(SBI_SMCR, SMCR_DRAC)){
 	case 01: /* 10 row + bank address bits, A<20> must not be set */
 	  	if(physaddr & (1<<20))
 		  	return -1;
@@ -341,7 +341,7 @@
 		break;
 	default:
 	  	printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%o\n",
-		       __FUNCTION__, FExtr(SMCR, SMCR_DRAC));
+		       __FUNCTION__, FExtr(SBI_SMCR, SMCR_DRAC));
 		return -1;
 	}
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/generic.c linux/arch/arm/mach-sa1100/generic.c
--- v2.4.12/linux/arch/arm/mach-sa1100/generic.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/generic.c	Thu Oct 11 09:04:57 2001
@@ -69,7 +69,7 @@
  * Validate the speed in khz.  If we can't generate the precise
  * frequency requested, round it down (to be on the safe side).
  */
-unsigned int cpufreq_validatespeed(unsigned int khz)
+unsigned int sa1100_validatespeed(unsigned int khz)
 {
 	int i;
 
@@ -87,7 +87,7 @@
  * above, we can match for an exact frequency.  If we don't find
  * an exact match, we will to set the lowest frequency to be safe.
  */
-void cpufreq_setspeed(unsigned int khz)
+void sa1100_setspeed(unsigned int khz)
 {
 	int i;
 
@@ -103,6 +103,7 @@
 static int __init sa1100_init_clock(void)
 {
 	cpufreq_init(get_cclk_frequency() * 100);
+	cpufreq_setfunctions(sa1100_validatespeed, sa1100_setspeed);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/graphicsclient.c linux/arch/arm/mach-sa1100/graphicsclient.c
--- v2.4.12/linux/arch/arm/mach-sa1100/graphicsclient.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/graphicsclient.c	Thu Oct 11 09:04:57 2001
@@ -131,14 +131,15 @@
 	mi->nr_banks = 2;
 
 	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
-	setup_ramdisk( 1, 0, 0, 4096 );
+	setup_ramdisk( 1, 0, 0, 8192 );
 	setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 );
 }
 
 static struct map_desc graphicsclient_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
+  { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
   { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
+  { 0xf1000000, 0x18000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CAN */
   LAST_DESC
 };
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/graphicsmaster.c linux/arch/arm/mach-sa1100/graphicsmaster.c
--- v2.4.12/linux/arch/arm/mach-sa1100/graphicsmaster.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-sa1100/graphicsmaster.c	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,225 @@
+/*
+ * linux/arch/arm/mach-sa1100/graphicsmaster.c
+ *
+ * Pieces specific to the GraphicsMaster board
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+
+#include <asm/mach/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/serial_sa1100.h>
+
+#include <asm/arch/irq.h>
+
+#include "generic.h"
+#include "sa1111.h"
+
+static int __init graphicsmaster_init(void)
+{
+	int ret;
+
+	if (!machine_is_graphicsmaster())
+		return -ENODEV;
+
+	/*
+	 * Ensure that the memory bus request/grant signals are setup,
+	 * and the grant is held in its inactive state
+	 */
+	sa1110_mb_disable();
+
+	/*
+	 * Probe for SA1111.
+	 */
+	ret = sa1111_probe();
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * We found it.  Wake the chip up.
+	 */
+	sa1111_wake();
+
+	/*
+	 * The SDRAM configuration of the SA1110 and the SA1111 must
+	 * match.  This is very important to ensure that SA1111 accesses
+	 * don't corrupt the SDRAM.  Note that this ungates the SA1111's
+	 * MBGNT signal, so we must have called sa1110_mb_disable()
+	 * beforehand.
+	 */
+	sa1111_configure_smc(1,
+			     FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
+			     FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
+
+	/*
+	 * Enable PWM control for LCD
+	 */
+	SKPCR |= SKPCR_PWMCLKEN;
+	SKPWM0 = 0x7F;				// VEE
+	SKPEN0 = 1;
+	SKPWM1 = 0x01;				// Backlight
+	SKPEN1 = 1;
+
+	/*
+	 * We only need to turn on DCLK whenever we want to use the
+	 * DMA.  It can otherwise be held firmly in the off position.
+	 */
+	SKPCR |= SKPCR_DCLKEN;
+
+	/*
+	 * Enable the SA1110 memory bus request and grant signals.
+	 */
+	sa1110_mb_enable();
+
+	sa1111_init_irq(ADS_EXT_IRQ(0));
+
+	return 0;
+}
+
+__initcall(graphicsmaster_init);
+
+/*
+ * Handlers for GraphicsMaster's external IRQ logic
+ */
+
+static void ADS_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs )
+{
+	int i;
+
+	while( (irq = ADS_INT_ST1 | (ADS_INT_ST2 << 8)) ){
+		for( i = 0; i < 16; i++ )
+			if( irq & (1<<i) ) {
+				do_IRQ( ADS_EXT_IRQ(i), regs );
+			}
+	}
+}
+
+static struct irqaction ADS_ext_irq = {
+	name:		"ADS_ext_IRQ",
+	handler:	ADS_IRQ_demux,
+	flags:		SA_INTERRUPT
+};
+
+static void ADS_mask_and_ack_irq0(unsigned int irq)
+{
+	int mask = (1 << (irq - ADS_EXT_IRQ(0)));
+	ADS_INT_EN1 &= ~mask;
+	ADS_INT_ST1 = mask;
+}
+
+static void ADS_mask_irq0(unsigned int irq)
+{
+	ADS_INT_ST1 = (1 << (irq - ADS_EXT_IRQ(0)));
+}
+
+static void ADS_unmask_irq0(unsigned int irq)
+{
+	ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0)));
+}
+
+static void ADS_mask_and_ack_irq1(unsigned int irq)
+{
+	int mask = (1 << (irq - ADS_EXT_IRQ(8)));
+	ADS_INT_EN2 &= ~mask;
+	ADS_INT_ST2 = mask;
+}
+
+static void ADS_mask_irq1(unsigned int irq)
+{
+	ADS_INT_ST2 = (1 << (irq - ADS_EXT_IRQ(8)));
+}
+
+static void ADS_unmask_irq1(unsigned int irq)
+{
+	ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8)));
+}
+
+static void __init graphicsmaster_init_irq(void)
+{
+	int irq;
+
+	/* First the standard SA1100 IRQs */
+	sa1100_init_irq();
+
+	/* disable all IRQs */
+	ADS_INT_EN1 = 0;
+	ADS_INT_EN2 = 0;
+	/* clear all IRQs */
+	ADS_INT_ST1 = 0xff;
+	ADS_INT_ST2 = 0xff;
+
+	for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) {
+		irq_desc[irq].valid	= 1;
+		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].mask_ack	= ADS_mask_and_ack_irq0;
+		irq_desc[irq].mask	= ADS_mask_irq0;
+		irq_desc[irq].unmask	= ADS_unmask_irq0;
+	}
+	for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) {
+		irq_desc[irq].valid	= 1;
+		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].mask_ack	= ADS_mask_and_ack_irq1;
+		irq_desc[irq].mask	= ADS_mask_irq1;
+		irq_desc[irq].unmask	= ADS_unmask_irq1;
+	}
+	GPDR &= ~GPIO_GPIO0;
+	set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE);
+	setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq );
+}
+
+
+/*
+ * Initialization fixup
+ */
+
+static void __init
+fixup_graphicsmaster(struct machine_desc *desc, struct param_struct *params,
+		     char **cmdline, struct meminfo *mi)
+{
+	SET_BANK( 0, 0xc0000000, 16*1024*1024 );
+	mi->nr_banks = 1;
+	SET_BANK( 1, 0xc8000000, 16*1024*1024 );
+	mi->nr_banks = 2;
+
+	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+	setup_ramdisk( 1, 0, 0, 8192 );
+	setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 );
+}
+
+static struct map_desc graphicsmaster_io_desc[] __initdata = {
+ /* virtual     physical    length      domain     r  w  c  b */
+  { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
+  { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* CPLD */
+  { 0xf1000000, 0x40000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* CAN */
+  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+  LAST_DESC
+};
+
+static void __init graphicsmaster_map_io(void)
+{
+	sa1100_map_io();
+	iotable_init(graphicsmaster_io_desc);
+
+	sa1100_register_uart(0, 3);
+	sa1100_register_uart(1, 1);
+	sa1100_register_uart(2, 2);
+}
+
+MACHINE_START(GRAPHICSMASTER, "ADS GraphicsMaster")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	FIXUP(fixup_graphicsmaster)
+	MAPIO(graphicsmaster_map_io)
+	INITIRQ(graphicsmaster_init_irq)
+MACHINE_END
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/h3600.c linux/arch/arm/mach-sa1100/h3600.c
--- v2.4.12/linux/arch/arm/mach-sa1100/h3600.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-sa1100/h3600.c	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,189 @@
+/*
+ * linux/arch/arm/mach-sa1100/h3600.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/setup.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/serial_sa1100.h>
+#include <linux/serial_core.h>
+
+#include "generic.h"
+
+
+/*
+ * Bitsy has extended, write-only memory-mapped GPIO's
+ */
+
+static int h3600_egpio = EGPIO_H3600_RS232_ON;
+
+void clr_h3600_egpio(unsigned long x)
+{
+	h3600_egpio &= ~x;
+	H3600_EGPIO = h3600_egpio;
+}
+
+void set_h3600_egpio(unsigned long x)
+{
+	h3600_egpio |= x;
+	H3600_EGPIO = h3600_egpio;
+}
+
+EXPORT_SYMBOL(clr_h3600_egpio);
+EXPORT_SYMBOL(set_h3600_egpio);
+
+
+/*
+ * Low-level UART features.
+ *
+ * Note that RTS, CTS and DCD are all active low.
+ */
+
+static void h3600_uart_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+	if (port->mapbase == _Ser3UTCR0) {
+		if (mctrl & TIOCM_RTS)
+			GPCR = GPIO_H3600_COM_RTS;
+		else
+			GPSR = GPIO_H3600_COM_RTS;
+	}
+}
+
+static int h3600_uart_get_mctrl(struct uart_port *port)
+{
+	int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
+
+	if (port->mapbase == _Ser3UTCR0) {
+		int gplr = GPLR;
+		if (gplr & GPIO_H3600_COM_DCD)
+			ret &= ~TIOCM_CD;
+		if (gplr & GPIO_H3600_COM_CTS)
+			ret &= ~TIOCM_CTS;
+	}
+
+	return ret;
+}
+
+static void h3600_dcd_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_info *info = dev_id;
+	/* Note: should only call this if something has changed */
+	uart_handle_dcd_change(info, !(GPLR & GPIO_H3600_COM_DCD));
+}
+
+static void h3600_cts_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_info *info = dev_id;
+	/* Note: should only call this if something has changed */
+	uart_handle_cts_change(info, !(GPLR & GPIO_H3600_COM_CTS));
+}
+
+static void h3600_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
+{
+	if (port->mapbase == _Ser2UTCR0) {
+		if (state == 0) {
+			set_h3600_egpio(EGPIO_H3600_IR_ON);
+		} else {
+			clr_h3600_egpio(EGPIO_H3600_IR_ON);
+		}
+	} else if (port->mapbase == _Ser3UTCR0) {
+		if (state == 0) {
+			set_h3600_egpio(EGPIO_H3600_RS232_ON);
+		} else {
+			clr_h3600_egpio(EGPIO_H3600_RS232_ON);
+		}
+	}
+}
+
+static int h3600_uart_open(struct uart_port *port, struct uart_info *info)
+{
+	int ret = 0;
+
+	if (port->mapbase == _Ser2UTCR0) {
+		Ser2UTCR4 = UTCR4_HSE;
+		Ser2HSCR0 = 0;
+		Ser2HSSR0 = HSSR0_EIF | HSSR0_TUR |
+			    HSSR0_RAB | HSSR0_FRE;
+	} else if (port->mapbase == _Ser3UTCR0) {
+		GPDR &= ~(GPIO_H3600_COM_DCD|GPIO_H3600_COM_CTS);
+		GPDR |= GPIO_H3600_COM_RTS;
+		set_GPIO_IRQ_edge(GPIO_H3600_COM_DCD|GPIO_H3600_COM_CTS,
+				  GPIO_BOTH_EDGES);
+
+		ret = request_irq(IRQ_GPIO_H3600_COM_DCD, h3600_dcd_intr,
+				  0, "RS232 DCD", info);
+		if (ret)
+			return ret;
+
+		ret = request_irq(IRQ_GPIO_H3600_COM_CTS, h3600_cts_intr,
+				  0, "RS232 CTS", info);
+		if (ret)
+			free_irq(IRQ_GPIO_H3600_COM_DCD, info);
+	}
+	return ret;
+}
+
+static void h3600_uart_close(struct uart_port *port, struct uart_info *info)
+{
+	if (port->mapbase == _Ser3UTCR0) {
+		free_irq(IRQ_GPIO_H3600_COM_DCD, info);
+		free_irq(IRQ_GPIO_H3600_COM_CTS, info);
+	}
+}
+
+static struct sa1100_port_fns h3600_port_fns __initdata = {
+	set_mctrl:	h3600_uart_set_mctrl,
+	get_mctrl:	h3600_uart_get_mctrl,
+	pm:		h3600_uart_pm,
+	open:		h3600_uart_open,
+	close:		h3600_uart_close,
+};
+
+static struct map_desc h3600_io_desc[] __initdata = {
+ /* virtual     physical    length      domain     r  w  c  b */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf0000000, 0x49000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */
+  { 0xf1000000, 0x10000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 */
+  { 0xf3000000, 0x40000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 */
+  LAST_DESC
+};
+
+static void __init h3600_map_io(void)
+{
+	sa1100_map_io();
+	iotable_init(h3600_io_desc);
+
+	sa1100_register_uart_fns(&h3600_port_fns);
+	sa1100_register_uart(0, 3);
+	sa1100_register_uart(1, 1); /* isn't this one driven elsewhere? */
+	sa1100_register_uart(2, 2);
+
+	/*
+	 * Default GPIO settings.
+	 */
+	GPCR = 0x0fffffff;
+	GPDR = 0x0401f3fc;
+
+	/*
+	 * Ensure those pins are outputs and driving low.
+	 */
+	PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+	PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+}
+
+MACHINE_START(H3600, "Compaq iPAQ")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100)
+	MAPIO(h3600_map_io)
+	INITIRQ(sa1100_init_irq)
+MACHINE_END
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/jornada720.c linux/arch/arm/mach-sa1100/jornada720.c
--- v2.4.12/linux/arch/arm/mach-sa1100/jornada720.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/jornada720.c	Thu Oct 11 09:04:57 2001
@@ -46,7 +46,8 @@
 	PPDR |= PPC_LDD3 | PPC_LDD4;
 
 	/* initialize extra IRQs */
-	sa1111_init_irq(1);	/* chained on GPIO 1 */
+	set_GPIO_IRQ_edge(GPIO_GPIO(1), GPIO_RISING_EDGE);
+	sa1111_init_irq(SA1100_GPIO_TO_IRQ(1));	/* chained on GPIO 1 */
 
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/leds-graphicsmaster.c linux/arch/arm/mach-sa1100/leds-graphicsmaster.c
--- v2.4.12/linux/arch/arm/mach-sa1100/leds-graphicsmaster.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-sa1100/leds-graphicsmaster.c	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,104 @@
+/*
+ *  linux/arch/arm/mach-sa1100/leds-graphicsmaster.c
+ *
+ * GraphicsClient Plus LEDs support
+ * Woojung Huh, Feb 13, 2001
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+#include "leds.h"
+
+
+#define LED_STATE_ENABLED	1
+#define LED_STATE_CLAIMED	2
+
+static unsigned int led_state;
+static unsigned int hw_led_state;
+
+#define LED_TIMER       ADS_LED0  /* green heartbeat */
+#define LED_USER        ADS_LED1  /* amber, boots to on */
+#define LED_IDLE        ADS_LED2  /* red has the idle led, if any */
+
+#define LED_MASK	(ADS_LED0|ADS_LED1|ADS_LED2)
+
+void graphicsmaster_leds_event(led_event_t evt)
+{
+	unsigned long flags;
+
+	save_flags_cli(flags);
+
+	switch (evt) {
+	case led_start:
+		hw_led_state = 0;        /* gc leds are positive logic */
+		led_state = LED_STATE_ENABLED;
+		break;
+
+	case led_stop:
+		led_state &= ~LED_STATE_ENABLED;
+		break;
+
+	case led_claim:
+		led_state |= LED_STATE_CLAIMED;
+		hw_led_state = LED_MASK;
+		break;
+
+	case led_release:
+		led_state &= ~LED_STATE_CLAIMED;
+		hw_led_state = LED_MASK;
+		break;
+
+#ifdef CONFIG_LEDS_TIMER
+	case led_timer:
+		if (!(led_state & LED_STATE_CLAIMED))
+			hw_led_state ^= LED_TIMER;
+		break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+	case led_idle_start:
+		if (!(led_state & LED_STATE_CLAIMED))
+			hw_led_state &= ~LED_IDLE;
+		break;
+
+	case led_idle_end:
+		if (!(led_state & LED_STATE_CLAIMED))
+			hw_led_state |= LED_IDLE;
+		break;
+#endif
+
+	case led_green_on:
+		break;
+
+	case led_green_off:
+		break;
+
+	case led_amber_on:
+		hw_led_state |= LED_USER;
+		break;
+
+	case led_amber_off:
+		hw_led_state &= ~LED_USER;
+		break;
+
+	case led_red_on:
+		break;
+
+	case led_red_off:
+		break;
+
+	default:
+		break;
+	}
+
+	if  (led_state & LED_STATE_ENABLED) {
+		GPSR = hw_led_state;
+		GPCR = hw_led_state ^ LED_MASK;
+	}
+
+	restore_flags(flags);
+}
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/leds.c linux/arch/arm/mach-sa1100/leds.c
--- v2.4.12/linux/arch/arm/mach-sa1100/leds.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/leds.c	Thu Oct 11 09:04:57 2001
@@ -30,6 +30,8 @@
 		leds_event = lart_leds_event;
 	if (machine_is_pfs168())
 		leds_event = pfs168_leds_event;
+	if (machine_is_graphicsmaster())
+		leds_event = graphicsmaster_leds_event;
 
 	leds_event(led_start);
 	return 0;
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/leds.h linux/arch/arm/mach-sa1100/leds.h
--- v2.4.12/linux/arch/arm/mach-sa1100/leds.h	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/leds.h	Thu Oct 11 09:04:57 2001
@@ -5,4 +5,4 @@
 extern void graphicsclient_leds_event(led_event_t evt);
 extern void lart_leds_event(led_event_t evt);
 extern void pfs168_leds_event(led_event_t evt);
-
+extern void graphicsmaster_leds_event(led_event_t evt);
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/neponset.c linux/arch/arm/mach-sa1100/neponset.c
--- v2.4.12/linux/arch/arm/mach-sa1100/neponset.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/neponset.c	Thu Oct 11 09:04:57 2001
@@ -74,36 +74,73 @@
 
 static int __init neponset_init(void)
 {
-	/* only on assabet */
+	int ret;
+
+	/*
+	 * The Neponset is only present on the Assabet machine type.
+	 */
 	if (!machine_is_assabet())
-		return 0;
+		return -ENODEV;
+
+	/*
+	 * Ensure that the memory bus request/grant signals are setup,
+	 * and the grant is held in its inactive state, whether or not
+	 * we actually have a Neponset attached.
+	 */
+	sa1110_mb_disable();
+
+	if (!machine_has_neponset()) {
+		printk(KERN_DEBUG "Neponset expansion board not present\n");
+		return -ENODEV;
+	}
+
+	if (WHOAMI != 0x11) {
+		printk(KERN_WARNING "Neponset board detected, but "
+			"wrong ID: %02x\n", WHOAMI);
+		return -ENODEV;
+	}
+
+	/*
+	 * Neponset has SA1111 connected to CS4.  We know that after
+	 * reset the chip will be configured for variable latency IO.
+	 */
+	/* FIXME: setup MSC2 */
+
+	/*
+	 * Probe for a SA1111.
+	 */
+	ret = sa1111_probe();
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * We found it.  Wake the chip up.
+	 */
+	sa1111_wake();
+
+	/*
+	 * The SDRAM configuration of the SA1110 and the SA1111 must
+	 * match.  This is very important to ensure that SA1111 accesses
+	 * don't corrupt the SDRAM.  Note that this ungates the SA1111's
+	 * MBGNT signal, so we must have called sa1110_mb_disable()
+	 * beforehand.
+	 */
+	sa1111_configure_smc(1,
+			     FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
+			     FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
+
+	/*
+	 * We only need to turn on DCLK whenever we want to use the
+	 * DMA.  It can otherwise be held firmly in the off position.
+	 */
+	SKPCR |= SKPCR_DCLKEN;
 
-	if (machine_has_neponset()) {
-		LEDS = WHOAMI;
+	/*
+	 * Enable the SA1110 memory bus request and grant signals.
+	 */
+	sa1110_mb_enable();
 
-		if (sa1111_init() < 0)
-			return -EINVAL;
-		/*
-		 * Assabet is populated by default with two Samsung
-		 * KM416S8030T-G8
-		 * 128Mb SDRAMs, which are organized as 12-bit (row addr) x
-		 * 9-bit
-		 * (column addr), according to the data sheet. Apparently, the
-		 * bank selects factor into the row address, as Angel sets up
-		 * the
-		 * SA-1110 to use 14x9 addresses. The SDRAM datasheet specifies
-		 * that when running at 100-125MHz, the CAS latency for -8
-		 * parts
-		 * is 3 cycles, which is consistent with Angel.
-		 */
-		SMCR = (SMCR_DTIM | SMCR_MBGE |
-			FInsrt(FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), SMCR_DRAC) |
-			((FExtr(MDCNFG, MDCNFG_SA1110_TDL0)==3) ? SMCR_CLAT : 0));
-		SKPCR |= SKPCR_DCLKEN;
-
-		neponset_init_irq();
-	} else
-		printk("Neponset expansion board not present\n");
+	neponset_init_irq();
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/pangolin.c linux/arch/arm/mach-sa1100/pangolin.c
--- v2.4.12/linux/arch/arm/mach-sa1100/pangolin.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/pangolin.c	Thu Oct 11 09:04:57 2001
@@ -20,7 +20,7 @@
 fixup_pangolin(struct machine_desc *desc, struct param_struct *params,
 	       char **cmdline, struct meminfo *mi)
 {
-	SET_BANK( 0, 0xc0000000, 64*1024*1024 );
+	SET_BANK( 0, 0xc0000000, 128*1024*1024 );
 	mi->nr_banks = 1;
 
 	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/pfs168.c linux/arch/arm/mach-sa1100/pfs168.c
--- v2.4.12/linux/arch/arm/mach-sa1100/pfs168.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/pfs168.c	Thu Oct 11 09:04:57 2001
@@ -20,14 +20,53 @@
 
 static int __init pfs168_init(void)
 {
-	if (sa1111_init() < 0)
-		return -EINVAL;
-	SMCR = (SMCR_DTIM | SMCR_MBGE |
-		FInsrt(FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), SMCR_DRAC) |
-		((FExtr(MDCNFG, MDCNFG_SA1110_TDL0)==3) ? SMCR_CLAT : 0));
+	int ret;
+
+	if (!machine_is_pfs168())
+		return -ENODEV;
+
+	/*
+	 * Ensure that the memory bus request/grant signals are setup,
+	 * and the grant is held in its inactive state
+	 */
+	sa1110_mb_disable();
+
+	/*
+	 * Probe for SA1111.
+	 */
+	ret = sa1111_probe();
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * We found it.  Wake the chip up.
+	 */
+	sa1111_wake();
+
+	/*
+	 * The SDRAM configuration of the SA1110 and the SA1111 must
+	 * match.  This is very important to ensure that SA1111 accesses
+	 * don't corrupt the SDRAM.  Note that this ungates the SA1111's
+	 * MBGNT signal, so we must have called sa1110_mb_disable()
+	 * beforehand.
+	 */
+	sa1111_configure_smc(1,
+			     FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
+			     FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
+
+	/*
+	 * We only need to turn on DCLK whenever we want to use the
+	 * DMA.  It can otherwise be held firmly in the off position.
+	 */
 	SKPCR |= SKPCR_DCLKEN;
 
-	sa1111_init_irq(25);	/* SA1111 IRQ on GPIO 25 */
+	/*
+	 * Enable the SA1110 memory bus request and grant signals.
+	 */
+	sa1110_mb_enable();
+
+	set_GPIO_IRQ_edge(GPIO_GPIO(25), GPIO_RISING_EDGE);
+	sa1111_init_irq(SA1100_GPIO_TO_IRQ(25));	/* SA1111 IRQ on GPIO 25 */
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/sa1111-pcibuf.c linux/arch/arm/mach-sa1100/sa1111-pcibuf.c
--- v2.4.12/linux/arch/arm/mach-sa1100/sa1111-pcibuf.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/sa1111-pcibuf.c	Thu Oct 11 09:04:57 2001
@@ -13,7 +13,6 @@
  *
  *  06/13/2001 - created.
  */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -64,13 +63,6 @@
 	return 0;
 }
 
-static void
-free_safe_buffers(void)
-{
-	pci_pool_destroy(small_buffer_cache);
-	pci_pool_destroy(large_buffer_cache);
-}
-
 /* allocate a 'safe' buffer and keep track of it */
 static char *
 alloc_safe_buffer(char *unsafe, int size, dma_addr_t *pbus)
@@ -183,17 +175,11 @@
  * we assume calls to map_single are symmetric with calls to unmap_single...
  */
 dma_addr_t
-pci_map_single(struct pci_dev *hwdev, void *virtptr,
+sa1111_map_single(struct pci_dev *hwdev, void *virtptr,
 	       size_t size, int direction)
 {
 	dma_addr_t busptr;
 
-	/* hack; usb-ohci.c never sends hwdev==NULL, all others do */
-	if (hwdev == NULL) {
-		consistent_sync(virtptr, size, direction);
-		return virt_to_bus(virtptr);
-	}
-
 	mapped_alloc_size += size;
 
 	if (0) printk("pci_map_single(hwdev=%p,ptr=%p,size=%d,dir=%x) "
@@ -235,7 +221,7 @@
  * (basically return things back to the way they should be)
  */
 void
-pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+sa1111_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
 		 size_t size, int direction)
 {
 	char *safe, *unsafe;
@@ -267,13 +253,21 @@
 	}
 }
 
-EXPORT_SYMBOL(pci_map_single);
-EXPORT_SYMBOL(pci_unmap_single);
+EXPORT_SYMBOL(sa1111_map_single);
+EXPORT_SYMBOL(sa1111_unmap_single);
 
-static void __init sa1111_init_safe_buffers(void)
+static int __init sa1111_init_safe_buffers(void)
 {
 	printk("Initializing SA1111 buffer pool for DMA workaround\n");
 	init_safe_buffers(NULL);
+	return 0;
+}
+
+static void free_safe_buffers(void)
+{
+	pci_pool_destroy(small_buffer_cache);
+	pci_pool_destroy(large_buffer_cache);
 }
 
-__initcall(sa1111_init_safe_buffers);
+module_init(sa1111_init_safe_buffers);
+module_exit(free_safe_buffers);
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/sa1111.c linux/arch/arm/mach-sa1100/sa1111.c
--- v2.4.12/linux/arch/arm/mach-sa1100/sa1111.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/sa1111.c	Thu Oct 11 09:04:57 2001
@@ -15,7 +15,6 @@
  * All initialization functions provided here are intended to be called
  * from machine specific code with proper arguments when required.
  */
-
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -23,8 +22,6 @@
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/mm.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -33,64 +30,6 @@
 
 #include "sa1111.h"
 
-static int sa1111_ohci_hcd_init(void);
-
-/*
- * SA1111 initialization
- */
-
-int __init sa1111_init(void)
-{
-	unsigned long id = SKID;
-
-	if((id & SKID_ID_MASK) == SKID_SA1111_ID)
-		printk( KERN_INFO "SA-1111 Microprocessor Companion Chip: "
-			"silicon revision %lx, metal revision %lx\n",
-			(id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
-	else {
-		printk(KERN_ERR "Could not detect SA-1111!\n");
-		return -EINVAL;
-	}
-
-	/*
-	 * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
-	 * (SA-1110 Developer's Manual, section 9.1.2.1)
-	 */
-	GAFR |= GPIO_32_768kHz;
-	GPDR |= GPIO_32_768kHz;
-	TUCR = TUCR_3_6864MHz;
-
-	/* Now, set up the PLL and RCLK in the SA-1111: */
-	SKCR = SKCR_PLL_BYPASS | SKCR_RDYEN | SKCR_OE_EN;
-	udelay(100);
-	SKCR = SKCR_PLL_BYPASS | SKCR_RCLKEN | SKCR_RDYEN | SKCR_OE_EN;
-
-	/*
-	 * SA-1111 Register Access Bus should now be available. Clocks for
-	 * any other SA-1111 functional blocks must be enabled separately
-	 * using the SKPCR.
-	 */
-
-	/*
-	 * If the system is going to use the SA-1111 DMA engines, set up
-	 * the memory bus request/grant pins. Also configure the shared
-	 * memory controller on the SA-1111 (SA-1111 Developer's Manual,
-	 * section 3.2.3) and power up the DMA bus clock:
-	 */
-	GAFR |= (GPIO_MBGNT | GPIO_MBREQ);
-	GPDR |= GPIO_MBGNT;
-	GPDR &= ~GPIO_MBREQ;
-	TUCR |= TUCR_MR;
-
-#ifdef CONFIG_USB_OHCI
-	/* setup up sa1111 usb host controller h/w */
-	sa1111_ohci_hcd_init();
-#endif
-
-	return 0;
-}
-
-
 /*
  * SA1111  Interrupt support
  */
@@ -159,7 +98,7 @@
 	INTEN1 |= 1 << ((irq - SA1111_IRQ(32)));
 }
 
-void __init sa1111_init_irq(int gpio_nr)
+void __init sa1111_init_irq(int irq_nr)
 {
 	int irq;
 
@@ -181,144 +120,146 @@
 
 	for (irq = SA1111_IRQ(0); irq <= SA1111_IRQ(26); irq++) {
 		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].probe_ok	= 0;
 		irq_desc[irq].mask_ack	= sa1111_mask_and_ack_lowirq;
 		irq_desc[irq].mask	= sa1111_mask_lowirq;
 		irq_desc[irq].unmask	= sa1111_unmask_lowirq;
 	}
 	for (irq = SA1111_IRQ(32); irq <= SA1111_IRQ(54); irq++) {
 		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].probe_ok	= 0;
 		irq_desc[irq].mask_ack	= sa1111_mask_and_ack_highirq;
 		irq_desc[irq].mask	= sa1111_mask_highirq;
 		irq_desc[irq].unmask	= sa1111_unmask_highirq;
 	}
 
-	/* Not every machines has the SA1111 interrupt routed to a GPIO */
-	if (gpio_nr >= 0) {
-		set_GPIO_IRQ_edge (GPIO_GPIO(gpio_nr), GPIO_RISING_EDGE);
-		setup_arm_irq (SA1100_GPIO_TO_IRQ(gpio_nr), &sa1111_irq);
-	}
+	/* Register SA1111 interrupt */
+	if (irq_nr >= 0)
+		setup_arm_irq(irq_nr, &sa1111_irq);
 }
 
-/* ----------------- */
-
-#ifdef CONFIG_USB_OHCI
-
-#if defined(CONFIG_SA1100_XP860) || defined(CONFIG_ASSABET_NEPONSET) || defined(CONFIG_SA1100_PFS168)
-#define PwrSensePolLow  1
-#define PwrCtrlPolLow   1
-#else
-#define PwrSensePolLow  0
-#define PwrCtrlPolLow   0
-#endif
-
 /*
- * The SA-1111 errata says that the DMA hardware needs to be exercised
- * before the clocks are turned on to work properly.  This code does
- * a tiny dma transfer to prime to hardware.
+ * Probe for a SA1111 chip.
  */
-static void __init sa1111_dma_setup(void)
+
+int __init sa1111_probe(void)
 {
-	dma_addr_t vbuf;
-	void * pbuf;
+	unsigned long id = SBI_SKID;
+	int ret = -ENODEV;
 
-	/* DMA init & setup */
+	if ((id & SKID_ID_MASK) == SKID_SA1111_ID) {
+		printk(KERN_INFO "SA-1111 Microprocessor Companion Chip: "
+			"silicon revision %lx, metal revision %lx\n",
+			(id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
+		ret = 0;
+	} else {
+		printk(KERN_DEBUG "SA-1111 not detected: ID = %08lx\n", id);
+	}
 
-	/* WARNING: The SA-1111 L3 function is used as part of this
-	 * SA-1111 DMA errata workaround.
-	 *
-	 * N.B., When the L3 function is enabled, it uses GPIO_B<4:5>
-	 * and takes precedence over the PS/2 mouse and GPIO_B
-	 * functions. Refer to "Intel StrongARM SA-1111 Microprocessor
-	 * Companion Chip, Sect 10.2" for details.  So this "fix" may
-	 * "break" support of either PS/2 mouse or GPIO_B if
-	 * precautions are not taken to avoid collisions in
-	 * configuration and use of these pins. AFAIK, no precautions
-	 * are taken at this time. So it is likely that the action
-	 * taken here may cause problems in PS/2 mouse and/or GPIO_B
-	 * pin use elsewhere.
-	 *
-	 * But wait, there's more... What we're doing here is
-	 * obviously altogether a bad idea. We're indiscrimanately bit
-	 * flipping config for a few different functions here which
-	 * are "owned" by other drivers. This needs to be handled
-	 * better than it is being done here at this time.  */
-
-	/* prime the dma engine with a tiny dma */
-	SKPCR |= SKPCR_I2SCLKEN;
-	SKAUD |= SKPCR_L3CLKEN | SKPCR_SCLKEN;
-
-	SACR0 |= 0x00003305;
-	SACR1 = 0x00000000;
-
-	/* we need memory below 1mb */
-	pbuf = consistent_alloc(GFP_KERNEL | GFP_DMA, 4, &vbuf);
+	return ret;
+}
 
-	SADTSA = (unsigned long)pbuf;
-	SADTCA = 4;
+/*
+ * Bring the SA1111 out of reset.  This requires a set procedure:
+ *  1. nRESET asserted (by hardware)
+ *  2. CLK turned on from SA1110
+ *  3. nRESET deasserted
+ *  4. VCO turned on, PLL_BYPASS turned off
+ *  5. Wait lock time, then assert RCLKEn
+ *  7. PCR set to allow clocking of individual functions
+ *
+ * Until we've done this, the only registers we can access are:
+ *   SBI_SKCR
+ *   SBI_SMCR
+ *   SBI_SKID
+ */
+void sa1111_wake(void)
+{
+	/*
+	 * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
+	 * (SA-1110 Developer's Manual, section 9.1.2.1)
+	 */
+	GAFR |= GPIO_32_768kHz;
+	GPDR |= GPIO_32_768kHz;
+	TUCR = TUCR_3_6864MHz;
 
-	SADTCS |= 0x00000011;
-	SKPCR |= SKPCR_DCLKEN;
+	/*
+	 * Turn VCO on, and disable PLL Bypass.
+	 */
+	SBI_SKCR &= ~SKCR_VCO_OFF;
+	SBI_SKCR |= SKCR_PLL_BYPASS | SKCR_OE_EN;
 
-	/* wait */
+	/*
+	 * Wait lock time.  SA1111 manual _doesn't_
+	 * specify a figure for this!  We choose 100us.
+	 */
 	udelay(100);
 
-	SACR0 &= ~(0x00000002);
-	SACR0 &= ~(0x00000001);
-
-	/* */
-	SACR0 |= 0x00000004;
-	SACR0 &= ~(0x00000004);
+	/*
+	 * Enable RCLK.  We also ensure that RDYEN is set.
+	 */
+	SBI_SKCR |= SKCR_RCLKEN | SKCR_RDYEN;
 
-	SKAUD &= ~(SKPCR_L3CLKEN | SKPCR_SCLKEN);
+	/*
+	 * Wait 14 RCLK cycles for the chip to finish coming out
+	 * of reset. (RCLK=24MHz).  This is 590ns.
+	 */
+	udelay(1);
 
-	SKPCR &= ~SKPCR_I2SCLKEN;
+	/*
+	 * Ensure all clocks are initially off.
+	 */
+	SKPCR = 0;
+}
 
-	consistent_free(pbuf, 4, vbuf);
+void sa1111_doze(void)
+{
+	if (SKPCR & SKPCR_UCLKEN) {
+		printk("SA1111 doze mode refused\n");
+		return;
+	}
+	SBI_SKCR &= ~SKCR_RCLKEN;
 }
 
-#ifdef CONFIG_USB_OHCI
 /*
- * reset the SA-1111 usb controller and turn on it's clocks
+ * Configure the SA1111 shared memory controller.
  */
-static int __init sa1111_ohci_hcd_init(void)
+void sa1111_configure_smc(int sdram, unsigned int drac, unsigned int cas_latency)
 {
-	volatile unsigned long *Reset = (void *)SA1111_p2v(_SA1111(0x051c));
-	volatile unsigned long *Status = (void *)SA1111_p2v(_SA1111(0x0518));
-
-	/* turn on clocks */
-	SKPCR |= SKPCR_UCLKEN;
-	udelay(100);
-
-	/* force a reset */
-	*Reset = 0x01;
-	*Reset |= 0x02;
-	udelay(100);
+	unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC);
 
-	*Reset = 0;
+	if (cas_latency == 3)
+		smcr |= SMCR_CLAT;
 
-	/* take out of reset */
-	/* set power sense and control lines (this from the diags code) */
-        *Reset = ( PwrSensePolLow << 6 )
-               | ( PwrCtrlPolLow << 7 );
-
-	*Status = 0;
+	SBI_SMCR = smcr;
+}
 
-	udelay(10);
+/*
+ * Disable the memory bus request/grant signals on the SA1110 to
+ * ensure that we don't receive spurious memory requests.  We set
+ * the MBGNT signal false to ensure the SA1111 doesn't own the
+ * SDRAM bus.
+ */
+void __init sa1110_mb_disable(void)
+{
+	PGSR &= ~GPIO_MBGNT;
+	GPCR = GPIO_MBGNT;
+	GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT;
 
-	/* compensate for dma bug */
-	sa1111_dma_setup();
+	GAFR &= ~(GPIO_MBGNT | GPIO_MBREQ);
 
-	return 0;
 }
 
-void sa1111_ohci_hcd_cleanup(void)
+/*
+ * If the system is going to use the SA-1111 DMA engines, set up
+ * the memory bus request/grant pins.
+ */
+void __init sa1110_mb_enable(void)
 {
-	/* turn the USB clock off */
-	SKPCR &= ~SKPCR_UCLKEN;
-}
-#endif
-
+	PGSR &= ~GPIO_MBGNT;
+	GPCR = GPIO_MBGNT;
+	GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT;
 
-#endif /* CONFIG_USB_OHCI */
+	GAFR |= (GPIO_MBGNT | GPIO_MBREQ);
+	TUCR |= TUCR_MR;
+}
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/sa1111.h linux/arch/arm/mach-sa1100/sa1111.h
--- v2.4.12/linux/arch/arm/mach-sa1100/sa1111.h	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/sa1111.h	Thu Oct 11 09:04:57 2001
@@ -2,7 +2,33 @@
  * linux/arch/arm/mach-sa1100/sa1111.h
  */
 
-extern int __init sa1111_init(void);
-extern void __init sa1111_init_irq(int gpio_nr);
+/*
+ * These two don't really belong in here.
+ */
+extern void sa1110_mb_enable(void);
+extern void sa1110_mb_disable(void);
+
+/*
+ * Probe for a SA1111 chip.
+ */
+extern int sa1111_probe(void);
+
+/*
+ * Wake up a SA1111 chip.
+ */
+extern void sa1111_wake(void);
+
+/*
+ * Doze the SA1111 chip.
+ */
+extern void sa1111_doze(void);
+
+/*
+ * Configure the SA1111 shared memory controller.
+ */
+extern void sa1111_configure_smc(int sdram, unsigned int drac, unsigned int cas_latency);
+
+
+extern void sa1111_init_irq(int irq_nr);
 extern void sa1111_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs );
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/xp860.c linux/arch/arm/mach-sa1100/xp860.c
--- v2.4.12/linux/arch/arm/mach-sa1100/xp860.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mach-sa1100/xp860.c	Thu Oct 11 09:04:57 2001
@@ -28,10 +28,27 @@
 	while(1);
 }
 
+/*
+ * Note: I replaced the sa1111_init() without the full SA1111 initialisation
+ * because this machine doesn't appear to use the DMA features.  If this is
+ * wrong, please look at neponset.c to fix it properly.
+ */
 static int __init xp860_init(void)
 {
 	pm_power_off = xp860_power_off;
-	sa1111_init();
+
+	/*
+	 * Probe for SA1111.
+	 */
+	ret = sa1111_probe();
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * We found it.  Wake the chip up.
+	 */
+	sa1111_wake();
+
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mm/extable.c linux/arch/arm/mm/extable.c
--- v2.4.12/linux/arch/arm/mm/extable.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/extable.c	Thu Oct 11 09:04:57 2001
@@ -30,6 +30,8 @@
         return 0;
 }
 
+extern spinlock_t modlist_lock;
+
 unsigned long
 search_exception_table(unsigned long addr)
 {
@@ -38,18 +40,24 @@
 #ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
-	if (ret) return ret;
 #else
 	/* The kernel is the last "module" -- no need to treat it special.  */
+	unsigned long flags;
 	struct module *mp;
+
+	ret = 0;
+	spin_lock_irqsave(&modlist_lock, flags);
 	for (mp = module_list; mp != NULL; mp = mp->next) {
-		if (mp->ex_table_start == NULL)
+		if (mp->ex_table_start == NULL ||
+		    !(mp->flags & (MOD_RUNNING | MOD_INITIALIZING)))
 			continue;
 		ret = search_one_table(mp->ex_table_start,
 				       mp->ex_table_end - 1, addr);
-		if (ret) return ret;
+		if (ret)
+			break;
 	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
 #endif
 
-	return 0;
+	return ret;
 }
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c
--- v2.4.12/linux/arch/arm/mm/fault-armv.c	Sun Sep 23 11:40:55 2001
+++ linux/arch/arm/mm/fault-armv.c	Thu Oct 11 09:04:57 2001
@@ -599,10 +599,10 @@
 	if (!inf->fn(addr, error_code, regs))
 		return;
 bad:
-	force_sig(inf->sig, current);
 	printk(KERN_ALERT "Unhandled fault: %s (%X) at 0x%08lx\n",
 		inf->name, fsr, addr);
 	show_pte(current->mm, addr);
+	force_sig(inf->sig, current);
 	die_if_kernel("Oops", regs, 0);
 	return;
 
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c
--- v2.4.12/linux/arch/arm/mm/fault-common.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mm/fault-common.c	Thu Oct 11 09:04:57 2001
@@ -301,6 +301,10 @@
 	tsk->thread.error_code = error_code;
 	tsk->thread.trap_no = 14;
 	force_sig(SIGBUS, tsk);
+#ifdef CONFIG_DEBUG_USER
+	printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n",
+		current->comm, addr, instruction_pointer(regs));
+#endif
 
 	/* Kernel mode? Handle exceptions or die */
 	if (user_mode(regs))
@@ -339,13 +343,10 @@
 	if (addr < TASK_SIZE)
 		return do_page_fault(addr, error_code, regs);
 
-	tsk = current;
-	mm  = tsk->active_mm;
-
 	offset = __pgd_offset(addr);
 
+	pgd = cpu_get_pgd() + offset;
 	pgd_k = init_mm.pgd + offset;
-	pgd   = mm->pgd + offset;
 
 	if (pgd_none(*pgd_k))
 		goto bad_area;
@@ -365,6 +366,9 @@
 	return 0;
 
 bad_area:
+	tsk = current;
+	mm  = tsk->active_mm;
+
 	do_bad_area(tsk, mm, addr, error_code, regs);
 	return 0;
 }
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c
--- v2.4.12/linux/arch/arm/mm/init.c	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mm/init.c	Thu Oct 11 09:04:57 2001
@@ -96,10 +96,22 @@
 }
 #endif
 
+/* This is currently broken
+ * PG_skip is used on sparc/sparc64 architectures to "skip" certain
+ * parts of the address space.
+ *
+ * #define PG_skip	10
+ * #define PageSkip(page) (machine_is_riscpc() && test_bit(PG_skip, &(page)->flags))
+ *			if (PageSkip(page)) {
+ *				page = page->next_hash;
+ *				if (page == NULL)
+ *					break;
+ *			}
+ */
 void show_mem(void)
 {
 	int free = 0, total = 0, reserved = 0;
-	int shared = 0, cached = 0, node;
+	int shared = 0, cached = 0, slab = 0, node;
 
 	printk("Mem-info:\n");
 	show_free_areas();
@@ -112,23 +124,13 @@
 		end  = page + NODE_DATA(node)->node_size;
 
 		do {
-/* This is currently broken
- * PG_skip is used on sparc/sparc64 architectures to "skip" certain
- * parts of the address space.
- *
- * #define PG_skip	10
- * #define PageSkip(page) (machine_is_riscpc() && test_bit(PG_skip, &(page)->flags))
- *			if (PageSkip(page)) {
- *				page = page->next_hash;
- *				if (page == NULL)
- *					break;
- *			}
- */
 			total++;
 			if (PageReserved(page))
 				reserved++;
 			else if (PageSwapCache(page))
 				cached++;
+			else if (PageSlab(page))
+				slab++;
 			else if (!page_count(page))
 				free++;
 			else
@@ -140,6 +142,7 @@
 	printk("%d pages of RAM\n", total);
 	printk("%d free pages\n", free);
 	printk("%d reserved pages\n", reserved);
+	printk("%d slab pages\n", slab);
 	printk("%d pages shared\n", shared);
 	printk("%d pages swap cached\n", cached);
 #ifndef CONFIG_NO_PGT_CACHE
@@ -375,6 +378,8 @@
 	 */
 	if (machine_is_archimedes() || machine_is_a5k())
 		reserve_bootmem_node(pgdat, 0x02000000, 0x00080000);
+	if (machine_is_edb7211())
+		reserve_bootmem_node(pgdat, 0xc0000000, 0x00020000);
 	if (machine_is_p720t())
 		reserve_bootmem_node(pgdat, PHYS_OFFSET, 0x00014000);
 #ifdef CONFIG_SA1111
@@ -471,6 +476,7 @@
 
 	if (map_pg != bootmap_pfn + bootmap_pages)
 		BUG();
+
 }
 
 /*
@@ -528,6 +534,12 @@
 				(bdata->node_boot_start >> PAGE_SHIFT);
 
 		/*
+		 * If this zone has zero size, skip it.
+		 */
+		if (!zone_size[0])
+			continue;
+
+		/*
 		 * For each bank in this node, calculate the size of the
 		 * holes.  holes = node_size - sum(bank_sizes_in_node)
 		 */
@@ -598,8 +610,12 @@
 		create_memmap_holes(&meminfo);
 
 	/* this will put all unused low memory onto the freelists */
-	for (node = 0; node < numnodes; node++)
-		totalram_pages += free_all_bootmem_node(NODE_DATA(node));
+	for (node = 0; node < numnodes; node++) {
+		pg_data_t *pgdat = NODE_DATA(node);
+
+		if (pgdat->node_size != 0)
+			totalram_pages += free_all_bootmem_node(pgdat);
+	}
 
 #ifdef CONFIG_SA1111
 	/* now that our DMA memory is actually so designated, we can free it */
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mm/mm-ftvpci.c linux/arch/arm/mm/mm-ftvpci.c
--- v2.4.12/linux/arch/arm/mm/mm-ftvpci.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mm/mm-ftvpci.c	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,32 @@
+/*
+ *  linux/arch/arm/mm/mm-nexuspci.c
+ *   from linux/arch/arm/mm/mm-ebsa110.c
+ *
+ *  Copyright (C) 1998-1999 Phil Blundell
+ *  Copyright (C) 1998-1999 Russell King
+ *
+ *  Extra MM routines for the FTV/PCI architecture
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+ 
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/io.h>
+
+#include <asm/mach/map.h>
+
+static struct map_desc nexuspci_io_desc[] __initdata = {
+ 	{ INTCONT_BASE,	INTCONT_START,	0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ PLX_BASE,	PLX_START,	0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ PCIO_BASE,	PLX_IO_START,	0x00100000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ DUART_BASE,	DUART_START,	0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+	{ STATUS_BASE,	STATUS_START,	0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+	LAST_DESC
+};
+
+void __init nexuspci_map_io(void)
+{
+	iotable_init(nexuspci_io_desc);
+}
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mm/mm-nexuspci.c linux/arch/arm/mm/mm-nexuspci.c
--- v2.4.12/linux/arch/arm/mm/mm-nexuspci.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/mm-nexuspci.c	Wed Dec 31 16:00:00 1969
@@ -1,32 +0,0 @@
-/*
- *  linux/arch/arm/mm/mm-nexuspci.c
- *   from linux/arch/arm/mm/mm-ebsa110.c
- *
- *  Copyright (C) 1998-1999 Phil Blundell
- *  Copyright (C) 1998-1999 Russell King
- *
- *  Extra MM routines for the FTV/PCI architecture
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/init.h>
- 
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/io.h>
-
-#include <asm/mach/map.h>
-
-static struct map_desc nexuspci_io_desc[] __initdata = {
- 	{ INTCONT_BASE,	INTCONT_START,	0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
- 	{ PLX_BASE,	PLX_START,	0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
- 	{ PCIO_BASE,	PLX_IO_START,	0x00100000, DOMAIN_IO, 0, 1, 0, 0 },
- 	{ DUART_BASE,	DUART_START,	0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
-	{ STATUS_BASE,	STATUS_START,	0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
-	LAST_DESC
-};
-
-void __init nexuspci_map_io(void)
-{
-	iotable_init(nexuspci_io_desc);
-}
diff -u --recursive --new-file v2.4.12/linux/arch/arm/mm/proc-arm720.S linux/arch/arm/mm/proc-arm720.S
--- v2.4.12/linux/arch/arm/mm/proc-arm720.S	Mon Aug 27 12:41:38 2001
+++ linux/arch/arm/mm/proc-arm720.S	Thu Oct 11 09:04:57 2001
@@ -108,6 +108,7 @@
  * Function: arm720_data_abort ()
  *
  * Params  : r0 = address of aborted instruction
+ *         : r3 = saved SPSR
  *
  * Purpose : obtain information about current aborted instruction
  *
@@ -143,6 +144,8 @@
 		mov	pc, lr
 
 ENTRY(cpu_arm720_data_abort)
+		tst	r3, #T_BIT
+		bne	.data_thumb_abort
 		ldr	r4, [r0]			@ read instruction causing problem
 		tst	r4, r4, lsr #21			@ C = bit 20
 		sbc	r1, r1, r1			@ r1 = C - 1
@@ -169,7 +172,7 @@
 Ldata_unknown:	@ Part of jumptable
 		mov	r0, r2
 		mov	r1, r4
-		mov	r2, r3
+		mov	r2, sp
 		bl	baddataabort
 		b	ret_from_exception
 
@@ -255,6 +258,77 @@
 		addeq	r7, r0, r2
 		b	Ldata_saver7
 
+.data_thumb_abort:
+		ldrh	r4, [r0]			@ read instruction
+		tst	r4, r4, lsr #12			@ C = bit 11
+		sbc	r1, r1, r1			@ r1 = C - 1
+		and	r2, r4, #15 << 12
+		add	pc, pc, r2, lsr #10		@ lookup in table
+		nop
+
+/* 0 */		b	Ldata_unknown
+/* 1 */		b	Ldata_unknown
+/* 2 */		b	Ldata_unknown
+/* 3 */		b	Ldata_unknown
+/* 4 */		b	Ldata_unknown
+/* 5 */		b	.data_thumb_reg
+/* 6 */		b	Ldata_simple
+/* 7 */		b	Ldata_simple
+/* 8 */		b	Ldata_simple
+/* 9 */		b	Ldata_simple
+/* A */		b	Ldata_unknown
+/* B */		b	.data_thumb_pushpop
+/* C */		b	.data_thumb_ldmstm
+/* D */		b	Ldata_unknown
+/* E */		b	Ldata_unknown
+/* F */		b	Ldata_unknown
+
+.data_thumb_reg:
+		tst	r4, #1 << 9
+		beq	Ldata_simple
+		tst	r4, #1 << 10		@ If 'S' (signed) bit is set
+		movne	r1, #0			@ it must be a load instr
+		b	Ldata_simple
+
+.data_thumb_pushpop:
+		tst	r4, #1 << 10
+		beq	Ldata_unknown
+		mov	r7, #0x11
+		and	r0, r4, r7
+		and	r2, r4, r7, lsl #1
+		add	r0, r0, r2, lsr #1
+		and	r2, r4, r7, lsl #2
+		add	r0, r0, r2, lsr #2
+		and	r2, r4, r7, lsl #3
+		add	r0, r0, r2, lsr #3
+		add	r0, r0, r0, lsr #4
+		and	r2, r4, #0x0100			@ catch 'R' bit for push/pop
+		add	r0, r0, r2, lsr #8
+		and	r0, r0, #15			@ number of regs to transfer
+		ldr	r7, [sp, #13 << 2]
+		tst	r4, #1 << 11
+		addne	r7, r7, r0, lsl #2		@ increment SP if PUSH
+		subeq	r7, r7, r0, lsr #2		@ decrement SP if POP
+		str	r7, [sp, #13 << 2]
+		b	Ldata_simple
+
+.data_thumb_ldmstm:
+		mov	r7, #0x11
+		and	r0, r4, r7
+		and	r2, r4, r7, lsl #1
+		add	r0, r0, r2, lsr #1
+		and	r2, r4, r7, lsl #2
+		add	r0, r0, r2, lsr #2
+		and	r2, r4, r7, lsl #3
+		add	r0, r0, r2, lsr #3
+		add	r0, r0, r0, lsr #4
+		and	r0, r0, #15			@ number of regs to transfer
+		and	r5, r4, #7 << 8
+		ldr	r7, [sp, r5, lsr #6]
+		sub	r7, r7, r0, lsr #2		@ always decrement
+		str	r7, [sp, r5, lsr #6]
+		b	Ldata_simple
+
 /*
  * Function: arm720_check_bugs (void)
  *	   : arm720_proc_init (void)
@@ -437,7 +511,7 @@
 		.align
 
 /*
- * See /include/asm-arm for a definition of this structure.
+ * See linux/include/asm-arm/procinfo.h for a definition of this structure.
  */
 	
 		.section ".proc.info", #alloc, #execinstr
@@ -450,7 +524,7 @@
 		b	__arm720_setup				@ cpu_flush
 		.long	cpu_arch_name				@ arch_name
 		.long	cpu_elf_name				@ elf_name
-		.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT	@ elf_hwcap
+		.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_26BIT	@ elf_hwcap
 		.long	cpu_arm720_info				@ info
 		.long	arm720_processor_functions
 		.size	__arm720_proc_info, . - __arm720_proc_info
diff -u --recursive --new-file v2.4.12/linux/arch/arm/tools/Makefile linux/arch/arm/tools/Makefile
--- v2.4.12/linux/arch/arm/tools/Makefile	Sun Sep 23 11:40:55 2001
+++ linux/arch/arm/tools/Makefile	Thu Oct 11 09:04:57 2001
@@ -12,13 +12,15 @@
 
 # Generate the constants.h header file using the compiler.  We get
 # the compiler to spit out assembly code, and then mundge it into
-# what we want.
+# what we want.  We do this in several stages so make picks up on
+# any errors that occur along the way.
 
 $(TOPDIR)/include/asm-arm/constants.h: constants-hdr getconstants.c
-	$(CC) $(CFLAGS) -S -o - getconstants.c | \
-	 sed 's/^\(#define .* \)[#$$]\(.*\)/\1\2/;/^#define/!d' | \
-	 cat constants-hdr - > $@.tmp
-	cmp $@.tmp $@ >/dev/null 2>&1 || mv $@.tmp $@; $(RM) $@.tmp
+	$(CC) $(CFLAGS) -S -o - getconstants.c > $@.tmp.1
+	sed 's/^\(#define .* \)[#$$]\(.*\)/\1\2/;/^#define/!d' $@.tmp.1 > $@.tmp.2
+	cat constants-hdr $@.tmp.2 > $@.tmp
+	cmp $@.tmp $@ >/dev/null 2>&1 || mv $@.tmp $@
+	$(RM) $@.tmp*
 
 # Build our dependencies, and then generate the constants and
 # mach-types header files.  If we do it now, mkdep will pick
diff -u --recursive --new-file v2.4.12/linux/arch/arm/tools/getconstants.c linux/arch/arm/tools/getconstants.c
--- v2.4.12/linux/arch/arm/tools/getconstants.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/arm/tools/getconstants.c	Thu Oct 11 09:04:57 2001
@@ -14,8 +14,14 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
-#ifndef __APCS_32__
-#error APCS-32 required
+/*
+ * Make sure that the compiler and target are compatible.
+ */
+#if defined(__APCS_32__) && defined(CONFIG_CPU_26)
+#error Your compiler targets APCS-32 but this kernel requires APCS-26
+#endif
+#if defined(__APCS_26__) && defined(CONFIG_CPU_32)
+#error Your compiler targets APCS-26 but this kernel requires APCS-32
 #endif
 
 #define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n)
diff -u --recursive --new-file v2.4.12/linux/arch/arm/tools/mach-types linux/arch/arm/tools/mach-types
--- v2.4.12/linux/arch/arm/tools/mach-types	Sun Sep 23 11:40:55 2001
+++ linux/arch/arm/tools/mach-types	Thu Oct 11 09:04:57 2001
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Thu Aug 23 12:38:13 2001
+# Last update: Fri Oct 5 18:40:53 2001
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -71,7 +71,7 @@
 jupiter			SA1100_JUPITER		JUPITER			59
 psionw			ARCH_PSIONW		PSIONW			60
 aln			SA1100_ALN		ALN			61
-camelot			ARCH_CAMELOT		CAMELOT			62
+epxa10db		ARCH_CAMELOT		CAMELOT			62
 gds2200			SA1100_GDS2200		GDS2200			63
 psion_series7		SA1100_PSION_SERIES7	PSION_SERIES7		64
 xfile			SA1100_XFILE		XFILE			65
@@ -114,7 +114,7 @@
 gator			SA1100_GATOR		GATOR			103
 granite			ARCH_GRANITE		GRANITE			104
 consus			SA1100_CONSUS		CONSUS			105
-aaec2000_aaed20		ARCH_AAEC2000_AAED2000	AAEC2000_AAED2000	106
+agilent_aaed2000	ARCH_AAEC2000_AAED2000	AAEC2000_AAED2000	106
 cdb89712		ARCH_CDB89712		CDB89712		107
 graphicsmaster		SA1100_GRAPHICSMASTER	GRAPHICSMASTER		108
 adsbitsy		SA1100_ADSBITSY		ADSBITSY		109
@@ -122,3 +122,12 @@
 plce			ARCH_PLCE		PLCE			111
 pt_system3		SA1100_PT_SYSTEM3	PT_SYSTEM3		112
 medalb			ARCH_MEDALB		MEDALB			113
+eagle			ARCH_EAGLE		EAGLE			114
+dsc21			ARCH_DSC21		DSC21			115
+dsc24			ARCH_DSC24		DSC24			116
+ti5472			ARCH_TI5472		TI5472			117
+autcpu12		ARCH_AUTCPU12		AUTCPU12		118
+uengine			ARCH_UENGINE		UENGINE			119
+bluestem		SA1100_BLUESTEM		BLUESTEM		120
+xingu8			ARCH_XINGU8		XINGU8			121
+bushstb			ARCH_BUSHSTB		BUSHSTB			122
diff -u --recursive --new-file v2.4.12/linux/arch/cris/config.in linux/arch/cris/config.in
--- v2.4.12/linux/arch/cris/config.in	Tue Oct  9 17:06:51 2001
+++ linux/arch/cris/config.in	Mon Oct 15 13:42:14 2001
@@ -180,7 +180,7 @@
 
 source drivers/ieee1394/Config.in
 
-source drivers/i2o/Config.in
+source drivers/message/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
   mainmenu_option next_comment
diff -u --recursive --new-file v2.4.12/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.4.12/linux/arch/i386/config.in	Tue Oct  9 17:06:51 2001
+++ linux/arch/i386/config.in	Sat Oct 20 19:17:19 2001
@@ -315,7 +315,7 @@
 
 source drivers/ieee1394/Config.in
 
-source drivers/i2o/Config.in
+source drivers/message/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
    mainmenu_option next_comment
@@ -398,6 +398,7 @@
 
 bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
 if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Debug high memory support' CONFIG_DEBUG_HIGHMEM
    bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
    bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
    bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
diff -u --recursive --new-file v2.4.12/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.4.12/linux/arch/i386/defconfig	Tue Oct  9 17:06:51 2001
+++ linux/arch/i386/defconfig	Sat Oct 20 19:17:37 2001
@@ -411,6 +411,7 @@
 # CONFIG_NE2K_PCI is not set
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
 # CONFIG_8139TOO is not set
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
@@ -579,6 +580,7 @@
 # PCMCIA character devices
 #
 # CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_MWAVE is not set
 
 #
 # Multimedia devices
@@ -703,6 +705,8 @@
 #
 # CONFIG_USB_DEVICEFS is not set
 # CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_LONG_TIMEOUT is not set
+# CONFIG_USB_LARGE_CONFIG is not set
 
 #
 # USB Controllers
@@ -717,9 +721,13 @@
 # CONFIG_USB_BLUETOOTH is not set
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
 # CONFIG_USB_STORAGE_ISD200 is not set
 # CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 
@@ -743,20 +751,18 @@
 #
 # USB Multimedia devices
 #
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_PWC is not set
-# CONFIG_USB_SE401 is not set
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_DABUSB is not set
+
+#
+#   Video4Linux support is needed for USB Multimedia device support
+#
 
 #
 # USB Network adaptors
 #
 # CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_KAWETH is not set
 # CONFIG_USB_USBNET is not set
 
 #
@@ -768,9 +774,33 @@
 # USB Serial Converter support
 #
 # CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
 
 #
-# USB misc drivers
+# USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
 
diff -u --recursive --new-file v2.4.12/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- v2.4.12/linux/arch/i386/kernel/apm.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/i386/kernel/apm.c	Fri Oct 19 08:32:28 2001
@@ -38,6 +38,7 @@
  * Jan 2000, Version 1.12
  * Feb 2000, Version 1.13
  * Nov 2000, Version 1.14
+ * Oct 2001, Version 1.15
  *
  * History:
  *    0.6b: first version in official kernel, Linux 1.3.46
@@ -157,7 +158,14 @@
  *         Work around byte swap bug in one of the Vaio's BIOS's
  *         (Marc Boucher <marc@mbsi.ca>).
  *         Exposed the disable flag to dmi so that we can handle known
- *	   broken APM (Alan Cox <alan@redhat.com>).
+ *         broken APM (Alan Cox <alan@redhat.com>).
+ *   1.14ac: If the BIOS says "I slowed the CPU down" then don't spin
+ *         calling it - instead idle. (Alan Cox <alan@redhat.com>)
+ *         If an APM idle fails log it and idle sensibly
+ *   1.15: Don't queue events to clients who open the device O_WRONLY.
+ *         Don't expect replies from clients who open the device O_RDONLY.
+ *         (Idea from Thomas Hood <jdthood at yahoo.co.uk>)
+ *         Minor waitqueue cleanups.(John Fremlin <chief@bandits.org>)
  *
  * APM 1.1 Reference:
  *
@@ -222,8 +230,14 @@
  * Various options can be changed at boot time as follows:
  * (We allow underscores for compatibility with the modules code)
  *	apm=on/off			enable/disable APM
+ *	    [no-]allow[-_]ints		allow interrupts during BIOS calls
+ *	    [no-]broken[-_]psr		BIOS has a broken GetPowerStatus call
+ *	    [no-]realmode[-_]power[-_]off	switch to real mode before
+ *	    					powering off
  *	    [no-]debug			log some debugging messages
  *	    [no-]power[-_]off		power off on shutdown
+ *	    bounce[-_]interval=<n>	number of ticks to ignore suspend
+ *	    				bounces
  */
 
 /* KNOWN PROBLEM MACHINES:
@@ -308,6 +322,8 @@
 	int		magic;
 	struct apm_user *	next;
 	int		suser: 1;
+	int		writer: 1;
+	int		reader: 1;
 	int		suspend_wait: 1;
 	int		suspend_result;
 	int		suspends_pending;
@@ -372,8 +388,12 @@
 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
 static struct apm_user *	user_list;
 
-static char			driver_version[] = "1.14";	/* no spaces */
+static char			driver_version[] = "1.15";	/* no spaces */
 
+/*
+ *	APM event names taken from the APM 1.2 specification. These are
+ *	the message codes that the BIOS uses to tell us about events
+ */
 static char *	apm_event_name[] = {
 	"system standby",
 	"system suspend",
@@ -396,6 +416,11 @@
 	char *	msg;
 } lookup_t;
 
+/*
+ *	The BIOS returns a set of standard error codes in AX when the
+ *	carry flag is set.
+ */
+ 
 static const lookup_t error_table[] = {
 /* N/A	{ APM_SUCCESS,		"Operation succeeded" }, */
 	{ APM_DISABLED,		"Power management disabled" },
@@ -419,7 +444,7 @@
 
 /*
  * These are the actual BIOS calls.  Depending on APM_ZERO_SEGS and
- * CONFIG_APM_ALLOW_INTS, we are being really paranoid here!  Not only
+ * apm_info.allow_ints, we are being really paranoid here!  Not only
  * are interrupts disabled, but all the segment registers (except SS)
  * are saved and zeroed this means that if the BIOS tries to reference
  * any data without explicitly loading the segment registers, the kernel
@@ -465,6 +490,26 @@
 #	define APM_DO_RESTORE_SEGS
 #endif
 
+/**
+ *	apm_bios_call	-	Make an APM BIOS 32bit call
+ *	@func: APM function to execute
+ *	@ebx_in: EBX register for call entry
+ *	@ecx_in: ECX register for call entry
+ *	@eax: EAX register return
+ *	@ebx: EBX register return
+ *	@ecx: ECX register return
+ *	@edx: EDX register return
+ *	@esi: ESI register return
+ *
+ *	Make an APM call using the 32bit protected mode interface. The
+ *	caller is responsible for knowing if APM BIOS is configured and
+ *	enabled. This call can disable interrupts for a long period of
+ *	time on some laptops.  The return value is in AH and the carry
+ *	flag is loaded into AL.  If there is an error, then the error
+ *	code is returned in AH (bits 8-15 of eax) and this function
+ *	returns non-zero.
+ */
+ 
 static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
 	u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi)
 {
@@ -495,8 +540,18 @@
 	return *eax & 0xff;
 }
 
-/*
- * This version only returns one value (usually an error code)
+/**
+ *	apm_bios_call_simple	-	make a simple APM BIOS 32bit call
+ *	@func: APM function to invoke
+ *	@ebx_in: EBX register value for BIOS call
+ *	@ecx_in: ECX register value for BIOS call
+ *	@eax: EAX register on return from the BIOS call
+ *
+ *	Make a BIOS call that does only returns one value, or just status.
+ *	If there is an error, then the error code is returned in AH
+ *	(bits 8-15 of eax) and this function returns non-zero. This is
+ *	used for simpler BIOS operations. This call may hold interrupts
+ *	off for a long time on some laptops.
  */
 
 static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
@@ -533,6 +588,22 @@
 	return error;
 }
 
+/**
+ *	apm_driver_version	-	APM driver version
+ *	@val:	loaded with the APM version on return
+ *
+ *	Retrieve the APM version supported by the BIOS. This is only
+ *	supported for APM 1.1 or higher. An error indicates APM 1.0 is
+ *	probably present.
+ *
+ *	On entry val should point to a value indicating the APM driver
+ *	version with the high byte being the major and the low byte the
+ *	minor number both in BCD
+ *
+ *	On return it will hold the BIOS revision supported in the
+ *	same format.
+ */
+
 static int __init apm_driver_version(u_short *val)
 {
 	u32	eax;
@@ -543,6 +614,23 @@
 	return APM_SUCCESS;
 }
 
+/**
+ *	apm_get_event	-	get an APM event from the BIOS
+ *	@event: pointer to the event
+ *	@info: point to the event information
+ *
+ *	The APM BIOS provides a polled information for event
+ *	reporting. The BIOS expects to be polled at least every second
+ *	when events are pending. When a message is found the caller should
+ *	poll until no more messages are present.  However, this causes
+ *	problems on some laptops where a suspend event notification is
+ *	not cleared until it is acknowledged.
+ *
+ *	Additional information is returned in the info pointer, providing
+ *	that APM 1.2 is in use. If no messges are pending the value 0x80
+ *	is returned (No power management events pending).
+ */
+ 
 static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
 {
 	u32	eax;
@@ -561,6 +649,20 @@
 	return APM_SUCCESS;
 }
 
+/**
+ *	set_power_state	-	set the power management state
+ *	@what: which items to transition
+ *	@state: state to transition to
+ *
+ *	Request an APM change of state for one or more system devices. The
+ *	processor state must be transitioned last of all. what holds the
+ *	class of device in the upper byte and the device number (0xFF for
+ *	all) for the object to be transitioned.
+ *
+ *	The state holds the state to transition to, which may in fact
+ *	be an acceptance of a BIOS requested state change.
+ */
+ 
 static int set_power_state(u_short what, u_short state)
 {
 	u32	eax;
@@ -570,27 +672,59 @@
 	return APM_SUCCESS;
 }
 
+/**
+ *	apm_set_power_state - set system wide power state
+ *	@state: which state to enter
+ *
+ *	Transition the entire system into a new APM power state.
+ */
+ 
 static int apm_set_power_state(u_short state)
 {
 	return set_power_state(APM_DEVICE_ALL, state);
 }
 
 #ifdef CONFIG_APM_CPU_IDLE
+
+/**
+ *	apm_do_idle	-	perform power saving
+ *
+ *	This function notifies the BIOS that the processor is (in the view
+ *	of the OS) idle. It returns -1 in the event that the BIOS refuses
+ *	to handle the idle request. On a success the function returns 1
+ *	if the BIOS did clock slowing or 0 otherwise.
+ */
+ 
 static int apm_do_idle(void)
 {
-	u32	dummy;
+	u32	eax;
+	int	slowed;
 
-	if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &dummy))
-		return 0;
+	if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax)) {
+		static unsigned long t;
 
+		if (time_after(jiffies, t + 10 * HZ)) {
+			printk(KERN_DEBUG "apm_do_idle failed (%d)\n",
+					(eax >> 8) & 0xff);
+			t = jiffies;
+		}
+		return -1;
+	}
+	slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0;
 #ifdef ALWAYS_CALL_BUSY
 	clock_slowed = 1;
 #else
-	clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0;
+	clock_slowed = slowed;
 #endif
-	return 1;
+	return slowed;
 }
 
+/**
+ *	apm_do_busy	-	inform the BIOS the CPU is busy
+ *
+ *	Request that the BIOS brings the CPU back to full performance. 
+ */
+ 
 static void apm_do_busy(void)
 {
 	u32	dummy;
@@ -615,9 +749,16 @@
 /* This should wake up kapmd and ask it to slow the CPU */
 #define powermanagement_idle()  do { } while (0)
 
-/*
- * This is the idle thing.
+/**
+ * apm_cpu_idle		-	cpu idling for APM capable Linux
+ *
+ * This is the idling function the kernel executes when APM is available. It 
+ * tries to save processor time directly by using hlt instructions. A
+ * separate apm thread tries to do the BIOS power management.
+ *
+ * N.B. This is curently not used for kernels 2.4.x.
  */
+
 static void apm_cpu_idle(void)
 {
 	unsigned int start_idle;
@@ -660,6 +801,16 @@
 }
 #endif
 
+/**
+ *	apm_power_off	-	ask the BIOS to power off
+ *
+ *	Handle the power off sequence. This is the one piece of code we
+ *	will execute even on SMP machines. In order to deal with BIOS
+ *	bugs we support real mode APM BIOS power off calls. We also make
+ *	the SMP call on CPU0 as some systems will only honour this call
+ *	on their first cpu.
+ */
+ 
 static void apm_power_off(void)
 {
 	unsigned char	po_bios_call[] = {
@@ -689,15 +840,23 @@
 		(void) apm_set_power_state(APM_STATE_OFF);
 }
 
-/*
- * Magic sysrq key and handler for the power off function
+/**
+ * handle_poweroff	-	sysrq callback for power down
+ * @key: key pressed (unused)
+ * @pt_regs: register state (unused)
+ * @kbd: keyboard state (unused)
+ * @tty: tty involved (unused)
+ *
+ * When the user hits Sys-Rq o to power down the machine this is the
+ * callback we use.
  */
 
 void handle_poweroff (int key, struct pt_regs *pt_regs,
-		                        struct kbd_struct *kbd, struct tty_struct *tty) {
-	        apm_power_off();
+		struct kbd_struct *kbd, struct tty_struct *tty) {
+        apm_power_off();
 }
-struct sysrq_key_op sysrq_poweroff_op = {
+
+struct sysrq_key_op	sysrq_poweroff_op = {
 	handler:        handle_poweroff,
 	help_msg:       "Off",
 	action_msg:     "Power Off\n"
@@ -705,6 +864,14 @@
 
 
 #ifdef CONFIG_APM_DO_ENABLE
+
+/**
+ *	apm_enable_power_management - enable BIOS APM power management
+ *	@enable: enable yes/no
+ *
+ *	Enable or disable the APM BIOS power services. 
+ */
+ 
 static int apm_enable_power_management(int enable)
 {
 	u32	eax;
@@ -722,6 +889,20 @@
 }
 #endif
 
+/**
+ *	apm_get_power_status	-	get current power state
+ *	@status: returned status
+ *	@bat: battery info
+ *	@life: estimated life
+ *
+ *	Obtain the current power status from the APM BIOS. We return a
+ *	status which gives the rough battery status, and current power
+ *	source. The bat value returned give an estimate as a percentage
+ *	of life and a status value for the battery. The estimated life
+ *	if reported is a lifetime in secodnds/minutes at current powwer
+ *	consumption.
+ */
+ 
 static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
 {
 	u32	eax;
@@ -774,6 +955,15 @@
 }
 #endif
 
+/**
+ *	apm_engage_power_management	-	enable PM on a device
+ *	@device: identity of device
+ *	@enable: on/off
+ *
+ *	Activate or deactive power management on either a specific device
+ *	or the entire system (%APM_DEVICE_ALL).
+ */
+ 
 static int apm_engage_power_management(u_short device, int enable)
 {
 	u32	eax;
@@ -792,6 +982,15 @@
 	return APM_SUCCESS;
 }
 
+/**
+ *	apm_error	-	display an APM error
+ *	@str: information string
+ *	@err: APM BIOS return code
+ *
+ *	Write a meaningful log entry to the kernel log in the event of
+ *	an APM error.
+ */
+ 
 static void apm_error(char *str, int err)
 {
 	int	i;
@@ -806,6 +1005,17 @@
 }
 
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
+
+/**
+ *	apm_console_blank	-	blank the display
+ *	@blank: on/off
+ *
+ *	Attempt to blank the console, firstly by blanking just video device
+ *	zero, and if that fails (some BIOSes dont support it) then it blanks
+ *	all video devices. Typically the BIOS will do laptop backlight and
+ *	monitor powerdown for us.
+ */
+ 
 static int apm_console_blank(int blank)
 {
 	int	error;
@@ -846,7 +1056,7 @@
 	if (user_list == NULL)
 		return;
 	for (as = user_list; as != NULL; as = as->next) {
-		if (as == sender)
+		if ((as == sender) || (!as->reader))
 			continue;
 		as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
 		if (as->event_head == as->event_tail) {
@@ -857,7 +1067,7 @@
 			as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
 		}
 		as->events[as->event_head] = event;
-		if (!as->suser)
+		if ((!as->suser) || (!as->writer))
 			continue;
 		switch (event) {
 		case APM_SYS_SUSPEND:
@@ -932,7 +1142,9 @@
 		/* map all suspends to ACPI D3 */
 		if (pm_send_all(PM_SUSPEND, (void *)3)) {
 			if (event == APM_CRITICAL_SUSPEND) {
-				printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armageddon\n" );
+				printk(KERN_CRIT
+					"apm: Critical suspend was vetoed, "
+					"expect armageddon\n" );
 				return 0;
 			}
 			if (apm_info.connection_version > 0x100)
@@ -1109,7 +1321,8 @@
 	int		err;
 
 	if ((standbys_pending > 0) || (suspends_pending > 0)) {
-		if ((apm_info.connection_version > 0x100) && (pending_count-- <= 0)) {
+		if ((apm_info.connection_version > 0x100) &&
+				(pending_count-- <= 0)) {
 			pending_count = 4;
 			if (debug)
 				printk(KERN_DEBUG "apm: setting state busy\n");
@@ -1140,7 +1353,7 @@
 	set_current_state(TASK_INTERRUPTIBLE);
 	for (;;) {
 		/* Nothing to do, just sleep for the timeout */
-		timeout = 2*timeout;
+		timeout = 2 * timeout;
 		if (timeout > APM_CHECK_TIMEOUT)
 			timeout = APM_CHECK_TIMEOUT;
 		schedule_timeout(timeout);
@@ -1156,10 +1369,21 @@
 #ifdef CONFIG_APM_CPU_IDLE
 		if (!system_idle())
 			continue;
-		if (apm_do_idle()) {
+		
+		/*
+		 *	If we can idle...
+		 */
+		if (apm_do_idle() != -1) {
 			unsigned long start = jiffies;
 			while ((!exit_kapmd) && system_idle()) {
-				apm_do_idle();
+				if (apm_do_idle()) {
+					set_current_state(TASK_INTERRUPTIBLE);
+					/* APM needs us to snooze .. either
+					   the BIOS call failed (-1) or it
+					   slowed the clock (1). We sleep
+					   until it talks to us again */
+					schedule_timeout(1);
+				}
 				if ((jiffies - start) > APM_CHECK_TIMEOUT) {
 					apm_event_handler();
 					start = jiffies;
@@ -1188,26 +1412,15 @@
 	struct apm_user *	as;
 	int			i;
 	apm_event_t		event;
-	DECLARE_WAITQUEUE(wait, current);
 
 	as = fp->private_data;
 	if (check_apm_user(as, "read"))
 		return -EIO;
 	if (count < sizeof(apm_event_t))
 		return -EINVAL;
-	if (queue_empty(as)) {
-		if (fp->f_flags & O_NONBLOCK)
-			return -EAGAIN;
-		add_wait_queue(&apm_waitqueue, &wait);
-repeat:
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (queue_empty(as) && !signal_pending(current)) {
-			schedule();
-			goto repeat;
-		}
-		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&apm_waitqueue, &wait);
-	}
+	if ((queue_empty(as)) && (fp->f_flags & O_NONBLOCK))
+		return -EAGAIN;
+	wait_event_interruptible(apm_waitqueue, !queue_empty(as));
 	i = count;
 	while ((i >= sizeof(event)) && !queue_empty(as)) {
 		event = get_queued_event(as);
@@ -1254,7 +1467,6 @@
 		    u_int cmd, u_long arg)
 {
 	struct apm_user *	as;
-	DECLARE_WAITQUEUE(wait, current);
 
 	as = filp->private_data;
 	if (check_apm_user(as, "ioctl"))
@@ -1288,16 +1500,8 @@
 				return -EIO;
 		} else {
 			as->suspend_wait = 1;
-			add_wait_queue(&apm_suspend_waitqueue, &wait);
-			while (1) {
-				set_current_state(TASK_INTERRUPTIBLE);
-				if ((as->suspend_wait == 0)
-				    || signal_pending(current))
-					break;
-				schedule();
-			}
-			set_current_state(TASK_RUNNING);
-			remove_wait_queue(&apm_suspend_waitqueue, &wait);
+			wait_event_interruptible(apm_suspend_waitqueue,
+					as->suspend_wait == 0);
 			return as->suspend_result;
 		}
 		break;
@@ -1367,6 +1571,8 @@
 	 * privileged operation -- cevans
 	 */
 	as->suser = capable(CAP_SYS_ADMIN);
+	as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
+	as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
 	as->next = user_list;
 	user_list = as;
 	filp->private_data = as;
@@ -1562,7 +1768,7 @@
 	/* Install our power off handler.. */
 	if (power_off)
 		pm_power_off = apm_power_off;
-	register_sysrq_key('o',&sysrq_poweroff_op);
+	register_sysrq_key('o', &sysrq_poweroff_op);
 
 	if (smp_num_cpus == 1) {
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
@@ -1588,15 +1794,9 @@
 			apm_disabled = 1;
 		if (strncmp(str, "on", 2) == 0)
 			apm_disabled = 0;
-		if ((strncmp(str, "allow-ints", 10) == 0) ||
-		    (strncmp(str, "allow_ints", 10) == 0))
- 			apm_info.allow_ints = 1;
-		if ((strncmp(str, "broken-psr", 10) == 0) ||
-		    (strncmp(str, "broken_psr", 10) == 0))
-			apm_info.get_power_status_broken = 1;
-		if ((strncmp(str, "realmode-power-off", 18) == 0) ||
-		    (strncmp(str, "realmode_power_off", 18) == 0))
-			apm_info.realmode_power_off = 1;
+		if ((strncmp(str, "bounce-interval=", 16) == 0) ||
+		    (strncmp(str, "bounce_interval=", 16) == 0))
+			bounce_interval = simple_strtol(str + 16, NULL, 0);
 		invert = (strncmp(str, "no-", 3) == 0);
 		if (invert)
 			str += 3;
@@ -1605,9 +1805,15 @@
 		if ((strncmp(str, "power-off", 9) == 0) ||
 		    (strncmp(str, "power_off", 9) == 0))
 			power_off = !invert;
-		if ((strncmp(str, "bounce-interval=", 16) == 0) ||
-		    (strncmp(str, "bounce_interval=", 16) == 0))
-			bounce_interval = simple_strtol(str + 16, NULL, 0);
+		if ((strncmp(str, "allow-ints", 10) == 0) ||
+		    (strncmp(str, "allow_ints", 10) == 0))
+ 			apm_info.allow_ints = !invert;
+		if ((strncmp(str, "broken-psr", 10) == 0) ||
+		    (strncmp(str, "broken_psr", 10) == 0))
+			apm_info.get_power_status_broken = !invert;
+		if ((strncmp(str, "realmode-power-off", 18) == 0) ||
+		    (strncmp(str, "realmode_power_off", 18) == 0))
+			apm_info.realmode_power_off = !invert;
 		str = strchr(str, ',');
 		if (str != NULL)
 			str += strspn(str, ", \t");
@@ -1791,15 +1997,20 @@
 
 MODULE_AUTHOR("Stephen Rothwell");
 MODULE_DESCRIPTION("Advanced Power Management");
+MODULE_LICENSE("GPL");
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Enable debug mode");
 MODULE_PARM(power_off, "i");
 MODULE_PARM_DESC(power_off, "Enable power off");
 MODULE_PARM(bounce_interval, "i");
-MODULE_PARM_DESC(bounce_interval, "Set the number of ticks to ignore suspend bounces");
+MODULE_PARM_DESC(bounce_interval,
+		"Set the number of ticks to ignore suspend bounces");
 MODULE_PARM(allow_ints, "i");
 MODULE_PARM_DESC(allow_ints, "Allow interrupts during BIOS calls");
 MODULE_PARM(broken_psr, "i");
 MODULE_PARM_DESC(broken_psr, "BIOS has a broken GetPowerStatus call");
+MODULE_PARM(realmode_power_off, "i");
+MODULE_PARM_DESC(realmode_power_off,
+		"Switch to real mode before powering off");
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.12/linux/arch/i386/kernel/bluesmoke.c linux/arch/i386/kernel/bluesmoke.c
--- v2.4.12/linux/arch/i386/kernel/bluesmoke.c	Sun Sep 23 11:40:55 2001
+++ linux/arch/i386/kernel/bluesmoke.c	Thu Oct 11 09:04:57 2001
@@ -6,6 +6,8 @@
 #include <asm/processor.h> 
 #include <asm/msr.h>
 
+static int mce_disabled __initdata = 0;
+
 /*
  *	Machine Check Handler For PII/PIII
  */
@@ -111,7 +113,7 @@
  *	Set up machine check reporting for Intel processors
  */
 
-void __init intel_mcheck_init(struct cpuinfo_x86 *c)
+static void __init intel_mcheck_init(struct cpuinfo_x86 *c)
 {
 	u32 l, h;
 	int i;
@@ -130,6 +132,9 @@
 	
 	if(c->x86 == 5)
 	{
+		/* Default P5 to off as its often misconnected */
+		if(mce_disabled != -1)
+			return;
 		machine_check_vector = pentium_machine_check;
 		wmb();
 		/* Read registers before enabling */
@@ -137,11 +142,8 @@
 		rdmsr(MSR_IA32_P5_MC_TYPE, l, h);
 		if(done==0)
 			printk(KERN_INFO "Intel old style machine check architecture supported.\n");
-		/* Enable MCE */		
-		__asm__ __volatile__ (
-			"movl %%cr4, %%eax\n\t"
-			"orl $0x40, %%eax\n\t"
-			"movl %%eax, %%cr4\n\t" : : : "eax");
+ 		/* Enable MCE */
+		set_in_cr4(X86_CR4_MCE);
 		printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id());
 		return;
 	}
@@ -195,10 +197,7 @@
 	lo|= (1<<2);	/* Enable EIERRINT (int 18 MCE) */
 	lo&= ~(1<<4);	/* Enable MCE */
 	wrmsr(MSR_IDT_FCR1, lo, hi);
-	__asm__ __volatile__ (
-		"movl %%cr4, %%eax\n\t"
-		"orl $0x40, %%eax\n\t"
-		"movl %%eax, %%cr4\n\t" : : : "eax");
+	set_in_cr4(X86_CR4_MCE);
 	printk(KERN_INFO "Winchip machine check reporting enabled on CPU#%d.\n", smp_processor_id());
 }
 
@@ -208,11 +207,10 @@
  */
 
 
-static int mce_disabled = 0;
 
 void __init mcheck_init(struct cpuinfo_x86 *c)
 {
-	if(mce_disabled)
+	if(mce_disabled==1)
 		return;
 		
 	switch(c->x86_vendor)
@@ -230,6 +228,8 @@
 		case X86_VENDOR_CENTAUR:
 			winchip_mcheck_init(c);
 			break;
+		default:
+			break;
 	}
 }
 
@@ -238,4 +238,12 @@
 	mce_disabled = 1;
 	return 0;
 }
+
+static int __init mcheck_enable(char *str)
+{
+	mce_disabled = -1;
+	return 0;
+}
+
 __setup("nomce", mcheck_disable);
+__setup("mce", mcheck_enable);
diff -u --recursive --new-file v2.4.12/linux/arch/i386/kernel/cpuid.c linux/arch/i386/kernel/cpuid.c
--- v2.4.12/linux/arch/i386/kernel/cpuid.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/i386/kernel/cpuid.c	Thu Oct 11 09:04:57 2001
@@ -163,3 +163,4 @@
 
 MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
 MODULE_DESCRIPTION("x86 generic CPUID driver");
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c
--- v2.4.12/linux/arch/i386/kernel/dmi_scan.c	Sun Sep 23 11:40:55 2001
+++ linux/arch/i386/kernel/dmi_scan.c	Thu Oct 11 13:47:17 2001
@@ -10,6 +10,8 @@
 #include <linux/keyboard.h>
 #include <asm/keyboard.h>
 
+int is_sony_vaio_laptop;
+
 struct dmi_header
 {
 	u8	type;
@@ -322,8 +324,6 @@
  * This one isn't a bug detect for those who asked, we simply want to
  * activate Sony specific goodies like the camera and jogdial..
  */
-int is_sony_vaio_laptop;
-
 static __init int sony_vaio_laptop(struct dmi_blacklist *d)
 {
 	if (is_sony_vaio_laptop == 0)
diff -u --recursive --new-file v2.4.12/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.4.12/linux/arch/i386/kernel/entry.S	Tue Oct  9 17:06:51 2001
+++ linux/arch/i386/kernel/entry.S	Wed Oct 17 10:02:39 2001
@@ -621,6 +621,7 @@
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for TUX */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* Reserved for Security */
 	.long SYMBOL_NAME(sys_gettid)
+	.long SYMBOL_NAME(sys_readahead)	/* 225 */
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -u --recursive --new-file v2.4.12/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.4.12/linux/arch/i386/kernel/i386_ksyms.c	Sun Sep 23 11:40:55 2001
+++ linux/arch/i386/kernel/i386_ksyms.c	Thu Oct 11 13:47:50 2001
@@ -170,8 +170,5 @@
 EXPORT_SYMBOL(do_BUG);
 #endif
 
-#if defined(CONFIG_SONYPI) || defined(CONFIG_SONYPI_MODULE)
 extern int is_sony_vaio_laptop;
 EXPORT_SYMBOL(is_sony_vaio_laptop);
-#endif
-
diff -u --recursive --new-file v2.4.12/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
--- v2.4.12/linux/arch/i386/kernel/ldt.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/i386/kernel/ldt.c	Wed Oct 17 14:46:29 2001
@@ -45,6 +45,25 @@
 	return err;
 }
 
+static int read_default_ldt(void * ptr, unsigned long bytecount)
+{
+	int err;
+	unsigned long size;
+	void *address;
+
+	err = 0;
+	address = &default_ldt[0];
+	size = sizeof(struct desc_struct);
+	if (size > bytecount)
+		size = bytecount;
+
+	err = size;
+	if (copy_to_user(ptr, address, size))
+		err = -EFAULT;
+
+	return err;
+}
+
 static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
 {
 	struct mm_struct * mm = current->mm;
@@ -139,6 +158,9 @@
 		break;
 	case 1:
 		ret = write_ldt(ptr, bytecount, 1);
+		break;
+	case 2:
+		ret = read_default_ldt(ptr, bytecount);
 		break;
 	case 0x11:
 		ret = write_ldt(ptr, bytecount, 0);
diff -u --recursive --new-file v2.4.12/linux/arch/i386/kernel/microcode.c linux/arch/i386/kernel/microcode.c
--- v2.4.12/linux/arch/i386/kernel/microcode.c	Sun Sep 23 11:40:55 2001
+++ linux/arch/i386/kernel/microcode.c	Thu Oct 11 09:04:57 2001
@@ -65,6 +65,7 @@
 
 MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver");
 MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
+MODULE_LICENSE("GPL");
 EXPORT_NO_SYMBOLS;
 
 #define MICRO_DEBUG 0
diff -u --recursive --new-file v2.4.12/linux/arch/i386/kernel/msr.c linux/arch/i386/kernel/msr.c
--- v2.4.12/linux/arch/i386/kernel/msr.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/i386/kernel/msr.c	Thu Oct 11 09:04:57 2001
@@ -271,3 +271,4 @@
 
 MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
 MODULE_DESCRIPTION("x86 generic MSR driver");
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.4.12/linux/arch/i386/kernel/mtrr.c	Sun Sep 23 11:40:55 2001
+++ linux/arch/i386/kernel/mtrr.c	Mon Oct 15 13:43:24 2001
@@ -1253,7 +1253,8 @@
 	break;
 
     case MTRR_IF_INTEL:
-	/*  For Intel PPro stepping <= 7, must be 4 MiB aligned  */
+	/*  For Intel PPro stepping <= 7, must be 4 MiB aligned 
+	    and not touch 0x70000000->0x7003FFFF */
 	if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
 	     boot_cpu_data.x86 == 6 &&
 	     boot_cpu_data.x86_model == 1 &&
@@ -1264,6 +1265,12 @@
 		printk (KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base);
 		return -EINVAL;
 	    }
+	    if (!(base + size < 0x70000000 || base > 0x7003FFFF) &&
+		 (type == MTRR_TYPE_WRCOMB || type == MTRR_TYPE_WRBACK))
+	    {
+		printk (KERN_WARNING "mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n");
+	        return -EINVAL;
+	    }
 	}
 	/* Fall through */
 	
@@ -2119,10 +2126,8 @@
 		break;
 
 	case X86_VENDOR_CENTAUR:
-		/* Cyrix III has Intel style MTRRs, but doesn't support PAE */
-		if (boot_cpu_data.x86 == 6 &&
-			(boot_cpu_data.x86_model == 6 ||
-			 boot_cpu_data.x86_model == 7)) {
+		/* VIA Cyrix family have Intel style MTRRs, but don't support PAE */
+		if (boot_cpu_data.x86 == 6) {
 			size_or_mask  = 0xfff00000; /* 32 bits */
 			size_and_mask = 0;
 		}
diff -u --recursive --new-file v2.4.12/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c
--- v2.4.12/linux/arch/i386/kernel/pci-irq.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/i386/kernel/pci-irq.c	Mon Oct 15 19:30:33 2001
@@ -458,6 +458,8 @@
 	{ "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
 	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4,
 	  pirq_serverworks_get, pirq_serverworks_set },
+	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5,
+	  pirq_serverworks_get, pirq_serverworks_set },
 	{ "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B,
 		pirq_amd756_get, pirq_amd756_set },
 
diff -u --recursive --new-file v2.4.12/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.4.12/linux/arch/i386/kernel/setup.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/i386/kernel/setup.c	Mon Oct 15 13:43:24 2001
@@ -1604,7 +1604,7 @@
 
 		case 6:
 			switch (c->x86_model) {
-				case 6 ... 7:		/* Cyrix III or C3 */
+				case 6 ... 8:		/* Cyrix III family */
 					rdmsr (MSR_VIA_FCR, lo, hi);
 					lo |= (1<<1 | 1<<7);	/* Report CX8 & enable PGE */
 					wrmsr (MSR_VIA_FCR, lo, hi);
diff -u --recursive --new-file v2.4.12/linux/arch/ia64/config.in linux/arch/ia64/config.in
--- v2.4.12/linux/arch/ia64/config.in	Sun Aug 12 13:27:58 2001
+++ linux/arch/ia64/config.in	Mon Oct 15 13:42:14 2001
@@ -149,7 +149,7 @@
 source drivers/mtd/Config.in
 source drivers/pnp/Config.in
 source drivers/block/Config.in
-source drivers/i2o/Config.in
+source drivers/message/i2o/Config.in
 source drivers/md/Config.in
 
 mainmenu_option next_comment
diff -u --recursive --new-file v2.4.12/linux/arch/ia64/sn/io/pci_dma.c linux/arch/ia64/sn/io/pci_dma.c
--- v2.4.12/linux/arch/ia64/sn/io/pci_dma.c	Thu Apr 12 12:16:35 2001
+++ linux/arch/ia64/sn/io/pci_dma.c	Fri Oct 12 15:35:53 2001
@@ -182,7 +182,7 @@
 }
 
 /*
- * On sn1 we use the alt_address entry of the scatterlist to store
+ * On sn1 we use the orig_address entry of the scatterlist to store
  * the physical address corresponding to the given virtual address
  */
 int
diff -u --recursive --new-file v2.4.12/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.4.12/linux/arch/mips/config.in	Sun Sep 23 11:40:55 2001
+++ linux/arch/mips/config.in	Mon Oct 15 13:41:34 2001
@@ -377,7 +377,7 @@
 
 if [ "$CONFIG_DECSTATION" != "y" -a \
      "$CONFIG_SGI_IP22" != "y" ]; then
-   source drivers/i2o/Config.in
+   source drivers/message/i2o/Config.in
 fi
 
 if [ "$CONFIG_NET" = "y" ]; then
diff -u --recursive --new-file v2.4.12/linux/arch/parisc/kernel/ccio-dma.c linux/arch/parisc/kernel/ccio-dma.c
--- v2.4.12/linux/arch/parisc/kernel/ccio-dma.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/parisc/kernel/ccio-dma.c	Fri Oct 12 15:35:53 2001
@@ -638,7 +638,7 @@
 }
 
 
-static int ccio_dma_supported( struct pci_dev *dev, dma_addr_t mask)
+static int ccio_dma_supported( struct pci_dev *dev, u64 mask)
 {
 	if (dev == NULL) {
 		printk(MODULE_NAME ": EISA/ISA/et al not supported\n");
diff -u --recursive --new-file v2.4.12/linux/arch/parisc/kernel/ccio-rm-dma.c linux/arch/parisc/kernel/ccio-rm-dma.c
--- v2.4.12/linux/arch/parisc/kernel/ccio-rm-dma.c	Tue Dec  5 12:29:39 2000
+++ linux/arch/parisc/kernel/ccio-rm-dma.c	Fri Oct 12 15:35:53 2001
@@ -93,7 +93,7 @@
 }
 
 
-static int ccio_dma_supported( struct pci_dev *dev, dma_addr_t mask)  
+static int ccio_dma_supported( struct pci_dev *dev, u64 mask)
 {
 	if (dev == NULL) {
 		printk(MODULE_NAME ": EISA/ISA/et al not supported\n");
diff -u --recursive --new-file v2.4.12/linux/arch/parisc/kernel/pci-dma.c linux/arch/parisc/kernel/pci-dma.c
--- v2.4.12/linux/arch/parisc/kernel/pci-dma.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/parisc/kernel/pci-dma.c	Fri Oct 12 15:35:53 2001
@@ -77,7 +77,7 @@
 static inline void dump_resmap(void) {;}
 #endif
 
-static int pa11_dma_supported( struct pci_dev *dev, dma_addr_t mask)
+static int pa11_dma_supported( struct pci_dev *dev, u64 mask)
 {
 	return 1;
 }
diff -u --recursive --new-file v2.4.12/linux/arch/parisc/kernel/sba_iommu.c linux/arch/parisc/kernel/sba_iommu.c
--- v2.4.12/linux/arch/parisc/kernel/sba_iommu.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/parisc/kernel/sba_iommu.c	Fri Oct 12 15:35:53 2001
@@ -779,7 +779,7 @@
 }
 
 static int
-sba_dma_supported( struct pci_dev *dev, dma_addr_t mask)
+sba_dma_supported( struct pci_dev *dev, u64 mask)
 {
 	if (dev == NULL) {
 		printk(MODULE_NAME ": EISA/ISA/et al not supported\n");
diff -u --recursive --new-file v2.4.12/linux/arch/ppc/8xx_io/Config.in linux/arch/ppc/8xx_io/Config.in
--- v2.4.12/linux/arch/ppc/8xx_io/Config.in	Sun Sep 23 11:40:56 2001
+++ linux/arch/ppc/8xx_io/Config.in	Mon Oct 15 13:35:26 2001
@@ -33,7 +33,4 @@
 bool 'CPU6 Silicon Errata (860 Pre Rev. C)' CONFIG_8xx_CPU6
 bool 'I2C/SPI Microcode Patch' CONFIG_UCODE_PATCH
 
-if [ "$CONFIG_IDE" = "y" ]; then
-	bool 'MPC8xx direct IDE support on PCMCIA port' CONFIG_BLK_DEV_MPC8xx_IDE
-fi
 endmenu
diff -u --recursive --new-file v2.4.12/linux/arch/ppc/8xx_io/enet.c linux/arch/ppc/8xx_io/enet.c
--- v2.4.12/linux/arch/ppc/8xx_io/enet.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/ppc/8xx_io/enet.c	Wed Oct 17 14:37:01 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.enet.c 1.15 09/14/01 18:01:16 trini
+ * BK Id: SCCS/s.enet.c 1.17 10/11/01 11:55:47 trini
  */
 /*
  * Ethernet driver for Motorola MPC8xx.
@@ -147,7 +147,7 @@
 static int scc_enet_open(struct net_device *dev);
 static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static int scc_enet_rx(struct net_device *dev);
-static void scc_enet_interrupt(void *dev_id);
+static void scc_enet_interrupt(void *dev_id, struct pt_regs *regs);
 static int scc_enet_close(struct net_device *dev);
 static struct net_device_stats *scc_enet_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
@@ -303,7 +303,7 @@
  * This is called from the CPM handler, not the MPC core interrupt.
  */
 static void
-scc_enet_interrupt(void *dev_id)
+scc_enet_interrupt(void *dev_id, struct pt_regs *regs)
 {
 	struct	net_device *dev = dev_id;
 	volatile struct	scc_enet_private *cep;
@@ -805,22 +805,10 @@
 	ep->sen_iaddr4 = 0;
 
 	/* Set Ethernet station address.
-	 *
-	 * If we performed a MBX diskless boot, the Ethernet controller
-	 * has been initialized and we copy the address out into our
-	 * own structure.
-	 *
-	 * All other types of boards supply the address in the board
-	 * information structure, so we copy that into the controller.
 	 */
 	eap = (unsigned char *)&(ep->sen_paddrh);
-#ifndef CONFIG_MBX
 	for (i=5; i>=0; i--)
 		*eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i];
-#else
-	for (i=5; i>=0; i--)
-		dev->dev_addr[i] = *eap++;
-#endif
 
 	ep->sen_pper = 0;	/* 'cause the book says so */
 	ep->sen_taddrl = 0;	/* temp address (LSB) */
@@ -943,6 +931,14 @@
 	immap->im_ioport.iop_pcdat &= ~PC_BSE_LOOPBACK;
 #endif
 
+#ifdef CONFIG_FADS
+	cp->cp_pbpar |= PB_ENET_TENA;
+	cp->cp_pbdir |= PB_ENET_TENA;
+
+	/* Enable the EEST PHY.
+	*/
+	*((volatile uint *)BCSR1) &= ~BCSR1_ETHEN;
+#endif
 
 	dev->base_addr = (unsigned long)ep;
 	dev->priv = cep;
@@ -970,5 +966,3 @@
 
 	return 0;
 }
-
-
diff -u --recursive --new-file v2.4.12/linux/arch/ppc/8xx_io/fec.c linux/arch/ppc/8xx_io/fec.c
--- v2.4.12/linux/arch/ppc/8xx_io/fec.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/ppc/8xx_io/fec.c	Wed Oct 17 14:37:01 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.fec.c 1.18 09/22/01 09:12:32 trini
+ * BK Id: SCCS/s.fec.c 1.20 10/11/01 11:55:47 trini
  */
 /*
  * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx.
@@ -868,6 +868,8 @@
 		*s |= PHY_STAT_FAULT;
 	if (mii_reg & 0x0020)
 		*s |= PHY_STAT_ANC;
+
+	fep->link = (*s & PHY_STAT_LINK) ? 1 : 0;
 }
 
 static void mii_parse_cr(uint mii_reg, struct net_device *dev)
@@ -1650,11 +1652,11 @@
 #endif
 
 #ifdef PHY_INTERRUPT
-	if (request_8xxirq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0)
-		panic("Could not allocate MII IRQ!");
-
 	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
 		(0x80000000 >> PHY_INTERRUPT);
+
+	if (request_8xxirq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0)
+		panic("Could not allocate MII IRQ!");
 #endif
 
 	dev->base_addr = (unsigned long)fecp;
diff -u --recursive --new-file v2.4.12/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.4.12/linux/arch/ppc/Makefile	Sun Sep 23 11:40:56 2001
+++ linux/arch/ppc/Makefile	Thu Oct 11 09:04:57 2001
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.21 08/19/01 20:06:47 paulus
+# BK Id: SCCS/s.Makefile 1.23 09/18/01 11:19:05 paulus
 #
 # This file is included by the global makefile so that you can add your own
 # architecture-specific flags and dependencies. Remember to do have actions
diff -u --recursive --new-file v2.4.12/linux/arch/ppc/amiga/config.c linux/arch/ppc/amiga/config.c
--- v2.4.12/linux/arch/ppc/amiga/config.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/ppc/amiga/config.c	Thu Oct 11 09:04:57 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.config.c 1.7 05/21/01 00:48:24 cort
+ * BK Id: SCCS/s.config.c 1.12 09/18/01 11:19:06 paulus
  */
 #define m68k_debug_device debug_device
 
diff -u --recursive --new-file v2.4.12/linux/arch/ppc/boot/prep/misc.c linux/arch/ppc/boot/prep/misc.c
--- v2.4.12/linux/arch/ppc/boot/prep/misc.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/ppc/boot/prep/misc.c	Mon Oct 15 13:35:26 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.misc.c 1.18 07/30/01 17:19:40 trini
+ * BK Id: SCCS/s.misc.c 1.20 09/24/01 18:42:54 trini
  *
  * arch/ppc/boot/prep/misc.c
  *
@@ -47,6 +47,15 @@
 RESIDUAL hold_resid_buf;
 RESIDUAL *hold_residual = &hold_resid_buf;
 unsigned long initrd_start = 0, initrd_end = 0;
+
+/* These values must be variables.  If not, the compiler optimizer
+ * will remove some code, causing the size of the code to vary
+ * when these values are zero.  This is bad because we first
+ * compile with these zero to determine the size and offsets
+ * in an image, than compile again with these set to the proper
+ * discovered value.
+ */
+unsigned int initrd_offset, initrd_size;
 char *zimage_start;
 int zimage_size;
 
@@ -302,12 +311,14 @@
 	   size of the elf header which we strip -- Cort */
 	zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET);
 	zimage_size = ZIMAGE_SIZE;
+	initrd_offset = INITRD_OFFSET;
+	initrd_size = INITRD_SIZE;
 
-	if ( INITRD_OFFSET )
-		initrd_start = load_addr - 0x10000 + INITRD_OFFSET;
+	if ( initrd_offset )
+		initrd_start = load_addr - 0x10000 + initrd_offset;
 	else
 		initrd_start = 0;
-	initrd_end = INITRD_SIZE + initrd_start;
+	initrd_end = initrd_size + initrd_start;
 
 	/*
 	 * Find a place to stick the zimage and initrd and 
@@ -332,9 +343,9 @@
 			puts(" "); puthex(initrd_end); puts("\n");
 			avail_ram = (char *)PAGE_ALIGN(
 				(unsigned long)zimage_size+(unsigned long)zimage_start);
-			memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE );
+			memcpy ((void *)avail_ram, (void *)initrd_start, initrd_size );
 			initrd_start = (unsigned long)avail_ram;
-			initrd_end = initrd_start + INITRD_SIZE;
+			initrd_end = initrd_start + initrd_size;
 			puts("relocated to:  "); puthex(initrd_start);
 			puts(" "); puthex(initrd_end); puts("\n");
 		}
diff -u --recursive --new-file v2.4.12/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c
--- v2.4.12/linux/arch/ppc/kernel/m8xx_setup.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/ppc/kernel/m8xx_setup.c	Wed Oct 17 14:37:01 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.m8xx_setup.c 1.32 09/27/01 09:01:12 trini
+ * BK Id: SCCS/s.m8xx_setup.c 1.35 10/11/01 11:55:47 trini
  *
  *  linux/arch/ppc/kernel/setup.c
  *
@@ -52,7 +52,7 @@
 
 unsigned char __res[sizeof(bd_t)];
 
-extern void m8xx_ide_init();
+extern void m8xx_ide_init(void);
 
 #ifdef CONFIG_BLK_DEV_RAM
 extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
@@ -164,9 +164,9 @@
 	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = ~KAPWR_KEY;
 	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = ~KAPWR_KEY;
 	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk    = ~KAPWR_KEY;
-	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
-	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
-	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk    = KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk =  KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck =  KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk    =  KAPWR_KEY;
 
 	/* Disable the RTC one second and alarm interrupts. */
 	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &=
diff -u --recursive --new-file v2.4.12/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- v2.4.12/linux/arch/ppc/kernel/prep_pci.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/ppc/kernel/prep_pci.c	Mon Oct 15 13:35:26 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prep_pci.c 1.26 09/08/01 15:47:42 paulus
+ * BK Id: SCCS/s.prep_pci.c 1.31 10/05/01 17:48:18 trini
  */
 /*
  * PReP pci functions.
@@ -33,15 +33,15 @@
 
 /* Which PCI interrupt line does a given device [slot] use? */
 /* Note: This really should be two dimensional based in slot/pin used */
-unsigned char *Motherboard_map;
+static unsigned char *Motherboard_map;
 unsigned char *Motherboard_map_name;
 
 /* How is the 82378 PIRQ mapping setup? */
-unsigned char *Motherboard_routes;
+static unsigned char *Motherboard_routes;
 
-void (*Motherboard_non0)(struct pci_dev *);
+static void (*Motherboard_non0)(struct pci_dev *);
 
-void Powerplus_Map_Non0(struct pci_dev *);
+static void Powerplus_Map_Non0(struct pci_dev *);
 
 /* Used for Motorola to store system config register */
 static unsigned long	*ProcInfo;
@@ -474,16 +474,17 @@
         0, /* Slot 21 -  */
         2, /* Slot 22 -  */
 };
+
 static char ibm6015_pci_IRQ_routes[] __prepdata = {
         0,      /* Line 0 - unused */
         13,     /* Line 1 */
-        10,     /* Line 2 */
+        15,     /* Line 2 */
         15,     /* Line 3 */
         15,     /* Line 4 */
 };
 
 
-/* IBM Nobis and 850 */
+/* IBM Nobis and Thinkpad 850 */
 static char Nobis_pci_IRQ_map[23] __prepdata ={
         0, /* Slot 0  - unused */
         0, /* Slot 1  - unused */
@@ -564,7 +565,7 @@
  * are routed to OpenPIC inputs 5-8.  These values are offset by
  * 16 in the table to reflect the Linux kernel interrupt value.
  */
-struct powerplus_irq_list Powerplus_pci_IRQ_list =
+struct powerplus_irq_list Powerplus_pci_IRQ_list __prepdata =
 {
 	{25, 26, 27, 28},
 	{21, 22, 23, 24}
@@ -577,7 +578,7 @@
  * are routed to OpenPIC inputs 12-15. These values are offset by
  * 16 in the table to reflect the Linux kernel interrupt value.
  */
-struct powerplus_irq_list Mesquite_pci_IRQ_list =
+struct powerplus_irq_list Mesquite_pci_IRQ_list __prepdata =
 {
 	{24, 25, 26, 27},
 	{28, 29, 30, 31}
@@ -587,7 +588,7 @@
  * This table represents the standard PCI swizzle defined in the
  * PCI bus specification.
  */
-static unsigned char prep_pci_intpins[4][4] =
+static unsigned char prep_pci_intpins[4][4] __prepdata =
 {
 	{ 1, 2, 3, 4},  /* Buses 0, 4, 8, ... */
 	{ 2, 3, 4, 1},  /* Buses 1, 5, 9, ... */
@@ -600,8 +601,6 @@
  * other than hard-coded as well... IRQ's are individually mappable
  * to either edge or level.
  */
-#define CAROLINA_IRQ_EDGE_MASK_LO   0x00  /* IRQ's 0-7  */
-#define CAROLINA_IRQ_EDGE_MASK_HI   0xA4  /* IRQ's 8-15 [10,13,15] */
 
 /*
  * 8259 edge/level control definitions
@@ -694,7 +693,8 @@
 int MotMPIC;
 int mot_multi;
 
-int __init raven_init(void)
+int __init
+raven_init(void)
 {
 	unsigned int	devid;
 	unsigned int	pci_membase;
@@ -776,7 +776,7 @@
 	void            (*map_non0_bus)(struct pci_dev *);      /* For boards with more than bus 0 devices. */
 	struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */
 	unsigned char   secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */
-} mot_info[] = {
+} mot_info[] __prepdata = {
 	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
 	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
 	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes, NULL, NULL, 0x00},
@@ -805,7 +805,8 @@
 	{0x000, 0x00, 0x00, "",					NULL,			NULL, NULL, NULL, 0x00}
 };
 
-void ibm_prep_init(void)
+void __init
+ibm_prep_init(void)
 {
 	u32 addr;
 #ifdef CONFIG_PREP_RESIDUAL
@@ -828,13 +829,12 @@
 #ifdef CONFIG_PREP_RESIDUAL
 	mpic = residual_find_device(-1, NULL, SystemPeripheral,
 				    ProgrammableInterruptController, MPIC, 0);
-	if (mpic != NULL) {
+	if (mpic != NULL)
 		printk("mpic = %p\n", mpic);
-	}
 #endif
 }
 
-void
+static void __init
 ibm43p_pci_map_non0(struct pci_dev *dev)
 {
 	unsigned char intpin;
@@ -850,7 +850,8 @@
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
 }
 
-void __init prep_route_pci_interrupts(void)
+void __init
+prep_route_pci_interrupts(void)
 {
 	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
 	unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
@@ -913,68 +914,65 @@
 			/* AJF adjust level/edge control according to routes */
 			irq_mode = 0;
 			for (i = 1;  i <= 4;  i++)
-			{
 				irq_mode |= ( 1 << Motherboard_routes[i] );
-			}
 			outb( irq_mode & 0xff, 0x4d0 );
 			outb( (irq_mode >> 8) & 0xff, 0x4d1 );
 		}
-	} else if ( _prep_type == _PREP_IBM )
-	{
-		unsigned char pl_id;
-		/*
-		 * my carolina is 0xf0
-		 * 6015 has 0xfc
-		 * -- Cort
-		 */
-		printk("IBM ID: %08x\n", inb(0x0852));
-		switch(inb(0x0852))
-		{
+	} else if ( _prep_type == _PREP_IBM ) {
+		unsigned char planar_id = inb(0x0852);
+		unsigned char irq_edge_mask_lo, irq_edge_mask_hi;
+
+		printk("IBM ID: %08x\n", planar_id);
+		switch(planar_id) {
 		case 0xff:
-			Motherboard_map_name = "IBM 850/860 Portable";
+			Motherboard_map_name = "IBM Thinkpad 850/860";
 			Motherboard_map = Nobis_pci_IRQ_map;
 			Motherboard_routes = Nobis_pci_IRQ_routes;
+			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
 			break;
 		case 0xfc:
-			Motherboard_map_name = "IBM 6015";
+			Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)";
 			Motherboard_map = ibm6015_pci_IRQ_map;
 			Motherboard_routes = ibm6015_pci_IRQ_routes;
+			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
 			break;
 		case 0xd5:
-			Motherboard_map_name = "IBM 43p/140";
+			Motherboard_map_name = "IBM 43P-140 (Tiger1)";
 			Motherboard_map = ibm43p_pci_IRQ_map;
 			Motherboard_routes = ibm43p_pci_IRQ_routes;
 			Motherboard_non0 = ibm43p_pci_map_non0;
+			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
 			break;
 		default:
-			Motherboard_map_name = "IBM 8xx (Carolina)";
+			printk(KERN_ERR "Unknown IBM motherboard! Defaulting to Carolina.\n");
+		case 0xf0: /* PowerSeries 830/850 */
+		case 0xf1: /* PowerSeries 830/850 */
+		case 0xf2: /* PowerSeries 830/850 */
+		case 0xf4: /* 7248-43P */
+		case 0xf5: /* 7248-43P */
+		case 0xf6: /* 7248-43P */
+		case 0xf7: /* 7248-43P (missing from Carolina Tech Spec) */
+			Motherboard_map_name = "IBM PS830/PS850/7248 (Carolina)";
 			Motherboard_map = ibm8xx_pci_IRQ_map;
 			Motherboard_routes = ibm8xx_pci_IRQ_routes;
+			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+			irq_edge_mask_hi = 0xA4; /* irq's 10, 13, 15 level-triggered */
 			break;
 		}
 
-		/*printk("Changing IRQ mode\n");*/
-		pl_id=inb(0x04d0);
-		/*printk("Low mask is %#0x\n", pl_id);*/
-		outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
-		
-		pl_id=inb(0x04d1);
-		/*printk("Hi mask is  %#0x\n", pl_id);*/
-		outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
-		pl_id=inb(0x04d1);
-		/*printk("Hi mask now %#0x\n", pl_id);*/
-	}
-	else
-	{
+		outb(inb(0x04d0)|irq_edge_mask_lo, 0x04d0); /* primary 8259 */
+		outb(inb(0x04d1)|irq_edge_mask_hi, 0x04d1); /* cascaded 8259 */
+	} else {
 		printk("No known machine pci routing!\n");
 		return;
 	}
 	
 	/* Set up mapping from slots */
 	for (i = 1;  i <= 4;  i++)
-	{
 		ibc_pirq[i-1] = Motherboard_routes[i];
-	}
 	/* Enable PCI interrupts */
 	*ibc_pcicon |= 0x20;
 }
@@ -1039,14 +1037,14 @@
 			pci_write_config_byte(dev,
 					PCI_INTERRUPT_LINE,
 					dev->irq);
-		}else{
+		} else {
 			/* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */
 			pci_write_config_dword(dev, 0x40, 0x10ff08a1);
 		}
 	}
 }
 
-void
+static void __init
 Powerplus_Map_Non0(struct pci_dev *dev)
 {
 	struct pci_bus  *pbus;          /* Parent bus structure pointer */
@@ -1092,23 +1090,19 @@
 	 * Otherwise, assume it's a PMC site and get the interrupt line
 	 * value from the interrupt routing table.
 	 */ 
-	if (mot_info[mot_entry].secondary_bridge_devfn)
-	{
+	if (mot_info[mot_entry].secondary_bridge_devfn) {
 		pbus = dev->bus;
 
 		while (pbus->primary != 0)
 			pbus = pbus->parent;
 
-		if ((pbus->self)->devfn != 0xA0)
-		{
+		if ((pbus->self)->devfn != 0xA0) {
 			if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn)
 				intline = mot_info[mot_entry].pci_irq_list->secondary[intpin];
-			else
-			{
+			else {
 				if ((char *)(mot_info[mot_entry].map) == (char *)Mesquite_pci_IRQ_map)
 					intline = mot_info[mot_entry].map[((pbus->self)->devfn)/8] + 16;
-				else
-				{
+				else {
 					int i;
 					for (i=0;i<3;i++)
 						intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
@@ -1137,13 +1131,10 @@
 	if (OpenPIC_Addr) {
 		/* PCI interrupts are controlled by the OpenPIC */
 		pci_for_each_dev(dev) {
-			if (dev->bus->number == 0)
-			{
+			if (dev->bus->number == 0) {
                        		dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
 				pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq);
-			}
-			else
-			{
+			} else {
 				if (Motherboard_non0 != NULL)
 					Motherboard_non0(dev);
 			}
@@ -1164,26 +1155,26 @@
 		unsigned char d = PCI_SLOT(dev->devfn);
 		dev->irq = Motherboard_routes[Motherboard_map[d]];
 
-		for ( i = 0 ; i <= 5 ; i++ )
-		{
+		for ( i = 0 ; i <= 5 ; i++ ) {
 			/*
 			 * Relocate PCI I/O resources if necessary so the
 			 * standard 256MB BAT covers them.
 			 */
 			if ( (pci_resource_flags(dev, i) & IORESOURCE_IO) &&
-				(dev->resource[i].start > 0x10000000) ) 
-		        {
-		                printk("Relocating PCI address %lx -> %lx\n",
-		                       dev->resource[i].start,
-		                       (dev->resource[i].start & 0x00FFFFFF)
-		                       | 0x01000000);
-		                dev->resource[i].start =
-		                  (dev->resource[i].start & 0x00FFFFFF) | 0x01000000;
+				      (dev->resource[i].start > 0x10000000))  {
+				printk("Relocating PCI address %lx -> %lx\n",
+						dev->resource[i].start,
+						(dev->resource[i].start & 
+						 0x00FFFFFF)| 0x01000000);
+				dev->resource[i].start =
+					(dev->resource[i].start & 0x00FFFFFF)
+					| 0x01000000;
 		                pci_write_config_dword(dev,
-		                        PCI_BASE_ADDRESS_0+(i*0x4),
-		                       dev->resource[i].start );
-				dev->resource[i].end =
-					(dev->resource[i].end & 0x00FFFFFF) | 0x01000000;
+						PCI_BASE_ADDRESS_0 + (i*0x4),
+						dev->resource[i].start);
+				dev->resource[i].end = 
+					(dev->resource[i].end & 0x00FFFFFF)
+					| 0x01000000;
 		        }
 		}
 #if 0
@@ -1223,7 +1214,8 @@
 	hose->first_busno = 0;
 	hose->last_busno = 0xff;
 	hose->pci_mem_offset = PREP_ISA_MEM_BASE;
-	hose->io_base_virt = (void *)PREP_ISA_IO_BASE;
+	hose->io_base_phys = PREP_ISA_IO_BASE;
+	hose->io_base_virt = (void *)0x80000000; /* see prep_map_io() */
 	prep_init_resource(&hose->io_resource, 0, 0x0fffffff, IORESOURCE_IO);
 	prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff,
 			   IORESOURCE_MEM);
@@ -1241,25 +1233,17 @@
 			pkt = PnP_find_large_vendor_packet(
 				res->DevicePnPHeap+hostbridge->AllocatedOffset,
 				3, 0);
-			if(pkt)
-			{
+			if(pkt) {
 #define p pkt->L4_Pack.L4_Data.L4_PPCPack
 				setup_indirect_pci(hose, 
 					ld_le32((unsigned *) (p.PPCData)),
 					ld_le32((unsigned *) (p.PPCData+8)));
-			}
-			else
-			{
+			} else
 				setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc);
-			}
-		}
-		else
+		} else
 #endif /* CONFIG_PREP_RESIDUAL */
-		{
 			hose->ops = &prep_pci_ops;
-		}
 	}
 
 	ppc_md.pcibios_fixup = prep_pcibios_fixup;
 }
-
diff -u --recursive --new-file v2.4.12/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.4.12/linux/arch/ppc/kernel/prep_setup.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/ppc/kernel/prep_setup.c	Mon Oct 15 13:35:26 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prep_setup.c 1.36 09/08/01 15:47:42 paulus
+ * BK Id: SCCS/s.prep_setup.c 1.38 09/15/01 09:13:52 trini
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -840,8 +840,8 @@
  */
 void __init prep_map_io(void)
 {
-	io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
-	io_block_mapping(0xf0000000, 0xc0000000, 0x08000000, _PAGE_IO);
+	io_block_mapping(0x80000000, PREP_ISA_IO_BASE, 0x10000000, _PAGE_IO);
+	io_block_mapping(0xf0000000, PREP_ISA_MEM_BASE, 0x08000000, _PAGE_IO);
 }
 
 void __init
diff -u --recursive --new-file v2.4.12/linux/arch/s390/Makefile linux/arch/s390/Makefile
--- v2.4.12/linux/arch/s390/Makefile	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390/Makefile	Thu Oct 11 09:04:57 2001
@@ -55,16 +55,6 @@
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
-MAKESILO = $(MAKE) -C arch/$(ARCH)/tools/silo
-
-MAKEDASDFMT = $(MAKE) -C arch/$(ARCH)/tools/dasdfmt
-
-silo:
-	@$(MAKESILO) silo
-
-dasdfmt:
-	@$(MAKEDASDFMT) dasdfmt
-
 image: vmlinux 
 	@$(MAKEBOOT) image
 
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/Makefile linux/arch/s390/kernel/Makefile
--- v2.4.12/linux/arch/s390/kernel/Makefile	Wed Apr 11 19:02:27 2001
+++ linux/arch/s390/kernel/Makefile	Thu Oct 11 09:04:57 2001
@@ -15,7 +15,7 @@
 O_TARGET := kernel.o
 
 export-objs	:= debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o
-obj-y	:= lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \
+obj-y	:= entry.o bitmap.o traps.o time.o process.o irq.o \
             setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
             semaphore.o s390fpu.o reipl.o s390_ext.o debug.o
 
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/debug.c linux/arch/s390/kernel/debug.c
--- v2.4.12/linux/arch/s390/kernel/debug.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390/kernel/debug.c	Thu Oct 11 09:04:57 2001
@@ -83,6 +83,9 @@
 static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
 				struct file *file, const char *user_buf,
 				size_t user_buf_size, loff_t * offset);
+static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
+                                struct file *file, const char *user_buf,
+                                size_t user_buf_size, loff_t * offset);
 static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
                                 char *out_buf, const char *in_buf);
 static int debug_raw_format_fn(debug_info_t * id,
@@ -123,6 +126,15 @@
 	NULL
 };
 
+struct debug_view debug_flush_view = {
+        "flush",
+        NULL,
+        NULL,
+        NULL,
+        &debug_input_flush_fn,
+        NULL
+};
+
 struct debug_view debug_sprintf_view = {
 	"sprintf",
 	NULL,
@@ -664,6 +676,7 @@
 	if(!rc) 
 		goto out;
 	debug_register_view(rc, &debug_level_view);
+        debug_register_view(rc, &debug_flush_view);
 	printk(KERN_INFO
 	       "debug: reserved %d areas of %d pages for debugging %s\n",
 	       nr_areas, 1 << page_order, rc->name);
@@ -1027,6 +1040,73 @@
       out:
 	*offset += in_buf_size;
 	return rc;		/* number of input characters */
+}
+
+
+/*
+ * flushes debug areas
+ */
+ 
+void debug_flush(debug_info_t* id, int area)
+{
+        unsigned long flags;
+        int i;
+
+        if(!id)
+                return;
+        spin_lock_irqsave(&id->lock,flags);
+        if(area == DEBUG_FLUSH_ALL){
+                id->active_area = 0;
+                memset(id->active_entry, 0, id->nr_areas * sizeof(int));
+                for (i = 0; i < id->nr_areas; i++) 
+                        memset(id->areas[i], 0, PAGE_SIZE << id->page_order);
+                printk(KERN_INFO "debug: %s: all areas flushed\n",id->name);
+        } else if(area >= 0 && area < id->nr_areas) {
+                id->active_entry[area] = 0;
+                memset(id->areas[area], 0, PAGE_SIZE << id->page_order);
+                printk(KERN_INFO
+                        "debug: %s: area %i has been flushed\n",
+                        id->name, area);
+        } else {
+                printk(KERN_INFO
+                        "debug: %s: area %i cannot be flushed (range: %i - %i)\n",
+                        id->name, area, 0, id->nr_areas-1);
+        }
+        spin_unlock_irqrestore(&id->lock,flags);
+}
+
+/*
+ * view function: flushes debug areas 
+ */
+ 
+static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
+                                struct file *file, const char *user_buf,
+                                size_t in_buf_size, loff_t * offset)
+{
+        char input_buf[1];
+        int rc = in_buf_size;
+ 
+        if (*offset != 0)
+                goto out;
+        if (copy_from_user(input_buf, user_buf, 1)){
+                rc = -EFAULT;
+                goto out;
+        }
+        if(input_buf[0] == '-') { 
+                debug_flush(id, DEBUG_FLUSH_ALL);
+                goto out;
+        }
+        if (isdigit(input_buf[0])) {
+                int area = ((int) input_buf[0] - (int) '0');
+                debug_flush(id, area);
+                goto out;
+        }
+
+        printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]);
+
+      out:
+        *offset += in_buf_size;
+        return rc;              /* number of input characters */
 }
 
 /*
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S
--- v2.4.12/linux/arch/s390/kernel/entry.S	Tue Oct  9 17:06:51 2001
+++ linux/arch/s390/kernel/entry.S	Thu Oct 11 09:04:57 2001
@@ -97,17 +97,27 @@
  *    R15 - kernel stack pointer
  */
 
-        .macro  SAVE_ALL psworg           # system entry macro
+        .macro  SAVE_ALL psworg,sync      # system entry macro
         stm     %r13,%r15,__LC_SAVE_AREA
-        stam    %a2,%a4,__LC_SAVE_AREA+12
         basr    %r13,0                    #  temp base pointer
         l       %r13,.Lentry_base-.(%r13) # load &entry_base to %r13 
         tm      \psworg+1,0x01            # test problem state bit
-        bz      BASED(.+12)               # skip stack setup save
-        l       %r15,__LC_KERNEL_STACK    # problem state -> load ksp
-        lam     %a2,%a4,BASED(.Lc_ac)     # set ac.reg. 2 to primary space
-                                          # and access reg. 4 to home space
-0:      s       %r15,BASED(.Lc_spsize)    # make room for registers & psw
+        stam    %a2,%a4,__LC_SAVE_AREA+12
+	.if	\sync
+        bz      BASED(1f)                 # skip stack setup save
+	.else
+        bnz     BASED(0f)                 # from user -> load kernel stack
+	l	%r14,__LC_ASYNC_STACK	  # are we already on the async stack ?
+	slr     %r14,%r15
+	sra	%r14,13
+	be	BASED(1f)
+        l       %r15,__LC_ASYNC_STACK     # load async. stack
+	b	BASED(1f)
+	.endif
+0:      l       %r15,__LC_KERNEL_STACK    # problem state -> load ksp
+	lam	%a2,%a4,BASED(.Lc_ac)	  # set ac.reg. 2 to primary space
+					  # and ac.reg. 4 to home space
+1:      s       %r15,BASED(.Lc_spsize)    # make room for registers & psw
         n       %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
         stm     %r0,%r12,SP_R0(%r15)      # store gprs 0-12 to kernel stack
         st      %r2,SP_ORIG_R2(%r15)      # store original content of gpr 2
@@ -120,7 +130,7 @@
         xc      0(4,%r15),0(%r15)         # clear back chain
         .endm
 
-        .macro  RESTORE_ALL               # system exit macro
+        .macro  RESTORE_ALL sync          # system exit macro
         mvc     __LC_RETURN_PSW(8),SP_PSW(%r15)  # move user PSW to lowcore
         lam     %a0,%a15,SP_AREGS(%r15)   # load the access registers
         lm      %r0,%r15,SP_R0(%r15)      # load gprs 0-15 of user
@@ -129,8 +139,8 @@
         .endm
 
         .macro  GET_CURRENT
-        lr      %r9,%r15                  # load pointer to task_struct to %r9
-        n       %r9,BASED(.Lc0xffffe000)
+	l	%r9,BASED(.Lc0xffffe000)  # load pointer to task_struct to %r9
+	al	%r9,__LC_KERNEL_STACK
         .endm
 
 
@@ -171,13 +181,35 @@
         br      %r14
 
 /*
+ * do_softirq calling function. We want to run the softirq functions on the
+ * asynchronous interrupt stack.
+ */
+	.global do_call_softirq
+do_call_softirq:
+	stm	%r12,%r15,24(%r15)
+	lr	%r12,%r15
+        basr    %r13,0
+do_call_base:
+	l	%r0,__LC_ASYNC_STACK
+	slr     %r0,%r15
+	sra	%r0,13
+	be	0f-do_call_base(%r13)
+	l	%r15,__LC_ASYNC_STACK
+0:	sl	%r15,.Lc_overhead-do_call_base(%r13)
+        st	%r12,0(%r15)	# store backchain
+	l	%r1,.Ldo_softirq-do_call_base(%r13)
+	basr	%r14,%r1
+	lm	%r12,%r15,24(%r12)
+	br	%r14
+	
+/*
  * SVC interrupt handler routine. System calls are synchronous events and
  * are executed with interrupts enabled.
  */
 
 	.globl  system_call
 system_call:
-        SAVE_ALL __LC_SVC_OLD_PSW
+        SAVE_ALL __LC_SVC_OLD_PSW,1
 	mvi     SP_PGM_OLD_ILC(%r15),1  # mark PGM_OLD_ILC as invalid
 pgm_system_call:	
         GET_CURRENT               # load pointer to task_struct to R9
@@ -207,7 +239,7 @@
 	tm      SP_PGM_OLD_ILC(%r15),0xff
         bz      BASED(pgm_svcret)
 	stnsm   24(%r15),0xfc            # disable I/O and ext. interrupts
-        RESTORE_ALL
+        RESTORE_ALL 1
 
 #
 # call do_signal before return
@@ -557,7 +589,10 @@
         .long  sys_madvise
 	.long  sys_getdents64		 /* 220 */
         .long  sys_fcntl64 
-	.rept  255-221
+	.long  sys_ni_syscall		 /* 222 - reserved for posix_acl */
+	.long  sys_ni_syscall		 /* 223 - reserved for posix_acl */
+	.long  sys_ni_syscall		 /* 224 - reserved for posix_acl */
+	.rept  255-224
 	.long  sys_ni_syscall
 	.endr
 
@@ -581,10 +616,10 @@
  * for LPSW?).
  */
 	stm     %r13,%r15,__LC_SAVE_AREA
-	stam    %a2,%a4,__LC_SAVE_AREA+12
 	basr    %r13,0                   # temp base pointer
 	l       %r13,.Lentry_base-.(%r13)# load &entry_base to %r13
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
+	stam    %a2,%a4,__LC_SAVE_AREA+12
         bz      BASED(pgm_sv)            # skip if not
         tm      __LC_PGM_OLD_PSW,0x40    # test if per event recording is on
         bnz     BASED(pgm_sv)            # skip if it is
@@ -677,7 +712,7 @@
 
         .globl io_int_handler
 io_int_handler:
-        SAVE_ALL __LC_IO_OLD_PSW
+        SAVE_ALL __LC_IO_OLD_PSW,0
         GET_CURRENT               # load pointer to task_struct to R9
         la      %r2,SP_PTREGS(%r15) # address of register-save area
         sr      %r3,%r3
@@ -710,7 +745,7 @@
         bnz     BASED(io_signal_return)
 io_leave:
         stnsm   24(%r15),0xfc            # disable I/O and ext. interrupts
-        RESTORE_ALL
+        RESTORE_ALL 0
 
 #
 # call do_softirq
@@ -744,7 +779,7 @@
 
         .globl  ext_int_handler
 ext_int_handler:
-        SAVE_ALL __LC_EXT_OLD_PSW
+        SAVE_ALL __LC_EXT_OLD_PSW,0
         GET_CURRENT                    # load pointer to task_struct to R9
         la      %r2,SP_PTREGS(%r15)    # address of register-save area
         lh      %r3,__LC_EXT_INT_CODE  # error code
@@ -772,11 +807,11 @@
 
         .globl mcck_int_handler
 mcck_int_handler:
-        SAVE_ALL __LC_MCK_OLD_PSW
+        SAVE_ALL __LC_MCK_OLD_PSW,0
 	l       %r1,BASED(.Ls390_mcck)
 	basr    %r14,%r1	  # call machine check handler
 mcck_return:
-        RESTORE_ALL
+        RESTORE_ALL 0
 
 #ifdef CONFIG_SMP
 /*
@@ -784,7 +819,7 @@
  */
         .globl restart_int_handler
 restart_int_handler:
-        l       %r15,__LC_KERNEL_STACK # load ksp
+        l       %r15,__LC_SAVE_AREA+60 # load ksp
         lctl    %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
         lam     %a0,%a15,__LC_AREGS_SAVE_AREA
         stosm   0(%r15),0x04           # now we can turn dat on
@@ -817,6 +852,7 @@
 .Lc0xffffe000: .long  -8192        # to round stack pointer to &task_struct
 .Lc8191:       .long  8191
 .Lc_spsize:    .long  SP_SIZE
+.Lc_overhead:  .long  STACK_FRAME_OVERHEAD
 .Lc_ac:        .long  0,0,1
 .Lc_ENOSYS:    .long  -ENOSYS
 .Lc4:          .long  4
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/gdb-stub.c linux/arch/s390/kernel/gdb-stub.c
--- v2.4.12/linux/arch/s390/kernel/gdb-stub.c	Fri May 12 11:41:44 2000
+++ linux/arch/s390/kernel/gdb-stub.c	Thu Oct 11 09:04:57 2001
@@ -65,7 +65,8 @@
  * $m0,10#2a               +$00010203040506070809101112131415#42
  *
  */
-
+#define TRUE 1
+#define FALSE 0
 #include <asm/gdb-stub.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
@@ -74,14 +75,15 @@
 #include <linux/mm.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
+#include <linux/stddef.h>
 
+#define S390_REGS_COMMON_SIZE offsetof(struct gdb_pt_regs,orig_gpr2)
 
 /*
  * external low-level support routines
  */
 
-extern int putDebugChar(char c);    /* write a single character      */
-extern char getDebugChar(void);     /* read and return a single char */
+
 extern void fltr_set_mem_err(void);
 extern void trap_low(void);
 
@@ -247,8 +249,10 @@
 
 	while (count-- > 0) {
 		ch = *(mem++);
+#if 0
 		if (mem_err)
 			return 0;
+#endif
 		*buf++ = hexchars[ch >> 4];
 		*buf++ = hexchars[ch & 0xf];
 	}
@@ -276,8 +280,10 @@
 		ch = hex(*buf++) << 4;
 		ch |= hex(*buf++);
 		*(mem++) = ch;
+#if 0
 		if (mem_err)
 			return 0;
+#endif
 	}
 
 /*	set_mem_fault_trap(0); */
@@ -349,7 +355,7 @@
 	return (numChars);
 }
 
-void gdb_stub_get_non_pt_regs(gdb_pt_regs *regs)
+void gdb_stub_get_non_pt_regs(struct gdb_pt_regs *regs)
 {
 	s390_fp_regs *fpregs=&regs->fp_regs;
 	int has_ieee=save_fp_regs1(fpregs);
@@ -365,7 +371,7 @@
 	}
 }
 
-void gdb_stub_set_non_pt_regs(gdb_pt_regs *regs)
+void gdb_stub_set_non_pt_regs(struct gdb_pt_regs *regs)
 {
 	restore_fp_regs1(&regs->fp_regs);
 }
@@ -390,7 +396,7 @@
  * returns 1 if you should skip the instruction at the trap address, 0
  * otherwise.
  */
-void gdb_stub_handle_exception(gdb_pt_regs *regs,int sigval)
+void gdb_stub_handle_exception(struct gdb_pt_regs *regs,int sigval)
 {
 	int trap;			/* Trap type */
 	int addr;
@@ -402,19 +408,23 @@
 	/*
 	 * reply to host that an exception has occurred
 	 */
+#if 0
 	send_signal(sigval);
-
+#endif
 	/*
 	 * Wait for input from remote GDB
 	 */
-	while (1) {
+	while (1) 
+	{
 		output_buffer[0] = 0;
 		getpacket(input_buffer);
 
 		switch (input_buffer[0])
 		{
 		case '?':
+#if 0
 			send_signal(sigval);
+#endif
 			continue;
 
 		case 'd':
@@ -427,9 +437,9 @@
 		case 'g':
 			gdb_stub_get_non_pt_regs(regs);
 			ptr = output_buffer;
-			ptr=  mem2hex((char *)regs,ptr,sizeof(s390_regs_common),FALSE);
+			ptr=  mem2hex((char *)regs,ptr,S390_REGS_COMMON_SIZE,FALSE);
 			ptr=  mem2hex((char *)&regs->crs[0],ptr,NUM_CRS*CR_SIZE,FALSE);
-			ptr = mem2hex((char *)&regs->fp_regs, ptr,sizeof(s390_fp_regs));
+			ptr = mem2hex((char *)&regs->fp_regs, ptr,sizeof(s390_fp_regs),FALSE);
 			break;
 	  
 		/*
@@ -438,11 +448,11 @@
 		 */
 		case 'G':
 			ptr=input_buffer;
-			hex2mem (ptr, (char *)regs,sizeof(s390_regs_common), FALSE);
-			ptr+=sizeof(s390_regs_common)*2;
+			hex2mem (ptr, (char *)regs,S390_REGS_COMMON_SIZE, FALSE);
+			ptr+=S390_REGS_COMMON_SIZE*2;
 			hex2mem (ptr, (char *)regs->crs[0],NUM_CRS*CR_SIZE, FALSE);
 			ptr+=NUM_CRS*CR_SIZE*2;
-			hex2mem (ptr, (char *)regs->fp_regs,sizeof(s390_fp_regs), FALSE);
+			hex2mem (ptr, (char *)&regs->fp_regs,sizeof(s390_fp_regs), FALSE);
 			gdb_stub_set_non_pt_regs(regs);
 			strcpy(output_buffer,"OK");
 		break;
@@ -472,7 +482,8 @@
 			if (hexToInt(&ptr, &addr)
 				&& *ptr++ == ','
 				&& hexToInt(&ptr, &length)
-				&& *ptr++ == ':') {
+				&& *ptr++ == ':') 
+			{
 				if (hex2mem(ptr, (char *)addr, length, 1))
 					strcpy(output_buffer, "OK");
 				else
@@ -490,8 +501,7 @@
 
 			ptr = &input_buffer[1];
 			if (hexToInt(&ptr, &addr))
-				regs->cp0_epc = addr;
-	  
+				regs->psw.addr = addr;
 			/*
 			 * Need to flush the instruction cache here, as we may
 			 * have deposited a breakpoint, and the icache probably
@@ -529,22 +539,22 @@
 			 * There is no single step insn in the MIPS ISA, so we
 			 * use breakpoints and continue, instead.
 			 */
+#if 0
 			single_step(regs);
+#endif
 			flush_cache_all();
 			return;
 			/* NOTREACHED */
+			break;
 
-		}
-		break;
-
-		}			/* switch */
-
-		/*
-		 * reply to the request
-		 */
+		}      /* switch */
 
+	/*
+	 * reply to the request
+	 */
+	
 		putpacket(output_buffer);
-
+	
 	} /* while */
 }
 
@@ -558,13 +568,9 @@
 {
 	if (!gdb_stub_initialised)
 		return;
-	__asm__ __volatile__(
-			".globl	breakinst\n"
-			"breakinst:\t.word   %0\n\t"
-			:
-			: "i" (S390_BREAKPOINT_U16)
-				:
-				);
+	asm volatile (".globl	breakinst\n"
+		"breakinst:\t.word   %0"
+		: : "i" (S390_BREAKPOINT_U16) );
 }
 
 
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S
--- v2.4.12/linux/arch/s390/kernel/head.S	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390/kernel/head.S	Thu Oct 11 09:04:57 2001
@@ -461,28 +461,52 @@
         .org  0x10000
 startup:basr  %r13,0                     # get base
 .LPG1:  lctl  %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
-	la    %r12,parmarea-.LPG1(%r13)  # pointer to parameter area
+	la    %r12,_pstart-.LPG1(%r13)   # pointer to parameter area
 					 # move IPL device to lowcore
         mvc   __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
 	
 #
-# find out memory size.
+# find memory chunks.
 #
 	mvc   __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13)
-        lhi   %r2,1
-        sll   %r2,17                     # test in increments of 128KB
-	lr    %r1,%r2
-	ahi   %r1,-4                     # test last word in the segment
-.Lloop:	
-	l     %r0,0(%r1)                 # test 128KB segment
-	st    %r0,0(%r1)
-	ar    %r1,%r2                    # add 128KB
-	bnm   .Lloop-.LPG1(%r13)         # r1 < 0x80000000 -> loop
-.Lchkmem:
-	n     %r1,.L4malign-.LPG1(%r13)  # align to multiples of 4M
-        l     %r2,.Lmemsize-.LPG1(%r13)  # address of variable memory_size
-	st    %r1,0(%r2)                 # store memory size
-
+	la    %r1,1                      # test in increments of 128KB
+	sll   %r1,17
+	l     %r3,.Lmchunk-.LPG1(%r13)   # get pointer to memory_chunk array
+	slr   %r4,%r4                    # set start of chunk to zero
+	slr   %r5,%r5                    # set end of chunk to zero
+	slr   %r6,%r6			 # set access code to zero
+.Lloop:
+	tprot 0(%r5),0			 # test protection of first byte
+	ipm   %r7
+	srl   %r7,28
+	clr   %r6,%r7			 # compare cc with last access code
+	be    .Lsame-.LPG1(%r13)
+	clr   %r4,%r5			 # chunk size > 0?
+	be    .Lsize0-.LPG1(%r13)
+	st    %r4,0(%r3)		 # store start address of chunk
+	lr    %r0,%r5
+	slr   %r0,%r4
+	st    %r0,4(%r3)		 # store size of chunk
+	st    %r6,8(%r3)		 # store type of chunk
+	la    %r3,12(%r3)
+	lr    %r4,%r5			 # set start to end
+.Lsize0:
+	lr    %r6,%r7			 # set access code to last cc
+.Lsame:
+	ar    %r5,%r1			 # add 128KB to end of chunk
+	bno   .Lloop-.LPG1(%r13)	 # r1 < 0x80000000 -> loop
+.Lchkmem:				 # > 2GB or tprot got a program check
+	clr   %r4,%r5			 # chunk size > 0?
+	be    .Ldonemem-.LPG1(%r13)
+	st    %r4,0(%r3)		 # store start address of chunk
+	lr    %r0,%r5
+	slr   %r0,%r4
+	st    %r0,4(%r3)		 # store size of chunk
+	st    %r6,8(%r3)		 # store type of chunk
+.Ldonemem:		
+        l     %r1,.Lmemsize-.LPG1(%r13)  # address of variable memory_size
+	st    %r5,0(%r1)                 # store last end to memory size
+	
         l      %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
 #
 # find out if we are running under VM
@@ -534,7 +558,7 @@
 .Lentry:.long  0x00080000,0x80000000 + _stext
 .Lctl:  .long  0x04b50002               # cr0: various things
         .long  0                        # cr1: primary space segment table
-        .long  0                        # cr2: access register translation
+        .long  .Lduct                   # cr2: dispatchable unit control table
         .long  0                        # cr3: instruction authorization
         .long  0                        # cr4: instruction authorization
         .long  0                        # cr5:  various things
@@ -552,47 +576,50 @@
 .Lpcfpu:.long  0x00080000,0x80000000 + .Lchkfpu
 .Lpccsp:.long  0x00080000,0x80000000 + .Lchkcsp
 .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
-.L4malign:.long 0xffc00000
 .Lmemsize:.long memory_size
+.Lmchunk:.long memory_chunk
 .Lmflags:.long machine_flags
 
+	.org PARMAREA-64
+.Lduct:	.long 0,0,0,0,0,0,0,0
+	.long 0,0,0,0,0,0,0,0
+
 #
 # params at 10400 (setup.h)
 #
 	.org   PARMAREA
-parmarea:	
+	.global _pstart
+_pstart:	
         .long  0,0                      # IPL_DEVICE
         .long  0,RAMDISK_ORIGIN         # INITRD_START
-        .long  0,0x800000               # INITRD_SIZE
+        .long  0,RAMDISK_SIZE           # INITRD_SIZE
 
         .org   COMMAND_LINE
     	.byte  "root=/dev/ram0 ro"
         .byte  0
+	.org   0x11000
+	.global _pend
+_pend:	
 
-#
-# startup-code, running in virtual mode
-#
 #ifdef CONFIG_SHARED_KERNEL
 	.org   0x100000
-#else
-        .org   0x10800
 #endif
+
+#
+# startup-code, running in virtual mode
+#
         .globl _stext
 _stext:	basr  %r13,0                    # get base
 .LPG2:
 #
-# Setup lowcore
+# Setup stack
 #
-        l     %r1,__LC_IPLDEV           # load ipl device number
-        spx   .Lprefix-.LPG2(%r13)      # set prefix to linux lowcore
-        st    %r1,__LC_IPLDEV           # store ipl device number
         l     %r15,.Linittu-.LPG2(%r13)
-        ahi   %r15,8192                 # init_task_union + 8191
+        ahi   %r15,8192                 # init_task_union + 8192
         st    %r15,__LC_KERNEL_STACK    # set end of kernel stack
         ahi   %r15,-96
         xc    0(4,%r15),0(%r15)         # set backchain to zero
-        lhi   %r0,-1
-        st    %r0,__LC_KERNEL_LEVEL     # set interrupt count to -1
+
 #
 # clear bss memory
 #
@@ -622,7 +649,6 @@
 #
             .align 8
 .Ldw:	    .long  0x000a0000,0x00000000
-.Lprefix:   .long  init_S390_lowcore	
 .Linittu:   .long  init_task_union
 .Lstart:    .long  start_kernel
 .Lbss_bgn:  .long  __bss_start
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/lowcore.S linux/arch/s390/kernel/lowcore.S
--- v2.4.12/linux/arch/s390/kernel/lowcore.S	Fri May 12 11:41:44 2000
+++ linux/arch/s390/kernel/lowcore.S	Wed Dec 31 16:00:00 1969
@@ -1,60 +0,0 @@
-/*
- *  arch/s390/kernel/lowcore.S
- *    S390 lowcore definition.
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Hartmut Penner (hp@de.ibm.com)
- *               Martin Schwidefsky (schwidefsky@de.ibm.com),
- */
-
-#include <asm/lowcore.h>
-         .align 4096
-         .globl init_S390_lowcore
-init_S390_lowcore:      
-         .long  _RESTART_PSW_MASK
-         .long  restart_int_handler + _ADDR_31
-         .long  0,0
-         .long  0,0
-EXT_OLD: .long  0,0
-SVC_OLD: .long  0,0
-PGM_OLD: .long  0,0
-MCCK_OLD:.long  0,0
-IO_OLD:  .long  0,0
-         .long  0,0,0,0,0,0
-#
-# new psws need all to be physical
-# because we start with dat off
-#
-EXT_PSW: .long  _EXT_PSW_MASK
-         .long  ext_int_handler + _ADDR_31
-#
-SVC_PSW: .long  _SVC_PSW_MASK
-         .long  system_call + _ADDR_31
-#
-PGM_PSW: .long  _PGM_PSW_MASK
-         .long  pgm_check_handler + _ADDR_31
-#
-MCCK_PSW:.long  _MCCK_PSW_MASK
-         .long  mcck_int_handler + _ADDR_31
-#
-IO_PSW:  .long  _IO_PSW_MASK
-         .long  io_int_handler + _ADDR_31
-#
-#
-#
-EXTERNAL_PARAMETER:     .long  0
-CPU_ADDRESS:            .word 0
-EXT_INTERRUPT_CODE:     .word 0
-SVC_ILC:                .word 0
-SVC_CODE:               .word 0
-PGM_ILC:                .word 0
-PGM_CODE:               .word 0
-TRANS_EXC_ADDR:         .long  0                         # 090
-                        .fill 0xC00-0x094,1,0
-SAVE_AREA:              .fill 0x40,1,0                   # C00
-KERNEL_STACK:           .long 0                          # C40
-KERNEL_LEVEL:           .long 0                          # C44
-CPUID:                  .long 0,0                        # C48
-                        .fill 0x1000-0xC50,1,0
-
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c
--- v2.4.12/linux/arch/s390/kernel/process.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/s390/kernel/process.c	Thu Oct 11 09:04:57 2001
@@ -44,8 +44,6 @@
 #include <asm/processor.h>
 #include <asm/irq.h>
 
-spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
-
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
 /*
@@ -209,7 +207,7 @@
 void show_regs(struct pt_regs *regs)
 {
 	char buff[80];
-	int line;
+	int i, line;
 
         printk("CPU:    %d\n",smp_processor_id());
         printk("Process %s (pid: %d, stackpage=%08X)\n",
@@ -217,6 +215,17 @@
 	
 	for (line = 0; sprintf_regs(line, buff, current, regs); line++)
 		printk(buff);
+
+	if (regs->psw.mask & PSW_PROBLEM_STATE)
+	{
+		printk("User Code:\n");
+		memset(buff, 0, 20);
+		copy_from_user(buff,
+			       (char *) (regs->psw.addr & PSW_ADDR_MASK), 20);
+		for (i = 0; i < 20; i++)
+			printk("%02x ", buff[i]);
+		printk("\n");
+	}
 }
 
 char *task_show_regs(struct task_struct *task, char *buffer)
@@ -324,28 +333,19 @@
 
 asmlinkage int sys_fork(struct pt_regs regs)
 {
-        int ret;
-
-        lock_kernel();
-        ret = do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
-        unlock_kernel();
-        return ret;
+        return do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
 }
 
 asmlinkage int sys_clone(struct pt_regs regs)
 {
         unsigned long clone_flags;
         unsigned long newsp;
-        int ret;
 
-        lock_kernel();
         clone_flags = regs.gprs[3];
         newsp = regs.orig_gpr2;
         if (!newsp)
                 newsp = regs.gprs[15];
-        ret = do_fork(clone_flags, newsp, &regs, 0);
-        unlock_kernel();
-        return ret;
+        return do_fork(clone_flags, newsp, &regs, 0);
 }
 
 /*
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c
--- v2.4.12/linux/arch/s390/kernel/s390_ksyms.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390/kernel/s390_ksyms.c	Thu Oct 11 09:04:57 2001
@@ -15,11 +15,11 @@
 /*
  * memory management
  */
-EXPORT_SYMBOL(_oi_bitmap);
-EXPORT_SYMBOL(_ni_bitmap);
-EXPORT_SYMBOL(_zb_findmap);
-EXPORT_SYMBOL(__copy_from_user_fixup);
-EXPORT_SYMBOL(__copy_to_user_fixup);
+EXPORT_SYMBOL_NOVERS(_oi_bitmap);
+EXPORT_SYMBOL_NOVERS(_ni_bitmap);
+EXPORT_SYMBOL_NOVERS(_zb_findmap);
+EXPORT_SYMBOL_NOVERS(__copy_from_user_fixup);
+EXPORT_SYMBOL_NOVERS(__copy_to_user_fixup);
 
 /*
  * semaphore ops
@@ -56,10 +56,7 @@
 EXPORT_SYMBOL(csum_fold);
 EXPORT_SYMBOL(console_mode);
 EXPORT_SYMBOL(console_device);
+EXPORT_SYMBOL_NOVERS(do_call_softirq);
 
-#if CONFIG_IP_MULTICAST
-/* Required for lcs gigabit ethernet multicast support */
-EXPORT_SYMBOL(arp_mc_map);
-#endif
 
 
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/setup.c linux/arch/s390/kernel/setup.c
--- v2.4.12/linux/arch/s390/kernel/setup.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390/kernel/setup.c	Thu Oct 11 09:04:57 2001
@@ -47,6 +47,9 @@
 unsigned int console_device = -1;
 unsigned long memory_size = 0;
 unsigned long machine_flags = 0;
+struct { unsigned long addr, size, type; } memory_chunk[16];
+#define CHUNK_READ_WRITE 0
+#define CHUNK_READ_ONLY 1
 __u16 boot_cpu_addr;
 int cpus_initialized = 0;
 unsigned long cpu_initialized = 0;
@@ -258,6 +261,8 @@
  * Setup function called from init/main.c just after the banner
  * was printed.
  */
+extern char _pstart, _pend, _stext;
+
 void __init setup_arch(char **cmdline_p)
 {
         unsigned long bootmap_size;
@@ -267,19 +272,14 @@
 	unsigned long start_pfn, end_pfn;
         static unsigned int smptrap=0;
         unsigned long delay = 0;
+	struct _lowcore *lowcore;
+	int i;
 
         if (smptrap)
                 return;
         smptrap=1;
 
         /*
-         * Setup lowcore information for boot cpu
-         */
-        cpu_init();
-        boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
-        __cpu_logical_map[0] = boot_cpu_addr;
-
-        /*
          * print what head.S has found out about the machine 
          */
 	printk((MACHINE_IS_VM) ?
@@ -291,7 +291,7 @@
 
         ROOT_DEV = to_kdev_t(0x0100);
         memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
-	memory_end = memory_size;
+	memory_end = memory_size & ~0x400000UL;  /* align memory end to 4MB */
         /*
          * We need some free virtual space to be able to do vmalloc.
          * On a machine with 2GB memory we make sure that we have at
@@ -373,10 +373,25 @@
 	bootmap_size = init_bootmem(start_pfn, end_pfn);
 
 	/*
-	 * Register RAM pages with the bootmem allocator.
+	 * Register RAM areas with the bootmem allocator.
 	 */
-	free_bootmem(start_pfn << PAGE_SHIFT, 
-		     (end_pfn - start_pfn) << PAGE_SHIFT);
+	for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) {
+		unsigned long start_chunk, end_chunk;
+
+		if (memory_chunk[i].type != CHUNK_READ_WRITE)
+			continue;
+		start_chunk = (memory_chunk[i].addr + PAGE_SIZE - 1);
+		start_chunk >>= PAGE_SHIFT;
+		end_chunk = (memory_chunk[i].addr + memory_chunk[i].size);
+		end_chunk >>= PAGE_SHIFT;
+		if (start_chunk < start_pfn)
+			start_chunk = start_pfn;
+		if (end_chunk > end_pfn)
+			end_chunk = end_pfn;
+		if (start_chunk < end_chunk)
+			free_bootmem(start_chunk << PAGE_SHIFT,
+				     (end_chunk - start_chunk) << PAGE_SHIFT);
+	}
 
         /*
          * Reserve the bootmem bitmap itself as well. We do this in two
@@ -401,6 +416,36 @@
         }
 #endif
 
+        /*
+         * Setup lowcore for boot cpu
+         */
+	lowcore = (struct _lowcore *)
+		__alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
+	memset(lowcore, 0, PAGE_SIZE);
+	lowcore->restart_psw.mask = _RESTART_PSW_MASK;
+	lowcore->restart_psw.addr = _ADDR_31 + (addr_t) &restart_int_handler;
+	lowcore->external_new_psw.mask = _EXT_PSW_MASK;
+	lowcore->external_new_psw.addr = _ADDR_31 + (addr_t) &ext_int_handler;
+	lowcore->svc_new_psw.mask = _SVC_PSW_MASK;
+	lowcore->svc_new_psw.addr = _ADDR_31 + (addr_t) &system_call;
+	lowcore->program_new_psw.mask = _PGM_PSW_MASK;
+	lowcore->program_new_psw.addr = _ADDR_31 + (addr_t) &pgm_check_handler;
+        lowcore->mcck_new_psw.mask = _MCCK_PSW_MASK;
+	lowcore->mcck_new_psw.addr = _ADDR_31 + (addr_t) &mcck_int_handler;
+	lowcore->io_new_psw.mask = _IO_PSW_MASK;
+	lowcore->io_new_psw.addr = _ADDR_31 + (addr_t) &io_int_handler;
+	lowcore->ipl_device = S390_lowcore.ipl_device;
+	lowcore->kernel_stack = ((__u32) &init_task_union) + 8192;
+	lowcore->async_stack = (__u32)
+		__alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0) + 8192;
+	set_prefix((__u32) lowcore);
+        cpu_init();
+        boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
+        __cpu_logical_map[0] = boot_cpu_addr;
+
+	/*
+	 * Create kernel page tables and switch to virtual addressing.
+	 */
         paging_init();
 
 	res = alloc_bootmem_low(sizeof(struct resource));
@@ -433,30 +478,49 @@
 }
 
 /*
- *	Get CPU information for use by the procfs.
+ * get_cpuinfo - Get information on one CPU for use by procfs.
+ *
+ *	Prints info on the next CPU into buffer.  Beware, doesn't check for
+ *	buffer overflow.  Current implementation of procfs assumes that the
+ *	resulting data is <= 1K.
+ *
+ * Args:
+ *	buffer	-- you guessed it, the data buffer
+ *	cpu_np	-- Input: next cpu to get (start at 0).  Output: Updated.
+ *
+ *	Returns number of bytes written to buffer.
  */
 
-int get_cpuinfo(char * buffer)
+int get_cpuinfo(char *buffer, unsigned *cpu_np)
 {
         struct cpuinfo_S390 *cpuinfo;
         char *p = buffer;
-        int i;
+	unsigned n;
 
-        p += sprintf(p,"vendor_id       : IBM/S390\n"
-                       "# processors    : %i\n"
-                       "bogomips per cpu: %lu.%02lu\n",
-                       smp_num_cpus, loops_per_jiffy/(500000/HZ),
-                       (loops_per_jiffy/(5000/HZ))%100);
-        for (i = 0; i < smp_num_cpus; i++) {
-                cpuinfo = &safe_get_cpu_lowcore(i).cpu_data;
-                p += sprintf(p,"processor %i: "
-                               "version = %02X,  "
-                               "identification = %06X,  "
-                               "machine = %04X\n",
-                               i, cpuinfo->cpu_id.version,
-                               cpuinfo->cpu_id.ident,
-                               cpuinfo->cpu_id.machine);
-        }
+	n = *cpu_np;
+	while (n < NR_CPUS && (cpu_online_map & (1 << n)) == 0)
+		n++;
+	if (n >= NR_CPUS) {
+		*cpu_np = NR_CPUS;
+		return (0);
+	}
+	*cpu_np = n + 1;
+
+	if (n == 0) {
+		p += sprintf(p,"vendor_id       : IBM/S390\n"
+			       "# processors    : %i\n"
+			       "bogomips per cpu: %lu.%02lu\n",
+			       smp_num_cpus, loops_per_jiffy/(500000/HZ),
+			       (loops_per_jiffy/(5000/HZ))%100);
+	}
+	cpuinfo = &safe_get_cpu_lowcore(n).cpu_data;
+	p += sprintf(p,"processor %i: "
+		       "version = %02X,  "
+		       "identification = %06X,  "
+		       "machine = %04X\n",
+		       n, cpuinfo->cpu_id.version,
+		       cpuinfo->cpu_id.ident,
+		       cpuinfo->cpu_id.machine);
         return p - buffer;
 }
 
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/signal.c linux/arch/s390/kernel/signal.c
--- v2.4.12/linux/arch/s390/kernel/signal.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390/kernel/signal.c	Thu Oct 11 09:04:57 2001
@@ -12,6 +12,7 @@
  *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
@@ -23,31 +24,25 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
+#include <linux/personality.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 
-#define DEBUG_SIG 0
-
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-/* pretcode & sig are used to store the return addr on Intel
-   & the signal no as the first parameter we do this differently
-   using gpr14 & gpr2. */
-
-#define SIGFRAME_COMMON \
-__u8     callee_used_stack[__SIGNAL_FRAMESIZE]; \
-struct sigcontext sc; \
-_sigregs sregs; \
-__u8 retcode[S390_SYSCALL_SIZE];
 
 typedef struct 
 {
-	SIGFRAME_COMMON
+	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
+	struct sigcontext sc;
+	_sigregs sregs;
+	__u8 retcode[S390_SYSCALL_SIZE];
 } sigframe;
 
 typedef struct 
 {
-	SIGFRAME_COMMON
+	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
+	__u8 retcode[S390_SYSCALL_SIZE];
 	struct siginfo info;
 	struct ucontext uc;
 } rt_sigframe;
@@ -205,7 +200,7 @@
 	err=__copy_from_user(regs,&sregs->regs,sizeof(_s390_regs_common));
 	if(!err)
 	{
-		regs->orig_gpr2 = -1;		/* disable syscall checks */
+		regs->trap = -1;		/* disable syscall checks */
 		regs->psw.mask=(saved_psw.mask&~PSW_MASK_DEBUGCHANGE)|
 		(regs->psw.mask&PSW_MASK_DEBUGCHANGE);
 		regs->psw.addr=(saved_psw.addr&~PSW_ADDR_DEBUGCHANGE)|
@@ -217,53 +212,51 @@
 	return(err);
 }
 
-static int
-restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
-		 _sigregs *sregs,sigset_t *set)
-{
-	unsigned int err;
-
-	err=restore_sigregs(regs,sregs);
-	if(!err)
-		err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE);
-		return(err);
-}
-
-int sigreturn_common(struct pt_regs *regs,int framesize)
+asmlinkage long sys_sigreturn(struct pt_regs *regs)
 {
 	sigframe *frame = (sigframe *)regs->gprs[15];
 	sigset_t set;
 
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
-		return -1;
-	if (restore_sigcontext(&frame->sc,regs,&frame->sregs,&set))
-	        return -1;
+		goto badframe;
+	if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
+		goto badframe;
+
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
-	return 0;
-}
-
-asmlinkage int sys_sigreturn(struct pt_regs *regs)
-{
 
-	if (sigreturn_common(regs,sizeof(sigframe)))
+	if (restore_sigregs(regs, &frame->sregs))
 		goto badframe;
+
 	return regs->gprs[2];
 
 badframe:
 	force_sig(SIGSEGV, current);
 	return 0;
-}	
+}
 
-asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
 {
 	rt_sigframe *frame = (rt_sigframe *)regs->gprs[15];
+	sigset_t set;
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
 
-	if (sigreturn_common(regs,sizeof(rt_sigframe)))
+	if (restore_sigregs(regs, &frame->uc.uc_mcontext))
 		goto badframe;
+
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
 	do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]);
@@ -272,7 +265,7 @@
 badframe:
 	force_sig(SIGSEGV, current);
 	return 0;
-}	
+}
 
 /*
  * Set up a signal frame.
@@ -306,58 +299,48 @@
 	return (void *)((sp - frame_size) & -8ul);
 }
 
-static void *setup_frame_common(int sig, struct k_sigaction *ka,
-			sigset_t *set, struct pt_regs * regs,
-				int frame_size,u16 retcode)
+static inline int map_signal(int sig)
 {
-	sigframe *frame;
-	int err;
+	if (current->exec_domain
+	    && current->exec_domain->signal_invmap
+	    && sig < 32)
+		return current->exec_domain->signal_invmap[sig];
+	else
+		return sig;
+}
 
-	frame = get_sigframe(ka, regs,frame_size);
-	if (!access_ok(VERIFY_WRITE, frame,frame_size))
-		return 0;
-	err = save_sigregs(regs,&frame->sregs);
-	if(!err)
-		err=__put_user(&frame->sregs,&frame->sc.sregs);
-	if(!err)
+static void setup_frame(int sig, struct k_sigaction *ka,
+			sigset_t *set, struct pt_regs * regs)
+{
+	sigframe *frame = get_sigframe(ka, regs, sizeof(sigframe));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe)))
+		goto give_sigsegv;
+
+	if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE))
+		goto give_sigsegv;
+
+	if (save_sigregs(regs, &frame->sregs))
+		goto give_sigsegv;
+	if (__put_user(&frame->sregs, &frame->sc.sregs))
+		goto give_sigsegv;
 
-		err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE);
-	if(!err)
-	{
-		regs->gprs[2]=(current->exec_domain
-		           && current->exec_domain->signal_invmap
-		           && sig < 32
-		           ? current->exec_domain->signal_invmap[sig]
-		           : sig);
-		/* Set up registers for signal handler */
-		regs->gprs[15] = (addr_t)frame;
-		regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
-		regs->psw.mask = _USER_PSW_MASK;
-	}
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
 	if (ka->sa.sa_flags & SA_RESTORER) {
                 regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
 	} else {
                 regs->gprs[14] = FIX_PSW(frame->retcode);
-		err |= __put_user(retcode, (u16 *)(frame->retcode));
+		if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, 
+	                       (u16 *)(frame->retcode)))
+			goto give_sigsegv;
 	}
-	return(err ? 0:frame);
-}
 
-static void setup_frame(int sig, struct k_sigaction *ka,
-			sigset_t *set, struct pt_regs * regs)
-{
-	sigframe *frame;
+	/* Set up registers for signal handler */
+	regs->gprs[15] = (addr_t)frame;
+	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+	regs->psw.mask = _USER_PSW_MASK;
 
-	if((frame=setup_frame_common(sig,ka,set,regs,sizeof(sigframe),
-		    (S390_SYSCALL_OPCODE|__NR_sigreturn)))==0)
-		goto give_sigsegv;
-#if DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
-		current->comm, current->pid, frame, regs->eip, frame->pretcode);
-#endif
-	/* Martin wants this for pthreads */
+	regs->gprs[2] = map_signal(sig);
 	regs->gprs[3] = (addr_t)&frame->sc;
 
 	/* We forgot to include these in the sigcontext.
@@ -375,34 +358,44 @@
 static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 			   sigset_t *set, struct pt_regs * regs)
 {
-	rt_sigframe *frame;
-	addr_t      orig_sp=regs->gprs[15];
-	int err;
+	int err = 0;
+	rt_sigframe *frame = get_sigframe(ka, regs, sizeof(rt_sigframe));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe)))
+		goto give_sigsegv;
 
-	if((frame=setup_frame_common(sig,ka,set,regs,sizeof(rt_sigframe),
-		    (S390_SYSCALL_OPCODE|__NR_rt_sigreturn)))==0)
+	if (copy_siginfo_to_user(&frame->info, info))
 		goto give_sigsegv;
-	
-	err = copy_siginfo_to_user(&frame->info, info);
 
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __put_user(0, &frame->uc.uc_link);
 	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-	err |= __put_user(sas_ss_flags(orig_sp),
+	err |= __put_user(sas_ss_flags(regs->gprs[15]),
 			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-	err |= __put_user(&frame->sc,&frame->uc.sc);
-	regs->gprs[3] = (addr_t)&frame->info;
-	regs->gprs[4] = (addr_t)&frame->uc;
-
+	err |= save_sigregs(regs, &frame->uc.uc_mcontext);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 	if (err)
 		goto give_sigsegv;
 
-#if DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
-		current->comm, current->pid, frame, regs->eip, frame->pretcode);
-#endif
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+                regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
+	} else {
+                regs->gprs[14] = FIX_PSW(frame->retcode);
+		err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, 
+	                          (u16 *)(frame->retcode));
+	}
+
+	/* Set up registers for signal handler */
+	regs->gprs[15] = (addr_t)frame;
+	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+	regs->psw.mask = _USER_PSW_MASK;
+
+	regs->gprs[2] = map_signal(sig);
+	regs->gprs[3] = (addr_t)&frame->info;
+	regs->gprs[4] = (addr_t)&frame->uc;
 	return;
 
 give_sigsegv:
@@ -551,13 +544,16 @@
 					continue;
 				/* FALLTHRU */
 
-			case SIGSTOP:
+			case SIGSTOP: {
+				struct signal_struct *sig;
 				set_current_state(TASK_STOPPED);
 				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+				sig = current->p_pptr->sig;
+				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
+			}
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c
--- v2.4.12/linux/arch/s390/kernel/smp.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390/kernel/smp.c	Thu Oct 11 09:04:57 2001
@@ -57,6 +57,8 @@
 
 spinlock_t       kernel_flag = SPIN_LOCK_UNLOCKED;
 
+unsigned long	 cpu_online_map;
+
 /*
  *      Setup routine for controlling SMP activation
  *
@@ -92,6 +94,95 @@
 
 extern void reipl(unsigned long devno);
 
+static sigp_ccode smp_ext_bitcall(int, ec_bit_sig);
+static void smp_ext_bitcall_others(ec_bit_sig);
+
+/*
+ * Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ */
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+
+struct call_data_struct {
+	void (*func) (void *info);
+	void *info;
+	atomic_t started;
+	atomic_t finished;
+	int wait;
+};
+
+static struct call_data_struct * call_data;
+
+/*
+ * 'Call function' interrupt callback
+ */
+static void do_call_function(void)
+{
+	void (*func) (void *info) = call_data->func;
+	void *info = call_data->info;
+	int wait = call_data->wait;
+
+	atomic_inc(&call_data->started);
+	(*func)(info);
+	if (wait)
+		atomic_inc(&call_data->finished);
+}
+
+/*
+ * this function sends a 'generic call function' IPI to all other CPUs
+ * in the system.
+ */
+
+int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+			int wait)
+/*
+ * [SUMMARY] Run a function on all other CPUs.
+ * <func> The function to run. This must be fast and non-blocking.
+ * <info> An arbitrary pointer to pass to the function.
+ * <nonatomic> currently unused.
+ * <wait> If true, wait (atomically) until function has completed on other CPUs.
+ * [RETURNS] 0 on success, else a negative status code. Does not return until
+ * remote CPUs are nearly ready to execute <<func>> or are or have executed.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler, you may call it from a bottom half handler.
+ */
+{
+	struct call_data_struct data;
+	int cpus = smp_num_cpus-1;
+
+	if (!cpus || !atomic_read(&smp_commenced))
+		return 0;
+
+	data.func = func;
+	data.info = info;
+	atomic_set(&data.started, 0);
+	data.wait = wait;
+	if (wait)
+		atomic_set(&data.finished, 0);
+
+	spin_lock_bh(&call_lock);
+	call_data = &data;
+	/* Send a message to all other CPUs and wait for them to respond */
+        smp_ext_bitcall_others(ec_call_function);
+
+	/* Wait for response */
+	while (atomic_read(&data.started) != cpus)
+		barrier();
+
+	if (wait)
+		while (atomic_read(&data.finished) != cpus)
+			barrier();
+	spin_unlock_bh(&call_lock);
+
+	return 0;
+}
+
+
+/*
+ * Various special callbacks
+ */
+
 void do_machine_restart(void)
 {
         smp_send_stop();
@@ -148,7 +239,6 @@
 
 void do_ext_call_interrupt(struct pt_regs *regs, __u16 code)
 {
-        ec_ext_call *ec, *next;
         int bits;
 
         /*
@@ -169,131 +259,15 @@
 		do_machine_halt();
         if (test_bit(ec_power_off, &bits))
 		do_machine_power_off();
-	if (test_bit(ec_ptlb, &bits))
-	        local_flush_tlb();
-
-        /*
-         * Handle external call commands with a parameter area
-         */
-        do {
-                ec = (ec_ext_call *) atomic_read(&S390_lowcore.ext_call_queue);
-        } while (atomic_compare_and_swap((int) ec, 0,
-                                         &S390_lowcore.ext_call_queue));
-        if (ec == NULL)
-                return;   /* no command signals */
-
-        /* Make a fifo out of the lifo */
-        next = ec->next;
-        ec->next = NULL;
-        while (next != NULL) {
-                ec_ext_call *tmp = next->next;
-                next->next = ec;
-                ec = next;
-                next = tmp;
-        }
-
-        /* Execute every sigp command on the queue */
-        while (ec != NULL) {
-                switch (ec->cmd) {
-                case ec_callback_async: {
-                        void (*func)(void *info);
-                        void *info;
-
-                        func = ec->func;
-                        info = ec->info;
-                        atomic_set(&ec->status,ec_executing);
-                        (func)(info);
-                        return;
-                }
-                case ec_callback_sync:
-                        atomic_set(&ec->status,ec_executing);
-                        (ec->func)(ec->info);
-                        atomic_set(&ec->status,ec_done);
-                        return;
-                default:
-                }
-                ec = ec->next;
-        }
-}
-
-/*
- * Send a callback sigp to another cpu.
- */
-sigp_ccode
-smp_ext_call(int cpu, void (*func)(void *info), void *info, int wait)
-{
-        struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
-        sigp_ccode ccode;
-        ec_ext_call ec;
-
-        ec.cmd = wait ? ec_callback_sync : ec_callback_async;
-        atomic_set(&ec.status, ec_pending);
-	ec.func = func;
-        ec.info = info;
-        do {
-                ec.next = (ec_ext_call*) atomic_read(&lowcore->ext_call_queue);
-        } while (atomic_compare_and_swap((int) ec.next, (int)(&ec),
-                                         &lowcore->ext_call_queue));
-        /*
-         * We try once to deliver the signal. There are four possible
-         * return codes:
-         * 0) Order code accepted - can't show up on an external call
-         * 1) Status stored - fine, wait for completion.
-         * 2) Busy - there is another signal pending. Thats fine too, because
-         *    do_ext_call from the pending signal will execute all signals on
-         *    the queue. We wait for completion.
-         * 3) Not operational - something very bad has happened to the cpu.
-         *    do not wait for completion.
-         */
-        ccode = signal_processor(cpu, sigp_external_call);
-
-        if (ccode != sigp_not_operational)
-                /* wait for completion, FIXME: possible seed of a deadlock */
-                while (atomic_read(&ec.status) != (wait?ec_done:ec_executing));
-
-        return ccode;
-}
-
-/*
- * Send a callback sigp to every other cpu in the system.
- */
-void smp_ext_call_others(void (*func)(void *info), void *info, int wait)
-{
-        struct _lowcore *lowcore;
-        ec_ext_call ec[NR_CPUS];
-        sigp_ccode ccode;
-        int i;
-
-        for (i = 0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() == i)
-                        continue;
-                lowcore = &get_cpu_lowcore(i);
-		ec[i].cmd = wait ? ec_callback_sync : ec_callback_async;
-		atomic_set(&ec[i].status, ec_pending);
-		ec[i].func = func;
-		ec[i].info = info;
-                do {
-                        ec[i].next = (ec_ext_call *)
-                                        atomic_read(&lowcore->ext_call_queue);
-                } while (atomic_compare_and_swap((int) ec[i].next, (int)(ec+i),
-                                                 &lowcore->ext_call_queue));
-                ccode = signal_processor(i, sigp_external_call);
-        }
-
-        /* wait for completion, FIXME: possible seed of a deadlock */
-        for (i = 0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() == i)
-                        continue;
-                while (atomic_read(&ec[i].status) != 
-		       (wait ? ec_done:ec_executing));
-        }
+	if (test_bit(ec_call_function, &bits)) 
+		do_call_function();
 }
 
 /*
  * Send an external call sigp to another cpu and return without waiting
  * for its completion.
  */
-sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig)
+static sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig)
 {
         struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
         sigp_ccode ccode;
@@ -310,7 +284,7 @@
  * Send an external call sigp to every other cpu in the system and
  * return without waiting for its completion.
  */
-void smp_ext_bitcall_others(ec_bit_sig sig)
+static void smp_ext_bitcall_others(ec_bit_sig sig)
 {
         struct _lowcore *lowcore;
         sigp_ccode ccode;
@@ -329,51 +303,6 @@
 }
 
 /*
- * cycles through all the cpus,
- * returns early if info is not NULL & the processor has something
- * of intrest to report in the info structure.
- * it returns the next cpu to check if it returns early.
- * i.e. it should be used as follows if you wish to receive info.
- * next_cpu=0;
- * do
- * {
- *    info->cpu=next_cpu;
- *    next_cpu=smp_signal_others(order_code,parameter,1,info);
- *    ... check info here
- * } while(next_cpu<=smp_num_cpus)
- *
- *  if you are lazy just use it like
- * smp_signal_others(order_code,parameter,0,1,NULL);
- */
-int smp_signal_others(sigp_order_code order_code, u32 parameter,
-                      int spin, sigp_info *info)
-{
-        sigp_ccode   ccode;
-        u32          dummy;
-        u16          i;
-
-        if (info)
-                info->intresting = 0;
-        for (i = (info ? info->cpu : 0); i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        do {
-                                ccode = signal_processor_ps(
-                                        (info ? &info->status : &dummy),
-                                        parameter, i, order_code);
-                        } while(spin && ccode == sigp_busy);
-                        if (info && ccode != sigp_order_code_accepted) {
-                                info->intresting = 1;
-                                info->cpu = i;
-                                info->ccode = ccode;
-                                i++;
-                                break;
-                        }
-                }
-        }
-        return i;
-}
-
-/*
  * this function sends a 'stop' sigp to all other CPUs in the system.
  * it goes straight through.
  */
@@ -390,7 +319,18 @@
 
         /* stop all processors */
 
-        smp_signal_others(sigp_stop, 0, 1, NULL);
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() != i) {
+                        int ccode;
+                        do {
+                                ccode = signal_processor_ps(
+                                   &dummy,
+                                   0,
+                                   i,
+                                   sigp_stop);
+                        } while(ccode == sigp_busy);
+                }
+        }
 
         /* store status of all processors in their lowcores (real 0) */
 
@@ -419,7 +359,7 @@
 
 void smp_ptlb_all(void)
 {
-        smp_ext_call_others(smp_ptlb_callback, NULL, 1);
+        smp_call_function(smp_ptlb_callback, NULL, 0, 1);
 	local_flush_tlb();
 }
 
@@ -482,7 +422,7 @@
                 parms.end_ctl = cr;
                 parms.orvals[cr] = 1 << bit;
                 parms.andvals[cr] = 0xFFFFFFFF;
-                smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
+                smp_call_function(smp_ctl_bit_callback, &parms, 0, 1);
         }
         __ctl_set_bit(cr, bit);
 }
@@ -498,36 +438,12 @@
                 parms.end_ctl = cr;
                 parms.orvals[cr] = 0x00000000;
                 parms.andvals[cr] = ~(1 << bit);
-                smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
+                smp_call_function(smp_ctl_bit_callback, &parms, 0, 1);
         }
         __ctl_clear_bit(cr, bit);
 }
 
 /*
- * Call a function on all other processors
- */
-
-int
-smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
-/*
- * [SUMMARY] Run a function on all other CPUs.
- * <func> The function to run. This must be fast and non-blocking.
- * <info> An arbitrary pointer to pass to the function.
- * <retry> currently unused.
- * <wait> If true, wait (atomically) until function has completed on other CPUs.
- * [RETURNS] 0 on success, else a negative status code. Does not return until
- * remote CPUs are nearly ready to execute <<func>> or are or have executed.
- *
- * You must not call this function with disabled interrupts or from a
- * hardware interrupt handler, you may call it from a bottom half handler.
- */
-{
-        if (atomic_read(&smp_commenced) != 0)
-                smp_ext_call_others(func, info, wait);
-        return 0;
-}
-
-/*
  * Lets check how many CPUs we have.
  */
 
@@ -537,6 +453,7 @@
 
         current->processor = 0;
         smp_num_cpus = 1;
+	cpu_online_map = 1;
         for (curr_cpu = 0;
              curr_cpu <= 65535 && smp_num_cpus < max_cpus; curr_cpu++) {
                 if ((__u16) curr_cpu == boot_cpu_addr)
@@ -556,6 +473,7 @@
  *      Activate a secondary processor.
  */
 extern void init_100hz_timer(void);
+extern int pfault_init(void);
 extern int pfault_token(void);
 
 int __init start_secondary(void *cpuvoid)
@@ -620,15 +538,20 @@
         init_tasks[cpu] = idle;
 
         cpu_lowcore=&get_cpu_lowcore(cpu);
-        cpu_lowcore->kernel_stack=idle->thread.ksp;
-        __asm__ __volatile__("stctl 0,15,%0\n\t"
-                             "stam  0,15,%1"
+	cpu_lowcore->save_area[15] = idle->thread.ksp;
+	cpu_lowcore->kernel_stack = (idle->thread.ksp | 8191) + 1;
+        __asm__ __volatile__("la    1,%0\n\t"
+			     "stctl 0,15,0(1)\n\t"
+			     "la    1,%1\n\t"
+                             "stam  0,15,0(1)"
                              : "=m" (cpu_lowcore->cregs_save_area[0]),
                                "=m" (cpu_lowcore->access_regs_save_area[0])
-                             : : "memory");
+                             : : "1", "memory");
 
         eieio();
         signal_processor(cpu,sigp_restart);
+	/* Mark this cpu as online */
+	set_bit(cpu, &cpu_online_map);
 }
 
 /*
@@ -650,12 +573,12 @@
 }
 
 /*
- *	Cycle through the processors sending APIC IPIs to boot each.
+ *	Cycle through the processors sending sigp_restart to boot each.
  */
 
 void __init smp_boot_cpus(void)
 {
-        struct _lowcore *curr_lowcore;
+	unsigned long async_stack;
         sigp_ccode   ccode;
         int i;
 
@@ -680,34 +603,37 @@
 
         for(i = 0; i < smp_num_cpus; i++)
         {
-                curr_lowcore = (struct _lowcore *)
-                                    __get_free_page(GFP_KERNEL|GFP_DMA);
-                if (curr_lowcore == NULL) {
-                        printk("smp_boot_cpus failed to allocate prefix memory\n");
-                        break;
-                }
-                lowcore_ptr[i] = curr_lowcore;
-                memcpy(curr_lowcore, &S390_lowcore, sizeof(struct _lowcore));
+		lowcore_ptr[i] = (struct _lowcore *)
+			__get_free_page(GFP_KERNEL|GFP_DMA);
+                if (lowcore_ptr[i] == NULL)
+                        panic("smp_boot_cpus failed to "
+			      "allocate prefix memory\n");
+		async_stack = __get_free_pages(GFP_KERNEL,1);
+		if (async_stack == 0)
+			panic("smp_boot_cpus failed to allocate "
+			      "asyncronous interrupt stack\n");
+
+                memcpy(lowcore_ptr[i], &S390_lowcore, sizeof(struct _lowcore));
+		lowcore_ptr[i]->async_stack = async_stack + (2 * PAGE_SIZE);
                 /*
                  * Most of the parameters are set up when the cpu is
                  * started up.
                  */
-                if (smp_processor_id() == i)
-                        set_prefix((u32) curr_lowcore);
-                else {
-                        ccode = signal_processor_p((u32)(curr_lowcore),
-                                                   i, sigp_set_prefix);
-                        if(ccode) {
-                                /* if this gets troublesome I'll have to do
-                                 * something about it. */
-                                printk("ccode %d for cpu %d  returned when "
-                                       "setting prefix in smp_boot_cpus not good.\n",
-                                       (int) ccode, (int) i);
-                        }
-                        else
-                                do_boot_cpu(i);
-                }
-        }
+		if (smp_processor_id() == i)
+			set_prefix((u32) lowcore_ptr[i]);
+		else {
+			ccode = signal_processor_p((u32)(lowcore_ptr[i]),
+						   i, sigp_set_prefix);
+			if (ccode)
+				/* if this gets troublesome I'll have to do
+				 * something about it. */
+				printk("ccode %d for cpu %d  returned when "
+				       "setting prefix in smp_boot_cpus not good.\n",
+				       (int) ccode, (int) i);
+			else
+				do_boot_cpu(i);
+		}
+	}
 }
 
 /*
@@ -746,8 +672,6 @@
                 s390_do_profile(regs->psw.addr);
 
         if (!--prof_counter[cpu]) {
-                int system = 1-user;
-                struct task_struct * p = current;
 
                 /*
                  * The multiplier may have changed since the last time we got
@@ -771,9 +695,7 @@
                  * WrongThing (tm) to do.
                  */
 
-                irq_enter(cpu, 0);
 		update_process_times(user);
-                irq_exit(cpu, 0);
         }
 }
 
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/time.c linux/arch/s390/kernel/time.c
--- v2.4.12/linux/arch/s390/kernel/time.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390/kernel/time.c	Thu Oct 11 09:04:57 2001
@@ -151,15 +151,14 @@
 
 void do_timer_interrupt(struct pt_regs *regs, __u16 error_code)
 {
-        unsigned long flags;
+	int cpu = smp_processor_id();
+
+	irq_enter(cpu, 0);
 
         /*
          * reset timer to 10ms minus time already elapsed
          * since timer-interrupt pending
          */
- 
-        save_flags(flags);
-        cli();
 #ifdef CONFIG_SMP
 	if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) {
 		write_lock(&xtime_lock);
@@ -195,8 +194,8 @@
 		write_unlock(&xtime_lock);
 #endif
 	}
-        restore_flags(flags);
 
+	irq_exit(cpu, 0);
 }
 
 /*
@@ -250,4 +249,7 @@
         init_timer_cc -= 0x8126d60e46000000LL -
                          (0x3c26700LL*1000000*4096);
         tod_to_timeval(init_timer_cc, &xtime);
+
+	/* Set do_get_fast_time function pointer.  */
+	do_get_fast_time = do_gettimeofday;
 }
diff -u --recursive --new-file v2.4.12/linux/arch/s390/kernel/traps.c linux/arch/s390/kernel/traps.c
--- v2.4.12/linux/arch/s390/kernel/traps.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390/kernel/traps.c	Thu Oct 11 09:04:57 2001
@@ -60,14 +60,16 @@
 extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
 #endif
 
-spinlock_t die_lock;
+spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
         console_verbose();
         spin_lock_irq(&die_lock);
+	bust_spinlocks(1);
         printk("%s: %04lx\n", str, err & 0xffff);
         show_regs(regs);
+	bust_spinlocks(0);
         spin_unlock_irq(&die_lock);
         do_exit(SIGSEGV);
 }
@@ -135,7 +137,7 @@
 #if CONFIG_REMOTE_DEBUG
 		if(gdb_stub_initialised)
 		{
-			gdb_stub_handle_exception((gdb_pt_regs *)regs,signal);
+			gdb_stub_handle_exception((struct gdb_pt_regs *)regs,signal);
 			return 0;
 		}
 #endif
@@ -211,7 +213,7 @@
 specification_exception(struct pt_regs * regs, long interruption_code)
 {
         __u8 opcode[6];
-	__u16 *location;
+	__u16 *location = NULL;
 	int signal = 0;
 
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
diff -u --recursive --new-file v2.4.12/linux/arch/s390/math-emu/math.c linux/arch/s390/math-emu/math.c
--- v2.4.12/linux/arch/s390/math-emu/math.c	Thu Apr 12 12:16:35 2001
+++ linux/arch/s390/math-emu/math.c	Thu Oct 11 09:04:57 2001
@@ -1471,20 +1471,98 @@
 }
 
 /* Test data class long double */
-static int emu_tcxb (int rx, double *val) {
-        display_emulation_not_implemented("tcxb");
+static int emu_tcxb (int rx, long val) {
+        FP_DECL_Q(QA);
+	mathemu_ldcv cvt;
+	int bit;
+
+        cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+        FP_UNPACK_RAW_QP(QA, &cvt.ld);
+	switch (QA_e) {
+	default:
+		bit = 8;		/* normalized number */
+		break;
+	case 0:
+		if (_FP_FRAC_ZEROP_4(QA))
+			bit = 10;	/* zero */
+		else
+			bit = 6;	/* denormalized number */
+		break;
+	case _FP_EXPMAX_Q:
+		if (_FP_FRAC_ZEROP_4(QA))
+			bit = 4;	/* infinity */
+		else if (_FP_FRAC_HIGH_RAW_Q(QA) & _FP_QNANBIT_Q)
+			bit = 2;	/* quiet NAN */
+		else
+			bit = 0;	/* signaling NAN */
+		break;
+	}
+	if (!QA_s)
+		bit++;
+	emu_set_CC(((__u32) val >> bit) & 1);
         return 0;
 }
 
 /* Test data class double */
-static int emu_tcdb (int rx, double *val) {
-        display_emulation_not_implemented("tcdb");
+static int emu_tcdb (int rx, long val) {
+        FP_DECL_D(DA);
+	int bit;
+
+        FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+	switch (DA_e) {
+	default:
+		bit = 8;		/* normalized number */
+		break;
+	case 0:
+		if (_FP_FRAC_ZEROP_2(DA))
+			bit = 10;	/* zero */
+		else
+			bit = 6;	/* denormalized number */
+		break;
+	case _FP_EXPMAX_D:
+		if (_FP_FRAC_ZEROP_2(DA))
+			bit = 4;	/* infinity */
+		else if (_FP_FRAC_HIGH_RAW_D(DA) & _FP_QNANBIT_D)
+			bit = 2;	/* quiet NAN */
+		else
+			bit = 0;	/* signaling NAN */
+		break;
+	}
+	if (!DA_s)
+		bit++;
+	emu_set_CC(((__u32) val >> bit) & 1);
         return 0;
 }
 
 /* Test data class float */
-static int emu_tceb (int rx, __u32 val) {
-        display_emulation_not_implemented("tceb");
+static int emu_tceb (int rx, long val) {
+        FP_DECL_S(SA);
+	int bit;
+
+        FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+	switch (SA_e) {
+	default:
+		bit = 8;		/* normalized number */
+		break;
+	case 0:
+		if (_FP_FRAC_ZEROP_1(SA))
+			bit = 10;	/* zero */
+		else
+			bit = 6;	/* denormalized number */
+		break;
+	case _FP_EXPMAX_S:
+		if (_FP_FRAC_ZEROP_1(SA))
+			bit = 4;	/* infinity */
+		else if (_FP_FRAC_HIGH_RAW_S(SA) & _FP_QNANBIT_S)
+			bit = 2;	/* quiet NAN */
+		else
+			bit = 0;	/* signaling NAN */
+		break;
+	}
+	if (!SA_s)
+		bit++;
+	emu_set_CC(((__u32) val >> bit) & 1);
         return 0;
 }
 
@@ -1796,13 +1874,13 @@
         int _fex = 0;
 
         static const __u8 format_table[256] = {
-                [0x04] = 0x08,[0x05] = 0x07,[0x06] = 0x09,[0x07] = 0x07,
-		[0x08] = 0x03,[0x09] = 0x03,[0x0a] = 0x03,[0x0b] = 0x03,
-		[0x0c] = 0x08,[0x0d] = 0x03,[0x0e] = 0x06,[0x0f] = 0x06,
-                [0x10] = 0x03,[0x11] = 0x02,[0x12] = 0x01,[0x14] = 0x03,
-		[0x15] = 0x02,[0x17] = 0x03,[0x18] = 0x02,[0x19] = 0x02,
-		[0x1a] = 0x02,[0x1b] = 0x02,[0x1c] = 0x02,[0x1d] = 0x02,
-                [0x1e] = 0x05,[0x1f] = 0x05,
+                [0x04] = 0x06,[0x05] = 0x05,[0x06] = 0x07,[0x07] = 0x05,
+		[0x08] = 0x02,[0x09] = 0x02,[0x0a] = 0x02,[0x0b] = 0x02,
+		[0x0c] = 0x06,[0x0d] = 0x02,[0x0e] = 0x04,[0x0f] = 0x04,
+                [0x10] = 0x08,[0x11] = 0x09,[0x12] = 0x0a,[0x14] = 0x02,
+		[0x15] = 0x01,[0x17] = 0x02,[0x18] = 0x01,[0x19] = 0x01,
+		[0x1a] = 0x01,[0x1b] = 0x01,[0x1c] = 0x01,[0x1d] = 0x01,
+                [0x1e] = 0x03,[0x1f] = 0x03,
         };
         static const void *jump_table[]= {
                 [0x04] = emu_ldeb,[0x05] = emu_lxdb,[0x06] = emu_lxeb,
@@ -1817,25 +1895,7 @@
         };
 
         switch (format_table[opcode[5]]) {
-        case 1: /* RXE format, long double constant */ {
-                __u64 *dxb, temp[2];
-                __u32 opc;
-
-                if ((opcode[1] >> 4) & 2)
-			return SIGILL;
-                emu_store_regd((opcode[1] >> 4) & 15);
-                emu_store_regd(((opcode[1] >> 4) & 15) + 2);
-                opc = *((__u32 *) opcode);
-                dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
-                mathemu_copy_from_user(&temp, dxb, 16);
-                /* call the emulation function */
-                _fex = ((int (*)(int, long double *)) jump_table[opcode[5]])
-                        (opcode[1] >> 4, (long double *) &temp);
-                emu_load_regd((opcode[1] >> 4) & 15);
-                emu_load_regd(((opcode[1] >> 4) & 15) + 2);
-                break;
-        }
-        case 2: /* RXE format, double constant */ {
+        case 1: /* RXE format, double constant */ {
                 __u64 *dxb, temp;
                 __u32 opc;
 
@@ -1849,7 +1909,7 @@
                 emu_load_regd((opcode[1] >> 4) & 15);
                 break;
         }
-        case 3: /* RXE format, float constant */ {
+        case 2: /* RXE format, float constant */ {
                 __u32 *dxb, temp;
                 __u32 opc;
 
@@ -1863,27 +1923,7 @@
                 emu_load_rege((opcode[1] >> 4) & 15);
                 break;
         }
-        case 4: /* RXF format, long double constant */ {
-                __u64 *dxb, temp[2];
-                __u32 opc;
-
-                if (((opcode[1] >> 4) & 0x20) || ((opcode[4] >> 4) & 0x20))
-			return SIGILL;
-                emu_store_regd((opcode[1] >> 4) & 15);
-                emu_store_regd(((opcode[1] >> 4) & 15) + 2);
-                emu_store_regd((opcode[4] >> 4) & 15);
-                emu_store_regd(((opcode[4] >> 4) & 15) + 2);
-                opc = *((__u32 *) opcode);
-                dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
-                mathemu_copy_from_user(&temp, dxb, 16);
-                /* call the emulation function */
-                _fex = ((int (*)(int,long double *,int)) jump_table[opcode[5]])
-                        (opcode[1] >> 4, (double *) &temp, opcode[4] >> 4);
-                emu_load_regd((opcode[1] >> 4) & 15);
-                emu_load_regd(((opcode[1] >> 4) & 15) + 2);
-                break;
-        }
-        case 5: /* RXF format, double constant */ {
+        case 3: /* RXF format, double constant */ {
                 __u64 *dxb, temp;
                 __u32 opc;
 
@@ -1898,7 +1938,7 @@
                 emu_load_regd((opcode[1] >> 4) & 15);
                 break;
         }
-        case 6: /* RXF format, float constant */ {
+        case 4: /* RXF format, float constant */ {
                 __u32 *dxb, temp;
                 __u32 opc;
 
@@ -1913,7 +1953,7 @@
                 emu_load_rege((opcode[4] >> 4) & 15);
                 break;
         }
-        case 7: /* RXE format, double constant */
+        case 5: /* RXE format, double constant */
                 /* store double and load long double */ 
         {
                 __u64 *dxb, temp;
@@ -1931,7 +1971,7 @@
                 emu_load_regd(((opcode[1] >> 4) & 15) + 2);
                 break;
         }
-        case 8: /* RXE format, float constant */
+        case 6: /* RXE format, float constant */
                 /* store float and load double */ 
         {
                 __u32 *dxb, temp;
@@ -1946,7 +1986,7 @@
                 emu_load_regd((opcode[1] >> 4) & 15);
                 break;
         }
-        case 9: /* RXE format, float constant */
+        case 7: /* RXE format, float constant */
                 /* store float and load long double */ 
         {
                 __u32 *dxb, temp;
@@ -1962,6 +2002,45 @@
                         (opcode[1] >> 4, (float *) &temp);
                 emu_load_regd((opcode[1] >> 4) & 15);
                 emu_load_regd(((opcode[1] >> 4) & 15) + 2);
+                break;
+        }
+        case 8: /* RXE format, RX address used as int value */ {
+                __u64 dxb;
+                __u32 opc;
+
+                emu_store_rege((opcode[1] >> 4) & 15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
+                /* call the emulation function */
+                _fex = ((int (*)(int, long)) jump_table[opcode[5]])
+                        (opcode[1] >> 4, dxb);
+                break;
+        }
+        case 9: /* RXE format, RX address used as int value */ {
+                __u64 dxb;
+                __u32 opc;
+
+                emu_store_regd((opcode[1] >> 4) & 15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
+                /* call the emulation function */
+                _fex = ((int (*)(int, long)) jump_table[opcode[5]])
+                        (opcode[1] >> 4, dxb);
+                break;
+        }
+        case 10: /* RXE format, RX address used as int value */ {
+                __u64 dxb;
+                __u32 opc;
+
+                if ((opcode[1] >> 4) & 2)
+			return SIGILL;
+                emu_store_regd((opcode[1] >> 4) & 15);
+                emu_store_regd(((opcode[1] >> 4) & 15) + 2);
+                opc = *((__u32 *) opcode);
+                dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
+                /* call the emulation function */
+                _fex = ((int (*)(int, long)) jump_table[opcode[5]])
+                        (opcode[1] >> 4, dxb);
                 break;
         }
         default: /* invalid operation */
diff -u --recursive --new-file v2.4.12/linux/arch/s390/mm/extable.c linux/arch/s390/mm/extable.c
--- v2.4.12/linux/arch/s390/mm/extable.c	Fri May 12 11:41:45 2000
+++ linux/arch/s390/mm/extable.c	Thu Oct 11 09:04:57 2001
@@ -10,6 +10,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
 extern const struct exception_table_entry __start___ex_table[];
@@ -36,28 +37,37 @@
         return 0;
 }
 
+extern spinlock_t modlist_lock;
+
 unsigned long
 search_exception_table(unsigned long addr)
 {
-	unsigned long ret;
+	unsigned long ret = 0;
+	unsigned long flags;
 
 #ifndef CONFIG_MODULES
         addr &= 0x7fffffff;  /* remove amode bit from address */
 	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
-	if (ret) return FIX_PSW(ret);
+	if (ret) ret = FIX_PSW(ret);
+	return ret;
 #else
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
         addr &= 0x7fffffff;  /* remove amode bit from address */
+
+	spin_lock_irqsave(&modlist_lock, flags);
 	for (mp = module_list; mp != NULL; mp = mp->next) {
-		if (mp->ex_table_start == NULL)
+		if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
 			continue;
 		ret = search_one_table(mp->ex_table_start,
 				       mp->ex_table_end - 1, addr);
-		if (ret) return FIX_PSW(ret);
+		if (ret) {
+			ret = FIX_PSW(ret);
+			break;
+		}
 	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
+	return ret;
 #endif
-
-	return 0;
 }
diff -u --recursive --new-file v2.4.12/linux/arch/s390/mm/fault.c linux/arch/s390/mm/fault.c
--- v2.4.12/linux/arch/s390/mm/fault.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390/mm/fault.c	Thu Oct 11 09:04:57 2001
@@ -4,6 +4,7 @@
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Hartmut Penner (hp@de.ibm.com)
+ *               Ulrich Weigand (uweigand@de.ibm.com)
  *
  *  Derived from "arch/i386/mm/fault.c"
  *    Copyright (C) 1995  Linus Torvalds
@@ -23,6 +24,7 @@
 #include <linux/smp_lock.h>
 #include <linux/compatmac.h>
 #include <linux/init.h>
+#include <linux/console.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -34,6 +36,34 @@
 #endif
 
 extern void die(const char *,struct pt_regs *,long);
+static void force_sigsegv(struct task_struct *tsk, int code, void *address);
+
+extern spinlock_t timerlist_lock;
+
+/*
+ * Unlock any spinlocks which will prevent us from getting the
+ * message out (timerlist_lock is acquired through the
+ * console unblank code)
+ */
+void bust_spinlocks(int yes)
+{
+	spin_lock_init(&timerlist_lock);
+	if (yes) {
+		oops_in_progress = 1;
+	} else {
+		int loglevel_save = console_loglevel;
+		oops_in_progress = 0;
+		console_unblank();
+		/*
+		 * OK, the message is on the console.  Now we call printk()
+		 * without oops_in_progress set so that printk will give klogd
+		 * a poke.  Hold onto your hats...
+		 */
+		console_loglevel = 15;
+		printk(" ");
+		console_loglevel = loglevel_save;
+	}
+}
 
 /*
  * This routine handles page faults.  It determines the address,
@@ -56,18 +86,36 @@
 	int si_code = SEGV_MAPERR;
 	int kernel_address = 0;
 
+        tsk = current;
+        mm = tsk->mm;
+	
+	/* 
+         * Check for low-address protection.  This needs to be treated
+	 * as a special case because the translation exception code 
+	 * field is not guaranteed to contain valid data in this case.
+	 */
+	if ((error_code & 0xff) == 4 && !(S390_lowcore.trans_exc_code & 4)) {
+
+		/* Low-address protection hit in kernel mode means 
+		   NULL pointer write access in kernel mode.  */
+ 		if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
+			address = 0;
+			kernel_address = 1;
+			goto no_context;
+		}
+
+		/* Low-address protection hit in user mode 'cannot happen'.  */
+		die ("Low-address protection", regs, error_code);
+        	do_exit(SIGKILL);
+	}
+
         /* 
          * get the failing address 
          * more specific the segment and page table portion of 
          * the address 
          */
-        address = S390_lowcore.trans_exc_code&0x7ffff000;
 
-        tsk = current;
-        mm = tsk->mm;
-
-        if (in_interrupt() || !mm)
-                goto no_context;
+        address = S390_lowcore.trans_exc_code&0x7ffff000;
 
 
 	/*
@@ -99,6 +147,7 @@
 			}
 		}
 		die("page fault via unknown access register", regs, error_code);
+        	do_exit(SIGKILL);
 		break;
 
 	case 2: /* Secondary Segment Table Descriptor */
@@ -107,6 +156,11 @@
 		break;
 	}
 
+	/*
+	 * Check whether we have a user MM in the first place.
+	 */
+        if (in_interrupt() || !mm)
+                goto no_context;
 
 	/*
 	 * When we get here, the fault happened in the current
@@ -146,6 +200,7 @@
                        goto bad_area;
         }
 
+ survive:
 	/*
 	 * If for any reason at all we couldn't handle the fault,
 	 * make sure we exit gracefully rather than endlessly redo
@@ -176,7 +231,6 @@
 
         /* User mode accesses just cause a SIGSEGV */
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
-		struct siginfo si;
                 tsk->thread.prot_addr = address;
                 tsk->thread.trap_no = error_code;
 #ifndef CONFIG_SYSCTL
@@ -193,10 +247,8 @@
 			show_regs(regs);
 		}
 #endif
-		si.si_signo = SIGSEGV;
-		si.si_code = si_code;
-		si.si_addr = (void*) address;
-		force_sig_info(SIGSEGV, &si, tsk);
+
+		force_sigsegv(tsk, si_code, (void *)address);
                 return;
 	}
 
@@ -218,9 +270,6 @@
         else
                 printk(KERN_ALERT "Unable to handle kernel paging request"
 		       " at virtual user address %08lx\n", address);
-/*
- * need to define, which information is useful here
- */
 
         die("Oops", regs, error_code);
         do_exit(SIGKILL);
@@ -232,6 +281,12 @@
 */
 out_of_memory:
 	up_read(&mm->mmap_sem);
+	if (tsk->pid == 1) {
+		tsk->policy |= SCHED_YIELD;
+		schedule();
+		down_read(&mm->mmap_sem);
+		goto survive;
+	}
 	printk("VM: killing process %s\n", tsk->comm);
 	if (regs->psw.mask & PSW_PROBLEM_STATE)
 		do_exit(SIGKILL);
@@ -253,6 +308,18 @@
 		goto no_context;
 }
 
+/*
+ * Send SIGSEGV to task.  This is an external routine
+ * to keep the stack usage of do_page_fault small.
+ */
+static void force_sigsegv(struct task_struct *tsk, int code, void *address)
+{
+	struct siginfo si;
+	si.si_signo = SIGSEGV;
+	si.si_code = code;
+	si.si_addr = address;
+	force_sig_info(SIGSEGV, &si, tsk);
+}
 
 typedef struct _pseudo_wait_t {
        struct _pseudo_wait_t *next;
@@ -434,7 +501,6 @@
 asmlinkage void
 pfault_interrupt(struct pt_regs *regs, __u16 error_code)
 {
-        DECLARE_WAITQUEUE(wait, current);
 	struct task_struct *tsk;
 	wait_queue_head_t queue;
 	wait_queue_head_t *qp;
@@ -447,7 +513,7 @@
          * external interrupt. 
 	 */
 	subcode = S390_lowcore.cpu_addr;
-	if ((subcode & 0xff00) != 0x06)
+	if ((subcode & 0xff00) != 0x0600)
 		return;
 
 	/*
diff -u --recursive --new-file v2.4.12/linux/arch/s390/mm/init.c linux/arch/s390/mm/init.c
--- v2.4.12/linux/arch/s390/mm/init.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/s390/mm/init.c	Thu Oct 11 09:04:57 2001
@@ -44,44 +44,23 @@
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 
-static int test_access(unsigned long loc)
-{
-	static const int ssm_mask = 0x07000000L;
-	int rc, i;
-
-        rc = 0;
-	for (i=0; i<4; i++) {
-		__asm__ __volatile__(
-                        "    slr   %0,%0\n"
-			"    ssm   %1\n"
-			"    tprot 0(%2),0\n"
-			"0:  jne   1f\n"
-			"    lhi   %0,1\n"
-			"1:  ssm   %3\n"
-                        ".section __ex_table,\"a\"\n"
-                        "   .align 4\n"
-                        "   .long  0b,1b\n"
-                        ".previous"
-			: "+&d" (rc) : "i" (0), "a" (loc), "m" (ssm_mask)
-			: "cc");
-		if (rc == 0)
-			break;
-		loc += 0x100000;
-	}
-	return rc;
-}
-
 int do_check_pgt_cache(int low, int high)
 {
         int freed = 0;
         if(pgtable_cache_size > high) {
                 do {
-                        if(pgd_quicklist)
-                                free_pgd_slow(get_pgd_fast()), freed += 2;
-                        if(pmd_quicklist)
-                                pmd_free_slow(pmd_alloc_one_fast(NULL, 0)), freed++;
-                        if(pte_quicklist)
-                                pte_free_slow(pte_alloc_one_fast(NULL, 0)), freed++;
+                        if(pgd_quicklist) {
+                                free_pgd_slow(get_pgd_fast());
+				freed += 2;
+			}
+                        if(pmd_quicklist) {
+                                pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
+				freed++;
+			}
+                        if(pte_quicklist) {
+                                pte_free_slow(pte_alloc_one_fast(NULL, 0));
+				freed++;
+			}
                 } while(pgtable_cache_size > low);
         }
         return freed;
@@ -200,7 +179,6 @@
 void __init mem_init(void)
 {
 	int codesize, reservedpages, datasize, initsize;
-        int tmp;
 
         max_mapnr = num_physpages = max_low_pfn;
         high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
@@ -211,24 +189,7 @@
 	/* this will put all low memory onto the freelists */
 	totalram_pages += free_all_bootmem();
 
-        /* mark usable pages in the mem_map[] and count reserved pages */
 	reservedpages = 0;
-	tmp = 0;
-	do {
-		if (tmp && (tmp & 0x3ff) == 0 && 
-                    test_access(tmp * PAGE_SIZE) == 0) {
-                        printk("4M Segment %lX not available\n",tmp*PAGE_SIZE);
-			do {
-                                set_bit(PG_reserved, &mem_map[tmp].flags);
-				reservedpages++;
-				tmp++;
-			} while (tmp < max_low_pfn && (tmp & 0x3ff));
-		} else {
-			if (PageReserved(mem_map+tmp))
-				reservedpages++;
-			tmp++;
-		}
-	} while (tmp < max_low_pfn);
 
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/Makefile linux/arch/s390x/Makefile
--- v2.4.12/linux/arch/s390x/Makefile	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390x/Makefile	Thu Oct 11 09:04:57 2001
@@ -52,16 +52,6 @@
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
-MAKESILO = $(MAKE) -C arch/$(ARCH)/tools/silo
-
-MAKEDASDFMT = $(MAKE) -C arch/$(ARCH)/tools/dasdfmt
-
-silo:
-	@$(MAKE) -C arch/$(ARCH)/tools/silo
-
-dasdfmt:
-	@$(MAKE) -C arch/$(ARCH)/tools/dasdfmt
-
 image: vmlinux 
 	@$(MAKEBOOT) image
 
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/config.in linux/arch/s390x/config.in
--- v2.4.12/linux/arch/s390x/config.in	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390x/config.in	Thu Oct 11 09:04:57 2001
@@ -8,6 +8,7 @@
 define_bool CONFIG_MCA n
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+define_bool CONFIG_GENERIC_BUST_SPINLOCK n
 
 mainmenu_name "Linux Kernel Configuration"
 define_bool CONFIG_ARCH_S390 y
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/defconfig linux/arch/s390x/defconfig
--- v2.4.12/linux/arch/s390x/defconfig	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390x/defconfig	Thu Oct 11 09:04:57 2001
@@ -6,6 +6,7 @@
 # CONFIG_MCA is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_GENERIC_BUST_SPINLOCK=n
 CONFIG_ARCH_S390=y
 CONFIG_ARCH_S390X=y
 
@@ -72,6 +73,7 @@
 CONFIG_MD_RAID0=m
 CONFIG_MD_RAID1=m
 CONFIG_MD_RAID5=m
+# CONFIG_MD_MULTIPATH is not set
 CONFIG_BLK_DEV_LVM=m
 
 #
@@ -247,6 +249,7 @@
 CONFIG_IBM_PARTITION=y
 # CONFIG_MAC_PARTITION is not set
 # CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/Makefile linux/arch/s390x/kernel/Makefile
--- v2.4.12/linux/arch/s390x/kernel/Makefile	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/Makefile	Thu Oct 11 09:04:57 2001
@@ -12,12 +12,14 @@
 
 all: kernel.o head.o init_task.o
 
-O_TARGET := kernel.o
+O_TARGET	:= kernel.o
 
-export-objs	:= debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o
-obj-y	:= lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \
-            setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
-            semaphore.o s390fpu.o reipl.o s390_ext.o debug.o
+export-objs	:= debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o \
+		   exec32.o
+
+obj-y		:= entry.o bitmap.o traps.o time.o process.o irq.o \
+		   setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
+		   semaphore.o s390fpu.o reipl.o s390_ext.o debug.o
 
 obj-$(CONFIG_MODULES)		+= s390_ksyms.o
 obj-$(CONFIG_SMP)		+= smp.o
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/cpcmd.c linux/arch/s390x/kernel/cpcmd.c
--- v2.4.12/linux/arch/s390x/kernel/cpcmd.c	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/cpcmd.c	Thu Oct 11 09:04:57 2001
@@ -6,21 +6,25 @@
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  */
 
-#include <linux/stddef.h>
-#include <linux/kernel.h>
 #include <linux/string.h>
-#include <asm/ebcdic.h>
+#include <linux/spinlock.h>
 #include <asm/cpcmd.h>
+#include <asm/ebcdic.h>
+#include <asm/system.h>
+
+static spinlock_t cpcmd_lock = SPIN_LOCK_UNLOCKED;
+static char cpcmd_buf[128];
 
 void cpcmd(char *cmd, char *response, int rlen)
 {
         const int mask = 0x40000000L;
-        char obuffer[128];
-        int olen;
+	unsigned long flags;
+        int cmdlen;
 
-        olen = strlen(cmd);
-        strcpy(obuffer, cmd);
-        ASCEBC(obuffer,olen);
+	spin_lock_irqsave(&cpcmd_lock, flags);
+        cmdlen = strlen(cmd);
+        strcpy(cpcmd_buf, cmd);
+        ASCEBC(cpcmd_buf, cmdlen);
 
         if (response != NULL && rlen > 0) {
                 asm volatile ("   lrag  2,0(%0)\n"
@@ -32,7 +36,7 @@
                               "   .long 0x83240008 # Diagnose 83\n"
                               "   sam64"
                               : /* no output */
-                              : "a" (obuffer), "d" (olen),
+                              : "a" (cpcmd_buf), "d" (cmdlen),
                                 "a" (response), "d" (rlen), "m" (mask)
                               : "2", "3", "4", "5" );
                 EBCASC(response, rlen);
@@ -43,8 +47,9 @@
                               "   .long 0x83230008 # Diagnose 83\n"
                               "   sam64"
                               : /* no output */
-                              : "a" (obuffer), "d" (olen)
+                              : "a" (cpcmd_buf), "d" (cmdlen)
                               : "2", "3"  );
         }
+	spin_unlock_irqrestore(&cpcmd_lock, flags);
 }
 
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/debug.c linux/arch/s390x/kernel/debug.c
--- v2.4.12/linux/arch/s390x/kernel/debug.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390x/kernel/debug.c	Thu Oct 11 09:04:57 2001
@@ -83,6 +83,9 @@
 static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
 				struct file *file, const char *user_buf,
 				size_t user_buf_size, loff_t * offset);
+static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
+                                struct file *file, const char *user_buf,
+                                size_t user_buf_size, loff_t * offset);
 static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
                                 char *out_buf, const char *in_buf);
 static int debug_raw_format_fn(debug_info_t * id,
@@ -123,6 +126,15 @@
 	NULL
 };
 
+struct debug_view debug_flush_view = {
+        "flush",
+        NULL,
+        NULL,
+        NULL,
+        &debug_input_flush_fn,
+        NULL
+};
+
 struct debug_view debug_sprintf_view = {
 	"sprintf",
 	NULL,
@@ -664,6 +676,7 @@
 	if(!rc) 
 		goto out;
 	debug_register_view(rc, &debug_level_view);
+        debug_register_view(rc, &debug_flush_view);
 	printk(KERN_INFO
 	       "debug: reserved %d areas of %d pages for debugging %s\n",
 	       nr_areas, 1 << page_order, rc->name);
@@ -1027,6 +1040,73 @@
       out:
 	*offset += in_buf_size;
 	return rc;		/* number of input characters */
+}
+
+
+/*
+ * flushes debug areas
+ */
+ 
+void debug_flush(debug_info_t* id, int area)
+{
+        unsigned long flags;
+        int i;
+
+        if(!id)
+                return;
+        spin_lock_irqsave(&id->lock,flags);
+        if(area == DEBUG_FLUSH_ALL){
+                id->active_area = 0;
+                memset(id->active_entry, 0, id->nr_areas * sizeof(int));
+                for (i = 0; i < id->nr_areas; i++) 
+                        memset(id->areas[i], 0, PAGE_SIZE << id->page_order);
+                printk(KERN_INFO "debug: %s: all areas flushed\n",id->name);
+        } else if(area >= 0 && area < id->nr_areas) {
+                id->active_entry[area] = 0;
+                memset(id->areas[area], 0, PAGE_SIZE << id->page_order);
+                printk(KERN_INFO
+                        "debug: %s: area %i has been flushed\n",
+                        id->name, area);
+        } else {
+                printk(KERN_INFO
+                        "debug: %s: area %i cannot be flushed (range: %i - %i)\n",
+                        id->name, area, 0, id->nr_areas-1);
+        }
+        spin_unlock_irqrestore(&id->lock,flags);
+}
+
+/*
+ * view function: flushes debug areas 
+ */
+ 
+static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
+                                struct file *file, const char *user_buf,
+                                size_t in_buf_size, loff_t * offset)
+{
+        char input_buf[1];
+        int rc = in_buf_size;
+ 
+        if (*offset != 0)
+                goto out;
+        if (copy_from_user(input_buf, user_buf, 1)){
+                rc = -EFAULT;
+                goto out;
+        }
+        if(input_buf[0] == '-') { 
+                debug_flush(id, DEBUG_FLUSH_ALL);
+                goto out;
+        }
+        if (isdigit(input_buf[0])) {
+                int area = ((int) input_buf[0] - (int) '0');
+                debug_flush(id, area);
+                goto out;
+        }
+
+        printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]);
+
+      out:
+        *offset += in_buf_size;
+        return rc;              /* number of input characters */
 }
 
 /*
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/entry.S linux/arch/s390x/kernel/entry.S
--- v2.4.12/linux/arch/s390x/kernel/entry.S	Tue Oct  9 17:06:51 2001
+++ linux/arch/s390x/kernel/entry.S	Thu Oct 11 09:04:57 2001
@@ -89,17 +89,25 @@
  *    R15 - kernel stack pointer
  */
 
-        .macro  SAVE_ALL psworg          # system entry macro
+        .macro  SAVE_ALL psworg,sync     # system entry macro
         stmg    %r14,%r15,__LC_SAVE_AREA
-        stam    %a2,%a4,__LC_SAVE_AREA+16
         tm      \psworg+1,0x01           # test problem state bit
-        jz      0f                       # skip stack setup save
-        lg      %r15,__LC_KERNEL_STACK   # problem state -> load ksp
-        slr     %r14,%r14
-        sar     %a2,%r14                 # set ac.reg. 2 to primary space
-        lhi     %r14,1
-        sar     %a4,%r14                 # set access reg. 4 to home space
-0:      aghi    %r15,-SP_SIZE            # make room for registers & psw
+	stam    %a2,%a4,__LC_SAVE_AREA+16
+	.if	\sync
+        jz      1f                       # skip stack setup save
+	.else
+	jnz	0f			 # from user -> load kernel stack
+	lg	%r14,__LC_ASYNC_STACK	 # are we already on the async. stack ?
+	slgr	%r14,%r15
+	srag	%r14,%r14,14
+	jz	1f
+	lg	%r15,__LC_ASYNC_STACK	 # load async. stack
+	j	1f
+	.endif
+0:	lg      %r15,__LC_KERNEL_STACK   # problem state -> load ksp
+	larl	%r14,.Lc_ac
+	lam	%a2,%a4,0(%r14)
+1:      aghi    %r15,-SP_SIZE            # make room for registers & psw
         nill    %r15,0xfff8              # align stack pointer to 8
         stmg    %r0,%r14,SP_R0(%r15)     # store gprs 0-14 to kernel stack
         stg     %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
@@ -112,7 +120,7 @@
         xc      0(8,%r15),0(%r15)        # clear back chain
         .endm
 
-        .macro  RESTORE_ALL              # system exit macro
+        .macro  RESTORE_ALL sync         # system exit macro
         mvc     __LC_RETURN_PSW(16),SP_PSW(%r15) # move user PSW to lowcore
         lam     %a0,%a15,SP_AREGS(%r15)  # load the access registers
         lmg     %r0,%r15,SP_R0(%r15)     # load gprs 0-15 of user
@@ -121,8 +129,8 @@
         .endm
 
         .macro  GET_CURRENT
-        lghi    %r9,-16384               # load pointer to task_struct to %r9
-        ngr     %r9,15
+	lg	%r9,__LC_KERNEL_STACK    # load pointer to task_struct to %r9
+	aghi	%r9,-16384
         .endm
 
 
@@ -161,13 +169,32 @@
         br      %r14
 
 /*
+ * do_softirq calling function. We want to run the softirq functions on the
+ * asynchronous interrupt stack.
+ */
+	.global do_call_softirq
+do_call_softirq:
+	stmg	%r12,%r15,48(%r15)
+	lgr	%r12,%r15
+	lg	%r0,__LC_ASYNC_STACK
+	slgr    %r0,%r15
+	srag	%r0,%r0,14
+	je	0f
+	lg	%r15,__LC_ASYNC_STACK
+0:	aghi	%r15,-STACK_FRAME_OVERHEAD
+	stg	%r12,0(%r15)		# store back chain
+	brasl	%r14,do_softirq
+	lmg	%r12,%r15,48(%r12)
+	br	%r14
+	
+/*
  * SVC interrupt handler routine. System calls are synchronous events and
  * are executed with interrupts enabled.
  */
 
 	.globl  system_call
 system_call:
-        SAVE_ALL __LC_SVC_OLD_PSW
+        SAVE_ALL __LC_SVC_OLD_PSW,1
 	mvi     SP_PGM_OLD_ILC(%r15),1  # mark PGM_OLD_ILC as invalid
 pgm_system_call:
         GET_CURRENT               # load pointer to task_struct to R9
@@ -202,7 +229,7 @@
         tm      SP_PGM_OLD_ILC(%r15),0xff
         jz      pgm_svcret
 	stnsm   48(%r15),0xfc         # disable I/O and ext. interrupts
-        RESTORE_ALL
+        RESTORE_ALL 1
 
 #
 # call do_signal before return
@@ -565,9 +592,9 @@
 	.long  SYSCALL(sys_mmap2,sys32_mmap2_wrapper)
 	.long  SYSCALL(sys_ni_syscall,sys32_truncate64_wrapper)
         .long  SYSCALL(sys_ni_syscall,sys32_ftruncate64_wrapper)
-        .long  SYSCALL(sys_ni_syscall,sys32_stat64)     /* 195 */
-        .long  SYSCALL(sys_ni_syscall,sys32_lstat64)   
-        .long  SYSCALL(sys_ni_syscall,sys32_fstat64)    
+        .long  SYSCALL(sys_ni_syscall,sys32_stat64_wrapper)     /* 195 */
+        .long  SYSCALL(sys_ni_syscall,sys32_lstat64_wrapper)   
+        .long  SYSCALL(sys_ni_syscall,sys32_fstat64_wrapper)    
 	.long  SYSCALL(sys_lchown,sys32_lchown_wrapper)
 	.long  SYSCALL(sys_getuid,sys_getuid)
 	.long  SYSCALL(sys_getgid,sys_getgid)         /* 200 */
@@ -592,7 +619,10 @@
         .long  SYSCALL(sys_madvise,sys32_madvise_wrapper)
 	.long  SYSCALL(sys_getdents64,sys32_getdents64_wrapper)/* 220 */
 	.long  SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper)
-        .rept  255-221
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 222 - reserved for posix_acl */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 223 - reserved for posix_acl */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 224 - reserved for posix_acl */
+        .rept  255-224
 	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
 	.endr
 
@@ -626,7 +656,7 @@
 	lpswe   __LC_PGM_OLD_PSW
 # it was a single stepped SVC that is causing all the trouble
 pgm_svcper:
-	SAVE_ALL __LC_SVC_OLD_PSW
+	SAVE_ALL __LC_SVC_OLD_PSW,1
         mvc     SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information
         j       pgm_system_call          # now do the svc
 pgm_svcret:
@@ -636,7 +666,7 @@
         mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
 	j       pgm_no_sv
 pgm_sv:
-	SAVE_ALL __LC_PGM_OLD_PSW
+	SAVE_ALL __LC_PGM_OLD_PSW,1
         mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
         llgh    %r7,__LC_PGM_ILC         # load instruction length
 	GET_CURRENT
@@ -668,7 +698,7 @@
  */
         .globl io_int_handler
 io_int_handler:
-        SAVE_ALL __LC_IO_OLD_PSW
+        SAVE_ALL __LC_IO_OLD_PSW,0
         GET_CURRENT                    # load pointer to task_struct to R9
         la      %r2,SP_PTREGS(%r15)    # address of register-save area
 	llgh    %r3,__LC_SUBCHANNEL_NR # load subchannel number
@@ -701,7 +731,7 @@
         jnz     io_signal_return
 io_leave:
         stnsm   48(%r15),0xfc          # disable I/O and ext. interrupts
-        RESTORE_ALL
+        RESTORE_ALL 0
 
 #
 # call do_softirq and return from syscall, if interrupt-level
@@ -732,7 +762,7 @@
  */
         .globl  ext_int_handler
 ext_int_handler:
-        SAVE_ALL __LC_EXT_OLD_PSW
+        SAVE_ALL __LC_EXT_OLD_PSW,0
         GET_CURRENT                    # load pointer to task_struct to R9
         la      %r2,SP_PTREGS(%r15)    # address of register-save area
         llgh    %r3,__LC_EXT_INT_CODE  # error code
@@ -760,10 +790,10 @@
  */
         .globl mcck_int_handler
 mcck_int_handler:
-        SAVE_ALL __LC_MCK_OLD_PSW
+        SAVE_ALL __LC_MCK_OLD_PSW,0
 	brasl   %r14,s390_do_machine_check
 mcck_return:
-        RESTORE_ALL
+        RESTORE_ALL 0
 
 #ifdef CONFIG_SMP
 /*
@@ -771,10 +801,10 @@
  */
         .globl restart_int_handler
 restart_int_handler:
-        lg      %r15,__LC_KERNEL_STACK # load ksp
-        lhi     %r10,__LC_CREGS_SAVE_AREA
+        lg      %r15,__LC_SAVE_AREA+120 # load ksp
+        lghi    %r10,__LC_CREGS_SAVE_AREA
         lctlg   %c0,%c15,0(%r10) # get new ctl regs
-        lhi     %r10,__LC_AREGS_SAVE_AREA
+        lghi    %r10,__LC_AREGS_SAVE_AREA
         lam     %a0,%a15,0(%r10)
         stosm   0(%r15),0x04           # now we can turn dat on
         lmg     %r6,%r15,48(%r15)      # load registers from clone
@@ -794,3 +824,8 @@
 restart_go:
 #endif
 
+/*
+ * Integer constants
+ */
+               .align 4
+.Lc_ac:        .long  0,0,1
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/head.S linux/arch/s390x/kernel/head.S
--- v2.4.12/linux/arch/s390x/kernel/head.S	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390x/kernel/head.S	Thu Oct 11 09:04:57 2001
@@ -261,7 +261,7 @@
 	l     %r1,0xb8                         # load ipl subchannel number
         la    %r2,IPL_BS                       # load start address
         bas   %r14,.Lloader                    # load rest of ipl image
-        larl  %r12,parmarea                    # pointer to parameter area
+        larl  %r12,_pstart                     # pointer to parameter area
         st    %r1,IPL_DEVICE+4-PARMAREA(%r12)  # store ipl device number
 
 #
@@ -464,7 +464,7 @@
         sigp  %r1,%r0,0x12               # switch to esame mode
 	sam64				 # switch to 64 bit mode
 	lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
-	larl  %r12,parmarea              # pointer to parameter area
+	larl  %r12,_pstart               # pointer to parameter area
 					 # move IPL device to lowcore
         mvc   __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
 					 # set program check new psw mask
@@ -472,42 +472,64 @@
 
 
 #
-# find out memory size.
+# find memory chunks.
 #
-	la    %r1,1f-.LPG1(%r13)         # set program check address
+	larl  %r1,.Lchkmem               # set program check address
 	stg   %r1,__LC_PGM_NEW_PSW+8
-        lghi  %r2,1
-        sllg  %r2,%r2,17                 # test in increments of 128KB
-	lgr   %r1,%r2
-	aghi  %r1,-8                     # test last word in the segment
-0:	lg    %r0,0(%r1)                 # test 128KB segment
-        stg   %r0,0(%r1)
-	algr  %r1,%r2                    # add 128KB
-	bc    12,0b-.LPG1(%r13)          # r1 < 2^64 -> loop
-1:	ng    %r1,.L4malign-.LPG1(%r13)  # align to multiples of 4M
-	larl  %r3,memory_size-.
-	stg   %r1,0(%r3)                 # store memory size
-#
-# find out memory size part 2. Running native the HSA is located at
-# 2GB and we will get an addressing exception trying to access it.
-# We have to restart the scan at 2GB to find out if the machine has
-# more than 2GB of storage.
-#
-	la    %r1,1f-.LPG1(%r13)         # set program check address
-	stg   %r1,__LC_PGM_NEW_PSW+8
-	lg    %r1,.Lscan2g-.LPG1(%r13)   # restart scanning @ 2GB + 128K - 8
-0:	lg    %r0,0(%r1)                 # test 128KB segment
-	stg   %r0,0(%r1)
-	algr  %r1,%r2                    # add 128 KB
-	bc    12,0b-.LPG1(%r13)          # r1 < 2^64 -> loop
-1:	clg   %r1,.Lscan2g-.LPG1(%r13)   # program check @ 2GB + 128K - 8 ?
-	be    2f-.LPG1(%r13)
-	ng    %r1,.L4malign-.LPG1(%r13)  # align to multiples of 4M
-	larl  %r3,memory_size-.
-	stg   %r1,0(%r3)                 # store memory size
-2:
+	la    %r1,1                      # test in increments of 128KB
+	sllg  %r1,%r1,17
+	larl  %r3,memory_chunk
+	slgr  %r4,%r4                    # set start of chunk to zero
+	slgr  %r5,%r5                    # set end of chunk to zero
+	slr  %r6,%r6			 # set access code to zero
+.Lloop:
+	tprot 0(%r5),0			 # test protection of first byte
+	ipm   %r7
+	srl   %r7,28
+	clr   %r6,%r7			 # compare cc with last access code
+	je    .Lsame
+	clgr  %r4,%r5			 # chunk size > 0?
+	je    .Lsize0
+	stg   %r4,0(%r3)		 # store start address of chunk
+	lgr   %r0,%r5
+	slgr  %r0,%r4
+	stg   %r0,8(%r3)		 # store size of chunk
+	st    %r6,20(%r3)		 # store type of chunk
+	la    %r3,24(%r3)
+	lgr   %r4,%r5			 # set start to end
+	larl  %r8,memory_size
+	stg   %r5,0(%r8)                 # store memory size
+.Lsize0:
+	lr    %r6,%r7			 # set access code to last cc
+.Lsame:
+	algr  %r5,%r1			 # add 128KB to end of chunk
+	brc   12,.Lloop
+.Lchkmem:				 # > 16EB or tprot got a program check
+	clgr  %r4,%r5			 # chunk size > 0?
+	je    .Ldonemem
+	stg   %r4,0(%r3)		 # store start address of chunk
+	lgr   %r0,%r5
+	slgr  %r0,%r4
+	stg   %r0,8(%r3)		 # store size of chunk
+	st    %r6,20(%r3)		 # store type of chunk
+	la    %r3,24(%r3)
+	lgr   %r4,%r5
+	larl  %r8,memory_size
+	stg   %r5,0(%r8)                 # store memory size
+#
+# Running native the HSA is located at 2GB and we will get an
+# addressing exception trying to access it. We have to restart
+# the scan at 2GB to find out if the machine has more than 2GB.
+#
+	lghi  %r4,1
+	sllg  %r4,%r4,31
+	clgr  %r5,%r4
+	jhe   .Ldonemem
+	lgr   %r5,%r4
+	j     .Lloop
+.Ldonemem:		
 
-	larl  %r12,machine_flags-.
+	larl  %r12,machine_flags
 #
 # find out if we are running under VM
 #
@@ -539,7 +561,7 @@
 .Lentry:.quad  0x0000000180000000,_stext
 .Lctl:  .quad  0x04b50002               # cr0: various things
         .quad  0                        # cr1: primary space segment table
-        .quad  0                        # cr2: access register translation
+        .quad  .Lduct                   # cr2: dispatchable unit control table
         .quad  0                        # cr3: instruction authorization
         .quad  0                        # cr4: instruction authorization
         .quad  0                        # cr5:  various things
@@ -557,11 +579,16 @@
 .L4malign:.quad 0xffffffffffc00000
 .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
 
+	.org PARMAREA-64
+.Lduct:	.long 0,0,0,0,0,0,0,0
+	.long 0,0,0,0,0,0,0,0
+
 #
 # params at 10400 (setup.h)
 #
 	.org   PARMAREA
-parmarea:
+	.global _pstart
+_pstart:
 	.quad  0                        # IPL_DEVICE
         .quad  RAMDISK_ORIGIN           # INITRD_START
         .quad  RAMDISK_SIZE             # INITRD_SIZE
@@ -569,31 +596,28 @@
         .org   COMMAND_LINE
     	.byte  "root=/dev/ram0 ro"
         .byte  0
+	.org   0x11000
+	.global _pend
+_pend:	
 
-#
-# startup-code, running in virtual mode
-#
 #ifdef CONFIG_SHARED_KERNEL
 	.org   0x100000
-#else
-        .org   0x10800
 #endif
+	
+#
+# startup-code, running in virtual mode
+#
         .globl _stext
 _stext:	basr  %r13,0                    # get base
 .LPG2:
 #
-# Setup lowcore
+# Setup stack
 #
-        l     %r1,__LC_IPLDEV           # load ipl device number
-        spx   .Lprefix-.LPG2(%r13)      # set prefix to linux lowcore
-        st    %r1,__LC_IPLDEV           # store ipl device number
 	larl  %r15,init_task_union
         aghi  %r15,16384                # init_task_union + 16384
         stg   %r15,__LC_KERNEL_STACK    # set end of kernel stack
         aghi  %r15,-160
         xc    0(8,%r15),0(%r15)         # set backchain to zero
-        lghi  %r0,-1
-        stg   %r0,__LC_KERNEL_LEVEL     # set interrupt count to -1
 #
 # clear bss memory
 #
@@ -621,6 +645,5 @@
 #
             .align 8
 .Ldw:       .quad  0x0002000180000000,0x0000000000000000
-.Lprefix:   .long  init_S390_lowcore	
 .Laregs:    .long  0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
 
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/ioctl32.c linux/arch/s390x/kernel/ioctl32.c
--- v2.4.12/linux/arch/s390x/kernel/ioctl32.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/s390x/kernel/ioctl32.c	Thu Oct 11 09:04:57 2001
@@ -27,6 +27,7 @@
 #include <asm/types.h>
 #include <asm/uaccess.h>
 #include <asm/dasd.h>
+#include <asm/sockios.h>
 
 #include "linux32.h"
 
@@ -451,6 +452,8 @@
 	IOCTL32_DEFAULT(VT_RESIZEX),
 	IOCTL32_DEFAULT(VT_LOCKSWITCH),
 	IOCTL32_DEFAULT(VT_UNLOCKSWITCH),
+
+	IOCTL32_DEFAULT(SIOCGSTAMP),
 
 	IOCTL32_HANDLER(SIOCGIFNAME, dev_ifname32),
 	IOCTL32_HANDLER(SIOCGIFCONF, dev_ifconf),
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/linux32.c linux/arch/s390x/kernel/linux32.c
--- v2.4.12/linux/arch/s390x/kernel/linux32.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/s390x/kernel/linux32.c	Thu Oct 11 09:04:57 2001
@@ -2884,7 +2884,7 @@
 			err = copy_from_user(kaddr + offset, (char *)A(str),
 					     bytes_to_copy);
 			flush_page_to_ram(page);
-			kunmap((unsigned long)kaddr);
+			kunmap(page);
 
 			if (err)
 				return -EFAULT;
@@ -4038,57 +4038,55 @@
 }
 
 struct stat64_emu31 {
-        unsigned short  st_dev;
-        unsigned char   __pad0[6];
-
-        long long	st_ino;
-        unsigned int    st_mode;
-        unsigned int    st_nlink;
-
-        __u32		st_uid;
-        __u32		st_gid;
-
-        unsigned short  st_rdev;
-        unsigned char   __pad3[10];
-
-        long long       st_size;
-        __u32		st_blksize;
-
-        __u32		st_blocks;      /* Number 512-byte blocks allocated. */
-        __u32		__pad4;         /* future possible st_blocks high bits */
-
-        __u32		st_atime;
-        __u32		__pad5;
-
-        __u32		st_mtime;
-        __u32		__pad6;
-
-        __u32		st_ctime;
-        __u32		__pad7;         /* will be high 32 bits of ctime someday */
-
-        __u32		__unused1;
-        __u32		__unused2;
-};
+	unsigned char   __pad0[6];
+	unsigned short  st_dev;
+	unsigned int    __pad1;
+#define STAT64_HAS_BROKEN_ST_INO        1
+	u32             __st_ino;
+	unsigned int    st_mode;
+	unsigned int    st_nlink;
+	u32             st_uid;
+	u32             st_gid;
+	unsigned char   __pad2[6];
+	unsigned short  st_rdev;
+	unsigned int    __pad3;
+	long            st_size;
+	u32             st_blksize;
+	unsigned char   __pad4[4];
+	u32             __pad5;     /* future possible st_blocks high bits */
+	u32             st_blocks;  /* Number 512-byte blocks allocated. */
+	u32             st_atime;
+	u32             __pad6;
+	u32             st_mtime;
+	u32             __pad7;
+	u32             st_ctime;
+	u32             __pad8;     /* will be high 32 bits of ctime someday */
+	unsigned long   st_ino;
+};	
 
 static inline int
 putstat64 (struct stat64_emu31 *ubuf, struct stat *kbuf)
 {
-    int err;
-    
-    err = put_user (kbuf->st_dev, &ubuf->st_dev);
-    err |= __put_user (kbuf->st_ino, &ubuf->st_ino);
-    err |= __put_user (kbuf->st_mode, &ubuf->st_mode);
-    err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink);
-    err |= __put_user (kbuf->st_uid, &ubuf->st_uid);
-    err |= __put_user (kbuf->st_gid, &ubuf->st_gid);
-    err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev);
-    err |= __put_user (kbuf->st_size, &ubuf->st_size);
-    err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize);
-    err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks);
-    err |= __put_user (kbuf->st_atime, &ubuf->st_atime);
-    err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime);
-    err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime);
-    return err;
+    struct stat64_emu31 tmp;
+   
+    memset(&tmp, 0, sizeof(tmp));
+
+    tmp.st_dev = (unsigned short)kbuf->st_dev;
+    tmp.st_ino = kbuf->st_ino;
+    tmp.__st_ino = (u32)kbuf->st_ino;
+    tmp.st_mode = kbuf->st_mode;
+    tmp.st_nlink = (unsigned int)kbuf->st_nlink;
+    tmp.st_uid = kbuf->st_uid;
+    tmp.st_gid = kbuf->st_gid;
+    tmp.st_rdev = (unsigned short)kbuf->st_rdev;
+    tmp.st_size = kbuf->st_size;
+    tmp.st_blksize = (u32)kbuf->st_blksize;
+    tmp.st_blocks = (u32)kbuf->st_blocks;
+    tmp.st_atime = (u32)kbuf->st_atime;
+    tmp.st_mtime = (u32)kbuf->st_mtime;
+    tmp.st_ctime = (u32)kbuf->st_ctime;
+
+    return copy_to_user(ubuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 
 }
 
 extern asmlinkage long sys_newstat(char * filename, struct stat * statbuf);
@@ -4131,7 +4129,7 @@
 	    return err;
 
     set_fs (KERNEL_DS);
-    ret = sys_newstat(tmp, &s);
+    ret = sys_newlstat(tmp, &s);
     set_fs (old_fs);
     putname(tmp);
     if (putstat64 (statbuf, &s)) 
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/linux32.h linux/arch/s390x/kernel/linux32.h
--- v2.4.12/linux/arch/s390x/kernel/linux32.h	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/linux32.h	Thu Oct 11 09:04:57 2001
@@ -237,8 +237,8 @@
 	__u32			uc_flags;
 	__u32			uc_link;	/* pointer */	
 	stack_t32		uc_stack;
+	_sigregs32		uc_mcontext;
 	sigset_t32		uc_sigmask;	/* mask last for extensibility */
-	__u32			sc;		/* pointer */
 };
 
 #endif /* !CONFIG_S390_SUPPORT */
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/lowcore.S linux/arch/s390x/kernel/lowcore.S
--- v2.4.12/linux/arch/s390x/kernel/lowcore.S	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/lowcore.S	Wed Dec 31 16:00:00 1969
@@ -1,28 +0,0 @@
-/*
- *  arch/s390/kernel/lowcore.S
- *    S390 lowcore definition.
- *
- *  S390 64 bit Version
- *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Hartmut Penner (hpenner@de.ibm.com)
- *               Martin Schwidefsky (schwidefsky@de.ibm.com),
- */
-#include <asm/lowcore.h>
-	
-         .align 8192
-         .globl init_S390_lowcore
-init_S390_lowcore:      
-         .fill 0x1a0-0x000,1,0	
-         .quad  _RESTART_PSW_MASK
-         .quad  restart_int_handler 
-         .quad  _EXT_PSW_MASK
-         .quad  ext_int_handler 
-         .quad  _SVC_PSW_MASK
-         .quad  system_call
-         .quad  _PGM_PSW_MASK
-         .quad  pgm_check_handler 
-         .quad  _MCCK_PSW_MASK
-         .quad  mcck_int_handler 
-EXT_PSW: .quad  _IO_PSW_MASK
-         .quad  io_int_handler
-	 .fill  0x2000-0x200,1,0
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/mathemu.c linux/arch/s390x/kernel/mathemu.c
--- v2.4.12/linux/arch/s390x/kernel/mathemu.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/mathemu.c	Wed Dec 31 16:00:00 1969
@@ -1,920 +0,0 @@
-/*
- *  arch/s390/kernel/mathemu.c
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- *
- * 'mathemu.c' handles IEEE instructions on a S390 processor
- * that does not have the IEEE fpu
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-
-#include <asm/uaccess.h>
-#include <asm/mathemu.h>
-
-#ifdef CONFIG_SYSCTL
-int sysctl_ieee_emulation_warnings=1;
-#endif
-
-static void display_emulation_not_implemented(char *instr)
-{
-	struct pt_regs *regs;
-	__u16 *location;
-	
-#if CONFIG_SYSCTL
-	if(sysctl_ieee_emulation_warnings)
-#endif
-	{
-		regs=current->thread.regs;
-		location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
-		printk("%s ieee fpu instruction not emulated process name: %s pid: %d \n",
-		       instr,
-		       current->comm, current->pid);
-		printk("%s's PSW:    %08lx %08lx\n",instr,
-		       (unsigned long) regs->psw.mask,
-		       (unsigned long) location);
-	}
-}
-
-
-static void set_CC_df(__u64 val1,__u64 val2) {
-        int rc;
-        rc = __cmpdf2(val1,val2);
-        current->thread.regs->psw.mask &= 0xFFFFCFFFFFFFFFFFL;
-        switch (rc) {
-                case -1:
-                        current->thread.regs->psw.mask |= 0x0000100000000000L;
-                        break;
-                case 1:
-                        current->thread.regs->psw.mask |= 0x0000200000000000L;
-                        break;
-        }
-}
-
-static void set_CC_sf(__u32 val1,__u32 val2) {
-        int rc;
-        rc = __cmpsf2(val1,val2);
-        current->thread.regs->psw.mask &= 0xFFFFCFFFFFFFFFFF;
-        switch (rc) {
-                case -1:
-                        current->thread.regs->psw.mask |= 0x0000100000000000L;
-                        break;
-                case 1:
-                        current->thread.regs->psw.mask |= 0x0000200000000000L;
-                        break;
-        }
-}
-
-
-static void emu_adb (int rx, __u64 val) {
-        current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,val);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-}
-
-static void emu_adbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,
-                                         current->thread.fp_regs.fprs[ry].d);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-}
-
-static void emu_aeb (int rx, __u32 val) {
-        current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,val);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-}
-
-static void emu_aebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,
-                                        current->thread.fp_regs.fprs[ry].f);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-}
-
-static void emu_axbr (int rx, int ry) {
-        display_emulation_not_implemented("axbr");
-}
-
-static void emu_cdb (int rx, __u64 val) {
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,val);
-}
-
-static void emu_cdbr (int rx, int ry) {
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,current->thread.fp_regs.fprs[ry].d);
-}
-
-static void emu_cdfbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d =
-                     __floatsidf(current->thread.regs->gprs[ry]);
-}
-
-static void emu_ceb (int rx, __u32 val) {
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,val);
-}
-
-static void emu_cebr (int rx, int ry) {
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,current->thread.fp_regs.fprs[ry].f);
-}
-
-static void emu_cefbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f =
-                     __floatsisf(current->thread.regs->gprs[ry]);
-}
-
-static void emu_cfdbr (int rx, int ry, int mask) {
-        current->thread.regs->gprs[rx] =
-                     __fixdfsi(current->thread.fp_regs.fprs[ry].d);
-}
-
-static void emu_cfebr (int rx, int ry, int mask) {
-        current->thread.regs->gprs[rx] =
-                     __fixsfsi(current->thread.fp_regs.fprs[ry].f);
-}
-
-static void emu_cfxbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("cfxbr");
-}
-
-static void emu_cxbr (int rx, int ry) {
-        display_emulation_not_implemented("cxbr");
-}
-
-static void emu_cxfbr (int rx, int ry) {
-        display_emulation_not_implemented("cxfbr");
-}
-
-static void emu_ddb (int rx, __u64 val) {
-        current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,val);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-}
-
-static void emu_ddbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,
-                                         current->thread.fp_regs.fprs[ry].d);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-}
-
-static void emu_deb (int rx, __u32 val) {
-        current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,val);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-}
-
-static void emu_debr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,
-                                         current->thread.fp_regs.fprs[ry].f);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-}
-
-static void emu_didbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("didbr");
-}
-
-static void emu_diebr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("diebr");
-}
-
-static void emu_dxbr (int rx, int ry) {
-        display_emulation_not_implemented("dxbr");
-}
-
-static void emu_efpc (int rx, int ry) {
-        display_emulation_not_implemented("efpc");
-}
-
-static void emu_fidbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("fidbr");
-}
-
-static void emu_fiebr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("fiebr");
-}
-
-static void emu_fixbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("fixbr");
-}
-
-static void emu_kdb (int rx, __u64 val) {
-        display_emulation_not_implemented("kdb");
-}
-
-static void emu_kdbr (int rx, int ry) {
-        display_emulation_not_implemented("kdbr");
-}
-
-static void emu_keb (int rx, __u32 val) {
-        display_emulation_not_implemented("keb");
-}
-
-static void emu_kebr (int rx, int ry) {
-        display_emulation_not_implemented("kebr");
-}
-
-static void emu_kxbr (int rx, int ry) {
-        display_emulation_not_implemented("kxbr");
-}
-
-static void emu_lcdbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d =
-        __negdf2(current->thread.fp_regs.fprs[ry].d);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-}
-
-static void emu_lcebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f =
-        __negsf2(current->thread.fp_regs.fprs[ry].f);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-}
-
-static void emu_lcxbr (int rx, int ry) {
-        display_emulation_not_implemented("lcxbr");
-}
-
-static void emu_ldeb (int rx, __u32 val) {
-        current->thread.fp_regs.fprs[rx].d = __extendsfdf2(val);
-}
-
-static void emu_ldebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d =
-        __extendsfdf2(current->thread.fp_regs.fprs[ry].f);
-}
-
-static void emu_ldxbr (int rx, int ry) {
-        display_emulation_not_implemented("ldxbr");
-}
-
-static void emu_ledbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = __truncdfsf2(current->thread.fp_regs.fprs[ry].d);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-}
-
-static void emu_lexbr (int rx, int ry) {
-        display_emulation_not_implemented("lexbr");
-}
-
-static void emu_lndbr (int rx, int ry) {
-        display_emulation_not_implemented("lndbr");
-}
-
-static void emu_lnebr (int rx, int ry) {
-        display_emulation_not_implemented("lnebr");
-}
-
-static void emu_lnxbr (int rx, int ry) {
-        display_emulation_not_implemented("lnxbr");
-}
-
-static void emu_lpdbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d = __absdf2(current->thread.fp_regs.fprs[ry].d);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0);
-}
-
-static void emu_lpebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = __abssf2(current->thread.fp_regs.fprs[ry].f);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-}
-
-static void emu_lpxbr (int rx, int ry) {
-        display_emulation_not_implemented("lpxbr");
-}
-
-static void emu_ltdbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d = current->thread.fp_regs.fprs[ry].d;
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-}
-
-static void emu_ltebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = current->thread.fp_regs.fprs[ry].f;
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-}
-
-static void emu_ltxbr (int rx, int ry) {
-        display_emulation_not_implemented("ltxbr");
-}
-
-static void emu_lxdb (int rx, __u64 val) {
-        display_emulation_not_implemented("lxdb");
-}
-
-static void emu_lxdbr (int rx, int ry) {
-        display_emulation_not_implemented("lxdbr");
-}
-
-static void emu_lxeb (int rx, __u32 val) {
-        display_emulation_not_implemented("lxeb");
-}
-
-static void emu_lxebr (int rx, int ry) {
-        display_emulation_not_implemented("lxebr");
-}
-
-static void emu_madb (int rx, __u64 val, int mask) {
-        display_emulation_not_implemented("madb");
-}
-
-static void emu_madbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("madbr");
-}
-
-static void emu_maeb (int rx, __u32 val, int mask) {
-        display_emulation_not_implemented("maeb");
-}
-
-static void emu_maebr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("maebr");
-}
-
-static void emu_mdb (int rx, __u64 val) {
-        current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,val);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-}
-
-static void emu_mdbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,
-                                         current->thread.fp_regs.fprs[ry].d);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-}
-
-static void emu_mdeb (int rx, __u32 val) {
-        display_emulation_not_implemented("mdeb");
-}
-
-static void emu_mdebr (int rx, int ry) {
-        display_emulation_not_implemented("mdebr");
-}
-
-static void emu_meeb (int rx, __u32 val) {
-        current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f,
-                                         val);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-}
-
-static void emu_meebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f,
-                                         current->thread.fp_regs.fprs[ry].f);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-}
-
-static void emu_msdb (int rx, __u64 val, int mask) {
-        display_emulation_not_implemented("msdb");
-}
-
-static void emu_msdbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("msdbr");
-}
-
-static void emu_mseb (int rx, __u32 val, int mask) {
-        display_emulation_not_implemented("mseb");
-}
-
-static void emu_msebr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("msebr");
-}
-
-static void emu_mxbr (int rx, int ry) {
-        display_emulation_not_implemented("mxbr");
-}
-
-static void emu_mxdb (int rx, __u64 val) {
-        display_emulation_not_implemented("mxdb");
-}
-
-static void emu_mxdbr (int rx, int ry) {
-        display_emulation_not_implemented("mxdbr");
-}
-
-static void emu_sdb (int rx, __u64 val) {
-        current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d,
-                                         val);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL);
-}
-
-static void emu_sdbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d,
-                                         current->thread.fp_regs.fprs[ry].d);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL);
-}
-
-static void emu_seb (int rx, __u32 val) {
-        current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f,
-                                         val);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-}
-
-static void emu_sebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f,
-                                         current->thread.fp_regs.fprs[ry].f);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-}
-
-static void emu_sfpc (int rx, int ry) {
-        display_emulation_not_implemented("sfpc");
-}
-
-static void emu_sqdb (int rx, __u64 val) {
-        display_emulation_not_implemented("sqdb");
-}
-
-static void emu_sqdbr (int rx, int ry) {
-        display_emulation_not_implemented("sqdbr");
-}
-
-static void emu_sqeb (int rx, __u32 val) {
-        display_emulation_not_implemented("sqeb");
-}
-
-static void emu_sqebr (int rx, int ry) {
-        display_emulation_not_implemented("sqebr");
-}
-
-static void emu_sqxbr (int rx, int ry) {
-        display_emulation_not_implemented("sqxbr");
-}
-
-static void emu_sxbr (int rx, int ry) {
-        display_emulation_not_implemented("sxbr");
-}
-
-static void emu_tcdb (int rx, __u64 val) {
-        display_emulation_not_implemented("tcdb");
-}
-
-static void emu_tceb (int rx, __u32 val) {
-        display_emulation_not_implemented("tceb");
-}
-
-static void emu_tcxb (int rx, __u64 val) {
-        display_emulation_not_implemented("tcxb");
-}
-
-
-static inline void emu_load_regd(int reg) {
-        if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
-                __asm__ __volatile (       /* load reg from fp_regs.fprs[reg] */
-                        "     bras  1,0f\n"
-                        "     ld    0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
-                        : "1" );
-        }
-}
-
-static inline void emu_load_rege(int reg) {
-        if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
-                __asm__ __volatile (       /* load reg from fp_regs.fprs[reg] */
-                        "     bras  1,0f\n"
-                        "     le    0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
-                        : "1" );
-        }
-}
-
-static inline void emu_store_regd(int reg) {
-        if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
-                __asm__ __volatile (       /* store reg to fp_regs.fprs[reg] */
-                        "     bras  1,0f\n"
-                        "     std   0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
-                        : "1" );
-        }
-}
-
-
-static inline void emu_store_rege(int reg) {
-        if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
-                __asm__ __volatile (       /* store reg to fp_regs.fprs[reg] */
-                        "     bras  1,0f\n"
-                        "     ste   0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
-                        : "1" );
-        }
-}
-
-int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
-        static const __u8 format_table[] = {
-                2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4,
-                1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                1, 1, 1, 1,10, 1, 1, 3, 1, 1, 1, 1, 1, 1, 0, 0,
-                0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 3,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
-                0, 0, 0, 0, 5, 6, 6, 0, 7, 8, 8, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-        };
-        static const void *jump_table[]= {
-                emu_lpebr, emu_lnebr, emu_ltebr, emu_lcebr,
-                emu_ldebr, emu_lxdbr, emu_lxebr, emu_mxdbr,
-                emu_kebr,  emu_cebr,  emu_aebr,  emu_sebr,
-                emu_mdebr, emu_debr,  emu_maebr, emu_msebr,
-                emu_lpdbr, emu_lndbr, emu_ltdbr, emu_lcdbr,
-                emu_sqebr, emu_sqdbr, emu_sqxbr, emu_meebr,
-                emu_kdbr,  emu_cdbr,  emu_adbr,  emu_sdbr,
-                emu_mdbr,  emu_ddbr,  emu_madbr, emu_msdbr,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                emu_lpxbr, emu_lnxbr, emu_ltxbr, emu_lcxbr,
-                emu_ledbr, emu_ldxbr, emu_lexbr, emu_fixbr,
-                emu_kxbr,  emu_cxbr,  emu_axbr,  emu_sxbr,
-                emu_mxbr,  emu_dxbr,  NULL,      NULL,
-                NULL,      NULL,      NULL,      emu_diebr,
-                NULL,      NULL,      NULL,      emu_fiebr,
-                NULL,      NULL,      NULL,      emu_didbr,
-                NULL,      NULL,      NULL,      emu_fidbr,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                emu_sfpc,  NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                emu_efpc,  NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                emu_cefbr, emu_cdfbr, emu_cxfbr, NULL,
-                emu_cfebr, emu_cfdbr, emu_cfxbr
-        };
-
-        switch (format_table[opcode[1]]) {
-        case 1: /* RRE format, double operation */
-                emu_store_regd((opcode[3]>>4)&15);
-                emu_store_regd(opcode[3]&15);
-                /* call the emulation function */
-                ((void (*)(int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15);
-                emu_load_regd((opcode[3]>>4)&15);
-                emu_load_regd(opcode[3]&15);
-                return 0;
-        case 2: /* RRE format, float operation */
-                emu_store_rege((opcode[3]>>4)&15);
-                emu_store_rege(opcode[3]&15);
-                /* call the emulation function */
-                ((void (*)(int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15);
-                emu_load_rege((opcode[3]>>4)&15);
-                emu_load_rege(opcode[3]&15);
-                return 0;
-        case 3: /* RRF format, double operation */
-                emu_store_regd((opcode[3]>>4)&15);
-                emu_store_regd(opcode[3]&15);
-                /* call the emulation function */
-                ((void (*)(int, int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
-                emu_load_regd((opcode[3]>>4)&15);
-                emu_load_regd(opcode[3]&15);
-                return 0;
-        case 4: /* RRF format, float operation */
-                emu_store_rege((opcode[3]>>4)&15);
-                emu_store_rege(opcode[3]&15);
-                /* call the emulation function */
-                ((void (*)(int, int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
-                emu_load_rege((opcode[3]>>4)&15);
-                emu_load_rege(opcode[3]&15);
-                return 0;
-        case 5: /* RRE format, cefbr instruction */
-                emu_store_rege((opcode[3]>>4)&15);
-                /* call the emulation function */
-                ((void (*)(int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15);
-                emu_load_rege((opcode[3]>>4)&15);
-                return 0;
-        case 6: /* RRE format, cdfbr & cxfbr instruction */
-                emu_store_regd((opcode[3]>>4)&15);
-                /* call the emulation function */
-                ((void (*)(int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15);
-                emu_load_regd((opcode[3]>>4)&15);
-                return 0;
-                /* FIXME !! */
-                return 0;
-        case 7: /* RRF format, cfebr instruction */
-                emu_store_rege(opcode[3]&15);
-                /* call the emulation function */
-                ((void (*)(int, int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
-                return 0;
-        case 8: /* RRF format, cfdbr & cfxbr instruction */
-                emu_store_regd(opcode[3]&15);
-                /* call the emulation function */
-                ((void (*)(int, int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
-                return 0;
-	case 9: /* RRE format, ldebr & mdebr instruction */
-		/* float store but double load */
-                emu_store_rege((opcode[3]>>4)&15);
-                emu_store_rege(opcode[3]&15);
-                /* call the emulation function */
-                ((void (*)(int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15);
-                emu_load_regd((opcode[3]>>4)&15);
-                return 0;
-        case 10: /* RRE format, ledbr instruction */
-		/* double store but float load */
-                emu_store_regd((opcode[3]>>4)&15);
-                emu_store_regd(opcode[3]&15);
-                /* call the emulation function */
-                ((void (*)(int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15);
-                emu_load_rege((opcode[3]>>4)&15);
-                return 0;
-        default:
-                return 1;
-        }
-}
-
-static void* calc_addr(struct pt_regs *regs,int rx,int rb,int disp)
-{
-  rx &= 0xf;
-  rb &= 0xf;
-  disp &= 0xfff;
-  return (void*) ((rx != 0 ? regs->gprs[rx] : 0)  + /* index */   
-         (rb != 0 ? regs->gprs[rb] : 0)  + /* base */
-         disp);
-}
-    
-int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
-        static const __u8 format_table[] = {
-                0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4,
-                2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-        };
-        static const void *jump_table[]= {
-                NULL,     NULL,     NULL,     NULL,
-                emu_ldeb, emu_lxdb, emu_lxeb, emu_mxdb,
-                emu_keb,  emu_ceb,  emu_aeb,  emu_seb,
-                emu_mdeb, emu_deb,  emu_maeb, emu_mseb,
-                emu_tceb, emu_tcdb, emu_tcxb, NULL,
-                emu_sqeb, emu_sqdb, NULL,     emu_meeb,
-                emu_kdb,  emu_cdb,  emu_adb,  emu_sdb,
-                emu_mdb,  emu_ddb,  emu_madb, emu_msdb
-        };
-
-        switch (format_table[opcode[5]]) {
-        case 1: /* RXE format, __u64 constant */ {
-                __u64 *dxb, temp;
-                __u32 opc;
-
-                emu_store_regd((opcode[1]>>4)&15);
-                opc = *((__u32 *) opcode);
-                dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                /* FIXME: how to react if copy_from_user fails ? */
-                copy_from_user(&temp, dxb, 8);
-                /* call the emulation function */
-                ((void (*)(int, __u64))jump_table[opcode[5]])
-                        (opcode[1]>>4,temp);
-                emu_load_regd((opcode[1]>>4)&15);
-                return 0;
-        }
-        case 2: /* RXE format, __u32 constant */ {
-                __u32 *dxb, temp;
-                __u32 opc;
-
-                emu_store_rege((opcode[1]>>4)&15);
-                opc = *((__u32 *) opcode);
-                dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                /* FIXME: how to react if get_user fails ? */
-                get_user(temp, dxb);
-                /* call the emulation function */
-                ((void (*)(int, __u32))jump_table[opcode[5]])
-                        (opcode[1]>>4,temp);
-                emu_load_rege((opcode[1]>>4)&15);
-                return 0;
-        }
-        case 3: /* RXF format, __u64 constant */ {
-                __u32 *dxb, temp;
-                __u32 opc;
-
-                emu_store_regd((opcode[1]>>4)&15);
-                opc = *((__u32 *) opcode);
-                dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                /* FIXME: how to react if copy_from_user fails ? */
-                copy_from_user(&temp, dxb, 8);
-                /* call the emulation function */
-                ((void (*)(int, __u32, int))jump_table[opcode[5]])
-                        (opcode[1]>>4,temp,opcode[4]>>4);
-                emu_load_regd((opcode[1]>>4)&15);
-                return 0;
-        }
-        case 4: /* RXF format, __u32 constant */ {
-                __u32 *dxb, temp;
-                __u32 opc;
-
-                emu_store_rege((opcode[1]>>4)&15);
-                opc = *((__u32 *) opcode);
-                dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                /* FIXME: how to react if get_user fails ? */
-                get_user(temp, dxb);
-                /* call the emulation function */
-                ((void (*)(int, __u32, int))jump_table[opcode[5]])
-                        (opcode[1]>>4,temp,opcode[4]>>4);
-                emu_load_rege((opcode[1]>>4)&15);
-                return 0;
-        }
-	case 5: /* RXE format, __u32 constant */
-                /* store_rege and load_regd */ 
-		{
-                __u32 *dxb, temp;
-                __u32 opc;
-                emu_store_rege((opcode[1]>>4)&15);
-                opc = *((__u32 *) opcode);
-                dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                /* FIXME: how to react if get_user fails ? */
-                get_user(temp, dxb);
-                /* call the emulation function */
-                ((void (*)(int, __u32))jump_table[opcode[5]])
-                        (opcode[1]>>4,temp);
-                emu_load_regd((opcode[1]>>4)&15);
-                return 0;
-        }
-        default:
-                return 1;
-        }
-}
-
-/*
- * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
- */
-void math_emu_ldr(__u8 *opcode) {
-        __u16 opc = *((__u16 *) opcode);
-
-        if ((opc & 0x0090) == 0) {         /* test if rx in {0,2,4,6} */
-                /* we got an exception therfore ry can't be in {0,2,4,6} */
-                __asm__ __volatile (       /* load rx from fp_regs.fprs[ry] */
-                        "     bras  1,0f\n"
-                        "     ld    0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" (opc&0x00f0),
-                          "a" (&current->thread.fp_regs.fprs[opc&0x000f].d)
-                        : "1" );
-        } else if ((opc & 0x0009) == 0) {  /* test if ry in {0,2,4,6} */
-                __asm__ __volatile (       /* store ry to fp_regs.fprs[rx] */
-                        "     bras  1,0f\n"
-                        "     std   0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" ((opc&0x000f)<<4),
-                          "a" (&current->thread.fp_regs.fprs[(opc&0x00f0)>>4].d)
-                        : "1" );
-        } else {                          /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
-                current->thread.fp_regs.fprs[(opc&0x00f0)>>4] =
-                        current->thread.fp_regs.fprs[opc&0x000f];
-        }
-}
-
-/*
- * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
- */
-void math_emu_ler(__u8 *opcode) {
-        __u16 opc = *((__u16 *) opcode);
-
-        if ((opc & 0x0090) == 0) {         /* test if rx in {0,2,4,6} */
-                /* we got an exception therfore ry can't be in {0,2,4,6} */
-                __asm__ __volatile (       /* load rx from fp_regs.fprs[ry] */
-                        "     bras  1,0f\n"
-                        "     le    0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" (opc&0x00f0),
-                          "a" (&current->thread.fp_regs.fprs[opc&0x000f].f)
-                        : "1" );
-        } else if ((opc & 0x0009) == 0) {  /* test if ry in {0,2,4,6} */
-                __asm__ __volatile (       /* store ry to fp_regs.fprs[rx] */
-                        "     bras  1,0f\n"
-                        "     ste   0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" ((opc&0x000f)<<4),
-                          "a" (&current->thread.fp_regs.fprs[(opc&0x00f0)>>4].f)
-                        : "1" );
-        } else {                          /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
-                current->thread.fp_regs.fprs[(opc&0x00f0)>>4] =
-                        current->thread.fp_regs.fprs[opc&0x000f];
-        }
-}
-
-/*
- * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
- */
-void math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
-        __u32 opc = *((__u32 *) opcode);
-        __u64 *dxb;
-
-        dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
-        /* FIXME: how to react if copy_from_user fails ? */
-        copy_from_user(&current->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
-}
-
-/*
- * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
- */
-void math_emu_le(__u8 *opcode, struct pt_regs * regs) {
-        __u32 opc = *((__u32 *) opcode);
-        __u32 *mem, *dxb;
-
-        dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-        /* FIXME: how to react if get_user fails ? */
-        mem = (__u32 *) (&current->thread.fp_regs.fprs[(opc>>20)&15].f);
-        get_user(mem[0], dxb);
-}
-
-/*
- * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
- */
-void math_emu_std(__u8 *opcode, struct pt_regs * regs) {
-        __u32 opc = *((__u32 *) opcode);
-        __u64 *dxb;
-        dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
-        /* FIXME: how to react if copy_to_user fails ? */
-        copy_to_user(dxb, &current->thread.fp_regs.fprs[(opc>>20)&15].d, 8);
-}
-
-/*
- * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
- */
-void math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
-        __u32 opc = *((__u32 *) opcode);
-        __u32 *mem, *dxb;
-        dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-        /* FIXME: how to react if put_user fails ? */
-        mem = (__u32 *) (&current->thread.fp_regs.fprs[(opc>>20)&15].f);
-        put_user(mem[0], dxb);
-}
-
-/*
- * Emulate LFPC D(B)
- */
-int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
-        /* FIXME: how to do that ?!? */
-        return 0;
-}
-
-/*
- * Emulate STFPC D(B)
- */
-int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
-        /* FIXME: how to do that ?!? */
-        return 0;
-}
-
-/*
- * Emulate SRNM D(B)
- */
-int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
-        /* FIXME: how to do that ?!? */
-        return 0;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/process.c linux/arch/s390x/kernel/process.c
--- v2.4.12/linux/arch/s390x/kernel/process.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/s390x/kernel/process.c	Thu Oct 11 09:04:57 2001
@@ -44,8 +44,6 @@
 #include <asm/processor.h>
 #include <asm/irq.h>
 
-spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
-
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
 /*
@@ -210,7 +208,7 @@
 void show_regs(struct pt_regs *regs)
 {
 	char buff[80];
-	int line;
+	int i, line;
 
         printk("CPU:    %d\n",smp_processor_id());
         printk("Process %s (pid: %d, stackpage=%016lX)\n",
@@ -218,6 +216,17 @@
 	
 	for (line = 0; sprintf_regs(line, buff, current, regs); line++)
 		printk(buff);
+
+	if (regs->psw.mask & PSW_PROBLEM_STATE)
+	{
+		printk("User Code:\n");
+		memset(buff, 0, 20);
+		copy_from_user(buff,
+			       (char *) (regs->psw.addr & PSW_ADDR_MASK), 20);
+		for (i = 0; i < 20; i++)
+			printk("%02x ", buff[i]);
+		printk("\n");
+	}
 }
 
 char *task_show_regs(struct task_struct *task, char *buffer)
@@ -323,28 +332,19 @@
 
 asmlinkage int sys_fork(struct pt_regs regs)
 {
-        int ret;
-
-        lock_kernel();
-        ret = do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
-        unlock_kernel();
-        return ret;
+        return do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
 }
 
 asmlinkage int sys_clone(struct pt_regs regs)
 {
         unsigned long clone_flags;
         unsigned long newsp;
-        int ret;
 
-        lock_kernel();
         clone_flags = regs.gprs[3];
         newsp = regs.orig_gpr2;
         if (!newsp)
                 newsp = regs.gprs[15];
-        ret = do_fork(clone_flags, newsp, &regs, 0);
-        unlock_kernel();
-        return ret;
+        return do_fork(clone_flags, newsp, &regs, 0);
 }
 
 /*
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/s390_ksyms.c linux/arch/s390x/kernel/s390_ksyms.c
--- v2.4.12/linux/arch/s390x/kernel/s390_ksyms.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390x/kernel/s390_ksyms.c	Thu Oct 11 09:04:57 2001
@@ -18,11 +18,11 @@
 /*
  * memory management
  */
-EXPORT_SYMBOL(_oi_bitmap);
-EXPORT_SYMBOL(_ni_bitmap);
-EXPORT_SYMBOL(_zb_findmap);
-EXPORT_SYMBOL(__copy_from_user_fixup);
-EXPORT_SYMBOL(__copy_to_user_fixup);
+EXPORT_SYMBOL_NOVERS(_oi_bitmap);
+EXPORT_SYMBOL_NOVERS(_ni_bitmap);
+EXPORT_SYMBOL_NOVERS(_zb_findmap);
+EXPORT_SYMBOL_NOVERS(__copy_from_user_fixup);
+EXPORT_SYMBOL_NOVERS(__copy_to_user_fixup);
 
 /*
  * semaphore ops
@@ -41,12 +41,12 @@
 EXPORT_SYMBOL_NOVERS(strlen);
 EXPORT_SYMBOL_NOVERS(strchr);
 EXPORT_SYMBOL_NOVERS(strcmp);
-EXPORT_SYMBOL_NOVERS(strcat);
 EXPORT_SYMBOL_NOVERS(strncat);
 EXPORT_SYMBOL_NOVERS(strncmp);
 EXPORT_SYMBOL_NOVERS(strncpy);
 EXPORT_SYMBOL_NOVERS(strnlen);
 EXPORT_SYMBOL_NOVERS(strrchr);
+EXPORT_SYMBOL_NOVERS(strstr);
 EXPORT_SYMBOL_NOVERS(strtok);
 EXPORT_SYMBOL_NOVERS(strpbrk);
 
@@ -66,8 +66,5 @@
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(console_mode);
 EXPORT_SYMBOL(console_device);
+EXPORT_SYMBOL_NOVERS(do_call_softirq);
 
-#if CONFIG_IP_MULTICAST
-/* Required for lcs gigibit ethernet multicast support */
-EXPORT_SYMBOL(arp_mc_map);
-#endif
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/setup.c linux/arch/s390x/kernel/setup.c
--- v2.4.12/linux/arch/s390x/kernel/setup.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390x/kernel/setup.c	Thu Oct 11 09:04:57 2001
@@ -47,6 +47,9 @@
 unsigned int console_device = -1;
 unsigned long memory_size = 0;
 unsigned long machine_flags = 0;
+struct { unsigned long addr, size, type; } memory_chunk[16];
+#define CHUNK_READ_WRITE 0
+#define CHUNK_READ_ONLY 1
 __u16 boot_cpu_addr;
 int cpus_initialized = 0;
 unsigned long cpu_initialized = 0;
@@ -257,6 +260,8 @@
  * Setup function called from init/main.c just after the banner
  * was printed.
  */
+extern char _pstart, _pend, _stext;
+
 void __init setup_arch(char **cmdline_p)
 {
         unsigned long bootmap_size;
@@ -266,19 +271,14 @@
 	unsigned long start_pfn, end_pfn;
         static unsigned int smptrap=0;
         unsigned long delay = 0;
+	struct _lowcore *lowcore;
+	int i;
 
         if (smptrap)
                 return;
         smptrap=1;
 
         /*
-         * Setup lowcore information for boot cpu
-         */
-        cpu_init();
-        boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
-        __cpu_logical_map[0] = boot_cpu_addr;
-
-        /*
          * print what head.S has found out about the machine 
          */
 	printk((MACHINE_IS_VM) ?
@@ -287,7 +287,7 @@
 
         ROOT_DEV = to_kdev_t(0x0100);
         memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
-	memory_end = memory_size;                /* detected in head.s */
+	memory_end = memory_size & ~0x200000UL;  /* detected in head.s */
         init_mm.start_code = PAGE_OFFSET;
         init_mm.end_code = (unsigned long) &_etext;
         init_mm.end_data = (unsigned long) &_edata;
@@ -362,11 +362,26 @@
 	bootmap_size = init_bootmem(start_pfn, end_pfn);
 
 	/*
-	 * Register RAM pages with the bootmem allocator.
+	 * Register RAM areas with the bootmem allocator.
 	 */
-	free_bootmem(start_pfn << PAGE_SHIFT, 
-		     (end_pfn - start_pfn) << PAGE_SHIFT);
+	for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) {
+		unsigned long start_chunk, end_chunk;
 
+		if (memory_chunk[i].type != CHUNK_READ_WRITE)
+			continue;
+		start_chunk = (memory_chunk[i].addr + PAGE_SIZE - 1);
+		start_chunk >>= PAGE_SHIFT;
+		end_chunk = (memory_chunk[i].addr + memory_chunk[i].size);
+		end_chunk >>= PAGE_SHIFT;
+		if (start_chunk < start_pfn)
+			start_chunk = start_pfn;
+		if (end_chunk > end_pfn)
+			end_chunk = end_pfn;
+		if (start_chunk < end_chunk)
+			free_bootmem(start_chunk << PAGE_SHIFT,
+				     (end_chunk - start_chunk) << PAGE_SHIFT);
+	}
+	
         /*
          * Reserve the bootmem bitmap itself as well. We do this in two
          * steps (first step was init_bootmem()) because this catches
@@ -390,6 +405,36 @@
         }
 #endif
 
+        /*
+         * Setup lowcore for boot cpu
+         */
+	lowcore = (struct _lowcore *) 
+		__alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0);
+	memset(lowcore, 0, 2*PAGE_SIZE);
+	lowcore->restart_psw.mask = _RESTART_PSW_MASK;
+	lowcore->restart_psw.addr = (addr_t) &restart_int_handler;
+	lowcore->external_new_psw.mask = _EXT_PSW_MASK;
+	lowcore->external_new_psw.addr = (addr_t) &ext_int_handler;
+	lowcore->svc_new_psw.mask = _SVC_PSW_MASK;
+	lowcore->svc_new_psw.addr = (addr_t) &system_call;
+	lowcore->program_new_psw.mask = _PGM_PSW_MASK;
+	lowcore->program_new_psw.addr = (addr_t) &pgm_check_handler;
+	lowcore->mcck_new_psw.mask = _MCCK_PSW_MASK;
+	lowcore->mcck_new_psw.addr = (addr_t) &mcck_int_handler;
+	lowcore->io_new_psw.mask = _IO_PSW_MASK;
+	lowcore->io_new_psw.addr = (addr_t) &io_int_handler;
+	lowcore->ipl_device = S390_lowcore.ipl_device;
+	lowcore->kernel_stack = ((__u32) &init_task_union) + 16384;
+	lowcore->async_stack = (__u64)
+		__alloc_bootmem(4*PAGE_SIZE, 4*PAGE_SIZE, 0) + 16384;
+	set_prefix((__u32)(__u64) lowcore);
+        cpu_init();
+        boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
+        __cpu_logical_map[0] = boot_cpu_addr;
+
+	/*
+	 * Create kernel page tables and switch to virtual addressing.
+	 */
         paging_init();
 
 	res = alloc_bootmem_low(sizeof(struct resource));
@@ -422,30 +467,49 @@
 }
 
 /*
- *	Get CPU information for use by the procfs.
+ * get_cpuinfo - Get information on one CPU for use by procfs.
+ *
+ *	Prints info on the next CPU into buffer.  Beware, doesn't check for
+ *	buffer overflow.  Current implementation of procfs assumes that the
+ *	resulting data is <= 1K.
+ *
+ * Args:
+ *	buffer	-- you guessed it, the data buffer
+ *	cpu_np	-- Input: next cpu to get (start at 0).  Output: Updated.
+ *
+ *	Returns number of bytes written to buffer.
  */
 
-int get_cpuinfo(char * buffer)
+int get_cpuinfo(char *buffer, unsigned *cpu_np)
 {
         struct cpuinfo_S390 *cpuinfo;
         char *p = buffer;
-        int i;
+	unsigned n;
 
-        p += sprintf(p,"vendor_id       : IBM/S390\n"
-                       "# processors    : %i\n"
-                       "bogomips per cpu: %lu.%02lu\n",
-                       smp_num_cpus, loops_per_jiffy/(500000/HZ),
-                       (loops_per_jiffy/(5000/HZ))%100);
-        for (i = 0; i < smp_num_cpus; i++) {
-                cpuinfo = &safe_get_cpu_lowcore(i).cpu_data;
-                p += sprintf(p,"processor %i: "
-                               "version = %02X,  "
-                               "identification = %06X,  "
-                               "machine = %04X\n",
-                               i, cpuinfo->cpu_id.version,
-                               cpuinfo->cpu_id.ident,
-                               cpuinfo->cpu_id.machine);
-        }
+	n = *cpu_np;
+	while (n < NR_CPUS && (cpu_online_map & (1 << n)) == 0)
+		n++;
+	if (n >= NR_CPUS) {
+		*cpu_np = NR_CPUS;
+		return (0);
+	}
+	*cpu_np = n + 1;
+
+	if (n == 0) {
+		p += sprintf(p, "vendor_id       : IBM/S390\n"
+				"# processors    : %i\n"
+				"bogomips per cpu: %lu.%02lu\n",
+				smp_num_cpus, loops_per_jiffy/(500000/HZ),
+				(loops_per_jiffy/(5000/HZ))%100);
+	}
+	cpuinfo = &safe_get_cpu_lowcore(n).cpu_data;
+	p += sprintf(p, "processor %i: "
+			"version = %02X,  "
+			"identification = %06X,  "
+			"machine = %04X\n",
+			n, cpuinfo->cpu_id.version,
+			cpuinfo->cpu_id.ident,
+			cpuinfo->cpu_id.machine);
         return p - buffer;
 }
 
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/signal.c linux/arch/s390x/kernel/signal.c
--- v2.4.12/linux/arch/s390x/kernel/signal.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390x/kernel/signal.c	Thu Oct 11 09:04:57 2001
@@ -24,31 +24,25 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
+#include <linux/personality.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 
-#define DEBUG_SIG 0
-
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-/* pretcode & sig are used to store the return addr on Intel
-   & the signal no as the first parameter we do this differently
-   using gpr14 & gpr2. */
-
-#define SIGFRAME_COMMON \
-__u8     callee_used_stack[__SIGNAL_FRAMESIZE]; \
-struct sigcontext sc; \
-_sigregs sregs; \
-__u8 retcode[S390_SYSCALL_SIZE];
 
 typedef struct 
 {
-	SIGFRAME_COMMON
+	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
+	struct sigcontext sc;
+	_sigregs sregs;
+	__u8 retcode[S390_SYSCALL_SIZE];
 } sigframe;
 
 typedef struct 
 {
-	SIGFRAME_COMMON
+	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
+	__u8 retcode[S390_SYSCALL_SIZE];
 	struct siginfo info;
 	struct ucontext uc;
 } rt_sigframe;
@@ -206,7 +200,7 @@
 	err=__copy_from_user(regs,&sregs->regs,sizeof(_s390_regs_common));
 	if(!err)
 	{
-		regs->orig_gpr2 = -1;		/* disable syscall checks */
+		regs->trap = -1;		/* disable syscall checks */
 		regs->psw.mask=(saved_psw.mask&~PSW_MASK_DEBUGCHANGE)|
 		(regs->psw.mask&PSW_MASK_DEBUGCHANGE);
 		regs->psw.addr=(saved_psw.addr&~PSW_ADDR_DEBUGCHANGE)|
@@ -218,53 +212,51 @@
 	return(err);
 }
 
-static int
-restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
-		 _sigregs *sregs,sigset_t *set)
-{
-	unsigned int err;
-
-	err=restore_sigregs(regs,sregs);
-	if(!err)
-		err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE);
-		return(err);
-}
-
-int sigreturn_common(struct pt_regs *regs,int framesize)
+asmlinkage long sys_sigreturn(struct pt_regs *regs)
 {
 	sigframe *frame = (sigframe *)regs->gprs[15];
 	sigset_t set;
 
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
-		return -1;
-	if (restore_sigcontext(&frame->sc,regs,&frame->sregs,&set))
-	        return -1;
+		goto badframe;
+	if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
+		goto badframe;
+
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
-	return 0;
-}
 
-asmlinkage long sys_sigreturn(struct pt_regs *regs)
-{
-
-	if (sigreturn_common(regs,sizeof(sigframe)))
+	if (restore_sigregs(regs, &frame->sregs))
 		goto badframe;
+
 	return regs->gprs[2];
 
 badframe:
 	force_sig(SIGSEGV, current);
 	return 0;
-}	
+}
 
 asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
 {
 	rt_sigframe *frame = (rt_sigframe *)regs->gprs[15];
+	sigset_t set;
 
-	if (sigreturn_common(regs,sizeof(rt_sigframe)))
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	if (restore_sigregs(regs, &frame->uc.uc_mcontext))
+		goto badframe;
+
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
 	do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]);
@@ -273,7 +265,7 @@
 badframe:
 	force_sig(SIGSEGV, current);
 	return 0;
-}	
+}
 
 /*
  * Set up a signal frame.
@@ -307,58 +299,48 @@
 	return (void *)((sp - frame_size) & -8ul);
 }
 
-static void *setup_frame_common(int sig, struct k_sigaction *ka,
-			sigset_t *set, struct pt_regs * regs,
-				int frame_size,u16 retcode)
+static inline int map_signal(int sig)
 {
-	sigframe *frame;
-	int err;
+	if (current->exec_domain
+	    && current->exec_domain->signal_invmap
+	    && sig < 32)
+		return current->exec_domain->signal_invmap[sig];
+	else
+		return sig;
+}
 
-	frame = get_sigframe(ka, regs,frame_size);
-	if (!access_ok(VERIFY_WRITE, frame,frame_size))
-		return 0;
-	err = save_sigregs(regs,&frame->sregs);
-	if(!err)
-		err=__put_user(&frame->sregs,&frame->sc.sregs);
-	if(!err)
+static void setup_frame(int sig, struct k_sigaction *ka,
+			sigset_t *set, struct pt_regs * regs)
+{
+	sigframe *frame = get_sigframe(ka, regs, sizeof(sigframe));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe)))
+		goto give_sigsegv;
+
+	if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE))
+		goto give_sigsegv;
+
+	if (save_sigregs(regs, &frame->sregs))
+		goto give_sigsegv;
+	if (__put_user(&frame->sregs, &frame->sc.sregs))
+		goto give_sigsegv;
 
-		err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE);
-	if(!err)
-	{
-		regs->gprs[2]=(current->exec_domain
-		           && current->exec_domain->signal_invmap
-		           && sig < 32
-		           ? current->exec_domain->signal_invmap[sig]
-		           : sig);
-		/* Set up registers for signal handler */
-		regs->gprs[15] = (addr_t)frame;
-		regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
-		regs->psw.mask = _USER_PSW_MASK;
-	}
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
 	if (ka->sa.sa_flags & SA_RESTORER) {
                 regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
 	} else {
                 regs->gprs[14] = FIX_PSW(frame->retcode);
-		err |= __put_user(retcode, (u16 *)(frame->retcode));
+		if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, 
+	                       (u16 *)(frame->retcode)))
+			goto give_sigsegv;
 	}
-	return(err ? 0:frame);
-}
 
-static void setup_frame(int sig, struct k_sigaction *ka,
-			sigset_t *set, struct pt_regs * regs)
-{
-	sigframe *frame;
+	/* Set up registers for signal handler */
+	regs->gprs[15] = (addr_t)frame;
+	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+	regs->psw.mask = _USER_PSW_MASK;
 
-	if((frame=setup_frame_common(sig,ka,set,regs,sizeof(sigframe),
-		    (S390_SYSCALL_OPCODE|__NR_sigreturn)))==0)
-		goto give_sigsegv;
-#if DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
-		current->comm, current->pid, frame, regs->eip, frame->pretcode);
-#endif
-	/* Martin wants this for pthreads */
+	regs->gprs[2] = map_signal(sig);
 	regs->gprs[3] = (addr_t)&frame->sc;
 
 	/* We forgot to include these in the sigcontext.
@@ -376,34 +358,44 @@
 static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 			   sigset_t *set, struct pt_regs * regs)
 {
-	rt_sigframe *frame;
-	addr_t      orig_sp=regs->gprs[15];
-	int err;
+	int err = 0;
+	rt_sigframe *frame = get_sigframe(ka, regs, sizeof(rt_sigframe));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe)))
+		goto give_sigsegv;
 
-	if((frame=setup_frame_common(sig,ka,set,regs,sizeof(rt_sigframe),
-		    (S390_SYSCALL_OPCODE|__NR_rt_sigreturn)))==0)
+	if (copy_siginfo_to_user(&frame->info, info))
 		goto give_sigsegv;
-	
-	err = copy_siginfo_to_user(&frame->info, info);
 
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __put_user(0, &frame->uc.uc_link);
 	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-	err |= __put_user(sas_ss_flags(orig_sp),
+	err |= __put_user(sas_ss_flags(regs->gprs[15]),
 			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-	err |= __put_user(&frame->sc,&frame->uc.sc);
-	regs->gprs[3] = (addr_t)&frame->info;
-	regs->gprs[4] = (addr_t)&frame->uc;
-
+	err |= save_sigregs(regs, &frame->uc.uc_mcontext);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 	if (err)
 		goto give_sigsegv;
 
-#if DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
-		current->comm, current->pid, frame, regs->eip, frame->pretcode);
-#endif
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+                regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
+	} else {
+                regs->gprs[14] = FIX_PSW(frame->retcode);
+		err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, 
+	                          (u16 *)(frame->retcode));
+	}
+
+	/* Set up registers for signal handler */
+	regs->gprs[15] = (addr_t)frame;
+	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+	regs->psw.mask = _USER_PSW_MASK;
+
+	regs->gprs[2] = map_signal(sig);
+	regs->gprs[3] = (addr_t)&frame->info;
+	regs->gprs[4] = (addr_t)&frame->uc;
 	return;
 
 give_sigsegv:
@@ -558,13 +550,16 @@
 					continue;
 				/* FALLTHRU */
 
-			case SIGSTOP:
+			case SIGSTOP: {
+				struct signal_struct *sig;
 				set_current_state(TASK_STOPPED);
 				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+				sig = current->p_pptr->sig;
+				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
+			}
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/signal32.c linux/arch/s390x/kernel/signal32.c
--- v2.4.12/linux/arch/s390x/kernel/signal32.c	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/signal32.c	Thu Oct 11 09:04:57 2001
@@ -11,6 +11,7 @@
  *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
@@ -22,32 +23,27 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
+#include <linux/personality.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include "linux32.h"
 
-#define DEBUG_SIG 0
-
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-/* pretcode & sig are used to store the return addr on Intel
-   & the signal no as the first parameter we do this differently
-   using gpr14 & gpr2. */
-
-#define SIGFRAME_COMMON32 \
-__u8     callee_used_stack[__SIGNAL_FRAMESIZE32]; \
-struct sigcontext32 sc; \
-_sigregs32 sregs; \
-__u8 retcode[S390_SYSCALL_SIZE];
+#define _USER_PSW_MASK32 0x0701C00080000000
 
 typedef struct 
 {
-	SIGFRAME_COMMON32
+	__u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
+	struct sigcontext32 sc;
+	_sigregs32 sregs;
+	__u8 retcode[S390_SYSCALL_SIZE];
 } sigframe32;
 
 typedef struct 
 {
-	SIGFRAME_COMMON32
+	__u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
+	__u8 retcode[S390_SYSCALL_SIZE];
 	struct siginfo32 info;
 	struct ucontext32 uc;
 } rt_sigframe32;
@@ -328,7 +324,7 @@
 
 	if(!err)
 	{
-		regs->orig_gpr2 = -1;		/* disable syscall checks */
+		regs->trap = -1;		/* disable syscall checks */
 		regs->psw.mask=(saved_psw.mask&~PSW_MASK_DEBUGCHANGE)|
 		(regs->psw.mask&PSW_MASK_DEBUGCHANGE);
 		regs->psw.addr=(saved_psw.addr&~PSW_ADDR_DEBUGCHANGE)|
@@ -342,40 +338,25 @@
 	return(err);
 }
 
-static int
-restore_sigcontext32(struct sigcontext32 *sc, struct pt_regs *regs,
-		 _sigregs32 *sregs,sigset_t *set)
-{
-	unsigned int err;
-
-	err=restore_sigregs32(regs,sregs);
-	if(!err)
-		err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE32);
-	return(err);
-}
-
-int sigreturn_common32(struct pt_regs *regs)
+asmlinkage long sys32_sigreturn(struct pt_regs *regs)
 {
 	sigframe32 *frame = (sigframe32 *)regs->gprs[15];
 	sigset_t set;
 
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
-		return -1;
-	if (restore_sigcontext32(&frame->sc,regs,&frame->sregs,&set))
-	        return -1;
+		goto badframe;
+	if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
+		goto badframe;
+
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
-	return 0;
-}
 
-asmlinkage long sys32_sigreturn(struct pt_regs *regs)
-{
-
-	if (sigreturn_common32(regs))
+	if (restore_sigregs32(regs, &frame->sregs))
 		goto badframe;
+
 	return regs->gprs[2];
 
 badframe:
@@ -386,11 +367,23 @@
 asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
 {
 	rt_sigframe32 *frame = (rt_sigframe32 *)regs->gprs[15];
+	sigset_t set;
 	stack_t st;
 	int err;
 	mm_segment_t old_fs = get_fs();
 
-	if (sigreturn_common32(regs))
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
 		goto badframe;
 
 	err = __get_user(st.ss_sp, &frame->uc.uc_stack.ss_sp);
@@ -399,17 +392,18 @@
 	err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);
 	if (err)
 		goto badframe; 
-	set_fs (KERNEL_DS);   
+
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
+	set_fs (KERNEL_DS);   
 	do_sigaltstack(&st, NULL, regs->gprs[15]);
 	set_fs (old_fs);
 
 	return regs->gprs[2];
 
 badframe:
-	force_sig(SIGSEGV, current);
-	return 0;
+        force_sig(SIGSEGV, current);
+        return 0;
 }	
 
 /*
@@ -444,58 +438,54 @@
 	return (void *)((sp - frame_size) & -8ul);
 }
 
-static void *setup_frame_common32(int sig, struct k_sigaction *ka,
-			sigset_t *set, struct pt_regs * regs,
-				int frame_size,u16 retcode)
+static inline int map_signal(int sig)
 {
-	sigframe32 *frame;
-	int err;
+	if (current->exec_domain
+	    && current->exec_domain->signal_invmap
+	    && sig < 32)
+		return current->exec_domain->signal_invmap[sig];
+        else
+		return sig;
+}
 
-	frame = get_sigframe(ka, regs,frame_size);
-	if (!access_ok(VERIFY_WRITE, frame,frame_size))
-		return 0;
-	err = save_sigregs32(regs,&frame->sregs);
-	if(!err)
-		err=__put_user(&frame->sregs,&frame->sc.sregs);
-	if(!err)
+static void setup_frame32(int sig, struct k_sigaction *ka,
+			sigset_t *set, struct pt_regs * regs)
+{
+	sigframe32 *frame = get_sigframe(ka, regs, sizeof(sigframe32));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32)))
+		goto give_sigsegv;
+
+	if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32))
+		goto give_sigsegv;
+
+	if (save_sigregs32(regs, &frame->sregs))
+		goto give_sigsegv;
+	if (__put_user(&frame->sregs, &frame->sc.sregs))
+		goto give_sigsegv;
 
-		err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE32);
-	if(!err)
-	{
-		regs->gprs[2]=(current->exec_domain
-		           && current->exec_domain->signal_invmap
-		           && sig < 32
-		           ? current->exec_domain->signal_invmap[sig]
-		           : sig);
-		/* Set up registers for signal handler */
-		regs->gprs[15] = (addr_t)frame;
-		regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
-	}
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
 	if (ka->sa.sa_flags & SA_RESTORER) {
-                regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
+		regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
 	} else {
-                regs->gprs[14] = FIX_PSW(frame->retcode);
-		err |= __put_user(retcode, (u16 *)(frame->retcode));
-	}
-	return(err ? 0:frame);
-}
+		regs->gprs[14] = FIX_PSW(frame->retcode);
+		if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
+		               (u16 *)(frame->retcode)))
+			goto give_sigsegv;
+        }
 
-static void setup_frame32(int sig, struct k_sigaction *ka,
-			sigset_t *set, struct pt_regs * regs)
-{
-	sigframe32 *frame;
-         
-	if((frame=setup_frame_common32(sig,ka,set,regs,sizeof(sigframe32),
-		    (S390_SYSCALL_OPCODE|__NR_sigreturn)))==0)
-		goto give_sigsegv;
-#if DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
-		current->comm, current->pid, frame, regs->eip, frame->pretcode);
-#endif
-	 /* Martin wants this for pthreads */
-	regs->gprs[3] = (addr_t)&frame->sc;   
+	/* Set up registers for signal handler */
+	regs->gprs[15] = (addr_t)frame;
+	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+	regs->psw.mask = _USER_PSW_MASK32;
+
+	regs->gprs[2] = map_signal(sig);
+	regs->gprs[3] = (addr_t)&frame->sc;
+
+	/* We forgot to include these in the sigcontext.
+	   To avoid breaking binary compatibility, they are passed as args. */
+	regs->gprs[4] = current->thread.trap_no;
+	regs->gprs[5] = current->thread.prot_addr;
 	return;
 
 give_sigsegv:
@@ -507,33 +497,44 @@
 static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
 			   sigset_t *set, struct pt_regs * regs)
 {
-	rt_sigframe32 *frame;
-	addr_t      orig_sp=regs->gprs[15];
-	int err;
+	int err = 0;
+	rt_sigframe32 *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32)))
+		goto give_sigsegv;
 
-	if((frame=setup_frame_common32(sig,ka,set,regs,sizeof(rt_sigframe32),
-		    (S390_SYSCALL_OPCODE|__NR_rt_sigreturn)))==0)
+	if (copy_siginfo_to_user32(&frame->info, info))
 		goto give_sigsegv;
-	
-	err = copy_siginfo_to_user32(&frame->info, info);
 
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __put_user(0, &frame->uc.uc_link);
 	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-	err |= __put_user(sas_ss_flags(orig_sp),
-			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(sas_ss_flags(regs->gprs[15]),
+	                  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-	regs->gprs[3] = (addr_t)&frame->info;
-	regs->gprs[4] = (addr_t)&frame->uc;
-
+	err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 	if (err)
 		goto give_sigsegv;
 
-#if DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
-		current->comm, current->pid, frame, regs->eip, frame->pretcode);
-#endif
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
+	} else {
+		regs->gprs[14] = FIX_PSW(frame->retcode);
+		err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
+		                  (u16 *)(frame->retcode));
+	}
+
+	/* Set up registers for signal handler */
+	regs->gprs[15] = (addr_t)frame;
+	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+	regs->psw.mask = _USER_PSW_MASK32;
+
+	regs->gprs[2] = map_signal(sig);
+	regs->gprs[3] = (addr_t)&frame->info;
+	regs->gprs[4] = (addr_t)&frame->uc;
 	return;
 
 give_sigsegv:
@@ -551,7 +552,7 @@
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
 	/* Are we from a system call? */
-	if (regs->orig_gpr2 >= 0) {
+	if (regs->trap == __LC_SVC_OLD_PSW) {
 		/* If so, check system call restarting.. */
 		switch (regs->gprs[2]) {
 			case -ERESTARTNOHAND:
@@ -692,12 +693,12 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
+			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
                                 if (do_coredump(signr, regs))
                                         exit_code |= 0x80;
                                 /* FALLTHRU */
 
 			default:
-				lock_kernel();
 				sigaddset(&current->pending.signal, signr);
 				recalc_sigpending(current);
 				current->flags |= PF_SIGNALED;
@@ -712,7 +713,7 @@
 	}
 
 	/* Did we come from a system call? */
-	if ( regs->trap ==  __LC_SVC_OLD_PSW /* System Call! */ ) {
+	if ( regs->trap == __LC_SVC_OLD_PSW /* System Call! */ ) {
 		/* Restart the system call - no handlers present */
 		if (regs->gprs[2] == -ERESTARTNOHAND ||
 		    regs->gprs[2] == -ERESTARTSYS ||
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/smp.c linux/arch/s390x/kernel/smp.c
--- v2.4.12/linux/arch/s390x/kernel/smp.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390x/kernel/smp.c	Thu Oct 11 09:04:57 2001
@@ -57,6 +57,8 @@
 
 spinlock_t       kernel_flag = SPIN_LOCK_UNLOCKED;
 
+unsigned long	 cpu_online_map;
+
 /*
  *      Setup routine for controlling SMP activation
  *
@@ -92,6 +94,95 @@
 
 extern void reipl(unsigned long devno);
 
+static sigp_ccode smp_ext_bitcall(int, ec_bit_sig);
+static void smp_ext_bitcall_others(ec_bit_sig);
+
+/*
+ * Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ */
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+
+struct call_data_struct {
+	void (*func) (void *info);
+	void *info;
+	atomic_t started;
+	atomic_t finished;
+	int wait;
+};
+
+static struct call_data_struct * call_data;
+
+/*
+ * 'Call function' interrupt callback
+ */
+static void do_call_function(void)
+{
+	void (*func) (void *info) = call_data->func;
+	void *info = call_data->info;
+	int wait = call_data->wait;
+
+	atomic_inc(&call_data->started);
+	(*func)(info);
+	if (wait)
+		atomic_inc(&call_data->finished);
+}
+
+/*
+ * this function sends a 'generic call function' IPI to all other CPUs
+ * in the system.
+ */
+
+int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+			int wait)
+/*
+ * [SUMMARY] Run a function on all other CPUs.
+ * <func> The function to run. This must be fast and non-blocking.
+ * <info> An arbitrary pointer to pass to the function.
+ * <nonatomic> currently unused.
+ * <wait> If true, wait (atomically) until function has completed on other CPUs.
+ * [RETURNS] 0 on success, else a negative status code. Does not return until
+ * remote CPUs are nearly ready to execute <<func>> or are or have executed.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler, you may call it from a bottom half handler.
+ */
+{
+	struct call_data_struct data;
+	int cpus = smp_num_cpus-1;
+
+	if (!cpus || !atomic_read(&smp_commenced))
+		return 0;
+
+	data.func = func;
+	data.info = info;
+	atomic_set(&data.started, 0);
+	data.wait = wait;
+	if (wait)
+		atomic_set(&data.finished, 0);
+
+	spin_lock_bh(&call_lock);
+	call_data = &data;
+	/* Send a message to all other CPUs and wait for them to respond */
+        smp_ext_bitcall_others(ec_call_function);
+
+	/* Wait for response */
+	while (atomic_read(&data.started) != cpus)
+		barrier();
+
+	if (wait)
+		while (atomic_read(&data.finished) != cpus)
+			barrier();
+	spin_unlock_bh(&call_lock);
+
+	return 0;
+}
+
+
+/*
+ * Various special callbacks
+ */
+
 void do_machine_restart(void)
 {
         smp_send_stop();
@@ -148,7 +239,6 @@
 
 void do_ext_call_interrupt(struct pt_regs *regs, __u16 code)
 {
-        ec_ext_call *ec, *next;
         unsigned long bits;
 
         /*
@@ -167,138 +257,15 @@
 		do_machine_halt();
         if (test_bit(ec_power_off, &bits))
 		do_machine_power_off();
-
-        /*
-         * Handle external call commands with a parameter area
-         */
-	ec = (ec_ext_call *) xchg(&S390_lowcore.ext_call_queue, 0);
-        if (ec == NULL)
-                return;   /* no command signals */
-
-        /* Make a fifo out of the lifo */
-        next = ec->next;
-        ec->next = NULL;
-        while (next != NULL) {
-                ec_ext_call *tmp = next->next;
-                next->next = ec;
-                ec = next;
-                next = tmp;
-        }
-
-        /* Execute every sigp command on the queue */
-        while (ec != NULL) {
-                switch (ec->cmd) {
-                case ec_callback_async: {
-                        void (*func)(void *info);
-                        void *info;
-
-                        func = ec->func;
-                        info = ec->info;
-                        atomic_set(&ec->status,ec_executing);
-                        (func)(info);
-                        return;
-                }
-                case ec_callback_sync:
-                        atomic_set(&ec->status,ec_executing);
-                        (ec->func)(ec->info);
-                        atomic_set(&ec->status,ec_done);
-                        return;
-                default:
-                }
-                ec = ec->next;
-        }
-}
-
-/*
- * Swap in a new request to external call queue 
- */
-static inline void smp_add_ext_call(ec_ext_call *ec, struct _lowcore *lowcore)
-{
-	int success;
-
-	while (1) {
-		ec->next = (ec_ext_call*) lowcore->ext_call_queue;
-		__asm__ __volatile__ (
-                        "   lgr 0,%2\n"
-			"   csg 0,%3,%1\n"
-			"   ipm %0\n"
-			"   srl %0,28\n"
-			: "=d" (success), "+m" (lowcore->ext_call_queue)
-			: "d" (ec->next), "d" (ec)
-			: "cc", "0" );
-		if (success == 0) break;
-	}
-}
-
-/*
- * Send an external call sigp to another cpu and wait for its completion.
- */
-sigp_ccode
-smp_ext_call(int cpu, void (*func)(void *info), void *info, int wait)
-{
-        sigp_ccode ccode;
-        ec_ext_call ec;
-
-        ec.cmd = wait ? ec_callback_sync:ec_callback_async;
-        atomic_set(&ec.status, ec_pending);
-        ec.func = func;
-	ec.info = info;
-	/* swap in new request to external call queue */
-	smp_add_ext_call(&ec, &get_cpu_lowcore(cpu));
-        /*
-         * We try once to deliver the signal. There are four possible
-         * return codes:
-         * 0) Order code accepted - can't show up on an external call
-         * 1) Status stored - fine, wait for completion.
-         * 2) Busy - there is another signal pending. Thats fine too, because
-         *    do_ext_call from the pending signal will execute all signals on
-         *    the queue. We wait for completion.
-         * 3) Not operational - something very bad has happened to the cpu.
-         *    do not wait for completion.
-         */
-        ccode = signal_processor(cpu, sigp_external_call);
-
-        if (ccode != sigp_not_operational)
-                /* wait for completion, FIXME: possible seed of a deadlock */
-                while (atomic_read(&ec.status) != (wait?ec_done:ec_executing));
-
-        return ccode;
-}
-
-/*
- * Send a callback sigp to every other cpu in the system.
- */
-void smp_ext_call_others(void (*func)(void *info), void *info, int wait)
-{
-        ec_ext_call ec[NR_CPUS];
-        sigp_ccode ccode;
-        int i;
-
-        for (i = 0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() == i)
-                        continue;
-		ec[i].cmd = wait ? ec_callback_sync : ec_callback_async;
-		atomic_set(&ec[i].status, ec_pending);
-		ec[i].func = func;
-		ec[i].info = info;
-		smp_add_ext_call(ec+i, &get_cpu_lowcore(i));
-                ccode = signal_processor(i, sigp_external_call);
-        }
-
-        /* wait for completion, FIXME: possible seed of a deadlock */
-        for (i = 0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() == i)
-                        continue;
-                while (atomic_read(&ec[i].status) != 
-		       (wait ? ec_done:ec_executing));
-        }
+        if (test_bit(ec_call_function, &bits))
+		do_call_function();
 }
 
 /*
  * Send an external call sigp to another cpu and return without waiting
  * for its completion.
  */
-sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig)
+static sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig)
 {
         sigp_ccode ccode;
 
@@ -314,7 +281,7 @@
  * Send an external call sigp to every other cpu in the system and
  * return without waiting for its completion.
  */
-void smp_ext_bitcall_others(ec_bit_sig sig)
+static void smp_ext_bitcall_others(ec_bit_sig sig)
 {
         sigp_ccode ccode;
         int i;
@@ -331,51 +298,6 @@
 }
 
 /*
- * cycles through all the cpus,
- * returns early if info is not NULL & the processor has something
- * of intrest to report in the info structure.
- * it returns the next cpu to check if it returns early.
- * i.e. it should be used as follows if you wish to receive info.
- * next_cpu=0;
- * do
- * {
- *    info->cpu=next_cpu;
- *    next_cpu=smp_signal_others(order_code,parameter,1,info);
- *    ... check info here
- * } while(next_cpu<=smp_num_cpus)
- *
- *  if you are lazy just use it like
- * smp_signal_others(order_code,parameter,0,1,NULL);
- */
-int smp_signal_others(sigp_order_code order_code, u32 parameter,
-                      int spin, sigp_info *info)
-{
-        sigp_ccode   ccode;
-        u32          dummy;
-        u16          i;
-
-        if (info)
-                info->intresting = 0;
-        for (i = (info ? info->cpu : 0); i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        do {
-                                ccode = signal_processor_ps(
-                                        (info ? &info->status : &dummy),
-                                        parameter, i, order_code);
-                        } while(spin && ccode == sigp_busy);
-                        if (info && ccode != sigp_order_code_accepted) {
-                                info->intresting = 1;
-                                info->cpu = i;
-                                info->ccode = ccode;
-                                i++;
-                                break;
-                        }
-                }
-        }
-        return i;
-}
-
-/*
  * this function sends a 'stop' sigp to all other CPUs in the system.
  * it goes straight through.
  */
@@ -392,7 +314,18 @@
 
         /* stop all processors */
 
-        smp_signal_others(sigp_stop, 0, 1, NULL);
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() != i) {
+                        int ccode;
+                        do {
+                                ccode = signal_processor_ps(
+                                   &dummy,
+                                   0,
+                                   i,
+                                   sigp_stop);
+                        } while(ccode == sigp_busy);
+                }
+        }
 
         /* store status of all processors in their lowcores (real 0) */
 
@@ -469,7 +402,7 @@
                 parms.end_ctl = cr;
                 parms.orvals[cr] = 1 << bit;
                 parms.andvals[cr] = -1L;
-                smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
+                smp_call_function(smp_ctl_bit_callback, &parms, 0, 1);
         }
         __ctl_set_bit(cr, bit);
 }
@@ -485,34 +418,11 @@
                 parms.end_ctl = cr;
                 parms.orvals[cr] = 0;
                 parms.andvals[cr] = ~(1L << bit);
-                smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
+                smp_call_function(smp_ctl_bit_callback, &parms, 0, 1);
         }
         __ctl_clear_bit(cr, bit);
 }
 
-/*
- * Call a function on all other processors
- */
-
-int
-smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
-/*
- * [SUMMARY] Run a function on all other CPUs.
- * <func> The function to run. This must be fast and non-blocking.
- * <info> An arbitrary pointer to pass to the function.
- * <retry> currently unused.
- * <wait> If true, wait (atomically) until function has completed on other CPUs.
- * [RETURNS] 0 on success, else a negative status code. Does not return until
- * remote CPUs are nearly ready to execute <<func>> or are or have executed.
- *
- * You must not call this function with disabled interrupts or from a
- * hardware interrupt handler, you may call it from a bottom half handler.
- */
-{
-        if (atomic_read(&smp_commenced) != 0)
-                smp_ext_call_others(func, info, wait);
-        return 0;
-}
 
 /*
  * Lets check how many CPUs we have.
@@ -607,15 +517,20 @@
         init_tasks[cpu] = idle;
 
         cpu_lowcore=&get_cpu_lowcore(cpu);
-        cpu_lowcore->kernel_stack=idle->thread.ksp;
-        __asm__ __volatile__("stctg 0,15,%0\n\t"
-                             "stam  0,15,%1"
+	cpu_lowcore->save_area[15] = idle->thread.ksp;
+	cpu_lowcore->kernel_stack = (idle->thread.ksp | 16383) + 1;
+        __asm__ __volatile__("la    1,%0\n\t"
+			     "stctg 0,15,0(1)\n\t"
+			     "la    1,%1\n\t"
+                             "stam  0,15,0(1)"
                              : "=m" (cpu_lowcore->cregs_save_area[0]),
                                "=m" (cpu_lowcore->access_regs_save_area[0])
-                             : : "memory");
+                             : : "1", "memory");
 
         eieio();
         signal_processor(cpu,sigp_restart);
+	/* Mark this cpu as online. */
+	set_bit(cpu, &cpu_online_map);
 }
 
 /*
@@ -643,6 +558,7 @@
 void __init smp_boot_cpus(void)
 {
         struct _lowcore *curr_lowcore;
+	unsigned long async_stack;
         sigp_ccode   ccode;
         int i;
 
@@ -673,8 +589,16 @@
                         printk("smp_boot_cpus failed to allocate prefix memory\n");
                         break;
                 }
+		async_stack = __get_free_pages(GFP_KERNEL,2);
+		if (async_stack == 0) {
+			printk("smp_boot_cpus failed to allocate asyncronous"
+			       " interrupt stack\n");
+			free_page((unsigned long) curr_lowcore);
+			break;
+		}
                 lowcore_ptr[i] = curr_lowcore;
                 memcpy(curr_lowcore, &S390_lowcore, sizeof(struct _lowcore));
+		curr_lowcore->async_stack = async_stack + (4 * PAGE_SIZE);
                 /*
                  * Most of the parameters are set up when the cpu is
                  * started up.
@@ -733,8 +657,6 @@
                 s390_do_profile(regs->psw.addr);
 
         if (!--prof_counter[cpu]) {
-                int system = 1-user;
-                struct task_struct * p = current;
 
                 /*
                  * The multiplier may have changed since the last time we got
@@ -756,9 +678,7 @@
                  * WrongThing (tm) to do.
                  */
 
-                irq_enter(cpu, 0);
 		update_process_times(user);
-                irq_exit(cpu, 0);
         }
 }
 
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/time.c linux/arch/s390x/kernel/time.c
--- v2.4.12/linux/arch/s390x/kernel/time.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390x/kernel/time.c	Thu Oct 11 09:04:57 2001
@@ -155,17 +155,16 @@
 extern __u16 boot_cpu_addr;
 #endif
 
-void do_timer_interrupt(struct pt_regs *regs,int error_code)
+void do_timer_interrupt(struct pt_regs *regs, __u16 error_code)
 {
-        unsigned long flags;
+	int cpu = smp_processor_id();
+
+	irq_enter(cpu, 0);
 
         /*
          * reset timer to 10ms minus time already elapsed
          * since timer-interrupt pending
          */
- 
-        save_flags(flags);
-        cli();
 #ifdef CONFIG_SMP
 	if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) {
 		write_lock(&xtime_lock);
@@ -201,8 +200,8 @@
 		write_unlock(&xtime_lock);
 #endif
 	}
-        restore_flags(flags);
 
+	irq_exit(cpu, 0);
 }
 
 /*
@@ -256,4 +255,7 @@
         init_timer_cc -= 0x8126d60e46000000LL -
                          (0x3c26700LL*1000000*4096);
         tod_to_timeval(init_timer_cc, &xtime);
+
+	/* Set do_get_fast_time function pointer.  */
+	do_get_fast_time = do_gettimeofday;
 }
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/traps.c linux/arch/s390x/kernel/traps.c
--- v2.4.12/linux/arch/s390x/kernel/traps.c	Sun Aug 12 13:27:58 2001
+++ linux/arch/s390x/kernel/traps.c	Thu Oct 11 09:04:57 2001
@@ -31,7 +31,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/atomic.h>
-#include <asm/mathemu.h>
 #if CONFIG_REMOTE_DEBUG
 #include <asm/gdb-stub.h>
 #endif
@@ -59,14 +58,16 @@
 extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
 #endif
 
-spinlock_t die_lock;
+spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
         console_verbose();
         spin_lock_irq(&die_lock);
+	bust_spinlocks(1);
         printk("%s: %04lx\n", str, err & 0xffff);
         show_regs(regs);
+	bust_spinlocks(0);
         spin_unlock_irq(&die_lock);
         do_exit(SIGSEGV);
 }
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/kernel/wrapper32.S linux/arch/s390x/kernel/wrapper32.S
--- v2.4.12/linux/arch/s390x/kernel/wrapper32.S	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/wrapper32.S	Thu Oct 11 09:04:57 2001
@@ -1069,3 +1069,23 @@
 	llgfr	%r4,%r4			# unsigned long
 	jg	sys32_fcntl64		# branch to system call
 
+	.globl	sys32_stat64_wrapper
+sys32_stat64_wrapper:
+	llgtr	%r2,%r2			# char *
+	llgtr	%r3,%r3			# struct stat64 *
+	llgfr	%r4,%r4			# long
+	jg	sys32_stat64		# branch to system call
+
+	.globl	sys32_lstat64_wrapper
+sys32_lstat64_wrapper:
+	llgtr	%r2,%r2			# char *
+	llgtr	%r3,%r3			# struct stat64 *
+	llgfr	%r4,%r4			# long
+	jg	sys32_lstat64		# branch to system call
+
+	.globl	sys32_fstat64_wrapper
+sys32_fstat64_wrapper:
+	llgfr	%r2,%r2			# unsigned long
+	llgtr	%r3,%r3			# struct stat64 *
+	llgfr	%r4,%r4			# long
+	jg	sys32_fstat64		# branch to system call
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/mm/extable.c linux/arch/s390x/mm/extable.c
--- v2.4.12/linux/arch/s390x/mm/extable.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/mm/extable.c	Thu Oct 11 09:04:57 2001
@@ -10,6 +10,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
 extern const struct exception_table_entry __start___ex_table[];
@@ -36,26 +37,32 @@
         return 0;
 }
 
+extern spinlock_t modlist_lock;
+
 unsigned long
 search_exception_table(unsigned long addr)
 {
-	unsigned long ret;
+	unsigned long ret = 0;
+	unsigned long flags;
 
 #ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
-	if (ret) return FIX_PSW(ret);
+	return ret;
 #else
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
+
+	spin_lock_irqsave(&modlist_lock, flags);
 	for (mp = module_list; mp != NULL; mp = mp->next) {
-		if (mp->ex_table_start == NULL)
+		if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
 			continue;
 		ret = search_one_table(mp->ex_table_start,
 				       mp->ex_table_end - 1, addr);
-		if (ret) return FIX_PSW(ret);
+		if (ret) 
+			break;
 	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
+	return ret;
 #endif
-
-	return 0;
 }
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/mm/fault.c linux/arch/s390x/mm/fault.c
--- v2.4.12/linux/arch/s390x/mm/fault.c	Sun Aug 12 13:27:59 2001
+++ linux/arch/s390x/mm/fault.c	Thu Oct 11 09:04:57 2001
@@ -4,6 +4,7 @@
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Hartmut Penner (hp@de.ibm.com)
+ *               Ulrich Weigand (uweigand@de.ibm.com)
  *
  *  Derived from "arch/i386/mm/fault.c"
  *    Copyright (C) 1995  Linus Torvalds
@@ -22,6 +23,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/console.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -33,33 +35,33 @@
 #endif
 
 extern void die(const char *,struct pt_regs *,long);
+static void force_sigsegv(struct task_struct *tsk, int code, void *address);
 
 extern spinlock_t timerlist_lock;
 
 /*
  * Unlock any spinlocks which will prevent us from getting the
- * message out
+ * message out (timerlist_lock is acquired through the
+ * console unblank code)
  */
 void bust_spinlocks(int yes)
 {
-        spin_lock_init(&timerlist_lock);
-        if (yes) {
-                oops_in_progress = 1;
-#ifdef CONFIG_SMP
-                atomic_set(&global_irq_lock,0);
-#endif
-        } else {
-                int loglevel_save = console_loglevel;
-                oops_in_progress = 0;
-                /*
-                 * OK, the message is on the console.  Now we call printk()
-                 * without oops_in_progress set so that printk will give klogd
-                 * a poke.  Hold onto your hats...
-                 */
-                console_loglevel = 15;          /* NMI oopser may have shut the console up */
-                printk(" ");
-                console_loglevel = loglevel_save;
-        }
+	spin_lock_init(&timerlist_lock);
+	if (yes) {
+		oops_in_progress = 1;
+	} else {
+		int loglevel_save = console_loglevel;
+		oops_in_progress = 0;
+		console_unblank();
+		/*
+		 * OK, the message is on the console.  Now we call printk()
+		 * without oops_in_progress set so that printk will give klogd
+		 * a poke.  Hold onto your hats...
+		 */
+		console_loglevel = 15;
+		printk(" ");
+		console_loglevel = loglevel_save;
+	}
 }
 
 /*
@@ -84,6 +86,29 @@
 	int si_code = SEGV_MAPERR;
 	int kernel_address = 0;
 
+        tsk = current;
+        mm = tsk->mm;
+	
+	/* 
+         * Check for low-address protection.  This needs to be treated
+	 * as a special case because the translation exception code 
+	 * field is not guaranteed to contain valid data in this case.
+	 */
+	if ((error_code & 0xff) == 4 && !(S390_lowcore.trans_exc_code & 4)) {
+
+		/* Low-address protection hit in kernel mode means 
+		   NULL pointer write access in kernel mode.  */
+ 		if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
+			address = 0;
+			kernel_address = 1;
+			goto no_context;
+		}
+
+		/* Low-address protection hit in user mode 'cannot happen'.  */
+		die ("Low-address protection", regs, error_code);
+        	do_exit(SIGKILL);
+	}
+
         /* 
          * get the failing address 
          * more specific the segment and page table portion of 
@@ -92,11 +117,6 @@
 
         address = S390_lowcore.trans_exc_code&-4096L;
 
-        tsk = current;
-        mm = tsk->mm;
-
-        if (in_interrupt() || !mm)
-                goto no_context;
 
 	/*
 	 * Check which address space the address belongs to
@@ -127,6 +147,7 @@
 			}
 		}
 		die("page fault via unknown access register", regs, error_code);
+        	do_exit(SIGKILL);
 		break;
 
 	case 2: /* Secondary Segment Table Descriptor */
@@ -135,6 +156,11 @@
 		break;
 	}
 
+	/*
+	 * Check whether we have a user MM in the first place.
+	 */
+        if (in_interrupt() || !mm)
+                goto no_context;
 
 	/*
 	 * When we get here, the fault happened in the current
@@ -144,10 +170,8 @@
         down_read(&mm->mmap_sem);
 
         vma = find_vma(mm, address);
-        if (!vma) {
-	        printk("no vma for address %lX\n",address);
+        if (!vma)
                 goto bad_area;
-        }
         if (vma->vm_start <= address) 
                 goto good_area;
         if (!(vma->vm_flags & VM_GROWSDOWN))
@@ -177,6 +201,7 @@
                        goto bad_area;
         }
 
+ survive:
 	/*
 	 * If for any reason at all we couldn't handle the fault,
 	 * make sure we exit gracefully rather than endlessly redo
@@ -207,7 +232,6 @@
 
         /* User mode accesses just cause a SIGSEGV */
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
-		struct siginfo si;
                 tsk->thread.prot_addr = address;
                 tsk->thread.trap_no = error_code;
 #ifndef CONFIG_SYSCTL
@@ -224,10 +248,8 @@
 			show_regs(regs);
 		}
 #endif
-		si.si_signo = SIGSEGV;
-		si.si_code = si_code;
-		si.si_addr = (void*) address;
-		force_sig_info(SIGSEGV, &si, tsk);
+
+		force_sigsegv(tsk, si_code, (void *)address);
                 return;
 	}
 
@@ -242,6 +264,7 @@
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
  */
+
         if (kernel_address)
                 printk(KERN_ALERT "Unable to handle kernel pointer dereference"
         	       " at virtual kernel address %016lx\n", address);
@@ -249,10 +272,6 @@
                 printk(KERN_ALERT "Unable to handle kernel paging request"
 		       " at virtual user address %016lx\n", address);
 
-/*
- * need to define, which information is useful here
- */
-
         die("Oops", regs, error_code);
         do_exit(SIGKILL);
 
@@ -263,6 +282,12 @@
 */
 out_of_memory:
 	up_read(&mm->mmap_sem);
+	if (tsk->pid == 1) {
+		tsk->policy |= SCHED_YIELD;
+		schedule();
+		down_read(&mm->mmap_sem);
+		goto survive;
+	}
 	printk("VM: killing process %s\n", tsk->comm);
 	if (regs->psw.mask & PSW_PROBLEM_STATE)
 		do_exit(SIGKILL);
@@ -284,6 +309,20 @@
 		goto no_context;
 }
 
+/*
+ * Send SIGSEGV to task.  This is an external routine
+ * to keep the stack usage of do_page_fault small.
+ */
+static void force_sigsegv(struct task_struct *tsk, int code, void *address)
+{
+	struct siginfo si;
+	si.si_signo = SIGSEGV;
+	si.si_code = code;
+	si.si_addr = address;
+	force_sig_info(SIGSEGV, &si, tsk);
+}
+
+
 #ifdef CONFIG_PFAULT
 /*
  * 'pfault' pseudo page faults routines.
@@ -316,13 +355,11 @@
        int resolved;
 } pseudo_wait_t;
 
-static pseudo_wait_t *pseudo_lock_queue = NULL;
-static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */
-
 int pfault_init(void)
 {
 	pfault_refbk_t refbk =
-	{ 0x258, 0, 5, 2, __LC_KERNEL_STACK, 1ULL << 48, 1ULL << 48, 0ULL };
+	{ 0x258, 0, 5, 2, __LC_KERNEL_STACK, 1ULL << 48, 1ULL << 48,
+          0x8000000000000000ULL };
         int rc;
 
 	if (pfault_disable)
@@ -362,7 +399,6 @@
 asmlinkage void
 pfault_interrupt(struct pt_regs *regs, __u16 error_code)
 {
-        DECLARE_WAITQUEUE(wait, current);
 	struct task_struct *tsk;
 	wait_queue_head_t queue;
 	wait_queue_head_t *qp;
@@ -375,7 +411,7 @@
          * external interrupt. 
 	 */
 	subcode = S390_lowcore.cpu_addr;
-	if ((subcode & 0xff00) != 0x06)
+	if ((subcode & 0xff00) != 0x0600)
 		return;
 
 	/*
diff -u --recursive --new-file v2.4.12/linux/arch/s390x/mm/init.c linux/arch/s390x/mm/init.c
--- v2.4.12/linux/arch/s390x/mm/init.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/s390x/mm/init.c	Thu Oct 11 09:04:57 2001
@@ -36,7 +36,7 @@
 #include <asm/dma.h>
 #include <asm/lowcore.h>
 #include <asm/tlb.h>
- 
+
 mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
@@ -44,44 +44,23 @@
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 
-static int test_access(unsigned long loc)
-{
-	static const int ssm_mask = 0x07000000L;
-	int rc, i;
-
-        rc = 0;
-	for (i=0; i<2; i++) {
-		__asm__ __volatile__(
-                        "    slgr  %0,%0\n"
-			"    ssm   %1\n"
-			"    tprot 0(%2),0\n"
-			"0:  jne   1f\n"
-			"    lghi  %0,1\n"
-			"1:  ssm   %3\n"
-                        ".section __ex_table,\"a\"\n"
-                        "   .align 8\n"
-                        "   .quad  0b,1b\n"
-                        ".previous"
-			: "+&d" (rc) : "i" (0), "a" (loc), "m" (ssm_mask)
-			: "cc");
-		if (rc == 0)
-			break;
-		loc += 0x100000;
-	}
-	return rc;
-}
-
 int do_check_pgt_cache(int low, int high)
 {
         int freed = 0;
         if(pgtable_cache_size > high) {
                 do {
-                        if(pgd_quicklist)
-                                free_pgd_slow(get_pgd_fast()), freed += 4;
-                        if(pmd_quicklist)
-                                pmd_free_slow(pmd_alloc_one_fast(NULL, 0)), freed += 4;
-                        if(pte_quicklist)
-                                pte_free_slow(pte_alloc_one_fast(NULL, 0)), freed++;
+                        if(pgd_quicklist) {
+				free_pgd_slow(get_pgd_fast());
+				freed += 4;
+			}
+                        if(pmd_quicklist) {
+				pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
+				freed += 4;
+			}
+                        if(pte_quicklist) {
+				pte_free_slow(pte_alloc_one_fast(NULL, 0));
+				freed += 4;
+			}
                 } while(pgtable_cache_size > low);
         }
         return freed;
@@ -139,7 +118,7 @@
 	int     i,j,k;
         unsigned long address=0;
         unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) |
-          _REGION_TABLE;
+          _KERN_REGION_TABLE;
 	unsigned long end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE);
 	static const int ssm_mask = 0x04000000L;
 
@@ -212,7 +191,6 @@
 void __init mem_init(void)
 {
 	unsigned long codesize, reservedpages, datasize, initsize;
-        unsigned long tmp;
 
         max_mapnr = num_physpages = max_low_pfn;
         high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
@@ -223,25 +201,7 @@
 	/* this will put all low memory onto the freelists */
 	totalram_pages += free_all_bootmem();
 
-        /* mark usable pages in the mem_map[] and count reserved pages */
 	reservedpages = 0;
-	tmp = 0;
-	do {
-		if (tmp && (tmp & 0x1ff) == 0 && 
-                    test_access(tmp * PAGE_SIZE) == 0) {
-                        printk("2M Segment 0x%016lX not available\n",
-                               tmp * PAGE_SIZE);
-			do {
-                                set_bit(PG_reserved, &mem_map[tmp].flags);
-				reservedpages++;
-				tmp++;
-			} while (tmp < max_low_pfn && (tmp & 0x1ff));
-		} else {
-			if (PageReserved(mem_map+tmp))
-				reservedpages++;
-			tmp++;
-		}
-	} while (tmp < max_low_pfn);
 
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
diff -u --recursive --new-file v2.4.12/linux/arch/sh/Makefile linux/arch/sh/Makefile
--- v2.4.12/linux/arch/sh/Makefile	Sun Sep 23 11:40:56 2001
+++ linux/arch/sh/Makefile	Mon Oct 15 13:36:48 2001
@@ -12,11 +12,6 @@
 # this architecture
 #
 
-#
-# Select the object file format to substitute into the linker script.
-#
-tool_prefix	= sh-linux-gnu-
-
 ifdef CONFIG_CPU_LITTLE_ENDIAN
 CFLAGS		+= -ml
 AFLAGS		+= -ml
@@ -29,10 +24,6 @@
 LDFLAGS		:= -EB
 endif
 
-# ifdef CONFIG_CROSSCOMPILE
-CROSS_COMPILE  = $(tool_prefix)
-# endif
-
 LD	=$(CROSS_COMPILE)ld $(LDFLAGS)
 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -R .stab -R .stabstr -S
 
@@ -46,8 +37,8 @@
 AFLAGS		+= -m3
 endif
 ifdef CONFIG_CPU_SH4
-CFLAGS		+= -m4-nofpu
-AFLAGS		+= -m4-nofpu
+CFLAGS		+= -m4 -mno-implicit-fp
+AFLAGS		+= -m4 -mno-implicit-fp
 endif
 
 #
diff -u --recursive --new-file v2.4.12/linux/arch/sh/config.in linux/arch/sh/config.in
--- v2.4.12/linux/arch/sh/config.in	Sun Sep 23 11:40:56 2001
+++ linux/arch/sh/config.in	Mon Oct 15 13:36:48 2001
@@ -90,8 +90,17 @@
 fi
 bool 'Little Endian' CONFIG_CPU_LITTLE_ENDIAN
 # Platform-specific memory start and size definitions
-if [ "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o "$CONFIG_SH_HP600" = "y" -o \
-     "$CONFIG_SH_BIGSUR" = "y" -o "$CONFIG_SH_7751_SOLUTION_ENGINE" = "y" -o \
+if [ "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then
+   define_hex CONFIG_MEMORY_START 0c000000
+   define_hex CONFIG_MEMORY_SIZE 02000000
+   define_bool CONFIG_MEMORY_SET y
+fi
+if [ "$CONFIG_SH_7751_SOLUTION_ENGINE" = "y" ]; then
+   define_hex CONFIG_MEMORY_START 0c000000
+   define_hex CONFIG_MEMORY_SIZE 04000000
+   define_bool CONFIG_MEMORY_SET y
+fi
+if [ "$CONFIG_SH_HP600" = "y" -o "$CONFIG_SH_BIGSUR" = "y" -o \
      "$CONFIG_SH_DREAMCAST" = "y" -o "$CONFIG_SH_SH2000" = "y" ]; then
    define_hex CONFIG_MEMORY_START 0c000000
    define_hex CONFIG_MEMORY_SIZE 00400000
@@ -326,6 +335,16 @@
    dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
 fi
 bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
+
+mainmenu_option next_comment
+comment 'Watchdog Cards'
+bool 'Watchdog Timer Support' CONFIG_WATCHDOG
+if [ "$CONFIG_WATCHDOG" != "n" ]; then
+   bool '  Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
+   dep_tristate '  SH 3/4 Watchdog' CONFIG_SH_WDT $CONFIG_SUPERH
+fi
+endmenu
+
 tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
 if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
    source drivers/char/pcmcia/Config.in
diff -u --recursive --new-file v2.4.12/linux/arch/sh/defconfig linux/arch/sh/defconfig
--- v2.4.12/linux/arch/sh/defconfig	Wed Aug  9 13:59:04 2000
+++ linux/arch/sh/defconfig	Mon Oct 15 13:36:48 2001
@@ -201,6 +201,4 @@
 #
 # CONFIG_MAGIC_SYSRQ is not set
 CONFIG_SH_STANDARD_BIOS=y
-CONFIG_DEBUG_KERNEL_WITH_GDB_STUB=y
-CONFIG_GDB_STUB_VBR=a0000000
 CONFIG_SH_EARLY_PRINTK=y
diff -u --recursive --new-file v2.4.12/linux/arch/sh/kernel/io_generic.c linux/arch/sh/kernel/io_generic.c
--- v2.4.12/linux/arch/sh/kernel/io_generic.c	Wed Apr 11 21:24:52 2001
+++ linux/arch/sh/kernel/io_generic.c	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: io_generic.c,v 1.3 2000/05/07 23:31:58 gniibe Exp $
+/* $Id: io_generic.c,v 1.12 2000/11/14 16:45:11 sugioka Exp $
  *
  * linux/arch/sh/kernel/io_generic.c
  *
diff -u --recursive --new-file v2.4.12/linux/arch/sh/kernel/io_hd64461.c linux/arch/sh/kernel/io_hd64461.c
--- v2.4.12/linux/arch/sh/kernel/io_hd64461.c	Wed Apr 11 21:24:52 2001
+++ linux/arch/sh/kernel/io_hd64461.c	Mon Oct 15 13:36:48 2001
@@ -1,5 +1,5 @@
 /*
- *	$Id: io_hd64461.c,v 1.1 2000/06/10 21:45:18 yaegashi Exp $
+ *	$Id: io_hd64461.c,v 1.6 2000/11/16 23:28:44 yaegashi Exp $
  *	Copyright (C) 2000 YAEGASHI Takeshi
  *	Typical I/O routines for HD64461 system.
  */
diff -u --recursive --new-file v2.4.12/linux/arch/sh/kernel/io_se.c linux/arch/sh/kernel/io_se.c
--- v2.4.12/linux/arch/sh/kernel/io_se.c	Wed Apr 11 21:24:52 2001
+++ linux/arch/sh/kernel/io_se.c	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: io_se.c,v 1.5 2000/06/08 05:50:10 gniibe Exp $
+/* $Id: io_se.c,v 1.12 2001/08/11 01:23:28 jzs Exp $
  *
  * linux/arch/sh/kernel/io_se.c
  *
diff -u --recursive --new-file v2.4.12/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c
--- v2.4.12/linux/arch/sh/kernel/process.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/sh/kernel/process.c	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.34 2001/07/30 12:42:11 gniibe Exp $
+/* $Id: process.c,v 1.35 2001/10/11 09:18:17 gniibe Exp $
  *
  *  linux/arch/sh/kernel/process.c
  *
diff -u --recursive --new-file v2.4.12/linux/arch/sh/kernel/ptrace.c linux/arch/sh/kernel/ptrace.c
--- v2.4.12/linux/arch/sh/kernel/ptrace.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sh/kernel/ptrace.c	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: ptrace.c,v 1.12 2001/07/23 00:00:56 gniibe Exp $
+/* $Id: ptrace.c,v 1.13 2001/10/01 02:21:50 gniibe Exp $
  *
  * linux/arch/sh/kernel/ptrace.c
  *
diff -u --recursive --new-file v2.4.12/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c
--- v2.4.12/linux/arch/sh/kernel/signal.c	Sun Jan 28 18:56:00 2001
+++ linux/arch/sh/kernel/signal.c	Mon Oct 15 13:36:48 2001
@@ -21,6 +21,7 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
+#include <linux/personality.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.4.12/linux/arch/sh/kernel/sys_sh.c linux/arch/sh/kernel/sys_sh.c
--- v2.4.12/linux/arch/sh/kernel/sys_sh.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sh/kernel/sys_sh.c	Mon Oct 15 13:36:48 2001
@@ -68,7 +68,10 @@
 	if (!addr)
 		addr = TASK_UNMAPPED_BASE;
 
-	addr = COLOUR_ALIGN(addr);
+	if (flags & MAP_PRIVATE)
+		addr = PAGE_ALIGN(addr);
+	else
+		addr = COLOUR_ALIGN(addr);
 
 	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
 		/* At this point:  (!vma || addr < vma->vm_end). */
@@ -77,7 +80,8 @@
 		if (!vma || addr + len <= vma->vm_start)
 			return addr;
 		addr = vma->vm_end;
-		addr = COLOUR_ALIGN(addr);
+		if (!(flags & MAP_PRIVATE))
+			addr = COLOUR_ALIGN(addr);
 	}
 }
 #endif
diff -u --recursive --new-file v2.4.12/linux/arch/sh/lib/memchr.S linux/arch/sh/lib/memchr.S
--- v2.4.12/linux/arch/sh/lib/memchr.S	Mon Oct 25 10:59:18 1999
+++ linux/arch/sh/lib/memchr.S	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: memchr.S,v 1.1 1999/10/17 11:32:38 gniibe Exp $
+/* $Id: memchr.S,v 1.1 2000/04/14 16:49:01 mjd Exp $
  *
  * "memchr" implementation of SuperH
  *
diff -u --recursive --new-file v2.4.12/linux/arch/sh/lib/memcpy.S linux/arch/sh/lib/memcpy.S
--- v2.4.12/linux/arch/sh/lib/memcpy.S	Mon Oct 18 11:16:13 1999
+++ linux/arch/sh/lib/memcpy.S	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: memcpy.S,v 1.3 1999/09/28 11:32:48 gniibe Exp $
+/* $Id: memcpy.S,v 1.3 2001/07/27 11:50:52 gniibe Exp $
  *
  * "memcpy" implementation of SuperH
  *
diff -u --recursive --new-file v2.4.12/linux/arch/sh/lib/memmove.S linux/arch/sh/lib/memmove.S
--- v2.4.12/linux/arch/sh/lib/memmove.S	Mon Oct 18 11:16:13 1999
+++ linux/arch/sh/lib/memmove.S	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: memmove.S,v 1.2 1999/09/21 12:55:49 gniibe Exp $
+/* $Id: memmove.S,v 1.2 2001/07/27 11:51:09 gniibe Exp $
  *
  * "memmove" implementation of SuperH
  *
diff -u --recursive --new-file v2.4.12/linux/arch/sh/lib/memset.S linux/arch/sh/lib/memset.S
--- v2.4.12/linux/arch/sh/lib/memset.S	Mon Oct 18 11:16:13 1999
+++ linux/arch/sh/lib/memset.S	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: memset.S,v 1.1 1999/09/18 16:57:09 gniibe Exp $
+/* $Id: memset.S,v 1.1 2000/04/14 16:49:01 mjd Exp $
  *
  * "memset" implementation of SuperH
  *
diff -u --recursive --new-file v2.4.12/linux/arch/sh/mm/cache-sh3.c linux/arch/sh/mm/cache-sh3.c
--- v2.4.12/linux/arch/sh/mm/cache-sh3.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sh/mm/cache-sh3.c	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: cache-sh3.c,v 1.5 2001/08/24 15:31:41 dwmw2 Exp $
+/* $Id: cache-sh3.c,v 1.6 2001/09/10 08:59:59 dwmw2 Exp $
  *
  *  linux/arch/sh/mm/cache-sh3.c
  *
@@ -20,10 +20,17 @@
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 
+
 #define CCR		0xffffffec	/* Address of Cache Control Register */
-#define CCR_CACHE_VAL	0x00000005	/* 8k-byte cache, P1-wb, enable */
-#define CCR_CACHE_INIT	0x0000000d	/* 8k-byte cache, CF, P1-wb, enable */
-#define CCR_CACHE_ENABLE	 1
+
+#define CCR_CACHE_CE	0x01	/* Cache Enable */
+#define CCR_CACHE_WT	0x02	/* Write-Through (for P0,U0,P3) (else writeback) */
+#define CCR_CACHE_CB	0x04	/* Write-Back (for P1) (else writethrough) */
+#define CCR_CACHE_CF	0x08	/* Cache Flush */
+#define CCR_CACHE_RA	0x20	/* RAM mode */
+
+#define CCR_CACHE_VAL	(CCR_CACHE_CB|CCR_CACHE_CE)	/* 8k-byte cache, P1-wb, enable */
+#define CCR_CACHE_INIT	(CCR_CACHE_CF|CCR_CACHE_VAL)	/* 8k-byte cache, CF, P1-wb, enable */
 
 #define CACHE_OC_ADDRESS_ARRAY 0xf0000000
 #define CACHE_VALID	  1
@@ -131,7 +138,7 @@
 
 	jump_to_P2();
 	ccr = ctrl_inl(CCR);
-	if (ccr & CCR_CACHE_ENABLE)
+	if (ccr & CCR_CACHE_CE)
 		/*
 		 * XXX: Should check RA here. 
 		 * If RA was 1, we only need to flush the half of the caches.
diff -u --recursive --new-file v2.4.12/linux/arch/sh/mm/cache-sh4.c linux/arch/sh/mm/cache-sh4.c
--- v2.4.12/linux/arch/sh/mm/cache-sh4.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sh/mm/cache-sh4.c	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: cache-sh4.c,v 1.15 2001/08/10 14:13:13 gniibe Exp $
+/* $Id: cache-sh4.c,v 1.16 2001/09/10 11:06:35 dwmw2 Exp $
  *
  *  linux/arch/sh/mm/cache.c
  *
@@ -22,9 +22,21 @@
 #include <asm/mmu_context.h>
 
 #define CCR		 0xff00001c	/* Address of Cache Control Register */
-#define CCR_CACHE_VAL	 0x00000105	/* 8k+16k-byte cache,P1-wb,enable */
-#define CCR_CACHE_INIT	 0x0000090d	/* ICI,ICE(8k), OCI,P1-wb,OCE(16k) */
-#define CCR_CACHE_ENABLE 0x00000101
+
+#define CCR_CACHE_OCE	0x0001	/* Operand Cache Enable */
+#define CCR_CACHE_WT	0x0002	/* Write-Through (for P0,U0,P3) (else writeback)*/
+#define CCR_CACHE_CB	0x0004	/* Copy-Back (for P1) (else writethrough) */
+#define CCR_CACHE_OCI	0x0008	/* OC Invalidate */
+#define CCR_CACHE_ORA	0x0020	/* OC RAM Mode */
+#define CCR_CACHE_OIX	0x0080	/* OC Index Enable */
+#define CCR_CACHE_ICE	0x0100	/* Instruction Cache Enable */
+#define CCR_CACHE_ICI	0x0800	/* IC Invalidate */
+#define CCR_CACHE_IIX	0x8000	/* IC Index Enable */
+
+/* Default CCR setup: 8k+16k-byte cache,P1-wb,enable */
+#define CCR_CACHE_VAL	(CCR_CACHE_ICE|CCR_CACHE_CB|CCR_CACHE_OCE)
+#define CCR_CACHE_INIT	(CCR_CACHE_VAL|CCR_CACHE_OCI|CCR_CACHE_ICI)
+#define CCR_CACHE_ENABLE (CCR_CACHE_OCE|CCR_CACHE_ICE)
 
 #define CACHE_IC_ADDRESS_ARRAY 0xf0000000
 #define CACHE_OC_ADDRESS_ARRAY 0xf4000000
diff -u --recursive --new-file v2.4.12/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c
--- v2.4.12/linux/arch/sh/mm/fault.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sh/mm/fault.c	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.48 2001/08/09 00:27:04 gniibe Exp $
+/* $Id: fault.c,v 1.49 2001/10/06 19:46:00 lethal Exp $
  *
  *  linux/arch/sh/mm/fault.c
  *  Copyright (C) 1999  Niibe Yutaka
@@ -134,6 +134,7 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
+survive:
 	switch (handle_mm_fault(mm, vma, address, writeaccess)) {
 	case 1:
 		tsk->min_flt++;
@@ -205,6 +206,12 @@
  */
 out_of_memory:
 	up_read(&mm->mmap_sem);
+	if (current->pid == 1) {
+		current->policy |= SCHED_YIELD;
+		schedule();
+		down_read(&mm->mmap_sem);
+		goto survive;
+	}
 	printk("VM: killing process %s\n", tsk->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -u --recursive --new-file v2.4.12/linux/arch/sh/mm/init.c linux/arch/sh/mm/init.c
--- v2.4.12/linux/arch/sh/mm/init.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sh/mm/init.c	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.18 2001/08/03 11:22:06 gniibe Exp $
+/* $Id: init.c,v 1.19 2001/10/01 02:21:50 gniibe Exp $
  *
  *  linux/arch/sh/mm/init.c
  *
diff -u --recursive --new-file v2.4.12/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S
--- v2.4.12/linux/arch/sparc/kernel/systbls.S	Thu Oct 11 08:02:26 2001
+++ linux/arch/sparc/kernel/systbls.S	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.100 2001/10/09 10:54:38 davem Exp $
+/* $Id: systbls.S,v 1.101 2001/10/18 08:27:05 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -59,7 +59,7 @@
 /*190*/	.long sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*195*/	.long sys_nis_syscall, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask
 /*200*/	.long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
-/*205*/	.long sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+/*205*/	.long sys_readahead, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
 /*210*/	.long sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
 /*215*/	.long sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
 /*220*/	.long sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile
--- v2.4.12/linux/arch/sparc64/Makefile	Sun Aug 12 13:27:59 2001
+++ linux/arch/sparc64/Makefile	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.47 2001/07/27 09:42:22 davem Exp $
+# $Id: Makefile,v 1.49 2001/10/17 18:26:58 davem Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -15,7 +15,7 @@
 CC		:= $(shell if gcc -m64 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo gcc; else echo sparc64-linux-gcc; fi )
 
 NEW_GCC := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; )
-NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
+NEW_GAS := $(shell if $(LD) -V 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
 UNDECLARED_REGS := $(shell if $(CC) -c -x assembler /dev/null -Wa,--help | grep undeclared-regs > /dev/null; then echo y; else echo n; fi; )
 
 export NEW_GCC
@@ -61,6 +61,15 @@
     CFLAGS += -DSPIN_LOCK_DEBUG
     AFLAGS += -DSPIN_LOCK_DEBUG
   endif
+endif
+
+# Uncomment this to keep track of how often flush_dcache_page
+# actually flushes the caches, output via /proc/cpuinfo
+#
+# DEBUG_DCACHE_FLUSH = 1
+ifdef DEBUG_DCACHE_FLUSH
+  CFLAGS += -DDCFLUSH_DEBUG
+  AFLAGS += -DDCFLUSH_DEBUG
 endif
 
 LINKFLAGS = -T arch/sparc64/vmlinux.lds
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.4.12/linux/arch/sparc64/defconfig	Thu Oct 11 08:02:26 2001
+++ linux/arch/sparc64/defconfig	Sun Oct 21 10:36:54 2001
@@ -100,7 +100,6 @@
 CONFIG_FB_ATY=y
 # CONFIG_FB_ATY_GX is not set
 CONFIG_FB_ATY_CT=y
-# CONFIG_FB_ATY_CT_VAIO_LCD is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
@@ -464,7 +463,6 @@
 # CONFIG_TLAN is not set
 CONFIG_VIA_RHINE=m
 CONFIG_WINBOND_840=m
-# CONFIG_LAN_SAA9730 is not set
 # CONFIG_NET_POCKET is not set
 
 #
@@ -703,11 +701,14 @@
 #
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_LONG_TIMEOUT is not set
+# CONFIG_USB_LARGE_CONFIG is not set
 
 #
 # USB Controllers
 #
 CONFIG_USB_UHCI=y
+# CONFIG_USB_UHCI_ALT is not set
 CONFIG_USB_OHCI=y
 
 #
@@ -717,11 +718,13 @@
 CONFIG_USB_BLUETOOTH=m
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
 CONFIG_USB_STORAGE_FREECOM=y
 CONFIG_USB_STORAGE_ISD200=y
 CONFIG_USB_STORAGE_DPCM=y
 CONFIG_USB_STORAGE_HP8200e=y
 CONFIG_USB_STORAGE_SDDR09=y
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
 CONFIG_USB_ACM=m
 CONFIG_USB_PRINTER=m
 
@@ -729,6 +732,7 @@
 # USB Human Interface Devices (HID)
 #
 CONFIG_USB_HID=y
+# CONFIG_USB_HIDDEV is not set
 CONFIG_USB_WACOM=m
 
 #
@@ -754,9 +758,9 @@
 # USB Network adaptors
 #
 CONFIG_USB_PEGASUS=m
+CONFIG_USB_KAWETH=m
 CONFIG_USB_CATC=m
 CONFIG_USB_CDCETHER=m
-CONFIG_USB_KAWETH=m
 CONFIG_USB_USBNET=m
 
 #
@@ -794,7 +798,7 @@
 CONFIG_USB_SERIAL_OMNINET=m
 
 #
-# USB misc drivers
+# USB Miscellaneous drivers
 #
 CONFIG_USB_RIO500=m
 
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/dtlb_base.S linux/arch/sparc64/kernel/dtlb_base.S
--- v2.4.12/linux/arch/sparc64/kernel/dtlb_base.S	Thu Oct 11 08:02:26 2001
+++ linux/arch/sparc64/kernel/dtlb_base.S	Wed Oct 17 14:16:39 2001
@@ -1,4 +1,4 @@
-/* $Id: dtlb_base.S,v 1.16 2001/10/09 04:02:11 davem Exp $
+/* $Id: dtlb_base.S,v 1.17 2001/10/11 22:33:52 davem Exp $
  * dtlb_base.S:	Front end to DTLB miss replacement strategy.
  *              This is included directly into the trap table.
  *
@@ -71,8 +71,8 @@
 	be,pn		%xcc, 3f			! Yep, special processing
 	 CREATE_VPTE_OFFSET2(%g4, %g6)			! Create VPTE offset
 	cmp		%g5, 3				! Last trap level?
-	be,a,pn		%xcc, 1f			! Yep, use non-faulting load
-	 ldxa		[%g3 + %g6] ASI_SNF, %g5	! Load VPTE (no-VPTE-fault)
+	be,pn		%xcc, longpath			! Yep, cannot risk VPTE miss
+	 nop						! delay slot
 
 /* DTLB ** ICACHE line 2: User finish + quick kernel TLB misses	*/
 	ldxa		[%g3 + %g6] ASI_S, %g5		! Load VPTE
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.4.12/linux/arch/sparc64/kernel/entry.S	Sun Sep 23 11:40:56 2001
+++ linux/arch/sparc64/kernel/entry.S	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.134 2001/08/27 18:42:07 kanoj Exp $
+/* $Id: entry.S,v 1.137 2001/10/18 09:06:36 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -725,19 +725,14 @@
 __do_data_access_exception_tl1:
 	rdpr		%pstate, %g4
 	wrpr		%g4, PSTATE_MG|PSTATE_AG, %pstate
-	rdpr		%tl, %g3
-	cmp		%g3, 1
 	mov		TLB_SFSR, %g3
 	mov		DMMU_SFAR, %g5
 	ldxa		[%g3] ASI_DMMU, %g4	! Get SFSR
 	ldxa		[%g5] ASI_DMMU, %g5	! Get SFAR
 	stxa		%g0, [%g3] ASI_DMMU	! Clear SFSR.FaultValid bit
 	membar		#Sync
-	bgu,pn		%icc, winfix_dax
+	ba,pt		%xcc, winfix_dax
 	 rdpr		%tpc, %g3
-	sethi		%hi(109f), %g7
-	ba,pt		%xcc, etraptl1
-	 or		%g7, %lo(109f), %g7	! Merge in below
 __do_data_access_exception:
 	rdpr		%pstate, %g4
 	wrpr		%g4, PSTATE_MG|PSTATE_AG, %pstate
@@ -1186,7 +1181,7 @@
 	ldxa		[%g3] ASI_DMMU, %g5
 	stxa		%g0, [%g3] ASI_DMMU	! Clear FaultValid bit
 	membar		#Sync
-	bgu,pn		%icc, winfix_dax
+	bgu,pn		%icc, winfix_mna
 	 rdpr		%tpc, %g3
 
 1:	sethi		%hi(109f), %g7
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.4.12/linux/arch/sparc64/kernel/ioctl32.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.125 2001/09/18 22:29:05 davem Exp $
+/* $Id: ioctl32.c,v 1.126 2001/10/18 11:41:02 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -1404,6 +1404,229 @@
 	return err;
 }
 
+typedef struct sg_io_hdr32 {
+	s32 interface_id;	/* [i] 'S' for SCSI generic (required) */
+	s32 dxfer_direction;	/* [i] data transfer direction  */
+	u8  cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
+	u8  mx_sb_len;		/* [i] max length to write to sbp */
+	u16 iovec_count;	/* [i] 0 implies no scatter gather */
+	u32 dxfer_len;		/* [i] byte count of data transfer */
+	u32 dxferp;		/* [i], [*io] points to data transfer memory
+					      or scatter gather list */
+	u32 cmdp;		/* [i], [*i] points to command to perform */
+	u32 sbp;		/* [i], [*o] points to sense_buffer memory */
+	u32 timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
+	u32 flags;		/* [i] 0 -> default, see SG_FLAG... */
+	s32 pack_id;		/* [i->o] unused internally (normally) */
+	u32 usr_ptr;		/* [i->o] unused internally */
+	u8  status;		/* [o] scsi status */
+	u8  masked_status;	/* [o] shifted, masked scsi status */
+	u8  msg_status;		/* [o] messaging level data (optional) */
+	u8  sb_len_wr;		/* [o] byte count actually written to sbp */
+	u16 host_status;	/* [o] errors from host adapter */
+	u16 driver_status;	/* [o] errors from software driver */
+	s32 resid;		/* [o] dxfer_len - actual_transferred */
+	u32 duration;		/* [o] time taken by cmd (unit: millisec) */
+	u32 info;		/* [o] auxiliary information */
+} sg_io_hdr32_t;  /* 64 bytes long (on sparc32) */
+
+typedef struct sg_iovec32 {
+	u32 iov_base;
+	u32 iov_len;
+} sg_iovec32_t;
+
+static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov;
+	int i;
+
+	sgp->dxferp = kmalloc(sgp->iovec_count *
+			      sizeof(sg_iovec_t), GFP_KERNEL);
+	if (!sgp->dxferp)
+		return -ENOMEM;
+	memset(sgp->dxferp, 0,
+	       sgp->iovec_count * sizeof(sg_iovec_t));
+
+	kiov = (sg_iovec_t *) sgp->dxferp;
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+		if (__get_user(iov_base32, &uiov->iov_base) ||
+		    __get_user(kiov->iov_len, &uiov->iov_len))
+			return -EFAULT;
+
+		kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL);
+		if (!kiov->iov_base)
+			return -ENOMEM;
+		if (copy_from_user(kiov->iov_base,
+				   (void *) A(iov_base32),
+				   kiov->iov_len))
+			return -EFAULT;
+
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static int copy_back_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
+	int i;
+
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+
+		if (__get_user(iov_base32, &uiov->iov_base))
+			return -EFAULT;
+
+		if (copy_to_user((void *) A(iov_base32),
+				 kiov->iov_base,
+				 kiov->iov_len))
+			return -EFAULT;
+
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static void free_sg_iovec(sg_io_hdr_t *sgp)
+{
+	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
+	int i;
+
+	for (i = 0; i < sgp->iovec_count; i++) {
+		if (kiov->iov_base) {
+			kfree(kiov->iov_base);
+			kiov->iov_base = NULL;
+		}
+		kiov++;
+	}
+	kfree(sgp->dxferp);
+	sgp->dxferp = NULL;
+}
+
+static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	sg_io_hdr32_t *sg_io32;
+	sg_io_hdr_t sg_io64;
+	u32 dxferp32, cmdp32, sbp32;
+	mm_segment_t old_fs;
+	int err = 0;
+
+	sg_io32 = (sg_io_hdr32_t *)arg;
+	err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
+	err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
+	err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
+	err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
+	err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
+	err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
+	err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
+	err |= __get_user(sg_io64.flags, &sg_io32->flags);
+	err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
+
+	sg_io64.dxferp = NULL;
+	sg_io64.cmdp = NULL;
+	sg_io64.sbp = NULL;
+
+	err |= __get_user(cmdp32, &sg_io32->cmdp);
+	sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
+	if (!sg_io64.cmdp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.cmdp,
+			   (void *) A(cmdp32),
+			   sg_io64.cmd_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(sbp32, &sg_io32->sbp);
+	sg_io64.sbp = kmalloc(64, GFP_KERNEL);
+	if (!sg_io64.sbp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	memset(sg_io64.sbp, 0, 64);
+
+	err |= __get_user(dxferp32, &sg_io32->dxferp);
+	if (sg_io64.iovec_count) {
+		int ret;
+
+		if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
+			err = ret;
+			goto out;
+		}
+	} else {
+		sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
+		if (!sg_io64.dxferp) {
+			err = -ENOMEM;
+			goto out;
+		}
+		if (copy_from_user(sg_io64.dxferp,
+				   (void *) A(dxferp32),
+				   sg_io64.dxfer_len)) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+
+	/* Unused internally, do not even bother to copy it over. */
+	sg_io64.usr_ptr = NULL;
+
+	if (err)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
+	set_fs (old_fs);
+
+	if (err < 0)
+		goto out;
+
+	err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
+	err |= __put_user(sg_io64.status, &sg_io32->status);
+	err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
+	err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
+	err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
+	err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
+	err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
+	err |= __put_user(sg_io64.resid, &sg_io32->resid);
+	err |= __put_user(sg_io64.duration, &sg_io32->duration);
+	err |= __put_user(sg_io64.info, &sg_io32->info);
+	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, 64);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count)
+			err |= copy_back_sg_iovec(&sg_io64, dxferp32);
+		else
+			err |= copy_to_user((void *)A(dxferp32),
+					    sg_io64.dxferp,
+					    sg_io64.dxfer_len);
+	}
+	if (err)
+		err = -EFAULT;
+
+out:
+	if (sg_io64.cmdp)
+		kfree(sg_io64.cmdp);
+	if (sg_io64.sbp)
+		kfree(sg_io64.sbp);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count) {
+			free_sg_iovec(&sg_io64);
+		} else {
+			kfree(sg_io64.dxferp);
+		}
+	}
+	return err;
+}
+
 struct ppp_option_data32 {
 	__kernel_caddr_t32	ptr;
 	__u32			length;
@@ -3900,7 +4123,6 @@
 COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
 COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
 COMPATIBLE_IOCTL(SG_SCSI_RESET)
-COMPATIBLE_IOCTL(SG_IO)
 COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
 COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
 COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
@@ -4338,6 +4560,7 @@
 HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans)
 HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans)
 HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans)
+HANDLE_IOCTL(SG_IO,sg_ioctl_trans)
 HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans)
 HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans)
 HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans)
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/iommu_common.c linux/arch/sparc64/kernel/iommu_common.c
--- v2.4.12/linux/arch/sparc64/kernel/iommu_common.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sparc64/kernel/iommu_common.c	Fri Oct 12 15:35:53 2001
@@ -1,4 +1,4 @@
-/* $Id: iommu_common.c,v 1.5 2001/08/24 17:57:51 kanoj Exp $
+/* $Id: iommu_common.c,v 1.6 2001/10/09 02:24:33 davem Exp $
  * iommu_common.c: UltraSparc SBUS/PCI common iommu code.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -12,7 +12,7 @@
  */
 
 #ifdef VERIFY_SG
-int verify_lengths(struct scatterlist *sg, int nents, int npages)
+static int verify_lengths(struct scatterlist *sg, int nents, int npages)
 {
 	int sg_len, dma_len;
 	int i, pgcount;
@@ -22,8 +22,8 @@
 		sg_len += sg[i].length;
 
 	dma_len = 0;
-	for (i = 0; i < nents && sg[i].dvma_length; i++)
-		dma_len += sg[i].dvma_length;
+	for (i = 0; i < nents && sg[i].dma_length; i++)
+		dma_len += sg[i].dma_length;
 
 	if (sg_len != dma_len) {
 		printk("verify_lengths: Error, different, sg[%d] dma[%d]\n",
@@ -32,13 +32,13 @@
 	}
 
 	pgcount = 0;
-	for (i = 0; i < nents && sg[i].dvma_length; i++) {
+	for (i = 0; i < nents && sg[i].dma_length; i++) {
 		unsigned long start, end;
 
-		start = sg[i].dvma_address;
+		start = sg[i].dma_address;
 		start = start & IO_PAGE_MASK;
 
-		end = sg[i].dvma_address + sg[i].dvma_length;
+		end = sg[i].dma_address + sg[i].dma_length;
 		end = (end + (IO_PAGE_SIZE - 1)) & IO_PAGE_MASK;
 
 		pgcount += ((end - start) >> IO_PAGE_SHIFT);
@@ -55,15 +55,16 @@
 	return 0;
 }
 
-int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte)
+static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte)
 {
 	struct scatterlist *sg = *__sg;
 	iopte_t *iopte = *__iopte;
-	u32 dlen = dma_sg->dvma_length;
-	u32 daddr = dma_sg->dvma_address;
+	u32 dlen = dma_sg->dma_length;
+	u32 daddr;
 	unsigned int sglen;
 	unsigned long sgaddr;
 
+	daddr = dma_sg->dma_address;
 	sglen = sg->length;
 	sgaddr = (unsigned long) sg->address;
 	while (dlen > 0) {
@@ -136,7 +137,7 @@
 	return nents;
 }
 
-int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte)
+static int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte)
 {
 	struct scatterlist *dma_sg = sg;
 	struct scatterlist *orig_dma_sg = dma_sg;
@@ -147,7 +148,7 @@
 		if (nents <= 0)
 			break;
 		dma_sg++;
-		if (dma_sg->dvma_length == 0)
+		if (dma_sg->dma_length == 0)
 			break;
 	}
 
@@ -174,14 +175,15 @@
 	    verify_maps(sg, nents, iopte) < 0) {
 		int i;
 
-		printk("verify_sglist: Crap, messed up mappings, dumping, iodma at %08x.\n",
-		       (u32) (sg->dvma_address & IO_PAGE_MASK));
+		printk("verify_sglist: Crap, messed up mappings, dumping, iodma at ");
+		printk("%016lx.\n", sg->dma_address & IO_PAGE_MASK);
+
 		for (i = 0; i < nents; i++) {
 			printk("sg(%d): address(%p) length(%x) "
-			       "dma_address[%08x] dma_length[%08x]\n",
+			       "dma_address[%016lx] dma_length[%016lx]\n",
 			       i,
 			       sg[i].address, sg[i].length,
-			       sg[i].dvma_address, sg[i].dvma_length);
+			       sg[i].dma_address, sg[i].dma_length);
 		}
 	}
 
@@ -204,8 +206,8 @@
 		sg++;
 		addr = (unsigned long) sg->address;
 		if (! VCONTIG(prev, addr)) {
-			dma_sg->dvma_address = dent_addr;
-			dma_sg->dvma_length = dent_len;
+			dma_sg->dma_address = dent_addr;
+			dma_sg->dma_length = dent_len;
 			dma_sg++;
 
 			dent_addr = ((dent_addr +
@@ -218,8 +220,8 @@
 		dent_len += sg->length;
 		prev = addr + sg->length;
 	}
-	dma_sg->dvma_address = dent_addr;
-	dma_sg->dvma_length = dent_len;
+	dma_sg->dma_address = dent_addr;
+	dma_sg->dma_length = dent_len;
 
 	return ((unsigned long) dent_addr +
 		(unsigned long) dent_len +
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/iommu_common.h linux/arch/sparc64/kernel/iommu_common.h
--- v2.4.12/linux/arch/sparc64/kernel/iommu_common.h	Sun Sep 23 11:40:56 2001
+++ linux/arch/sparc64/kernel/iommu_common.h	Fri Oct 12 15:35:53 2001
@@ -1,4 +1,4 @@
-/* $Id: iommu_common.h,v 1.3 2001/08/24 19:36:58 kanoj Exp $
+/* $Id: iommu_common.h,v 1.4 2001/10/09 02:24:33 davem Exp $
  * iommu_common.h: UltraSparc SBUS/PCI common iommu declarations.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -34,10 +34,7 @@
 #undef VERIFY_SG
 
 #ifdef VERIFY_SG
-int verify_lengths(struct scatterlist *sg, int nents, int npages);
-int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte);
-int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte);
-void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages);
+extern void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages);
 #endif
 
 /* Two addresses are "virtually contiguous" if and only if:
@@ -47,4 +44,4 @@
 #define VCONTIG(__X, __Y)	(((__X) == (__Y)) || \
 				 (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL)
 
-unsigned long prepare_sg(struct scatterlist *sg, int nents);
+extern unsigned long prepare_sg(struct scatterlist *sg, int nents);
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/pci_iommu.c linux/arch/sparc64/kernel/pci_iommu.c
--- v2.4.12/linux/arch/sparc64/kernel/pci_iommu.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sparc64/kernel/pci_iommu.c	Fri Oct 12 15:35:53 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_iommu.c,v 1.15 2001/08/24 19:36:58 kanoj Exp $
+/* $Id: pci_iommu.c,v 1.16 2001/10/09 02:24:33 davem Exp $
  * pci_iommu.c: UltraSparc PCI controller IOM/STC support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -378,7 +378,8 @@
 		((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 #ifdef DEBUG_PCI_IOMMU
 	if (iopte_val(*base) == IOPTE_INVALID)
-		printk("pci_unmap_single called on non-mapped region %08x,%08x from %016lx\n", bus_addr, sz, __builtin_return_address(0));
+		printk("pci_unmap_single called on non-mapped region %08x,%08x from %016lx\n",
+		       bus_addr, sz, __builtin_return_address(0));
 #endif
 	bus_addr &= IO_PAGE_MASK;
 
@@ -423,18 +424,25 @@
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long iopte_protection)
+#define SG_ENT_PHYS_ADDRESS(SG)	\
+	((SG)->address ? \
+	 __pa((SG)->address) : \
+	 (__pa(page_address((SG)->page)) + (SG)->offset))
+
+static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
+			   int nused, int nelems, unsigned long iopte_protection)
 {
 	struct scatterlist *dma_sg = sg;
+	struct scatterlist *sg_end = sg + nelems;
 	int i;
 
 	for (i = 0; i < nused; i++) {
 		unsigned long pteval = ~0UL;
 		u32 dma_npages;
 
-		dma_npages = ((dma_sg->dvma_address & (IO_PAGE_SIZE - 1UL)) +
-			      dma_sg->dvma_length +
-			      ((u32)(IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
+		dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) +
+			      dma_sg->dma_length +
+			      ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
 		do {
 			unsigned long offset;
 			signed int len;
@@ -447,7 +455,7 @@
 			for (;;) {
 				unsigned long tmp;
 
-				tmp = (unsigned long) __pa(sg->address);
+				tmp = SG_ENT_PHYS_ADDRESS(sg);
 				len = sg->length;
 				if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
 					pteval = tmp & IO_PAGE_MASK;
@@ -479,10 +487,11 @@
 			 * adjusting pteval along the way.  Stop when we
 			 * detect a page crossing event.
 			 */
-			while ((pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
-			       pteval == __pa(sg->address) &&
+			while (sg < sg_end &&
+			       (pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
+			       (pteval == SG_ENT_PHYS_ADDRESS(sg)) &&
 			       ((pteval ^
-				 (__pa(sg->address) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
+				 (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
 				pteval += sg->length;
 				sg++;
 			}
@@ -511,8 +520,13 @@
 
 	/* Fast path single entry scatterlists. */
 	if (nelems == 1) {
-		sglist->dvma_address = pci_map_single(pdev, sglist->address, sglist->length, direction);
-		sglist->dvma_length = sglist->length;
+		sglist->dma_address =
+			pci_map_single(pdev,
+				       (sglist->address ?
+					sglist->address :
+					(page_address(sglist->page) + sglist->offset)),
+				       sglist->length, direction);
+		sglist->dma_length = sglist->length;
 		return 1;
 	}
 
@@ -540,8 +554,8 @@
 	used = nelems;
 
 	sgtmp = sglist;
-	while (used && sgtmp->dvma_length) {
-		sgtmp->dvma_address += dma_base;
+	while (used && sgtmp->dma_length) {
+		sgtmp->dma_address += dma_base;
 		sgtmp++;
 		used--;
 	}
@@ -559,7 +573,7 @@
 		iopte_protection = IOPTE_CONSISTENT(ctx);
 	if (direction != PCI_DMA_TODEVICE)
 		iopte_protection |= IOPTE_WRITE;
-	fill_sg (base, sglist, used, iopte_protection);
+	fill_sg (base, sglist, used, nelems, iopte_protection);
 #ifdef VERIFY_SG
 	verify_sglist(sglist, nelems, base, npages);
 #endif
@@ -591,20 +605,20 @@
 	iommu = pcp->pbm->iommu;
 	strbuf = &pcp->pbm->stc;
 	
-	bus_addr = sglist->dvma_address & IO_PAGE_MASK;
+	bus_addr = sglist->dma_address & IO_PAGE_MASK;
 
 	for (i = 1; i < nelems; i++)
-		if (sglist[i].dvma_length == 0)
+		if (sglist[i].dma_length == 0)
 			break;
 	i--;
-	npages = (IO_PAGE_ALIGN(sglist[i].dvma_address + sglist[i].dvma_length) - bus_addr) >> IO_PAGE_SHIFT;
+	npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - bus_addr) >> IO_PAGE_SHIFT;
 
 	base = iommu->page_table +
 		((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 
 #ifdef DEBUG_PCI_IOMMU
 	if (iopte_val(*base) == IOPTE_INVALID)
-		printk("pci_unmap_sg called on non-mapped region %08x,%d from %016lx\n", sglist->dvma_address, nelems, __builtin_return_address(0));
+		printk("pci_unmap_sg called on non-mapped region %016lx,%d from %016lx\n", sglist->dma_address, nelems, __builtin_return_address(0));
 #endif
 
 	spin_lock_irqsave(&iommu->lock, flags);
@@ -616,7 +630,7 @@
 
 	/* Step 1: Kick data out of streaming buffers if necessary. */
 	if (strbuf->strbuf_enabled) {
-		u32 vaddr = bus_addr;
+		u32 vaddr = (u32) bus_addr;
 
 		PCI_STC_FLUSHFLAG_INIT(strbuf);
 		if (strbuf->strbuf_ctxflush &&
@@ -735,7 +749,7 @@
 		iopte_t *iopte;
 
 		iopte = iommu->page_table +
-			((sglist[0].dvma_address - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
+			((sglist[0].dma_address - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 		ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL;
 	}
 
@@ -754,13 +768,13 @@
 		unsigned long i, npages;
 		u32 bus_addr;
 
-		bus_addr = sglist[0].dvma_address & IO_PAGE_MASK;
+		bus_addr = sglist[0].dma_address & IO_PAGE_MASK;
 
 		for(i = 1; i < nelems; i++)
-			if (!sglist[i].dvma_length)
+			if (!sglist[i].dma_length)
 				break;
 		i--;
-		npages = (IO_PAGE_ALIGN(sglist[i].dvma_address + sglist[i].dvma_length) - bus_addr) >> IO_PAGE_SHIFT;
+		npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - bus_addr) >> IO_PAGE_SHIFT;
 		for (i = 0; i < npages; i++, bus_addr += IO_PAGE_SIZE)
 			pci_iommu_write(strbuf->strbuf_pflush, bus_addr);
 	}
@@ -774,10 +788,10 @@
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-int pci_dma_supported(struct pci_dev *pdev, dma_addr_t device_mask)
+int pci_dma_supported(struct pci_dev *pdev, u64 device_mask)
 {
 	struct pcidev_cookie *pcp = pdev->sysdata;
-	u32 dma_addr_mask;
+	u64 dma_addr_mask;
 
 	if (pdev == NULL) {
 		dma_addr_mask = 0xffffffff;
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- v2.4.12/linux/arch/sparc64/kernel/pci_psycho.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sparc64/kernel/pci_psycho.c	Fri Oct 12 15:35:53 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.28 2001/08/24 19:36:58 kanoj Exp $
+/* $Id: pci_psycho.c,v 1.29 2001/10/11 00:44:38 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -36,7 +36,8 @@
 	__asm__ __volatile__("stxa %0, [%1] %2" \
 			     : /* no outputs */ \
 			     : "r" (__val), "r" (__reg), \
-			       "i" (ASI_PHYS_BYPASS_EC_E))
+			       "i" (ASI_PHYS_BYPASS_EC_E) \
+			     : "memory")
 
 /* Misc. PSYCHO PCI controller register offsets and definitions. */
 #define PSYCHO_CONTROL		0x0010UL
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- v2.4.12/linux/arch/sparc64/kernel/pci_sabre.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sparc64/kernel/pci_sabre.c	Fri Oct 12 15:35:53 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.39 2001/08/24 19:36:58 kanoj Exp $
+/* $Id: pci_sabre.c,v 1.40 2001/10/11 00:44:38 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -37,7 +37,8 @@
 	__asm__ __volatile__("stxa %0, [%1] %2" \
 			     : /* no outputs */ \
 			     : "r" (__val), "r" (__reg), \
-			       "i" (ASI_PHYS_BYPASS_EC_E))
+			       "i" (ASI_PHYS_BYPASS_EC_E) \
+			     : "memory")
 
 /* SABRE PCI controller register offsets and definitions. */
 #define SABRE_UE_AFSR		0x0030UL
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c
--- v2.4.12/linux/arch/sparc64/kernel/pci_schizo.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sparc64/kernel/pci_schizo.c	Fri Oct 12 15:35:53 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.21 2001/08/24 19:36:58 kanoj Exp $
+/* $Id: pci_schizo.c,v 1.22 2001/10/11 00:44:38 davem Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -34,7 +34,8 @@
 	__asm__ __volatile__("stxa %0, [%1] %2" \
 			     : /* no outputs */ \
 			     : "r" (__val), "r" (__reg), \
-			       "i" (ASI_PHYS_BYPASS_EC_E))
+			       "i" (ASI_PHYS_BYPASS_EC_E) \
+			     : "memory")
 
 /* This is a convention that at least Excalibur and Merlin
  * follow.  I suppose the SCHIZO used in Starcat and friends
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.4.12/linux/arch/sparc64/kernel/process.c	Thu Oct 11 08:02:26 2001
+++ linux/arch/sparc64/kernel/process.c	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.120 2001/10/02 02:22:26 davem Exp $
+/*  $Id: process.c,v 1.122 2001/10/18 09:06:36 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- v2.4.12/linux/arch/sparc64/kernel/rtrap.S	Tue Jul  3 17:08:19 2001
+++ linux/arch/sparc64/kernel/rtrap.S	Wed Oct 17 14:16:39 2001
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.55 2001/06/05 09:56:06 davem Exp $
+/* $Id: rtrap.S,v 1.56 2001/10/13 00:14:34 kanoj Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -82,12 +82,12 @@
 		 andn			%l1, %l4, %l1
 
 		.align			64
-		.globl			rtrap_clr_l6, rtrap
+		.globl			rtrap_clr_l6, rtrap, irqsz_patchme
 rtrap_clr_l6:	clr			%l6
 rtrap:		lduw			[%g6 + AOFF_task_processor], %l0
 		sethi			%hi(irq_stat), %l2	! &softirq_active
 		or			%l2, %lo(irq_stat), %l2	! &softirq_active
-		sllx			%l0, 6, %l0
+irqsz_patchme:	sllx			%l0, 0, %l0
 		lduw			[%l2 + %l0], %l1	! softirq_pending
 		cmp			%l1, 0
 
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c
--- v2.4.12/linux/arch/sparc64/kernel/sbus.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sparc64/kernel/sbus.c	Fri Oct 12 15:35:53 2001
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.16 2001/08/24 19:36:58 kanoj Exp $
+/* $Id: sbus.c,v 1.17 2001/10/09 02:24:33 davem Exp $
  * sbus.c: UltraSparc SBUS controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -376,18 +376,24 @@
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long iopte_bits)
+#define SG_ENT_PHYS_ADDRESS(SG)	\
+	((SG)->address ? \
+	 __pa((SG)->address) : \
+	 (__pa(page_address((SG)->page)) + (SG)->offset))
+
+static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, int nelems, unsigned long iopte_bits)
 {
 	struct scatterlist *dma_sg = sg;
+	struct scatterlist *sg_end = sg + nelems;
 	int i;
 
 	for (i = 0; i < nused; i++) {
 		unsigned long pteval = ~0UL;
 		u32 dma_npages;
 
-		dma_npages = ((dma_sg->dvma_address & (IO_PAGE_SIZE - 1UL)) +
-			      dma_sg->dvma_length +
-			      ((u32)(IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
+		dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) +
+			      dma_sg->dma_length +
+			      ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
 		do {
 			unsigned long offset;
 			signed int len;
@@ -400,7 +406,7 @@
 			for (;;) {
 				unsigned long tmp;
 
-				tmp = (unsigned long) __pa(sg->address);
+				tmp = (unsigned long) SG_ENT_PHYS_ADDRESS(sg);
 				len = sg->length;
 				if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
 					pteval = tmp & IO_PAGE_MASK;
@@ -432,10 +438,11 @@
 			 * adjusting pteval along the way.  Stop when we
 			 * detect a page crossing event.
 			 */
-			while ((pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
-			       pteval == __pa(sg->address) &&
+			while (sg < sg_end &&
+			       (pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
+			       (pteval == SG_ENT_PHYS_ADDRESS(sg)) &&
 			       ((pteval ^
-				 (__pa(sg->address) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
+				 (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
 				pteval += sg->length;
 				sg++;
 			}
@@ -461,8 +468,13 @@
 
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
-		sg->dvma_address = sbus_map_single(sdev, sg->address, sg->length, dir);
-		sg->dvma_length = sg->length;
+		sg->dma_address =
+			sbus_map_single(sdev,
+					(sg->address ?
+					 sg->address :
+					 (page_address(sg->page) + sg->offset)),
+					sg->length, dir);
+		sg->dma_length = sg->length;
 		return 1;
 	}
 
@@ -478,8 +490,8 @@
 	sgtmp = sg;
 	used = nents;
 
-	while (used && sgtmp->dvma_length) {
-		sgtmp->dvma_address += dma_base;
+	while (used && sgtmp->dma_length) {
+		sgtmp->dma_address += dma_base;
 		sgtmp++;
 		used--;
 	}
@@ -489,7 +501,7 @@
 	if (dir != SBUS_DMA_TODEVICE)
 		iopte_bits |= IOPTE_WRITE;
 
-	fill_sg(iopte, sg, used, iopte_bits);
+	fill_sg(iopte, sg, used, nents, iopte_bits);
 #ifdef VERIFY_SG
 	verify_sglist(sg, nents, iopte, npages);
 #endif
@@ -512,17 +524,17 @@
 
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
-		sbus_unmap_single(sdev, sg->dvma_address, sg->dvma_length, direction);
+		sbus_unmap_single(sdev, sg->dma_address, sg->dma_length, direction);
 		return;
 	}
 
-	dvma_base = sg[0].dvma_address & IO_PAGE_MASK;
+	dvma_base = sg[0].dma_address & IO_PAGE_MASK;
 	for (i = 0; i < nents; i++) {
-		if (sg[i].dvma_length == 0)
+		if (sg[i].dma_length == 0)
 			break;
 	}
 	i--;
-	size = IO_PAGE_ALIGN(sg[i].dvma_address + sg[i].dvma_length) - dvma_base;
+	size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - dvma_base;
 
 	iommu = sdev->bus->iommu;
 	spin_lock_irqsave(&iommu->lock, flags);
@@ -550,13 +562,13 @@
 	u32 base;
 	int i;
 
-	base = sg[0].dvma_address & IO_PAGE_MASK;
+	base = sg[0].dma_address & IO_PAGE_MASK;
 	for (i = 0; i < nents; i++) {
-		if (sg[i].dvma_length == 0)
+		if (sg[i].dma_length == 0)
 			break;
 	}
 	i--;
-	size = IO_PAGE_ALIGN(sg[i].dvma_address + sg[i].dvma_length) - base;
+	size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base;
 
 	spin_lock_irqsave(&iommu->lock, flags);
 	strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT);
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- v2.4.12/linux/arch/sparc64/kernel/setup.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/sparc64/kernel/setup.c	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.67 2001/09/21 03:17:06 kanoj Exp $
+/*  $Id: setup.c,v 1.69 2001/10/18 09:40:00 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -90,6 +90,7 @@
 	struct console *cons, *saved_console = NULL;
 	unsigned long flags;
 	char *cmd;
+	extern spinlock_t prom_entry_lock;
 
 	if (!args)
 		return -1;
@@ -105,6 +106,7 @@
 	 */
 	irq_exit(smp_processor_id(), 0);
 	save_and_cli(flags);
+	spin_unlock(&prom_entry_lock);
 	cons = console_drivers;
 	while (cons) {
 		unregister_console(cons);
@@ -279,6 +281,7 @@
 		saved_console = cons->next;
 		register_console(cons);
 	}
+	spin_lock(&prom_entry_lock);
 	restore_flags(flags);
 	/*
 	 * Restore in-interrupt status for a resume from obp.
@@ -480,6 +483,18 @@
 	conswitchp = &prom_con;
 #endif
 
+#ifdef CONFIG_SMP
+	i = (unsigned long)&irq_stat[1] - (unsigned long)&irq_stat[0];
+	if ((i == SMP_CACHE_BYTES) || (i == (2 * SMP_CACHE_BYTES))) {
+		extern unsigned int irqsz_patchme[1];
+		irqsz_patchme[0] |= ((i == SMP_CACHE_BYTES) ? SMP_CACHE_BYTES_SHIFT : \
+							SMP_CACHE_BYTES_SHIFT + 1);
+		flushi((long)&irqsz_patchme[1]);
+	} else {
+		prom_printf("Unexpected size of irq_stat[] elements\n");
+		prom_halt();
+	}
+#endif
 	/* Work out if we are starfire early on */
 	check_if_starfire();
 
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.4.12/linux/arch/sparc64/kernel/smp.c	Sun Sep 23 11:40:56 2001
+++ linux/arch/sparc64/kernel/smp.c	Sun Oct 21 10:36:54 2001
@@ -582,6 +582,68 @@
 extern unsigned long xcall_flush_cache_all;
 extern unsigned long xcall_report_regs;
 extern unsigned long xcall_receive_signal;
+extern unsigned long xcall_flush_dcache_page_cheetah;
+extern unsigned long xcall_flush_dcache_page_spitfire;
+
+static spinlock_t dcache_xcall_lock = SPIN_LOCK_UNLOCKED;
+static struct page *dcache_page;
+#ifdef DCFLUSH_DEBUG
+extern atomic_t dcpage_flushes;
+extern atomic_t dcpage_flushes_xcall;
+#endif
+
+static __inline__ void __smp_flush_dcache_page_client(struct page *page)
+{
+#if (L1DCACHE_SIZE > PAGE_SIZE)
+	__flush_dcache_page(page->virtual,
+			    ((tlb_type == spitfire) &&
+			     page->mapping != NULL));
+#else
+	if (page->mapping != NULL &&
+	    tlb_type == spitfire)
+		__flush_icache_page(__pa(page->virtual));
+#endif
+}
+
+void smp_flush_dcache_page_client(void)
+{
+	__smp_flush_dcache_page_client(dcache_page);
+	spin_unlock(&dcache_xcall_lock);
+}
+
+void smp_flush_dcache_page_impl(struct page *page)
+{
+	if (smp_processors_ready) {
+		int cpu = dcache_dirty_cpu(page);
+		unsigned long mask = 1UL << cpu;
+
+#ifdef DCFLUSH_DEBUG
+		atomic_inc(&dcpage_flushes);
+#endif
+		if (cpu == smp_processor_id()) {
+			__smp_flush_dcache_page_client(page);
+		} else if ((cpu_present_map & mask) != 0) {
+			u64 data0;
+
+			if (tlb_type == spitfire) {
+				spin_lock(&dcache_xcall_lock);
+				dcache_page = page;
+				data0 = ((u64)&xcall_flush_dcache_page_spitfire);
+				spitfire_xcall_deliver(data0, 0, 0, mask);
+				/* Target cpu drops dcache_xcall_lock. */
+			} else {
+				/* Look mom, no locks... */
+				data0 = ((u64)&xcall_flush_dcache_page_cheetah);
+				cheetah_xcall_deliver(data0,
+						      (u64) page->virtual,
+						      0, mask);
+			}
+#ifdef DCFLUSH_DEBUG
+			atomic_inc(&dcpage_flushes_xcall);
+#endif
+		}
+	}
+}
 
 void smp_receive_signal(int cpu)
 {
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.4.12/linux/arch/sparc64/kernel/sparc64_ksyms.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.112 2001/09/25 23:30:23 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.113 2001/10/17 18:26:58 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -183,7 +183,7 @@
 EXPORT_SYMBOL(tlb_type);
 EXPORT_SYMBOL(get_fb_unmapped_area);
 EXPORT_SYMBOL(flush_icache_range);
-EXPORT_SYMBOL(__flush_dcache_page);
+EXPORT_SYMBOL(flush_dcache_page);
 
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.4.12/linux/arch/sparc64/kernel/sys_sparc32.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.179 2001/09/25 00:48:09 davem Exp $
+/* $Id: sys_sparc32.c,v 1.182 2001/10/18 09:06:36 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -3999,6 +3999,12 @@
 	return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
+extern asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count);
+
+asmlinkage ssize_t32 sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
+{
+	return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
+}
 
 extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
 
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S
--- v2.4.12/linux/arch/sparc64/kernel/systbls.S	Thu Oct 11 08:02:26 2001
+++ linux/arch/sparc64/kernel/systbls.S	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.78 2001/10/09 10:54:38 davem Exp $
+/* $Id: systbls.S,v 1.79 2001/10/18 08:27:05 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -60,7 +60,7 @@
 /*190*/	.word sys32_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
-	.word sys_nis_syscall, sys32_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+	.word sys32_readahead, sys32_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
 /*210*/	.word sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys32_sysinfo
 	.word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
 /*220*/	.word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
@@ -119,7 +119,7 @@
 /*190*/	.word sys_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
-	.word sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+	.word sys_readahead, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
 /*210*/	.word sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
 	.word sys_ipc, sys_nis_syscall, sys_clone, sys_nis_syscall, sys_adjtimex
 /*220*/	.word sys_nis_syscall, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.4.12/linux/arch/sparc64/mm/init.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/sparc64/mm/init.c	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.193 2001/09/25 22:47:35 davem Exp $
+/*  $Id: init.c,v 1.194 2001/10/17 18:26:58 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -108,23 +108,73 @@
 
 extern void __update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
 
+#ifdef DCFLUSH_DEBUG
+atomic_t dcpage_flushes = ATOMIC_INIT(0);
+#ifdef CONFIG_SMP
+atomic_t dcpage_flushes_xcall = ATOMIC_INIT(0);
+#endif
+#endif
+
+__inline__ void flush_dcache_page_impl(struct page *page)
+{
+#ifdef DCFLUSH_DEBUG
+	atomic_inc(&dcpage_flushes);
+#endif
+
+#if (L1DCACHE_SIZE > PAGE_SIZE)
+	__flush_dcache_page(page->virtual,
+			    ((tlb_type == spitfire) &&
+			     page->mapping != NULL));
+#else
+	if (page->mapping != NULL &&
+	    tlb_type == spitfire)
+		__flush_icache_page(__pa(page->virtual));
+#endif
+}
+
 void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
 	struct page *page = pte_page(pte);
 
 	if (VALID_PAGE(page) && page->mapping &&
 	    test_bit(PG_dcache_dirty, &page->flags)) {
-#if (L1DCACHE_SIZE > PAGE_SIZE)			/* is there D$ aliasing problem */
-		__flush_dcache_page(page->virtual, (tlb_type == spitfire));
-#else
-		if (tlb_type == spitfire)	/* fix local I$ coherency */
-			__flush_icache_page(__get_phys((unsigned long)(page->virtual)));
-#endif
-		clear_bit(PG_dcache_dirty, &page->flags);
+		/* This is just to optimize away some function calls
+		 * in the SMP case.
+		 */
+		if (dcache_dirty_cpu(page) == smp_processor_id())
+			flush_dcache_page_impl(page);
+		else
+			smp_flush_dcache_page_impl(page);
+
+		clear_dcache_dirty(page);
 	}
 	__update_mmu_cache(vma, address, pte);
 }
 
+void flush_dcache_page(struct page *page)
+{
+	int dirty = test_bit(PG_dcache_dirty, &page->flags);
+	int dirty_cpu = dcache_dirty_cpu(page);
+
+	if (page->mapping &&
+	    page->mapping->i_mmap == NULL &&
+	    page->mapping->i_mmap_shared == NULL) {
+		if (dirty) {
+			if (dirty_cpu == smp_processor_id())
+				return;
+			smp_flush_dcache_page_impl(page);
+		}
+		set_dcache_dirty(page);
+	} else {
+		/* We could delay the flush for the !page->mapping
+		 * case too.  But that case is for exec env/arg
+		 * pages and those are %99 certainly going to get
+		 * faulted into the tlb (and thus flushed) anyways.
+		 */
+		flush_dcache_page_impl(page);
+	}
+}
+
 void flush_icache_range(unsigned long start, unsigned long end)
 {
 	/* Cheetah has coherent I-cache. */
@@ -153,12 +203,25 @@
 
 int mmu_info(char *buf)
 {
+	int len;
+
 	if (tlb_type == cheetah)
-		return sprintf(buf, "MMU Type\t: Cheetah\n");
+		len = sprintf(buf, "MMU Type\t: Cheetah\n");
 	else if (tlb_type == spitfire)
-		return sprintf(buf, "MMU Type\t: Spitfire\n");
+		len = sprintf(buf, "MMU Type\t: Spitfire\n");
 	else
-		return sprintf(buf, "MMU Type\t: ???\n");
+		len = sprintf(buf, "MMU Type\t: ???\n");
+
+#ifdef DCFLUSH_DEBUG
+	len += sprintf(buf + len, "DCPageFlushes\t: %d\n",
+		       atomic_read(&dcpage_flushes));
+#ifdef CONFIG_SMP
+	len += sprintf(buf + len, "DCPageFlushesXC\t: %d\n",
+		       atomic_read(&dcpage_flushes_xcall));
+#endif /* CONFIG_SMP */
+#endif /* DCFLUSH_DEBUG */
+
+	return len;
 }
 
 struct linux_prom_translation {
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.4.12/linux/arch/sparc64/mm/ultra.S	Tue Oct  9 17:06:51 2001
+++ linux/arch/sparc64/mm/ultra.S	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.61 2001/09/25 18:04:51 kanoj Exp $
+/* $Id: ultra.S,v 1.63 2001/10/17 19:30:21 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
@@ -500,6 +500,32 @@
 109:	 or		%g7, %lo(109b), %g7
 	call		__show_regs
 	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	b,pt		%xcc, rtrap
+	 clr		%l6
+
+	.align		32
+	.globl		xcall_flush_dcache_page_cheetah
+xcall_flush_dcache_page_cheetah:
+	sethi		%hi(PAGE_SIZE), %g3
+1:	subcc		%g3, (1 << 5), %g3
+	stxa		%g0, [%g1 + %g3] ASI_DCACHE_INVALIDATE
+	membar		#Sync
+	bne,pt		%icc, 1b
+	 nop
+	retry
+	nop
+
+	.globl		xcall_flush_dcache_page_spitfire
+xcall_flush_dcache_page_spitfire:
+	rdpr		%pstate, %g2
+	wrpr		%g2, PSTATE_IG | PSTATE_AG, %pstate
+	rdpr		%pil, %g2
+	wrpr		%g0, 15, %pil
+	sethi		%hi(109f), %g7
+	b,pt		%xcc, etrap_irq
+109:	 or		%g7, %lo(109b), %g7
+	call		smp_flush_dcache_page_client
+	 nop
 	b,pt		%xcc, rtrap
 	 clr		%l6
 
diff -u --recursive --new-file v2.4.12/linux/arch/sparc64/prom/p1275.c linux/arch/sparc64/prom/p1275.c
--- v2.4.12/linux/arch/sparc64/prom/p1275.c	Thu Apr 26 22:17:25 2001
+++ linux/arch/sparc64/prom/p1275.c	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.21 2001/04/24 01:09:12 davem Exp $
+/* $Id: p1275.c,v 1.22 2001/10/18 09:40:00 davem Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -247,39 +247,12 @@
 "	" : : "r" (&p1275buf), "i" (PSTATE_PRIV));
 }
 
-/* We need some SMP protection here.  But be careful as
- * prom callback code can call into here too, this is why
- * the counter is needed.  -DaveM
+/*
+ * This provides SMP safety on the p1275buf. prom_callback() drops this lock
+ * to allow recursuve acquisition.
  */
-static int prom_entry_depth = 0;
 spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED;
 
-static __inline__ unsigned long prom_get_lock(void)
-{
-	unsigned long flags;
-
-	__save_and_cli(flags);
-	if (prom_entry_depth == 0) {
-		spin_lock(&prom_entry_lock);
-
-#if 1 /* DEBUGGING */
-		if (prom_entry_depth != 0)
-			panic("prom_get_lock");
-#endif
-	}
-	prom_entry_depth++;
-
-	return flags;
-}
-
-static __inline__ void prom_release_lock(unsigned long flags)
-{
-	if (--prom_entry_depth == 0)
-		spin_unlock(&prom_entry_lock);
-
-	__restore_flags(flags);
-}
-
 long p1275_cmd (char *service, long fmt, ...)
 {
 	char *p, *q;
@@ -296,7 +269,7 @@
 		spitfire_set_primary_context (0);
 	}
 
-	flags = prom_get_lock();
+	spin_lock_irqsave(&prom_entry_lock, flags);
 
 	p1275buf.prom_args[0] = (unsigned long)p;		/* service */
 	strcpy (p, service);
@@ -388,7 +361,7 @@
 	va_end(list);
 	x = p1275buf.prom_args [nargs + 3];
 
-	prom_release_lock(flags);
+	spin_unlock_irqrestore(&prom_entry_lock, flags);
 
 	if (ctx)
 		spitfire_set_primary_context (ctx);
diff -u --recursive --new-file v2.4.12/linux/drivers/Makefile linux/drivers/Makefile
--- v2.4.12/linux/drivers/Makefile	Wed Jul 25 17:10:19 2001
+++ linux/drivers/Makefile	Sun Oct 21 10:12:41 2001
@@ -7,7 +7,7 @@
 
 
 mod-subdirs :=	dio mtd sbus video macintosh usb input telephony sgi ide \
-		i2o message/fusion scsi md ieee1394 pnp isdn atm \
+		message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
 		fc4 net/hamradio i2c acpi bluetooth
 
 subdir-y :=	parport char block net sound misc media cdrom
@@ -31,7 +31,7 @@
 subdir-$(CONFIG_SGI)		+= sgi
 subdir-$(CONFIG_IDE)		+= ide
 subdir-$(CONFIG_SCSI)		+= scsi
-subdir-$(CONFIG_I2O)		+= i2o
+subdir-$(CONFIG_I2O)		+= message/i2o
 subdir-$(CONFIG_FUSION)		+= message/fusion
 subdir-$(CONFIG_MD)		+= md
 subdir-$(CONFIG_IEEE1394)	+= ieee1394
diff -u --recursive --new-file v2.4.12/linux/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c
--- v2.4.12/linux/drivers/acorn/block/mfmhd.c	Sun Sep 23 11:40:56 2001
+++ linux/drivers/acorn/block/mfmhd.c	Mon Oct 15 13:27:42 2001
@@ -1209,7 +1209,7 @@
 		return 0;
 
 	case BLKGETSIZE:
-		return put_user (mfm[minor].nr_sects, (long *)arg);
+		return put_user (mfm[minor].nr_sects, (unsigned long *)arg);
 	case BLKGETSIZE64:
 		return put_user ((u64)mfm[minor].nr_sects << 9, (u64 *)arg);
 
diff -u --recursive --new-file v2.4.12/linux/drivers/acorn/char/mouse_rpc.c linux/drivers/acorn/char/mouse_rpc.c
--- v2.4.12/linux/drivers/acorn/char/mouse_rpc.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/acorn/char/mouse_rpc.c	Thu Oct 11 09:04:57 2001
@@ -83,3 +83,8 @@
 
 module_init(mouse_rpc_init);
 module_exit(mouse_rpc_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("RiscPC mouse driver");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.12/linux/drivers/acorn/scsi/acornscsi.c linux/drivers/acorn/scsi/acornscsi.c
--- v2.4.12/linux/drivers/acorn/scsi/acornscsi.c	Sun Sep 23 11:40:56 2001
+++ linux/drivers/acorn/scsi/acornscsi.c	Thu Oct 11 09:04:57 2001
@@ -3159,5 +3159,7 @@
 module_init(acornscsi_init);
 module_exit(acornscsi_exit);
 
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("AcornSCSI driver");
 MODULE_LICENSE("GPL");
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.12/linux/drivers/acorn/scsi/arxescsi.c linux/drivers/acorn/scsi/arxescsi.c
--- v2.4.12/linux/drivers/acorn/scsi/arxescsi.c	Sun Sep 23 11:40:56 2001
+++ linux/drivers/acorn/scsi/arxescsi.c	Thu Oct 11 09:04:57 2001
@@ -439,4 +439,7 @@
 module_init(init_arxe_scsi_driver);
 module_exit(exit_arxe_scsi_driver);
 
+MODULE_AUTHOR("Stefan Hanske");
+MODULE_DESCRIPTION("ARXESCSI driver for Acorn machines");
 MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.12/linux/drivers/acorn/scsi/cumana_2.c linux/drivers/acorn/scsi/cumana_2.c
--- v2.4.12/linux/drivers/acorn/scsi/cumana_2.c	Sun Sep 23 11:40:56 2001
+++ linux/drivers/acorn/scsi/cumana_2.c	Thu Oct 11 09:04:57 2001
@@ -82,12 +82,6 @@
 
 static struct expansion_card *ecs[MAX_ECARDS];
 
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Cumana SCSI II driver");
-MODULE_PARM(term, "1-8i");
-MODULE_PARM_DESC(term, "SCSI bus termination");
-MODULE_LICENSE("GPL");
-
 /*
  * Use term=0,1,0,0,0 to turn terminators on/off
  */
@@ -600,3 +594,10 @@
 
 module_init(cumanascsi2_init);
 module_exit(cumanascsi2_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Cumana SCSI-2 driver for Acorn machines");
+MODULE_PARM(term, "1-8i");
+MODULE_PARM_DESC(term, "SCSI bus termination");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.12/linux/drivers/acorn/scsi/ecoscsi.c linux/drivers/acorn/scsi/ecoscsi.c
--- v2.4.12/linux/drivers/acorn/scsi/ecoscsi.c	Sun Sep 23 11:40:56 2001
+++ linux/drivers/acorn/scsi/ecoscsi.c	Thu Oct 11 09:04:57 2001
@@ -293,5 +293,7 @@
 module_init(ecoscsi_init);
 module_exit(ecoscsi_exit);
 
-EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Econet-SCSI driver for Acorn machines");
 MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.12/linux/drivers/acorn/scsi/eesox.c linux/drivers/acorn/scsi/eesox.c
--- v2.4.12/linux/drivers/acorn/scsi/eesox.c	Sun Sep 23 11:40:56 2001
+++ linux/drivers/acorn/scsi/eesox.c	Thu Oct 11 09:04:57 2001
@@ -80,11 +80,6 @@
 
 static struct expansion_card *ecs[MAX_ECARDS];
 
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("EESOX SCSI driver");
-MODULE_PARM(term, "1-8i");
-MODULE_PARM_DESC(term, "SCSI bus termination");
-
 /*
  * Use term=0,1,0,0,0 to turn terminators on/off
  */
@@ -602,5 +597,9 @@
 module_init(eesox_init);
 module_exit(eesox_exit);
 
-EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("EESOX 'Fast' SCSI driver for Acorn machines");
+MODULE_PARM(term, "1-8i");
+MODULE_PARM_DESC(term, "SCSI bus termination");
 MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.12/linux/drivers/acorn/scsi/fas216.c linux/drivers/acorn/scsi/fas216.c
--- v2.4.12/linux/drivers/acorn/scsi/fas216.c	Sun Sep 23 11:40:56 2001
+++ linux/drivers/acorn/scsi/fas216.c	Thu Oct 11 09:04:57 2001
@@ -60,9 +60,6 @@
 #include "../../scsi/hosts.h"
 #include "fas216.h"
 
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver");
-
 #define VER_MAJOR	0
 #define VER_MINOR	0
 #define VER_PATCH	5
@@ -2767,15 +2764,6 @@
 EXPORT_SYMBOL(fas216_print_stats);
 EXPORT_SYMBOL(fas216_print_device);
 
-#ifdef MODULE
-int __init init_module(void)
-{
-	return 0;
-}
-
-void __exit cleanup_module(void)
-{
-}
-#endif
-
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver core");
 MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/acorn/scsi/msgqueue.c linux/drivers/acorn/scsi/msgqueue.c
--- v2.4.12/linux/drivers/acorn/scsi/msgqueue.c	Sun Sep 23 11:40:56 2001
+++ linux/drivers/acorn/scsi/msgqueue.c	Thu Oct 11 09:04:57 2001
@@ -16,10 +16,6 @@
 
 #include "msgqueue.h"
 
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("SCSI message queue handling");
-MODULE_LICENSE("GPL");
-
 /*
  * Function: struct msgqueue_entry *mqe_alloc(MsgQueue_t *msgq)
  * Purpose : Allocate a message queue entry
@@ -170,13 +166,6 @@
 EXPORT_SYMBOL(msgqueue_addmsg);
 EXPORT_SYMBOL(msgqueue_flush);
 
-#ifdef MODULE
-int __init init_module(void)
-{
-	return 0;
-}
-
-void __exit cleanup_module(void)
-{
-}
-#endif
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("SCSI message queue handling");
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/acorn/scsi/oak.c linux/drivers/acorn/scsi/oak.c
--- v2.4.12/linux/drivers/acorn/scsi/oak.c	Sun Sep 23 11:40:56 2001
+++ linux/drivers/acorn/scsi/oak.c	Thu Oct 11 09:04:57 2001
@@ -286,5 +286,7 @@
 module_init(oakscsi_init);
 module_exit(oakscsi_exit);
 
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Oak SCSI driver");
 MODULE_LICENSE("GPL");
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.12/linux/drivers/acorn/scsi/powertec.c linux/drivers/acorn/scsi/powertec.c
--- v2.4.12/linux/drivers/acorn/scsi/powertec.c	Sun Sep 23 11:40:56 2001
+++ linux/drivers/acorn/scsi/powertec.c	Thu Oct 11 09:04:57 2001
@@ -77,12 +77,6 @@
 #define VER_MINOR	0
 #define VER_PATCH	5
 
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Powertec SCSI driver");
-MODULE_PARM(term, "1-8i");
-MODULE_PARM_DESC(term, "SCSI bus termination");
-MODULE_LICENSE("GPL");
-
 static struct expansion_card *ecs[MAX_ECARDS];
 
 /*
@@ -502,3 +496,10 @@
 
 module_init(powertecscsi_init);
 module_exit(powertecscsi_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Powertec SCSI driver");
+MODULE_PARM(term, "1-8i");
+MODULE_PARM_DESC(term, "SCSI bus termination");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.12/linux/drivers/acorn/scsi/queue.c linux/drivers/acorn/scsi/queue.c
--- v2.4.12/linux/drivers/acorn/scsi/queue.c	Sun Sep 23 11:40:56 2001
+++ linux/drivers/acorn/scsi/queue.c	Thu Oct 11 09:04:57 2001
@@ -25,10 +25,6 @@
 
 #include "../../scsi/scsi.h"
 
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("SCSI command queueing");
-MODULE_LICENSE("GPL");
-
 #define DEBUG
 
 typedef struct queue_entry {
@@ -296,13 +292,6 @@
 EXPORT_SYMBOL(queue_remove_cmd);
 EXPORT_SYMBOL(queue_probetgtlun);
 
-#ifdef MODULE
-int __init init_module (void)
-{
-	return 0;
-}
-
-void __exit cleanup_module (void)
-{
-}
-#endif
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("SCSI command queueing");
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/acpi/include/platform/acgcc.h linux/drivers/acpi/include/platform/acgcc.h
--- v2.4.12/linux/drivers/acpi/include/platform/acgcc.h	Sun Sep 23 11:40:56 2001
+++ linux/drivers/acpi/include/platform/acgcc.h	Mon Oct 15 18:48:28 2001
@@ -39,7 +39,6 @@
 #define BREAKPOINT3
 #define disable() __cli()
 #define enable()  __sti()
-#define wbinvd()
 
 /*! [Begin] no source code translation */
 
diff -u --recursive --new-file v2.4.12/linux/drivers/acpi/ospm/thermal/tz_osl.c linux/drivers/acpi/ospm/thermal/tz_osl.c
--- v2.4.12/linux/drivers/acpi/ospm/thermal/tz_osl.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/acpi/ospm/thermal/tz_osl.c	Thu Oct 11 09:04:57 2001
@@ -177,7 +177,7 @@
 tz_osl_add_device(
 	TZ_CONTEXT		*thermal_zone)
 {
-	struct proc_dir_entry	*proc_entry = NULL;
+	struct proc_dir_entry	*proc_entry = NULL, *proc;
 
 	if (!thermal_zone) {
 		return(AE_BAD_PARAMETER);
@@ -186,15 +186,18 @@
 	printk("Thermal Zone: found\n");
 
 	proc_entry = proc_mkdir(thermal_zone->uid, tz_proc_root);
-	if (!proc_entry) {
+	if (!proc_entry)
 		return(AE_ERROR);
-	}
 
-	create_proc_read_entry(TZ_PROC_STATUS, S_IFREG | S_IRUGO,
+	proc = create_proc_read_entry(TZ_PROC_STATUS, S_IFREG | S_IRUGO,
 		proc_entry, tz_osl_proc_read_status, (void*)thermal_zone);
+	if (!proc)
+		return(AE_ERROR);
 
-	create_proc_read_entry(TZ_PROC_INFO, S_IFREG | S_IRUGO,
+	proc = create_proc_read_entry(TZ_PROC_INFO, S_IFREG | S_IRUGO,
 		proc_entry, tz_osl_proc_read_info, (void*)thermal_zone);
+	if (!proc)
+		return(AE_ERROR);
 
 	return(AE_OK);
 }
diff -u --recursive --new-file v2.4.12/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c
--- v2.4.12/linux/drivers/block/DAC960.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/DAC960.c	Wed Oct 17 14:46:29 2001
@@ -19,8 +19,8 @@
 */
 
 
-#define DAC960_DriverVersion			"2.4.10"
-#define DAC960_DriverDate			"23 July 2001"
+#define DAC960_DriverVersion			"2.4.11"
+#define DAC960_DriverDate			"11 October 2001"
 
 
 #include <linux/version.h>
@@ -42,6 +42,7 @@
 #include <linux/spinlock.h>
 #include <linux/timer.h>
 #include <linux/pci.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <asm/uaccess.h>
@@ -99,7 +100,7 @@
 */
 
 static NotifierBlock_T
-  DAC960_NotifierBlock =    { DAC960_Finalize, NULL, 0 };
+  DAC960_NotifierBlock =    { DAC960_Notifier, NULL, 0 };
 
 
 /*
@@ -269,7 +270,9 @@
 
 /*
   DAC960_AllocateCommand allocates a Command structure from Controller's
-  free list.
+  free list.  During driver initialization, a special initialization command
+  has been placed on the free list to guarantee that command allocation can
+  never fail.
 */
 
 static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T
@@ -480,6 +483,52 @@
 
 
 /*
+  DAC960_P_QueueCommand queues Command for DAC960 P Series Controllers.
+*/
+
+static void DAC960_P_QueueCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  switch (CommandMailbox->Common.CommandOpcode)
+    {
+    case DAC960_V1_Enquiry:
+      CommandMailbox->Common.CommandOpcode = DAC960_V1_Enquiry_Old;
+      break;
+    case DAC960_V1_GetDeviceState:
+      CommandMailbox->Common.CommandOpcode = DAC960_V1_GetDeviceState_Old;
+      break;
+    case DAC960_V1_Read:
+      CommandMailbox->Common.CommandOpcode = DAC960_V1_Read_Old;
+      DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
+      break;
+    case DAC960_V1_Write:
+      CommandMailbox->Common.CommandOpcode = DAC960_V1_Write_Old;
+      DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
+      break;
+    case DAC960_V1_ReadWithScatterGather:
+      CommandMailbox->Common.CommandOpcode =
+	DAC960_V1_ReadWithScatterGather_Old;
+      DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
+      break;
+    case DAC960_V1_WriteWithScatterGather:
+      CommandMailbox->Common.CommandOpcode =
+	DAC960_V1_WriteWithScatterGather_Old;
+      DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
+      break;
+    default:
+      break;
+    }
+  while (DAC960_PD_MailboxFullP(ControllerBaseAddress))
+    udelay(1);
+  DAC960_PD_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
+  DAC960_PD_NewCommand(ControllerBaseAddress);
+}
+
+
+/*
   DAC960_ExecuteCommand executes Command and waits for completion.
 */
 
@@ -522,6 +571,32 @@
 
 
 /*
+  DAC960_V1_ExecuteTypeB executes a DAC960 V1 Firmware Controller Type 3B
+  Command and waits for completion.  It returns true on success and false
+  on failure.
+*/
+
+static boolean DAC960_V1_ExecuteType3B(DAC960_Controller_T *Controller,
+				       DAC960_V1_CommandOpcode_T CommandOpcode,
+				       unsigned char CommandOpcode2,
+				       void *DataPointer)
+{
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandStatus_T CommandStatus;
+  DAC960_V1_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->Type3B.CommandOpcode = CommandOpcode;
+  CommandMailbox->Type3B.CommandOpcode2 = CommandOpcode2;
+  CommandMailbox->Type3B.BusAddress = Virtual_to_Bus32(DataPointer);
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V1.CommandStatus;
+  DAC960_DeallocateCommand(Command);
+  return (CommandStatus == DAC960_V1_NormalCompletion);
+}
+
+
+/*
   DAC960_V1_ExecuteType3D executes a DAC960 V1 Firmware Controller Type 3D
   Command and waits for completion.  It returns true on success and false
   on failure.
@@ -1055,7 +1130,17 @@
     DAC1164P		    5.06 and above
     DAC960PTL/PRL/PJ/PG	    4.06 and above
     DAC960PU/PD/PL	    3.51 and above
+    DAC960PU/PD/PL/P	    2.73 and above
   */
+  if (Enquiry2.FirmwareID.MajorVersion == 0)
+    {
+      Enquiry2.FirmwareID.MajorVersion =
+	Controller->V1.Enquiry.MajorFirmwareVersion;
+      Enquiry2.FirmwareID.MinorVersion =
+	Controller->V1.Enquiry.MinorFirmwareVersion;
+      Enquiry2.FirmwareID.FirmwareType = '0';
+      Enquiry2.FirmwareID.TurnID = 0;
+    }
   sprintf(Controller->FirmwareVersion, "%d.%02d-%c-%02d",
 	  Enquiry2.FirmwareID.MajorVersion, Enquiry2.FirmwareID.MinorVersion,
 	  Enquiry2.FirmwareID.FirmwareType, Enquiry2.FirmwareID.TurnID);
@@ -1064,7 +1149,9 @@
 	(Controller->FirmwareVersion[0] == '4' &&
 	 strcmp(Controller->FirmwareVersion, "4.06") >= 0) ||
 	(Controller->FirmwareVersion[0] == '3' &&
-	 strcmp(Controller->FirmwareVersion, "3.51") >= 0)))
+	 strcmp(Controller->FirmwareVersion, "3.51") >= 0) ||
+	(Controller->FirmwareVersion[0] == '2' &&
+	 strcmp(Controller->FirmwareVersion, "2.73") >= 0)))
     {
       DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION");
       DAC960_Error("Firmware Version = '%s'\n", Controller,
@@ -1120,6 +1207,20 @@
       return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY");
     }
   /*
+    Initialize the Background Initialization Status.
+  */
+  if ((Controller->FirmwareVersion[0] == '4' &&
+      strcmp(Controller->FirmwareVersion, "4.08") >= 0) ||
+      (Controller->FirmwareVersion[0] == '5' &&
+       strcmp(Controller->FirmwareVersion, "5.08") >= 0))
+    {
+      Controller->V1.BackgroundInitializationStatusSupported = true;
+      DAC960_V1_ExecuteType3B(Controller,
+			      DAC960_V1_BackgroundInitializationControl, 0x20,
+			      &Controller->
+			       V1.LastBackgroundInitializationStatus);
+    }
+  /*
     Initialize the Logical Drive Initially Accessible flag.
   */
   for (LogicalDriveNumber = 0;
@@ -1573,7 +1674,7 @@
 	    DeviceState->DeviceType == DAC960_V1_DiskType)
 	  {
 	    if (Controller->V1.DeviceResetCount[Channel][TargetID] > 0)
-	      DAC960_Info("         Disk Status: %s, %d blocks, %d resets\n",
+	      DAC960_Info("         Disk Status: %s, %u blocks, %d resets\n",
 			  Controller,
 			  (DeviceState->DeviceState == DAC960_V1_Device_Dead
 			   ? "Dead"
@@ -1586,7 +1687,7 @@
 			  DeviceState->DiskSize,
 			  Controller->V1.DeviceResetCount[Channel][TargetID]);
 	    else
-	      DAC960_Info("         Disk Status: %s, %d blocks\n", Controller,
+	      DAC960_Info("         Disk Status: %s, %u blocks\n", Controller,
 			  (DeviceState->DeviceState == DAC960_V1_Device_Dead
 			   ? "Dead"
 			   : DeviceState->DeviceState
@@ -1615,7 +1716,7 @@
     {
       DAC960_V1_LogicalDriveInformation_T *LogicalDriveInformation =
 	&Controller->V1.LogicalDriveInformation[LogicalDriveNumber];
-      DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %d blocks, %s\n",
+      DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %u blocks, %s\n",
 		  Controller, Controller->ControllerNumber, LogicalDriveNumber,
 		  LogicalDriveInformation->RAIDLevel,
 		  (LogicalDriveInformation->LogicalDriveState
@@ -1681,18 +1782,32 @@
       if (PhysicalDeviceInfo->PhysicalDeviceState ==
 	  DAC960_V2_Device_Unconfigured)
 	continue;
-      DAC960_Info("         Disk Status: %s, %d blocks\n", Controller,
+      DAC960_Info("         Disk Status: %s, %u blocks\n", Controller,
 		  (PhysicalDeviceInfo->PhysicalDeviceState
 		   == DAC960_V2_Device_Online
 		   ? "Online"
 		   : PhysicalDeviceInfo->PhysicalDeviceState
-		     == DAC960_V2_Device_WriteOnly
-		     ? "Write-Only"
+		     == DAC960_V2_Device_Rebuild
+		     ? "Rebuild"
 		     : PhysicalDeviceInfo->PhysicalDeviceState
-		       == DAC960_V2_Device_Dead
-		       ? "Dead" : "Standby"),
-		  PhysicalDeviceInfo
-		  ->ConfigurableDeviceSizeIn512ByteBlocksOrMB);
+		       == DAC960_V2_Device_Missing
+		       ? "Missing"
+		       : PhysicalDeviceInfo->PhysicalDeviceState
+			 == DAC960_V2_Device_Critical
+			 ? "Critical"
+			 : PhysicalDeviceInfo->PhysicalDeviceState
+			   == DAC960_V2_Device_Dead
+			   ? "Dead"
+			   : PhysicalDeviceInfo->PhysicalDeviceState
+			     == DAC960_V2_Device_SuspectedDead
+			     ? "Suspected-Dead"
+			     : PhysicalDeviceInfo->PhysicalDeviceState
+			       == DAC960_V2_Device_CommandedOffline
+			       ? "Commanded-Offline"
+			       : PhysicalDeviceInfo->PhysicalDeviceState
+				 == DAC960_V2_Device_Standby
+				 ? "Standby" : "Unknown"),
+		  PhysicalDeviceInfo->ConfigurableDeviceSize);
       if (PhysicalDeviceInfo->ParityErrors == 0 &&
 	  PhysicalDeviceInfo->SoftErrors == 0 &&
 	  PhysicalDeviceInfo->HardErrors == 0 &&
@@ -1734,7 +1849,7 @@
 					    "-", "-", "-", "-" };
       unsigned char *GeometryTranslation;
       if (LogicalDeviceInfo == NULL) continue;
-      switch(LogicalDeviceInfo->DriveGeometry)
+      switch (LogicalDeviceInfo->DriveGeometry)
 	{
 	case DAC960_V2_Geometry_128_32:
 	  GeometryTranslation = "128/32";
@@ -1748,7 +1863,7 @@
 		       Controller, LogicalDeviceInfo->DriveGeometry);
 	  break;
 	}
-      DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %d blocks\n",
+      DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %u blocks\n",
 		  Controller, Controller->ControllerNumber, LogicalDriveNumber,
 		  LogicalDeviceInfo->RAIDLevel,
 		  (LogicalDeviceInfo->LogicalDeviceState
@@ -1757,7 +1872,7 @@
 		   : LogicalDeviceInfo->LogicalDeviceState
 		     == DAC960_V2_LogicalDevice_Critical
 		     ? "Critical" : "Offline"),
-		  LogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB);
+		  LogicalDeviceInfo->ConfigurableDeviceSize);
       DAC960_Info("                  Logical Device %s, BIOS Geometry: %s\n",
 		  Controller,
 		  (LogicalDeviceInfo->LogicalDeviceControl
@@ -1907,15 +2022,11 @@
   RequestQueue->queuedata = Controller;
   Controller->RequestQueue = RequestQueue;
   /*
-    Initialize the Disk Partitions array, Partition Sizes array, Block Sizes
-    array, and Max Sectors per Request array.
+    Initialize the Max Sectors per Request array.
   */
   for (MinorNumber = 0; MinorNumber < DAC960_MinorCount; MinorNumber++)
-    {
-      Controller->BlockSizes[MinorNumber] = BLOCK_SIZE;
-      Controller->MaxSectorsPerRequest[MinorNumber] =
-	Controller->MaxBlocksPerCommand;
-    }
+    Controller->MaxSectorsPerRequest[MinorNumber] =
+      Controller->MaxBlocksPerCommand;
   Controller->GenericDiskInfo.part = Controller->DiskPartitions;
   Controller->GenericDiskInfo.sizes = Controller->PartitionSizes;
   blksize_size[MajorNumber] = Controller->BlockSizes;
@@ -1931,7 +2042,8 @@
   Controller->GenericDiskInfo.major_name = "rd";
   Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
   Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
-  Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount;
+  Controller->GenericDiskInfo.nr_real = DAC960_MaxLogicalDrives;
+  Controller->GenericDiskInfo.real_devices = Controller;
   Controller->GenericDiskInfo.next = NULL;
   Controller->GenericDiskInfo.fops = &DAC960_BlockDeviceOperations;
   /*
@@ -1978,6 +2090,46 @@
 
 
 /*
+  DAC960_ComputeGenericDiskInfo computes the values for the Generic Disk
+  Information Partition Sector Counts and Block Sizes.
+*/
+
+static void DAC960_ComputeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
+{
+  DAC960_Controller_T *Controller =
+    (DAC960_Controller_T *) GenericDiskInfo->real_devices;
+  int LogicalDriveNumber, i;
+  for (LogicalDriveNumber = 0;
+       LogicalDriveNumber < DAC960_MaxLogicalDrives;
+       LogicalDriveNumber++)
+    {
+      int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber, 0);
+      if (Controller->FirmwareType == DAC960_V1_Controller)
+	{
+	  if (LogicalDriveNumber < Controller->LogicalDriveCount)
+	    GenericDiskInfo->part[MinorNumber].nr_sects =
+	      Controller->V1.LogicalDriveInformation
+			     [LogicalDriveNumber].LogicalDriveSize;
+	  else GenericDiskInfo->part[MinorNumber].nr_sects = 0;
+	}
+      else
+	{
+	  DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+	    Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+	  if (LogicalDeviceInfo != NULL)
+	    GenericDiskInfo->part[MinorNumber].nr_sects =
+	      LogicalDeviceInfo->ConfigurableDeviceSize;
+	  else GenericDiskInfo->part[MinorNumber].nr_sects = 0;
+	}
+      for (i = 0; i < DAC960_MaxPartitions; i++)
+	if (GenericDiskInfo->part[MinorNumber].nr_sects > 0)
+	  Controller->BlockSizes[MinorNumber + i] = BLOCK_SIZE;
+	else Controller->BlockSizes[MinorNumber + i] = 0;
+    }
+}
+
+
+/*
   DAC960_RegisterDisk registers the DAC960 Logical Disk Device for Logical
   Drive Number if it exists.
 */
@@ -1991,7 +2143,8 @@
       register_disk(&Controller->GenericDiskInfo,
 		    DAC960_KernelDevice(Controller->ControllerNumber,
 					LogicalDriveNumber, 0),
-		    DAC960_MaxPartitions, &DAC960_BlockDeviceOperations,
+		    DAC960_MaxPartitions,
+		    &DAC960_BlockDeviceOperations,
 		    Controller->V1.LogicalDriveInformation
 				   [LogicalDriveNumber].LogicalDriveSize);
     }
@@ -2003,9 +2156,9 @@
       register_disk(&Controller->GenericDiskInfo,
 		    DAC960_KernelDevice(Controller->ControllerNumber,
 					LogicalDriveNumber, 0),
-		    DAC960_MaxPartitions, &DAC960_BlockDeviceOperations,
-		    LogicalDeviceInfo
-		    ->ConfigurableDeviceSizeIn512ByteBlocksOrMB);
+		    DAC960_MaxPartitions,
+		    &DAC960_BlockDeviceOperations,
+		    LogicalDeviceInfo->ConfigurableDeviceSize);
     }
 }
 
@@ -2116,6 +2269,13 @@
       InterruptHandler = DAC960_PD_InterruptHandler;
       MemoryWindowSize = DAC960_PD_RegisterWindowSize;
       break;
+    case DAC960_P_Controller:
+      VendorID = PCI_VENDOR_ID_MYLEX;
+      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_P;
+      FirmwareType = DAC960_V1_Controller;
+      InterruptHandler = DAC960_P_InterruptHandler;
+      MemoryWindowSize = DAC960_PD_RegisterWindowSize;
+      break;
     }
   while ((PCI_Device = pci_find_device(VendorID, DeviceID, PCI_Device)) != NULL)
     {
@@ -2151,6 +2311,10 @@
 	  IO_Address = pci_resource_start(PCI_Device, 0);
 	  PCI_Address = pci_resource_start(PCI_Device, 1);
 	  break;
+	case DAC960_P_Controller:
+	  IO_Address = pci_resource_start(PCI_Device, 0);
+	  PCI_Address = pci_resource_start(PCI_Device, 1);
+	  break;
 	}
       if (DAC960_ControllerCount == DAC960_MaxControllers)
 	{
@@ -2348,6 +2512,32 @@
 	  Controller->QueueReadWriteCommand =
 	    DAC960_V1_QueueReadWriteCommand;
 	  break;
+	case DAC960_P_Controller:
+	  request_region(Controller->IO_Address, 0x80,
+			 Controller->FullModelName);
+	  DAC960_PD_DisableInterrupts(BaseAddress);
+	  DAC960_PD_AcknowledgeStatus(BaseAddress);
+	  udelay(1000);
+	  while (DAC960_PD_InitializationInProgressP(BaseAddress))
+	    {
+	      if (DAC960_PD_ReadErrorStatus(BaseAddress, &ErrorStatus,
+					    &Parameter0, &Parameter1) &&
+		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
+					   Parameter0, Parameter1))
+		goto Failure;
+	      udelay(10);
+	    }
+	  DAC960_PD_EnableInterrupts(Controller->BaseAddress);
+	  Controller->QueueCommand = DAC960_P_QueueCommand;
+	  Controller->ReadControllerConfiguration =
+	    DAC960_V1_ReadControllerConfiguration;
+	  Controller->ReadDeviceConfiguration =
+	    DAC960_V1_ReadDeviceConfiguration;
+	  Controller->ReportDeviceConfiguration =
+	    DAC960_V1_ReportDeviceConfiguration;
+	  Controller->QueueReadWriteCommand =
+	    DAC960_V1_QueueReadWriteCommand;
+	  break;
 	}
       /*
 	Acquire shared access to the IRQ Channel.
@@ -2519,7 +2709,7 @@
   DAC960_Initialize initializes the DAC960 Driver.
 */
 
-void DAC960_Initialize(void)
+static int DAC960_Initialize(void)
 {
   int ControllerNumber;
   DAC960_DetectControllers(DAC960_BA_Controller);
@@ -2527,8 +2717,9 @@
   DAC960_DetectControllers(DAC960_LA_Controller);
   DAC960_DetectControllers(DAC960_PG_Controller);
   DAC960_DetectControllers(DAC960_PD_Controller);
+  DAC960_DetectControllers(DAC960_P_Controller);
   DAC960_SortControllers();
-  if (DAC960_ActiveControllerCount == 0) return;
+  if (DAC960_ActiveControllerCount == 0) return -ENODEV;
   for (ControllerNumber = 0;
        ControllerNumber < DAC960_ControllerCount;
        ControllerNumber++)
@@ -2537,6 +2728,7 @@
       int LogicalDriveNumber;
       if (Controller == NULL) continue;
       DAC960_InitializeController(Controller);
+      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
       for (LogicalDriveNumber = 0;
 	   LogicalDriveNumber < DAC960_MaxLogicalDrives;
 	   LogicalDriveNumber++)
@@ -2544,6 +2736,7 @@
     }
   DAC960_CreateProcEntries();
   register_reboot_notifier(&DAC960_NotifierBlock);
+  return 0;
 }
 
 
@@ -2551,14 +2744,10 @@
   DAC960_Finalize finalizes the DAC960 Driver.
 */
 
-static int DAC960_Finalize(NotifierBlock_T *NotifierBlock,
-			   unsigned long Event,
-			   void *Buffer)
+static void DAC960_Finalize(void)
 {
   int ControllerNumber;
-  if (!(Event == SYS_RESTART || Event == SYS_HALT || Event == SYS_POWER_OFF))
-    return NOTIFY_DONE;
-  if (DAC960_ActiveControllerCount == 0) return NOTIFY_OK;
+  if (DAC960_ActiveControllerCount == 0) return;
   for (ControllerNumber = 0;
        ControllerNumber < DAC960_ControllerCount;
        ControllerNumber++)
@@ -2566,6 +2755,20 @@
       DAC960_FinalizeController(DAC960_Controllers[ControllerNumber]);
   DAC960_DestroyProcEntries();
   unregister_reboot_notifier(&DAC960_NotifierBlock);
+}
+
+
+/*
+  DAC960_Notifier is the notifier for the DAC960 Driver.
+*/
+
+static int DAC960_Notifier(NotifierBlock_T *NotifierBlock,
+			   unsigned long Event,
+			   void *Buffer)
+{
+  if (!(Event == SYS_RESTART || Event == SYS_HALT || Event == SYS_POWER_OFF))
+    return NOTIFY_DONE;
+  DAC960_Finalize();
   return NOTIFY_OK;
 }
 
@@ -2599,11 +2802,9 @@
       char *LastDataEndPointer = NULL;
       int SegmentNumber = 0;
       if (Command->CommandType == DAC960_ReadCommand)
-	CommandMailbox->Type5.CommandOpcode =
-	  DAC960_V1_ReadWithOldScatterGather;
+	CommandMailbox->Type5.CommandOpcode = DAC960_V1_ReadWithScatterGather;
       else
-	CommandMailbox->Type5.CommandOpcode =
-	  DAC960_V1_WriteWithOldScatterGather;
+	CommandMailbox->Type5.CommandOpcode = DAC960_V1_WriteWithScatterGather;
       CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
       CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
       CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
@@ -2865,12 +3066,12 @@
 		   Controller, Command->V1.CommandStatus, CommandName);
       break;
     }
-  DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %d..%d\n",
+  DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %u..%u\n",
 	       Controller, Controller->ControllerNumber,
 	       Command->LogicalDriveNumber, Command->BlockNumber,
 	       Command->BlockNumber + Command->BlockCount - 1);
   if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0)
-    DAC960_Error("  /dev/rd/c%dd%dp%d: relative blocks %d..%d\n",
+    DAC960_Error("  /dev/rd/c%dd%dp%d: relative blocks %u..%u\n",
 		 Controller, Controller->ControllerNumber,
 		 Command->LogicalDriveNumber,
 		 DAC960_PartitionNumber(Command->BufferHeader->b_rdev),
@@ -3027,6 +3228,8 @@
 				LogicalDriveNumber,
 				Controller->ControllerNumber,
 				LogicalDriveNumber);
+	      Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
+	      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
 	    }
 	  if (NewEnquiry->NumberOfLogicalDrives < Controller->LogicalDriveCount)
 	    {
@@ -3037,8 +3240,9 @@
 				LogicalDriveNumber,
 				Controller->ControllerNumber,
 				LogicalDriveNumber);
+	      Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
+	      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
 	    }
-	  Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
 	  if (NewEnquiry->StatusFlags.DeferredWriteError !=
 	      OldEnquiry->StatusFlags.DeferredWriteError)
 	    DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller,
@@ -3064,6 +3268,8 @@
 	      Controller->V1.NeedErrorTableInformation = true;
 	      Controller->V1.NeedDeviceStateInformation = true;
 	      Controller->V1.StartDeviceStateScan = true;
+	      Controller->V1.NeedBackgroundInitializationStatus =
+		Controller->V1.BackgroundInitializationStatusSupported;
 	      Controller->SecondaryMonitoringTime = jiffies;
 	    }
 	  if (NewEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress ||
@@ -3186,7 +3392,7 @@
 			   AdditionalSenseCodeQualifier == 0x02))))
 		{
 		  DAC960_Critical("Physical Device %d:%d Error Log: "
-				  "Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
+				  "Sense Key = %X, ASC = %02X, ASCQ = %02X\n",
 				  Controller,
 				  EventLogEntry->Channel,
 				  EventLogEntry->TargetID,
@@ -3396,6 +3602,77 @@
 	      Controller->EphemeralProgressMessage = false;
 	    }
 	}
+      else if (CommandOpcode == DAC960_V1_BackgroundInitializationControl)
+	{
+	  unsigned int LogicalDriveNumber =
+	    Controller->V1.BackgroundInitializationStatus.LogicalDriveNumber;
+	  unsigned int LogicalDriveSize =
+	    Controller->V1.BackgroundInitializationStatus.LogicalDriveSize;
+	  unsigned int BlocksCompleted =
+	    Controller->V1.BackgroundInitializationStatus.BlocksCompleted;
+	  switch (CommandStatus)
+	    {
+	    case DAC960_V1_NormalCompletion:
+	      switch (Controller->V1.BackgroundInitializationStatus.Status)
+		{
+		case DAC960_V1_BackgroundInitializationInvalid:
+		  break;
+		case DAC960_V1_BackgroundInitializationStarted:
+		  DAC960_Progress("Background Initialization Started\n",
+				  Controller);
+		  break;
+		case DAC960_V1_BackgroundInitializationInProgress:
+		  if (BlocksCompleted ==
+		      Controller->V1.LastBackgroundInitializationStatus
+				    .BlocksCompleted &&
+		      LogicalDriveNumber ==
+		      Controller->V1.LastBackgroundInitializationStatus
+				    .LogicalDriveNumber)
+		    break;
+		  Controller->EphemeralProgressMessage = true;
+		  DAC960_Progress("Background Initialization in Progress: "
+				  "Logical Drive %d (/dev/rd/c%dd%d) "
+				  "%d%% completed\n",
+				  Controller, LogicalDriveNumber,
+				  Controller->ControllerNumber,
+				  LogicalDriveNumber,
+				  (100 * (BlocksCompleted >> 7))
+				  / (LogicalDriveSize >> 7));
+		  Controller->EphemeralProgressMessage = false;
+		  break;
+		case DAC960_V1_BackgroundInitializationSuspended:
+		  DAC960_Progress("Background Initialization Suspended\n",
+				  Controller);
+		  break;
+		case DAC960_V1_BackgroundInitializationCancelled:
+		  DAC960_Progress("Background Initialization Cancelled\n",
+				  Controller);
+		  break;
+		}
+	      memcpy(&Controller->V1.LastBackgroundInitializationStatus,
+		     &Controller->V1.BackgroundInitializationStatus,
+		     sizeof(DAC960_V1_BackgroundInitializationStatus_T));
+	      break;
+	    case DAC960_V1_BackgroundInitSuccessful:
+	      if (Controller->V1.BackgroundInitializationStatus.Status ==
+		  DAC960_V1_BackgroundInitializationInProgress)
+		DAC960_Progress("Background Initialization "
+				"Completed Successfully\n", Controller);
+	      Controller->V1.BackgroundInitializationStatus.Status =
+		DAC960_V1_BackgroundInitializationInvalid;
+	      break;
+	    case DAC960_V1_BackgroundInitAborted:
+	      if (Controller->V1.BackgroundInitializationStatus.Status ==
+		  DAC960_V1_BackgroundInitializationInProgress)
+		DAC960_Progress("Background Initialization Aborted\n",
+				Controller);
+	      Controller->V1.BackgroundInitializationStatus.Status =
+		DAC960_V1_BackgroundInitializationInvalid;
+	      break;
+	    case DAC960_V1_NoBackgroundInitInProgress:
+	      break;
+	    }
+	}
     }
   if (CommandType == DAC960_MonitoringCommand)
     {
@@ -3562,6 +3839,17 @@
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
+      if (Controller->V1.NeedBackgroundInitializationStatus)
+	{
+	  Controller->V1.NeedBackgroundInitializationStatus = false;
+	  Command->V1.CommandMailbox.Type3B.CommandOpcode =
+	    DAC960_V1_BackgroundInitializationControl;
+	  Command->V1.CommandMailbox.Type3B.CommandOpcode2 = 0x20;
+	  Command->V1.CommandMailbox.Type3B.BusAddress =
+	    Virtual_to_Bus32(&Controller->V1.BackgroundInitializationStatus);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
       Controller->MonitoringTimerCount++;
       Controller->MonitoringTimer.expires =
 	jiffies + DAC960_MonitoringTimerInterval;
@@ -3642,12 +3930,12 @@
     }
   DAC960_Error("Error Condition %s on %s:\n", Controller,
 	       SenseErrors[Command->V2.RequestSense.SenseKey], CommandName);
-  DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %d..%d\n",
+  DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %u..%u\n",
 	       Controller, Controller->ControllerNumber,
 	       Command->LogicalDriveNumber, Command->BlockNumber,
 	       Command->BlockNumber + Command->BlockCount - 1);
   if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0)
-    DAC960_Error("  /dev/rd/c%dd%dp%d: relative blocks %d..%d\n",
+    DAC960_Error("  /dev/rd/c%dd%dp%d: relative blocks %u..%u\n",
 		 Controller, Controller->ControllerNumber,
 		 Command->LogicalDriveNumber,
 		 DAC960_PartitionNumber(Command->BufferHeader->b_rdev),
@@ -3680,11 +3968,14 @@
       { 0x000B, "P Rebuild Failed due to Logical Drive Failure" },
       { 0x000C, "S Offline" },
       { 0x000D, "P Found" },
-      { 0x000E, "P Gone" },
+      { 0x000E, "P Removed" },
       { 0x000F, "P Unconfigured" },
       { 0x0010, "P Expand Capacity Started" },
       { 0x0011, "P Expand Capacity Completed" },
       { 0x0012, "P Expand Capacity Failed" },
+      { 0x0013, "P Command Timed Out" },
+      { 0x0014, "P Command Aborted" },
+      { 0x0015, "P Command Retried" },
       { 0x0016, "P Parity Error" },
       { 0x0017, "P Soft Error" },
       { 0x0018, "P Miscellaneous Error" },
@@ -3715,6 +4006,8 @@
       { 0x0031, "P Failed because BDT Write Operation Failed" },
       { 0x0039, "P Missing at Startup" },
       { 0x003A, "P Start Rebuild Failed due to Physical Drive Too Small" },
+      { 0x003C, "P Temporarily Offline Device Automatically Made Online" },
+      { 0x003D, "P Standby Rebuild Started" },
       /* Logical Device Events (0x0080 - 0x00FF) */
       { 0x0080, "M Consistency Check Started" },
       { 0x0081, "M Consistency Check Completed" },
@@ -3737,7 +4030,7 @@
       { 0x0092, "M Initialization Cancelled" },
       { 0x0093, "M Initialization Failed" },
       { 0x0094, "L Found" },
-      { 0x0095, "L Gone" },
+      { 0x0095, "L Deleted" },
       { 0x0096, "M Expand Capacity Started" },
       { 0x0097, "M Expand Capacity Completed" },
       { 0x0098, "M Expand Capacity Failed" },
@@ -3747,6 +4040,9 @@
       { 0x009C, "L Bad Data Block Found" },
       { 0x009E, "L Read of Data Block in BDT" },
       { 0x009F, "L Write Back Data for Disk Block Lost" },
+      { 0x00A0, "L Temporarily Offline RAID-5/3 Drive Made Online" },
+      { 0x00A1, "L Temporarily Offline RAID-6/1/0/7 Drive Made Online" },
+      { 0x00A2, "L Standby Rebuild Started" },
       /* Fault Management Events (0x0100 - 0x017F) */
       { 0x0140, "E Fan %d Failed" },
       { 0x0141, "E Fan %d OK" },
@@ -3754,24 +4050,31 @@
       { 0x0143, "E Power Supply %d Failed" },
       { 0x0144, "E Power Supply %d OK" },
       { 0x0145, "E Power Supply %d Not Present" },
-      { 0x0146, "E Temperature Sensor %d Failed" },
-      { 0x0147, "E Temperature Sensor %d Critical" },
-      { 0x0148, "E Temperature Sensor %d OK" },
+      { 0x0146, "E Temperature Sensor %d Temperature Exceeds Safe Limit" },
+      { 0x0147, "E Temperature Sensor %d Temperature Exceeds Working Limit" },
+      { 0x0148, "E Temperature Sensor %d Temperature Normal" },
       { 0x0149, "E Temperature Sensor %d Not Present" },
-      { 0x014A, "E Unit %d Access Critical" },
-      { 0x014B, "E Unit %d Access OK" },
-      { 0x014C, "E Unit %d Access Offline" },
+      { 0x014A, "E Enclosure Management Unit %d Access Critical" },
+      { 0x014B, "E Enclosure Management Unit %d Access OK" },
+      { 0x014C, "E Enclosure Management Unit %d Access Offline" },
       /* Controller Events (0x0180 - 0x01FF) */
       { 0x0181, "C Cache Write Back Error" },
       { 0x0188, "C Battery Backup Unit Found" },
       { 0x0189, "C Battery Backup Unit Charge Level Low" },
       { 0x018A, "C Battery Backup Unit Charge Level OK" },
       { 0x0193, "C Installation Aborted" },
-      { 0x0195, "C Mirror Race Recovery In Progress" },
-      { 0x0196, "C Mirror Race on Critical Drive" },
-      { 0x019E, "C Memory Soft ECC Error" },
-      { 0x019F, "C Memory Hard ECC Error" },
+      { 0x0195, "C Battery Backup Unit Physically Removed" },
+      { 0x0196, "C Memory Error During Warm Boot" },
+      { 0x019E, "C Memory Soft ECC Error Corrected" },
+      { 0x019F, "C Memory Hard ECC Error Corrected" },
       { 0x01A2, "C Battery Backup Unit Failed" },
+      { 0x01AB, "C Mirror Race Recovery Failed" },
+      { 0x01AC, "C Mirror Race on Critical Drive" },
+      /* Controller Internal Processor Events */
+      { 0x0380, "C Internal Controller Hung" },
+      { 0x0381, "C Internal Controller Firmware Breakpoint" },
+      { 0x0390, "C Internal Controller i960 Processor Specific Error" },
+      { 0x03A0, "C Internal Controller StrongARM Processor Specific Error" },
       { 0, "" } };
   int EventListIndex = 0, EventCode;
   unsigned char EventType, *EventMessage;
@@ -3821,7 +4124,7 @@
       DAC960_Critical("Physical Device %d:%d %s\n", Controller,
 		      Event->Channel, Event->TargetID, EventMessage);
       DAC960_Critical("Physical Device %d:%d Request Sense: "
-		      "Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
+		      "Sense Key = %X, ASC = %02X, ASCQ = %02X\n",
 		      Controller,
 		      Event->Channel,
 		      Event->TargetID,
@@ -4142,22 +4445,34 @@
 	    {
 	      if (NewPhysicalDeviceInfo->PhysicalDeviceState !=
 		  PhysicalDeviceInfo->PhysicalDeviceState)
-		DAC960_Critical("Physical Device %d:%d is now %s\n", Controller,
-				NewPhysicalDeviceInfo->Channel,
-				NewPhysicalDeviceInfo->TargetID,
-				(NewPhysicalDeviceInfo->PhysicalDeviceState
-				 == DAC960_V2_Device_Unconfigured
-				 ? "UNCONFIGURED"
-				 : NewPhysicalDeviceInfo->PhysicalDeviceState
-				   == DAC960_V2_Device_Online
-				   ? "ONLINE"
-				   : NewPhysicalDeviceInfo->PhysicalDeviceState
-				     == DAC960_V2_Device_WriteOnly
-				     ? "WRITE-ONLY"
-				     : NewPhysicalDeviceInfo
-				       ->PhysicalDeviceState
-				       == DAC960_V2_Device_Dead
-				       ? "DEAD" : "STANDBY"));
+		DAC960_Critical(
+		  "Physical Device %d:%d is now %s\n", Controller,
+		  NewPhysicalDeviceInfo->Channel,
+		  NewPhysicalDeviceInfo->TargetID,
+		  (NewPhysicalDeviceInfo->PhysicalDeviceState
+		   == DAC960_V2_Device_Online
+		   ? "ONLINE"
+		   : NewPhysicalDeviceInfo->PhysicalDeviceState
+		     == DAC960_V2_Device_Rebuild
+		     ? "REBUILD"
+		     : NewPhysicalDeviceInfo->PhysicalDeviceState
+		       == DAC960_V2_Device_Missing
+		       ? "MISSING"
+		       : NewPhysicalDeviceInfo->PhysicalDeviceState
+			 == DAC960_V2_Device_Critical
+			 ? "CRITICAL"
+			 : NewPhysicalDeviceInfo->PhysicalDeviceState
+			   == DAC960_V2_Device_Dead
+			   ? "DEAD"
+			   : NewPhysicalDeviceInfo->PhysicalDeviceState
+			     == DAC960_V2_Device_SuspectedDead
+			     ? "SUSPECTED-DEAD"
+			     : NewPhysicalDeviceInfo->PhysicalDeviceState
+			       == DAC960_V2_Device_CommandedOffline
+			       ? "COMMANDED-OFFLINE"
+			       : NewPhysicalDeviceInfo->PhysicalDeviceState
+				 == DAC960_V2_Device_Standby
+				 ? "STANDBY" : "UNKNOWN"));
 	      if ((NewPhysicalDeviceInfo->ParityErrors !=
 		   PhysicalDeviceInfo->ParityErrors) ||
 		  (NewPhysicalDeviceInfo->SoftErrors !=
@@ -4263,13 +4578,16 @@
 			      (LogicalDeviceInfo != NULL
 			       ? "" : " - Allocation Failed"));
 	      if (LogicalDeviceInfo != NULL)
-		memset(LogicalDeviceInfo, 0,
-		       sizeof(DAC960_V2_LogicalDeviceInfo_T));
+		{
+		  memset(LogicalDeviceInfo, 0,
+			 sizeof(DAC960_V2_LogicalDeviceInfo_T));
+		  DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+		}
 	    }
 	  if (LogicalDeviceInfo != NULL)
 	    {
 	      unsigned long LogicalDeviceSize =
-		NewLogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB;
+		NewLogicalDeviceInfo->ConfigurableDeviceSize;
 	      if (NewLogicalDeviceInfo->LogicalDeviceState !=
 		  LogicalDeviceInfo->LogicalDeviceState)
 		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
@@ -4380,6 +4698,7 @@
 	      kfree(LogicalDeviceInfo);
 	      Controller->LogicalDriveInitiallyAccessible
 			  [LogicalDriveNumber] = false;
+	      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
 	    }
 	  Controller->V2.NeedLogicalDeviceInformation = false;
 	}
@@ -4785,6 +5104,85 @@
 
 
 /*
+  DAC960_P_InterruptHandler handles hardware interrupts from DAC960 P Series
+  Controllers.
+*/
+
+static void DAC960_P_InterruptHandler(int IRQ_Channel,
+				      void *DeviceIdentifier,
+				      Registers_T *InterruptRegisters)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+  /*
+    Process Hardware Interrupts for Controller.
+  */
+  while (DAC960_PD_StatusAvailableP(ControllerBaseAddress))
+    {
+      DAC960_V1_CommandIdentifier_T CommandIdentifier =
+	DAC960_PD_ReadStatusCommandIdentifier(ControllerBaseAddress);
+      DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+      DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+      DAC960_V1_CommandOpcode_T CommandOpcode =
+	CommandMailbox->Common.CommandOpcode;
+      Command->V1.CommandStatus =
+	DAC960_PD_ReadStatusRegister(ControllerBaseAddress);
+      DAC960_PD_AcknowledgeInterrupt(ControllerBaseAddress);
+      DAC960_PD_AcknowledgeStatus(ControllerBaseAddress);
+      switch (CommandOpcode)
+	{
+	case DAC960_V1_Enquiry_Old:
+	  Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Enquiry;
+	  DAC960_P_To_PD_TranslateEnquiry(
+	    Bus32_to_Virtual(CommandMailbox->Type3.BusAddress));
+	  break;
+	case DAC960_V1_GetDeviceState_Old:
+	  Command->V1.CommandMailbox.Common.CommandOpcode =
+	    DAC960_V1_GetDeviceState;
+	  DAC960_P_To_PD_TranslateDeviceState(
+	    Bus32_to_Virtual(CommandMailbox->Type3.BusAddress));
+	  break;
+	case DAC960_V1_Read_Old:
+	  Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Read;
+	  DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox);
+	  break;
+	case DAC960_V1_Write_Old:
+	  Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Write;
+	  DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox);
+	  break;
+	case DAC960_V1_ReadWithScatterGather_Old:
+	  Command->V1.CommandMailbox.Common.CommandOpcode =
+	    DAC960_V1_ReadWithScatterGather;
+	  DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox);
+	  break;
+	case DAC960_V1_WriteWithScatterGather_Old:
+	  Command->V1.CommandMailbox.Common.CommandOpcode =
+	    DAC960_V1_WriteWithScatterGather;
+	  DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox);
+	  break;
+	default:
+	  break;
+	}
+      DAC960_V1_ProcessCompletedCommand(Command);
+    }
+  /*
+    Attempt to remove additional I/O Requests from the Controller's
+    I/O Request Queue and queue them to the Controller.
+  */
+  while (DAC960_ProcessRequest(Controller, false)) ;
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
+/*
   DAC960_V1_QueueMonitoringCommand queues a Monitoring Command to DAC960 V1
   Firmware Controllers.
 */
@@ -4881,8 +5279,7 @@
 		Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
 	      if (LogicalDeviceInfo == NULL) continue;
 	      if (!LogicalDeviceInfo->LogicalDeviceControl
-				     .LogicalDeviceInitialized &&
-		  Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 0)
+				     .LogicalDeviceInitialized)
 		{
 		  ForceMonitoringCommand = true;
 		  break;
@@ -4970,6 +5367,7 @@
   if (!Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber])
     {
       Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true;
+      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
       DAC960_RegisterDisk(Controller, LogicalDriveNumber);
     }
   if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
@@ -5049,7 +5447,7 @@
 	    Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
 	  if (LogicalDeviceInfo == NULL)
 	    return -EINVAL;
-	  switch(LogicalDeviceInfo->DriveGeometry)
+	  switch (LogicalDeviceInfo->DriveGeometry)
 	    {
 	    case DAC960_V2_Geometry_128_32:
 	      Geometry.heads = 128;
@@ -5065,7 +5463,7 @@
 	      return -EINVAL;
 	    }
 	  Geometry.cylinders =
-	    LogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB
+	    LogicalDeviceInfo->ConfigurableDeviceSize
 	    / (Geometry.heads * Geometry.sectors);
 	}
       Geometry.start =
@@ -5074,19 +5472,22 @@
 			   sizeof(DiskGeometry_T)) ? -EFAULT : 0);
     case BLKGETSIZE:
       /* Get Device Size. */
+      if ((unsigned long *) Argument == NULL) return -EINVAL;
       return put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)]
 						 .nr_sects,
-		      (long *) Argument);
+		      (unsigned long *) Argument);
     case BLKGETSIZE64:
-      return put_user((u64)Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)].nr_sects << 9,
+      if ((u64 *) Argument == NULL) return -EINVAL;
+      return put_user((u64) Controller->GenericDiskInfo
+				       .part[MINOR(Inode->i_rdev)]
+				       .nr_sects << 9,
 		      (u64 *) Argument);
     case BLKRAGET:
     case BLKRASET:
     case BLKFLSBUF:
     case BLKBSZGET:
     case BLKBSZSET:
-      return blk_ioctl (Inode->i_rdev, Request, Argument);
-
+      return blk_ioctl(Inode->i_rdev, Request, Argument);
     case BLKRRPART:
       /* Re-Read Partition Table. */
       if (!capable(CAP_SYS_ADMIN)) return -EACCES;
@@ -5120,20 +5521,7 @@
 	  */
 	  set_blocksize(Device, BLOCK_SIZE);
 	}
-      if (Controller->FirmwareType == DAC960_V1_Controller)
-	grok_partitions(&Controller->GenericDiskInfo,
-			LogicalDriveNumber,
-			DAC960_MaxPartitions,
-			Controller->V1.LogicalDriveInformation
-				       [LogicalDriveNumber]
-				       .LogicalDriveSize);
-      else
-	grok_partitions(
-	  &Controller->GenericDiskInfo,
-	  LogicalDriveNumber,
-	  DAC960_MaxPartitions,
-	  Controller->V2.LogicalDeviceInformation[LogicalDriveNumber]
-			 ->ConfigurableDeviceSizeIn512ByteBlocksOrMB);
+      DAC960_RegisterDisk(Controller, LogicalDriveNumber);
       return 0;
     }
   return -EINVAL;
@@ -6365,6 +6753,43 @@
 			   == DAC960_V2_NormalCompletion
 			   ? "Cancelled" : "Not Cancelled"));
     }
+  else if (strcmp(UserCommand, "perform-discovery") == 0)
+    {
+      CommandMailbox->Common.IOCTL_Opcode = DAC960_V2_StartDiscovery;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Discovery %s\n", Controller,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Initiated" : "Not Initiated"));
+      if (Command->V2.CommandStatus == DAC960_V2_NormalCompletion)
+	{
+	  CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL;
+	  CommandMailbox->ControllerInfo.CommandControlBits
+					.DataTransferControllerToHost = true;
+	  CommandMailbox->ControllerInfo.CommandControlBits
+					.NoAutoRequestSense = true;
+	  CommandMailbox->ControllerInfo.DataTransferSize =
+	    sizeof(DAC960_V2_ControllerInfo_T);
+	  CommandMailbox->ControllerInfo.ControllerNumber = 0;
+	  CommandMailbox->ControllerInfo.IOCTL_Opcode =
+	    DAC960_V2_GetControllerInfo;
+	  CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+					.ScatterGatherSegments[0]
+					.SegmentDataPointer =
+	    Virtual_to_Bus64(&Controller->V2.NewControllerInformation);
+	  CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+					.ScatterGatherSegments[0]
+					.SegmentByteCount =
+	    CommandMailbox->ControllerInfo.DataTransferSize;
+	  DAC960_ExecuteCommand(Command);
+	  while (Controller->V2.NewControllerInformation.PhysicalScanActive)
+	    {
+	      DAC960_ExecuteCommand(Command);
+	      sleep_on_timeout(&Controller->CommandWaitQueue, HZ);
+	    }
+	  DAC960_UserCritical("Discovery Completed\n", Controller);
+ 	}
+    }
   else if (strcmp(UserCommand, "suppress-enclosure-messages") == 0)
     Controller->SuppressEnclosureMessages = true;
   else DAC960_UserCritical("Illegal User Command: '%s'\n",
@@ -6587,24 +7012,5 @@
 }
 
 
-/*
-  Include Module support if requested.
-*/
-
-#ifdef MODULE
-
-
-int init_module(void)
-{
-  DAC960_Initialize();
-  return (DAC960_ActiveControllerCount > 0 ? 0 : -1);
-}
-
-
-void cleanup_module(void)
-{
-  DAC960_Finalize(&DAC960_NotifierBlock, SYS_RESTART, NULL);
-}
-
-
-#endif
+module_init(DAC960_Initialize);
+module_exit(DAC960_Finalize);
diff -u --recursive --new-file v2.4.12/linux/drivers/block/DAC960.h linux/drivers/block/DAC960.h
--- v2.4.12/linux/drivers/block/DAC960.h	Sun Aug 12 13:27:59 2001
+++ linux/drivers/block/DAC960.h	Wed Oct 17 14:46:29 2001
@@ -224,9 +224,9 @@
   DAC960_V1_ReadExtendedWithScatterGather =	0xB3,
   DAC960_V1_WriteExtendedWithScatterGather =	0xB4,
   DAC960_V1_Read =				0x36,
-  DAC960_V1_ReadWithOldScatterGather =		0xB6,
+  DAC960_V1_ReadWithScatterGather =		0xB6,
   DAC960_V1_Write =				0x37,
-  DAC960_V1_WriteWithOldScatterGather =		0xB7,
+  DAC960_V1_WriteWithScatterGather =		0xB7,
   DAC960_V1_DCDB =				0x04,
   DAC960_V1_DCDBWithScatterGather =		0x84,
   DAC960_V1_Flush =				0x0A,
@@ -280,7 +280,14 @@
   DAC960_V1_RunDiagnostic =			0x32,
   /* Subsystem Service Commands */
   DAC960_V1_GetSubsystemData =			0x70,
-  DAC960_V1_SetSubsystemParameters =		0x71
+  DAC960_V1_SetSubsystemParameters =		0x71,
+  /* Version 2.xx Firmware Commands */
+  DAC960_V1_Enquiry_Old =			0x05,
+  DAC960_V1_GetDeviceState_Old =		0x14,
+  DAC960_V1_Read_Old =				0x02,
+  DAC960_V1_Write_Old =				0x03,
+  DAC960_V1_ReadWithScatterGather_Old =		0x82,
+  DAC960_V1_WriteWithScatterGather_Old =	0x83
 }
 __attribute__ ((packed))
 DAC960_V1_CommandOpcode_T;
@@ -327,6 +334,9 @@
 #define DAC960_V1_RebuildFailed_NewDriveFailed	0x0004	/* Consistency */
 #define DAC960_V1_RebuildSuccessful		0x0100	/* Consistency */
 #define DAC960_V1_RebuildSuccessfullyTerminated	0x0107	/* Consistency */
+#define DAC960_V1_BackgroundInitSuccessful	0x0100	/* Consistency */
+#define DAC960_V1_BackgroundInitAborted		0x0005	/* Consistency */
+#define DAC960_V1_NoBackgroundInitInProgress	0x0105	/* Consistency */
 #define DAC960_V1_AddCapacityInProgress		0x0004	/* Consistency */
 #define DAC960_V1_AddCapacityFailedOrSuspended	0x00F4	/* Consistency */
 #define DAC960_V1_Config2ChecksumError		0x0002	/* Configuration */
@@ -634,6 +644,8 @@
 
 /*
   Define the DAC960 V1 Firmware Get Device State Command reply structure.
+  The structure is padded by 2 bytes for compatibility with Version 2.xx
+  Firmware.
 */
 
 typedef struct DAC960_V1_DeviceState
@@ -658,6 +670,7 @@
   unsigned char SynchronousOffset:5;			/* Byte 5 Bits 0-4 */
   unsigned char :3;					/* Byte 5 Bits 5-7 */
   unsigned int DiskSize __attribute__ ((packed));	/* Bytes 6-9 */
+  unsigned short :16;					/* Bytes 10-11 */
 }
 DAC960_V1_DeviceState_T;
 
@@ -676,6 +689,30 @@
 
 
 /*
+  Define the DAC960 V1 Firmware Background Initialization Status Command
+  reply structure.
+*/
+
+typedef struct DAC960_V1_BackgroundInitializationStatus
+{
+  unsigned int LogicalDriveSize;			/* Bytes 0-3 */
+  unsigned int BlocksCompleted;				/* Bytes 4-7 */
+  unsigned char Reserved1[12];				/* Bytes 8-19 */
+  unsigned int LogicalDriveNumber;			/* Bytes 20-23 */
+  unsigned char RAIDLevel;				/* Byte 24 */
+  enum {
+    DAC960_V1_BackgroundInitializationInvalid =	    0x00,
+    DAC960_V1_BackgroundInitializationStarted =	    0x02,
+    DAC960_V1_BackgroundInitializationInProgress =  0x04,
+    DAC960_V1_BackgroundInitializationSuspended =   0x05,
+    DAC960_V1_BackgroundInitializationCancelled =   0x06
+  } __attribute__ ((packed)) Status;			/* Byte 25 */
+  unsigned char Reserved2[6];				/* Bytes 26-31 */
+}
+DAC960_V1_BackgroundInitializationStatus_T;
+
+
+/*
   Define the DAC960 V1 Firmware Error Table Entry structure.
 */
 
@@ -853,6 +890,14 @@
   struct {
     DAC960_V1_CommandOpcode_T CommandOpcode;		/* Byte 0 */
     DAC960_V1_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    unsigned char CommandOpcode2;			/* Byte 2 */
+    unsigned char Dummy1[5];				/* Bytes 3-7 */
+    DAC960_BusAddress32_T BusAddress;			/* Bytes 8-11 */
+    unsigned char Dummy2[4];				/* Bytes 12-15 */
+  } __attribute__ ((packed)) Type3B;
+  struct {
+    DAC960_V1_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_V1_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
     unsigned char Dummy1[5];				/* Bytes 2-6 */
     unsigned char LogicalDriveNumber:6;			/* Byte 7 Bits 0-6 */
     boolean AutoRestore:1;				/* Byte 7 Bit 7 */
@@ -956,6 +1001,7 @@
   DAC960_V2_GetPhysicalDeviceInfoValid =	0x05,
   DAC960_V2_GetHealthStatus =			0x11,
   DAC960_V2_GetEvent =				0x15,
+  DAC960_V2_StartDiscovery =			0x81,
   DAC960_V2_SetDeviceState =			0x82,
   DAC960_V2_RebuildDeviceStart =		0x88,
   DAC960_V2_RebuildDeviceStop =			0x89,
@@ -982,7 +1028,10 @@
 
 #define DAC960_V2_NormalCompletion		0x00
 #define DAC960_V2_AbormalCompletion		0x02
+#define DAC960_V2_DeviceBusy			0x08
 #define DAC960_V2_DeviceNonresponsive		0x0E
+#define DAC960_V2_DeviceNonresponsive2		0x0F
+#define DAC960_V2_DeviceRevervationConflict	0x18
 
 typedef unsigned char DAC960_V2_CommandStatus_T;
 
@@ -1056,7 +1105,8 @@
     DAC960_V2_EXR2000P =			0x1C,
     DAC960_V2_EXR3000P =			0x1D,
     DAC960_V2_AcceleRAID352 =			0x1E,
-    DAC960_V2_AcceleRAID351 =			0x1F,
+    DAC960_V2_AcceleRAID170 =			0x1F,
+    DAC960_V2_AcceleRAID160 =			0x20,
     DAC960_V2_DAC960S =				0x60,
     DAC960_V2_DAC960SU =			0x61,
     DAC960_V2_DAC960SX =			0x62,
@@ -1073,7 +1123,9 @@
   unsigned char :8;					/* Byte 3 */
   unsigned short BusInterfaceSpeedMHz;			/* Bytes 4-5 */
   unsigned char BusWidthBits;				/* Byte 6 */
-  unsigned char Reserved1[9];				/* Bytes 7-15 */
+  unsigned char FlashCodeTypeOrProductID;		/* Byte 7 */
+  unsigned char NumberOfHostPortsPresent;		/* Byte 8 */
+  unsigned char Reserved1[7];				/* Bytes 9-15 */
   unsigned char BusInterfaceName[16];			/* Bytes 16-31 */
   unsigned char ControllerName[16];			/* Bytes 32-47 */
   unsigned char Reserved2[16];				/* Bytes 48-63 */
@@ -1102,17 +1154,17 @@
   unsigned char HardwareManufacturingMonth;		/* Byte 85 */
   unsigned char HardwareManufacturingYearHigh2Digits;	/* Byte 86 */
   unsigned char HardwareManufacturingYearLow2Digits;	/* Byte 87 */
-  unsigned char MaximumNumberOfPDDperXLDD;		/* Byte 88 */
-  unsigned char MaximumNumberOfILDDperXLDD;		/* Byte 89 */
+  unsigned char MaximumNumberOfPDDperXLD;		/* Byte 88 */
+  unsigned char MaximumNumberOfILDperXLD;		/* Byte 89 */
   unsigned short NonvolatileMemorySizeKB;		/* Bytes 90-91 */
-  unsigned char MaximumNumberOfXLDD;			/* Byte 92 */
+  unsigned char MaximumNumberOfXLD;			/* Byte 92 */
   unsigned int :24;					/* Bytes 93-95 */
   /* Unique Information per Controller */
   unsigned char ControllerSerialNumber[16];		/* Bytes 96-111 */
   unsigned char Reserved3[16];				/* Bytes 112-127 */
   /* Vendor Information */
   unsigned int :24;					/* Bytes 128-130 */
-  unsigned char OEM_Information;			/* Byte 131 */
+  unsigned char OEM_Code;				/* Byte 131 */
   unsigned char VendorName[16];				/* Bytes 132-147 */
   /* Other Physical/Controller/Operation Information */
   boolean BBU_Present:1;				/* Byte 148 Bit 0 */
@@ -1193,12 +1245,14 @@
   unsigned short PhysicalDeviceHostCommandAbortsDone;	/* Bytes 370-371 */
   unsigned short PhysicalDevicePredictedFailuresDetected; /* Bytes 372-373 */
   unsigned short PhysicalDeviceHostCommandsFailed;	/* Bytes 374-375 */
-  unsigned char Reserved9[8];				/* Bytes 376-383 */
+  unsigned short PhysicalDeviceHardErrors;		/* Bytes 376-377 */
+  unsigned char Reserved9[6];				/* Bytes 378-383 */
   /* Error Counters on Logical Devices */
   unsigned short LogicalDeviceSoftErrors;		/* Bytes 384-385 */
   unsigned short LogicalDeviceCommandsFailed;		/* Bytes 386-387 */
   unsigned short LogicalDeviceHostCommandAbortsDone;	/* Bytes 388-389 */
   unsigned short :16;					/* Bytes 390-391 */
+  /* Error Counters on Controller */
   unsigned short ControllerMemoryErrors;		/* Bytes 392-393 */
   unsigned short ControllerHostCommandAbortsDone;	/* Bytes 394-395 */
   unsigned int :32;					/* Bytes 396-399 */
@@ -1210,8 +1264,7 @@
   unsigned short RebuildsActive;			/* Bytes 408-409 */
   unsigned short OnlineExpansionsActive;		/* Bytes 410-411 */
   unsigned short PatrolActivitiesActive;		/* Bytes 412-413 */
-  unsigned char LongOperationStatus;			/* Byte 414 */
-  unsigned char :8;					/* Byte 415 */
+  unsigned short :16;					/* Bytes 414-415 */
   /* Flash ROM Information */
   unsigned char FlashType;				/* Byte 416 */
   unsigned char :8;					/* Byte 417 */
@@ -1234,8 +1287,7 @@
   unsigned short NumberOfConfigurationGroups;		/* Bytes 474-475 */
   boolean InstallationAbortStatus:1;			/* Byte 476 Bit 0 */
   boolean MaintenanceModeStatus:1;			/* Byte 476 Bit 1 */
-  unsigned int :6;					/* Byte 476 Bits 2-7 */
-  unsigned int :24;					/* Bytes 477-479 */
+  unsigned int :24;					/* Bytes 476-479 */
   unsigned char Reserved10[32];				/* Bytes 480-511 */
   unsigned char Reserved11[512];			/* Bytes 512-1023 */
 }
@@ -1311,7 +1363,7 @@
     DAC960_V2_Geometry_Reserved1 =		0x2,
     DAC960_V2_Geometry_Reserved2 =		0x3
   } __attribute__ ((packed)) DriveGeometry:2;		/* Byte 14 Bits 5-6 */
-  unsigned char :1;					/* Byte 14 Bit 7 */
+  boolean SuperReadAheadEnabled:1;			/* Byte 14 Bit 7 */
   unsigned char :8;					/* Byte 15 */
   /* Error Counters */
   unsigned short SoftErrors;				/* Bytes 16-17 */
@@ -1323,8 +1375,8 @@
   /* Device Size Information */
   unsigned short :16;					/* Bytes 32-33 */
   unsigned short DeviceBlockSizeInBytes;		/* Bytes 34-35 */
-  unsigned int OriginalDeviceSizeIn512ByteBlocksOrMB;	/* Bytes 36-39 */
-  unsigned int ConfigurableDeviceSizeIn512ByteBlocksOrMB; /* Bytes 40-43 */
+  unsigned int OriginalDeviceSize;			/* Bytes 36-39 */
+  unsigned int ConfigurableDeviceSize;			/* Bytes 40-43 */
   unsigned int :32;					/* Bytes 44-47 */
   unsigned char LogicalDeviceName[32];			/* Bytes 48-79 */
   unsigned char SCSI_InquiryData[36];			/* Bytes 80-115 */
@@ -1350,8 +1402,12 @@
 {
     DAC960_V2_Device_Unconfigured =		0x00,
     DAC960_V2_Device_Online =			0x01,
-    DAC960_V2_Device_WriteOnly =		0x03,
+    DAC960_V2_Device_Rebuild =			0x03,
+    DAC960_V2_Device_Missing =			0x04,
+    DAC960_V2_Device_Critical =			0x05,
     DAC960_V2_Device_Dead =			0x08,
+    DAC960_V2_Device_SuspectedDead =		0x0C,
+    DAC960_V2_Device_CommandedOffline =		0x10,
     DAC960_V2_Device_Standby =			0x21,
     DAC960_V2_Device_InvalidState =		0xFF
 }
@@ -1371,7 +1427,7 @@
   unsigned char LogicalUnit;				/* Byte 3 */
   /* Configuration Status Bits */
   boolean PhysicalDeviceFaultTolerant:1;		/* Byte 4 Bit 0 */
-  boolean :1;						/* Byte 4 Bit 1 */
+  boolean PhysicalDeviceConnected:1;			/* Byte 4 Bit 1 */
   boolean PhysicalDeviceLocalToController:1;		/* Byte 4 Bit 2 */
   unsigned char :5;					/* Byte 4 Bits 3-7 */
   /* Multiple Host/Controller Status Bits */
@@ -1407,15 +1463,15 @@
   unsigned int :32;					/* Bytes 44-47 */
   unsigned short :16;					/* Bytes 48-49 */
   unsigned short DeviceBlockSizeInBytes;		/* Bytes 50-51 */
-  unsigned int OriginalDeviceSizeIn512ByteBlocksOrMB;	/* Bytes 52-55 */
-  unsigned int ConfigurableDeviceSizeIn512ByteBlocksOrMB; /* Bytes 56-59 */
+  unsigned int OriginalDeviceSize;			/* Bytes 52-55 */
+  unsigned int ConfigurableDeviceSize;			/* Bytes 56-59 */
   unsigned int :32;					/* Bytes 60-63 */
   unsigned char PhysicalDeviceName[16];			/* Bytes 64-79 */
   unsigned char Reserved1[16];				/* Bytes 80-95 */
   unsigned char Reserved2[32];				/* Bytes 96-127 */
   unsigned char SCSI_InquiryData[36];			/* Bytes 128-163 */
-  unsigned char Reserved3[12];				/* Bytes 164-175 */
-  unsigned char Reserved4[16];				/* Bytes 176-191 */
+  unsigned char Reserved3[20];				/* Bytes 164-183 */
+  unsigned char Reserved4[8];				/* Bytes 184-191 */
   DAC960_ByteCount64_T LastReadBlockNumber;		/* Bytes 192-199 */
   DAC960_ByteCount64_T LastWrittenBlockNumber;		/* Bytes 200-207 */
   DAC960_ByteCount64_T ConsistencyCheckBlockNumber;	/* Bytes 208-215 */
@@ -1549,7 +1605,8 @@
   DAC960_V2_RAID_Channel =			0x03,
   DAC960_V2_Physical_Controller =		0x04,
   DAC960_V2_RAID_Controller =			0x05,
-  DAC960_V2_Configuration_Group =		0x10
+  DAC960_V2_Configuration_Group =		0x10,
+  DAC960_V2_Enclosure =				0x11
 }
 __attribute__ ((packed))
 DAC960_V2_OperationDevice_T;
@@ -1630,8 +1687,7 @@
     DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
     DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
     DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
-    DAC960_ByteCount32_T DataTransferSize:24;		/* Bytes 4-6 */
-    unsigned char DataTransferPageNumber;		/* Byte 7 */
+    DAC960_ByteCount32_T DataTransferSize;		/* Bytes 4-7 */
     DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
     DAC960_V2_PhysicalDevice_T PhysicalDevice;		/* Bytes 16-18 */
     DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
@@ -1645,8 +1701,7 @@
     DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
     DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
     DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
-    DAC960_ByteCount32_T DataTransferSize:24;		/* Bytes 4-6 */
-    unsigned char DataTransferPageNumber;		/* Byte 7 */
+    DAC960_ByteCount32_T DataTransferSize;		/* Bytes 4-7 */
     DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
     DAC960_V2_PhysicalDevice_T PhysicalDevice;		/* Bytes 16-18 */
     DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
@@ -1795,7 +1850,6 @@
       DataTransferMemoryAddress;			/* Bytes 32-63 */
   } DeviceOperation;
 }
-__attribute__ ((packed))
 DAC960_V2_CommandMailbox_T;
 
 
@@ -2074,7 +2128,8 @@
   DAC960_LP_Controller =			2,	/* AcceleRAID 352 */
   DAC960_LA_Controller =			3,	/* DAC1164P */
   DAC960_PG_Controller =			4,	/* DAC960PTL/PJ/PG */
-  DAC960_PD_Controller =			5	/* DAC960PU/PD/PL */
+  DAC960_PD_Controller =			5,	/* DAC960PU/PD/PL/P */
+  DAC960_P_Controller =				6	/* DAC960PU/PD/PL/P */
 }
 DAC960_HardwareType_T;
 
@@ -2336,6 +2391,7 @@
       unsigned short DeviceStateChannel;
       unsigned short DeviceStateTargetID;
       boolean DualModeMemoryMailboxInterface;
+      boolean BackgroundInitializationStatusSupported;
       boolean SAFTE_EnclosureManagementEnabled;
       boolean NeedLogicalDriveInformation;
       boolean NeedErrorTableInformation;
@@ -2344,6 +2400,7 @@
       boolean NeedDeviceSerialNumberInformation;
       boolean NeedRebuildProgress;
       boolean NeedConsistencyCheckProgress;
+      boolean NeedBackgroundInitializationStatus;
       boolean StartDeviceStateScan;
       boolean RebuildProgressFirst;
       boolean RebuildFlagPending;
@@ -2367,6 +2424,10 @@
       DAC960_V1_CommandStatus_T PendingRebuildStatus;
       DAC960_V1_LogicalDriveInformationArray_T LogicalDriveInformation;
       DAC960_V1_LogicalDriveInformationArray_T NewLogicalDriveInformation;
+      DAC960_V1_BackgroundInitializationStatus_T
+        BackgroundInitializationStatus;
+      DAC960_V1_BackgroundInitializationStatus_T
+        LastBackgroundInitializationStatus;
       DAC960_V1_DeviceState_T
 	DeviceState[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
       DAC960_V1_DeviceState_T NewDeviceState;
@@ -4143,13 +4204,46 @@
   return true;
 }
 
+static inline void DAC960_P_To_PD_TranslateEnquiry(void *Enquiry)
+{
+  memcpy(Enquiry + 132, Enquiry + 36, 64);
+  memset(Enquiry + 36, 0, 96);
+}
+
+static inline void DAC960_P_To_PD_TranslateDeviceState(void *DeviceState)
+{
+  memcpy(DeviceState + 2, DeviceState + 3, 1);
+  memcpy(DeviceState + 4, DeviceState + 5, 2);
+  memcpy(DeviceState + 6, DeviceState + 8, 4);
+}
+
+static inline
+void DAC960_PD_To_P_TranslateReadWriteCommand(DAC960_V1_CommandMailbox_T
+					      *CommandMailbox)
+{
+  int LogicalDriveNumber = CommandMailbox->Type5.LD.LogicalDriveNumber;
+  CommandMailbox->Bytes[3] &= 0x7;
+  CommandMailbox->Bytes[3] |= CommandMailbox->Bytes[7] << 6;
+  CommandMailbox->Bytes[7] = LogicalDriveNumber;
+}
+
+static inline
+void DAC960_P_To_PD_TranslateReadWriteCommand(DAC960_V1_CommandMailbox_T
+					      *CommandMailbox)
+{
+  int LogicalDriveNumber = CommandMailbox->Bytes[7];
+  CommandMailbox->Bytes[7] = CommandMailbox->Bytes[3] >> 6;
+  CommandMailbox->Bytes[3] &= 0x7;
+  CommandMailbox->Bytes[3] |= LogicalDriveNumber << 3;
+}
+
 
 /*
   Define prototypes for the forward referenced DAC960 Driver Internal Functions.
 */
 
 static void DAC960_FinalizeController(DAC960_Controller_T *);
-static int DAC960_Finalize(NotifierBlock_T *, unsigned long, void *);
+static int DAC960_Notifier(NotifierBlock_T *, unsigned long, void *);
 static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *);
 static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *);
 static void DAC960_RequestFunction(RequestQueue_T *);
@@ -4158,6 +4252,7 @@
 static void DAC960_LA_InterruptHandler(int, void *, Registers_T *);
 static void DAC960_PG_InterruptHandler(int, void *, Registers_T *);
 static void DAC960_PD_InterruptHandler(int, void *, Registers_T *);
+static void DAC960_P_InterruptHandler(int, void *, Registers_T *);
 static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *);
 static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *);
 static void DAC960_MonitoringTimerFunction(unsigned long);
diff -u --recursive --new-file v2.4.12/linux/drivers/block/acsi.c linux/drivers/block/acsi.c
--- v2.4.12/linux/drivers/block/acsi.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/acsi.c	Mon Oct 15 13:27:42 2001
@@ -1136,7 +1136,7 @@
 		
 	  case BLKGETSIZE:   /* Return device size */
 		return put_user(acsi_part[MINOR(inode->i_rdev)].nr_sects,
-				(long *) arg);
+				(unsigned long *) arg);
 
 	  case BLKGETSIZE64:   /* Return device size */
 		return put_user((u64)acsi_part[MINOR(inode->i_rdev)].nr_sects << 9,
diff -u --recursive --new-file v2.4.12/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- v2.4.12/linux/drivers/block/amiflop.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/amiflop.c	Mon Oct 15 13:27:41 2001
@@ -1555,7 +1555,7 @@
 			return -EFAULT;
 		break;
 	case BLKGETSIZE:
-		return put_user(unit[drive].blocks,(long *)param);
+		return put_user(unit[drive].blocks,(unsigned long *)param);
 		break;
 	case BLKGETSIZE64:
 		return put_user((u64)unit[drive].blocks << 9, (u64 *)param);
diff -u --recursive --new-file v2.4.12/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c
--- v2.4.12/linux/drivers/block/ataflop.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/ataflop.c	Mon Oct 15 13:27:42 2001
@@ -1600,7 +1600,7 @@
 				dtp = UDT;
 		}
 		if (cmd == BLKGETSIZE)
-			return put_user(dtp->blocks, (long *)param);
+			return put_user(dtp->blocks, (unsigned long *)param);
 
 		memset((void *)&getprm, 0, sizeof(getprm));
 		getprm.size = dtp->blocks;
diff -u --recursive --new-file v2.4.12/linux/drivers/block/blkpg.c linux/drivers/block/blkpg.c
--- v2.4.12/linux/drivers/block/blkpg.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/blkpg.c	Mon Oct 15 13:27:42 2001
@@ -242,10 +242,10 @@
 			/* add BLKGETSIZE64 too */
 			g = get_gendisk(dev);
 			if (!g)
-				longval = 0;
+				ulongval = 0;
 			else
-				longval = g->part[MINOR(dev)].nr_sects;
-			return put_user(longval, (long *) arg);
+				ulongval = g->part[MINOR(dev)].nr_sects;
+			return put_user(ulongval, (unsigned long *) arg);
 #endif
 #if 0
 		case BLKRRPART: /* Re-read partition tables */
diff -u --recursive --new-file v2.4.12/linux/drivers/block/cciss.c linux/drivers/block/cciss.c
--- v2.4.12/linux/drivers/block/cciss.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/cciss.c	Mon Oct 15 13:27:42 2001
@@ -401,7 +401,7 @@
 		put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].start_sect, &geo->start);
 		return 0;
 	case BLKGETSIZE:
-		put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, (long*)arg);
+		put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, (unsigned long *)arg);
 		return 0;
 	case BLKGETSIZE64:
 		put_user((u64)hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects << 9, (u64*)arg);
diff -u --recursive --new-file v2.4.12/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- v2.4.12/linux/drivers/block/cpqarray.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/cpqarray.c	Mon Oct 15 13:27:42 2001
@@ -1217,7 +1217,7 @@
 	case IDAGETDRVINFO:
 		return copy_to_user(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));
 	case BLKGETSIZE:
-		return put_user(ida[(ctlr<<CTLR_SHIFT)+MINOR(inode->i_rdev)].nr_sects, (long*)arg);
+		return put_user(ida[(ctlr<<CTLR_SHIFT)+MINOR(inode->i_rdev)].nr_sects, (unsigned long *)arg);
 	case BLKGETSIZE64:
 		return put_user((u64)(ida[(ctlr<<CTLR_SHIFT)+MINOR(inode->i_rdev)].nr_sects) << 9, (u64*)arg);
 	case BLKRRPART:
diff -u --recursive --new-file v2.4.12/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.4.12/linux/drivers/block/floppy.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/floppy.c	Mon Oct 15 13:27:41 2001
@@ -3496,7 +3496,7 @@
 
 		case BLKGETSIZE:
 			ECALL(get_floppy_geometry(drive, type, &g));
-			return put_user(g->size, (long *) param);
+			return put_user(g->size, (unsigned long *) param);
 
 		case BLKGETSIZE64:
 			ECALL(get_floppy_geometry(drive, type, &g));
diff -u --recursive --new-file v2.4.12/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.4.12/linux/drivers/block/genhd.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/block/genhd.c	Wed Oct 17 14:46:29 2001
@@ -161,9 +161,6 @@
 
 
 extern int blk_dev_init(void);
-#ifdef CONFIG_BLK_DEV_DAC960
-extern void DAC960_Initialize(void);
-#endif
 #ifdef CONFIG_FUSION_BOOT
 extern int fusion_init(void);
 #endif
@@ -181,9 +178,6 @@
 	sti();
 #ifdef CONFIG_I2O
 	i2o_init();
-#endif
-#ifdef CONFIG_BLK_DEV_DAC960
-	DAC960_Initialize();
 #endif
 #ifdef CONFIG_FUSION_BOOT
 	fusion_init();
diff -u --recursive --new-file v2.4.12/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.4.12/linux/drivers/block/ll_rw_blk.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/ll_rw_blk.c	Sat Oct 13 10:30:30 2001
@@ -149,8 +149,8 @@
 		return 0;
 
 	do {
-		rq = list_entry(head->next, struct request, table);
-		list_del(&rq->table);
+		rq = list_entry(head->next, struct request, queue);
+		list_del(&rq->queue);
 		kmem_cache_free(request_cachep, rq);
 		i++;
 	} while (!list_empty(head));
@@ -349,7 +349,7 @@
 		}
 		memset(rq, 0, sizeof(struct request));
 		rq->rq_status = RQ_INACTIVE;
-		list_add(&rq->table, &q->request_freelist[i & 1]);
+		list_add(&rq->queue, &q->request_freelist[i & 1]);
 	}
 
 	init_waitqueue_head(&q->wait_for_request);
@@ -415,7 +415,7 @@
 	q->head_active    	= 1;
 }
 
-#define blkdev_free_rq(list) list_entry((list)->next, struct request, table);
+#define blkdev_free_rq(list) list_entry((list)->next, struct request, queue);
 /*
  * Get a free request. io_request_lock must be held and interrupts
  * disabled on the way in.
@@ -426,7 +426,7 @@
 
 	if (!list_empty(&q->request_freelist[rw])) {
 		rq = blkdev_free_rq(&q->request_freelist[rw]);
-		list_del(&rq->table);
+		list_del(&rq->queue);
 		rq->rq_status = RQ_ACTIVE;
 		rq->special = NULL;
 		rq->q = q;
@@ -570,7 +570,7 @@
 		/*
 		 * Add to pending free list and batch wakeups
 		 */
-		list_add(&req->table, &q->pending_freelist[rw]);
+		list_add(&req->queue, &q->pending_freelist[rw]);
 
 		if (++q->pending_free[rw] >= batch_requests) {
 			int wake_up = q->pending_free[rw];
diff -u --recursive --new-file v2.4.12/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.4.12/linux/drivers/block/loop.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/block/loop.c	Mon Oct 15 18:53:51 2001
@@ -151,7 +151,7 @@
 
 #define MAX_DISK_SIZE 1024*1024*1024
 
-static int compute_loop_size(struct loop_device *lo, struct dentry * lo_dentry, kdev_t lodev)
+static unsigned long compute_loop_size(struct loop_device *lo, struct dentry * lo_dentry, kdev_t lodev)
 {
 	if (S_ISREG(lo_dentry->d_inode->i_mode))
 		return (lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS;
@@ -865,7 +865,7 @@
 			err = -ENXIO;
 			break;
 		}
-		err = put_user(loop_sizes[lo->lo_number] << 1, (long *) arg);
+		err = put_user((unsigned long)loop_sizes[lo->lo_number] << 1, (unsigned long *) arg);
 		break;
 	case BLKGETSIZE64:
 		if (lo->lo_state != Lo_bound) {
diff -u --recursive --new-file v2.4.12/linux/drivers/block/nbd.c linux/drivers/block/nbd.c
--- v2.4.12/linux/drivers/block/nbd.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/nbd.c	Mon Oct 15 13:27:42 2001
@@ -445,7 +445,7 @@
 		return 0;
 #endif
 	case BLKGETSIZE:
-		return put_user(nbd_bytesizes[dev] >> 9, (long *) arg);
+		return put_user(nbd_bytesizes[dev] >> 9, (unsigned long *) arg);
 	case BLKGETSIZE64:
 		return put_user((u64)nbd_bytesizes[dev], (u64 *) arg);
 	}
@@ -542,4 +542,6 @@
 module_exit(nbd_cleanup);
 
 MODULE_DESCRIPTION("Network Block Device");
+MODULE_LICENSE("GPL");
+
 
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/aten.c linux/drivers/block/paride/aten.c
--- v2.4.12/linux/drivers/block/paride/aten.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/aten.c	Thu Oct 11 09:04:57 2001
@@ -171,3 +171,4 @@
 #endif
 
 /* end of aten.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/bpck.c linux/drivers/block/paride/bpck.c
--- v2.4.12/linux/drivers/block/paride/bpck.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/bpck.c	Thu Oct 11 09:04:57 2001
@@ -482,3 +482,4 @@
 #endif
 
 /* end of bpck.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/comm.c linux/drivers/block/paride/comm.c
--- v2.4.12/linux/drivers/block/paride/comm.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/comm.c	Thu Oct 11 09:04:57 2001
@@ -227,3 +227,4 @@
 #endif
 
 /* end of comm.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/dstr.c linux/drivers/block/paride/dstr.c
--- v2.4.12/linux/drivers/block/paride/dstr.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/dstr.c	Thu Oct 11 09:04:57 2001
@@ -242,3 +242,4 @@
 #endif
 
 /* end of dstr.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/epat.c linux/drivers/block/paride/epat.c
--- v2.4.12/linux/drivers/block/paride/epat.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/epat.c	Thu Oct 11 09:04:57 2001
@@ -320,3 +320,4 @@
 #endif
 
 /* end of epat.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/epia.c linux/drivers/block/paride/epia.c
--- v2.4.12/linux/drivers/block/paride/epia.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/epia.c	Thu Oct 11 09:04:57 2001
@@ -325,3 +325,4 @@
 
 /* end of epia.c */
 
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/fit2.c linux/drivers/block/paride/fit2.c
--- v2.4.12/linux/drivers/block/paride/fit2.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/fit2.c	Thu Oct 11 09:04:57 2001
@@ -160,3 +160,4 @@
 #endif
 
 /* end of fit2.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/fit3.c linux/drivers/block/paride/fit3.c
--- v2.4.12/linux/drivers/block/paride/fit3.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/fit3.c	Thu Oct 11 09:04:57 2001
@@ -220,3 +220,4 @@
 #endif
 
 /* end of fit3.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/friq.c linux/drivers/block/paride/friq.c
--- v2.4.12/linux/drivers/block/paride/friq.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/friq.c	Thu Oct 11 09:04:57 2001
@@ -281,3 +281,4 @@
 #endif
 
 /* end of friq.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/frpw.c linux/drivers/block/paride/frpw.c
--- v2.4.12/linux/drivers/block/paride/frpw.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/frpw.c	Thu Oct 11 09:04:57 2001
@@ -322,3 +322,4 @@
 #endif
 
 /* end of frpw.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/kbic.c linux/drivers/block/paride/kbic.c
--- v2.4.12/linux/drivers/block/paride/kbic.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/kbic.c	Thu Oct 11 09:04:57 2001
@@ -310,3 +310,4 @@
 #endif
 
 /* end of kbic.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/ktti.c linux/drivers/block/paride/ktti.c
--- v2.4.12/linux/drivers/block/paride/ktti.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/ktti.c	Thu Oct 11 09:04:57 2001
@@ -137,3 +137,4 @@
 #endif
 
 /* end of ktti.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/on20.c linux/drivers/block/paride/on20.c
--- v2.4.12/linux/drivers/block/paride/on20.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/on20.c	Thu Oct 11 09:04:57 2001
@@ -162,3 +162,4 @@
 #endif
 
 /* end of on20.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/on26.c linux/drivers/block/paride/on26.c
--- v2.4.12/linux/drivers/block/paride/on26.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/on26.c	Thu Oct 11 09:04:57 2001
@@ -328,3 +328,4 @@
 
 /* end of on26.c */
 
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/paride.c linux/drivers/block/paride/paride.c
--- v2.4.12/linux/drivers/block/paride/paride.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/block/paride/paride.c	Thu Oct 11 09:04:57 2001
@@ -547,3 +547,4 @@
 #endif
 
 /* end of paride.c */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/pcd.c linux/drivers/block/paride/pcd.c
--- v2.4.12/linux/drivers/block/paride/pcd.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/pcd.c	Thu Oct 11 09:04:57 2001
@@ -948,3 +948,4 @@
 
 /* end of pcd.c */
 
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c
--- v2.4.12/linux/drivers/block/paride/pd.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/paride/pd.c	Mon Oct 15 13:27:41 2001
@@ -478,9 +478,9 @@
                 return 0;
             case BLKGETSIZE:
                 if (!arg) return -EINVAL;
-                err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
+                err = verify_area(VERIFY_WRITE,(unsigned long *) arg,sizeof(unsigned long));
                 if (err) return (err);
-                put_user(pd_hd[dev].nr_sects,(long *) arg);
+                put_user(pd_hd[dev].nr_sects,(unsigned long *) arg);
                 return (0);
             case BLKGETSIZE64:
                 return put_user((u64)pd_hd[dev].nr_sects << 9, (u64 *)arg);
@@ -586,8 +586,7 @@
 }
 
 void    cleanup_module(void)
-
-{       struct gendisk **gdp;
+{
 	int unit;
 
         devfs_unregister_blkdev(MAJOR_NR,name);
@@ -1069,3 +1068,4 @@
 
 /* end of pd.c */
 
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/pf.c linux/drivers/block/paride/pf.c
--- v2.4.12/linux/drivers/block/paride/pf.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/paride/pf.c	Thu Oct 11 09:04:57 2001
@@ -1111,3 +1111,4 @@
 
 /* end of pf.c */
 
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/pg.c linux/drivers/block/paride/pg.c
--- v2.4.12/linux/drivers/block/paride/pg.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/block/paride/pg.c	Thu Oct 11 09:04:57 2001
@@ -694,3 +694,4 @@
 
 /* end of pg.c */
 
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/ppc6lnx.c linux/drivers/block/paride/ppc6lnx.c
--- v2.4.12/linux/drivers/block/paride/ppc6lnx.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/paride/ppc6lnx.c	Thu Oct 11 09:04:57 2001
@@ -724,3 +724,4 @@
 
 //***************************************************************************
 
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/paride/pt.c linux/drivers/block/paride/pt.c
--- v2.4.12/linux/drivers/block/paride/pt.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/block/paride/pt.c	Thu Oct 11 09:04:57 2001
@@ -964,3 +964,4 @@
 
 /* end of pt.c */
 
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.4.12/linux/drivers/block/ps2esdi.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/ps2esdi.c	Mon Oct 15 13:27:42 2001
@@ -1107,9 +1107,9 @@
 
 		case BLKGETSIZE:
 			if (arg) {
-				if ((err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long))))
+				if ((err = verify_area(VERIFY_WRITE, (unsigned long *) arg, sizeof(unsigned long))))
 					 return (err);
-				put_user(ps2esdi[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
+				put_user(ps2esdi[MINOR(inode->i_rdev)].nr_sects, (unsigned long *) arg);
 
 				return (0);
 			}
diff -u --recursive --new-file v2.4.12/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.4.12/linux/drivers/block/rd.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/block/rd.c	Mon Oct 15 13:27:41 2001
@@ -384,7 +384,7 @@
          	case BLKGETSIZE:   /* Return device size */
 			if (!arg)
 				break;
-			error = put_user(rd_kbsize[minor] << 1, (long *) arg);
+			error = put_user(rd_kbsize[minor] << 1, (unsigned long *) arg);
 			break;
          	case BLKGETSIZE64:
 			error = put_user((u64)rd_kbsize[minor]<<10, (u64*)arg);
diff -u --recursive --new-file v2.4.12/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.4.12/linux/drivers/block/xd.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/block/xd.c	Mon Oct 15 13:27:41 2001
@@ -336,7 +336,7 @@
 		}
 		case BLKGETSIZE:
 			if (!arg) return -EINVAL;
-			return put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
+			return put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(unsigned long *) arg);
 		case BLKGETSIZE64:
 			return put_user((u64)xd_struct[MINOR(inode->i_rdev)].nr_sects << 9, (u64 *)arg);
 		case HDIO_SET_DMA:
diff -u --recursive --new-file v2.4.12/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.4.12/linux/drivers/cdrom/cdrom.c	Mon Aug 27 12:41:40 2001
+++ linux/drivers/cdrom/cdrom.c	Sun Oct 14 08:53:25 2001
@@ -2659,3 +2659,4 @@
 
 module_init(cdrom_init);
 module_exit(cdrom_exit);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.4.12/linux/drivers/char/Config.in	Tue Oct  9 17:06:51 2001
+++ linux/drivers/char/Config.in	Mon Oct 15 13:31:51 2001
@@ -155,6 +155,7 @@
    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 
@@ -191,7 +192,7 @@
 tristate 'Double Talk PC internal speech card support' CONFIG_DTLK
 tristate 'Siemens R3964 line discipline' CONFIG_R3964
 tristate 'Applicom intelligent fieldbus card support' CONFIG_APPLICOM
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X86" = "y" ]; then
    dep_tristate 'Sony Vaio Programmable I/O Control Device support' CONFIG_SONYPI $CONFIG_PCI
 fi
 
@@ -219,4 +220,7 @@
 if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
    source drivers/char/pcmcia/Config.in
 fi
+
+tristate 'ACP Modem (Mwave) support' CONFIG_MWAVE
+
 endmenu
diff -u --recursive --new-file v2.4.12/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.4.12/linux/drivers/char/Makefile	Tue Oct  9 17:06:51 2001
+++ linux/drivers/char/Makefile	Mon Oct 15 13:36:48 2001
@@ -220,6 +220,7 @@
 obj-$(CONFIG_PCWATCHDOG) += pcwd.o
 obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
 obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
+obj-$(CONFIG_IB700_WDT) += ib700wdt.o
 obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
 obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
 obj-$(CONFIG_WDT) += wdt.o
@@ -228,8 +229,13 @@
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
 obj-$(CONFIG_I810_TCO) += i810-tco.o
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
+obj-$(CONFIG_SH_WDT) += shwdt.o
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
 
+subdir-$(CONFIG_MWAVE) += mwave
+ifeq ($(CONFIG_MWAVE),y)
+  obj-y += mwave/mwave.o
+endif
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.4.12/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- v2.4.12/linux/drivers/char/adbmouse.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/char/adbmouse.c	Thu Oct 11 09:07:00 2001
@@ -206,4 +206,4 @@
 module_init(adb_mouse_init);
 module_exit(adb_mouse_cleanup);
 
-MODULE_LICENSE("GPL"):
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.4.12/linux/drivers/char/console.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/char/console.c	Mon Oct 15 14:00:43 2001
@@ -399,20 +399,28 @@
 	else {
 		u16 *q = p;
 		int cnt = count;
+		u16 a;
 
 		if (!can_do_color) {
-			while (cnt--) *q++ ^= 0x0800;
+			while (cnt--) {
+			    a = scr_readw(q);
+			    a ^= 0x0800;
+			    scr_writew(a, q);
+			    q++;
+			}
 		} else if (hi_font_mask == 0x100) {
 			while (cnt--) {
-				u16 a = *q;
+				a = scr_readw(q);
 				a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
-				*q++ = a;
+				scr_writew(a, q);
+				q++;
 			}
 		} else {
 			while (cnt--) {
-				u16 a = *q;
+				a = scr_readw(q);
 				a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
-				*q++ = a;
+				scr_writew(a, q);
+				q++;
 			}
 		}
 	}
diff -u --recursive --new-file v2.4.12/linux/drivers/char/drm/drm_drv.h linux/drivers/char/drm/drm_drv.h
--- v2.4.12/linux/drivers/char/drm/drm_drv.h	Sun Sep 23 11:40:57 2001
+++ linux/drivers/char/drm/drm_drv.h	Sun Oct 21 10:40:36 2001
@@ -1047,6 +1047,25 @@
 
 	atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] );
 
+#if __HAVE_KERNEL_CTX_SWITCH
+	/* We no longer really hold it, but if we are the next
+	 * agent to request it then we should just be able to
+	 * take it immediately and not eat the ioctl.
+	 */
+	dev->lock.pid = 0;
+	{
+		__volatile__ unsigned int *plock = &dev->lock.hw_lock->lock;
+		unsigned int old, new, prev, ctx;
+
+		ctx = lock.context;
+		do {
+			old  = *plock;
+			new  = ctx;
+			prev = cmpxchg(plock, old, new);
+		} while (prev != old);
+	}
+	wake_up_interruptible(&dev->lock.lock_queue);
+#else
 	DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock,
 			    DRM_KERNEL_CONTEXT );
 #if __HAVE_DMA_SCHEDULE
@@ -1061,6 +1080,7 @@
 			DRM_ERROR( "\n" );
 		}
 	}
+#endif /* !__HAVE_KERNEL_CTX_SWITCH */
 
 	unblock_all_signals();
 	return 0;
diff -u --recursive --new-file v2.4.12/linux/drivers/char/drm/drm_proc.h linux/drivers/char/drm/drm_proc.h
--- v2.4.12/linux/drivers/char/drm/drm_proc.h	Thu Oct 18 13:48:13 2001
+++ linux/drivers/char/drm/drm_proc.h	Thu Oct 18 17:44:48 2001
@@ -186,7 +186,7 @@
 	DRM_PROC_PRINT("slot	 offset	      size type flags	 "
 		       "address mtrr\n\n");
 	i = 0;
-	list_for_each(list, &dev->maplist->head) {
+	if (dev->maplist != NULL) list_for_each(list, &dev->maplist->head) {
 		r_list = (drm_map_list_t *)list;
 		map = r_list->map;
 		if(!map) continue;
diff -u --recursive --new-file v2.4.12/linux/drivers/char/drm/drm_vm.h linux/drivers/char/drm/drm_vm.h
--- v2.4.12/linux/drivers/char/drm/drm_vm.h	Thu Oct 18 13:48:13 2001
+++ linux/drivers/char/drm/drm_vm.h	Sun Oct 21 10:40:36 2001
@@ -175,7 +175,7 @@
 	page = pte_page(*pte);
 	get_page(page);
 
-	DRM_DEBUG("0x%08lx => 0x%08x\n", address, page_to_bus(page));
+	DRM_DEBUG("shm_nopage 0x%lx\n", address);
 #if LINUX_VERSION_CODE < 0x020317
 	return page_address(page);
 #else
@@ -299,8 +299,7 @@
 
 	get_page(page);
 
-	DRM_DEBUG("0x%08lx (page %lu) => 0x%08x\n", address, page_nr, 
-		  page_to_bus(page));
+	DRM_DEBUG("dma_nopage 0x%lx (page %lu)\n", address, page_nr); 
 #if LINUX_VERSION_CODE < 0x020317
 	return page_address(page);
 #else
@@ -532,10 +531,17 @@
 			vma->vm_flags |= VM_IO;	/* not in core dump */
 		}
 		offset = DRIVER_GET_REG_OFS();
+#ifdef __sparc__
+		if (io_remap_page_range(vma->vm_start,
+					VM_OFFSET(vma) + offset,
+					vma->vm_end - vma->vm_start,
+					vma->vm_page_prot, 0))
+#else
 		if (remap_page_range(vma->vm_start,
 				     VM_OFFSET(vma) + offset,
 				     vma->vm_end - vma->vm_start,
 				     vma->vm_page_prot))
+#endif
 				return -EAGAIN;
 		DRM_DEBUG("   Type = %d; start = 0x%lx, end = 0x%lx,"
 			  " offset = 0x%lx\n",
diff -u --recursive --new-file v2.4.12/linux/drivers/char/drm/ffb_drv.c linux/drivers/char/drm/ffb_drv.c
--- v2.4.12/linux/drivers/char/drm/ffb_drv.c	Mon Aug 27 12:41:40 2001
+++ linux/drivers/char/drm/ffb_drv.c	Sun Oct 21 10:40:36 2001
@@ -1,4 +1,4 @@
-/* $Id: ffb_drv.c,v 1.15 2001/08/09 17:47:51 davem Exp $
+/* $Id: ffb_drv.c,v 1.16 2001/10/18 16:00:24 davem Exp $
  * ffb_drv.c: Creator/Creator3D direct rendering driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -45,16 +45,16 @@
 #define DRIVER_PRESETUP()	do {		\
 	int _ret;				\
 	_ret = ffb_presetup(dev);		\
-	if(_ret != 0) return _ret;		\
+	if (_ret != 0) return _ret;		\
 } while(0)
 
 /* Free private structure */
 #define DRIVER_PRETAKEDOWN()	do {				\
-	if(dev->dev_private) kfree(dev->dev_private);		\
+	if (dev->dev_private) kfree(dev->dev_private);		\
 } while(0)
 
 #define DRIVER_POSTCLEANUP()	do {				\
-	if(ffb_position != NULL) kfree(ffb_position);		\
+	if (ffb_position != NULL) kfree(ffb_position);		\
 } while(0)
 
 /* We have to free up the rogue hw context state holding error or 
@@ -66,7 +66,9 @@
 	int idx;							\
 									\
 	idx = context - 1;						\
-	if (fpriv && fpriv->hw_state[idx] != NULL) {			\
+	if (fpriv &&							\
+	    context != DRM_KERNEL_CONTEXT &&				\
+	    fpriv->hw_state[idx] != NULL) {				\
 		kfree(fpriv->hw_state[idx]);				\
 		fpriv->hw_state[idx] = NULL;				\
 	}								\
diff -u --recursive --new-file v2.4.12/linux/drivers/char/epca.c linux/drivers/char/epca.c
--- v2.4.12/linux/drivers/char/epca.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/char/epca.c	Fri Oct 12 13:48:42 2001
@@ -1572,7 +1572,8 @@
 	cli();
 
 	if ((tty_unregister_driver(&pc_driver)) ||  
-	    (tty_unregister_driver(&pc_callout)))
+	    (tty_unregister_driver(&pc_callout)) ||
+	    (tty_unregister_driver(&pc_info)))
 	{
 		printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n");
 		restore_flags(flags);
diff -u --recursive --new-file v2.4.12/linux/drivers/char/i810_rng.c linux/drivers/char/i810_rng.c
--- v2.4.12/linux/drivers/char/i810_rng.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/char/i810_rng.c	Thu Oct 11 09:14:32 2001
@@ -342,6 +342,7 @@
 
 MODULE_AUTHOR("Jeff Garzik, Philipp Rumpf, Matt Sottek");
 MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver");
+MODULE_LICENSE("GPL");
 
 
 /*
diff -u --recursive --new-file v2.4.12/linux/drivers/char/ib700wdt.c linux/drivers/char/ib700wdt.c
--- v2.4.12/linux/drivers/char/ib700wdt.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/ib700wdt.c	Thu Oct 11 09:07:00 2001
@@ -0,0 +1,272 @@
+/*
+ *	IB700 Single Board Computer WDT driver for Linux 2.4.x
+ *
+ *	(c) Copyright 2001 Charles Howes <chowes@vsol.net>
+ *
+ *      Based on advantechwdt.c which is based on acquirewdt.c which
+ *       is based on wdt.c.
+ *
+ *	(c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ *	Based on acquirewdt.c which is based on wdt.c.
+ *	Original copyright messages:
+ *
+ *	(c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *				http://www.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.
+ *
+ *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ *	warranty for any of this software. This material is provided
+ *	"AS-IS" and at no charge.
+ *
+ *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+
+static int ibwdt_is_open;
+static spinlock_t ibwdt_lock;
+
+/*
+ *
+ * Watchdog Timer Configuration
+ *
+ * The function of the watchdog timer is to reset the system
+ * automatically and is defined at I/O port 0443H.  To enable the
+ * watchdog timer and allow the system to reset, write I/O port 0443H.
+ * To disable the timer, write I/O port 0441H for the system to stop the
+ * watchdog function.  The timer has a tolerance of 20% for its
+ * intervals.
+ *
+ * The following describes how the timer should be programmed.
+ *
+ * Enabling Watchdog:
+ * MOV AX,000FH (Choose the values from 0 to F)
+ * MOV DX,0443H
+ * OUT DX,AX
+ *
+ * Disabling Watchdog:
+ * MOV AX,000FH (Any value is fine.)
+ * MOV DX,0441H
+ * OUT DX,AX
+ *
+ * Watchdog timer control table:
+ * Level   Value  Time/sec | Level Value Time/sec
+ *   1       F       0     |   9     7      16
+ *   2       E       2     |   10    6      18
+ *   3       D       4     |   11    5      20
+ *   4       C       6     |   12    4      22
+ *   5       B       8     |   13    3      24
+ *   6       A       10    |   14    2      26
+ *   7       9       12    |   15    1      28
+ *   8       8       14    |   16    0      30
+ *
+ */
+
+#define WDT_STOP 0x441
+#define WDT_START 0x443
+
+#define WD_TIMO 0		/* 30 seconds +/- 20%, from table */
+
+/*
+ *	Kernel methods.
+ */
+
+static void
+ibwdt_ping(void)
+{
+	/* Write a watchdog value */
+	outb_p(WD_TIMO, WDT_START);
+}
+
+static ssize_t
+ibwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (count) {
+		ibwdt_ping();
+		return 1;
+	}
+	return 0;
+}
+
+static ssize_t
+ibwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+static int
+ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	  unsigned long arg)
+{
+	static struct watchdog_info ident = {
+		WDIOF_KEEPALIVEPING, 1, "IB700 WDT"
+	};
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+	  if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
+	    return -EFAULT;
+	  break;
+
+	case WDIOC_GETSTATUS:
+	  if (copy_to_user((int *)arg, &ibwdt_is_open,  sizeof(int)))
+	    return -EFAULT;
+	  break;
+
+	case WDIOC_KEEPALIVE:
+	  ibwdt_ping();
+	  break;
+
+	default:
+	  return -ENOTTY;
+	}
+	return 0;
+}
+
+static int
+ibwdt_open(struct inode *inode, struct file *file)
+{
+	switch (MINOR(inode->i_rdev)) {
+		case WATCHDOG_MINOR:
+			spin_lock(&ibwdt_lock);
+			if (ibwdt_is_open) {
+				spin_unlock(&ibwdt_lock);
+				return -EBUSY;
+			}
+			/*
+			 *	Activate
+			 */
+
+			ibwdt_is_open = 1;
+			ibwdt_ping();
+			spin_unlock(&ibwdt_lock);
+			return 0;
+		default:
+			return -ENODEV;
+	}
+}
+
+static int
+ibwdt_close(struct inode *inode, struct file *file)
+{
+	lock_kernel();
+	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+		spin_lock(&ibwdt_lock);
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+		outb_p(WD_TIMO, WDT_STOP);
+#endif
+		ibwdt_is_open = 0;
+		spin_unlock(&ibwdt_lock);
+	}
+	unlock_kernel();
+	return 0;
+}
+
+/*
+ *	Notifier for system down
+ */
+
+static int
+ibwdt_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT) {
+		/* Turn the WDT off */
+		outb_p(WD_TIMO, WDT_STOP);
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations ibwdt_fops = {
+	owner:		THIS_MODULE,
+	read:		ibwdt_read,
+	write:		ibwdt_write,
+	ioctl:		ibwdt_ioctl,
+	open:		ibwdt_open,
+	release:	ibwdt_close,
+};
+
+static struct miscdevice ibwdt_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&ibwdt_fops
+};
+
+/*
+ *	The WDT needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off.
+ */
+
+static struct notifier_block ibwdt_notifier = {
+	ibwdt_notify_sys,
+	NULL,
+	0
+};
+
+static int __init
+ibwdt_init(void)
+{
+	printk("WDT driver for IB700 single board computer initialising.\n");
+
+	spin_lock_init(&ibwdt_lock);
+	misc_register(&ibwdt_miscdev);
+#if WDT_START != WDT_STOP
+	request_region(WDT_STOP, 1, "IB700 WDT");
+#endif
+	request_region(WDT_START, 1, "IB700 WDT");
+	register_reboot_notifier(&ibwdt_notifier);
+	return 0;
+}
+
+static void __exit
+ibwdt_exit(void)
+{
+	misc_deregister(&ibwdt_miscdev);
+	unregister_reboot_notifier(&ibwdt_notifier);
+#if WDT_START != WDT_STOP
+	release_region(WDT_STOP,1);
+#endif
+	release_region(WDT_START,1);
+}
+
+module_init(ibwdt_init);
+module_exit(ibwdt_exit);
+
+MODULE_AUTHOR("Charles Howes <chowes@vsol.net>");
+MODULE_DESCRIPTION("IB700 SBC watchdog driver");
+MODULE_LICENSE("GPL");
+
+/* end of ib700wdt.c */
diff -u --recursive --new-file v2.4.12/linux/drivers/char/ip2main.c linux/drivers/char/ip2main.c
--- v2.4.12/linux/drivers/char/ip2main.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/char/ip2main.c	Thu Oct 11 09:14:32 2001
@@ -3458,3 +3458,4 @@
 }
 
 
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v2.4.12/linux/drivers/char/istallion.c	Wed Jul 25 17:10:19 2001
+++ linux/drivers/char/istallion.c	Thu Oct 11 09:14:32 2001
@@ -386,6 +386,8 @@
  */
 MODULE_AUTHOR("Greg Ungerer");
 MODULE_DESCRIPTION("Stallion Intelligent Multiport Serial Driver");
+MODULE_LICENSE("GPL");
+
 
 MODULE_PARM(board0, "1-3s");
 MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,memaddr]");
diff -u --recursive --new-file v2.4.12/linux/drivers/char/joystick/analog.c linux/drivers/char/joystick/analog.c
--- v2.4.12/linux/drivers/char/joystick/analog.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/char/joystick/analog.c	Thu Oct 18 09:08:16 2001
@@ -138,7 +138,7 @@
 
 #ifdef __i386__
 #define TSC_PRESENT	(test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability))
-#define GET_TIME(x)	do { if (TSC_PRESENT) rdtscl(x); else outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
+#define GET_TIME(x)	do { if (TSC_PRESENT) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0)
 #define DELTA(x,y)	(TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
 #define TIME_NAME	(TSC_PRESENT?"TSC":"PIT")
 #elif __x86_64__
@@ -499,7 +499,9 @@
 	else
 		printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME,
 		port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
-		port->speed > 10000 ? "M" : "k", (port->loop * 1000000) / port->speed);
+		port->speed > 10000 ? "M" : "k",
+		port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000)
+				    : (port->loop * 1000000) / port->speed);
 }
 
 /*
diff -u --recursive --new-file v2.4.12/linux/drivers/char/mwave/mwavedd.c linux/drivers/char/mwave/mwavedd.c
--- v2.4.12/linux/drivers/char/mwave/mwavedd.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/char/mwave/mwavedd.c	Thu Oct 11 09:14:32 2001
@@ -71,6 +71,10 @@
 #define __exit
 #endif
 
+MODULE_DESCRIPTION("3780i Advanced Communications Processor (Mwave) driver");
+MODULE_AUTHOR("Mike Sullivan and Paul Schroeder");
+MODULE_LICENSE("GPL");
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 static int mwave_get_info(char *buf, char **start, off_t offset, int len);
 #else
diff -u --recursive --new-file v2.4.12/linux/drivers/char/nwflash.c linux/drivers/char/nwflash.c
--- v2.4.12/linux/drivers/char/nwflash.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/char/nwflash.c	Fri Oct 12 13:48:42 2001
@@ -59,6 +59,7 @@
 static int gbWriteBase64Enable;
 static volatile unsigned char *FLASH_BASE;
 static int gbFlashSize = KFLASH_SIZE;
+static DECLARE_MUTEX(nwflash_sem);
 
 extern spinlock_t gpio_lock;
 
@@ -132,7 +133,6 @@
 
 static ssize_t flash_read(struct file *file, char *buf, size_t size, loff_t * ppos)
 {
-	struct inode *inode = file->f_dentry->d_inode;
 	unsigned long p = *ppos;
 	unsigned int count = size;
 	int ret = 0;
@@ -151,7 +151,7 @@
 		/*
 		 * We now lock against reads and writes. --rmk
 		 */
-		if (down_interruptible(&inode->i_sem))
+		if (down_interruptible(&nwflash_sem))
 			return -ERESTARTSYS;
 
 		ret = copy_to_user(buf, (void *)(FLASH_BASE + p), count);
@@ -159,14 +159,13 @@
 			ret = count;
 			*ppos += count;
 		}
-		up(&inode->i_sem);
+		up(&nwflash_sem);
 	}
 	return ret;
 }
 
 static ssize_t flash_write(struct file *file, const char *buf, size_t size, loff_t * ppos)
 {
-	struct inode *inode = file->f_dentry->d_inode;
 	unsigned long p = *ppos;
 	unsigned int count = size;
 	int written;
@@ -198,7 +197,7 @@
 	/*
 	 * We now lock against reads and writes. --rmk
 	 */
-	if (down_interruptible(&inode->i_sem))
+	if (down_interruptible(&nwflash_sem))
 		return -ERESTARTSYS;
 
 	written = 0;
@@ -286,7 +285,7 @@
 	 */
 	leds_event(led_release);
 
-	up(&inode->i_sem);
+	up(&nwflash_sem);
 
 	return written;
 }
diff -u --recursive --new-file v2.4.12/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.4.12/linux/drivers/char/random.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/char/random.c	Sun Oct 21 10:19:36 2001
@@ -164,25 +164,32 @@
  * sequence: 
  *
  *	echo "Initializing random number generator..."
- * 	random_seed=/var/run/random-seed
+ *	random_seed=/var/run/random-seed
  *	# Carry a random seed from start-up to start-up
- *	# Load and then save 512 bytes, which is the size of the entropy pool
- * 	if [ -f $random_seed ]; then
+ *	# Load and then save the whole entropy pool
+ *	if [ -f $random_seed ]; then
  *		cat $random_seed >/dev/urandom
- * 	fi
- *	dd if=/dev/urandom of=$random_seed count=1
- * 	chmod 600 $random_seed
+ *	else
+ *		touch $random_seed
+ *	fi
+ *	chmod 600 $random_seed
+ *	poolfile=/proc/sys/kernel/random/poolsize
+ *	[ -r $poolfile ] && bytes=`cat $poolfile` || bytes=512
+ *	dd if=/dev/urandom of=$random_seed count=1 bs=bytes
  *
  * and the following lines in an appropriate script which is run as
  * the system is shutdown:
- * 
+ *
  *	# Carry a random seed from shut-down to start-up
- *	# Save 512 bytes, which is the size of the entropy pool
+ *	# Save the whole entropy pool
  *	echo "Saving random seed..."
- * 	random_seed=/var/run/random-seed
- *	dd if=/dev/urandom of=$random_seed count=1
- * 	chmod 600 $random_seed
- * 
+ *	random_seed=/var/run/random-seed
+ *	touch $random_seed
+ *	chmod 600 $random_seed
+ *	poolfile=/proc/sys/kernel/random/poolsize
+ *	[ -r $poolfile ] && bytes=`cat $poolfile` || bytes=512
+ *	dd if=/dev/urandom of=$random_seed count=1 bs=bytes
+ *
  * For example, on most modern systems using the System V init
  * scripts, such code fragments would be found in
  * /etc/rc.d/init.d/random.  On older Linux systems, the correct script
@@ -272,8 +279,8 @@
 static int random_write_wakeup_thresh = 128;
 
 /*
- * A pool of size POOLWORDS is stirred with a primitive polynomial
- * of degree POOLWORDS over GF(2).  The taps for various sizes are
+ * A pool of size .poolwords is stirred with a primitive polynomial
+ * of degree .poolwords over GF(2).  The taps for various sizes are
  * defined below.  They are chosen to be evenly spaced (minimum RMS
  * distance from evenly spaced; the numbers in the comments are a
  * scaled squared error sum) except for the last tap, which is 1 to
@@ -284,19 +291,17 @@
 	int	tap1, tap2, tap3, tap4, tap5;
 } poolinfo_table[] = {
 	/* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1  -- 115 */
-	{ 2048,	1638,	1231,	819, 	411,	1 },
+	{ 2048,	1638,	1231,	819,	411,	1 },
 
 	/* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */
-	{ 1024,	817, 	615,	412,	204,	1 },
-
+	{ 1024,	817,	615,	412,	204,	1 },
 #if 0				/* Alternate polynomial */
 	/* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */
 	{ 1024,	819,	616,	410,	207,	2 },
 #endif
-	
+
 	/* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */
 	{ 512,	411,	308,	208,	104,	1 },
-
 #if 0				/* Alternates */
 	/* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */
 	{ 512,	409,	307,	206,	102,	2 },
@@ -306,10 +311,9 @@
 
 	/* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */
 	{ 256,	205,	155,	101,	52,	1 },
-	
+
 	/* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */
 	{ 128,	103,	76,	51,	25,	1 },
-
 #if 0	/* Alternate polynomial */
 	/* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */
 	{ 128,	103,	78,	51,	27,	2 },
@@ -321,9 +325,12 @@
 	/* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */
 	{ 32,	26,	20,	14,	7,	1 },
 
-	{ 0, 	0,	0,	0,	0,	0 },
-};		
-	
+	{ 0,	0,	0,	0,	0,	0 },
+};
+
+#define POOLBITS	poolwords*32
+#define POOLBYTES	poolwords*4
+
 /*
  * For the purposes of better mixing, we use the CRC-32 polynomial as
  * well to make a twisted Generalized Feedback Shift Reigster
@@ -461,6 +468,12 @@
 }
 #endif
 
+#if 0
+#define DEBUG_ENT(fmt, arg...) printk(KERN_DEBUG "random: " fmt, ## arg)
+#else
+#define DEBUG_ENT(fmt, arg...) do {} while (0)
+#endif
+
 /**********************************************************************
  *
  * OS independent entropy store.   Here are the functions which handle
@@ -480,7 +493,7 @@
 /*
  * Initialize the entropy store.  The input argument is the size of
  * the random pool.
- * 
+ *
  * Returns an negative error if there is a problem.
  */
 static int create_entropy_store(int size, struct entropy_store **ret_bucket)
@@ -507,12 +520,12 @@
 	memset (r, 0, sizeof(struct entropy_store));
 	r->poolinfo = *p;
 
-	r->pool = kmalloc(poolwords*4, GFP_KERNEL);
+	r->pool = kmalloc(POOLBYTES, GFP_KERNEL);
 	if (!r->pool) {
 		kfree(r);
 		return -ENOMEM;
 	}
-	memset(r->pool, 0, poolwords*4);
+	memset(r->pool, 0, POOLBYTES);
 	*ret_bucket = r;
 	return 0;
 }
@@ -524,7 +537,7 @@
 	r->entropy_count = 0;
 	r->input_rotate = 0;
 	r->extract_count = 0;
-	memset(r->pool, 0, r->poolinfo.poolwords*4);
+	memset(r->pool, 0, r->poolinfo.POOLBYTES);
 }
 
 static void free_entropy_store(struct entropy_store *r)
@@ -545,18 +558,19 @@
  * the entropy is concentrated in the low-order bits.
  */
 static void add_entropy_words(struct entropy_store *r, const __u32 *in,
-			     int num)
+			      int nwords)
 {
 	static __u32 const twist_table[8] = {
 		         0, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
 		0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
 	unsigned i;
 	int new_rotate;
+	int wordmask = r->poolinfo.poolwords - 1;
 	__u32 w;
 
-	while (num--) {
+	while (nwords--) {
 		w = rotate_left(r->input_rotate, *in);
-		i = r->add_ptr = (r->add_ptr - 1) & (r->poolinfo.poolwords-1);
+		i = r->add_ptr = (r->add_ptr - 1) & wordmask;
 		/*
 		 * Normally, we add 7 bits of rotation to the pool.
 		 * At the beginning of the pool, add an extra 7 bits
@@ -569,11 +583,11 @@
 		r->input_rotate = new_rotate & 31;
 
 		/* XOR in the various taps */
-		w ^= r->pool[(i+r->poolinfo.tap1)&(r->poolinfo.poolwords-1)];
-		w ^= r->pool[(i+r->poolinfo.tap2)&(r->poolinfo.poolwords-1)];
-		w ^= r->pool[(i+r->poolinfo.tap3)&(r->poolinfo.poolwords-1)];
-		w ^= r->pool[(i+r->poolinfo.tap4)&(r->poolinfo.poolwords-1)];
-		w ^= r->pool[(i+r->poolinfo.tap5)&(r->poolinfo.poolwords-1)];
+		w ^= r->pool[(i + r->poolinfo.tap1) & wordmask];
+		w ^= r->pool[(i + r->poolinfo.tap2) & wordmask];
+		w ^= r->pool[(i + r->poolinfo.tap3) & wordmask];
+		w ^= r->pool[(i + r->poolinfo.tap4) & wordmask];
+		w ^= r->pool[(i + r->poolinfo.tap5) & wordmask];
 		w ^= r->pool[i];
 		r->pool[i] = (w >> 3) ^ twist_table[w & 7];
 	}
@@ -582,16 +596,22 @@
 /*
  * Credit (or debit) the entropy store with n bits of entropy
  */
-static void credit_entropy_store(struct entropy_store *r, int num)
+static void credit_entropy_store(struct entropy_store *r, int nbits)
 {
-	int	max_entropy = r->poolinfo.poolwords*32;
-
-	if (r->entropy_count + num < 0)
+	if (r->entropy_count + nbits < 0) {
+		DEBUG_ENT("negative entropy/overflow (%d+%d)\n",
+			  r->entropy_count, nbits);
 		r->entropy_count = 0;
-	else if (r->entropy_count + num > max_entropy)
-		r->entropy_count = max_entropy;
-	else
-		r->entropy_count = r->entropy_count + num;
+	} else if (r->entropy_count + nbits > r->poolinfo.POOLBITS) {
+		r->entropy_count = r->poolinfo.POOLBITS;
+	} else {
+		r->entropy_count += nbits;
+		if (nbits)
+			DEBUG_ENT("%s added %d bits, now %d\n",
+				  r == sec_random_state ? "secondary" :
+				  r == random_state ? "primary" : "unknown",
+				  nbits, r->entropy_count);
+	}
 }
 
 /**********************************************************************
@@ -627,6 +647,12 @@
 	return 0;
 }
 
+/*
+ * Changes to the entropy data is put into a queue rather than being added to
+ * the entropy counts directly.  This is presumably to avoid doing heavy
+ * hashing calculations during an interrupt in add_timer_randomness().
+ * Instead, the entropy is only added to the pool once per timer tick.
+ */
 void batch_entropy_store(u32 a, u32 b, int num)
 {
 	int	new;
@@ -643,32 +669,35 @@
 		queue_task(&batch_tqueue, &tq_timer);
 		batch_head = new;
 	} else {
-#if 0
-		printk(KERN_NOTICE "random: batch entropy buffer full\n");
-#endif
+		DEBUG_ENT("batch entropy buffer full\n");
 	}
 }
 
+/*
+ * Flush out the accumulated entropy operations, adding entropy to the passed
+ * store (normally random_state).  If that store has enough entropy, alternate
+ * between randomizing the data of the primary and secondary stores.
+ */
 static void batch_entropy_process(void *private_)
 {
-	int	num = 0;
-	int	max_entropy;
 	struct entropy_store *r	= (struct entropy_store *) private_, *p;
-	
+	int max_entropy = r->poolinfo.POOLBITS;
+
 	if (!batch_max)
 		return;
 
-	max_entropy = r->poolinfo.poolwords*32;
+	p = r;
 	while (batch_head != batch_tail) {
+		if (r->entropy_count >= max_entropy) {
+			r = (r == sec_random_state) ?	random_state :
+							sec_random_state;
+			max_entropy = r->poolinfo.POOLBITS;
+		}
 		add_entropy_words(r, batch_entropy_pool + 2*batch_tail, 2);
-		p = r;
-		if (r->entropy_count > max_entropy && (num & 1))
-			r = sec_random_state;
 		credit_entropy_store(r, batch_entropy_credit[batch_tail]);
 		batch_tail = (batch_tail+1) & (batch_max-1);
-		num++;
 	}
-	if (r->entropy_count >= random_read_wakeup_thresh)
+	if (p->entropy_count >= random_read_wakeup_thresh)
 		wake_up_interruptible(&random_read_wait);
 }
 
@@ -1204,9 +1233,9 @@
 
 /*
  * This utility inline function is responsible for transfering entropy
- * from the primary pool to the secondary extraction pool.  We pull 
- * randomness under two conditions; one is if there isn't enough entropy 
- * in the secondary pool.  The other is after we have extract 1024 bytes,
+ * from the primary pool to the secondary extraction pool.  We pull
+ * randomness under two conditions; one is if there isn't enough entropy
+ * in the secondary pool.  The other is after we have extracted 1024 bytes,
  * at which point we do a "catastrophic reseeding".
  */
 static inline void xfer_secondary_pool(struct entropy_store *r,
@@ -1214,14 +1243,26 @@
 {
 	__u32	tmp[TMP_BUF_SIZE];
 
-	if (r->entropy_count < nbytes*8) {
-		extract_entropy(random_state, tmp, sizeof(tmp), 0);
-		add_entropy_words(r, tmp, TMP_BUF_SIZE);
-		credit_entropy_store(r, TMP_BUF_SIZE*8);
+	if (r->entropy_count < nbytes * 8 &&
+	    r->entropy_count < r->poolinfo.POOLBITS) {
+		int nwords = min(r->poolinfo.poolwords - r->entropy_count/32,
+				 sizeof(tmp) / 4);
+
+		DEBUG_ENT("xfer %d from primary to %s (have %d, need %d)\n",
+			  nwords * 32,
+			  r == sec_random_state ? "secondary" : "unknown",
+			  r->entropy_count, nbytes * 8);
+
+		extract_entropy(random_state, tmp, nwords, 0);
+		add_entropy_words(r, tmp, nwords);
+		credit_entropy_store(r, nwords * 32);
 	}
 	if (r->extract_count > 1024) {
+		DEBUG_ENT("reseeding %s with %d from primary\n",
+			  r == sec_random_state ? "secondary" : "unknown",
+			  sizeof(tmp) * 8);
 		extract_entropy(random_state, tmp, sizeof(tmp), 0);
-		add_entropy_words(r, tmp, TMP_BUF_SIZE);
+		add_entropy_words(r, tmp, sizeof(tmp) / 4);
 		r->extract_count = 0;
 	}
 }
@@ -1232,9 +1273,12 @@
  * bits of entropy are left in the pool, but it does not restrict the
  * number of bytes that are actually obtained.  If the EXTRACT_ENTROPY_USER
  * flag is given, then the buf pointer is assumed to be in user space.
- * If the EXTRACT_ENTROPY_SECONDARY flag is given, then this function will 
  *
- * Note: extract_entropy() assumes that POOLWORDS is a multiple of 16 words.
+ * If the EXTRACT_ENTROPY_SECONDARY flag is given, then we are actually
+ * extracting entropy from the secondary pool, and can refill from the
+ * primary pool if needed.
+ *
+ * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words.
  */
 static ssize_t extract_entropy(struct entropy_store *r, void * buf,
 			       size_t nbytes, int flags)
@@ -1244,14 +1288,19 @@
 	__u32 x;
 
 	add_timer_randomness(&extract_timer_state, nbytes);
-	
+
 	/* Redundant, but just in case... */
-	if (r->entropy_count > r->poolinfo.poolwords) 
-		r->entropy_count = r->poolinfo.poolwords;
+	if (r->entropy_count > r->poolinfo.POOLBITS)
+		r->entropy_count = r->poolinfo.POOLBITS;
 
 	if (flags & EXTRACT_ENTROPY_SECONDARY)
 		xfer_secondary_pool(r, nbytes);
 
+	DEBUG_ENT("%s has %d bits, want %d bits\n",
+		  r == sec_random_state ? "secondary" :
+		  r == random_state ? "primary" : "unknown",
+		  r->entropy_count, nbytes * 8);
+
 	if (r->entropy_count / 8 >= nbytes)
 		r->entropy_count -= nbytes*8;
 	else
@@ -1547,9 +1596,7 @@
 		c -= bytes;
 		p += bytes;
 
-		/* Convert bytes to words */
-		bytes = (bytes + 3) / sizeof(__u32);
-		add_entropy_words(random_state, buf, bytes);
+		add_entropy_words(random_state, buf, (bytes + 3) / 4);
 	}
 	if (p == buffer) {
 		return (ssize_t)ret;
@@ -1599,7 +1646,7 @@
 			return -EINVAL;
 		if (size > random_state->poolinfo.poolwords)
 			size = random_state->poolinfo.poolwords;
-		if (copy_to_user(p, random_state->pool, size*sizeof(__u32)))
+		if (copy_to_user(p, random_state->pool, size * 4))
 			return -EFAULT;
 		return 0;
 	case RNDADDENTROPY:
@@ -1716,11 +1763,11 @@
 {
 	int	ret;
 
-	sysctl_poolsize = random_state->poolinfo.poolwords * 4;
+	sysctl_poolsize = random_state->poolinfo.POOLBYTES;
 
 	ret = proc_dointvec(table, write, filp, buffer, lenp);
 	if (ret || !write ||
-	    (sysctl_poolsize == random_state->poolinfo.poolwords * 4))
+	    (sysctl_poolsize == random_state->poolinfo.POOLBYTES))
 		return ret;
 
 	return change_poolsize(sysctl_poolsize);
@@ -1732,7 +1779,7 @@
 {
 	int	len;
 	
-	sysctl_poolsize = random_state->poolinfo.poolwords * 4;
+	sysctl_poolsize = random_state->poolinfo.POOLBYTES;
 
 	/*
 	 * We only handle the write case, since the read case gets
@@ -1747,7 +1794,7 @@
 			return -EFAULT;
 	}
 
-	if (sysctl_poolsize != random_state->poolinfo.poolwords * 4)
+	if (sysctl_poolsize != random_state->poolinfo.POOLBYTES)
 		return change_poolsize(sysctl_poolsize);
 
 	return 0;
@@ -1846,8 +1893,7 @@
 {
 	min_read_thresh = 8;
 	min_write_thresh = 0;
-	max_read_thresh = max_write_thresh =
-		random_state->poolinfo.poolwords * 32;
+	max_read_thresh = max_write_thresh = random_state->poolinfo.POOLBITS;
 	random_table[1].data = &random_state->entropy_count;
 }
 #endif 	/* CONFIG_SYSCTL */
@@ -2239,4 +2285,5 @@
 EXPORT_SYMBOL(add_interrupt_randomness);
 EXPORT_SYMBOL(add_blkdev_randomness);
 EXPORT_SYMBOL(batch_entropy_store);
+EXPORT_SYMBOL(generate_random_uuid);
 
diff -u --recursive --new-file v2.4.12/linux/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c
--- v2.4.12/linux/drivers/char/sh-sci.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/char/sh-sci.c	Mon Oct 15 13:36:48 2001
@@ -1131,7 +1131,7 @@
 	}
 }
 
-static char banner[] __initdata[] =
+static char banner[] __initdata =
 	KERN_INFO "SuperH SCI(F) driver initialized\n";
 
 int __init sci_init(void)
diff -u --recursive --new-file v2.4.12/linux/drivers/char/shwdt.c linux/drivers/char/shwdt.c
--- v2.4.12/linux/drivers/char/shwdt.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/shwdt.c	Mon Oct 15 13:36:48 2001
@@ -0,0 +1,365 @@
+/*
+ * drivers/char/shwdt.c
+ *
+ * Watchdog driver for integrated watchdog in the SuperH 3/4 processors.
+ *
+ * Copyright (C) 2001 Paul Mundt <lethal@chaoticdreams.org>
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <linux/smp_lock.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#if defined(CONFIG_CPU_SH4)
+  #define WTCNT		0xffc00008
+  #define WTCSR		0xffc0000c
+#elif defined(CONFIG_CPU_SH3)
+  #define WTCNT		0xffffff84
+  #define WTCSR		0xffffff86
+#else
+  #error "Can't use SH 3/4 watchdog on non-SH 3/4 processor."
+#endif
+
+#define WTCNT_HIGH	0x5a00
+#define WTCSR_HIGH	0xa500
+
+#define WTCSR_TME	0x80
+#define WTCSR_WT	0x40
+#define WTCSR_RSTS	0x20
+#define WTCSR_WOVF	0x10
+#define WTCSR_IOVF	0x08
+#define WTCSR_CKS2	0x04
+#define WTCSR_CKS1	0x02
+#define WTCSR_CKS0	0x01
+
+#define WTCSR_CKS	0x07
+#define WTCSR_CKS_1	0x00
+#define WTCSR_CKS_4	0x01
+#define WTCSR_CKS_16	0x02
+#define WTCSR_CKS_32	0x03
+#define WTCSR_CKS_64	0x04
+#define WTCSR_CKS_256	0x05
+#define WTCSR_CKS_1024	0x06
+#define WTCSR_CKS_4096	0x07
+
+static int sh_is_open = 0;
+static struct watchdog_info sh_wdt_info;
+
+/**
+ *	sh_wdt_write_cnt - Write to Counter
+ *
+ *	@val: Value to write
+ *
+ *	Writes the given value @val to the lower byte of the timer counter.
+ *	The upper byte is set manually on each write.
+ */
+static void sh_wdt_write_cnt(__u8 val)
+{
+	ctrl_outw(WTCNT_HIGH | (__u16)val, WTCNT);
+}
+
+/**
+ * 	sh_wdt_write_csr - Write to Control/Status Register
+ *
+ * 	@val: Value to write
+ *
+ * 	Writes the given value @val to the lower byte of the control/status
+ * 	register. The upper byte is set manually on each write.
+ */
+static void sh_wdt_write_csr(__u8 val)
+{
+	ctrl_outw(WTCSR_HIGH | (__u16)val, WTCSR);
+}
+
+/**
+ * 	sh_wdt_start - Start the Watchdog
+ *
+ * 	Starts the watchdog.
+ */
+static void sh_wdt_start(void)
+{
+	sh_wdt_write_csr(WTCSR_WT | WTCSR_CKS_4096);
+	sh_wdt_write_cnt(0);
+	sh_wdt_write_csr((ctrl_inb(WTCSR) | WTCSR_TME));
+}
+
+/**
+ * 	sh_wdt_stop - Stop the Watchdog
+ *
+ * 	Stops the watchdog.
+ */
+static void sh_wdt_stop(void)
+{
+	sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_TME));
+}
+
+/**
+ * 	sh_wdt_ping - Ping the Watchdog
+ *
+ *	@data: Unused
+ *
+ * 	Clears overflow bit, resets timer counter.
+ */
+static void sh_wdt_ping(unsigned long data)
+{
+	sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_IOVF));
+	sh_wdt_write_cnt(0);
+}
+
+/**
+ * 	sh_wdt_open - Open the Device
+ *
+ * 	@inode: inode of device
+ * 	@file: file handle of device
+ *
+ * 	Watchdog device is opened and started.
+ */
+static int sh_wdt_open(struct inode *inode, struct file *file)
+{
+	switch (MINOR(inode->i_rdev)) {
+		case WATCHDOG_MINOR:
+			if (sh_is_open) {
+				return -EBUSY;
+			}
+
+			sh_is_open = 1;
+			sh_wdt_start();
+
+			return 0;
+		default:
+			return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ * 	sh_wdt_close - Close the Device
+ *
+ * 	@inode: inode of device
+ * 	@file: file handle of device
+ *
+ * 	Watchdog device is closed and stopped.
+ */
+static int sh_wdt_close(struct inode *inode, struct file *file)
+{
+	lock_kernel();
+	
+	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+		sh_wdt_stop();
+#endif
+		sh_is_open = 0;
+	}
+	
+	unlock_kernel();
+
+	return 0;
+}
+
+/**
+ * 	sh_wdt_read - Read from Device
+ *
+ * 	@file: file handle of device
+ * 	@char: buffer to write to
+ * 	@count: length of buffer
+ * 	@ppos: offset
+ *
+ * 	Unsupported.
+ */
+static ssize_t sh_wdt_read(struct file *file, char *buf,
+			   size_t count, loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+/**
+ * 	sh_wdt_write - Write to Device
+ *
+ * 	@file: file handle of device
+ * 	@char: buffer to write
+ * 	@count: length of buffer
+ * 	@ppos: offset
+ *
+ * 	Pings the watchdog on write.
+ */
+static ssize_t sh_wdt_write(struct file *file, const char *buf,
+			    size_t count, loff_t *ppos)
+{
+	/* Can't seek (pwrite) on this device */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (count) {
+		sh_wdt_ping(0);
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * 	sh_wdt_ioctl - Query Device
+ *
+ * 	@inode: inode of device
+ * 	@file: file handle of device
+ * 	@cmd: watchdog command
+ * 	@arg: argument
+ *
+ * 	Query basic information from the device or ping it, as outlined by the
+ * 	watchdog API.
+ */
+static int sh_wdt_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+		case WDIOC_GETSUPPORT:
+			if (copy_to_user((struct watchdog_info *)arg,
+					  &sh_wdt_info,
+					  sizeof(sh_wdt_info))) {
+				return -EFAULT;
+			}
+			
+			break;
+		case WDIOC_GETSTATUS:
+			if (copy_to_user((int *)arg,
+					 &sh_is_open,
+					 sizeof(int))) {
+				return -EFAULT;
+			}
+
+			break;
+		case WDIOC_KEEPALIVE:
+			sh_wdt_ping(0);
+			
+			break;
+		default:
+			return -ENOTTY;
+	}
+
+	return 0;
+}
+
+/**
+ * 	sh_wdt_notify_sys - Notifier Handler
+ * 	
+ * 	@this: notifier block
+ * 	@code: notifier event
+ * 	@unused: unused
+ *
+ * 	Handles specific events, such as turning off the watchdog during a
+ * 	shutdown event.
+ */
+static int sh_wdt_notify_sys(struct notifier_block *this,
+			     unsigned long code, void *unused)
+{
+	if (code == SYS_DOWN || SYS_HALT) {
+		sh_wdt_stop();
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct file_operations sh_wdt_fops = {
+	owner:		THIS_MODULE,
+	read:		sh_wdt_read,
+	write:		sh_wdt_write,
+	ioctl:		sh_wdt_ioctl,
+	open:		sh_wdt_open,
+	release:	sh_wdt_close,
+};
+
+static struct watchdog_info sh_wdt_info = {
+	WDIOF_KEEPALIVEPING,
+	1,
+	"SH WDT",
+};
+
+static struct notifier_block sh_wdt_notifier = {
+	sh_wdt_notify_sys,
+	NULL,
+	0
+};
+
+static struct miscdevice sh_wdt_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&sh_wdt_fops,
+};
+
+/**
+ * 	sh_wdt_init - Initialize module
+ *
+ * 	Registers the device and notifier handler. Actual device
+ * 	initialization is handled by sh_wdt_open().
+ */
+static int __init sh_wdt_init(void)
+{
+	if (misc_register(&sh_wdt_miscdev)) {
+		printk(KERN_ERR "shwdt: Can't register misc device\n");
+		return -EINVAL;
+	}
+
+	if (!request_region(WTCNT, 1, "shwdt")) {
+		printk(KERN_ERR "shwdt: Can't request WTCNT region\n");
+		misc_deregister(&sh_wdt_miscdev);
+		return -ENXIO;
+	}
+
+	if (!request_region(WTCSR, 1, "shwdt")) {
+		printk(KERN_ERR "shwdt: Can't request WTCSR region\n");
+		release_region(WTCNT, 1);
+		misc_deregister(&sh_wdt_miscdev);
+		return -ENXIO;
+	}
+
+	if (register_reboot_notifier(&sh_wdt_notifier)) {
+		printk(KERN_ERR "shwdt: Can't register reboot notifier\n");
+		release_region(WTCSR, 1);
+		release_region(WTCNT, 1);
+		misc_deregister(&sh_wdt_miscdev);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * 	sh_wdt_exit - Deinitialize module
+ *
+ * 	Unregisters the device and notifier handler. Actual device
+ * 	deinitialization is handled by sh_wdt_close().
+ */
+static void __exit sh_wdt_exit(void)
+{
+	unregister_reboot_notifier(&sh_wdt_notifier);
+	release_region(WTCSR, 1);
+	release_region(WTCNT, 1);
+	misc_deregister(&sh_wdt_miscdev);
+}
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("Paul Mundt <lethal@chaoticdreams.org>");
+MODULE_DESCRIPTION("SH 3/4 watchdog driver");
+MODULE_LICENSE("GPL");
+
+module_init(sh_wdt_init);
+module_exit(sh_wdt_exit);
+
diff -u --recursive --new-file v2.4.12/linux/drivers/char/sonypi.c linux/drivers/char/sonypi.c
--- v2.4.12/linux/drivers/char/sonypi.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/char/sonypi.c	Mon Oct 15 08:38:31 2001
@@ -39,6 +39,7 @@
 #include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <asm/system.h>
 
 #include "sonypi.h"
 #include <linux/sonypi.h>
@@ -48,7 +49,7 @@
 static int verbose; /* = 0 */
 static int fnkeyinit; /* = 0 */
 static int camera; /* = 0 */
-extern int is_sony_vaio_laptop; /* set in DMI table parse routines */
+static int compat; /* = 0 */
 
 /* Inits the queue */
 static inline void sonypi_initq(void) {
@@ -110,27 +111,27 @@
 
 static void sonypi_ecrset(u16 addr, u16 value) {
 
-	wait_on_command(inw_p(SONYPI_CST_IOPORT) & 3);
+	wait_on_command(1, inw_p(SONYPI_CST_IOPORT) & 3);
 	outw_p(0x81, SONYPI_CST_IOPORT);
-	wait_on_command(inw_p(SONYPI_CST_IOPORT) & 2);
+	wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
 	outw_p(addr, SONYPI_DATA_IOPORT);
-	wait_on_command(inw_p(SONYPI_CST_IOPORT) & 2);
+	wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
 	outw_p(value, SONYPI_DATA_IOPORT);
-	wait_on_command(inw_p(SONYPI_CST_IOPORT) & 2);
+	wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
 }
 
 static u16 sonypi_ecrget(u16 addr) {
 
-	wait_on_command(inw_p(SONYPI_CST_IOPORT) & 3);
+	wait_on_command(1, inw_p(SONYPI_CST_IOPORT) & 3);
 	outw_p(0x80, SONYPI_CST_IOPORT);
-	wait_on_command(inw_p(SONYPI_CST_IOPORT) & 2);
+	wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
 	outw_p(addr, SONYPI_DATA_IOPORT);
-	wait_on_command(inw_p(SONYPI_CST_IOPORT) & 2);
+	wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
 	return inw_p(SONYPI_DATA_IOPORT);
 }
 
 /* Initializes the device - this comes from the AML code in the ACPI bios */
-static void __devinit sonypi_normal_srs(void) {
+static void __devinit sonypi_type1_srs(void) {
 	u32 v;
 
 	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
@@ -152,7 +153,7 @@
 	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
 }
 
-static void __devinit sonypi_r505_srs(void) {
+static void __devinit sonypi_type2_srs(void) {
 	sonypi_ecrset(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8);
 	sonypi_ecrset(SONYPI_SLOB,  sonypi_device.ioport1 & 0x00FF);
 	sonypi_ecrset(SONYPI_SIRQ,  sonypi_device.bits);
@@ -160,7 +161,7 @@
 }
 
 /* Disables the device - this comes from the AML code in the ACPI bios */
-static void __devexit sonypi_normal_dis(void) {
+static void __devexit sonypi_type1_dis(void) {
 	u32 v;
 
 	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
@@ -172,7 +173,7 @@
 	outl(v, SONYPI_IRQ_PORT);
 }
 
-static void __devexit sonypi_r505_dis(void) {
+static void __devexit sonypi_type2_dis(void) {
 	sonypi_ecrset(SONYPI_SHIB, 0);
 	sonypi_ecrset(SONYPI_SLOB, 0);
 	sonypi_ecrset(SONYPI_SIRQ, 0);
@@ -181,7 +182,7 @@
 static u8 sonypi_call1(u8 dev) {
 	u8 v1, v2;
 
-	wait_on_command(inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
 	outb(dev, sonypi_device.ioport2);
 	v1 = inb_p(sonypi_device.ioport2);
 	v2 = inb_p(sonypi_device.ioport1);
@@ -191,9 +192,9 @@
 static u8 sonypi_call2(u8 dev, u8 fn) {
 	u8 v1;
 
-	wait_on_command(inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
 	outb(dev, sonypi_device.ioport2);
-	wait_on_command(inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
 	outb(fn, sonypi_device.ioport1);
 	v1 = inb_p(sonypi_device.ioport1);
 	return v1;
@@ -202,11 +203,11 @@
 static u8 sonypi_call3(u8 dev, u8 fn, u8 v) {
 	u8 v1;
 
-	wait_on_command(inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
 	outb(dev, sonypi_device.ioport2);
-	wait_on_command(inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
 	outb(fn, sonypi_device.ioport1);
-	wait_on_command(inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
 	outb(v, sonypi_device.ioport1);
 	v1 = inb_p(sonypi_device.ioport1);
 	return v1;
@@ -228,7 +229,7 @@
 /* Set brightness, hue etc */
 static void sonypi_set(u8 fn, u8 v) {
 	
-	wait_on_command(sonypi_call3(0x90, fn, v));
+	wait_on_command(0, sonypi_call3(0x90, fn, v));
 }
 
 /* Tests if the camera is ready */
@@ -291,19 +292,19 @@
 	int i;
 	u8 sonypi_jogger_ev, sonypi_fnkey_ev;
 
-	if (sonypi_device.model == SONYPI_DEVICE_MODEL_R505) {
-		sonypi_jogger_ev = SONYPI_R505_JOGGER_EV;
-		sonypi_fnkey_ev = SONYPI_R505_FNKEY_EV;
+	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
+		sonypi_jogger_ev = SONYPI_TYPE2_JOGGER_EV;
+		sonypi_fnkey_ev = SONYPI_TYPE2_FNKEY_EV;
 	}
 	else {
-		sonypi_jogger_ev = SONYPI_NORMAL_JOGGER_EV;
-		sonypi_fnkey_ev = SONYPI_NORMAL_FNKEY_EV;
+		sonypi_jogger_ev = SONYPI_TYPE1_JOGGER_EV;
+		sonypi_fnkey_ev = SONYPI_TYPE1_FNKEY_EV;
 	}
 
 	v1 = inb_p(sonypi_device.ioport1);
 	v2 = inb_p(sonypi_device.ioport2);
 
-	if ((v2 & SONYPI_NORMAL_PKEY_EV) == SONYPI_NORMAL_PKEY_EV) {
+	if ((v2 & SONYPI_TYPE1_PKEY_EV) == SONYPI_TYPE1_PKEY_EV) {
 		for (i = 0; sonypi_pkeyev[i].event; i++)
 			if (sonypi_pkeyev[i].data == v1) {
 				event = sonypi_pkeyev[i].event;
@@ -338,9 +339,23 @@
 				goto found;
 			}
 	}
+	if ((v2 & SONYPI_BACK_EV) == SONYPI_BACK_EV) {
+		for (i = 0; sonypi_backev[i].event; i++)
+			if (sonypi_backev[i].data == v1) {
+				event = sonypi_backev[i].event;
+				goto found;
+			}
+	}
+	if ((v2 & SONYPI_LID_EV) == SONYPI_LID_EV) {
+		for (i = 0; sonypi_lidev[i].event; i++)
+			if (sonypi_lidev[i].data == v1) {
+				event = sonypi_lidev[i].event;
+				goto found;
+			}
+	}
 	if (verbose)
 		printk(KERN_WARNING 
-		       "sonypi: unknown event port1=0x%x,port2=0x%x\n",v1,v2);
+		       "sonypi: unknown event port1=0x%02x,port2=0x%02x\n",v1,v2);
 	return;
 
 found:
@@ -535,23 +550,20 @@
 	-1, "sonypi", &sonypi_misc_fops
 };
 
-static int __devinit sonypi_probe(struct pci_dev *pcidev, 
-		                  const struct pci_device_id *ent) {
+static int __devinit sonypi_probe(struct pci_dev *pcidev) {
 	int i, ret;
 	struct sonypi_ioport_list *ioport_list;
 	struct sonypi_irq_list *irq_list;
 
-	if (sonypi_device.dev) {
-		printk(KERN_ERR "sonypi: only one device allowed!\n"),
-		ret = -EBUSY;
-		goto out1;
-	}
 	sonypi_device.dev = pcidev;
-	sonypi_device.model = (int)ent->driver_data;
+	if (pcidev)
+		sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
+	else
+		sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
 	sonypi_initq();
 	init_MUTEX(&sonypi_device.lock);
 	
-	if (pci_enable_device(pcidev)) {
+	if (pcidev && pci_enable_device(pcidev)) {
 		printk(KERN_ERR "sonypi: pci_enable_device failed\n");
 		ret = -EIO;
 		goto out1;
@@ -564,15 +576,15 @@
 		goto out1;
 	}
 
-	if (sonypi_device.model == SONYPI_DEVICE_MODEL_R505) {
-		ioport_list = sonypi_r505_ioport_list;
-		sonypi_device.region_size = SONYPI_R505_REGION_SIZE;
-		irq_list = sonypi_r505_irq_list;
+	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
+		ioport_list = sonypi_type2_ioport_list;
+		sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE;
+		irq_list = sonypi_type2_irq_list;
 	}
 	else {
-		ioport_list = sonypi_normal_ioport_list;
-		sonypi_device.region_size = SONYPI_NORMAL_REGION_SIZE;
-		irq_list = sonypi_normal_irq_list;
+		ioport_list = sonypi_type1_ioport_list;
+		sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
+		irq_list = sonypi_type1_irq_list;
 	}
 
 	for (i = 0; ioport_list[i].port1; i++) {
@@ -608,22 +620,27 @@
 	if (fnkeyinit)
 		outb(0xf0, 0xb2);
 
-	if (sonypi_device.model == SONYPI_DEVICE_MODEL_R505)
-		sonypi_r505_srs();
+	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
+		sonypi_type2_srs();
 	else
-		sonypi_normal_srs();
+		sonypi_type1_srs();
 
 	sonypi_call1(0x82);
 	sonypi_call2(0x81, 0xff);
-	sonypi_call1(0x92); 
+	if (compat)
+		sonypi_call1(0x92); 
+	else
+		sonypi_call1(0x82);
 
 	printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver v%d.%d.\n",
 	       SONYPI_DRIVER_MAJORVERSION,
 	       SONYPI_DRIVER_MINORVERSION);
-	printk(KERN_INFO "sonypi: detected %s model, camera = %s\n",
-	       (sonypi_device.model == SONYPI_DEVICE_MODEL_NORMAL) ?
-	       "normal" : "R505",
-	       camera ? "on" : "off");
+	printk(KERN_INFO "sonypi: detected %s model, "
+	       "camera = %s, compat = %s\n",
+	       (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
+			"type1" : "type2",
+	       camera ? "on" : "off",
+	       compat ? "on" : "off");
 	printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
 	       sonypi_device.irq, 
 	       sonypi_device.ioport1, sonypi_device.ioport2);
@@ -641,50 +658,64 @@
 	return ret;
 }
 
-static void __devexit sonypi_remove(struct pci_dev *pcidev) {
+static void __devexit sonypi_remove(void) {
 	sonypi_call2(0x81, 0); /* make sure we don't get any more events */
 	if (camera)
 		sonypi_camera_off();
-	if (sonypi_device.model == SONYPI_DEVICE_MODEL_R505)
-		sonypi_r505_dis();
+	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
+		sonypi_type2_dis();
 	else
-		sonypi_normal_dis();
+		sonypi_type1_dis();
 	free_irq(sonypi_device.irq, sonypi_irq);
 	release_region(sonypi_device.ioport1, sonypi_device.region_size);
 	misc_deregister(&sonypi_misc_device);
 	printk(KERN_INFO "sonypi: removed.\n");
 }
 
-static struct pci_device_id sonypi_id_tbl[] __devinitdata = {
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, 
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
-	  (unsigned long) SONYPI_DEVICE_MODEL_NORMAL },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
-	  (unsigned long) SONYPI_DEVICE_MODEL_R505 },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(pci, sonypi_id_tbl);
-
-static struct pci_driver sonypi_driver = {
-	name:		"sonypi",
-	id_table:	sonypi_id_tbl,
-	probe:		sonypi_probe,
-	remove:		sonypi_remove,
-};
-
 static int __init sonypi_init_module(void) {
-	if (is_sony_vaio_laptop)
-		return pci_module_init(&sonypi_driver);
+	struct pci_dev *pcidev = NULL;
+
+	if (is_sony_vaio_laptop) {
+		pcidev = pci_find_device(PCI_VENDOR_ID_INTEL, 
+					 PCI_DEVICE_ID_INTEL_82371AB_3, 
+					 NULL);
+		return sonypi_probe(pcidev);
+	}
 	else
 		return -ENODEV;
 }
 
 static void __exit sonypi_cleanup_module(void) {
-	pci_unregister_driver(&sonypi_driver);
+	sonypi_remove();
 }
 
+#ifndef MODULE
+static int __init sonypi_setup(char *str)  {
+	int ints[6];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	if (ints[0] <= 0) 
+		goto out;
+	minor = ints[1];
+	if (ints[0] == 1)
+		goto out;
+	verbose = ints[2];
+	if (ints[0] == 2)
+		goto out;
+	fnkeyinit = ints[3];
+	if (ints[0] == 3)
+		goto out;
+	camera = ints[4];
+	if (ints[0] == 4)
+		goto out;
+	compat = ints[5];
+out:
+	return 1;
+}
+
+__setup("sonypi=", sonypi_setup);
+#endif /* !MODULE */
+	
 /* Module entry points */
 module_init(sonypi_init_module);
 module_exit(sonypi_cleanup_module);
@@ -702,5 +733,7 @@
 MODULE_PARM_DESC(fnkeyinit, "set this if your Fn keys do not generate any event");
 MODULE_PARM(camera,"i");
 MODULE_PARM_DESC(camera, "set this if you have a MotionEye camera (PictureBook series)");
+MODULE_PARM(compat,"i");
+MODULE_PARM_DESC(compat, "set this if you want to enable backward compatibility mode");
 
 EXPORT_SYMBOL(sonypi_camera_command);
diff -u --recursive --new-file v2.4.12/linux/drivers/char/sonypi.h linux/drivers/char/sonypi.h
--- v2.4.12/linux/drivers/char/sonypi.h	Sun Sep 23 11:40:57 2001
+++ linux/drivers/char/sonypi.h	Mon Oct 15 08:38:31 2001
@@ -35,26 +35,26 @@
 #ifdef __KERNEL__
 
 #define SONYPI_DRIVER_MAJORVERSION	1
-#define SONYPI_DRIVER_MINORVERSION	5
+#define SONYPI_DRIVER_MINORVERSION	7
 
 #include <linux/types.h>
 #include <linux/pci.h>
 #include "linux/sonypi.h"
 
-/* Normal models use those */
+/* type1 models use those */
 #define SONYPI_IRQ_PORT			0x8034
 #define SONYPI_IRQ_SHIFT		22
 #define SONYPI_BASE			0x50
 #define SONYPI_G10A			(SONYPI_BASE+0x14)
-#define SONYPI_NORMAL_REGION_SIZE	0x08
+#define SONYPI_TYPE1_REGION_SIZE	0x08
 
-/* R505 series specifics */
-#define SONYPI_SIRQ		0x9b
-#define SONYPI_SLOB		0x9c
-#define SONYPI_SHIB		0x9d
-#define SONYPI_R505_REGION_SIZE	0x20
+/* type2 series specifics */
+#define SONYPI_SIRQ			0x9b
+#define SONYPI_SLOB			0x9c
+#define SONYPI_SHIB			0x9d
+#define SONYPI_TYPE2_REGION_SIZE	0x20
 
-/* ioports used for brightness and R505 events */
+/* ioports used for brightness and type2 events */
 #define SONYPI_DATA_IOPORT	0x62
 #define SONYPI_CST_IOPORT	0x66
 
@@ -64,7 +64,7 @@
 	u16	port2;
 };
 
-static struct sonypi_ioport_list sonypi_normal_ioport_list[] = {
+static struct sonypi_ioport_list sonypi_type1_ioport_list[] = {
 	{ 0x10c0, 0x10c4 },	/* looks like the default on C1Vx */
 	{ 0x1080, 0x1084 },
 	{ 0x1090, 0x1094 },
@@ -73,7 +73,7 @@
 	{ 0x0, 0x0 }
 };
 
-static struct sonypi_ioport_list sonypi_r505_ioport_list[] = {
+static struct sonypi_ioport_list sonypi_type2_ioport_list[] = {
 	{ 0x1080, 0x1084 },
 	{ 0x10a0, 0x10a4 },
 	{ 0x10c0, 0x10c4 },
@@ -87,14 +87,14 @@
 	u16	bits;
 };
 
-static struct sonypi_irq_list sonypi_normal_irq_list[] = {
+static struct sonypi_irq_list sonypi_type1_irq_list[] = {
 	{ 11, 0x2 },	/* IRQ 11, GO22=0,GO23=1 in AML */
 	{ 10, 0x1 },	/* IRQ 10, GO22=1,GO23=0 in AML */
 	{  5, 0x0 },	/* IRQ  5, GO22=0,GO23=0 in AML */
 	{  0, 0x3 }	/* no IRQ, GO22=1,GO23=1 in AML */
 };
 
-static struct sonypi_irq_list sonypi_r505_irq_list[] = {
+static struct sonypi_irq_list sonypi_type2_irq_list[] = {
 	{ 11, 0x80 },	/* IRQ 11, 0x80 in SIRQ in AML */
 	{ 10, 0x40 },	/* IRQ 10, 0x40 in SIRQ in AML */
 	{  9, 0x20 },	/* IRQ  9, 0x20 in SIRQ in AML */
@@ -132,13 +132,15 @@
 #define SONYPI_CAMERA_ROMVERSION 		9
 
 /* key press event data (ioport2) */
-#define SONYPI_NORMAL_JOGGER_EV	0x10
-#define SONYPI_R505_JOGGER_EV	0x08
+#define SONYPI_TYPE1_JOGGER_EV	0x10
+#define SONYPI_TYPE2_JOGGER_EV	0x08
 #define SONYPI_CAPTURE_EV	0x60
-#define SONYPI_NORMAL_FNKEY_EV	0x20
-#define SONYPI_R505_FNKEY_EV	0x08
+#define SONYPI_TYPE1_FNKEY_EV	0x20
+#define SONYPI_TYPE2_FNKEY_EV	0x08
 #define SONYPI_BLUETOOTH_EV	0x30
-#define SONYPI_NORMAL_PKEY_EV	0x40
+#define SONYPI_TYPE1_PKEY_EV	0x40
+#define SONYPI_BACK_EV		0x08
+#define SONYPI_LID_EV		0x38
 
 struct sonypi_event {
 	u8	data;
@@ -204,6 +206,19 @@
 	{ 0x00, 0x00 }
 };
 
+/* The set of possible back button events */
+static struct sonypi_event sonypi_backev[] = {
+	{ 0x20, SONYPI_EVENT_BACK_PRESSED },
+	{ 0x00, 0x00 }
+};
+
+/* The set of possible lid events */
+static struct sonypi_event sonypi_lidev[] = {
+	{ 0x51, SONYPI_EVENT_LID_CLOSED },
+	{ 0x50, SONYPI_EVENT_LID_OPENED },
+	{ 0x00, 0x00 }
+};
+
 #define SONYPI_BUF_SIZE	128
 struct sonypi_queue {
 	unsigned long head;
@@ -215,8 +230,8 @@
 	unsigned char buf[SONYPI_BUF_SIZE];
 };
 
-#define SONYPI_DEVICE_MODEL_NORMAL	1
-#define SONYPI_DEVICE_MODEL_R505	2
+#define SONYPI_DEVICE_MODEL_TYPE1	1
+#define SONYPI_DEVICE_MODEL_TYPE2	2
 
 struct sonypi_device {
 	struct pci_dev *dev;
@@ -232,11 +247,11 @@
 	int model;
 };
 
-#define wait_on_command(command) { \
+#define wait_on_command(quiet, command) { \
 	unsigned int n = 10000; \
 	while (--n && (command)) \
 		udelay(1); \
-	if (!n) \
+	if (!n && (verbose || !quiet)) \
 		printk(KERN_WARNING "sonypi command failed at " __FILE__ " : " __FUNCTION__ "(line %d)\n", __LINE__); \
 }
 
diff -u --recursive --new-file v2.4.12/linux/drivers/char/toshiba.c linux/drivers/char/toshiba.c
--- v2.4.12/linux/drivers/char/toshiba.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/char/toshiba.c	Thu Oct 11 09:04:57 2001
@@ -17,7 +17,9 @@
  *     0xfc15: Tom May <tom@you-bastards.com>
  *     0xfc17: Dave Konrad <konrad@xenia.it>
  *     0xfc1a: George Betzos <betzos@engr.colostate.edu>
+ *     0xfc1b: Munemasa Wada <munemasa@jnovel.co.jp>
  *     0xfc1d: Arthur Liu <armie@slap.mine.nu>
+ *     0xfc5a: Jacques L'helgoualc'h <lhh@free.fr>
  *     0xfcd1: Mr. Dave Konrad <konrad@xenia.it>
  *
  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
@@ -51,7 +53,7 @@
  *
  */
 
-#define TOSH_VERSION "1.9 22/3/2001"
+#define TOSH_VERSION "1.11 26/9/2001"
 #define TOSH_DEBUG 0
 
 #include <linux/module.h>
@@ -264,7 +266,7 @@
 	if (!arg)
 		return -EINVAL;
 
-	if(copy_from_user(&regs, (SMMRegisters *) arg, sizeof(SMMRegisters)))
+	if (copy_from_user(&regs, (SMMRegisters *) arg, sizeof(SMMRegisters)))
 		return -EFAULT;
 
 	switch (cmd) {
@@ -288,7 +290,7 @@
 			return -EINVAL;
 	}
 
-        if(copy_to_user((SMMRegisters *) arg, &regs, sizeof(SMMRegisters)))
+        if (copy_to_user((SMMRegisters *) arg, &regs, sizeof(SMMRegisters)))
         	return -EFAULT;
 
 	return (err==0) ? 0:-EINVAL;
@@ -335,7 +337,8 @@
 {
 	switch (tosh_id) {
 		case 0xfc02: case 0xfc04: case 0xfc09: case 0xfc0a: case 0xfc10:
-		case 0xfc11: case 0xfc13: case 0xfc15: case 0xfc1a:
+		case 0xfc11: case 0xfc13: case 0xfc15: case 0xfc1a: case 0xfc1b:
+		case 0xfc5a:
 			tosh_fn = 0x62;
 			break;
 		case 0xfc08: case 0xfc17: case 0xfc1d: case 0xfcd1: case 0xfce0:
@@ -412,8 +415,19 @@
  */
 int tosh_probe(void)
 {
-	int major,minor,day,year,month,flag;
+	int i,major,minor,day,year,month,flag;
+	unsigned char signature[7] = { 0x54,0x4f,0x53,0x48,0x49,0x42,0x41 };
 	SMMRegisters regs;
+
+	/* extra sanity check for the string "TOSHIBA" in the BIOS because
+	   some machines that are not Toshiba's pass the next test */
+
+	for (i=0;i<7;i++) {
+		if (isa_readb(0xfe010+i)!=signature[i]) {
+			printk("toshiba: not a supported Toshiba laptop\n");
+			return -ENODEV;
+		}
+	}
 
 	/* call the Toshiba SCI support check routine */
 	
diff -u --recursive --new-file v2.4.12/linux/drivers/fc4/soc.c linux/drivers/fc4/soc.c
--- v2.4.12/linux/drivers/fc4/soc.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/fc4/soc.c	Thu Oct 11 09:14:32 2001
@@ -764,3 +764,4 @@
 
 module_init(soc_probe);
 module_exit(soc_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/fc4/socal.c linux/drivers/fc4/socal.c
--- v2.4.12/linux/drivers/fc4/socal.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/fc4/socal.c	Thu Oct 11 09:14:32 2001
@@ -904,3 +904,4 @@
 
 module_init(socal_probe);
 module_exit(socal_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/Config.in linux/drivers/i2c/Config.in
--- v2.4.12/linux/drivers/i2c/Config.in	Sun Sep 23 11:40:57 2001
+++ linux/drivers/i2c/Config.in	Thu Oct 11 08:05:47 2001
@@ -26,11 +26,24 @@
          dep_tristate '  ITE I2C Adapter' CONFIG_ITE_I2C_ADAP $CONFIG_ITE_I2C_ALGO
       fi
    fi
+   if [ "$CONFIG_8xx" = "y" ]; then
+      dep_tristate 'MPC8xx CPM I2C interface' CONFIG_I2C_ALGO8XX $CONFIG_I2C
+      if [ "$CONFIG_RPXLITE" = "y" -o "$CONFIG_RPXCLASSIC" = "y" ]; then
+         dep_tristate '  Embedded Planet RPX Lite/Classic suppoort' CONFIG_I2C_RPXLITE $CONFIG_I2C_ALGO8XX
+      fi
+   fi
+   if [ "$CONFIG_405" = "y" ]; then
+      dep_tristate 'PPC 405 I2C Algorithm' CONFIG_I2C_PPC405_ALGO $CONFIG_I2C
+      if [ "$CONFIG_I2C_PPC405_ALGO" != "n" ]; then
+         dep_tristate '  PPC 405 I2C Adapter' CONFIG_I2C_PPC405_ADAP $CONFIG_I2C_PPC405_ALGO
+      fi
+   fi
 
 # This is needed for automatic patch generation: sensors code starts here
 # This is needed for automatic patch generation: sensors code ends here
 
    dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C
+   dep_tristate 'I2C /proc interface (required for hardware sensors)' CONFIG_I2C_PROC $CONFIG_I2C
 
 fi
 endmenu
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/Makefile linux/drivers/i2c/Makefile
--- v2.4.12/linux/drivers/i2c/Makefile	Fri Dec 29 14:07:21 2000
+++ linux/drivers/i2c/Makefile	Thu Oct 11 08:05:47 2001
@@ -4,7 +4,8 @@
 
 O_TARGET := i2c.o
 
-export-objs	:= i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o
+export-objs	:= i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \
+		   i2c-algo-ite.o i2c-proc.o
 
 obj-$(CONFIG_I2C)		+= i2c-core.o
 obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
@@ -14,6 +15,9 @@
 obj-$(CONFIG_I2C_VELLEMAN)	+= i2c-velleman.o
 obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
 obj-$(CONFIG_I2C_ELEKTOR)	+= i2c-elektor.o
+obj-$(CONFIG_ITE_I2C_ALGO)	+= i2c-algo-ite.o
+obj-$(CONFIG_ITE_I2C_ADAP)	+= i2c-adap-ite.o
+obj-$(CONFIG_I2C_PROC)		+= i2c-proc.o
 
 # This is needed for automatic patch generation: sensors code starts here
 # This is needed for automatic patch generation: sensors code ends here
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/i2c-adap-ite.c linux/drivers/i2c/i2c-adap-ite.c
--- v2.4.12/linux/drivers/i2c/i2c-adap-ite.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/i2c/i2c-adap-ite.c	Thu Oct 11 08:05:47 2001
@@ -37,7 +37,7 @@
 #include <linux/ioport.h>
 #include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/version.h>
 #include <linux/init.h>
 #include <asm/irq.h>
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/i2c-algo-bit.c linux/drivers/i2c/i2c-algo-bit.c
--- v2.4.12/linux/drivers/i2c/i2c-algo-bit.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/i2c/i2c-algo-bit.c	Thu Oct 11 08:05:47 2001
@@ -21,7 +21,7 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c-algo-bit.c,v 1.27 2000/07/09 15:16:16 frodo Exp $ */
+/* $Id: i2c-algo-bit.c,v 1.30 2001/07/29 02:44:25 mds Exp $ */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/i2c-algo-ite.c linux/drivers/i2c/i2c-algo-ite.c
--- v2.4.12/linux/drivers/i2c/i2c-algo-ite.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/i2c/i2c-algo-ite.c	Thu Oct 11 08:05:47 2001
@@ -37,7 +37,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/version.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/i2c-algo-pcf.c linux/drivers/i2c/i2c-algo-pcf.c
--- v2.4.12/linux/drivers/i2c/i2c-algo-pcf.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/i2c/i2c-algo-pcf.c	Thu Oct 11 08:05:47 2001
@@ -1,4 +1,3 @@
-
 /* ------------------------------------------------------------------------- */
 /* i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters		     */
 /* ------------------------------------------------------------------------- */
@@ -24,7 +23,9 @@
    Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
    <mbailey@littlefeet-inc.com> */
 
-/* $Id: i2c-algo-pcf.c,v 1.25 2000/11/10 13:43:32 frodo Exp $ */
+/* Partially rewriten by Oleg I. Vdovikin <vdovikin@jscc.ru> to handle multiple
+   messages, proper stop/repstart signaling during receive,
+   added detect code */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -49,26 +50,9 @@
  	/* debug the protocol by showing transferred bits */
 #define DEF_TIMEOUT 16
 
-/* debugging - slow down transfer to have a look at the data .. 	*/
-/* I use this with two leds&resistors, each one connected to sda,scl 	*/
-/* respectively. This makes sure that the algorithm works. Some chips   */
-/* might not like this, as they have an internal timeout of some mils	*/
-/*
-#define SLO_IO      jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
-                        if (need_resched) schedule();
-*/
-
-
-/* ----- global variables ---------------------------------------------	*/
-
-#ifdef SLO_IO
-	int jif;
-#endif
-
 /* module parameters:
  */
-static int i2c_debug=1;
-static int pcf_test=0;	/* see if the line-setting functions work	*/
+static int i2c_debug=0;
 static int pcf_scan=0;	/* have a look at what's hanging 'round		*/
 
 /* --- setting states on the bus with the right timing: ---------------	*/
@@ -80,7 +64,6 @@
 #define i2c_outb(adap, val) adap->setpcf(adap->data, 0, val)
 #define i2c_inb(adap) adap->getpcf(adap->data, 0)
 
-
 /* --- other auxiliary functions --------------------------------------	*/
 
 static void i2c_start(struct i2c_algo_pcf_data *adap) 
@@ -111,16 +94,15 @@
 	status = get_pcf(adap, 1);
 #ifndef STUB_I2C
 	while (timeout-- && !(status & I2C_PCF_BB)) {
-		udelay(1000); /* How much is this? */
+		udelay(100); /* wait for 100 us */
 		status = get_pcf(adap, 1);
 	}
 #endif
-	if (timeout<=0)
+	if (timeout <= 0) {
 		printk("Timeout waiting for Bus Busy\n");
-	/*
-	set_pcf(adap, 1, I2C_PCF_STOP);
-	*/
-	return(timeout<=0);
+	}
+	
+	return (timeout<=0);
 }
 
 
@@ -147,7 +129,6 @@
 		return(0);
 }
 
-
 /* 
  * This should perform the 'PCF8584 initialization sequence' as described
  * in the Philips IC12 data book (1995, Aug 29).
@@ -156,111 +137,64 @@
  * There should be a delay at the end equal to the longest I2C message
  * to synchronize the BB-bit (in multimaster systems). How long is
  * this? I assume 1 second is always long enough.
+ *
+ * vdovikin: added detect code for PCF8584
  */
 static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
 {
+	unsigned char temp;
+
+	DEB3(printk("i2c-algo-pcf.o: PCF state 0x%02x\n", get_pcf(adap, 1)));
 
-	/* S1=0x80: S0 selected, serial interface off			*/
+	/* S1=0x80: S0 selected, serial interface off */
 	set_pcf(adap, 1, I2C_PCF_PIN);
+	/* check to see S1 now used as R/W ctrl -
+	   PCF8584 does that when ESO is zero */
+	/* PCF also resets PIN bit */
+	if ((temp = get_pcf(adap, 1)) != (0)) {
+		DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
+		return -ENXIO; /* definetly not PCF8584 */
+	}
 
 	/* load own address in S0, effective address is (own << 1)	*/
 	i2c_outb(adap, get_own(adap));
+	/* check it's realy writen */
+	if ((temp = i2c_inb(adap)) != get_own(adap)) {
+		DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp));
+		return -ENXIO;
+	}
 
 	/* S1=0xA0, next byte in S2					*/
 	set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
+	/* check to see S2 now selected */
+	if ((temp = get_pcf(adap, 1)) != I2C_PCF_ES1) {
+		DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp));
+		return -ENXIO;
+	}
 
 	/* load clock register S2					*/
 	i2c_outb(adap, get_clock(adap));
+	/* check it's realy writen, the only 5 lowest bits does matter */
+	if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) {
+		DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp));
+		return -ENXIO;
+	}
 
 	/* Enable serial interface, idle, S0 selected			*/
 	set_pcf(adap, 1, I2C_PCF_IDLE);
 
-	DEB2(printk("i2c-algo-pcf.o: irq: Initialized 8584.\n"));
-	return 0;
-}
-
-
-/*
- * Sanity check for the adapter hardware - check the reaction of
- * the bus lines only if it seems to be idle.
- */
-static int test_bus(struct i2c_algo_pcf_data *adap, char *name) {
-#if 0
-	int scl,sda;
-	sda=getsda(adap);
-	if (adap->getscl==NULL) {
-		printk("i2c-algo-pcf.o: Warning: Adapter can't read from clock line - skipping test.\n");
-		return 0;		
-	}
-	scl=getscl(adap);
-	printk("i2c-algo-pcf.o: Adapter: %s scl: %d  sda: %d -- testing...\n",
-	name,getscl(adap),getsda(adap));
-	if (!scl || !sda ) {
-		printk("i2c-algo-pcf.o: %s seems to be busy.\n",adap->name);
-		goto bailout;
-	}
-	sdalo(adap);
-	printk("i2c-algo-pcf.o:1 scl: %d  sda: %d \n",getscl(adap),
-	       getsda(adap));
-	if ( 0 != getsda(adap) ) {
-		printk("i2c-algo-pcf.o: %s SDA stuck high!\n",name);
-		sdahi(adap);
-		goto bailout;
-	}
-	if ( 0 == getscl(adap) ) {
-		printk("i2c-algo-pcf.o: %s SCL unexpected low while pulling SDA low!\n",
-			name);
-		goto bailout;
-	}		
-	sdahi(adap);
-	printk("i2c-algo-pcf.o:2 scl: %d  sda: %d \n",getscl(adap),
-	       getsda(adap));
-	if ( 0 == getsda(adap) ) {
-		printk("i2c-algo-pcf.o: %s SDA stuck low!\n",name);
-		sdahi(adap);
-		goto bailout;
-	}
-	if ( 0 == getscl(adap) ) {
-		printk("i2c-algo-pcf.o: %s SCL unexpected low while SDA high!\n",
-		       adap->name);
-	goto bailout;
+	/* check to see PCF is realy idled and we can access status register */
+	if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) {
+		DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp));
+		return -ENXIO;
 	}
-	scllo(adap);
-	printk("i2c-algo-pcf.o:3 scl: %d  sda: %d \n",getscl(adap),
-	       getsda(adap));
-	if ( 0 != getscl(adap) ) {
-		printk("i2c-algo-pcf.o: %s SCL stuck high!\n",name);
-		sclhi(adap);
-		goto bailout;
-	}
-	if ( 0 == getsda(adap) ) {
-		printk("i2c-algo-pcf.o: %s SDA unexpected low while pulling SCL low!\n",
-			name);
-		goto bailout;
-	}
-	sclhi(adap);
-	printk("i2c-algo-pcf.o:4 scl: %d  sda: %d \n",getscl(adap),
-	       getsda(adap));
-	if ( 0 == getscl(adap) ) {
-		printk("i2c-algo-pcf.o: %s SCL stuck low!\n",name);
-		sclhi(adap);
-		goto bailout;
-	}
-	if ( 0 == getsda(adap) ) {
-		printk("i2c-algo-pcf.o: %s SDA unexpected low while SCL high!\n",
-			name);
-		goto bailout;
-	}
-	printk("i2c-algo-pcf.o: %s passed test.\n",name);
+	
+	printk("i2c-algo-pcf.o: deteted and initialized PCF8584.\n");
+
 	return 0;
-bailout:
-	sdahi(adap);
-	sclhi(adap);
-	return -ENODEV;
-#endif
-	return (0);
 }
 
+
 /* ----- Utility functions
  */
 
@@ -287,8 +221,8 @@
 }
 
 
-static int pcf_sendbytes(struct i2c_adapter *i2c_adap,const char *buf,
-                         int count)
+static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
+                         int count, int last)
 {
 	struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
 	int wrcount, status, timeout;
@@ -313,58 +247,59 @@
 		}
 #endif
 	}
-	i2c_stop(adap);
+	if (last) {
+		i2c_stop(adap);
+	}
+	else {
+		i2c_repstart(adap);
+	}
+
 	return (wrcount);
 }
 
 
-static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
+static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
+                         int count, int last)
 {
-	int rdcount=0, i, status, timeout, dummy=1;
+	int i, status;
 	struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
-    
-	for (i=0; i<count; ++i) {
-		buf[rdcount] = i2c_inb(adap);
-		if (dummy) {
-			dummy = 0;
-		} else {
-			rdcount++;
-		}
-		timeout = wait_for_pin(adap, &status);
-		if (timeout) {
+
+	/* increment number of bytes to read by one -- read dummy byte */
+	for (i = 0; i <= count; i++) {
+
+		if (wait_for_pin(adap, &status)) {
 			i2c_stop(adap);
-			printk("i2c-algo-pcf.o: i2c_read: "
-			       "i2c_inb timed out.\n");
+			printk("i2c-algo-pcf.o: pcf_readbytes timed out.\n");
 			return (-1);
 		}
+
 #ifndef STUB_I2C
-		if (status & I2C_PCF_LRB) {
+		if ((status & I2C_PCF_LRB) && (i != count)) {
 			i2c_stop(adap);
 			printk("i2c-algo-pcf.o: i2c_read: i2c_inb, No ack.\n");
 			return (-1);
 		}
 #endif
-	}
-	set_pcf(adap, 1, I2C_PCF_ESO);
-	buf[rdcount] = i2c_inb(adap);
-	if (dummy) {
-		dummy = 0;
-	} else {
-		rdcount++;
-	}
-	timeout = wait_for_pin(adap, &status);
-	if (timeout) {
-		i2c_stop(adap);
-		printk("i2c-algo-pcf.o: i2c_read: i2c_inb timed out.\n");
-		return (-1);
-	}
-    
-	i2c_stop(adap);
+		
+		if (i == count - 1) {
+			set_pcf(adap, 1, I2C_PCF_ESO);
+		} else 
+		if (i == count) {
+			if (last) {
+				i2c_stop(adap);
+			} else {
+				i2c_repstart(adap);
+			}
+		};
 
-	/* Read final byte from S0 register */
-	buf[rdcount++] = i2c_inb(adap);
+		if (i) {
+			buf[i - 1] = i2c_inb(adap);
+		} else {
+			i2c_inb(adap); /* dummy read */
+		}
+	}
 
-	return (rdcount);
+	return (i - 1);
 }
 
 
@@ -418,16 +353,10 @@
 {
 	struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
 	struct i2c_msg *pmsg;
-	int i = 0;
-	int ret, timeout, status;
-    
-	pmsg = &msgs[i];
-    
-	/* Send address here if Read */
-	if (pmsg->flags & I2C_M_RD) {
-		ret = pcf_doAddress(adap, pmsg, i2c_adap->retries);
-	}
+	int i;
+	int ret=0, timeout, status;
     
+
 	/* Check for bus busy */
 	timeout = wait_for_bb(adap);
 	if (timeout) {
@@ -435,60 +364,68 @@
 		            "Timeout waiting for BB in pcf_xfer\n");)
 		return -EIO;
 	}
+	
+	for (i = 0;ret >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+
+		DEB2(printk("i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n",
+		     pmsg->flags & I2C_M_RD ? "read" : "write",
+                     pmsg->len, pmsg->addr, i + 1, num);)
     
-	/* Send address here if Write */
-	if (!(pmsg->flags & I2C_M_RD)) {
 		ret = pcf_doAddress(adap, pmsg, i2c_adap->retries);
-	}
-	/* Send START */
-	i2c_start(adap);
+
+		/* Send START */
+		if (i == 0) {
+			i2c_start(adap); 
+		}
     
-	/* Wait for PIN (pending interrupt NOT) */
-	timeout = wait_for_pin(adap, &status);
-	if (timeout) {
-		i2c_stop(adap);
-		DEB2(printk("i2c-algo-pcf.o: Timeout waiting "
-		            "for PIN(1) in pcf_xfer\n");)
-		return (-EREMOTEIO);
-	}
+		/* Wait for PIN (pending interrupt NOT) */
+		timeout = wait_for_pin(adap, &status);
+		if (timeout) {
+			i2c_stop(adap);
+			DEB2(printk("i2c-algo-pcf.o: Timeout waiting "
+				    "for PIN(1) in pcf_xfer\n");)
+			return (-EREMOTEIO);
+		}
     
 #ifndef STUB_I2C
-	/* Check LRB (last rcvd bit - slave ack) */
-	if (status & I2C_PCF_LRB) {
-		i2c_stop(adap);
-		DEB2(printk("i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
-		return (-EREMOTEIO);
-	}
+		/* Check LRB (last rcvd bit - slave ack) */
+		if (status & I2C_PCF_LRB) {
+			i2c_stop(adap);
+			DEB2(printk("i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
+			return (-EREMOTEIO);
+		}
 #endif
     
-	DEB3(printk("i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
-	            i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
+		DEB3(printk("i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
+			    i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
     
-	/* Read */
-	if (pmsg->flags & I2C_M_RD) {
+		/* Read */
+		if (pmsg->flags & I2C_M_RD) {
+			/* read bytes into buffer*/
+			ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len,
+                                            (i + 1 == num));
         
-		/* read bytes into buffer*/
-		ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len);
-        
-		if (ret != pmsg->len) {
-			DEB2(printk("i2c-algo-pcf.o: fail: "
-			            "only read %d bytes.\n",ret));
-		} else {
-			DEB2(printk("i2c-algo-pcf.o: read %d bytes.\n",ret));
-		}
-	} else { /* Write */
-        
-        /* Write bytes from buffer */
-		ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len);
+			if (ret != pmsg->len) {
+				DEB2(printk("i2c-algo-pcf.o: fail: "
+					    "only read %d bytes.\n",ret));
+			} else {
+				DEB2(printk("i2c-algo-pcf.o: read %d bytes.\n",ret));
+			}
+		} else { /* Write */
+			ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len,
+                                            (i + 1 == num));
         
-		if (ret != pmsg->len) {
-			DEB2(printk("i2c-algo-pcf.o: fail: "
-			            "only wrote %d bytes.\n",ret));
-		} else {
-			DEB2(printk("i2c-algo-pcf.o: wrote %d bytes.\n",ret));
+			if (ret != pmsg->len) {
+				DEB2(printk("i2c-algo-pcf.o: fail: "
+					    "only wrote %d bytes.\n",ret));
+			} else {
+				DEB2(printk("i2c-algo-pcf.o: wrote %d bytes.\n",ret));
+			}
 		}
 	}
-	return (num);
+
+	return (i);
 }
 
 static int algo_control(struct i2c_adapter *adapter, 
@@ -524,12 +461,6 @@
 	int i, status;
 	struct i2c_algo_pcf_data *pcf_adap = adap->algo_data;
 
-	if (pcf_test) {
-		int ret = test_bus(pcf_adap, adap->name);
-		if (ret<0)
-			return -ENODEV;
-	}
-
 	DEB2(printk("i2c-algo-pcf.o: hw routines for %s registered.\n",
 	            adap->name));
 
@@ -538,21 +469,29 @@
 	adap->id |= pcf_algo.id;
 	adap->algo = &pcf_algo;
 
-	adap->timeout = 100;	/* default values, should	*/
+	adap->timeout = 100;		/* default values, should	*/
 	adap->retries = 3;		/* be replaced by defines	*/
 
+	if ((i = pcf_init_8584(pcf_adap))) {
+		return i;
+	}
+
 #ifdef MODULE
 	MOD_INC_USE_COUNT;
 #endif
 
 	i2c_add_adapter(adap);
-	pcf_init_8584(pcf_adap);
 
 	/* scan bus */
 	if (pcf_scan) {
 		printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s.\n",
 		       adap->name);
 		for (i = 0x00; i < 0xff; i+=2) {
+			if (wait_for_bb(pcf_adap)) {
+    			printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s - TIMEOUTed.\n",
+		           adap->name);
+			    break;
+			}
 			i2c_outb(pcf_adap, i);
 			i2c_start(pcf_adap);
 			if ((wait_for_pin(pcf_adap, &status) >= 0) && 
@@ -598,11 +537,9 @@
 MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(pcf_test, "i");
 MODULE_PARM(pcf_scan, "i");
 MODULE_PARM(i2c_debug,"i");
 
-MODULE_PARM_DESC(pcf_test, "Test if the I2C bus is available");
 MODULE_PARM_DESC(pcf_scan, "Scan for active chips on the bus");
 MODULE_PARM_DESC(i2c_debug,
         "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/i2c-core.c linux/drivers/i2c/i2c-core.c
--- v2.4.12/linux/drivers/i2c/i2c-core.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/i2c/i2c-core.c	Thu Oct 11 08:05:47 2001
@@ -20,7 +20,7 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
    All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c-core.c,v 1.58 2000/10/29 22:57:38 frodo Exp $ */
+/* $Id: i2c-core.c,v 1.64 2001/08/13 01:35:56 mds Exp $ */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -248,7 +248,7 @@
 		     */
 			if ((res=client->driver->detach_client(client))) {
 				printk("i2c-core.o: adapter %s not "
-					"unregisted, because client at "
+					"unregistered, because client at "
 					"address %02x can't be detached. ",
 					adap->name, client->addr);
 				goto ERROR0;
@@ -563,6 +563,7 @@
 			if(adapters[j]->clients[i]->flags & I2C_CLIENT_ALLOW_USE)	
 				return adapters[j]->clients[i];
 		}
+		i = 0;
 	}
 
 	return 0;
@@ -658,7 +659,7 @@
 	int i,j,k,order_nr,len=0,len_total;
 	int order[I2C_CLIENT_MAX];
 
-	if (count < 0)
+	if (count > 4000)
 		return -EINVAL; 
 	len_total = file->f_pos + count;
 	/* Too bad if this gets longer (unlikely) */
@@ -1277,14 +1278,41 @@
 }
 
 #ifndef MODULE
+#ifdef CONFIG_I2C_CHARDEV
 	extern int i2c_dev_init(void);
+#endif
+#ifdef CONFIG_I2C_ALGOBIT
 	extern int i2c_algo_bit_init(void);
+#endif
+#ifdef CONFIG_I2C_CONFIG_I2C_PHILIPSPAR
 	extern int i2c_bitlp_init(void);
+#endif
+#ifdef CONFIG_I2C_ELV
 	extern int i2c_bitelv_init(void);
+#endif
+#ifdef CONFIG_I2C_VELLEMAN
 	extern int i2c_bitvelle_init(void);
+#endif
+#ifdef CONFIG_I2C_BITVIA
 	extern int i2c_bitvia_init(void);
+#endif
+
+#ifdef CONFIG_I2C_ALGOPCF
 	extern int i2c_algo_pcf_init(void);	
+#endif
+#ifdef CONFIG_I2C_ELEKTOR
 	extern int i2c_pcfisa_init(void);
+#endif
+
+#ifdef CONFIG_I2C_ALGO8XX
+	extern int i2c_algo_8xx_init(void);
+#endif
+#ifdef CONFIG_I2C_RPXLITE
+	extern int i2c_rpx_init(void);
+#endif
+#ifdef CONFIG_I2C_PROC
+	extern int sensors_init(void);
+#endif
 
 /* This is needed for automatic patch generation: sensors code starts here */
 /* This is needed for automatic patch generation: sensors code ends here   */
@@ -1317,6 +1345,19 @@
 #endif
 #ifdef CONFIG_I2C_ELEKTOR
 	i2c_pcfisa_init();
+#endif
+
+	/* --------------------- 8xx -------- */
+#ifdef CONFIG_I2C_ALGO8XX
+	i2c_algo_8xx_init();
+#endif
+#ifdef CONFIG_I2C_RPXLITE
+	i2c_rpx_init();
+#endif
+
+	/* -------------- proc interface ---- */
+#ifdef CONFIG_I2C_PROC
+	sensors_init();
 #endif
 /* This is needed for automatic patch generation: sensors code starts here */
 /* This is needed for automatic patch generation: sensors code ends here */
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/i2c-dev.c linux/drivers/i2c/i2c-dev.c
--- v2.4.12/linux/drivers/i2c/i2c-dev.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/i2c/i2c-dev.c	Thu Oct 11 08:05:47 2001
@@ -28,7 +28,7 @@
 /* The devfs code is contributed by Philipp Matthias Hahn 
    <pmhahn@titan.lahn.de> */
 
-/* $Id: i2c-dev.c,v 1.36 2000/09/22 02:19:35 mds Exp $ */
+/* $Id: i2c-dev.c,v 1.40 2001/08/25 01:28:01 mds Exp $ */
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -60,6 +60,9 @@
 
 /* struct file_operations changed too often in the 2.1 series for nice code */
 
+#if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,9)
+static loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin);
+#endif
 static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, 
                             loff_t *offset);
 static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, 
@@ -88,7 +91,11 @@
 #if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0)
 	owner:		THIS_MODULE,
 #endif /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */
+#if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,9)
+	llseek:		i2cdev_lseek,
+#else
 	llseek:		no_llseek,
+#endif
 	read:		i2cdev_read,
 	write:		i2cdev_write,
 	ioctl:		i2cdev_ioctl,
@@ -126,6 +133,20 @@
 
 static int i2cdev_initialized;
 
+#if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,9)
+/* Note that the lseek function is called llseek in 2.1 kernels. But things
+   are complicated enough as is. */
+loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin)
+{
+#ifdef DEBUG
+	struct inode *inode = file->f_dentry->d_inode;
+	printk("i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n",
+	       MINOR(inode->i_rdev),(long) offset,origin);
+#endif /* DEBUG */
+	return -ESPIPE;
+}
+#endif
+
 static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
                             loff_t *offset)
 {
@@ -227,9 +248,6 @@
 				   sizeof(rdwr_arg)))
 			return -EFAULT;
 
-		if(rdwr_arg.nmsgs > 2048)
-			return -EINVAL;
-			
 		rdwr_pa = (struct i2c_msg *)
 			kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), 
 			GFP_KERNEL);
@@ -505,7 +523,7 @@
 			       "module not removed.\n");
 			return res;
 		}
-	i2cdev_initialized ++;
+	i2cdev_initialized --;
 	}
 
 	if (i2cdev_initialized >= 1) {
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/i2c-elektor.c linux/drivers/i2c/i2c-elektor.c
--- v2.4.12/linux/drivers/i2c/i2c-elektor.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/i2c/i2c-elektor.c	Thu Oct 11 08:05:47 2001
@@ -22,7 +22,8 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c-elektor.c,v 1.19 2000/07/25 23:52:17 frodo Exp $ */
+/* Partialy rewriten by Oleg I. Vdovikin for mmapped support of 
+   for Alpha Processor Inc. UP-2000(+) boards */
 
 #include <linux/kernel.h>
 #include <linux/ioport.h>
@@ -31,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/version.h>
 #include <linux/init.h>
+#include <linux/pci.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
@@ -39,17 +41,20 @@
 #include <linux/i2c-elektor.h>
 #include "i2c-pcf8584.h"
 
-#define DEFAULT_BASE 0x300
-#define DEFAULT_IRQ      0
-#define DEFAULT_CLOCK 0x1c
-#define DEFAULT_OWN   0x55
-
-static int base  = 0;
-static int irq   = 0;
-static int clock = 0;
-static int own   = 0;
-static int i2c_debug=0;
-static struct i2c_pcf_isa gpi;
+#define DEFAULT_BASE 0x330
+
+static int base   = 0;
+static int irq    = 0;
+static int clock  = 0x1c;
+static int own    = 0x55;
+static int mmapped = 0;
+static int i2c_debug = 0;
+
+/* vdovikin: removed static struct i2c_pcf_isa gpi; code - 
+  this module in real supports only one device, due to missing arguments
+  in some functions, called from the algo-pcf module. Sometimes it's
+  need to be rewriten - but for now just remove this for simpler reading */
+
 #if (LINUX_VERSION_CODE < 0x020301)
 static struct wait_queue *pcf_wait = NULL;
 #else
@@ -63,81 +68,63 @@
 #define DEB3(x) if (i2c_debug>=3) x
 #define DEBE(x)	x	/* error messages 				*/
 
-
-/* --- Convenience defines for the i2c port:			*/
-#define BASE	((struct i2c_pcf_isa *)(data))->pi_base
-#define DATA	BASE			/* Adapter data port		*/
-#define CTRL	(BASE+1)		/* Adapter control port	        */
-
 /* ----- local functions ----------------------------------------------	*/
 
 static void pcf_isa_setbyte(void *data, int ctl, int val)
 {
-        unsigned long j = jiffies + 10;
+	int address = ctl ? (base + 1) : base;
 
-        if (ctl) {
-		if (gpi.pi_irq > 0) {
-			DEB3(printk("i2c-elektor.o: Write Ctrl 0x%02X\n",
-			     val|I2C_PCF_ENI));
-                        DEB3({while (jiffies < j) schedule();})
-			outb(val | I2C_PCF_ENI, CTRL);
-		} else {
-			 DEB3(printk("i2c-elektor.o: Write Ctrl 0x%02X\n", val|I2C_PCF_ENI));
-                         DEB3({while (jiffies < j) schedule();})
-			 outb(val|I2C_PCF_ENI, CTRL);
-		}
-	} else {
-		DEB3(printk("i2c-elektor.o: Write Data 0x%02X\n", val&0xff));
-                DEB3({while (jiffies < j) schedule();})
-		outb(val, DATA);
+	if (ctl && irq) {
+		val |= I2C_PCF_ENI;
+	}
+
+	DEB3(printk("i2c-elektor.o: Write 0x%X 0x%02X\n", address, val & 255));
+
+	switch (mmapped) {
+	case 0: /* regular I/O */
+		outb(val, address);
+		break;
+	case 2: /* double mapped I/O needed for UP2000 board,
+                   I don't know why this... */
+		writeb(val, address);
+		/* fall */
+	case 1: /* memory mapped I/O */
+		writeb(val, address);
+		break;
 	}
 }
 
 static int pcf_isa_getbyte(void *data, int ctl)
 {
-	int val;
+	int address = ctl ? (base + 1) : base;
+	int val = mmapped ? readb(address) : inb(address);
+
+	DEB3(printk("i2c-elektor.o: Read 0x%X 0x%02X\n", address, val));
 
-	if (ctl) {
-		val = inb(CTRL);
-		DEB3(printk("i2c-elektor.o: Read Ctrl 0x%02X\n", val));
-	} else {
-		val = inb(DATA);
-		DEB3(printk("i2c-elektor.o: Read Data 0x%02X\n", val));
-	}
 	return (val);
 }
 
 static int pcf_isa_getown(void *data)
 {
-	return (gpi.pi_own);
+	return (own);
 }
 
 
 static int pcf_isa_getclock(void *data)
 {
-	return (gpi.pi_clock);
-}
-
-
-
-#if 0
-static void pcf_isa_sleep(unsigned long timeout)
-{
-	schedule_timeout( timeout * HZ);
+	return (clock);
 }
-#endif
-
 
 static void pcf_isa_waitforpin(void) {
 
 	int timeout = 2;
 
-	if (gpi.pi_irq > 0) {
+	if (irq > 0) {
 		cli();
-	if (pcf_pending == 0) {
-		interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ );
-	} else
-		pcf_pending = 0;
+		if (pcf_pending == 0) {
+			interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ );
+		} else
+			pcf_pending = 0;
 		sti();
 	} else {
 		udelay(100);
@@ -153,30 +140,34 @@
 
 static int pcf_isa_init(void)
 {
-	if (check_region(gpi.pi_base, 2) < 0 ) {
-		return -ENODEV;
-	} else {
-		request_region(gpi.pi_base, 2, "i2c (isa bus adapter)");
+	if (!mmapped) {
+		if (check_region(base, 2) < 0 ) {
+			printk("i2c-elektor.o: requested I/O region (0x%X:2) is in use.\n", base);
+			return -ENODEV;
+		} else {
+			request_region(base, 2, "i2c (isa bus adapter)");
+		}
 	}
-	if (gpi.pi_irq > 0) {
-		if (request_irq(gpi.pi_irq, pcf_isa_handler, 0, "PCF8584", 0)
-		    < 0) {
-		printk("i2c-elektor.o: Request irq%d failed\n", gpi.pi_irq);
-		gpi.pi_irq = 0;
-	} else
-		enable_irq(gpi.pi_irq);
+	if (irq > 0) {
+		if (request_irq(irq, pcf_isa_handler, 0, "PCF8584", 0) < 0) {
+			printk("i2c-elektor.o: Request irq%d failed\n", irq);
+			irq = 0;
+		} else
+			enable_irq(irq);
 	}
 	return 0;
 }
 
 
-static void pcf_isa_exit(void)
+static void __exit pcf_isa_exit(void)
 {
-	if (gpi.pi_irq > 0) {
-		disable_irq(gpi.pi_irq);
-		free_irq(gpi.pi_irq, 0);
+	if (irq > 0) {
+		disable_irq(irq);
+		free_irq(irq, 0);
+	}
+	if (!mmapped) {
+		release_region(base , 2);
 	}
-	release_region(gpi.pi_base , 2);
 }
 
 
@@ -217,7 +208,7 @@
 	pcf_isa_getown,
 	pcf_isa_getclock,
 	pcf_isa_waitforpin,
-	80, 80, 100,		/*	waits, timeout */
+	10, 10, 100,		/*	waits, timeout */
 };
 
 static struct i2c_adapter pcf_isa_ops = {
@@ -233,31 +224,61 @@
 
 int __init i2c_pcfisa_init(void) 
 {
+#ifdef __alpha__
+	/* check to see we have memory mapped PCF8584 connected to the 
+	Cypress cy82c693 PCI-ISA bridge as on UP2000 board */
+	if ((base == 0) && pci_present()) {
+		
+		struct pci_dev *cy693_dev =
+                    pci_find_device(PCI_VENDOR_ID_CONTAQ, 
+		                    PCI_DEVICE_ID_CONTAQ_82C693, NULL);
+
+		if (cy693_dev) {
+			char config;
+			/* yeap, we've found cypress, let's check config */
+			if (!pci_read_config_byte(cy693_dev, 0x47, &config)) {
+				
+				DEB3(printk("i2c-elektor.o: found cy82c693, config register 0x47 = 0x%02x.\n", config));
+
+				/* UP2000 board has this register set to 0xe1,
+                                   but the most significant bit as seems can be 
+				   reset during the proper initialisation
+                                   sequence if guys from API decides to do that
+                                   (so, we can even enable Tsunami Pchip
+                                   window for the upper 1 Gb) */
+
+				/* so just check for ROMCS at 0xe0000,
+                                   ROMCS enabled for writes
+				   and external XD Bus buffer in use. */
+				if ((config & 0x7f) == 0x61) {
+					/* seems to be UP2000 like board */
+					base = 0xe0000;
+                                        /* I don't know why we need to
+                                           write twice */
+					mmapped = 2;
+                                        /* UP2000 drives ISA with
+					   8.25 MHz (PCI/4) clock
+					   (this can be read from cypress) */
+					clock = I2C_PCF_CLK | I2C_PCF_TRNS90;
+					printk("i2c-elektor.o: found API UP2000 like board, will probe PCF8584 later.\n");
+				}
+			}
+		}
+	}
+#endif
 
-	struct i2c_pcf_isa *pisa = &gpi;
+	/* sanity checks for mmapped I/O */
+	if (mmapped && base < 0xc8000) {
+		printk("i2c-elektor.o: incorrect base address (0x%0X) specified for mmapped I/O.\n", base);
+		return -ENODEV;
+	}
 
 	printk("i2c-elektor.o: i2c pcf8584-isa adapter module\n");
-	if (base == 0)
-		pisa->pi_base = DEFAULT_BASE;
-	else
-		pisa->pi_base = base;
-
-	if (irq == 0)
-		pisa->pi_irq = DEFAULT_IRQ;
-	else
-		pisa->pi_irq = irq;
-
-	if (clock == 0)
-		pisa->pi_clock = DEFAULT_CLOCK;
-	else
-		pisa->pi_clock = clock;
-
-	if (own == 0)
-		pisa->pi_own = DEFAULT_OWN;
-	else
-		pisa->pi_own = own;
 
-	pcf_isa_data.data = (void *)pisa;
+	if (base == 0) {
+		base = DEFAULT_BASE;
+	}
+
 #if (LINUX_VERSION_CODE >= 0x020301)
 	init_waitqueue_head(&pcf_wait);
 #endif
@@ -267,7 +288,9 @@
 	} else {
 		return -ENODEV;
 	}
-	printk("i2c-elektor.o: found device at %#x.\n", pisa->pi_base);
+	
+	printk("i2c-elektor.o: found device at %#x.\n", base);
+
 	return 0;
 }
 
@@ -283,7 +306,8 @@
 MODULE_PARM(irq, "i");
 MODULE_PARM(clock, "i");
 MODULE_PARM(own, "i");
-MODULE_PARM(i2c_debug,"i");
+MODULE_PARM(mmapped, "i");
+MODULE_PARM(i2c_debug, "i");
 
 int init_module(void) 
 {
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/i2c-elv.c linux/drivers/i2c/i2c-elv.c
--- v2.4.12/linux/drivers/i2c/i2c-elv.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/i2c/i2c-elv.c	Thu Oct 11 08:05:47 2001
@@ -21,7 +21,7 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c-elv.c,v 1.16 2000/01/18 23:54:07 frodo Exp $ */
+/* $Id: i2c-elv.c,v 1.17 2001/07/29 02:44:25 mds Exp $ */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -115,7 +115,7 @@
 	return 0;
 }
 
-static void bit_elv_exit(void)
+static void __exit bit_elv_exit(void)
 {
 	release_region( base , (base == 0x3bc)? 3 : 8 );
 }
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/i2c-proc.c linux/drivers/i2c/i2c-proc.c
--- v2.4.12/linux/drivers/i2c/i2c-proc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2c/i2c-proc.c	Thu Oct 11 08:05:47 2001
@@ -0,0 +1,906 @@
+/*
+    i2c-proc.c - Part of lm_sensors, Linux kernel modules for hardware
+                monitoring
+    Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl> and
+    Mark D. Studebaker <mdsxyz123@yahoo.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    This driver puts entries in /proc/sys/dev/sensors for each I2C device
+*/
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-proc.h>
+
+#include <linux/init.h>
+
+/* FIXME need i2c versioning */
+#define LM_DATE "20010825"
+#define LM_VERSION "2.6.1"
+
+#ifndef THIS_MODULE
+#define THIS_MODULE NULL
+#endif
+
+static int i2c_create_name(char **name, const char *prefix,
+			       struct i2c_adapter *adapter, int addr);
+static int i2c_parse_reals(int *nrels, void *buffer, int bufsize,
+			       long *results, int magnitude);
+static int i2c_write_reals(int nrels, void *buffer, int *bufsize,
+			       long *results, int magnitude);
+static int i2c_proc_chips(ctl_table * ctl, int write,
+			      struct file *filp, void *buffer,
+			      size_t * lenp);
+static int i2c_sysctl_chips(ctl_table * table, int *name, int nlen,
+				void *oldval, size_t * oldlenp,
+				void *newval, size_t newlen,
+				void **context);
+
+int __init sensors_init(void);
+
+#define SENSORS_ENTRY_MAX 20
+static struct ctl_table_header *i2c_entries[SENSORS_ENTRY_MAX];
+
+static struct i2c_client *i2c_clients[SENSORS_ENTRY_MAX];
+static unsigned short i2c_inodes[SENSORS_ENTRY_MAX];
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+static void i2c_fill_inode(struct inode *inode, int fill);
+static void i2c_dir_fill_inode(struct inode *inode, int fill);
+#endif			/* LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1) */
+
+static ctl_table sysctl_table[] = {
+	{CTL_DEV, "dev", NULL, 0, 0555},
+	{0},
+	{DEV_SENSORS, "sensors", NULL, 0, 0555},
+	{0},
+	{0, NULL, NULL, 0, 0555},
+	{0}
+};
+
+static ctl_table i2c_proc_dev_sensors[] = {
+	{SENSORS_CHIPS, "chips", NULL, 0, 0644, NULL, &i2c_proc_chips,
+	 &i2c_sysctl_chips},
+	{0}
+};
+
+static ctl_table i2c_proc_dev[] = {
+	{DEV_SENSORS, "sensors", NULL, 0, 0555, i2c_proc_dev_sensors},
+	{0},
+};
+
+
+static ctl_table i2c_proc[] = {
+	{CTL_DEV, "dev", NULL, 0, 0555, i2c_proc_dev},
+	{0}
+};
+
+
+static struct ctl_table_header *i2c_proc_header;
+static int i2c_initialized;
+
+/* This returns a nice name for a new directory; for example lm78-isa-0310
+   (for a LM78 chip on the ISA bus at port 0x310), or lm75-i2c-3-4e (for
+   a LM75 chip on the third i2c bus at address 0x4e).  
+   name is allocated first. */
+int i2c_create_name(char **name, const char *prefix,
+			struct i2c_adapter *adapter, int addr)
+{
+	char name_buffer[50];
+	int id;
+	if (i2c_is_isa_adapter(adapter))
+		sprintf(name_buffer, "%s-isa-%04x", prefix, addr);
+	else {
+		if ((id = i2c_adapter_id(adapter)) < 0)
+			return -ENOENT;
+		sprintf(name_buffer, "%s-i2c-%d-%02x", prefix, id, addr);
+	}
+	*name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL);
+	strcpy(*name, name_buffer);
+	return 0;
+}
+
+/* This rather complex function must be called when you want to add an entry
+   to /proc/sys/dev/sensors/chips. It also creates a new directory within 
+   /proc/sys/dev/sensors/.
+   ctl_template should be a template of the newly created directory. It is
+   copied in memory. The extra2 field of each file is set to point to client.
+   If any driver wants subdirectories within the newly created directory,
+   this function must be updated! 
+   controlling_mod is the controlling module. It should usually be
+   THIS_MODULE when calling. Note that this symbol is not defined in
+   kernels before 2.3.13; define it to NULL in that case. We will not use it
+   for anything older than 2.3.27 anyway. */
+int i2c_register_entry(struct i2c_client *client, const char *prefix,
+			   ctl_table * ctl_template,
+			   struct module *controlling_mod)
+{
+	int i, res, len, id;
+	ctl_table *new_table;
+	char *name;
+	struct ctl_table_header *new_header;
+
+	if ((res = i2c_create_name(&name, prefix, client->adapter,
+				       client->addr))) return res;
+
+	for (id = 0; id < SENSORS_ENTRY_MAX; id++)
+		if (!i2c_entries[id]) {
+			break;
+		}
+	if (id == SENSORS_ENTRY_MAX) {
+		kfree(name);
+		return -ENOMEM;
+	}
+	id += 256;
+
+	len = 0;
+	while (ctl_template[len].procname)
+		len++;
+	len += 7;
+	if (!(new_table = kmalloc(sizeof(ctl_table) * len, GFP_KERNEL))) {
+		kfree(name);
+		return -ENOMEM;
+	}
+
+	memcpy(new_table, sysctl_table, 6 * sizeof(ctl_table));
+	new_table[0].child = &new_table[2];
+	new_table[2].child = &new_table[4];
+	new_table[4].child = &new_table[6];
+	new_table[4].procname = name;
+	new_table[4].ctl_name = id;
+	memcpy(new_table + 6, ctl_template, (len - 6) * sizeof(ctl_table));
+	for (i = 6; i < len; i++)
+		new_table[i].extra2 = client;
+
+	if (!(new_header = register_sysctl_table(new_table, 0))) {
+		kfree(new_table);
+		kfree(name);
+		return -ENOMEM;
+	}
+
+	i2c_entries[id - 256] = new_header;
+
+	i2c_clients[id - 256] = client;
+#ifdef DEBUG
+	if (!new_header || !new_header->ctl_table ||
+	    !new_header->ctl_table->child ||
+	    !new_header->ctl_table->child->child ||
+	    !new_header->ctl_table->child->child->de) {
+		printk
+		    ("i2c-proc.o: NULL pointer when trying to install fill_inode fix!\n");
+		return id;
+	}
+#endif				/* DEBUG */
+	i2c_inodes[id - 256] =
+	    new_header->ctl_table->child->child->de->low_ino;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))
+	new_header->ctl_table->child->child->de->owner = controlling_mod;
+#else
+	new_header->ctl_table->child->child->de->fill_inode =
+	    &i2c_dir_fill_inode;
+#endif	/* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) */
+
+	return id;
+}
+
+void i2c_deregister_entry(int id)
+{
+	ctl_table *table;
+	char *temp;
+	id -= 256;
+	if (i2c_entries[id]) {
+		table = i2c_entries[id]->ctl_table;
+		unregister_sysctl_table(i2c_entries[id]);
+		/* 2-step kfree needed to keep gcc happy about const points */
+		(const char *) temp = table[4].procname;
+		kfree(temp);
+		kfree(table);
+		i2c_entries[id] = NULL;
+		i2c_clients[id] = NULL;
+	}
+}
+
+/* Monitor access for /proc/sys/dev/sensors; make unloading i2c-proc.o 
+   impossible if some process still uses it or some file in it */
+void i2c_fill_inode(struct inode *inode, int fill)
+{
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
+}
+
+/* Monitor access for /proc/sys/dev/sensors/ directories; make unloading
+   the corresponding module impossible if some process still uses it or
+   some file in it */
+void i2c_dir_fill_inode(struct inode *inode, int fill)
+{
+	int i;
+	struct i2c_client *client;
+
+#ifdef DEBUG
+	if (!inode) {
+		printk("i2c-proc.o: Warning: inode NULL in fill_inode()\n");
+		return;
+	}
+#endif				/* def DEBUG */
+
+	for (i = 0; i < SENSORS_ENTRY_MAX; i++)
+		if (i2c_clients[i]
+		    && (i2c_inodes[i] == inode->i_ino)) break;
+#ifdef DEBUG
+	if (i == SENSORS_ENTRY_MAX) {
+		printk
+		    ("i2c-proc.o: Warning: inode (%ld) not found in fill_inode()\n",
+		     inode->i_ino);
+		return;
+	}
+#endif				/* def DEBUG */
+	client = i2c_clients[i];
+	if (fill)
+		client->driver->inc_use(client);
+	else
+		client->driver->dec_use(client);
+}
+
+int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp,
+		       void *buffer, size_t * lenp)
+{
+	char BUF[SENSORS_PREFIX_MAX + 30];
+	int buflen, curbufsize, i;
+	struct ctl_table *client_tbl;
+
+	if (write)
+		return 0;
+
+	/* If buffer is size 0, or we try to read when not at the start, we
+	   return nothing. Note that I think writing when not at the start
+	   does not work either, but anyway, this is straight from the kernel
+	   sources. */
+	if (!*lenp || (filp->f_pos && !write)) {
+		*lenp = 0;
+		return 0;
+	}
+	curbufsize = 0;
+	for (i = 0; i < SENSORS_ENTRY_MAX; i++)
+		if (i2c_entries[i]) {
+			client_tbl =
+			    i2c_entries[i]->ctl_table->child->child;
+			buflen =
+			    sprintf(BUF, "%d\t%s\n", client_tbl->ctl_name,
+				    client_tbl->procname);
+			if (buflen + curbufsize > *lenp)
+				buflen = *lenp - curbufsize;
+			if(copy_to_user(buffer, BUF, buflen))
+				return -EFAULT;
+			curbufsize += buflen;
+			(char *) buffer += buflen;
+		}
+	*lenp = curbufsize;
+	filp->f_pos += curbufsize;
+	return 0;
+}
+
+int i2c_sysctl_chips(ctl_table * table, int *name, int nlen,
+			 void *oldval, size_t * oldlenp, void *newval,
+			 size_t newlen, void **context)
+{
+	struct i2c_chips_data data;
+	int i, oldlen, nrels, maxels,ret=0;
+	struct ctl_table *client_tbl;
+
+	if (oldval && oldlenp && !((ret = get_user(oldlen, oldlenp))) && 
+	    oldlen) {
+		maxels = oldlen / sizeof(struct i2c_chips_data);
+		nrels = 0;
+		for (i = 0; (i < SENSORS_ENTRY_MAX) && (nrels < maxels);
+		     i++)
+			if (i2c_entries[i]) {
+				client_tbl =
+				    i2c_entries[i]->ctl_table->child->
+				    child;
+				data.sysctl_id = client_tbl->ctl_name;
+				strcpy(data.name, client_tbl->procname);
+				if(copy_to_user(oldval, &data,
+					     sizeof(struct
+						    i2c_chips_data)))
+					return -EFAULT;
+				(char *) oldval +=
+				    sizeof(struct i2c_chips_data);
+				nrels++;
+			}
+		oldlen = nrels * sizeof(struct i2c_chips_data);
+		if(put_user(oldlen, oldlenp))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+
+/* This funcion reads or writes a 'real' value (encoded by the combination
+   of an integer and a magnitude, the last is the power of ten the value
+   should be divided with) to a /proc/sys directory. To use this function,
+   you must (before registering the ctl_table) set the extra2 field to the
+   client, and the extra1 field to a function of the form:
+      void func(struct i2c_client *client, int operation, int ctl_name,
+                int *nrels_mag, long *results)
+   This function can be called for three values of operation. If operation
+   equals SENSORS_PROC_REAL_INFO, the magnitude should be returned in 
+   nrels_mag. If operation equals SENSORS_PROC_REAL_READ, values should
+   be read into results. nrels_mag should return the number of elements
+   read; the maximum number is put in it on entry. Finally, if operation
+   equals SENSORS_PROC_REAL_WRITE, the values in results should be
+   written to the chip. nrels_mag contains on entry the number of elements
+   found.
+   In all cases, client points to the client we wish to interact with,
+   and ctl_name is the SYSCTL id of the file we are accessing. */
+int i2c_proc_real(ctl_table * ctl, int write, struct file *filp,
+		      void *buffer, size_t * lenp)
+{
+#define MAX_RESULTS 32
+	int mag, nrels = MAX_RESULTS;
+	long results[MAX_RESULTS];
+	i2c_real_callback callback = ctl->extra1;
+	struct i2c_client *client = ctl->extra2;
+	int res;
+
+	/* If buffer is size 0, or we try to read when not at the start, we
+	   return nothing. Note that I think writing when not at the start
+	   does not work either, but anyway, this is straight from the kernel
+	   sources. */
+	if (!*lenp || (filp->f_pos && !write)) {
+		*lenp = 0;
+		return 0;
+	}
+
+	/* Get the magnitude */
+	callback(client, SENSORS_PROC_REAL_INFO, ctl->ctl_name, &mag,
+		 NULL);
+
+	if (write) {
+		/* Read the complete input into results, converting to longs */
+		res = i2c_parse_reals(&nrels, buffer, *lenp, results, mag);
+		if (res)
+			return res;
+
+		if (!nrels)
+			return 0;
+
+		/* Now feed this information back to the client */
+		callback(client, SENSORS_PROC_REAL_WRITE, ctl->ctl_name,
+			 &nrels, results);
+
+		filp->f_pos += *lenp;
+		return 0;
+	} else {		/* read */
+		/* Get the information from the client into results */
+		callback(client, SENSORS_PROC_REAL_READ, ctl->ctl_name,
+			 &nrels, results);
+
+		/* And write them to buffer, converting to reals */
+		res = i2c_write_reals(nrels, buffer, lenp, results, mag);
+		if (res)
+			return res;
+		filp->f_pos += *lenp;
+		return 0;
+	}
+}
+
+/* This function is equivalent to i2c_proc_real, only it interacts with
+   the sysctl(2) syscall, and returns no reals, but integers */
+int i2c_sysctl_real(ctl_table * table, int *name, int nlen,
+			void *oldval, size_t * oldlenp, void *newval,
+			size_t newlen, void **context)
+{
+	long results[MAX_RESULTS];
+	int oldlen, nrels = MAX_RESULTS,ret=0;
+	i2c_real_callback callback = table->extra1;
+	struct i2c_client *client = table->extra2;
+
+	/* Check if we need to output the old values */
+	if (oldval && oldlenp && !((ret=get_user(oldlen, oldlenp))) && oldlen) {
+		callback(client, SENSORS_PROC_REAL_READ, table->ctl_name,
+			 &nrels, results);
+
+		/* Note the rounding factor! */
+		if (nrels * sizeof(long) < oldlen)
+			oldlen = nrels * sizeof(long);
+		oldlen = (oldlen / sizeof(long)) * sizeof(long);
+		if(copy_to_user(oldval, results, oldlen))
+			return -EFAULT;
+		if(put_user(oldlen, oldlenp))
+			return -EFAULT;
+	}
+
+	if (newval && newlen) {
+		/* Note the rounding factor! */
+		newlen -= newlen % sizeof(long);
+		nrels = newlen / sizeof(long);
+		if(copy_from_user(results, newval, newlen))
+			return -EFAULT;
+
+		/* Get the new values back to the client */
+		callback(client, SENSORS_PROC_REAL_WRITE, table->ctl_name,
+			 &nrels, results);
+	}
+	return ret;
+}
+
+
+/* nrels contains initially the maximum number of elements which can be
+   put in results, and finally the number of elements actually put there.
+   A magnitude of 1 will multiply everything with 10; etc.
+   buffer, bufsize is the character buffer we read from and its length.
+   results will finally contain the parsed integers. 
+
+   Buffer should contain several reals, separated by whitespace. A real
+   has the following syntax:
+     [ Minus ] Digit* [ Dot Digit* ] 
+   (everything between [] is optional; * means zero or more).
+   When the next character is unparsable, everything is skipped until the
+   next whitespace.
+
+   WARNING! This is tricky code. I have tested it, but there may still be
+            hidden bugs in it, even leading to crashes and things!
+*/
+int i2c_parse_reals(int *nrels, void *buffer, int bufsize,
+			 long *results, int magnitude)
+{
+	int maxels, min, mag;
+	long res,ret=0;
+	char nextchar = 0;
+
+	maxels = *nrels;
+	*nrels = 0;
+
+	while (bufsize && (*nrels < maxels)) {
+
+		/* Skip spaces at the start */
+		while (bufsize && 
+		       !((ret=get_user(nextchar, (char *) buffer))) &&
+		       isspace((int) nextchar)) {
+			bufsize--;
+			((char *) buffer)++;
+		}
+
+		if (ret)
+			return -EFAULT;	
+		/* Well, we may be done now */
+		if (!bufsize)
+			return 0;
+
+		/* New defaults for our result */
+		min = 0;
+		res = 0;
+		mag = magnitude;
+
+		/* Check for a minus */
+		if (!((ret=get_user(nextchar, (char *) buffer)))
+		    && (nextchar == '-')) {
+			min = 1;
+			bufsize--;
+			((char *) buffer)++;
+		}
+		if (ret)
+			return -EFAULT;
+
+		/* Digits before a decimal dot */
+		while (bufsize && 
+		       !((ret=get_user(nextchar, (char *) buffer))) &&
+		       isdigit((int) nextchar)) {
+			res = res * 10 + nextchar - '0';
+			bufsize--;
+			((char *) buffer)++;
+		}
+		if (ret)
+			return -EFAULT;
+
+		/* If mag < 0, we must actually divide here! */
+		while (mag < 0) {
+			res = res / 10;
+			mag++;
+		}
+
+		if (bufsize && (nextchar == '.')) {
+			/* Skip the dot */
+			bufsize--;
+			((char *) buffer)++;
+
+			/* Read digits while they are significant */
+			while (bufsize && (mag > 0) &&
+			       !((ret=get_user(nextchar, (char *) buffer))) &&
+			       isdigit((int) nextchar)) {
+				res = res * 10 + nextchar - '0';
+				mag--;
+				bufsize--;
+				((char *) buffer)++;
+			}
+			if (ret)
+				return -EFAULT;
+		}
+		/* If we are out of data, but mag > 0, we need to scale here */
+		while (mag > 0) {
+			res = res * 10;
+			mag--;
+		}
+
+		/* Skip everything until we hit whitespace */
+		while (bufsize && 
+		       !((ret=get_user(nextchar, (char *) buffer))) &&
+		       isspace((int) nextchar)) {
+			bufsize--;
+			((char *) buffer)++;
+		}
+		if (ret)
+			return -EFAULT;
+
+		/* Put res in results */
+		results[*nrels] = (min ? -1 : 1) * res;
+		(*nrels)++;
+	}
+
+	/* Well, there may be more in the buffer, but we need no more data. 
+	   Ignore anything that is left. */
+	return 0;
+}
+
+int i2c_write_reals(int nrels, void *buffer, int *bufsize,
+			 long *results, int magnitude)
+{
+#define BUFLEN 20
+	char BUF[BUFLEN + 1];	/* An individual representation should fit! */
+	char printfstr[10];
+	int nr = 0;
+	int buflen, mag, times;
+	int curbufsize = 0;
+
+	while ((nr < nrels) && (curbufsize < *bufsize)) {
+		mag = magnitude;
+
+		if (nr != 0) {
+			if(put_user(' ', (char *) buffer))
+				return -EFAULT;
+			curbufsize++;
+			((char *) buffer)++;
+		}
+
+		/* Fill BUF with the representation of the next string */
+		if (mag <= 0) {
+			buflen = sprintf(BUF, "%ld", results[nr]);
+			if (buflen < 0) {	/* Oops, a sprintf error! */
+				*bufsize = 0;
+				return -EINVAL;
+			}
+			while ((mag < 0) && (buflen < BUFLEN)) {
+				BUF[buflen++] = '0';
+				mag++;
+			}
+			BUF[buflen] = 0;
+		} else {
+			times = 1;
+			for (times = 1; mag-- > 0; times *= 10);
+			if (results[nr] < 0) {
+				BUF[0] = '-';
+				buflen = 1;
+			} else
+				buflen = 0;
+			strcpy(printfstr, "%ld.%0Xld");
+			printfstr[6] = magnitude + '0';
+			buflen +=
+			    sprintf(BUF + buflen, printfstr,
+				    abs(results[nr]) / times,
+				    abs(results[nr]) % times);
+			if (buflen < 0) {	/* Oops, a sprintf error! */
+				*bufsize = 0;
+				return -EINVAL;
+			}
+		}
+
+		/* Now copy it to the user-space buffer */
+		if (buflen + curbufsize > *bufsize)
+			buflen = *bufsize - curbufsize;
+		if(copy_to_user(buffer, BUF, buflen))
+			return -EFAULT;
+		curbufsize += buflen;
+		(char *) buffer += buflen;
+
+		nr++;
+	}
+	if (curbufsize < *bufsize) {
+		if(put_user('\n', (char *) buffer))
+			return -EFAULT;
+		curbufsize++;
+	}
+	*bufsize = curbufsize;
+	return 0;
+}
+
+
+/* Very inefficient for ISA detects, and won't work for 10-bit addresses! */
+int i2c_detect(struct i2c_adapter *adapter,
+		   struct i2c_address_data *address_data,
+		   i2c_found_addr_proc * found_proc)
+{
+	int addr, i, found, j, err;
+	struct i2c_force_data *this_force;
+	int is_isa = i2c_is_isa_adapter(adapter);
+	int adapter_id =
+	    is_isa ? SENSORS_ISA_BUS : i2c_adapter_id(adapter);
+
+	/* Forget it if we can't probe using SMBUS_QUICK */
+	if ((!is_isa)
+	    && !i2c_check_functionality(adapter,
+					I2C_FUNC_SMBUS_QUICK)) return -1;
+
+	for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) {
+		if ((is_isa && check_region(addr, 1)) ||
+		    (!is_isa && i2c_check_addr(adapter, addr)))
+			continue;
+
+		/* If it is in one of the force entries, we don't do any
+		   detection at all */
+		found = 0;
+		for (i = 0;
+		     !found
+		     && (this_force =
+			 address_data->forces + i, this_force->force); i++) {
+			for (j = 0;
+			     !found
+			     && (this_force->force[j] != SENSORS_I2C_END);
+			     j += 2) {
+				if (
+				    ((adapter_id == this_force->force[j])
+				     ||
+				     ((this_force->
+				       force[j] == SENSORS_ANY_I2C_BUS)
+				      && !is_isa))
+				    && (addr == this_force->force[j + 1])) {
+#ifdef DEBUG
+					printk
+					    ("i2c-proc.o: found force parameter for adapter %d, addr %04x\n",
+					     adapter_id, addr);
+#endif
+					if (
+					    (err =
+					     found_proc(adapter, addr, 0,
+							this_force->
+							kind))) return err;
+					found = 1;
+				}
+			}
+		}
+		if (found)
+			continue;
+
+		/* If this address is in one of the ignores, we can forget about it
+		   right now */
+		for (i = 0;
+		     !found
+		     && (address_data->ignore[i] != SENSORS_I2C_END);
+		     i += 2) {
+			if (
+			    ((adapter_id == address_data->ignore[i])
+			     ||
+			     ((address_data->
+			       ignore[i] == SENSORS_ANY_I2C_BUS)
+			      && !is_isa))
+			    && (addr == address_data->ignore[i + 1])) {
+#ifdef DEBUG
+				printk
+				    ("i2c-proc.o: found ignore parameter for adapter %d, "
+				     "addr %04x\n", adapter_id, addr);
+#endif
+				found = 1;
+			}
+		}
+		for (i = 0;
+		     !found
+		     && (address_data->ignore_range[i] != SENSORS_I2C_END);
+		     i += 3) {
+			if (
+			    ((adapter_id == address_data->ignore_range[i])
+			     ||
+			     ((address_data->
+			       ignore_range[i] ==
+			       SENSORS_ANY_I2C_BUS) & !is_isa))
+			    && (addr >= address_data->ignore_range[i + 1])
+			    && (addr <= address_data->ignore_range[i + 2])) {
+#ifdef DEBUG
+				printk
+				    ("i2c-proc.o: found ignore_range parameter for adapter %d, "
+				     "addr %04x\n", adapter_id, addr);
+#endif
+				found = 1;
+			}
+		}
+		if (found)
+			continue;
+
+		/* Now, we will do a detection, but only if it is in the normal or 
+		   probe entries */
+		if (is_isa) {
+			for (i = 0;
+			     !found
+			     && (address_data->normal_isa[i] !=
+				 SENSORS_ISA_END); i += 1) {
+				if (addr == address_data->normal_isa[i]) {
+#ifdef DEBUG
+					printk
+					    ("i2c-proc.o: found normal isa entry for adapter %d, "
+					     "addr %04x\n", adapter_id,
+					     addr);
+#endif
+					found = 1;
+				}
+			}
+			for (i = 0;
+			     !found
+			     && (address_data->normal_isa_range[i] !=
+				 SENSORS_ISA_END); i += 3) {
+				if ((addr >=
+				     address_data->normal_isa_range[i])
+				    && (addr <=
+					address_data->normal_isa_range[i + 1])
+				    &&
+				    ((addr -
+				      address_data->normal_isa_range[i]) %
+				     address_data->normal_isa_range[i + 2] ==
+				     0)) {
+#ifdef DEBUG
+					printk
+					    ("i2c-proc.o: found normal isa_range entry for adapter %d, "
+					     "addr %04x", adapter_id, addr);
+#endif
+					found = 1;
+				}
+			}
+		} else {
+			for (i = 0;
+			     !found && (address_data->normal_i2c[i] !=
+				 SENSORS_I2C_END); i += 1) {
+				if (addr == address_data->normal_i2c[i]) {
+					found = 1;
+#ifdef DEBUG
+					printk
+					    ("i2c-proc.o: found normal i2c entry for adapter %d, "
+					     "addr %02x", adapter_id, addr);
+#endif
+				}
+			}
+			for (i = 0;
+			     !found
+			     && (address_data->normal_i2c_range[i] !=
+				 SENSORS_I2C_END); i += 2) {
+				if ((addr >=
+				     address_data->normal_i2c_range[i])
+				    && (addr <=
+					address_data->normal_i2c_range[i + 1]))
+				{
+#ifdef DEBUG
+					printk
+					    ("i2c-proc.o: found normal i2c_range entry for adapter %d, "
+					     "addr %04x\n", adapter_id, addr);
+#endif
+					found = 1;
+				}
+			}
+		}
+
+		for (i = 0;
+		     !found && (address_data->probe[i] != SENSORS_I2C_END);
+		     i += 2) {
+			if (((adapter_id == address_data->probe[i]) ||
+			     ((address_data->
+			       probe[i] == SENSORS_ANY_I2C_BUS) & !is_isa))
+			    && (addr == address_data->probe[i + 1])) {
+#ifdef DEBUG
+				printk
+				    ("i2c-proc.o: found probe parameter for adapter %d, "
+				     "addr %04x\n", adapter_id, addr);
+#endif
+				found = 1;
+			}
+		}
+		for (i = 0; !found &&
+		           (address_data->probe_range[i] != SENSORS_I2C_END);
+		     i += 3) {
+			if (
+			    ((adapter_id == address_data->probe_range[i])
+			     ||
+			     ((address_data->probe_range[i] ==
+			       SENSORS_ANY_I2C_BUS) & !is_isa))
+			    && (addr >= address_data->probe_range[i + 1])
+			    && (addr <= address_data->probe_range[i + 2])) {
+				found = 1;
+#ifdef DEBUG
+				printk
+				    ("i2c-proc.o: found probe_range parameter for adapter %d, "
+				     "addr %04x\n", adapter_id, addr);
+#endif
+			}
+		}
+		if (!found)
+			continue;
+
+		/* OK, so we really should examine this address. First check
+		   whether there is some client here at all! */
+		if (is_isa ||
+		    (i2c_smbus_xfer
+		     (adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) >= 0))
+			if ((err = found_proc(adapter, addr, 0, -1)))
+				return err;
+	}
+	return 0;
+}
+
+int __init sensors_init(void)
+{
+	printk("i2c-proc.o version %s (%s)\n", LM_VERSION, LM_DATE);
+	i2c_initialized = 0;
+	if (!
+	    (i2c_proc_header =
+	     register_sysctl_table(i2c_proc, 0))) return -ENOMEM;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1))
+	i2c_proc_header->ctl_table->child->de->owner = THIS_MODULE;
+#else
+	i2c_proc_header->ctl_table->child->de->fill_inode =
+	    &i2c_fill_inode;
+#endif			/* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)) */
+	i2c_initialized++;
+	return 0;
+}
+
+EXPORT_SYMBOL(i2c_deregister_entry);
+EXPORT_SYMBOL(i2c_detect);
+EXPORT_SYMBOL(i2c_proc_real);
+EXPORT_SYMBOL(i2c_register_entry);
+EXPORT_SYMBOL(i2c_sysctl_real);
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
+MODULE_DESCRIPTION("i2c-proc driver");
+MODULE_LICENSE("GPL");
+
+int i2c_cleanup(void)
+{
+	if (i2c_initialized >= 1) {
+		unregister_sysctl_table(i2c_proc_header);
+		i2c_initialized--;
+	}
+	return 0;
+}
+
+int init_module(void)
+{
+	return sensors_init();
+}
+
+int cleanup_module(void)
+{
+	return i2c_cleanup();
+}
+#endif				/* MODULE */
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/i2c-velleman.c linux/drivers/i2c/i2c-velleman.c
--- v2.4.12/linux/drivers/i2c/i2c-velleman.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/i2c/i2c-velleman.c	Thu Oct 11 08:05:47 2001
@@ -103,7 +103,7 @@
 	return 0;
 }
 
-static void bit_velle_exit(void)
+static void __exit bit_velle_exit(void)
 {	
 	release_region( base , (base == 0x3bc)? 3 : 8 );
 }
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/Config.in linux/drivers/i2o/Config.in
--- v2.4.12/linux/drivers/i2o/Config.in	Wed Apr 12 09:38:53 2000
+++ linux/drivers/i2o/Config.in	Wed Dec 31 16:00:00 1969
@@ -1,16 +0,0 @@
-mainmenu_option next_comment
-comment 'I2O device support'
-
-tristate 'I2O support' CONFIG_I2O
-
-if [ "$CONFIG_PCI" = "y" ]; then
-   dep_tristate '  I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O
-fi
-dep_tristate '  I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O
-if [ "$CONFIG_NET" = "y" ]; then
-   dep_tristate '  I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O
-fi
-dep_tristate '  I2O SCSI OSM' CONFIG_I2O_SCSI $CONFIG_I2O $CONFIG_SCSI
-dep_tristate '  I2O /proc support' CONFIG_I2O_PROC $CONFIG_I2O
-
-endmenu
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/Makefile linux/drivers/i2o/Makefile
--- v2.4.12/linux/drivers/i2o/Makefile	Fri Dec 29 14:07:21 2000
+++ linux/drivers/i2o/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-#
-# Makefile for the kernel I2O OSM.
-#
-# Note : at this point, these files are compiled on all systems.
-# In the future, some of these should be built conditionally.
-#
-
-O_TARGET := i2o.o
-
-export-objs	:= i2o_pci.o i2o_core.o i2o_config.o i2o_block.o i2o_lan.o i2o_scsi.o i2o_proc.o
-
-obj-$(CONFIG_I2O_PCI)	+= i2o_pci.o
-obj-$(CONFIG_I2O)	+= i2o_core.o i2o_config.o
-obj-$(CONFIG_I2O_BLOCK)	+= i2o_block.o
-obj-$(CONFIG_I2O_LAN)	+= i2o_lan.o
-obj-$(CONFIG_I2O_SCSI)	+= i2o_scsi.o
-obj-$(CONFIG_I2O_PROC)	+= i2o_proc.o
-
-include $(TOPDIR)/Rules.make
-
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/README linux/drivers/i2o/README
--- v2.4.12/linux/drivers/i2o/README	Mon Jun 19 13:30:55 2000
+++ linux/drivers/i2o/README	Wed Dec 31 16:00:00 1969
@@ -1,98 +0,0 @@
-
-	Linux I2O Support	(c) Copyright 1999 Red Hat Software
-					and others.
-
-	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.
-
-AUTHORS (so far)
-
-Alan Cox, Building Number Three Ltd.
-	Core code, SCSI and Block OSMs
-
-Steve Ralston, LSI Logic Corp.
-	Debugging SCSI and Block OSM
-
-Deepak Saxena, Intel Corp.
-	Various core/block extensions
-	/proc interface, bug fixes
-	Ioctl interfaces for control
-	Debugging LAN OSM
-
-Philip Rumpf
-	Fixed assorted dumb SMP locking bugs
-
-Juha Sievanen, University of Helsinki Finland
-	LAN OSM code
-	/proc interface to LAN class
-	Bug fixes
-	Core code extensions
-
-Auvo Häkkinen, University of Helsinki Finland
-	LAN OSM code
-	/Proc interface to LAN class
-	Bug fixes
-	Core code extensions
-
-Taneli Vähäkangas, University of Helsinki Finland
-	Fixes to i2o_config
-
-CREDITS
-
-	This work was made possible by 
-
-Red Hat Software
-	Funding for the Building #3 part of the project
-
-Symbios Logic (Now LSI)
-	Host adapters, hints, known to work platforms when I hit
-	compatibility problems
-
-BoxHill Corporation
-	Loan of initial FibreChannel disk array used for development work.
-
-European Comission
-	Funding the work done by the University of Helsinki
-
-SysKonnect
-        Loan of FDDI and Gigabit Ethernet cards
-
-ASUSTeK
-        Loan of I2O motherboard 
-
-STATUS:
-
-o	The core setup works within limits.
-o	The scsi layer seems to almost work. 
-           I'm still chasing down the hang bug.
-o	The block OSM is mostly functional
-o	LAN OSM works with FDDI and Ethernet cards.
-
-TO DO:
-
-General:
-o	Provide hidden address space if asked
-o	Long term message flow control
-o	PCI IOP's without interrupts are not supported yet
-o	Push FAIL handling into the core
-o	DDM control interfaces for module load etc
-o       Add I2O 2.0 support (Deffered to 2.5 kernel)
-
-Block:
-o	Multiple major numbers
-o	Read ahead and cache handling stuff. Talk to Ingo and people
-o	Power management
-o	Finish Media changers
-
-SCSI:
-o	Find the right way to associate drives/luns/busses
-
-Lan:	
-o	Performance tuning
-o	Test Fibre Channel code
-
-Tape:
-o	Anyone seen anything implementing this ?
-           (D.S: Will attempt to do so if spare cycles permit)
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/README.ioctl linux/drivers/i2o/README.ioctl
--- v2.4.12/linux/drivers/i2o/README.ioctl	Mon Jun 19 13:30:55 2000
+++ linux/drivers/i2o/README.ioctl	Wed Dec 31 16:00:00 1969
@@ -1,394 +0,0 @@
-
-Linux I2O User Space Interface
-rev 0.3 - 04/20/99
-
-=============================================================================
-Originally written by Deepak Saxena(deepak@plexity.net)
-Currently maintained by Deepak Saxena(deepak@plexity.net)
-=============================================================================
-
-I. Introduction
-
-The Linux I2O subsystem provides a set of ioctl() commands that can be
-utilized by user space applications to communicate with IOPs and devices
-on individual IOPs. This document defines the specific ioctl() commands
-that are available to the user and provides examples of their uses.
-
-This document assumes the reader is familiar with or has access to the 
-I2O specification as no I2O message parameters are outlined.  For information 
-on the specification, see http://www.i2osig.org
-
-This document and the I2O user space interface are currently maintained
-by Deepak Saxena.  Please send all comments, errata, and bug fixes to
-deepak@csociety.purdue.edu
-
-II. IOP Access
-
-Access to the I2O subsystem is provided through the device file named 
-/dev/i2o/ctl.  This file is a character file with major number 10 and minor
-number 166.  It can be created through the following command:
-
-   mknod /dev/i2o/ctl c 10 166
-
-III. Determining the IOP Count
-
-   SYNOPSIS 
-
-   ioctl(fd, I2OGETIOPS,  int *count);
-
-   u8 count[MAX_I2O_CONTROLLERS];
-
-   DESCRIPTION
-
-   This function returns the system's active IOP table.  count should
-   point to a buffer containing MAX_I2O_CONTROLLERS entries.  Upon 
-   returning, each entry will contain a non-zero value if the given
-   IOP unit is active, and NULL if it is inactive or non-existent.
-
-   RETURN VALUE.
-
-   Returns 0 if no errors occur, and -1 otherwise.  If an error occurs,
-   errno is set appropriately:
-
-     EFAULT   Invalid user space pointer was passed
-
-IV. Getting Hardware Resource Table
-
-   SYNOPSIS 
- 
-   ioctl(fd, I2OHRTGET, struct i2o_cmd_hrt *hrt);
-
-      struct i2o_cmd_hrtlct
-      {
-         u32   iop;      /* IOP unit number */
-         void  *resbuf;  /* Buffer for result */
-         u32   *reslen;  /* Buffer length in bytes */
-      };
-
-   DESCRIPTION
-
-   This function returns the Hardware Resource Table of the IOP specified 
-   by hrt->iop in the buffer pointed to by hrt->resbuf. The actual size of 
-   the data is written into *(hrt->reslen).
-
-   RETURNS
-
-   This function returns 0 if no errors occur. If an error occurs, -1 
-   is returned and errno is set appropriately:
-
-      EFAULT      Invalid user space pointer was passed
-      ENXIO       Invalid IOP number
-      ENOBUFS     Buffer not large enough.  If this occurs, the required
-                  buffer length is written into *(hrt->reslen)
-  
-V. Getting Logical Configuration Table
-   
-   SYNOPSIS 
- 
-   ioctl(fd, I2OLCTGET, struct i2o_cmd_lct *lct);
-
-      struct i2o_cmd_hrtlct
-      {
-         u32   iop;      /* IOP unit number */
-         void  *resbuf;  /* Buffer for result */
-         u32   *reslen;  /* Buffer length in bytes */
-      };
-
-   DESCRIPTION
-
-   This function returns the Logical Configuration Table of the IOP specified
-   by lct->iop in the buffer pointed to by lct->resbuf. The actual size of 
-   the data is written into *(lct->reslen).
-
-   RETURNS
-
-   This function returns 0 if no errors occur. If an error occurs, -1 
-   is returned and errno is set appropriately:
-
-      EFAULT      Invalid user space pointer was passed
-      ENXIO       Invalid IOP number
-      ENOBUFS     Buffer not large enough.  If this occurs, the required
-                  buffer length is written into *(lct->reslen)
-
-VI. Settting Parameters
-   
-   SYNOPSIS 
- 
-   ioctl(fd, I2OPARMSET, struct i2o_parm_setget *ops);
-
-      struct i2o_cmd_psetget
-      {
-         u32   iop;      /* IOP unit number */
-         u32   tid;      /* Target device TID */
-         void  *opbuf;   /* Operation List buffer */
-         u32   oplen;    /* Operation List buffer length in bytes */
-         void  *resbuf;  /* Result List buffer */
-         u32   *reslen;  /* Result List buffer length in bytes */
-      };
-
-   DESCRIPTION
-
-   This function posts a UtilParamsSet message to the device identified
-   by ops->iop and ops->tid.  The operation list for the message is 
-   sent through the ops->opbuf buffer, and the result list is written
-   into the buffer pointed to by ops->resbuf.  The number of bytes 
-   written is placed into *(ops->reslen). 
-
-   RETURNS
-
-   The return value is the size in bytes of the data written into
-   ops->resbuf if no errors occur.  If an error occurs, -1 is returned 
-   and errno is set appropriatly:
-
-      EFAULT      Invalid user space pointer was passed
-      ENXIO       Invalid IOP number
-      ENOBUFS     Buffer not large enough.  If this occurs, the required
-                  buffer length is written into *(ops->reslen)
-      ETIMEDOUT   Timeout waiting for reply message
-      ENOMEM      Kernel memory allocation error
-
-   A return value of 0 does not mean that the value was actually
-   changed properly on the IOP.  The user should check the result
-   list to determine the specific status of the transaction.
-
-VII. Getting Parameters
-   
-   SYNOPSIS 
- 
-   ioctl(fd, I2OPARMGET, struct i2o_parm_setget *ops);
-
-      struct i2o_parm_setget
-      {
-         u32   iop;      /* IOP unit number */
-         u32   tid;      /* Target device TID */
-         void  *opbuf;   /* Operation List buffer */
-         u32   oplen;    /* Operation List buffer length in bytes */
-         void  *resbuf;  /* Result List buffer */
-         u32   *reslen;  /* Result List buffer length in bytes */
-      };
-
-   DESCRIPTION
-
-   This function posts a UtilParamsGet message to the device identified
-   by ops->iop and ops->tid.  The operation list for the message is 
-   sent through the ops->opbuf buffer, and the result list is written
-   into the buffer pointed to by ops->resbuf.  The actual size of data
-   written is placed into *(ops->reslen).
-
-   RETURNS
-
-      EFAULT      Invalid user space pointer was passed
-      ENXIO       Invalid IOP number
-      ENOBUFS     Buffer not large enough.  If this occurs, the required
-                  buffer length is written into *(ops->reslen)
-      ETIMEDOUT   Timeout waiting for reply message
-      ENOMEM      Kernel memory allocation error
-
-   A return value of 0 does not mean that the value was actually
-   properly retreived.  The user should check the result list 
-   to determine the specific status of the transaction.
-
-VIII. Downloading Software
-   
-   SYNOPSIS 
- 
-   ioctl(fd, I2OSWDL, struct i2o_sw_xfer *sw);
-
-      struct i2o_sw_xfer
-      {
-         u32   iop;       /* IOP unit number */
-         u8    flags;     /* DownloadFlags field */
-         u8    sw_type;   /* Software type */
-         u32   sw_id;     /* Software ID */
-         void  *buf;      /* Pointer to software buffer */
-         u32   *swlen;    /* Length of software buffer */        
-         u32   *maxfrag;  /* Number of fragments */
-         u32   *curfrag;  /* Current fragment number */
-      };
-
-   DESCRIPTION
-
-   This function downloads a software fragment pointed by sw->buf
-   to the iop identified by sw->iop. The DownloadFlags, SwID, SwType
-   and SwSize fields of the ExecSwDownload message are filled in with
-   the values of sw->flags, sw->sw_id, sw->sw_type and *(sw->swlen).
-
-   The fragments _must_ be sent in order and be 8K in size. The last
-   fragment _may_ be shorter, however. The kernel will compute its
-   size based on information in the sw->swlen field.
-
-   Please note that SW transfers can take a long time.
-
-   RETURNS
-
-   This function returns 0 no errors occur. If an error occurs, -1 
-   is returned and errno is set appropriatly:
-
-      EFAULT      Invalid user space pointer was passed
-      ENXIO       Invalid IOP number
-      ETIMEDOUT   Timeout waiting for reply message
-      ENOMEM      Kernel memory allocation error
-
-IX. Uploading Software
-   
-   SYNOPSIS 
-
-   ioctl(fd, I2OSWUL, struct i2o_sw_xfer *sw);
-
-      struct i2o_sw_xfer
-      {
-         u32   iop;      /* IOP unit number */
-         u8    flags; 	 /* UploadFlags */
-         u8    sw_type;  /* Software type */
-         u32   sw_id;    /* Software ID */
-         void  *buf;     /* Pointer to software buffer */
-         u32   *swlen;   /* Length of software buffer */        
-         u32   *maxfrag; /* Number of fragments */
-         u32   *curfrag; /* Current fragment number */
-      };
-
-   DESCRIPTION
-
-   This function uploads a software fragment from the IOP identified
-   by sw->iop, sw->sw_type, sw->sw_id and optionally sw->swlen fields.
-   The UploadFlags, SwID, SwType and SwSize fields of the ExecSwUpload
-   message are filled in with the values of sw->flags, sw->sw_id,
-   sw->sw_type and *(sw->swlen).
-
-   The fragments _must_ be requested in order and be 8K in size. The
-   user is responsible for allocating memory pointed by sw->buf. The
-   last fragment _may_ be shorter.
-
-   Please note that SW transfers can take a long time.
-
-   RETURNS
-
-   This function returns 0 if no errors occur.  If an error occurs, -1
-   is returned and errno is set appropriatly:
-
-      EFAULT      Invalid user space pointer was passed
-      ENXIO       Invalid IOP number
-      ETIMEDOUT   Timeout waiting for reply message
-      ENOMEM      Kernel memory allocation error
-         
-X. Removing Software
-   
-   SYNOPSIS 
- 
-   ioctl(fd, I2OSWDEL, struct i2o_sw_xfer *sw);
-
-      struct i2o_sw_xfer
-      {
-         u32   iop;      /* IOP unit number */
-         u8    flags; 	 /* RemoveFlags */
-         u8    sw_type;  /* Software type */
-         u32   sw_id;    /* Software ID */
-         void  *buf;     /* Unused */
-         u32   *swlen;   /* Length of the software data */        
-         u32   *maxfrag; /* Unused */
-         u32   *curfrag; /* Unused */
-      };
-
-   DESCRIPTION
-
-   This function removes software from the IOP identified by sw->iop.
-   The RemoveFlags, SwID, SwType and SwSize fields of the ExecSwRemove message 
-   are filled in with the values of sw->flags, sw->sw_id, sw->sw_type and 
-   *(sw->swlen). Give zero in *(sw->len) if the value is unknown. IOP uses 
-   *(sw->swlen) value to verify correct identication of the module to remove. 
-   The actual size of the module is written into *(sw->swlen).
-
-   RETURNS
-
-   This function returns 0 if no errors occur.  If an error occurs, -1
-   is returned and errno is set appropriatly:
-
-      EFAULT      Invalid user space pointer was passed
-      ENXIO       Invalid IOP number
-      ETIMEDOUT   Timeout waiting for reply message
-      ENOMEM      Kernel memory allocation error
-
-X. Validating Configuration
-
-   SYNOPSIS
-
-   ioctl(fd, I2OVALIDATE, int *iop);
-	u32 iop;
-
-   DESCRIPTION
-
-   This function posts an ExecConfigValidate message to the controller
-   identified by iop. This message indicates that the the current
-   configuration is accepted. The iop changes the status of suspect drivers 
-   to valid and may delete old drivers from its store.
-
-   RETURNS
-
-   This function returns 0 if no erro occur.  If an error occurs, -1 is
-   returned and errno is set appropriatly:
-
-      ETIMEDOUT   Timeout waiting for reply message
-      ENXIO       Invalid IOP number
-
-XI. Configuration Dialog
-   
-   SYNOPSIS 
- 
-   ioctl(fd, I2OHTML, struct i2o_html *htquery);
-      struct i2o_html
-      {
-         u32   iop;      /* IOP unit number */
-         u32   tid;      /* Target device ID */
-         u32   page;     /* HTML page */
-         void  *resbuf;  /* Buffer for reply HTML page */
-         u32   *reslen;  /* Length in bytes of reply buffer */
-         void  *qbuf;    /* Pointer to HTTP query string */
-         u32   qlen;     /* Length in bytes of query string buffer */        
-      };
-
-   DESCRIPTION
-
-   This function posts an UtilConfigDialog message to the device identified
-   by htquery->iop and htquery->tid.  The requested HTML page number is 
-   provided by the htquery->page field, and the resultant data is stored 
-   in the buffer pointed to by htquery->resbuf.  If there is an HTTP query 
-   string that is to be sent to the device, it should be sent in the buffer
-   pointed to by htquery->qbuf.  If there is no query string, this field
-   should be set to NULL. The actual size of the reply received is written
-   into *(htquery->reslen).
-  
-   RETURNS
-
-   This function returns 0 if no error occur. If an error occurs, -1
-   is returned and errno is set appropriatly:
-
-      EFAULT      Invalid user space pointer was passed
-      ENXIO       Invalid IOP number
-      ENOBUFS     Buffer not large enough.  If this occurs, the required
-                  buffer length is written into *(ops->reslen)
-      ETIMEDOUT   Timeout waiting for reply message
-      ENOMEM      Kernel memory allocation error
-
-XII. Events
-
-    In the process of determining this.  Current idea is to have use
-    the select() interface to allow user apps to periodically poll
-    the /dev/i2o/ctl device for events.  When select() notifies the user
-    that an event is available, the user would call read() to retrieve
-    a list of all the events that are pending for the specific device.
-
-=============================================================================
-Revision History
-=============================================================================
-
-Rev 0.1 - 04/01/99
-- Initial revision
-
-Rev 0.2 - 04/06/99
-- Changed return values to match UNIX ioctl() standard.  Only return values
-  are 0 and -1.  All errors are reported through errno.
-- Added summary of proposed possible event interfaces
-
-Rev 0.3 - 04/20/99
-- Changed all ioctls() to use pointers to user data instead of actual data
-- Updated error values to match the code
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c
--- v2.4.12/linux/drivers/i2o/i2o_block.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/i2o/i2o_block.c	Wed Dec 31 16:00:00 1969
@@ -1,2051 +0,0 @@
-/*
- * I2O Random Block Storage Class OSM
- *
- * (C) Copyright 1999 Red Hat Software
- *	
- * Written by Alan Cox, Building Number Three Ltd
- *
- * 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 is a beta test release. Most of the good code was taken
- * from the nbd driver by Pavel Machek, who in turn took some of it
- * from loop.c. Isn't free software great for reusability 8)
- *
- * Fixes/additions:
- *	Steve Ralston:	
- *		Multiple device handling error fixes,
- *		Added a queue depth.
- *	Alan Cox:	
- *		FC920 has an rmw bug. Dont or in the end marker.
- *		Removed queue walk, fixed for 64bitness.
- *	Deepak Saxena:
- *		Independent queues per IOP
- *		Support for dynamic device creation/deletion
- *		Code cleanup	
- *    		Support for larger I/Os through merge* functions 
- *       	(taken from DAC960 driver)
- *	Boji T Kannanthanam:
- *		Set the I2O Block devices to be detected in increasing 
- *		order of TIDs during boot.
- *		Search and set the I2O block device that we boot off from  as
- *		the first device to be claimed (as /dev/i2o/hda)
- *		Properly attach/detach I2O gendisk structure from the system
- *		gendisk list. The I2O block devices now appear in 
- * 		/proc/partitions.
- *
- *	To do:
- *		Serial number scanning to find duplicates for FC multipathing
- */
-
-#include <linux/major.h>
-
-#include <linux/module.h>
-
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/file.h>
-#include <linux/ioctl.h>
-#include <linux/i2o.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/slab.h>
-#include <linux/hdreg.h>
-
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-
-#include <asm/uaccess.h>
-#include <asm/semaphore.h>
-#include <linux/completion.h>
-#include <asm/io.h>
-#include <asm/atomic.h>
-#include <linux/smp_lock.h>
-#include <linux/wait.h>
-
-#define MAJOR_NR I2O_MAJOR
-
-#include <linux/blk.h>
-
-#define MAX_I2OB	16
-
-#define MAX_I2OB_DEPTH	128
-#define MAX_I2OB_RETRIES 4
-
-//#define DRIVERDEBUG
-#ifdef DRIVERDEBUG
-#define DEBUG( s )
-#else
-#define DEBUG( s ) printk( s ) 
-#endif
-
-/*
- * Events that this OSM is interested in
- */
-#define I2OB_EVENT_MASK		(I2O_EVT_IND_BSA_VOLUME_LOAD |	\
-				 I2O_EVT_IND_BSA_VOLUME_UNLOAD | \
-				 I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ | \
-				 I2O_EVT_IND_BSA_CAPACITY_CHANGE | \
-				 I2O_EVT_IND_BSA_SCSI_SMART )
-
-
-/*
- * I2O Block Error Codes - should be in a header file really...
- */
-#define I2O_BSA_DSC_SUCCESS             0x0000
-#define I2O_BSA_DSC_MEDIA_ERROR         0x0001
-#define I2O_BSA_DSC_ACCESS_ERROR        0x0002
-#define I2O_BSA_DSC_DEVICE_FAILURE      0x0003
-#define I2O_BSA_DSC_DEVICE_NOT_READY    0x0004
-#define I2O_BSA_DSC_MEDIA_NOT_PRESENT   0x0005
-#define I2O_BSA_DSC_MEDIA_LOCKED        0x0006
-#define I2O_BSA_DSC_MEDIA_FAILURE       0x0007
-#define I2O_BSA_DSC_PROTOCOL_FAILURE    0x0008
-#define I2O_BSA_DSC_BUS_FAILURE         0x0009
-#define I2O_BSA_DSC_ACCESS_VIOLATION    0x000A
-#define I2O_BSA_DSC_WRITE_PROTECTED     0x000B
-#define I2O_BSA_DSC_DEVICE_RESET        0x000C
-#define I2O_BSA_DSC_VOLUME_CHANGED      0x000D
-#define I2O_BSA_DSC_TIMEOUT             0x000E
-
-/*
- *	Some of these can be made smaller later
- */
-
-static int i2ob_blksizes[MAX_I2OB<<4];
-static int i2ob_hardsizes[MAX_I2OB<<4];
-static int i2ob_sizes[MAX_I2OB<<4];
-static int i2ob_media_change_flag[MAX_I2OB];
-static u32 i2ob_max_sectors[MAX_I2OB<<4];
-
-static int i2ob_context;
-
-/*
- * I2O Block device descriptor 
- */
-struct i2ob_device
-{
-	struct i2o_controller *controller;
-	struct i2o_device *i2odev;
-	int unit;
-	int tid;
-	int flags;
-	int refcnt;
-	struct request *head, *tail;
-	request_queue_t *req_queue;
-	int max_segments;
-	int done_flag;
-	int constipated;
-	int depth;
-};
-
-/*
- *	FIXME:
- *	We should cache align these to avoid ping-ponging lines on SMP
- *	boxes under heavy I/O load...
- */
-struct i2ob_request
-{
-	struct i2ob_request *next;
-	struct request *req;
-	int num;
-};
-
-/*
- * Per IOP requst queue information
- *
- * We have a separate requeust_queue_t per IOP so that a heavilly
- * loaded I2O block device on an IOP does not starve block devices
- * across all I2O controllers.
- * 
- */
-struct i2ob_iop_queue
-{
-	atomic_t queue_depth;
-	struct i2ob_request request_queue[MAX_I2OB_DEPTH];
-	struct i2ob_request *i2ob_qhead;
-	request_queue_t req_queue;
-};
-static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS];
-static struct i2ob_request *i2ob_backlog[MAX_I2O_CONTROLLERS];
-static struct i2ob_request *i2ob_backlog_tail[MAX_I2O_CONTROLLERS];
-
-/*
- *	Each I2O disk is one of these.
- */
-
-static struct i2ob_device i2ob_dev[MAX_I2OB<<4];
-static int i2ob_dev_count = 0;
-static struct hd_struct i2ob[MAX_I2OB<<4];
-static struct gendisk i2ob_gendisk;	/* Declared later */
-
-/*
- * Mutex and spin lock for event handling synchronization
- * evt_msg contains the last event.
- */
-static DECLARE_MUTEX_LOCKED(i2ob_evt_sem);
-static DECLARE_COMPLETION(i2ob_thread_dead);
-static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED;
-static u32 evt_msg[MSG_FRAME_SIZE>>2];
-
-static struct timer_list i2ob_timer;
-static int i2ob_timer_started = 0;
-
-static void i2o_block_reply(struct i2o_handler *, struct i2o_controller *,
-	 struct i2o_message *);
-static void i2ob_new_device(struct i2o_controller *, struct i2o_device *);
-static void i2ob_del_device(struct i2o_controller *, struct i2o_device *);
-static void i2ob_reboot_event(void);
-static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int);
-static void i2ob_end_request(struct request *);
-static void i2ob_request(request_queue_t *);
-static int i2ob_backlog_request(struct i2o_controller *, struct i2ob_device *);
-static int i2ob_init_iop(unsigned int);
-static request_queue_t* i2ob_get_queue(kdev_t);
-static int i2ob_query_device(struct i2ob_device *, int, int, void*, int);
-static int do_i2ob_revalidate(kdev_t, int);
-static int i2ob_evt(void *);
-
-static int evt_pid = 0;
-static int evt_running = 0;
-static int scan_unit = 0;
-
-/*
- * I2O OSM registration structure...keeps getting bigger and bigger :)
- */
-static struct i2o_handler i2o_block_handler =
-{
-	i2o_block_reply,
-	i2ob_new_device,
-	i2ob_del_device,
-	i2ob_reboot_event,
-	"I2O Block OSM",
-	0,
-	I2O_CLASS_RANDOM_BLOCK_STORAGE
-};
-
-/*
- *	Get a message
- */
-
-static u32 i2ob_get(struct i2ob_device *dev)
-{
-	struct i2o_controller *c=dev->controller;
-   	return I2O_POST_READ32(c);
-}
- 
-/*
- *	Turn a Linux block request into an I2O block read/write.
- */
-
-static int i2ob_send(u32 m, struct i2ob_device *dev, struct i2ob_request *ireq, u32 base, int unit)
-{
-	struct i2o_controller *c = dev->controller;
-	int tid = dev->tid;
-	unsigned long msg;
-	unsigned long mptr;
-	u64 offset;
-	struct request *req = ireq->req;
-	struct buffer_head *bh = req->bh;
-	int count = req->nr_sectors<<9;
-	char *last = NULL;
-	unsigned short size = 0;
-
-	// printk(KERN_INFO "i2ob_send called\n");
-	/* Map the message to a virtual address */
-	msg = c->mem_offset + m;
-	
-	/*
-	 * Build the message based on the request.
-	 */
-	__raw_writel(i2ob_context|(unit<<8), msg+8);
-	__raw_writel(ireq->num, msg+12);
-	__raw_writel(req->nr_sectors << 9, msg+20);
-
-	/* 
-	 * Mask out partitions from now on
-	 */
-	unit &= 0xF0;
-		
-	/* This can be optimised later - just want to be sure its right for
-	   starters */
-	offset = ((u64)(req->sector+base)) << 9;
-	__raw_writel( offset & 0xFFFFFFFF, msg+24);
-	__raw_writel(offset>>32, msg+28);
-	mptr=msg+32;
-	
-	if(req->cmd == READ)
-	{
-		__raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4);
-		while(bh!=NULL)
-		{
-			if(bh->b_data == last) {
-				size += bh->b_size;
-				last += bh->b_size;
-				if(bh->b_reqnext)
-					__raw_writel(0x14000000|(size), mptr-8);
-				else
-					__raw_writel(0xD4000000|(size), mptr-8);
-			}
-			else
-			{
-				if(bh->b_reqnext)
-					__raw_writel(0x10000000|(bh->b_size), mptr);
-				else
-					__raw_writel(0xD0000000|(bh->b_size), mptr);
-				__raw_writel(virt_to_bus(bh->b_data), mptr+4);
-				mptr += 8;	
-				size = bh->b_size;
-				last = bh->b_data + size;
-			}
-
-			count -= bh->b_size;
-			bh = bh->b_reqnext;
-		}
-		/*
-		 *	Heuristic for now since the block layer doesnt give
-		 *	us enough info. If its a big write assume sequential
-		 *	readahead on controller. If its small then don't read
-		 *	ahead but do use the controller cache.
-		 */
-		if(size >= 8192)
-			__raw_writel((8<<24)|(1<<16)|8, msg+16);
-		else
-			__raw_writel((8<<24)|(1<<16)|4, msg+16);
-	}
-	else if(req->cmd == WRITE)
-	{
-		__raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4);
-		while(bh!=NULL)
-		{
-			if(bh->b_data == last) {
-				size += bh->b_size;
-				last += bh->b_size;
-				if(bh->b_reqnext)
-					__raw_writel(0x14000000|(size), mptr-8);
-				else
-					__raw_writel(0xD4000000|(size), mptr-8);
-			}
-			else
-			{
-				if(bh->b_reqnext)
-					__raw_writel(0x14000000|(bh->b_size), mptr);
-				else
-					__raw_writel(0xD4000000|(bh->b_size), mptr);
-				__raw_writel(virt_to_bus(bh->b_data), mptr+4);
-				mptr += 8;	
-				size = bh->b_size;
-				last = bh->b_data + size;
-			}
-
-			count -= bh->b_size;
-			bh = bh->b_reqnext;
-		}
-
-		if(c->battery)
-		{
-			
-			if(size>16384)
-				__raw_writel(4, msg+16);
-			else
-				/* 
-				 * Allow replies to come back once data is cached in the controller
-				 * This allows us to handle writes quickly thus giving more of the
-				 * queue to reads.
-				 */
-				__raw_writel(16, msg+16);
-		}
-		else
-		{
-			/* Large write, don't cache */
-			if(size>8192)
-				__raw_writel(4, msg+16);
-			else
-			/* write through */
-				__raw_writel(8, msg+16);
-		}
-	}
-	__raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg);
-	
-	if(count != 0)
-	{
-		printk(KERN_ERR "Request count botched by %d.\n", count);
-	}
-
-	i2o_post_message(c,m);
-	atomic_inc(&i2ob_queues[c->unit]->queue_depth);
-
-	return 0;
-}
-
-/*
- *	Remove a request from the _locked_ request list. We update both the
- *	list chain and if this is the last item the tail pointer. Caller
- *	must hold the lock.
- */
- 
-static inline void i2ob_unhook_request(struct i2ob_request *ireq, 
-	unsigned int iop)
-{
-	ireq->next = i2ob_queues[iop]->i2ob_qhead;
-	i2ob_queues[iop]->i2ob_qhead = ireq;
-}
-
-/*
- *	Request completion handler
- */
- 
-static inline void i2ob_end_request(struct request *req)
-{
-	/*
-	 * Loop until all of the buffers that are linked
-	 * to this request have been marked updated and
-	 * unlocked.
-	 */
-
-	while (end_that_request_first( req, !req->errors, "i2o block" ));
-
-	/*
-	 * It is now ok to complete the request.
-	 */
-	end_that_request_last( req );
-}
-
-/*
- * Request merging functions
- */
-static inline int i2ob_new_segment(request_queue_t *q, struct request *req,
-				  int __max_segments)
-{
-	int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments;
-
-	if (__max_segments < max_segments)
-		max_segments = __max_segments;
-
-	if (req->nr_segments < max_segments) {
-		req->nr_segments++;
-		return 1;
-	}
-	return 0;
-}
-
-static int i2ob_back_merge(request_queue_t *q, struct request *req, 
-			     struct buffer_head *bh, int __max_segments)
-{
-	if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data)
-		return 1;
-	return i2ob_new_segment(q, req, __max_segments);
-}
-
-static int i2ob_front_merge(request_queue_t *q, struct request *req, 
-			      struct buffer_head *bh, int __max_segments)
-{
-	if (bh->b_data + bh->b_size == req->bh->b_data)
-		return 1;
-	return i2ob_new_segment(q, req, __max_segments);
-}
-
-static int i2ob_merge_requests(request_queue_t *q,
-				struct request *req,
-				struct request *next,
-				int __max_segments)
-{
-	int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments;
-	int total_segments = req->nr_segments + next->nr_segments;
-
-	if (__max_segments < max_segments)
-		max_segments = __max_segments;
-
-	if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
-		total_segments--;
-    
-	if (total_segments > max_segments)
-		return 0;
-
-	req->nr_segments = total_segments;
-	return 1;
-}
-
-static int i2ob_flush(struct i2o_controller *c, struct i2ob_device *d, int unit)
-{
-	unsigned long msg;
-	u32 m = i2ob_get(d);
-	
-	if(m == 0xFFFFFFFF)
-		return -1;
-		
-	msg = c->mem_offset + m;
-
-	/*
-	 *	Ask the controller to write the cache back. This sorts out
-	 *	the supertrak firmware flaw and also does roughly the right
-	 *	thing for other cases too.
-	 */
-	 	
-	__raw_writel(FIVE_WORD_MSG_SIZE|SGL_OFFSET_0, msg);
-	__raw_writel(I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|d->tid, msg+4);
-	__raw_writel(i2ob_context|(unit<<8), msg+8);
-	__raw_writel(0, msg+12);
-	__raw_writel(60<<16, msg+16);
-	
-	i2o_post_message(c,m);
-	return 0;
-}
-			
-/*
- *	OSM reply handler. This gets all the message replies
- */
-
-static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
-{
-	unsigned long flags;
-	struct i2ob_request *ireq = NULL;
-	u8 st;
-	u32 *m = (u32 *)msg;
-	u8 unit = (m[2]>>8)&0xF0;	/* low 4 bits are partition */
-	struct i2ob_device *dev = &i2ob_dev[(unit&0xF0)];
-	
-	/*
-	 * FAILed message
-	 */
-	if(m[0] & (1<<13))
-	{
-		/*
-		 * FAILed message from controller
-		 * We increment the error count and abort it
-		 *
-		 * In theory this will never happen.  The I2O block class
-		 * speficiation states that block devices never return
-		 * FAILs but instead use the REQ status field...but
-		 * better be on the safe side since no one really follows
-		 * the spec to the book :)
-		 */
-		ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
-		ireq->req->errors++;
-
-		spin_lock_irqsave(&io_request_lock, flags);
-		i2ob_unhook_request(ireq, c->unit);
-		i2ob_end_request(ireq->req);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-	
-		/* Now flush the message by making it a NOP */
-		m[0]&=0x00FFFFFF;
-		m[0]|=(I2O_CMD_UTIL_NOP)<<24;
-		i2o_post_message(c,virt_to_bus(m));
-
-		return;
-	}
-
-	if(msg->function == I2O_CMD_UTIL_EVT_REGISTER)
-	{
-		spin_lock(&i2ob_evt_lock);
-		memcpy(evt_msg, msg, (m[0]>>16)<<2);
-		spin_unlock(&i2ob_evt_lock);
-		up(&i2ob_evt_sem);
-		return;
-	}
-
-	if(msg->function == I2O_CMD_BLOCK_CFLUSH)
-	{
-		spin_lock_irqsave(&io_request_lock, flags);
-		dev->constipated=0;
-		DEBUG(("unconstipated\n"));
-		if(i2ob_backlog_request(c, dev)==0)
-			i2ob_request(dev->req_queue);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-
-	if(!dev->i2odev)
-	{
-		/*
-		 * This is HACK, but Intel Integrated RAID allows user
-		 * to delete a volume that is claimed, locked, and in use 
-		 * by the OS. We have to check for a reply from a
-		 * non-existent device and flag it as an error or the system 
-		 * goes kaput...
-		 */
-		ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
-		ireq->req->errors++;
-		printk(KERN_WARNING "I2O Block: Data transfer to deleted device!\n");
-		spin_lock_irqsave(&io_request_lock, flags);
-		i2ob_unhook_request(ireq, c->unit);
-		i2ob_end_request(ireq->req);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}	
-
-	/*
-	 *	Lets see what is cooking. We stuffed the
-	 *	request in the context.
-	 */
-		 
-	ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
-	st=m[4]>>24;
-
-	if(st!=0)
-	{
-		int err;
-		char *bsa_errors[] = 
-		{ 
-			"Success", 
-			"Media Error", 
-			"Failure communicating to device",
-			"Device Failure",
-			"Device is not ready",
-			"Media not present",
-			"Media is locked by another user",
-			"Media has failed",
-			"Failure communicating to device",
-			"Device bus failure",
-			"Device is locked by another user",
-			"Device is write protected",
-			"Device has reset",
-			"Volume has changed, waiting for acknowledgement"
-		};
-				
-		err = m[4]&0xFFFF;
-		
-		/*
-		 *	Device not ready means two things. One is that the
-		 *	the thing went offline (but not a removal media)
-		 *
-		 *	The second is that you have a SuperTrak 100 and the
-		 *	firmware got constipated. Unlike standard i2o card
-		 *	setups the supertrak returns an error rather than
-		 *	blocking for the timeout in these cases.
-		 */
-		 
-		
-		spin_lock_irqsave(&io_request_lock, flags);
-		if(err==4)
-		{
-			/*
-			 *	Time to uncork stuff
-			 */
-			
-			if(!dev->constipated)
-			{
-				dev->constipated = 1;
-				DEBUG(("constipated\n"));
-				/* Now pull the chain */
-				if(i2ob_flush(c, dev, unit)<0)
-				{
-					DEBUG(("i2ob: Unable to queue flush. Retrying I/O immediately.\n"));
-					dev->constipated=0;
-				}
-				DEBUG(("flushing\n"));
-			}
-			
-			/*
-			 *	Recycle the request
-			 */
-			 
-//			i2ob_unhook_request(ireq, c->unit);
-			
-			/*
-			 *	Place it on the recycle queue
-			 */
-			 
-			ireq->next = NULL;
-			if(i2ob_backlog_tail[c->unit]!=NULL)
-				i2ob_backlog_tail[c->unit]->next = ireq;
-			else
-				i2ob_backlog[c->unit] = ireq;			
-			i2ob_backlog_tail[c->unit] = ireq;
-			
-			atomic_dec(&i2ob_queues[c->unit]->queue_depth);
-
-			/*
-			 *	If the constipator flush failed we want to
-			 *	poke the queue again. 
-			 */
-			 
-			i2ob_request(dev->req_queue);
-			spin_unlock_irqrestore(&io_request_lock, flags);
-			
-			/*
-			 *	and out
-			 */
-			 
-			return;	
-		}
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, 
-			bsa_errors[m[4]&0XFFFF]);
-		if(m[4]&0x00FF0000)
-			printk(" - DDM attempted %d retries", (m[4]>>16)&0x00FF );
-		printk(".\n");
-		ireq->req->errors++;	
-	}
-	else
-		ireq->req->errors = 0;
-
-	/*
-	 *	Dequeue the request. We use irqsave locks as one day we
-	 *	may be running polled controllers from a BH...
-	 */
-	
-	spin_lock_irqsave(&io_request_lock, flags);
-	i2ob_unhook_request(ireq, c->unit);
-	i2ob_end_request(ireq->req);
-	atomic_dec(&i2ob_queues[c->unit]->queue_depth);
-
-	/*
-	 *	We may be able to do more I/O
-	 */
-
-	if(i2ob_backlog_request(c, dev)==0)
-		i2ob_request(dev->req_queue);
-
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/* 
- * Event handler.  Needs to be a separate thread b/c we may have
- * to do things like scan a partition table, or query parameters
- * which cannot be done from an interrupt or from a bottom half.
- */
-static int i2ob_evt(void *dummy)
-{
-	unsigned int evt;
-	unsigned long flags;
-	int unit;
-	int i;
-	//The only event that has data is the SCSI_SMART event.
-	struct i2o_reply {
-		u32 header[4];
-		u32 evt_indicator;
-		u8 ASC;
-		u8 ASCQ;
-		u8 data[16];
-		} *evt_local;
-
-	lock_kernel();
-	daemonize();
-	unlock_kernel();
-
-	strcpy(current->comm, "i2oblock");
-	evt_running = 1;
-
-	while(1)
-	{
-		if(down_interruptible(&i2ob_evt_sem))
-		{
-			evt_running = 0;
-			printk("exiting...");
-			break;
-		}
-
-		/*
-		 * Keep another CPU/interrupt from overwriting the 
-		 * message while we're reading it
-		 *
-		 * We stuffed the unit in the TxContext and grab the event mask
-		 * None of the BSA we care about events have EventData
-		 */
-		spin_lock_irqsave(&i2ob_evt_lock, flags);
-		evt_local = (struct i2o_reply *)evt_msg;
-		spin_unlock_irqrestore(&i2ob_evt_lock, flags);
-
-		unit = evt_local->header[3];
-		evt = evt_local->evt_indicator;
-
-		switch(evt)
-		{
-			/*
-			 * New volume loaded on same TID, so we just re-install.
-			 * The TID/controller don't change as it is the same
-			 * I2O device.  It's just new media that we have to
-			 * rescan.
-			 */
-			case I2O_EVT_IND_BSA_VOLUME_LOAD:
-			{
-				i2ob_install_device(i2ob_dev[unit].i2odev->controller, 
-					i2ob_dev[unit].i2odev, unit);
-				break;
-			}
-
-			/*
-			 * No media, so set all parameters to 0 and set the media
-			 * change flag. The I2O device is still valid, just doesn't
-			 * have media, so we don't want to clear the controller or
-			 * device pointer.
-			 */
-			case I2O_EVT_IND_BSA_VOLUME_UNLOAD:
-			{
-				for(i = unit; i <= unit+15; i++)
-				{
-					i2ob_sizes[i] = 0;
-					i2ob_hardsizes[i] = 0;
-					i2ob_max_sectors[i] = 0;
-					i2ob[i].nr_sects = 0;
-					i2ob_gendisk.part[i].nr_sects = 0;
-				}
-				i2ob_media_change_flag[unit] = 1;
-				break;
-			}
-
-			case I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ:
-				printk(KERN_WARNING "%s: Attempt to eject locked media\n", 
-					i2ob_dev[unit].i2odev->dev_name);
-				break;
-
-			/*
-			 * The capacity has changed and we are going to be
-			 * updating the max_sectors and other information 
-			 * about this disk.  We try a revalidate first. If
-			 * the block device is in use, we don't want to
-			 * do that as there may be I/Os bound for the disk
-			 * at the moment.  In that case we read the size 
-			 * from the device and update the information ourselves
-			 * and the user can later force a partition table
-			 * update through an ioctl.
-			 */
-			case I2O_EVT_IND_BSA_CAPACITY_CHANGE:
-			{
-				u64 size;
-
-				if(do_i2ob_revalidate(MKDEV(MAJOR_NR, unit),0) != -EBUSY)
-					continue;
-
-	  			if(i2ob_query_device(&i2ob_dev[unit], 0x0004, 0, &size, 8) !=0 )
-					i2ob_query_device(&i2ob_dev[unit], 0x0000, 4, &size, 8);
-
-				spin_lock_irqsave(&io_request_lock, flags);	
-				i2ob_sizes[unit] = (int)(size>>10);
-				i2ob_gendisk.part[unit].nr_sects = size>>9;
-				i2ob[unit].nr_sects = (int)(size>>9);
-				spin_unlock_irqrestore(&io_request_lock, flags);	
-				break;
-			}
-
-			/* 
-			 * We got a SCSI SMART event, we just log the relevant
-			 * information and let the user decide what they want
-			 * to do with the information.
-			 */
-			case I2O_EVT_IND_BSA_SCSI_SMART:
-			{
-				char buf[16];
-				printk(KERN_INFO "I2O Block: %s received a SCSI SMART Event\n",i2ob_dev[unit].i2odev->dev_name);
-				evt_local->data[16]='\0';
-				sprintf(buf,"%s",&evt_local->data[0]);
-				printk(KERN_INFO "      Disk Serial#:%s\n",buf);
-				printk(KERN_INFO "      ASC 0x%02x \n",evt_local->ASC);
-				printk(KERN_INFO "      ASCQ 0x%02x \n",evt_local->ASCQ);
-				break;
-			}
-		
-			/*
-			 *	Non event
-			 */
-			 
-			case 0:
-				break;
-				
-			/*
-			 * An event we didn't ask for.  Call the card manufacturer
-			 * and tell them to fix their firmware :)
-			 */
-			default:
-				printk(KERN_INFO "%s: Received event %d we didn't register for\n"
-					KERN_INFO "   Blame the I2O card manufacturer 8)\n", 
-					i2ob_dev[unit].i2odev->dev_name, evt);
-				break;
-		}
-	};
-
-	complete_and_exit(&i2ob_thread_dead,0);
-	return 0;
-}
-
-/*
- * The timer handler will attempt to restart requests 
- * that are queued to the driver.  This handler
- * currently only gets called if the controller
- * had no more room in its inbound fifo.  
- */
-
-static void i2ob_timer_handler(unsigned long q)
-{
-	unsigned long flags;
-
-	/*
-	 * We cannot touch the request queue or the timer
-         * flag without holding the io_request_lock.
-	 */
-	spin_lock_irqsave(&io_request_lock,flags);
-
-	/* 
-	 * Clear the timer started flag so that 
-	 * the timer can be queued again.
-	 */
-	i2ob_timer_started = 0;
-
-	/* 
-	 * Restart any requests.
-	 */
-	i2ob_request((request_queue_t*)q);
-
-	/* 
-	 * Free the lock.
-	 */
-	spin_unlock_irqrestore(&io_request_lock,flags);
-}
-
-static int i2ob_backlog_request(struct i2o_controller *c, struct i2ob_device *dev)
-{
-	u32 m;
-	struct i2ob_request *ireq;
-	
-	while((ireq=i2ob_backlog[c->unit])!=NULL)
-	{
-		int unit;
-
-		if(atomic_read(&i2ob_queues[c->unit]->queue_depth) > dev->depth/4)
-			break;
-
-		m = i2ob_get(dev);
-		if(m == 0xFFFFFFFF)
-			break;
-
-		i2ob_backlog[c->unit] = ireq->next;
-		if(i2ob_backlog[c->unit] == NULL)
-			i2ob_backlog_tail[c->unit] = NULL;
-			
-		unit = MINOR(ireq->req->rq_dev);
-		i2ob_send(m, dev, ireq, i2ob[unit].start_sect, unit);
-	}
-	if(i2ob_backlog[c->unit])
-		return 1;
-	return 0;
-}
-
-/*
- *	The I2O block driver is listed as one of those that pulls the
- *	front entry off the queue before processing it. This is important
- *	to remember here. If we drop the io lock then CURRENT will change
- *	on us. We must unlink CURRENT in this routine before we return, if
- *	we use it.
- */
-
-static void i2ob_request(request_queue_t *q)
-{
-	struct request *req;
-	struct i2ob_request *ireq;
-	int unit;
-	struct i2ob_device *dev;
-	u32 m;
-	
-	
-	while (!list_empty(&q->queue_head)) {
-		/*
-		 *	On an IRQ completion if there is an inactive
-		 *	request on the queue head it means it isnt yet
-		 *	ready to dispatch.
-		 */
-		req = blkdev_entry_next_request(&q->queue_head);
-
-		if(req->rq_status == RQ_INACTIVE)
-			return;
-			
-		unit = MINOR(req->rq_dev);
-		dev = &i2ob_dev[(unit&0xF0)];
-
-		/* 
-		 *	Queue depths probably belong with some kind of 
-		 *	generic IOP commit control. Certainly its not right 
-		 *	its global!  
-		 */
-		if(atomic_read(&i2ob_queues[dev->unit]->queue_depth) >= dev->depth)
-			break;
-		
-		/*
-		 *	Is the channel constipated ?
-		 */
-
-		if(i2ob_backlog[dev->unit]!=NULL)
-			break;
-			
-		/* Get a message */
-		m = i2ob_get(dev);
-
-		if(m==0xFFFFFFFF)
-		{
-			/* 
-			 * See if the timer has already been queued.
-			 */
-			if (!i2ob_timer_started)
-			{
-				DEBUG((KERN_ERR "i2ob: starting timer\n"));
-
-				/*
-				 * Set the timer_started flag to insure
-				 * that the timer is only queued once.
-				 * Queing it more than once will corrupt
-				 * the timer queue.
-				 */
-				i2ob_timer_started = 1;
-
-				/* 
-				 * Set up the timer to expire in
-				 * 500ms.
-				 */
-				i2ob_timer.expires = jiffies + (HZ >> 1);
-				i2ob_timer.data = (unsigned int)q;
-
-				/*
-				 * Start it.
-				 */
-				 
-				add_timer(&i2ob_timer);
-				return;
-			}
-		}
-
-		/*
-		 * Everything ok, so pull from kernel queue onto our queue
-		 */
-		req->errors = 0;
-		blkdev_dequeue_request(req);	
-		req->waiting = NULL;
-		
-		ireq = i2ob_queues[dev->unit]->i2ob_qhead;
-		i2ob_queues[dev->unit]->i2ob_qhead = ireq->next;
-		ireq->req = req;
-
-		i2ob_send(m, dev, ireq, i2ob[unit].start_sect, (unit&0xF0));
-	}
-}
-
-
-/*
- *	SCSI-CAM for ioctl geometry mapping
- *	Duplicated with SCSI - this should be moved into somewhere common
- *	perhaps genhd ?
- *
- * LBA -> CHS mapping table taken from:
- *
- * "Incorporating the I2O Architecture into BIOS for Intel Architecture 
- *  Platforms" 
- *
- * This is an I2O document that is only available to I2O members,
- * not developers.
- *
- * From my understanding, this is how all the I2O cards do this
- *
- * Disk Size      | Sectors | Heads | Cylinders
- * ---------------+---------+-------+-------------------
- * 1 < X <= 528M  | 63      | 16    | X/(63 * 16 * 512)
- * 528M < X <= 1G | 63      | 32    | X/(63 * 32 * 512)
- * 1 < X <528M    | 63      | 16    | X/(63 * 16 * 512)
- * 1 < X <528M    | 63      | 16    | X/(63 * 16 * 512)
- *
- */
-#define	BLOCK_SIZE_528M		1081344
-#define	BLOCK_SIZE_1G		2097152
-#define	BLOCK_SIZE_21G		4403200
-#define	BLOCK_SIZE_42G		8806400
-#define	BLOCK_SIZE_84G		17612800
-
-static void i2o_block_biosparam(
-	unsigned long capacity,
-	unsigned short *cyls,
-	unsigned char *hds,
-	unsigned char *secs) 
-{ 
-	unsigned long heads, sectors, cylinders; 
-
-	sectors = 63L;      			/* Maximize sectors per track */ 
-	if(capacity <= BLOCK_SIZE_528M)
-		heads = 16;
-	else if(capacity <= BLOCK_SIZE_1G)
-		heads = 32;
-	else if(capacity <= BLOCK_SIZE_21G)
-		heads = 64;
-	else if(capacity <= BLOCK_SIZE_42G)
-		heads = 128;
-	else
-		heads = 255;
-
-	cylinders = capacity / (heads * sectors);
-
-	*cyls = (unsigned short) cylinders;	/* Stuff return values */ 
-	*secs = (unsigned char) sectors; 
-	*hds  = (unsigned char) heads; 
-}
-
-
-/*
- *	Rescan the partition tables
- */
- 
-static int do_i2ob_revalidate(kdev_t dev, int maxu)
-{
-	int minor=MINOR(dev);
-	int i;
-	
-	minor&=0xF0;
-
-	i2ob_dev[minor].refcnt++;
-	if(i2ob_dev[minor].refcnt>maxu+1)
-	{
-		i2ob_dev[minor].refcnt--;
-		return -EBUSY;
-	}
-	
-	for( i = 15; i>=0 ; i--)
-	{
-		int m = minor+i;
-		invalidate_device(MKDEV(MAJOR_NR, m), 1);
-		i2ob_gendisk.part[m].start_sect = 0;
-		i2ob_gendisk.part[m].nr_sects = 0;
-	}
-
-	/*
-	 *	Do a physical check and then reconfigure
-	 */
-	 
-	i2ob_install_device(i2ob_dev[minor].controller, i2ob_dev[minor].i2odev,
-		minor);
-	i2ob_dev[minor].refcnt--;
-	return 0;
-}
-
-/*
- *	Issue device specific ioctl calls.
- */
-
-static int i2ob_ioctl(struct inode *inode, struct file *file,
-		     unsigned int cmd, unsigned long arg)
-{
-	struct i2ob_device *dev;
-	int minor;
-
-	/* Anyone capable of this syscall can do *real bad* things */
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	if (!inode)
-		return -EINVAL;
-	minor = MINOR(inode->i_rdev);
-	if (minor >= (MAX_I2OB<<4))
-		return -ENODEV;
-
-	dev = &i2ob_dev[minor];
-	switch (cmd) {
-		case BLKGETSIZE:
-			return put_user(i2ob[minor].nr_sects, (long *) arg);
-		case BLKGETSIZE64:
-			return put_user((u64)i2ob[minor].nr_sects << 9, (u64 *)arg);
-
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry g;
-			int u=minor&0xF0;
-			i2o_block_biosparam(i2ob_sizes[u]<<1, 
-				&g.cylinders, &g.heads, &g.sectors);
-			g.start = i2ob[minor].start_sect;
-			return copy_to_user((void *)arg,&g, sizeof(g))?-EFAULT:0;
-		}
-	
-		case BLKRRPART:
-			if(!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			return do_i2ob_revalidate(inode->i_rdev,1);
-			
-		case BLKFLSBUF:
-		case BLKROSET:
-		case BLKROGET:
-		case BLKRASET:
-		case BLKRAGET:
-		case BLKPG:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-			
-		default:
-			return -EINVAL;
-	}
-}
-
-/*
- *	Close the block device down
- */
- 
-static int i2ob_release(struct inode *inode, struct file *file)
-{
-	struct i2ob_device *dev;
-	int minor;
-
-	minor = MINOR(inode->i_rdev);
-	if (minor >= (MAX_I2OB<<4))
-		return -ENODEV;
-	dev = &i2ob_dev[(minor&0xF0)];
-
-	/*
-	 * This is to deail with the case of an application
-	 * opening a device and then the device dissapears while
-	 * it's in use, and then the application tries to release
-	 * it.  ex: Unmounting a deleted RAID volume at reboot. 
-	 * If we send messages, it will just cause FAILs since
-	 * the TID no longer exists.
-	 */
-	if(!dev->i2odev)
-		return 0;
-
-	if (dev->refcnt <= 0)
-		printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt);
-	dev->refcnt--;
-	if(dev->refcnt==0)
-	{
-		/*
-		 *	Flush the onboard cache on unmount
-		 */
-		u32 msg[5];
-		int *query_done = &dev->done_flag;
-		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
-		msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid;
-		msg[2] = i2ob_context|0x40000000;
-		msg[3] = (u32)query_done;
-		msg[4] = 60<<16;
-		DEBUG("Flushing...");
-		i2o_post_wait(dev->controller, msg, 20, 60);
-
-		/*
-		 *	Unlock the media
-		 */
-		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
-		msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid;
-		msg[2] = i2ob_context|0x40000000;
-		msg[3] = (u32)query_done;
-		msg[4] = -1;
-		DEBUG("Unlocking...");
-		i2o_post_wait(dev->controller, msg, 20, 2);
-		DEBUG("Unlocked.\n");
-	
-		/*
- 		 * Now unclaim the device.
-		 */
-
-		if (i2o_release_device(dev->i2odev, &i2o_block_handler))
-			printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n");
-		
-		DEBUG("Unclaim\n");
-	}
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-/*
- *	Open the block device.
- */
- 
-static int i2ob_open(struct inode *inode, struct file *file)
-{
-	int minor;
-	struct i2ob_device *dev;
-	
-	if (!inode)
-		return -EINVAL;
-	minor = MINOR(inode->i_rdev);
-	if (minor >= MAX_I2OB<<4)
-		return -ENODEV;
-	dev=&i2ob_dev[(minor&0xF0)];
-
-	if(!dev->i2odev)	
-		return -ENODEV;
-	
-	if(dev->refcnt++==0)
-	{ 
-		u32 msg[6];
-		
-		DEBUG("Claim ");
-		if(i2o_claim_device(dev->i2odev, &i2o_block_handler))
-		{
-			dev->refcnt--;
-			printk(KERN_INFO "I2O Block: Could not open device\n");
-			return -EBUSY;
-		}
-		DEBUG("Claimed ");
-		
-		/*
-		 *	Mount the media if needed. Note that we don't use
-		 *	the lock bit. Since we have to issue a lock if it
-		 *	refuses a mount (quite possible) then we might as
-		 *	well just send two messages out.
-		 */
-		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;		
-		msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid;
-		msg[4] = -1;
-		msg[5] = 0;
-		DEBUG("Mount ");
-		i2o_post_wait(dev->controller, msg, 24, 2);
-
-		/*
-		 *	Lock the media
-		 */
-		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
-		msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid;
-		msg[4] = -1;
-		DEBUG("Lock ");
-		i2o_post_wait(dev->controller, msg, 20, 2);
-		DEBUG("Ready.\n");
-	}		
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
-/*
- *	Issue a device query
- */
- 
-static int i2ob_query_device(struct i2ob_device *dev, int table, 
-	int field, void *buf, int buflen)
-{
-	return i2o_query_scalar(dev->controller, dev->tid,
-		table, field, buf, buflen);
-}
-
-
-/*
- *	Install the I2O block device we found.
- */
- 
-static int i2ob_install_device(struct i2o_controller *c, struct i2o_device *d, int unit)
-{
-	u64 size;
-	u32 blocksize;
-	u32 limit;
-	u8 type;
-	u32 flags, status;
-	struct i2ob_device *dev=&i2ob_dev[unit];
-	int i;
-
-	/*
-	 * For logging purposes...
-	 */
-	printk(KERN_INFO "i2ob: Installing tid %d device at unit %d\n", 
-			d->lct_data.tid, unit);	
-
-	/*
-	 *	Ask for the current media data. If that isn't supported
-	 *	then we ask for the device capacity data
-	 */
-	if(i2ob_query_device(dev, 0x0004, 1, &blocksize, 4) != 0
-	  || i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 )
-	{
-		i2ob_query_device(dev, 0x0000, 3, &blocksize, 4);
-		i2ob_query_device(dev, 0x0000, 4, &size, 8);
-	}
-	
-	i2ob_query_device(dev, 0x0000, 5, &flags, 4);
-	i2ob_query_device(dev, 0x0000, 6, &status, 4);
-	i2ob_sizes[unit] = (int)(size>>10);
-	for(i=unit; i <= unit+15 ; i++)
-		i2ob_hardsizes[i] = blocksize;
-	i2ob_gendisk.part[unit].nr_sects = size>>9;
-	i2ob[unit].nr_sects = (int)(size>>9);
-
-	/* Set limit based on inbound frame size */
-	limit = (d->controller->status_block->inbound_frame_size - 8)/2;
-	limit = limit<<9;
-
-	/*
-	 * Max number of Scatter-Gather Elements
-	 */	
-
-	for(i=unit;i<=unit+15;i++)
-	{
-		if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.queue_buggy)
-		{
-			i2ob_max_sectors[i] = 32;
-			i2ob_dev[i].max_segments = 8;
-			i2ob_dev[i].depth = 4;
-		}
-		else if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.short_req)
-		{
-			i2ob_max_sectors[i] = 8;
-			i2ob_dev[i].max_segments = 8;
-		}
-		else
-		{
-			/* MAX_SECTORS was used but 255 is a dumb number for
-			   striped RAID */
-			i2ob_max_sectors[i]=256;
-			i2ob_dev[i].max_segments = (d->controller->status_block->inbound_frame_size - 8)/2;
-		}
-	}
-
-	printk(KERN_INFO "Max segments set to %d\n", 
-				i2ob_dev[unit].max_segments);
-	printk(KERN_INFO "Byte limit is %d.\n", limit);
-
-	i2ob_query_device(dev, 0x0000, 0, &type, 1);
-	
-	sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4));
-
-	printk(KERN_INFO "%s: ", d->dev_name);
-	switch(type)
-	{
-		case 0: printk("Disk Storage");break;
-		case 4: printk("WORM");break;
-		case 5: printk("CD-ROM");break;
-		case 7:	printk("Optical device");break;
-		default:
-			printk("Type %d", type);
-	}
-	if(status&(1<<10))
-		printk("(RAID)");
-	if(((flags & (1<<3)) && !(status & (1<<3))) ||
-	   ((flags & (1<<4)) && !(status & (1<<4))))
-	{
-		printk(KERN_INFO " Not loaded.\n");
-		return 1;
-	}
-	printk("- %dMb, %d byte sectors",
-		(int)(size>>20), blocksize);
-	if(status&(1<<0))
-	{
-		u32 cachesize;
-		i2ob_query_device(dev, 0x0003, 0, &cachesize, 4);
-		cachesize>>=10;
-		if(cachesize>4095)
-			printk(", %dMb cache", cachesize>>10);
-		else
-			printk(", %dKb cache", cachesize);
-		
-	}
-	printk(".\n");
-	printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", 
-		d->dev_name, i2ob_max_sectors[unit]);
-
-	/* 
-	 * If this is the first I2O block device found on this IOP,
-	 * we need to initialize all the queue data structures
-	 * before any I/O can be performed. If it fails, this
-	 * device is useless.
-	 */
-	if(!i2ob_queues[c->unit]) {
-		if(i2ob_init_iop(c->unit))
-			return 1;
-	}
-
-	/* 
-	 * This will save one level of lookup/indirection in critical 
-	 * code so that we can directly get the queue ptr from the
-	 * device instead of having to go the IOP data structure.
-	 */
-	dev->req_queue = &i2ob_queues[c->unit]->req_queue;
-
-	grok_partitions(&i2ob_gendisk, unit>>4, 1<<4, (long)(size>>9));
-
-	/*
-	 * Register for the events we're interested in and that the
-	 * device actually supports.
-	 */
-	i2o_event_register(c, d->lct_data.tid, i2ob_context, unit, 
-		(I2OB_EVENT_MASK & d->lct_data.event_capabilities));
-
-	return 0;
-}
-
-/*
- * Initialize IOP specific queue structures.  This is called
- * once for each IOP that has a block device sitting behind it.
- */
-static int i2ob_init_iop(unsigned int unit)
-{
-	int i;
-
-	i2ob_queues[unit] = (struct i2ob_iop_queue*)
-		kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC);
-	if(!i2ob_queues[unit])
-	{
-		printk(KERN_WARNING
-			"Could not allocate request queue for I2O block device!\n");
-		return -1;
-	}
-
-	for(i = 0; i< MAX_I2OB_DEPTH; i++)
-	{
-		i2ob_queues[unit]->request_queue[i].next = 
-			&i2ob_queues[unit]->request_queue[i+1];
-		i2ob_queues[unit]->request_queue[i].num = i;
-	}
-	
-	/* Queue is MAX_I2OB + 1... */
-	i2ob_queues[unit]->request_queue[i].next = NULL;
-	i2ob_queues[unit]->i2ob_qhead = &i2ob_queues[unit]->request_queue[0];
-	atomic_set(&i2ob_queues[unit]->queue_depth, 0);
-
-	blk_init_queue(&i2ob_queues[unit]->req_queue, i2ob_request);
-	blk_queue_headactive(&i2ob_queues[unit]->req_queue, 0);
-	i2ob_queues[unit]->req_queue.back_merge_fn = i2ob_back_merge;
-	i2ob_queues[unit]->req_queue.front_merge_fn = i2ob_front_merge;
-	i2ob_queues[unit]->req_queue.merge_requests_fn = i2ob_merge_requests;
-	i2ob_queues[unit]->req_queue.queuedata = &i2ob_queues[unit];
-
-	return 0;
-}
-
-/*
- * Get the request queue for the given device.
- */	
-static request_queue_t* i2ob_get_queue(kdev_t dev)
-{
-	int unit = MINOR(dev)&0xF0;
-
-	return i2ob_dev[unit].req_queue;
-}
-
-/*
- * Probe the I2O subsytem for block class devices
- */
-static void i2ob_scan(int bios)
-{
-	int i;
-	int warned = 0;
-
-	struct i2o_device *d, *b=NULL;
-	struct i2o_controller *c;
-	struct i2ob_device *dev;
-		
-	for(i=0; i< MAX_I2O_CONTROLLERS; i++)
-	{
-		c=i2o_find_controller(i);
-	
-		if(c==NULL)
-			continue;
-
-	/*
-	 *    The device list connected to the I2O Controller is doubly linked
-	 * Here we traverse the end of the list , and start claiming devices
-	 * from that end. This assures that within an I2O controller atleast
-	 * the newly created volumes get claimed after the older ones, thus
-	 * mapping to same major/minor (and hence device file name) after 
-	 * every reboot.
-	 * The exception being: 
-	 * 1. If there was a TID reuse.
-	 * 2. There was more than one I2O controller. 
-	 */
-
-	if(!bios)
-	{
-		for (d=c->devices;d!=NULL;d=d->next)
-		if(d->next == NULL)
-			b = d;
-	}
-	else
-		b = c->devices;
-
-	while(b != NULL)
-	{
-		d=b;
-		if(bios)
-			b = b->next;
-		else
-			b = b->prev;
-
-			if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE)
-				continue;
-
-			if(d->lct_data.user_tid != 0xFFF)
-				continue;
-
-			if(bios)
-			{
-				if(d->lct_data.bios_info != 0x80)
-					continue;
-				printk(KERN_INFO "Claiming as Boot device: Controller %d, TID %d\n", c->unit, d->lct_data.tid);
-			}
-			else
-			{
-				if(d->lct_data.bios_info == 0x80)
-					continue; /*Already claimed on pass 1 */
-			}
-
-			if(i2o_claim_device(d, &i2o_block_handler))
-			{
-				printk(KERN_WARNING "i2o_block: Controller %d, TID %d\n", c->unit,
-					d->lct_data.tid);
-				printk(KERN_WARNING "\t%sevice refused claim! Skipping installation\n", bios?"Boot d":"D");
-				continue;
-			}
-
-			if(scan_unit<MAX_I2OB<<4)
-			{
- 				/*
-				 * Get the device and fill in the
-				 * Tid and controller.
-				 */
-				dev=&i2ob_dev[scan_unit];
-				dev->i2odev = d; 
-				dev->controller = c;
-				dev->unit = c->unit;
-				dev->tid = d->lct_data.tid;
-
-				if(i2ob_install_device(c,d,scan_unit))
-					printk(KERN_WARNING "Could not install I2O block device\n");
-				else
-				{
-					scan_unit+=16;
-					i2ob_dev_count++;
-
-					/* We want to know when device goes away */
-					i2o_device_notify_on(d, &i2o_block_handler);
-				}
-			}
-			else
-			{
-				if(!warned++)
-					printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", scan_unit>>4);
-			}
-			i2o_release_device(d, &i2o_block_handler);
-		}
-		i2o_unlock_controller(c);
-	}
-}
-
-static void i2ob_probe(void)
-{
-	/*
-	 *      Some overhead/redundancy involved here, while trying to
-	 *      claim the first boot volume encountered as /dev/i2o/hda
-	 *      everytime. All the i2o_controllers are searched and the
-	 *      first i2o block device marked as bootable is claimed
-	 *      If an I2O block device was booted off , the bios sets
-	 *      its bios_info field to 0x80, this what we search for.
-	 *      Assuming that the bootable volume is /dev/i2o/hda
-	 *      everytime will prevent any kernel panic while mounting
-	 *      root partition
-	 */
-
-	printk(KERN_INFO "i2o_block: Checking for Boot device...\n");
-	i2ob_scan(1);
-
-	/*
-	 *      Now the remainder.
-	 */
-	printk(KERN_INFO "i2o_block: Checking for I2O Block devices...\n");
-	i2ob_scan(0);
-}
-
-
-/*
- * New device notification handler.  Called whenever a new
- * I2O block storage device is added to the system.
- * 
- * Should we spin lock around this to keep multiple devs from 
- * getting updated at the same time? 
- * 
- */
-void i2ob_new_device(struct i2o_controller *c, struct i2o_device *d)
-{
-	struct i2ob_device *dev;
-	int unit = 0;
-
-	printk(KERN_INFO "i2o_block: New device detected\n");
-	printk(KERN_INFO "   Controller %d Tid %d\n",c->unit, d->lct_data.tid);
-
-	/* Check for available space */
-	if(i2ob_dev_count>=MAX_I2OB<<4)
-	{
-		printk(KERN_ERR "i2o_block: No more devices allowed!\n");
-		return;
-	}
-	for(unit = 0; unit < (MAX_I2OB<<4); unit += 16)
-	{
-		if(!i2ob_dev[unit].i2odev)
-			break;
-	}
-
-	if(i2o_claim_device(d, &i2o_block_handler))
-	{
-		printk(KERN_INFO 
-			"i2o_block: Unable to claim device. Installation aborted\n");
-		return;
-	}
-
-	dev = &i2ob_dev[unit];
-	dev->i2odev = d; 
-	dev->controller = c;
-	dev->tid = d->lct_data.tid;
-
-	if(i2ob_install_device(c,d,unit))
-		printk(KERN_ERR "i2o_block: Could not install new device\n");
-	else	
-	{
-		i2ob_dev_count++;
-		i2o_device_notify_on(d, &i2o_block_handler);
-	}
-
-	i2o_release_device(d, &i2o_block_handler);
- 
-	return;
-}
-
-/*
- * Deleted device notification handler.  Called when a device we
- * are talking to has been deleted by the user or some other
- * mysterious fource outside the kernel.
- */
-void i2ob_del_device(struct i2o_controller *c, struct i2o_device *d)
-{	
-	int unit = 0;
-	int i = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-
-	/*
-	 * Need to do this...we somtimes get two events from the IRTOS
-	 * in a row and that causes lots of problems.
-	 */
-	i2o_device_notify_off(d, &i2o_block_handler);
-
-	printk(KERN_INFO "I2O Block Device Deleted\n");
-
-	for(unit = 0; unit < MAX_I2OB<<4; unit += 16)
-	{
-		if(i2ob_dev[unit].i2odev == d)
-		{
-			printk(KERN_INFO "  /dev/%s: Controller %d Tid %d\n", 
-				d->dev_name, c->unit, d->lct_data.tid);
-			break;
-		}
-	}
-	if(unit >= MAX_I2OB<<4)
-	{
-		printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n");
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-
-	/* 
-	 * This will force errors when i2ob_get_queue() is called
-	 * by the kenrel.
-	 */
-	i2ob_dev[unit].req_queue = NULL;
-	for(i = unit; i <= unit+15; i++)
-	{
-		i2ob_dev[i].i2odev = NULL;
-		i2ob_sizes[i] = 0;
-		i2ob_hardsizes[i] = 0;
-		i2ob_max_sectors[i] = 0;
-		i2ob[i].nr_sects = 0;
-		i2ob_gendisk.part[i].nr_sects = 0;
-	}
-	spin_unlock_irqrestore(&io_request_lock, flags);
-
-	/*
-	 * Sync the device...this will force all outstanding I/Os
-	 * to attempt to complete, thus causing error messages.
-	 * We have to do this as the user could immediatelly create
-	 * a new volume that gets assigned the same minor number.
-	 * If there are still outstanding writes to the device,
-	 * that could cause data corruption on the new volume!
-	 *
-	 * The truth is that deleting a volume that you are currently
-	 * accessing will do _bad things_ to your system.  This 
-	 * handler will keep it from crashing, but must probably 
-	 * you'll have to do a 'reboot' to get the system running
-	 * properly.  Deleting disks you are using is dumb.  
-	 * Umount them first and all will be good!
-	 *
-	 * It's not this driver's job to protect the system from
-	 * dumb user mistakes :)
-	 */
-	if(i2ob_dev[unit].refcnt)
-		fsync_dev(MKDEV(MAJOR_NR,unit));
-
-	/*
-	 * Decrease usage count for module
-	 */	
-	while(i2ob_dev[unit].refcnt--)
-		MOD_DEC_USE_COUNT;
-
-	i2ob_dev[unit].refcnt = 0;
-	
-	i2ob_dev[i].tid = 0;
-
-	/* 
-	 * Do we need this?
-	 * The media didn't really change...the device is just gone
-	 */
-	i2ob_media_change_flag[unit] = 1;
-
-	i2ob_dev_count--;	
-}
-
-/*
- *	Have we seen a media change ?
- */
-static int i2ob_media_change(kdev_t dev)
-{
-	int i=MINOR(dev);
-	i>>=4;
-	if(i2ob_media_change_flag[i])
-	{
-		i2ob_media_change_flag[i]=0;
-		return 1;
-	}
-	return 0;
-}
-
-static int i2ob_revalidate(kdev_t dev)
-{
-	return do_i2ob_revalidate(dev, 0);
-}
-
-/*
- * Reboot notifier.  This is called by i2o_core when the system
- * shuts down.
- */
-static void i2ob_reboot_event(void)
-{
-	int i;
-	
-	for(i=0;i<MAX_I2OB;i++)
-	{
-		struct i2ob_device *dev=&i2ob_dev[(i<<4)];
-		
-		if(dev->refcnt!=0)
-		{
-			/*
-			 *	Flush the onboard cache
-			 */
-			u32 msg[5];
-			int *query_done = &dev->done_flag;
-			msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
-			msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid;
-			msg[2] = i2ob_context|0x40000000;
-			msg[3] = (u32)query_done;
-			msg[4] = 60<<16;
-			
-			DEBUG("Flushing...");
-			i2o_post_wait(dev->controller, msg, 20, 60);
-
-			DEBUG("Unlocking...");
-			/*
-			 *	Unlock the media
-			 */
-			msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
-			msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid;
-			msg[2] = i2ob_context|0x40000000;
-			msg[3] = (u32)query_done;
-			msg[4] = -1;
-			i2o_post_wait(dev->controller, msg, 20, 2);
-			
-			DEBUG("Unlocked.\n");
-		}
-	}	
-}
-
-static struct block_device_operations i2ob_fops =
-{
-	open:			i2ob_open,
-	release:		i2ob_release,
-	ioctl:			i2ob_ioctl,
-	check_media_change:	i2ob_media_change,
-	revalidate:		i2ob_revalidate,
-};
-
-static struct gendisk i2ob_gendisk = 
-{
-	major:		MAJOR_NR,
-	major_name:	"i2o/hd",
-	minor_shift:	4,
-	max_p:		1<<4,
-	part:		i2ob,
-	sizes:		i2ob_sizes,
-	nr_real:	MAX_I2OB,
-	fops:		&i2ob_fops,
-};
-
-
-/*
- * And here should be modules and kernel interface 
- *  (Just smiley confuses emacs :-)
- */
-
-#ifdef MODULE
-#define i2o_block_init init_module
-#endif
-
-int i2o_block_init(void)
-{
-	int i;
-
-	printk(KERN_INFO "I2O Block Storage OSM v0.9\n");
-	printk(KERN_INFO "   (c) Copyright 1999-2001 Red Hat Software.\n");
-	
-	/*
-	 *	Register the block device interfaces
-	 */
-
-	if (register_blkdev(MAJOR_NR, "i2o_block", &i2ob_fops)) {
-		printk(KERN_ERR "Unable to get major number %d for i2o_block\n",
-		       MAJOR_NR);
-		return -EIO;
-	}
-#ifdef MODULE
-	printk(KERN_INFO "i2o_block: registered device at major %d\n", MAJOR_NR);
-#endif
-
-	/*
-	 *	Now fill in the boiler plate
-	 */
-	 
-	blksize_size[MAJOR_NR] = i2ob_blksizes;
-	hardsect_size[MAJOR_NR] = i2ob_hardsizes;
-	blk_size[MAJOR_NR] = i2ob_sizes;
-	max_sectors[MAJOR_NR] = i2ob_max_sectors;
-	blk_dev[MAJOR_NR].queue = i2ob_get_queue;
-	
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), i2ob_request);
-	blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
-
-	for (i = 0; i < MAX_I2OB << 4; i++) {
-		i2ob_dev[i].refcnt = 0;
-		i2ob_dev[i].flags = 0;
-		i2ob_dev[i].controller = NULL;
-		i2ob_dev[i].i2odev = NULL;
-		i2ob_dev[i].tid = 0;
-		i2ob_dev[i].head = NULL;
-		i2ob_dev[i].tail = NULL;
-		i2ob_dev[i].depth = MAX_I2OB_DEPTH;
-		i2ob_blksizes[i] = 1024;
-		i2ob_max_sectors[i] = 2;
-	}
-	
-	/*
-	 *	Set up the queue
-	 */
-	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
-	{
-		i2ob_queues[i] = NULL;
-	}
-
-	/*
-	 *	Timers
-	 */
-	 
-	init_timer(&i2ob_timer);
-	i2ob_timer.function = i2ob_timer_handler;
-	i2ob_timer.data = 0;
-	
-	/*
-	 *	Register the OSM handler as we will need this to probe for
-	 *	drives, geometry and other goodies.
-	 */
-
-	if(i2o_install_handler(&i2o_block_handler)<0)
-	{
-		unregister_blkdev(MAJOR_NR, "i2o_block");
-		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-		printk(KERN_ERR "i2o_block: unable to register OSM.\n");
-		return -EINVAL;
-	}
-	i2ob_context = i2o_block_handler.context;	 
-
-	/*
-	 * Initialize event handling thread
-	 */
-	init_MUTEX_LOCKED(&i2ob_evt_sem);
-	evt_pid = kernel_thread(i2ob_evt, NULL, CLONE_SIGHAND);
-	if(evt_pid < 0)
-	{
-		printk(KERN_ERR 
-			"i2o_block: Could not initialize event thread.  Aborting\n");
-		i2o_remove_handler(&i2o_block_handler);
-		return 0;
-	}
-
-	/*
-	 *	Finally see what is actually plugged in to our controllers
-	 */
-	for (i = 0; i < MAX_I2OB; i++)
-		register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4,
-			&i2ob_fops, 0);
-	i2ob_probe();
-
-	/*
-	 *	Adding i2ob_gendisk into the gendisk list.
-	 */
-	add_gendisk(&i2ob_gendisk);
-
-	return 0;
-}
-
-#ifdef MODULE
-
-EXPORT_NO_SYMBOLS;
-MODULE_AUTHOR("Red Hat Software");
-MODULE_DESCRIPTION("I2O Block Device OSM");
-
-void cleanup_module(void)
-{
-	struct gendisk *gdp;
-	int i;
-	
-	if(evt_running) {
-		printk(KERN_INFO "Killing I2O block threads...");
-		i = kill_proc(evt_pid, SIGTERM, 1);
-		if(!i) {
-			printk("waiting...");
-		}
-		/* Be sure it died */
-		wait_for_completion(&i2ob_thread_dead);
-		printk("done.\n");
-	}
-
-	/*
-	 * Unregister for updates from any devices..otherwise we still
-	 * get them and the core jumps to random memory :O
-	 */
-	if(i2ob_dev_count) {
-		struct i2o_device *d;
-		for(i = 0; i < MAX_I2OB; i++)
-		if((d=i2ob_dev[i<<4].i2odev)) {
-			i2o_device_notify_off(d, &i2o_block_handler);
-			i2o_event_register(d->controller, d->lct_data.tid, 
-				i2ob_context, i<<4, 0);
-		}
-	}
-	
-	/*
-	 *	We may get further callbacks for ourself. The i2o_core
-	 *	code handles this case reasonably sanely. The problem here
-	 *	is we shouldn't get them .. but a couple of cards feel 
-	 *	obliged to tell us stuff we dont care about.
-	 *
-	 *	This isnt ideal at all but will do for now.
-	 */
-	 
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ);
-	
-	/*
-	 *	Flush the OSM
-	 */
-
-	i2o_remove_handler(&i2o_block_handler);
-		 
-	/*
-	 *	Return the block device
-	 */
-	if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0)
-		printk("i2o_block: cleanup_module failed\n");
-
-	/*
-	 * free request queue
-	 */
-	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-
-	del_gendisk(&i2ob_gendisk);
-}
-#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c
--- v2.4.12/linux/drivers/i2o/i2o_config.c	Mon Aug 27 12:41:41 2001
+++ linux/drivers/i2o/i2o_config.c	Wed Dec 31 16:00:00 1969
@@ -1,965 +0,0 @@
-/*
- * I2O Configuration Interface Driver
- *
- * (C) Copyright 1999   Red Hat Software
- *	
- * Written by Alan Cox, Building Number Three Ltd
- *
- * Modified 04/20/1999 by Deepak Saxena
- *   - Added basic ioctl() support
- * Modified 06/07/1999 by Deepak Saxena
- *   - Added software download ioctl (still testing)
- * Modified 09/10/1999 by Auvo Häkkinen
- *   - Changes to i2o_cfg_reply(), ioctl_parms()
- *   - Added ioct_validate()
- * Modified 09/30/1999 by Taneli Vähäkangas
- *   - Fixed ioctl_swdl()
- * Modified 10/04/1999 by Taneli Vähäkangas
- *   - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
- * Modified 11/18/199 by Deepak Saxena
- *   - Added event managmenet support
- *
- * 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.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/i2o.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-static int i2o_cfg_context = -1;
-static void *page_buf;
-static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED;
-struct wait_queue *i2o_wait_queue;
-
-#define MODINC(x,y) (x = x++ % y)
-
-struct i2o_cfg_info
-{
-	struct file* fp;
-	struct fasync_struct *fasync;
-	struct i2o_evt_info event_q[I2O_EVT_Q_LEN];
-	u16		q_in;		// Queue head index
-	u16		q_out;		// Queue tail index
-	u16		q_len;		// Queue length
-	u16		q_lost;		// Number of lost events
-	u32		q_id;		// Event queue ID...used as tx_context
-	struct	i2o_cfg_info *next;
-};
-static struct i2o_cfg_info *open_files = NULL;
-static int i2o_cfg_info_id = 0;
-
-static int ioctl_getiops(unsigned long);
-static int ioctl_gethrt(unsigned long);
-static int ioctl_getlct(unsigned long);
-static int ioctl_parms(unsigned long, unsigned int);
-static int ioctl_html(unsigned long);
-static int ioctl_swdl(unsigned long);
-static int ioctl_swul(unsigned long);
-static int ioctl_swdel(unsigned long);
-static int ioctl_validate(unsigned long); 
-static int ioctl_evt_reg(unsigned long, struct file *);
-static int ioctl_evt_get(unsigned long, struct file *);
-static int cfg_fasync(int, struct file*, int);
-
-/*
- *	This is the callback for any message we have posted. The message itself
- *	will be returned to the message pool when we return from the IRQ
- *
- *	This runs in irq context so be short and sweet.
- */
-static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m)
-{
-	u32 *msg = (u32 *)m;
-
-	if (msg[0] & MSG_FAIL) {
-		u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]);
-
-		printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n");
-
-		/* Release the preserved msg frame by resubmitting it as a NOP */
-
-		preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
-		preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
-		preserved_msg[2] = 0;
-		i2o_post_message(c, msg[7]);
-	}
-
-	if (msg[4] >> 24)  // ReqStatus != SUCCESS
-		i2o_report_status(KERN_INFO,"i2o_config", msg);
-
-	if(m->function == I2O_CMD_UTIL_EVT_REGISTER)
-	{
-		struct i2o_cfg_info *inf;
-
-		for(inf = open_files; inf; inf = inf->next)
-			if(inf->q_id == msg[3])
-				break;
-
-		//
-		// If this is the case, it means that we're getting
-		// events for a file descriptor that's been close()'d
-		// w/o the user unregistering for events first.
-		// The code currently assumes that the user will 
-		// take care of unregistering for events before closing
-		// a file.
-		// 
-		// TODO: 
-		// Should we track event registartion and deregister
-		// for events when a file is close()'d so this doesn't
-		// happen? That would get rid of the search through
-		// the linked list since file->private_data could point
-		// directly to the i2o_config_info data structure...but
-		// it would mean having all sorts of tables to track
-		// what each file is registered for...I think the
-		// current method is simpler. - DS
-		//			
-		if(!inf)
-			return;
-
-		inf->event_q[inf->q_in].id.iop = c->unit;
-		inf->event_q[inf->q_in].id.tid = m->target_tid;
-		inf->event_q[inf->q_in].id.evt_mask = msg[4];
-
-		//
-		// Data size = msg size - reply header
-		//
-		inf->event_q[inf->q_in].data_size = (m->size - 5) * 4;
-		if(inf->event_q[inf->q_in].data_size)
-			memcpy(inf->event_q[inf->q_in].evt_data, 
-				(unsigned char *)(msg + 5),
-				inf->event_q[inf->q_in].data_size);
-
-		spin_lock(&i2o_config_lock);
-		MODINC(inf->q_in, I2O_EVT_Q_LEN);
-		if(inf->q_len == I2O_EVT_Q_LEN)
-		{
-			MODINC(inf->q_out, I2O_EVT_Q_LEN);
-			inf->q_lost++;
-		}
-		else
-		{
-			// Keep I2OEVTGET on another CPU from touching this
-			inf->q_len++;
-		}
-		spin_unlock(&i2o_config_lock);
-		
-
-//		printk(KERN_INFO "File %p w/id %d has %d events\n",
-//			inf->fp, inf->q_id, inf->q_len);	
-
-		kill_fasync(&inf->fasync, SIGIO, POLL_IN);
-	}
-
-	return;
-}
-
-/*
- *	Each of these describes an i2o message handler. They are
- *	multiplexed by the i2o_core code
- */
- 
-struct i2o_handler cfg_handler=
-{
-	i2o_cfg_reply,
-	NULL,
-	NULL,
-	NULL,
-	"Configuration",
-	0,
-	0xffffffff	// All classes
-};
-
-static ssize_t cfg_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-{
-	printk(KERN_INFO "i2o_config write not yet supported\n");
-
-	return 0;
-}
-
-
-static ssize_t cfg_read(struct file *file, char *buf, size_t count, loff_t *ptr)
-{
-	return 0;
-}
-
-/*
- * IOCTL Handler
- */
-static int cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
-	unsigned long arg)
-{
-	int ret;
-
-	switch(cmd)
-	{	
-		case I2OGETIOPS:
-			ret = ioctl_getiops(arg);
-			break;
-
-		case I2OHRTGET:
-			ret = ioctl_gethrt(arg);
-			break;
-
-		case I2OLCTGET:
-			ret = ioctl_getlct(arg);
-			break;
-
-		case I2OPARMSET:
-			ret = ioctl_parms(arg, I2OPARMSET);
-			break;
-
-		case I2OPARMGET:
-			ret = ioctl_parms(arg, I2OPARMGET);
-			break;
-
-		case I2OSWDL:
-			ret = ioctl_swdl(arg);
-			break;
-
-		case I2OSWUL:
-			ret = ioctl_swul(arg);
-			break;
-
-		case I2OSWDEL:
-			ret = ioctl_swdel(arg);
-			break;
-
-		case I2OVALIDATE:
-			ret = ioctl_validate(arg);
-			break;
-			
-		case I2OHTML:
-			ret = ioctl_html(arg);
-			break;
-
-		case I2OEVTREG:
-			ret = ioctl_evt_reg(arg, fp);
-			break;
-
-		case I2OEVTGET:
-			ret = ioctl_evt_get(arg, fp);
-			break;
-
-		default:
-			ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-int ioctl_getiops(unsigned long arg)
-{
-	u8 *user_iop_table = (u8*)arg;
-	struct i2o_controller *c = NULL;
-	int i;
-	u8 foo[MAX_I2O_CONTROLLERS];
-
-	if(!access_ok(VERIFY_WRITE, user_iop_table,  MAX_I2O_CONTROLLERS))
-		return -EFAULT;
-
-	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
-	{
-		c = i2o_find_controller(i);
-		if(c)
-		{
-			foo[i] = 1;
-			i2o_unlock_controller(c);
-		}
-		else
-		{
-			foo[i] = 0;
-		}
-	}
-
-	__copy_to_user(user_iop_table, foo, MAX_I2O_CONTROLLERS);
-	return 0;
-}
-
-int ioctl_gethrt(unsigned long arg)
-{
-	struct i2o_controller *c;
-	struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg;
-	struct i2o_cmd_hrtlct kcmd;
-	i2o_hrt *hrt;
-	int len;
-	u32 reslen;
-	int ret = 0;
-
-	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))
-		return -EFAULT;
-
-	if(get_user(reslen, kcmd.reslen) < 0)
-		return -EFAULT;
-
-	if(kcmd.resbuf == NULL)
-		return -EFAULT;
-
-	c = i2o_find_controller(kcmd.iop);
-	if(!c)
-		return -ENXIO;
-		
-	hrt = (i2o_hrt *)c->hrt;
-
-	i2o_unlock_controller(c);
-
-	len = 8 + ((hrt->entry_len * hrt->num_entries) << 2);
-	
-	/* We did a get user...so assuming mem is ok...is this bad? */
-	put_user(len, kcmd.reslen);
-	if(len > reslen)
-		ret = -ENOBUFS;	
-	if(copy_to_user(kcmd.resbuf, (void*)hrt, len))
-		ret = -EFAULT;
-
-	return ret;
-}
-
-int ioctl_getlct(unsigned long arg)
-{
-	struct i2o_controller *c;
-	struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg;
-	struct i2o_cmd_hrtlct kcmd;
-	i2o_lct *lct;
-	int len;
-	int ret = 0;
-	u32 reslen;
-
-	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))
-		return -EFAULT;
-
-	if(get_user(reslen, kcmd.reslen) < 0)
-		return -EFAULT;
-
-	if(kcmd.resbuf == NULL)
-		return -EFAULT;
-
-	c = i2o_find_controller(kcmd.iop);
-	if(!c)
-		return -ENXIO;
-
-	lct = (i2o_lct *)c->lct;
-	i2o_unlock_controller(c);
-
-	len = (unsigned int)lct->table_size << 2;
-	put_user(len, kcmd.reslen);
-	if(len > reslen)
-		ret = -ENOBUFS;	
-	else if(copy_to_user(kcmd.resbuf, (void*)lct, len))
-		ret = -EFAULT;
-
-	return ret;
-}
-
-static int ioctl_parms(unsigned long arg, unsigned int type)
-{
-	int ret = 0;
-	struct i2o_controller *c;
-	struct i2o_cmd_psetget *cmd = (struct i2o_cmd_psetget*)arg;
-	struct i2o_cmd_psetget kcmd;
-	u32 reslen;
-	u8 *ops;
-	u8 *res;
-	int len;
-
-	u32 i2o_cmd = (type == I2OPARMGET ? 
-				I2O_CMD_UTIL_PARAMS_GET :
-				I2O_CMD_UTIL_PARAMS_SET);
-
-	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget)))
-		return -EFAULT;
-
-	if(get_user(reslen, kcmd.reslen))
-		return -EFAULT;
-
-	c = i2o_find_controller(kcmd.iop);
-	if(!c)
-		return -ENXIO;
-
-	ops = (u8*)kmalloc(kcmd.oplen, GFP_KERNEL);
-	if(!ops)
-	{
-		i2o_unlock_controller(c);
-		return -ENOMEM;
-	}
-
-	if(copy_from_user(ops, kcmd.opbuf, kcmd.oplen))
-	{
-		i2o_unlock_controller(c);
-		kfree(ops);
-		return -EFAULT;
-	}
-
-	/*
-	 * It's possible to have a _very_ large table
-	 * and that the user asks for all of it at once...
-	 */
-	res = (u8*)kmalloc(65536, GFP_KERNEL);
-	if(!res)
-	{
-		i2o_unlock_controller(c);
-		kfree(ops);
-		return -ENOMEM;
-	}
-
-	len = i2o_issue_params(i2o_cmd, c, kcmd.tid, 
-				ops, kcmd.oplen, res, 65536);
-	i2o_unlock_controller(c);
-	kfree(ops);
-        
-	if (len < 0) {
-		kfree(res);
-		return -EAGAIN;
-	}
-
-	put_user(len, kcmd.reslen);
-	if(len > reslen)
-		ret = -ENOBUFS;
-	else if(copy_to_user(cmd->resbuf, res, len))
-		ret = -EFAULT;
-
-	kfree(res);
-
-	return ret;
-}
-
-int ioctl_html(unsigned long arg)
-{
-	struct i2o_html *cmd = (struct i2o_html*)arg;
-	struct i2o_html kcmd;
-	struct i2o_controller *c;
-	u8 *res = NULL;
-	void *query = NULL;
-	int ret = 0;
-	int token;
-	u32 len;
-	u32 reslen;
-	u32 msg[MSG_FRAME_SIZE/4];
-
-	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_html)))
-	{
-		printk(KERN_INFO "i2o_config: can't copy html cmd\n");
-		return -EFAULT;
-	}
-
-	if(get_user(reslen, kcmd.reslen) < 0)
-	{
-		printk(KERN_INFO "i2o_config: can't copy html reslen\n");
-		return -EFAULT;
-	}
-
-	if(!kcmd.resbuf)		
-	{
-		printk(KERN_INFO "i2o_config: NULL html buffer\n");
-		return -EFAULT;
-	}
-
-	c = i2o_find_controller(kcmd.iop);
-	if(!c)
-		return -ENXIO;
-
-	if(kcmd.qlen) /* Check for post data */
-	{
-		query = kmalloc(kcmd.qlen, GFP_KERNEL);
-		if(!query)
-		{
-			i2o_unlock_controller(c);
-			return -ENOMEM;
-		}
-		if(copy_from_user(query, kcmd.qbuf, kcmd.qlen))
-		{
-			i2o_unlock_controller(c);
-			printk(KERN_INFO "i2o_config: could not get query\n");
-			kfree(query);
-			return -EFAULT;
-		}
-	}
-
-	res = kmalloc(65536, GFP_KERNEL);
-	if(!res)
-	{
-		i2o_unlock_controller(c);
-		kfree(query);
-		return -ENOMEM;
-	}
-
-	msg[1] = (I2O_CMD_UTIL_CONFIG_DIALOG << 24)|HOST_TID<<12|kcmd.tid;
-	msg[2] = i2o_cfg_context;
-	msg[3] = 0;
-	msg[4] = kcmd.page;
-	msg[5] = 0xD0000000|65536;
-	msg[6] = virt_to_bus(res);
-	if(!kcmd.qlen) /* Check for post data */
-		msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5;
-	else
-	{
-		msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
-		msg[5] = 0x50000000|65536;
-		msg[7] = 0xD4000000|(kcmd.qlen);
-		msg[8] = virt_to_bus(query);
-	}
-	/*
-	Wait for a considerable time till the Controller 
-	does its job before timing out. The controller might
-	take more time to process this request if there are
-	many devices connected to it.
-	*/
-	token = i2o_post_wait_mem(c, msg, 9*4, 400, query, res);
-	if(token < 0)
-	{
-		printk(KERN_DEBUG "token = %#10x\n", token);
-		i2o_unlock_controller(c);
-		
-		if(token != -ETIMEDOUT)
-		{
-			kfree(res);
-			if(kcmd.qlen) kfree(query);
-		}
-
-		return token;
-	}
-	i2o_unlock_controller(c);
-
-	len = strnlen(res, 65536);
-	put_user(len, kcmd.reslen);
-	if(len > reslen)
-		ret = -ENOMEM;
-	if(copy_to_user(kcmd.resbuf, res, len))
-		ret = -EFAULT;
-
-	kfree(res);
-	if(kcmd.qlen) 
-		kfree(query);
-
-	return ret;
-}
- 
-int ioctl_swdl(unsigned long arg)
-{
-	struct i2o_sw_xfer kxfer;
-	struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg;
-	unsigned char maxfrag = 0, curfrag = 1;
-	unsigned char *buffer;
-	u32 msg[9];
-	unsigned int status = 0, swlen = 0, fragsize = 8192;
-	struct i2o_controller *c;
-
-	if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
-		return -EFAULT;
-
-	if(get_user(swlen, kxfer.swlen) < 0)
-		return -EFAULT;
-
-	if(get_user(maxfrag, kxfer.maxfrag) < 0)
-		return -EFAULT;
-
-	if(get_user(curfrag, kxfer.curfrag) < 0)
-		return -EFAULT;
-
-	if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192;
-
-	if(!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize))
-		return -EFAULT;
-	
-	c = i2o_find_controller(kxfer.iop);
-	if(!c)
-		return -ENXIO;
-
-	buffer=kmalloc(fragsize, GFP_KERNEL);
-	if (buffer==NULL)
-	{
-		i2o_unlock_controller(c);
-		return -ENOMEM;
-	}
-	__copy_from_user(buffer, kxfer.buf, fragsize);
-
-	msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7;
-	msg[1]= I2O_CMD_SW_DOWNLOAD<<24 | HOST_TID<<12 | ADAPTER_TID;
-	msg[2]= (u32)cfg_handler.context;
-	msg[3]= 0;
-	msg[4]= (((u32)kxfer.flags)<<24) | (((u32)kxfer.sw_type)<<16) |
-		(((u32)maxfrag)<<8) | (((u32)curfrag));
-	msg[5]= swlen;
-	msg[6]= kxfer.sw_id;
-	msg[7]= (0xD0000000 | fragsize);
-	msg[8]= virt_to_bus(buffer);
-
-//	printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
-	status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL);
-
-	i2o_unlock_controller(c);
-	if(status != -ETIMEDOUT)
-		kfree(buffer);
-	
-	if (status != I2O_POST_WAIT_OK)
-	{
-		// it fails if you try and send frags out of order
-		// and for some yet unknown reasons too
-		printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status);
-		return status;
-	}
-
-	return 0;
-}
-
-int ioctl_swul(unsigned long arg)
-{
-	struct i2o_sw_xfer kxfer;
-	struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg;
-	unsigned char maxfrag = 0, curfrag = 1;
-	unsigned char *buffer;
-	u32 msg[9];
-	unsigned int status = 0, swlen = 0, fragsize = 8192;
-	struct i2o_controller *c;
-	
-	if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
-		return -EFAULT;
-		
-	if(get_user(swlen, kxfer.swlen) < 0)
-		return -EFAULT;
-		
-	if(get_user(maxfrag, kxfer.maxfrag) < 0)
-		return -EFAULT;
-		
-	if(get_user(curfrag, kxfer.curfrag) < 0)
-		return -EFAULT;
-	
-	if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192;
-	
-	if(!kxfer.buf || !access_ok(VERIFY_WRITE, kxfer.buf, fragsize))
-		return -EFAULT;
-		
-	c = i2o_find_controller(kxfer.iop);
-	if(!c)
-		return -ENXIO;
-		
-	buffer=kmalloc(fragsize, GFP_KERNEL);
-	if (buffer==NULL)
-	{
-		i2o_unlock_controller(c);
-		return -ENOMEM;
-	}
-	
-	msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7;
-	msg[1]= I2O_CMD_SW_UPLOAD<<24 | HOST_TID<<12 | ADAPTER_TID;
-	msg[2]= (u32)cfg_handler.context;
-	msg[3]= 0;
-	msg[4]= (u32)kxfer.flags<<24|(u32)kxfer.sw_type<<16|(u32)maxfrag<<8|(u32)curfrag;
-	msg[5]= swlen;
-	msg[6]= kxfer.sw_id;
-	msg[7]= (0xD0000000 | fragsize);
-	msg[8]= virt_to_bus(buffer);
-	
-//	printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
-	status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL);
-	i2o_unlock_controller(c);
-	
-	if (status != I2O_POST_WAIT_OK)
-	{
-		if(status != -ETIMEDOUT)
-			kfree(buffer);
-		printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status);
-		return status;
-	}
-	
-	__copy_to_user(kxfer.buf, buffer, fragsize);
-	kfree(buffer);
-	
-	return 0;
-}
-
-int ioctl_swdel(unsigned long arg)
-{
-	struct i2o_controller *c;
-	struct i2o_sw_xfer kxfer, *pxfer = (struct i2o_sw_xfer *)arg;
-	u32 msg[7];
-	unsigned int swlen;
-	int token;
-	
-	if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
-		return -EFAULT;
-		
-	if (get_user(swlen, kxfer.swlen) < 0)
-		return -EFAULT;
-		
-	c = i2o_find_controller(kxfer.iop);
-	if (!c)
-		return -ENXIO;
-
-	msg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
-	msg[1] = I2O_CMD_SW_REMOVE<<24 | HOST_TID<<12 | ADAPTER_TID;
-	msg[2] = (u32)i2o_cfg_context;
-	msg[3] = 0;
-	msg[4] = (u32)kxfer.flags<<24 | (u32)kxfer.sw_type<<16;
-	msg[5] = swlen;
-	msg[6] = kxfer.sw_id;
-
-	token = i2o_post_wait(c, msg, sizeof(msg), 10);
-	i2o_unlock_controller(c);
-	
-	if (token != I2O_POST_WAIT_OK)
-	{
-		printk(KERN_INFO "i2o_config: swdel failed, DetailedStatus = %d\n", token);
-		return -ETIMEDOUT;
-	}
-	
-	return 0;
-}
-
-int ioctl_validate(unsigned long arg)
-{
-        int token;
-        int iop = (int)arg;
-        u32 msg[4];
-        struct i2o_controller *c;
-
-        c=i2o_find_controller(iop);
-        if (!c)
-                return -ENXIO;
-
-        msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
-        msg[1] = I2O_CMD_CONFIG_VALIDATE<<24 | HOST_TID<<12 | iop;
-        msg[2] = (u32)i2o_cfg_context;
-        msg[3] = 0;
-
-        token = i2o_post_wait(c, msg, sizeof(msg), 10);
-        i2o_unlock_controller(c);
-
-        if (token != I2O_POST_WAIT_OK)
-        {
-                printk(KERN_INFO "Can't validate configuration, ErrorStatus = %d\n",
-                	token);
-                return -ETIMEDOUT;
-        }
-
-        return 0;
-}   
-
-static int ioctl_evt_reg(unsigned long arg, struct file *fp)
-{
-	u32 msg[5];
-	struct i2o_evt_id *pdesc = (struct i2o_evt_id *)arg;
-	struct i2o_evt_id kdesc;
-	struct i2o_controller *iop;
-	struct i2o_device *d;
-
-	if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id)))
-		return -EFAULT;
-
-	/* IOP exists? */
-	iop = i2o_find_controller(kdesc.iop);
-	if(!iop)
-		return -ENXIO;
-	i2o_unlock_controller(iop);
-
-	/* Device exists? */
-	for(d = iop->devices; d; d = d->next)
-		if(d->lct_data.tid == kdesc.tid)
-			break;
-
-	if(!d)
-		return -ENODEV;
-
-	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
-	msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | kdesc.tid;
-	msg[2] = (u32)i2o_cfg_context;
-	msg[3] = (u32)fp->private_data;
-	msg[4] = kdesc.evt_mask;
-
-	i2o_post_this(iop, msg, 20);
-
-	return 0;
-}	
-
-static int ioctl_evt_get(unsigned long arg, struct file *fp)
-{
-	u32 id = (u32)fp->private_data;
-	struct i2o_cfg_info *p = NULL;
-	struct i2o_evt_get *uget = (struct i2o_evt_get*)arg;
-	struct i2o_evt_get kget;
-	unsigned long flags;
-
-	for(p = open_files; p; p = p->next)
-		if(p->q_id == id)
-			break;
-
-	if(!p->q_len)
-	{
-		return -ENOENT;
-		return 0;
-	}
-
-	memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info));
-	MODINC(p->q_out, I2O_EVT_Q_LEN);
-	spin_lock_irqsave(&i2o_config_lock, flags);
-	p->q_len--;
-	kget.pending = p->q_len;
-	kget.lost = p->q_lost;
-	spin_unlock_irqrestore(&i2o_config_lock, flags);
-
-	if(copy_to_user(uget, &kget, sizeof(struct i2o_evt_get)))
-		return -EFAULT;
-	return 0;
-}
-
-static int cfg_open(struct inode *inode, struct file *file)
-{
-	struct i2o_cfg_info *tmp = 
-		(struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), GFP_KERNEL);
-	unsigned long flags;
-
-	if(!tmp)
-		return -ENOMEM;
-
-	file->private_data = (void*)(i2o_cfg_info_id++);
-	tmp->fp = file;
-	tmp->fasync = NULL;
-	tmp->q_id = (u32)file->private_data;
-	tmp->q_len = 0;
-	tmp->q_in = 0;
-	tmp->q_out = 0;
-	tmp->q_lost = 0;
-	tmp->next = open_files;
-
-	spin_lock_irqsave(&i2o_config_lock, flags);
-	open_files = tmp;
-	spin_unlock_irqrestore(&i2o_config_lock, flags);
-	
-	return 0;
-}
-
-static int cfg_release(struct inode *inode, struct file *file)
-{
-	u32 id = (u32)file->private_data;
-	struct i2o_cfg_info *p1, *p2;
-	unsigned long flags;
-
-	lock_kernel();
-	p1 = p2 = NULL;
-
-	spin_lock_irqsave(&i2o_config_lock, flags);
-	for(p1 = open_files; p1; )
-	{
-		if(p1->q_id == id)
-		{
-
-			if(p1->fasync)
-				cfg_fasync(-1, file, 0);
-			if(p2)
-				p2->next = p1->next;
-			else
-				open_files = p1->next;
-
-			kfree(p1);
-			break;
-		}
-		p2 = p1;
-		p1 = p1->next;
-	}
-	spin_unlock_irqrestore(&i2o_config_lock, flags);
-	unlock_kernel();
-
-	return 0;
-}
-
-static int cfg_fasync(int fd, struct file *fp, int on)
-{
-	u32 id = (u32)fp->private_data;
-	struct i2o_cfg_info *p;
-
-	for(p = open_files; p; p = p->next)
-		if(p->q_id == id)
-			break;
-
-	if(!p)
-		return -EBADF;
-
-	return fasync_helper(fd, fp, on, &p->fasync);
-}
-
-static struct file_operations config_fops =
-{
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		cfg_read,
-	write:		cfg_write,
-	ioctl:		cfg_ioctl,
-	open:		cfg_open,
-	release:	cfg_release,
-	fasync:		cfg_fasync,
-};
-
-static struct miscdevice i2o_miscdev = {
-	I2O_MINOR,
-	"i2octl",
-	&config_fops
-};	
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init i2o_config_init(void)
-#endif
-{
-	printk(KERN_INFO "I2O configuration manager v 0.04.\n");
-	printk(KERN_INFO "  (C) Copyright 1999 Red Hat Software\n");
-	
-	if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL)
-	{
-		printk(KERN_ERR "i2o_config: no memory for page buffer.\n");
-		return -ENOBUFS;
-	}
-	if(misc_register(&i2o_miscdev)==-1)
-	{
-		printk(KERN_ERR "i2o_config: can't register device.\n");
-		kfree(page_buf);
-		return -EBUSY;
-	}
-	/*
-	 *	Install our handler
-	 */
-	if(i2o_install_handler(&cfg_handler)<0)
-	{
-		kfree(page_buf);
-		printk(KERN_ERR "i2o_config: handler register failed.\n");
-		misc_deregister(&i2o_miscdev);
-		return -EBUSY;
-	}
-	/*
-	 *	The low 16bits of the transaction context must match this
-	 *	for everything we post. Otherwise someone else gets our mail
-	 */
-	i2o_cfg_context = cfg_handler.context;
-	return 0;
-}
-
-#ifdef MODULE
-
-void cleanup_module(void)
-{
-	misc_deregister(&i2o_miscdev);
-	
-	if(page_buf)
-		kfree(page_buf);
-	if(i2o_cfg_context != -1)
-		i2o_remove_handler(&cfg_handler);
-}
- 
-EXPORT_NO_SYMBOLS;
-MODULE_AUTHOR("Red Hat Software");
-MODULE_DESCRIPTION("I2O Configuration");
-
-#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
--- v2.4.12/linux/drivers/i2o/i2o_core.c	Mon Aug 27 12:41:41 2001
+++ linux/drivers/i2o/i2o_core.c	Wed Dec 31 16:00:00 1969
@@ -1,3564 +0,0 @@
-/*
- * Core I2O structure management 
- * 
- * (C) Copyright 1999   Red Hat Software 
- *
- * Written by Alan Cox, Building Number Three Ltd 
- * 
- * 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.  
- * 
- * A lot of the I2O message side code from this is taken from the 
- * Red Creek RCPCI45 adapter driver by Red Creek Communications 
- * 
- * Fixes by: 
- *		Philipp Rumpf 
- *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> 
- *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> 
- *		Deepak Saxena <deepak@plexity.net> 
- *		Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
- * 
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-
-#include <linux/i2o.h>
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-
-#include <linux/bitops.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/tqueue.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <asm/semaphore.h>
-#include <linux/completion.h>
-
-#include <asm/io.h>
-#include <linux/reboot.h>
-
-#include "i2o_lan.h"
-
-//#define DRIVERDEBUG
-
-#ifdef DRIVERDEBUG
-#define dprintk(s, args...) printk(s, ## args)
-#else
-#define dprintk(s, args...)
-#endif
-
-/* OSM table */
-static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES];
-
-/* Controller list */
-static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];
-struct i2o_controller *i2o_controller_chain;
-int i2o_num_controllers;
-
-/* Initiator Context for Core message */
-static int core_context;
-
-/* Initialization && shutdown functions */
-static void i2o_sys_init(void);
-static void i2o_sys_shutdown(void);
-static int i2o_reset_controller(struct i2o_controller *);
-static int i2o_reboot_event(struct notifier_block *, unsigned long , void *);
-static int i2o_online_controller(struct i2o_controller *);
-static int i2o_init_outbound_q(struct i2o_controller *);
-static int i2o_post_outbound_messages(struct i2o_controller *);
-
-/* Reply handler */
-static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *,
-			   struct i2o_message *);
-
-/* Various helper functions */
-static int i2o_lct_get(struct i2o_controller *);
-static int i2o_lct_notify(struct i2o_controller *);
-static int i2o_hrt_get(struct i2o_controller *);
-
-static int i2o_build_sys_table(void);
-static int i2o_systab_send(struct i2o_controller *c);
-
-/* I2O core event handler */
-static int i2o_core_evt(void *);
-static int evt_pid;
-static int evt_running;
-
-/* Dynamic LCT update handler */
-static int i2o_dyn_lct(void *);
-
-void i2o_report_controller_unit(struct i2o_controller *, struct i2o_device *);
-
-/*
- * I2O System Table.  Contains information about
- * all the IOPs in the system.  Used to inform IOPs
- * about each other's existence.
- *
- * sys_tbl_ver is the CurrentChangeIndicator that is
- * used by IOPs to track changes.
- */
-static struct i2o_sys_tbl *sys_tbl;
-static int sys_tbl_ind;
-static int sys_tbl_len;
-
-/*
- * This spin lock is used to keep a device from being
- * added and deleted concurrently across CPUs or interrupts.
- * This can occur when a user creates a device and immediatelly
- * deletes it before the new_dev_notify() handler is called.
- */
-static spinlock_t i2o_dev_lock = SPIN_LOCK_UNLOCKED;
-
-#ifdef MODULE
-/* 
- * Function table to send to bus specific layers
- * See <include/linux/i2o.h> for explanation of this
- */
-static struct i2o_core_func_table i2o_core_functions =
-{
-	i2o_install_controller,
-	i2o_activate_controller,
-	i2o_find_controller,
-	i2o_unlock_controller,
-	i2o_run_queue,
-	i2o_delete_controller
-};
-
-#ifdef CONFIG_I2O_PCI_MODULE
-extern int i2o_pci_core_attach(struct i2o_core_func_table *);
-extern void i2o_pci_core_detach(void);
-#endif /* CONFIG_I2O_PCI_MODULE */
-
-#endif /* MODULE */
-
-/*
- * Structures and definitions for synchronous message posting.
- * See i2o_post_wait() for description.
- */ 
-struct i2o_post_wait_data
-{
-	int *status;		/* Pointer to status block on caller stack */
-	int *complete;		/* Pointer to completion flag on caller stack */
-	u32 id;			/* Unique identifier */
-	wait_queue_head_t *wq;	/* Wake up for caller (NULL for dead) */
-	struct i2o_post_wait_data *next;	/* Chain */
-	void *mem[2];		/* Memory blocks to recover on failure path */
-};
-static struct i2o_post_wait_data *post_wait_queue;
-static u32 post_wait_id;	// Unique ID for each post_wait
-static spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED;
-static void i2o_post_wait_complete(u32, int);
-
-/* OSM descriptor handler */ 
-static struct i2o_handler i2o_core_handler =
-{
-	(void *)i2o_core_reply,
-	NULL,
-	NULL,
-	NULL,
-	"I2O core layer",
-	0,
-	I2O_CLASS_EXECUTIVE
-};
-
-/*
- * Used when queueing a reply to be handled later
- */
- 
-struct reply_info
-{
-	struct i2o_controller *iop;
-	u32 msg[MSG_FRAME_SIZE];
-};
-static struct reply_info evt_reply;
-static struct reply_info events[I2O_EVT_Q_LEN];
-static int evt_in;
-static int evt_out;
-static int evt_q_len;
-#define MODINC(x,y) ((x) = ((x) + 1) % (y))
-
-/*
- * I2O configuration spinlock. This isnt a big deal for contention
- * so we have one only
- */
-
-static DECLARE_MUTEX(i2o_configuration_lock);
-
-/* 
- * Event spinlock.  Used to keep event queue sane and from
- * handling multiple events simultaneously.
- */
-static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- * Semaphore used to synchronize event handling thread with 
- * interrupt handler.
- */
- 
-static DECLARE_MUTEX(evt_sem);
-static DECLARE_COMPLETION(evt_dead);
-DECLARE_WAIT_QUEUE_HEAD(evt_wait);
-
-static struct notifier_block i2o_reboot_notifier =
-{
-        i2o_reboot_event,
-        NULL,
-        0
-};
-
-/*
- *	Config options
- */
-
-static int verbose;
-MODULE_PARM(verbose, "i");
-
-/*
- * I2O Core reply handler
- */
-static void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,
-		    struct i2o_message *m)
-{
-	u32 *msg=(u32 *)m;
-	u32 status;
-	u32 context = msg[2];
-
-	if (msg[0] & MSG_FAIL) // Fail bit is set
-	{
-		u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]);
-
-		i2o_report_status(KERN_INFO, "i2o_core", msg);
-		i2o_dump_message(preserved_msg);
-
-		/* If the failed request needs special treatment,
-		 * it should be done here. */
-
-                /* Release the preserved msg by resubmitting it as a NOP */
-
-		preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
-		preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
-		preserved_msg[2] = 0;
-		i2o_post_message(c, msg[7]);
-
-		/* If reply to i2o_post_wait failed, return causes a timeout */
-
-		return;
-	}       
-
-#ifdef DRIVERDEBUG
-	i2o_report_status(KERN_INFO, "i2o_core", msg);
-#endif
-
-	if(msg[2]&0x80000000)	// Post wait message
-	{
-		if (msg[4] >> 24)
-			status = (msg[4] & 0xFFFF);
-		else
-			status = I2O_POST_WAIT_OK;
-	
-		i2o_post_wait_complete(context, status);
-		return;
-	}
-
-	if(m->function == I2O_CMD_UTIL_EVT_REGISTER)
-	{
-		memcpy(events[evt_in].msg, msg, (msg[0]>>16)<<2);
-		events[evt_in].iop = c;
-
-		spin_lock(&i2o_evt_lock);
-		MODINC(evt_in, I2O_EVT_Q_LEN);
-		if(evt_q_len == I2O_EVT_Q_LEN)
-			MODINC(evt_out, I2O_EVT_Q_LEN);
-		else
-			evt_q_len++;
-		spin_unlock(&i2o_evt_lock);
-
-		up(&evt_sem);
-		wake_up_interruptible(&evt_wait);
-		return;
-	}
-
-	if(m->function == I2O_CMD_LCT_NOTIFY)
-	{
-		up(&c->lct_sem);
-		return;
-	}
-
-	/*
-	 * If this happens, we want to dump the message to the syslog so
-	 * it can be sent back to the card manufacturer by the end user
-	 * to aid in debugging.
-	 * 
-	 */
-	printk(KERN_WARNING "%s: Unsolicited message reply sent to core!"
-			"Message dumped to syslog\n", 
-			c->name);
-	i2o_dump_message(msg);
-
-	return;
-}
-
-/**
- *	i2o_install_handler - install a message handler
- *	@h: Handler structure
- *
- *	Install an I2O handler - these handle the asynchronous messaging
- *	from the card once it has initialised. If the table of handlers is
- *	full then -ENOSPC is returned. On a success 0 is returned and the
- *	context field is set by the function. The structure is part of the
- *	system from this time onwards. It must not be freed until it has
- *	been uninstalled
- */
- 
-int i2o_install_handler(struct i2o_handler *h)
-{
-	int i;
-	down(&i2o_configuration_lock);
-	for(i=0;i<MAX_I2O_MODULES;i++)
-	{
-		if(i2o_handlers[i]==NULL)
-		{
-			h->context = i;
-			i2o_handlers[i]=h;
-			up(&i2o_configuration_lock);
-			return 0;
-		}
-	}
-	up(&i2o_configuration_lock);
-	return -ENOSPC;
-}
-
-/**
- *	i2o_remove_handler - remove an i2o message handler
- *	@h: handler
- *
- *	Remove a message handler previously installed with i2o_install_handler.
- *	After this function returns the handler object can be freed or re-used
- */
- 
-int i2o_remove_handler(struct i2o_handler *h)
-{
-	i2o_handlers[h->context]=NULL;
-	return 0;
-}
-	
-
-/*
- *	Each I2O controller has a chain of devices on it.
- * Each device has a pointer to it's LCT entry to be used
- * for fun purposes.
- */
-
-/**
- *	i2o_install_device	-	attach a device to a controller
- *	@c: controller
- *	@d: device
- * 	
- *	Add a new device to an i2o controller. This can be called from
- *	non interrupt contexts only. It adds the device and marks it as
- *	unclaimed. The device memory becomes part of the kernel and must
- *	be uninstalled before being freed or reused. Zero is returned
- *	on success.
- */
- 
-int i2o_install_device(struct i2o_controller *c, struct i2o_device *d)
-{
-	int i;
-
-	down(&i2o_configuration_lock);
-	d->controller=c;
-	d->owner=NULL;
-	d->next=c->devices;
-	d->prev=NULL;
-	if (c->devices != NULL)
-		c->devices->prev=d;
-	c->devices=d;
-	*d->dev_name = 0;
-
-	for(i = 0; i < I2O_MAX_MANAGERS; i++)
-		d->managers[i] = NULL;
-
-	up(&i2o_configuration_lock);
-	return 0;
-}
-
-/* we need this version to call out of i2o_delete_controller */
-
-int __i2o_delete_device(struct i2o_device *d)
-{
-	struct i2o_device **p;
-	int i;
-
-	p=&(d->controller->devices);
-
-	/*
-	 *	Hey we have a driver!
-	 * Check to see if the driver wants us to notify it of 
-	 * device deletion. If it doesn't we assume that it
-	 * is unsafe to delete a device with an owner and 
-	 * fail.
-	 */
-	if(d->owner)
-	{
-		if(d->owner->dev_del_notify)
-		{
-			dprintk(KERN_INFO "Device has owner, notifying\n");
-			d->owner->dev_del_notify(d->controller, d);
-			if(d->owner)
-			{
-				printk(KERN_WARNING 
-					"Driver \"%s\" did not release device!\n", d->owner->name);
-				return -EBUSY;
-			}
-		}
-		else
-			return -EBUSY;
-	}
-
-	/*
-	 * Tell any other users who are talking to this device
-	 * that it's going away.  We assume that everything works.
-	 */
-	for(i=0; i < I2O_MAX_MANAGERS; i++)
-	{
-		if(d->managers[i] && d->managers[i]->dev_del_notify)
-			d->managers[i]->dev_del_notify(d->controller, d);
-	}
-	 			
-	while(*p!=NULL)
-	{
-		if(*p==d)
-		{
-			/*
-			 *	Destroy
-			 */
-			*p=d->next;
-			kfree(d);
-			return 0;
-		}
-		p=&((*p)->next);
-	}
-	printk(KERN_ERR "i2o_delete_device: passed invalid device.\n");
-	return -EINVAL;
-}
-
-/**
- *	i2o_delete_device	-	remove an i2o device
- *	@d: device to remove
- *
- *	This function unhooks a device from a controller. The device
- *	will not be unhooked if it has an owner who does not wish to free
- *	it, or if the owner lacks a dev_del_notify function. In that case
- *	-EBUSY is returned. On success 0 is returned. Other errors cause
- *	negative errno values to be returned
- */
- 
-int i2o_delete_device(struct i2o_device *d)
-{
-	int ret;
-
-	down(&i2o_configuration_lock);
-
-	/*
-	 *	Seek, locate
-	 */
-
-	ret = __i2o_delete_device(d);
-
-	up(&i2o_configuration_lock);
-
-	return ret;
-}
-
-/**
- *	i2o_install_controller	-	attach a controller
- *	@c: controller
- * 	
- *	Add a new controller to the i2o layer. This can be called from
- *	non interrupt contexts only. It adds the controller and marks it as
- *	unused with no devices. If the tables are full or memory allocations
- *	fail then a negative errno code is returned. On success zero is
- *	returned and the controller is bound to the system. The structure
- *	must not be freed or reused until being uninstalled.
- */
- 
-int i2o_install_controller(struct i2o_controller *c)
-{
-	int i;
-	down(&i2o_configuration_lock);
-	for(i=0;i<MAX_I2O_CONTROLLERS;i++)
-	{
-		if(i2o_controllers[i]==NULL)
-		{
-			c->dlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL);
-			if(c->dlct==NULL)
-			{
-				up(&i2o_configuration_lock);
-				return -ENOMEM;
-			}
-			i2o_controllers[i]=c;
-			c->devices = NULL;
-			c->next=i2o_controller_chain;
-			i2o_controller_chain=c;
-			c->unit = i;
-			c->page_frame = NULL;
-			c->hrt = NULL;
-			c->lct = NULL;
-			c->status_block = NULL;
-			sprintf(c->name, "i2o/iop%d", i);
-			i2o_num_controllers++;
-			init_MUTEX_LOCKED(&c->lct_sem);
-			up(&i2o_configuration_lock);
-			return 0;
-		}
-	}
-	printk(KERN_ERR "No free i2o controller slots.\n");
-	up(&i2o_configuration_lock);
-	return -EBUSY;
-}
-
-/**
- *	i2o_delete_controller	- delete a controller
- *	@c: controller
- *	
- *	Remove an i2o controller from the system. If the controller or its
- *	devices are busy then -EBUSY is returned. On a failure a negative
- *	errno code is returned. On success zero is returned.
- */
-  
-int i2o_delete_controller(struct i2o_controller *c)
-{
-	struct i2o_controller **p;
-	int users;
-	char name[16];
-	int stat;
-
-	dprintk(KERN_INFO "Deleting controller %s\n", c->name);
-
-	/*
-	 * Clear event registration as this can cause weird behavior
-	 */
-	if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL)
-		i2o_event_register(c, core_context, 0, 0, 0);
-
-	down(&i2o_configuration_lock);
-	if((users=atomic_read(&c->users)))
-	{
-		dprintk(KERN_INFO "I2O: %d users for controller %s\n", users,
-			c->name);
-		up(&i2o_configuration_lock);
-		return -EBUSY;
-	}
-	while(c->devices)
-	{
-		if(__i2o_delete_device(c->devices)<0)
-		{
-			/* Shouldnt happen */
-			c->bus_disable(c);
-			up(&i2o_configuration_lock);
-			return -EBUSY;
-		}
-	}
-
-	/*
-	 * If this is shutdown time, the thread's already been killed
-	 */
-	if(c->lct_running) {
-		stat = kill_proc(c->lct_pid, SIGTERM, 1);
-		if(!stat) {
-			int count = 10 * 100;
-			while(c->lct_running && --count) {
-				current->state = TASK_INTERRUPTIBLE;
-				schedule_timeout(1);
-			}
-		
-			if(!count)
-				printk(KERN_ERR 
-					"%s: LCT thread still running!\n", 
-					c->name);
-		}
-	}
-
-	p=&i2o_controller_chain;
-
-	while(*p)
-	{
-		if(*p==c)
-		{
- 			/* Ask the IOP to switch to RESET state */
-			i2o_reset_controller(c);
-
-			/* Release IRQ */
-			c->destructor(c);
-
-			*p=c->next;
-			up(&i2o_configuration_lock);
-
-			if(c->page_frame)
-				kfree(c->page_frame);
-			if(c->hrt)
-				kfree(c->hrt);
-			if(c->lct)
-				kfree(c->lct);
-			if(c->status_block)
-				kfree(c->status_block);
-			if(c->dlct)
-				kfree(c->dlct);
-
-			i2o_controllers[c->unit]=NULL;
-			memcpy(name, c->name, strlen(c->name)+1);
-			kfree(c);
-			dprintk(KERN_INFO "%s: Deleted from controller chain.\n", name);
-			
-			i2o_num_controllers--;
-			return 0;
-		}
-		p=&((*p)->next);
-	}
-	up(&i2o_configuration_lock);
-	printk(KERN_ERR "i2o_delete_controller: bad pointer!\n");
-	return -ENOENT;
-}
-
-/**
- *	i2o_unlock_controller	-	unlock a controller
- *	@c: controller to unlock
- *
- *	Take a lock on an i2o controller. This prevents it being deleted.
- *	i2o controllers are not refcounted so a deletion of an in use device
- *	will fail, not take affect on the last dereference.
- */
- 
-void i2o_unlock_controller(struct i2o_controller *c)
-{
-	atomic_dec(&c->users);
-}
-
-/**
- *	i2o_find_controller - return a locked controller
- *	@n: controller number
- *
- *	Returns a pointer to the controller object. The controller is locked
- *	on return. NULL is returned if the controller is not found.
- */
- 
-struct i2o_controller *i2o_find_controller(int n)
-{
-	struct i2o_controller *c;
-	
-	if(n<0 || n>=MAX_I2O_CONTROLLERS)
-		return NULL;
-	
-	down(&i2o_configuration_lock);
-	c=i2o_controllers[n];
-	if(c!=NULL)
-		atomic_inc(&c->users);
-	up(&i2o_configuration_lock);
-	return c;
-}
-
-/**
- *	i2o_issue_claim	- claim or release a device
- *	@cmd: command
- *	@c: controller to claim for
- *	@tid: i2o task id
- *	@type: type of claim
- *
- *	Issue I2O UTIL_CLAIM and UTIL_RELEASE messages. The message to be sent
- *	is set by cmd. The tid is the task id of the object to claim and the
- *	type is the claim type (see the i2o standard)
- *
- *	Zero is returned on success.
- */
- 
-static int i2o_issue_claim(u32 cmd, struct i2o_controller *c, int tid, u32 type)
-{
-	u32 msg[5];
-
-	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
-	msg[1] = cmd << 24 | HOST_TID<<12 | tid;
-	msg[3] = 0;
-	msg[4] = type;
-	
-	return i2o_post_wait(c, msg, sizeof(msg), 60);
-}
-
-/*
- * 	i2o_claim_device - claim a device for use by an OSM
- *	@d: device to claim
- *	@h: handler for this device
- *
- *	Do the leg work to assign a device to a given OSM on Linux. The
- *	kernel updates the internal handler data for the device and then
- *	performs an I2O claim for the device, attempting to claim the
- *	device as primary. If the attempt fails a negative errno code
- *	is returned. On success zero is returned.
- */
- 
-int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h)
-{
-	down(&i2o_configuration_lock);
-	if (d->owner) {
-		printk(KERN_INFO "Device claim called, but dev already owned by %s!",
-		       h->name);
-		up(&i2o_configuration_lock);
-		return -EBUSY;
-	}
-	d->owner=h;
-
-	if(i2o_issue_claim(I2O_CMD_UTIL_CLAIM ,d->controller,d->lct_data.tid, 
-			   I2O_CLAIM_PRIMARY))
-	{
-		d->owner = NULL;
-		return -EBUSY;
-	}
-	up(&i2o_configuration_lock);
-	return 0;
-}
-
-/**
- *	i2o_release_device - release a device that the OSM is using
- *	@d: device to claim
- *	@h: handler for this device
- *
- *	Drop a claim by an OSM on a given I2O device. The handler is cleared
- *	and 0 is returned on success.
- *
- *	AC - some devices seem to want to refuse an unclaim until they have
- *	finished internal processing. It makes sense since you don't want a
- *	new device to go reconfiguring the entire system until you are done.
- *	Thus we are prepared to wait briefly.
- */
-
-int i2o_release_device(struct i2o_device *d, struct i2o_handler *h)
-{
-	int err = 0;
-	int tries;
-
-	down(&i2o_configuration_lock);
-	if (d->owner != h) {
-		printk(KERN_INFO "Claim release called, but not owned by %s!\n",
-		       h->name);
-		up(&i2o_configuration_lock);
-		return -ENOENT;
-	}	
-
-	for(tries=0;tries<10;tries++)
-	{
-		d->owner = NULL;
-
-		/*
-		 *	If the controller takes a nonblocking approach to
-		 *	releases we have to sleep/poll for a few times.
-		 */
-		 
-		if((err=i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, I2O_CLAIM_PRIMARY)) )
-		{
-			err = -ENXIO;
-			current->state = TASK_UNINTERRUPTIBLE;
-			schedule_timeout(HZ);
-		}
-		else
-		{
-			err=0;
-			break;
-		}
-	}
-	up(&i2o_configuration_lock);
-	return err;
-}
-
-/**
- * 	i2o_device_notify_on	-	Enable deletion notifiers
- *	@d: device for notification
- *	@h: handler to install
- *
- *	Called by OSMs to let the core know that they want to be
- *	notified if the given device is deleted from the system.
- */
-
-int i2o_device_notify_on(struct i2o_device *d, struct i2o_handler *h)
-{
-	int i;
-
-	if(d->num_managers == I2O_MAX_MANAGERS)
-		return -ENOSPC;
-
-	for(i = 0; i < I2O_MAX_MANAGERS; i++)
-	{
-		if(!d->managers[i])
-		{
-			d->managers[i] = h;
-			break;
-		}
-	}
-	
-	d->num_managers++;
-	
-	return 0;
-}
-
-/**
- * 	i2o_device_notify_off	-	Remove deletion notifiers
- *	@d: device for notification
- *	@h: handler to remove
- *
- * Called by OSMs to let the core know that they no longer
- * are interested in the fate of the given device.
- */
-int i2o_device_notify_off(struct i2o_device *d, struct i2o_handler *h)
-{
-	int i;
-
-	for(i=0; i < I2O_MAX_MANAGERS; i++)
-	{
-		if(d->managers[i] == h)
-		{
-			d->managers[i] = NULL;
-			d->num_managers--;
-			return 0;
-		}
-	}
-
-	return -ENOENT;
-}
-
-/**
- *	i2o_event_register	-	register interest in an event
- * 	@c: Controller to register interest with
- *	@tid: I2O task id
- *	@init_context: initiator context to use with this notifier
- *	@tr_context: transaction context to use with this notifier
- *	@evt_mask: mask of events
- *
- *	Create and posts an event registration message to the task. No reply
- *	is waited for, or expected. Errors in posting will be reported.
- */
- 
-int i2o_event_register(struct i2o_controller *c, u32 tid, 
-		u32 init_context, u32 tr_context, u32 evt_mask)
-{
-	u32 msg[5];	// Not performance critical, so we just 
-			// i2o_post_this it instead of building it
-			// in IOP memory
-	
-	msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
-	msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | tid;
-	msg[2] = init_context;
-	msg[3] = tr_context;
-	msg[4] = evt_mask;
-
-	return i2o_post_this(c, msg, sizeof(msg));
-}
-
-/*
- * 	i2o_event_ack	-	acknowledge an event
- *	@c: controller 
- *	@msg: pointer to the UTIL_EVENT_REGISTER reply we received
- *
- *	We just take a pointer to the original UTIL_EVENT_REGISTER reply
- *	message and change the function code since that's what spec
- *	describes an EventAck message looking like.
- */
- 
-int i2o_event_ack(struct i2o_controller *c, u32 *msg)
-{
-	struct i2o_message *m = (struct i2o_message *)msg;
-
-	m->function = I2O_CMD_UTIL_EVT_ACK;
-
-	return i2o_post_wait(c, msg, m->size * 4, 2);
-}
-
-/*
- * Core event handler.  Runs as a separate thread and is woken
- * up whenever there is an Executive class event.
- */
-static int i2o_core_evt(void *reply_data)
-{
-	struct reply_info *reply = (struct reply_info *) reply_data;
-	u32 *msg = reply->msg;
-	struct i2o_controller *c = NULL;
-	unsigned long flags;
-
-	lock_kernel();
-	daemonize();
-	unlock_kernel();
-
-	strcpy(current->comm, "i2oevtd");
-	evt_running = 1;
-
-	while(1)
-	{
-		if(down_interruptible(&evt_sem))
-		{
-			dprintk(KERN_INFO "I2O event thread dead\n");
-			printk("exiting...");
-			evt_running = 0;
-			complete_and_exit(&evt_dead, 0);
-		}
-
-		/* 
-		 * Copy the data out of the queue so that we don't have to lock
-		 * around the whole function and just around the qlen update
-		 */
-		spin_lock_irqsave(&i2o_evt_lock, flags);
-		memcpy(reply, &events[evt_out], sizeof(struct reply_info));
-		MODINC(evt_out, I2O_EVT_Q_LEN);
-		evt_q_len--;
-		spin_unlock_irqrestore(&i2o_evt_lock, flags);
-	
-		c = reply->iop;
-	 	dprintk(KERN_INFO "I2O IRTOS EVENT: iop%d, event %#10x\n", c->unit, msg[4]);
-
-		/* 
-		 * We do not attempt to delete/quiesce/etc. the controller if
-		 * some sort of error indidication occurs.  We may want to do
-		 * so in the future, but for now we just let the user deal with 
-		 * it.  One reason for this is that what to do with an error
-		 * or when to send what ærror is not really agreed on, so
-		 * we get errors that may not be fatal but just look like they
-		 * are...so let the user deal with it.
-		 */
-		switch(msg[4])
-		{
-			case I2O_EVT_IND_EXEC_RESOURCE_LIMITS:
-				printk(KERN_ERR "%s: Out of resources\n", c->name);
-				break;
-
-			case I2O_EVT_IND_EXEC_POWER_FAIL:
-				printk(KERN_ERR "%s: Power failure\n", c->name);
-				break;
-
-			case I2O_EVT_IND_EXEC_HW_FAIL:
-			{
-				char *fail[] = 
-					{ 
-						"Unknown Error",
-						"Power Lost",
-						"Code Violation",
-						"Parity Error",
-						"Code Execution Exception",
-						"Watchdog Timer Expired" 
-					};
-
-				if(msg[5] <= 6)
-					printk(KERN_ERR "%s: Hardware Failure: %s\n", 
-						c->name, fail[msg[5]]);
-				else
-					printk(KERN_ERR "%s: Unknown Hardware Failure\n", c->name);
-
-				break;
-			}
-
-			/*
-		 	 * New device created
-		 	 * - Create a new i2o_device entry
-		 	 * - Inform all interested drivers about this device's existence
-		 	 */
-			case I2O_EVT_IND_EXEC_NEW_LCT_ENTRY:
-			{
-				struct i2o_device *d = (struct i2o_device *)
-					kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
-				int i;
-
-				if (d == NULL) {
-					printk(KERN_EMERG "i2oevtd: out of memory\n");
-					break;
-				}
-				memcpy(&d->lct_data, &msg[5], sizeof(i2o_lct_entry));
-	
-				d->next = NULL;
-				d->controller = c;
-				d->flags = 0;
-	
-				i2o_report_controller_unit(c, d);
-				i2o_install_device(c,d);
-	
-				for(i = 0; i < MAX_I2O_MODULES; i++)
-				{
-					if(i2o_handlers[i] && 
-						i2o_handlers[i]->new_dev_notify &&
-						(i2o_handlers[i]->class&d->lct_data.class_id))
-						{
-						spin_lock(&i2o_dev_lock);
-						i2o_handlers[i]->new_dev_notify(c,d);
-						spin_unlock(&i2o_dev_lock);
-						}
-				}
-			
-				break;
-			}
-	
-			/*
- 		 	 * LCT entry for a device has been modified, so update it
-		 	 * internally.
-		 	 */
-			case I2O_EVT_IND_EXEC_MODIFIED_LCT:
-			{
-				struct i2o_device *d;
-				i2o_lct_entry *new_lct = (i2o_lct_entry *)&msg[5];
-
-				for(d = c->devices; d; d = d->next)
-				{
-					if(d->lct_data.tid == new_lct->tid)
-					{
-						memcpy(&d->lct_data, new_lct, sizeof(i2o_lct_entry));
-						break;
-					}
-				}
-				break;
-			}
-	
-			case I2O_EVT_IND_CONFIGURATION_FLAG:
-				printk(KERN_WARNING "%s requires user configuration\n", c->name);
-				break;
-	
-			case I2O_EVT_IND_GENERAL_WARNING:
-				printk(KERN_WARNING "%s: Warning notification received!"
-					"Check configuration for errors!\n", c->name);
-				break;
-				
-			case I2O_EVT_IND_EVT_MASK_MODIFIED:
-				/* Well I guess that was us hey .. */
-				break;
-					
-			default:
-				printk(KERN_WARNING "%s: No handler for event (0x%08x)\n", c->name, msg[4]);
-				break;
-		}
-	}
-
-	return 0;
-}
-
-/*
- * Dynamic LCT update.  This compares the LCT with the currently
- * installed devices to check for device deletions..this needed b/c there
- * is no DELETED_LCT_ENTRY EventIndicator for the Executive class so
- * we can't just have the event handler do this...annoying
- *
- * This is a hole in the spec that will hopefully be fixed someday.
- */
-static int i2o_dyn_lct(void *foo)
-{
-	struct i2o_controller *c = (struct i2o_controller *)foo;
-	struct i2o_device *d = NULL;
-	struct i2o_device *d1 = NULL;
-	int i = 0;
-	int found = 0;
-	int entries;
-	void *tmp;
-	char name[16];
-
-	lock_kernel();
-	daemonize();
-	unlock_kernel();
-
-	sprintf(name, "iop%d_lctd", c->unit);
-	strcpy(current->comm, name);	
-	
-	c->lct_running = 1;
-
-	while(1)
-	{
-		down_interruptible(&c->lct_sem);
-		if(signal_pending(current))
-		{
-			dprintk(KERN_ERR "%s: LCT thread dead\n", c->name);
-			c->lct_running = 0;
-			return 0;
-		}
-
-		entries = c->dlct->table_size;
-		entries -= 3;
-		entries /= 9;
-
-		dprintk(KERN_INFO "%s: Dynamic LCT Update\n",c->name);
-		dprintk(KERN_INFO "%s: Dynamic LCT contains %d entries\n", c->name, entries);
-
-		if(!entries)
-		{
-			printk(KERN_INFO "%s: Empty LCT???\n", c->name);
-			continue;
-		}
-
-		/*
-		 * Loop through all the devices on the IOP looking for their
-		 * LCT data in the LCT.  We assume that TIDs are not repeated.
-		 * as that is the only way to really tell.  It's been confirmed
-		 * by the IRTOS vendor(s?) that TIDs are not reused until they 
-		 * wrap arround(4096), and I doubt a system will up long enough
-		 * to create/delete that many devices.
-		 */
-		for(d = c->devices; d; )
-		{
-			found = 0;
-			d1 = d->next;
-			
-			for(i = 0; i < entries; i++) 
-			{ 
-				if(d->lct_data.tid == c->dlct->lct_entry[i].tid) 
-				{ 
-					found = 1; 
-					break; 
-				} 
-			} 
-			if(!found) 
-			{
-				dprintk(KERN_INFO "i2o_core: Deleted device!\n"); 
-				spin_lock(&i2o_dev_lock);
-				i2o_delete_device(d); 
-				spin_unlock(&i2o_dev_lock);
-			} 
-			d = d1; 
-		}
-
-		/* 
-		 * Tell LCT to renotify us next time there is a change
-	 	 */
-		i2o_lct_notify(c);
-
-		/*
-		 * Copy new LCT into public LCT
-		 *
-		 * Possible race if someone is reading LCT while  we are copying 
-		 * over it. If this happens, we'll fix it then. but I doubt that
-		 * the LCT will get updated often enough or will get read by
-		 * a user often enough to worry.
-		 */
-		if(c->lct->table_size < c->dlct->table_size)
-		{
-			tmp = c->lct;
-			c->lct = kmalloc(c->dlct->table_size<<2, GFP_KERNEL);
-			if(!c->lct)
-			{
-				printk(KERN_ERR "%s: No memory for LCT!\n", c->name);
-				c->lct = tmp;
-				continue;
-			}
-			kfree(tmp);
-		}
-		memcpy(c->lct, c->dlct, c->dlct->table_size<<2);
-	}
-
-	return 0;
-}
-
-/**
- *	i2o_run_queue	-	process pending events on a controller
- *	@c: controller to process
- *
- *	This is called by the bus specific driver layer when an interrupt
- *	or poll of this card interface is desired.
- */
- 
-void i2o_run_queue(struct i2o_controller *c)
-{
-	struct i2o_message *m;
-	u32 mv;
-	u32 *msg;
-
-	/*
-	 * Old 960 steppings had a bug in the I2O unit that caused
-	 * the queue to appear empty when it wasn't.
-	 */
-	if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF)
-		mv=I2O_REPLY_READ32(c);
-
-	while(mv!=0xFFFFFFFF)
-	{
-		struct i2o_handler *i;
-		m=(struct i2o_message *)bus_to_virt(mv);
-		msg=(u32*)m;
-
-		i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)];
-		if(i && i->reply)
-			i->reply(i,c,m);
-		else
-		{
-			printk(KERN_WARNING "I2O: Spurious reply to handler %d\n", 
-				m->initiator_context&(MAX_I2O_MODULES-1));
-		}	
-	 	i2o_flush_reply(c,mv);
-		mb();
-
-		/* That 960 bug again... */	
-		if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF)
-			mv=I2O_REPLY_READ32(c);
-	}		
-}
-
-
-/**
- *	i2o_get_class_name - 	do i2o class name lookup
- *	@class: class number
- *
- *	Return a descriptive string for an i2o class
- */
- 
-const char *i2o_get_class_name(int class)
-{
-	int idx = 16;
-	static char *i2o_class_name[] = {
-		"Executive",
-		"Device Driver Module",
-		"Block Device",
-		"Tape Device",
-		"LAN Interface",
-		"WAN Interface",
-		"Fibre Channel Port",
-		"Fibre Channel Device",
-		"SCSI Device",
-		"ATE Port",
-		"ATE Device",
-		"Floppy Controller",
-		"Floppy Device",
-		"Secondary Bus Port",
-		"Peer Transport Agent",
-		"Peer Transport",
-		"Unknown"
-	};
-	
-	switch(class&0xFFF)
-	{
-		case I2O_CLASS_EXECUTIVE:
-			idx = 0; break;
-		case I2O_CLASS_DDM:
-			idx = 1; break;
-		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
-			idx = 2; break;
-		case I2O_CLASS_SEQUENTIAL_STORAGE:
-			idx = 3; break;
-		case I2O_CLASS_LAN:
-			idx = 4; break;
-		case I2O_CLASS_WAN:
-			idx = 5; break;
-		case I2O_CLASS_FIBRE_CHANNEL_PORT:
-			idx = 6; break;
-		case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL:
-			idx = 7; break;
-		case I2O_CLASS_SCSI_PERIPHERAL:
-			idx = 8; break;
-		case I2O_CLASS_ATE_PORT:
-			idx = 9; break;
-		case I2O_CLASS_ATE_PERIPHERAL:
-			idx = 10; break;
-		case I2O_CLASS_FLOPPY_CONTROLLER:
-			idx = 11; break;
-		case I2O_CLASS_FLOPPY_DEVICE:
-			idx = 12; break;
-		case I2O_CLASS_BUS_ADAPTER_PORT:
-			idx = 13; break;
-		case I2O_CLASS_PEER_TRANSPORT_AGENT:
-			idx = 14; break;
-		case I2O_CLASS_PEER_TRANSPORT:
-			idx = 15; break;
-	}
-
-	return i2o_class_name[idx];
-}
-
-
-/**
- *	i2o_wait_message	-	obtain an i2o message from the IOP
- *	@c: controller
- *	@why: explanation 
- *
- *	This function waits up to 5 seconds for a message slot to be
- *	available. If no message is available it prints an error message
- *	that is expected to be what the message will be used for (eg
- *	"get_status"). 0xFFFFFFFF is returned on a failure.
- *
- *	On a success the message is returned. This is the physical page
- *	frame offset address from the read port. (See the i2o spec)
- */
- 
-u32 i2o_wait_message(struct i2o_controller *c, char *why)
-{
-	long time=jiffies;
-	u32 m;
-	while((m=I2O_POST_READ32(c))==0xFFFFFFFF)
-	{
-		if((jiffies-time)>=5*HZ)
-		{
-			dprintk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", 
-				c->name, why);
-			return 0xFFFFFFFF;
-		}
-		schedule();
-		barrier();
-	}
-	return m;
-}
-	
-/**
- *	i2o_report_controller_unit - print information about a tid
- *	@c: controller
- *	@d: device
- *	
- *	Dump an information block associated with a given unit (TID). The
- *	tables are read and a block of text is output to printk that is
- *	formatted intended for the user.
- */
- 
-void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d)
-{
-	char buf[64];
-	char str[22];
-	int ret;
-	int unit = d->lct_data.tid;
-
-	if(verbose==0)
-		return;
-		
-	printk(KERN_INFO "Target ID %d.\n", unit);
-	if((ret=i2o_query_scalar(c, unit, 0xF100, 3, buf, 16))>=0)
-	{
-		buf[16]=0;
-		printk(KERN_INFO "     Vendor: %s\n", buf);
-	}
-	if((ret=i2o_query_scalar(c, unit, 0xF100, 4, buf, 16))>=0)
-	{
-		buf[16]=0;
-		printk(KERN_INFO "     Device: %s\n", buf);
-	}
-	if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0)
-	{
-		buf[16]=0;
-		printk(KERN_INFO "     Description: %s\n", buf);
-	}
-	if((ret=i2o_query_scalar(c, unit, 0xF100, 6, buf, 8))>=0)
-	{
-		buf[8]=0;
-		printk(KERN_INFO "        Rev: %s\n", buf);
-	}
-
-	printk(KERN_INFO "    Class: ");
-	sprintf(str, "%-21s", i2o_get_class_name(d->lct_data.class_id));
-	printk("%s\n", str);
-		
-	printk(KERN_INFO "  Subclass: 0x%04X\n", d->lct_data.sub_class);
-	printk(KERN_INFO "     Flags: ");
-		
-	if(d->lct_data.device_flags&(1<<0))
-		printk("C");		// ConfigDialog requested
-	if(d->lct_data.device_flags&(1<<1))
-		printk("U");		// Multi-user capable
-	if(!(d->lct_data.device_flags&(1<<4)))
-		printk("P");		// Peer service enabled!
-	if(!(d->lct_data.device_flags&(1<<5)))
-		printk("M");		// Mgmt service enabled!
-	printk("\n");
-			
-}
-
-
-/*
- *	Parse the hardware resource table. Right now we print it out
- *	and don't do a lot with it. We should collate these and then
- *	interact with the Linux resource allocation block.
- *
- *	Lets prove we can read it first eh ?
- *
- *	This is full of endianisms!
- */
- 
-static int i2o_parse_hrt(struct i2o_controller *c)
-{
-#ifdef DRIVERDEBUG
-	u32 *rows=(u32*)c->hrt;
-	u8 *p=(u8 *)c->hrt;
-	u8 *d;
-	int count;
-	int length;
-	int i;
-	int state;
-	
-	if(p[3]!=0)
-	{
-		printk(KERN_ERR "%s: HRT table for controller is too new a version.\n",
-			c->name);
-		return -1;
-	}
-		
-	count=p[0]|(p[1]<<8);
-	length = p[2];
-	
-	printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n",
-		c->name, count, length<<2);
-
-	rows+=2;
-	
-	for(i=0;i<count;i++)
-	{
-		printk(KERN_INFO "Adapter %08X: ", rows[0]);
-		p=(u8 *)(rows+1);
-		d=(u8 *)(rows+2);
-		state=p[1]<<8|p[0];
-		
-		printk("TID %04X:[", state&0xFFF);
-		state>>=12;
-		if(state&(1<<0))
-			printk("H");		/* Hidden */
-		if(state&(1<<2))
-		{
-			printk("P");		/* Present */
-			if(state&(1<<1))
-				printk("C");	/* Controlled */
-		}
-		if(state>9)
-			printk("*");		/* Hard */
-		
-		printk("]:");
-		
-		switch(p[3]&0xFFFF)
-		{
-			case 0:
-				/* Adapter private bus - easy */
-				printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", 
-					p[2], d[1]<<8|d[0], *(u32 *)(d+4));
-				break;
-			case 1:
-				/* ISA bus */
-				printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X",
-					p[2], d[2], d[1]<<8|d[0], *(u32 *)(d+4));
-				break;
-					
-			case 2: /* EISA bus */
-				printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
-					p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4));
-				break;
-
-			case 3: /* MCA bus */
-				printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
-					p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4));
-				break;
-
-			case 4: /* PCI bus */
-				printk("PCI %d: Bus %d Device %d Function %d",
-					p[2], d[2], d[1], d[0]);
-				break;
-
-			case 0x80: /* Other */
-			default:
-				printk("Unsupported bus type.");
-				break;
-		}
-		printk("\n");
-		rows+=length;
-	}
-#endif
-	return 0;
-}
-	
-/*
- *	The logical configuration table tells us what we can talk to
- *	on the board. Most of the stuff isn't interesting to us. 
- */
-
-static int i2o_parse_lct(struct i2o_controller *c)
-{
-	int i;
-	int max;
-	int tid;
-	struct i2o_device *d;
-	i2o_lct *lct = c->lct;
-
-	if (lct == NULL) {
-		printk(KERN_ERR "%s: LCT is empty???\n", c->name);
-		return -1;
-	}
-
-	max = lct->table_size;
-	max -= 3;
-	max /= 9;
-	
-	printk(KERN_INFO "%s: LCT has %d entries.\n", c->name, max);
-	
-	if(lct->iop_flags&(1<<0))
-		printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name);
-		
-	for(i=0;i<max;i++)
-	{
-		d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
-		if(d==NULL)
-		{
-			printk(KERN_CRIT "i2o_core: Out of memory for I2O device data.\n");
-			return -ENOMEM;
-		}
-		
-		d->controller = c;
-		d->next = NULL;
-
-		memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry));
-
-		d->flags = 0;
-		tid = d->lct_data.tid;
-		
-		i2o_report_controller_unit(c, d);
-		
-		i2o_install_device(c, d);
-	}
-	return 0;
-}
-
-
-/**
- *	i2o_quiesce_controller - quiesce controller
- *	@c: controller 
- *
- *	Quiesce an IOP. Causes IOP to make external operation quiescent
- *	(i2o 'READY' state). Internal operation of the IOP continues normally.
- */
- 
-int i2o_quiesce_controller(struct i2o_controller *c)
-{
-	u32 msg[4];
-	int ret;
-
-	i2o_status_get(c);
-
-	/* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
-
-	if ((c->status_block->iop_state != ADAPTER_STATE_READY) &&
-		(c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL))
-	{
-		return 0;
-	}
-
-	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
-	msg[1] = I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
-	msg[3] = 0;
-
-	/* Long timeout needed for quiesce if lots of devices */
-
-	if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240)))
-		printk(KERN_INFO "%s: Unable to quiesce (status=%#x).\n",
-			c->name, -ret);
-	else
-		dprintk(KERN_INFO "%s: Quiesced.\n", c->name);
-
-	i2o_status_get(c); // Entered READY state
-	return ret;
-}
-
-/**
- *	i2o_enable_controller - move controller from ready to operational
- *	@c: controller
- *
- *	Enable IOP. This allows the IOP to resume external operations and
- *	reverses the effect of a quiesce. In the event of an error a negative
- *	errno code is returned.
- */
- 
-int i2o_enable_controller(struct i2o_controller *c)
-{
-	u32 msg[4];
-	int ret;
-
-	i2o_status_get(c);
-	
-	/* Enable only allowed on READY state */	
-	if(c->status_block->iop_state != ADAPTER_STATE_READY)
-		return -EINVAL;
-
-	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
-	msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID;
-
-	/* How long of a timeout do we need? */
-
-	if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240)))
-		printk(KERN_ERR "%s: Could not enable (status=%#x).\n",
-			c->name, -ret);
-	else
-		dprintk(KERN_INFO "%s: Enabled.\n", c->name);
-
-	i2o_status_get(c); // entered OPERATIONAL state
-
-	return ret;
-}
-
-/**
- *	i2o_clear_controller	-	clear a controller
- *	@c: controller
- *
- *	Clear an IOP to HOLD state, ie. terminate external operations, clear all
- *	input queues and prepare for a system restart. IOP's internal operation
- *	continues normally and the outbound queue is alive.
- *	The IOP is not expected to rebuild its LCT.
- */
- 
-int i2o_clear_controller(struct i2o_controller *c)
-{
-	struct i2o_controller *iop;
-	u32 msg[4];
-	int ret;
-
-	/* Quiesce all IOPs first */
-
-	for (iop = i2o_controller_chain; iop; iop = iop->next)
-		i2o_quiesce_controller(iop);
-
-	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
-	msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID;
-	msg[3]=0;
-
-	if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30)))
-		printk(KERN_INFO "%s: Unable to clear (status=%#x).\n",
-			c->name, -ret);
-	else
-		dprintk(KERN_INFO "%s: Cleared.\n",c->name);
-
-	i2o_status_get(c);
-
-	/* Enable other IOPs */
-
-	for (iop = i2o_controller_chain; iop; iop = iop->next)
-		if (iop != c)
-			i2o_enable_controller(iop);
-
-	return ret;
-}
-
-
-/**
- *	i2o_reset_controller	-	reset an IOP
- *	@c: controller to reset
- *
- *	Reset the IOP into INIT state and wait until IOP gets into RESET state.
- *	Terminate all external operations, clear IOP's inbound and outbound
- *	queues, terminate all DDMs, and reload the IOP's operating environment
- *	and all local DDMs. The IOP rebuilds its LCT.
- */
- 
-static int i2o_reset_controller(struct i2o_controller *c)
-{
-	struct i2o_controller *iop;
-	u32 m;
-	u8 *status;
-	u32 *msg;
-	long time;
-
-	/* Quiesce all IOPs first */
-
-	for (iop = i2o_controller_chain; iop; iop = iop->next)
-	{
-		if(iop->type != I2O_TYPE_PCI || !iop->bus.pci.dpt)
-			i2o_quiesce_controller(iop);
-	}
-
-	m=i2o_wait_message(c, "AdapterReset");
-	if(m==0xFFFFFFFF)	
-		return -ETIMEDOUT;
-	msg=(u32 *)(c->mem_offset+m);
-	
-	status=(void *)kmalloc(4, GFP_KERNEL);
-	if(status==NULL) {
-		printk(KERN_ERR "IOP reset failed - no free memory.\n");
-		return -ENOMEM;
-	}
-	memset(status, 0, 4);
-	
-	msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
-	msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
-	msg[2]=core_context;
-	msg[3]=0;
-	msg[4]=0;
-	msg[5]=0;
-	msg[6]=virt_to_bus(status);
-	msg[7]=0;	/* 64bit host FIXME */
-
-	i2o_post_message(c,m);
-
-	/* Wait for a reply */
-	time=jiffies;
-	while(*status==0)
-	{
-		if((jiffies-time)>=20*HZ)
-		{
-			printk(KERN_ERR "IOP reset timeout.\n");
-			// Better to leak this for safety: kfree(status);
-			return -ETIMEDOUT;
-		}
-		schedule();
-		barrier();
-	}
-
-	if (*status==I2O_CMD_IN_PROGRESS)
-	{ 
-		/* 
-		 * Once the reset is sent, the IOP goes into the INIT state 
-		 * which is indeterminate.  We need to wait until the IOP 
-		 * has rebooted before we can let the system talk to 
-		 * it. We read the inbound Free_List until a message is 
-		 * available.  If we can't read one in the given ammount of 
-		 * time, we assume the IOP could not reboot properly.  
-		 */ 
-
-		dprintk(KERN_INFO "%s: Reset in progress, waiting for reboot...\n",
-			c->name); 
-
-		time = jiffies; 
-		m = I2O_POST_READ32(c); 
-		while(m == 0XFFFFFFFF) 
-		{ 
-			if((jiffies-time) >= 30*HZ)
-			{
-				printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n", 
-						c->name); 
-				return -ETIMEDOUT; 
-			} 
-			schedule(); 
-			barrier(); 
-			m = I2O_POST_READ32(c); 
-		}
-		i2o_flush_reply(c,m);
-	}
-
-	/* If IopReset was rejected or didn't perform reset, try IopClear */
-
-	i2o_status_get(c);
-	if (status[0] == I2O_CMD_REJECTED || 
-		c->status_block->iop_state != ADAPTER_STATE_RESET)
-	{
-		printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name);
-		i2o_clear_controller(c);
-	}
-	else
-		dprintk(KERN_INFO "%s: Reset completed.\n", c->name);
-
-	/* Enable other IOPs */
-
-	for (iop = i2o_controller_chain; iop; iop = iop->next)
-		if (iop != c)
-			i2o_enable_controller(iop);
-
-	kfree(status);
-	return 0;
-}
-
-
-/**
- * 	i2o_status_get	-	get the status block for the IOP
- *	@c: controller
- *
- *	Issue a status query on the controller. This updates the
- *	attached status_block. If the controller fails to reply or an
- *	error occurs then a negative errno code is returned. On success
- *	zero is returned and the status_blok is updated.
- */
- 
-int i2o_status_get(struct i2o_controller *c)
-{
-	long time;
-	u32 m;
-	u32 *msg;
-	u8 *status_block;
-
-	if (c->status_block == NULL) 
-	{
-		c->status_block = (i2o_status_block *)
-			kmalloc(sizeof(i2o_status_block),GFP_KERNEL);
-		if (c->status_block == NULL)
-		{
-			printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n",
-				c->name);
-			return -ENOMEM;
-		}
-	}
-
-	status_block = (u8*)c->status_block;
-	memset(c->status_block,0,sizeof(i2o_status_block));
-	
-	m=i2o_wait_message(c, "StatusGet");
-	if(m==0xFFFFFFFF)
-		return -ETIMEDOUT;	
-	msg=(u32 *)(c->mem_offset+m);
-
-	msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0;
-	msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID;
-	msg[2]=core_context;
-	msg[3]=0;
-	msg[4]=0;
-	msg[5]=0;
-	msg[6]=virt_to_bus(c->status_block);
-	msg[7]=0;   /* 64bit host FIXME */
-	msg[8]=sizeof(i2o_status_block); /* always 88 bytes */
-
-	i2o_post_message(c,m);
-
-	/* Wait for a reply */
-
-	time=jiffies;
-	while(status_block[87]!=0xFF)
-	{
-		if((jiffies-time)>=5*HZ)
-		{
-			printk(KERN_ERR "%s: Get status timeout.\n",c->name);
-			return -ETIMEDOUT;
-		}
-		schedule();
-		barrier();
-	}
-
-#ifdef DRIVERDEBUG
-	printk(KERN_INFO "%s: State = ", c->name);
-	switch (c->status_block->iop_state) {
-		case 0x01:  
-			printk("INIT\n");
-			break;
-		case 0x02:
-			printk("RESET\n");
-			break;
-		case 0x04:
-			printk("HOLD\n");
-			break;
-		case 0x05:
-			printk("READY\n");
-			break;
-		case 0x08:
-			printk("OPERATIONAL\n");
-			break;
-		case 0x10:
-			printk("FAILED\n");
-			break;
-		case 0x11:
-			printk("FAULTED\n");
-			break;
-		default: 
-			printk("%x (unknown !!)\n",c->status_block->iop_state);
-}     
-#endif   
-
-	return 0;
-}
-
-/*
- * Get the Hardware Resource Table for the device.
- * The HRT contains information about possible hidden devices
- * but is mostly useless to us 
- */
-int i2o_hrt_get(struct i2o_controller *c)
-{
-	u32 msg[6];
-	int ret, size = sizeof(i2o_hrt);
-
-	/* First read just the header to figure out the real size */
-
-	do  {
-		if (c->hrt == NULL) {
-			c->hrt=kmalloc(size, GFP_KERNEL);
-			if (c->hrt == NULL) {
-				printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name);
-				return -ENOMEM;
-			}
-		}
-
-		msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
-		msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
-		msg[3]= 0;
-		msg[4]= (0xD0000000 | size);	/* Simple transaction */
-		msg[5]= virt_to_bus(c->hrt);	/* Dump it here */
-
-		ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL);
-		
-		if(ret == -ETIMEDOUT)
-		{
-			/* The HRT block we used is in limbo somewhere. When the iop wakes up
-			   we will recover it */
-			c->hrt = NULL;
-			return ret;
-		}
-		
-		if(ret<0)
-		{
-			printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n",
-				c->name, -ret);	
-			return ret;
-		}
-
-		if (c->hrt->num_entries * c->hrt->entry_len << 2 > size) {
-			size = c->hrt->num_entries * c->hrt->entry_len << 2;
-			kfree(c->hrt);
-			c->hrt = NULL;
-		}
-	} while (c->hrt == NULL);
-
-	i2o_parse_hrt(c); // just for debugging
-
-	return 0;
-}
-
-/*
- * Send the I2O System Table to the specified IOP
- *
- * The system table contains information about all the IOPs in the
- * system.  It is build and then sent to each IOP so that IOPs can
- * establish connections between each other.
- *
- */
-static int i2o_systab_send(struct i2o_controller *iop)
-{
-	u32 msg[12];
-	int ret;
-	u32 *privbuf = kmalloc(16, GFP_KERNEL);
-	if(privbuf == NULL)
-		return -ENOMEM;
-	
-	if(iop->type == I2O_TYPE_PCI)
-	{
-		struct resource *root;
-		
-		if(iop->status_block->current_mem_size < iop->status_block->desired_mem_size)
-		{
-			struct resource *res = &iop->mem_resource;
-			res->name = iop->bus.pci.pdev->bus->name;
-			res->flags = IORESOURCE_MEM;
-			res->start = 0;
-			res->end = 0;
-			printk("%s: requires private memory resources.\n", iop->name);
-			root = pci_find_parent_resource(iop->bus.pci.pdev, res);
-			if(root==NULL)
-				printk("Can't find parent resource!\n");
-			if(root && allocate_resource(root, res, 
-					iop->status_block->desired_mem_size,
-					iop->status_block->desired_mem_size,
-					iop->status_block->desired_mem_size,
-					1<<20,	/* Unspecified, so use 1Mb and play safe */
-					NULL,
-					NULL)>=0)
-			{
-				iop->mem_alloc = 1;
-				iop->status_block->current_mem_size = 1 + res->end - res->start;
-				iop->status_block->current_mem_base = res->start;
-				printk(KERN_INFO "%s: allocated %ld bytes of PCI memory at 0x%08lX.\n", 
-					iop->name, 1+res->end-res->start, res->start);
-			}
-		}
-		if(iop->status_block->current_io_size < iop->status_block->desired_io_size)
-		{
-			struct resource *res = &iop->io_resource;
-			res->name = iop->bus.pci.pdev->bus->name;
-			res->flags = IORESOURCE_IO;
-			res->start = 0;
-			res->end = 0;
-			printk("%s: requires private memory resources.\n", iop->name);
-			root = pci_find_parent_resource(iop->bus.pci.pdev, res);
-			if(root==NULL)
-				printk("Can't find parent resource!\n");
-			if(root &&  allocate_resource(root, res, 
-					iop->status_block->desired_io_size,
-					iop->status_block->desired_io_size,
-					iop->status_block->desired_io_size,
-					1<<20,	/* Unspecified, so use 1Mb and play safe */
-					NULL,
-					NULL)>=0)
-			{
-				iop->io_alloc = 1;
-				iop->status_block->current_io_size = 1 + res->end - res->start;
-				iop->status_block->current_mem_base = res->start;
-				printk(KERN_INFO "%s: allocated %ld bytes of PCI I/O at 0x%08lX.\n", 
-					iop->name, 1+res->end-res->start, res->start);
-			}
-		}
-	}
-	else
-	{	
-		privbuf[0] = iop->status_block->current_mem_base;
-		privbuf[1] = iop->status_block->current_mem_size;
-		privbuf[2] = iop->status_block->current_io_base;
-		privbuf[3] = iop->status_block->current_io_size;
-	}
-
-	msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
-	msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
-	msg[3] = 0;
-	msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
-	msg[5] = 0;                               /* Segment 0 */
-
-	/* 
- 	 * Provide three SGL-elements:
- 	 * System table (SysTab), Private memory space declaration and 
- 	 * Private i/o space declaration  
- 	 *
- 	 * FIXME: provide these for controllers needing them
- 	 */
-	msg[6] = 0x54000000 | sys_tbl_len;
-	msg[7] = virt_to_bus(sys_tbl);
-	msg[8] = 0x54000000 | 8;
-	msg[9] = virt_to_bus(privbuf);
-	msg[10] = 0xD4000000 | 8;
-	msg[11] = virt_to_bus(privbuf+2);
-
-	ret=i2o_post_wait_mem(iop, msg, sizeof(msg), 120, privbuf, NULL);
-	
-	if(ret==-ETIMEDOUT)
-	{
-		printk(KERN_ERR "%s: SysTab setup timed out.\n", iop->name);
-	}
-	else if(ret<0)
-	{
-		printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n", 
-			iop->name, -ret);
-		kfree(privbuf);
-	}
-	else
-	{
-		dprintk(KERN_INFO "%s: SysTab set.\n", iop->name);
-		kfree(privbuf);
-	}
-	i2o_status_get(iop); // Entered READY state
-
-	return ret;	
-
- }
-
-/*
- * Initialize I2O subsystem.
- */
-static void __init i2o_sys_init(void)
-{
-	struct i2o_controller *iop, *niop = NULL;
-
-	printk(KERN_INFO "Activating I2O controllers...\n");
-	printk(KERN_INFO "This may take a few minutes if there are many devices\n");
-	
-	/* In INIT state, Activate IOPs */
-	for (iop = i2o_controller_chain; iop; iop = niop) {
-		dprintk(KERN_INFO "Calling i2o_activate_controller for %s...\n", 
-			iop->name);
-		niop = iop->next;
-		if (i2o_activate_controller(iop) < 0)
-			i2o_delete_controller(iop);
-	}
-
-	/* Active IOPs in HOLD state */
-
-rebuild_sys_tab:
-	if (i2o_controller_chain == NULL)
-		return;
-
-	/*
-	 * If build_sys_table fails, we kill everything and bail
-	 * as we can't init the IOPs w/o a system table
-	 */	
-	dprintk(KERN_INFO "i2o_core: Calling i2o_build_sys_table...\n");
-	if (i2o_build_sys_table() < 0) {
-		i2o_sys_shutdown();
-		return;
-	}
-
-	/* If IOP don't get online, we need to rebuild the System table */
-	for (iop = i2o_controller_chain; iop; iop = niop) {
-		niop = iop->next;
-		dprintk(KERN_INFO "Calling i2o_online_controller for %s...\n", iop->name);
-		if (i2o_online_controller(iop) < 0) {
-			i2o_delete_controller(iop);	
-			goto rebuild_sys_tab;
-		}
-	}
-	
-	/* Active IOPs now in OPERATIONAL state */
-
-	/*
-	 * Register for status updates from all IOPs
-	 */
-	for(iop = i2o_controller_chain; iop; iop=iop->next) {
-
-		/* Create a kernel thread to deal with dynamic LCT updates */
-		iop->lct_pid = kernel_thread(i2o_dyn_lct, iop, CLONE_SIGHAND);
-	
-		/* Update change ind on DLCT */
-		iop->dlct->change_ind = iop->lct->change_ind;
-
-		/* Start dynamic LCT updates */
-		i2o_lct_notify(iop);
-
-		/* Register for all events from IRTOS */
-		i2o_event_register(iop, core_context, 0, 0, 0xFFFFFFFF);
-	}
-}
-
-/**
- *	i2o_sys_shutdown - shutdown I2O system
- *
- *	Bring down each i2o controller and then return. Each controller
- *	is taken through an orderly shutdown
- */
- 
-static void i2o_sys_shutdown(void)
-{
-	struct i2o_controller *iop, *niop;
-
-	/* Delete all IOPs from the controller chain */
-	/* that will reset all IOPs too */
-
-	for (iop = i2o_controller_chain; iop; iop = niop) {
-		niop = iop->next;
-		i2o_delete_controller(iop);
-	}
-}
-
-/**
- *	i2o_activate_controller	-	bring controller up to HOLD
- *	@iop: controller
- *
- *	This function brings an I2O controller into HOLD state. The adapter
- *	is reset if neccessary and then the queues and resource table
- *	are read. -1 is returned on a failure, 0 on success.
- *	
- */
- 
-int i2o_activate_controller(struct i2o_controller *iop)
-{
-	/* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */
-	/* In READY state, Get status */
-
-	if (i2o_status_get(iop) < 0) {
-		printk(KERN_INFO "Unable to obtain status of %s, "
-			"attempting a reset.\n", iop->name);
-		if (i2o_reset_controller(iop) < 0)
-			return -1;
-	}
-
-	if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED) {
-		printk(KERN_CRIT "%s: hardware fault\n", iop->name);
-		return -1;
-	}
-
-	if (iop->status_block->i2o_version > I2OVER15) {
-		printk(KERN_ERR "%s: Not running vrs. 1.5. of the I2O Specification.\n",
-			iop->name);
-		return -1;
-	}
-
-	if (iop->status_block->iop_state == ADAPTER_STATE_READY ||
-	    iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
-	    iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
-	    iop->status_block->iop_state == ADAPTER_STATE_FAILED)
-	{
-		dprintk(KERN_INFO "%s: Already running, trying to reset...\n",
-			iop->name);
-		if (i2o_reset_controller(iop) < 0)
-			return -1;
-	}
-
-	if (i2o_init_outbound_q(iop) < 0)
-		return -1;
-
-	if (i2o_post_outbound_messages(iop)) 
-		return -1;
-
-	/* In HOLD state */
-	
-	if (i2o_hrt_get(iop) < 0)
-		return -1;
-
-	return 0;
-}
-
-
-/**
- *	i2o_init_outbound_queue	- setup the outbound queue
- *	@c: controller
- *
- *	Clear and (re)initialize IOP's outbound queue. Returns 0 on
- *	success or a negative errno code on a failure.
- */
- 
-int i2o_init_outbound_q(struct i2o_controller *c)
-{
-	u8 *status;
-	u32 m;
-	u32 *msg;
-	u32 time;
-
-	dprintk(KERN_INFO "%s: Initializing Outbound Queue...\n", c->name);
-	m=i2o_wait_message(c, "OutboundInit");
-	if(m==0xFFFFFFFF)
-		return -ETIMEDOUT;
-	msg=(u32 *)(c->mem_offset+m);
-
-	status = kmalloc(4,GFP_KERNEL);
-	if (status==NULL) {
-		printk(KERN_ERR "%s: Outbound Queue initialization failed - no free memory.\n",
-			c->name);
-		return -ENOMEM;
-	}
-	memset(status, 0, 4);
-
-	msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6;
-	msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID;
-	msg[2]= core_context;
-	msg[3]= 0x0106;				/* Transaction context */
-	msg[4]= 4096;				/* Host page frame size */
-	/* Frame size is in words. Pick 128, its what everyone elses uses and
-		other sizes break some adapters. */
-	msg[5]= MSG_FRAME_SIZE<<16|0x80;	/* Outbound msg frame size and Initcode */
-	msg[6]= 0xD0000004;			/* Simple SG LE, EOB */
-	msg[7]= virt_to_bus(status);
-
-	i2o_post_message(c,m);
-	
-	barrier();
-	time=jiffies;
-	while(status[0] < I2O_CMD_REJECTED)
-	{
-		if((jiffies-time)>=30*HZ)
-		{
-			if(status[0]==0x00)
-				printk(KERN_ERR "%s: Ignored queue initialize request.\n",
-					c->name);
-			else  
-				printk(KERN_ERR "%s: Outbound queue initialize timeout.\n",
-					c->name);
-			kfree(status);
-			return -ETIMEDOUT;
-		}  
-		schedule();
-		barrier();
-	}  
-
-	if(status[0] != I2O_CMD_COMPLETED)
-	{
-		printk(KERN_ERR "%s: IOP outbound initialise failed.\n", c->name);
-		kfree(status);
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
-/**
- *	i2o_post_outbound_messages	-	fill message queue
- *	@c: controller
- *
- *	Allocate a message frame and load the messages into the IOP. The
- *	function returns zero on success or a negative errno code on
- *	failure.
- */
-
-int i2o_post_outbound_messages(struct i2o_controller *c)
-{
-	int i;
-	u32 m;
-	/* Alloc space for IOP's outbound queue message frames */
-
-	c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
-	if(c->page_frame==NULL) {
-		printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n",
-			c->name);
-		return -ENOMEM;
-	}
-	m=virt_to_bus(c->page_frame);
-
-	/* Post frames */
-
-	for(i=0; i< NMBR_MSG_FRAMES; i++) {
-		I2O_REPLY_WRITE32(c,m);
-		mb();
-		m += MSG_FRAME_SIZE;
-	}
-
-	return 0;
-}
-
-/*
- * Get the IOP's Logical Configuration Table
- */
-int i2o_lct_get(struct i2o_controller *c)
-{
-	u32 msg[8];
-	int ret, size = c->status_block->expected_lct_size;
-
-	do {
-		if (c->lct == NULL) {
-			c->lct = kmalloc(size, GFP_KERNEL);
-			if(c->lct == NULL) {
-				printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
-					c->name);
-				return -ENOMEM;
-			}
-		}
-		memset(c->lct, 0, size);
-
-		msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
-		msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
-		/* msg[2] filled in i2o_post_wait */
-		msg[3] = 0;
-		msg[4] = 0xFFFFFFFF;	/* All devices */
-		msg[5] = 0x00000000;	/* Report now */
-		msg[6] = 0xD0000000|size;
-		msg[7] = virt_to_bus(c->lct);
-
-		ret=i2o_post_wait_mem(c, msg, sizeof(msg), 120, c->lct, NULL);
-		
-		if(ret == -ETIMEDOUT)
-		{
-			c->lct = NULL;
-			return ret;
-		}
-		
-		if(ret<0)
-		{
-			printk(KERN_ERR "%s: LCT Get failed (status=%#x.\n", 
-				c->name, -ret);	
-			return ret;
-		}
-
-		if (c->lct->table_size << 2 > size) {
-			size = c->lct->table_size << 2;
-			kfree(c->lct);
-			c->lct = NULL;
-		}
-	} while (c->lct == NULL);
-
-        if ((ret=i2o_parse_lct(c)) < 0)
-                return ret;
-
-	return 0;
-}
-
-/*
- * Like above, but used for async notification.  The main
- * difference is that we keep track of the CurrentChangeIndiicator
- * so that we only get updates when it actually changes.
- *
- */
-int i2o_lct_notify(struct i2o_controller *c)
-{
-	u32 msg[8];
-
-	msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
-	msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
-	msg[2] = core_context;
-	msg[3] = 0xDEADBEEF;	
-	msg[4] = 0xFFFFFFFF;	/* All devices */
-	msg[5] = c->dlct->change_ind+1;	/* Next change */
-	msg[6] = 0xD0000000|8192;
-	msg[7] = virt_to_bus(c->dlct);
-
-	return i2o_post_this(c, msg, sizeof(msg));
-}
-		
-/*
- *	Bring a controller online into OPERATIONAL state. 
- */
- 
-int i2o_online_controller(struct i2o_controller *iop)
-{
-	u32 v;
-	
-	if (i2o_systab_send(iop) < 0)
-		return -1;
-
-	/* In READY state */
-
-	dprintk(KERN_INFO "%s: Attempting to enable...\n", iop->name);
-	if (i2o_enable_controller(iop) < 0)
-		return -1;
-
-	/* In OPERATIONAL state  */
-
-	dprintk(KERN_INFO "%s: Attempting to get/parse lct...\n", iop->name);
-	if (i2o_lct_get(iop) < 0)
-		return -1;
-
-	/* Check battery status */
-	 
-	iop->battery = 0;
-	if(i2o_query_scalar(iop, ADAPTER_TID, 0x0000, 4, &v, 4)>=0)
-	{
-		if(v&16)
-			iop->battery = 1;
-	}
-
-	return 0;
-}
-
-/*
- * Build system table
- *
- * The system table contains information about all the IOPs in the
- * system (duh) and is used by the Executives on the IOPs to establish
- * peer2peer connections.  We're not supporting peer2peer at the moment,
- * but this will be needed down the road for things like lan2lan forwarding.
- */
-static int i2o_build_sys_table(void)
-{
-	struct i2o_controller *iop = NULL;
-	struct i2o_controller *niop = NULL;
-	int count = 0;
-
-	sys_tbl_len = sizeof(struct i2o_sys_tbl) +	// Header + IOPs
-				(i2o_num_controllers) *
-					sizeof(struct i2o_sys_tbl_entry);
-
-	if(sys_tbl)
-		kfree(sys_tbl);
-
-	sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL);
-	if(!sys_tbl) {
-		printk(KERN_CRIT "SysTab Set failed. Out of memory.\n");
-		return -ENOMEM;
-	}
-	memset((void*)sys_tbl, 0, sys_tbl_len);
-
-	sys_tbl->num_entries = i2o_num_controllers;
-	sys_tbl->version = I2OVERSION; /* TODO: Version 2.0 */
-	sys_tbl->change_ind = sys_tbl_ind++;
-
-	for(iop = i2o_controller_chain; iop; iop = niop)
-	{
-		niop = iop->next;
-
-		/* 
-		 * Get updated IOP state so we have the latest information
-		 *
-		 * We should delete the controller at this point if it
-		 * doesn't respond since  if it's not on the system table 
-		 * it is techninically not part of the I2O subsyßtem...
-		 */
-		if(i2o_status_get(iop)) {
-			printk(KERN_ERR "%s: Deleting b/c could not get status while"
-				"attempting to build system table\n", iop->name);
-			i2o_delete_controller(iop);		
-			sys_tbl->num_entries--;
-			continue; // try the next one
-		}
-
-		sys_tbl->iops[count].org_id = iop->status_block->org_id;
-		sys_tbl->iops[count].iop_id = iop->unit + 2;
-		sys_tbl->iops[count].seg_num = 0;
-		sys_tbl->iops[count].i2o_version = 
-				iop->status_block->i2o_version;
-		sys_tbl->iops[count].iop_state = 
-				iop->status_block->iop_state;
-		sys_tbl->iops[count].msg_type = 
-				iop->status_block->msg_type;
-		sys_tbl->iops[count].frame_size = 
-				iop->status_block->inbound_frame_size;
-		sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??
-		sys_tbl->iops[count].iop_capabilities = 
-				iop->status_block->iop_capabilities;
-		sys_tbl->iops[count].inbound_low = 
-				(u32)virt_to_bus(iop->post_port);
-		sys_tbl->iops[count].inbound_high = 0;	// TODO: 64-bit support
-
-		count++;
-	}
-
-#ifdef DRIVERDEBUG
-{
-	u32 *table;
-	table = (u32*)sys_tbl;
-	for(count = 0; count < (sys_tbl_len >>2); count++)
-		printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]);
-}
-#endif
-
-	return 0;
-}
-
-
-/*
- *	Run time support routines
- */
- 
-/*
- *	Generic "post and forget" helpers. This is less efficient - we do
- *	a memcpy for example that isnt strictly needed, but for most uses
- *	this is simply not worth optimising
- */
-
-int i2o_post_this(struct i2o_controller *c, u32 *data, int len)
-{
-	u32 m;
-	u32 *msg;
-	unsigned long t=jiffies;
-
-	do
-	{
-		mb();
-		m = I2O_POST_READ32(c);
-	}
-	while(m==0xFFFFFFFF && (jiffies-t)<HZ);
-	
-	if(m==0xFFFFFFFF)
-	{
-		printk(KERN_ERR "%s: Timeout waiting for message frame!\n",
-		       c->name);
-		return -ETIMEDOUT;
-	}
-	msg = (u32 *)(c->mem_offset + m);
- 	memcpy_toio(msg, data, len);
-	i2o_post_message(c,m);
-	return 0;
-}
-
-/**
- * 	i2o_post_wait_mem	-	I2O query/reply with DMA buffers
- *	@c: controller
- *	@msg: message to send
- *	@len: length of message
- *	@timeout: time in seconds to wait
- *	@mem1: attached memory buffer 1
- *	@mem2: attached memory buffer 2
- *
- * 	This core API allows an OSM to post a message and then be told whether
- *	or not the system received a successful reply. 
- *
- *	If the message times out then the value '-ETIMEDOUT' is returned. This
- *	is a special case. In this situation the message may (should) complete
- *	at an indefinite time in the future. When it completes it will use the
- *	memory buffers attached to the request. If -ETIMEDOUT is returned then
- *	the memory buffers must not be freed. Instead the event completion will
- *	free them for you. In all other cases the buffers are your problem.
- *
- *	Pass NULL for unneeded buffers.
- */
- 
-int i2o_post_wait_mem(struct i2o_controller *c, u32 *msg, int len, int timeout, void *mem1, void *mem2)
-{
-	DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post);
-	int complete = 0;
-	int status;
-	unsigned long flags = 0;
-	struct i2o_post_wait_data *wait_data =
-		kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL);
-
-	if(!wait_data)
-		return -ENOMEM;
-
-	/*
-	 *	Create a new notification object
-	 */
-	wait_data->status = &status;
-	wait_data->complete = &complete;
-	wait_data->mem[0] = mem1;
-	wait_data->mem[1] = mem2;
-	/* 
-	 *	Queue the event with its unique id
-	 */
-	spin_lock_irqsave(&post_wait_lock, flags);
-
-	wait_data->next = post_wait_queue;
-	post_wait_queue = wait_data;
-	wait_data->id = (++post_wait_id) & 0x7fff;
-	wait_data->wq = &wq_i2o_post;
-
-	spin_unlock_irqrestore(&post_wait_lock, flags);
-
-	/*
-	 *	Fill in the message id
-	 */
-	 
-	msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16);
-	
-	/*
-	 *	Post the message to the controller. At some point later it 
-	 *	will return. If we time out before it returns then
-	 *	complete will be zero.  From the point post_this returns
-	 *	the wait_data may have been deleted.
-	 */
-	if ((status = i2o_post_this(c, msg, len))==0) {
-		sleep_on_timeout(&wq_i2o_post, HZ * timeout);
-	}  
-	else
-		return -EIO;
-		
-	if(signal_pending(current))
-		status = -EINTR;
-		
-	spin_lock_irqsave(&post_wait_lock, flags);
-	barrier();	/* Be sure we see complete as it is locked */
-	if(!complete)
-	{
-		/* 
-		 *	Mark the entry dead. We cannot remove it. This is important.
-		 *	When it does terminate (which it must do if the controller hasnt
-		 *	died..) then it will otherwise scribble on stuff.
-		 *	!complete lets us safely check if the entry is still
-		 *	allocated and thus we can write into it
-		 */
-		wait_data->wq = NULL;
-		status = -ETIMEDOUT;
-	}
-	else
-	{
-		/* Debugging check - remove me soon */
-		if(status == -ETIMEDOUT)
-		{
-			printk("TIMEDOUT BUG!\n");
-			status = -EIO;
-		}
-	}
-	/* And the wait_data is not leaked either! */	 
-	spin_unlock_irqrestore(&post_wait_lock, flags);
-	return status;
-}
-
-/**
- * 	i2o_post_wait		-	I2O query/reply
- *	@c: controller
- *	@msg: message to send
- *	@len: length of message
- *	@timeout: time in seconds to wait
- *
- * 	This core API allows an OSM to post a message and then be told whether
- *	or not the system received a successful reply. 
- */
- 
-int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout)
-{
-	return i2o_post_wait_mem(c, msg, len, timeout, NULL, NULL);
-}
-
-/*
- * i2o_post_wait is completed and we want to wake up the 
- * sleeping proccess. Called by core's reply handler.
- */
-
-static void i2o_post_wait_complete(u32 context, int status)
-{
-	struct i2o_post_wait_data **p1, *q;
-	unsigned long flags;
-	
-	/* 
-	 * We need to search through the post_wait 
-	 * queue to see if the given message is still
-	 * outstanding.  If not, it means that the IOP 
-	 * took longer to respond to the message than we 
-	 * had allowed and timer has already expired.  
-	 * Not much we can do about that except log
-	 * it for debug purposes, increase timeout, and recompile
-	 *
-	 * Lock needed to keep anyone from moving queue pointers 
-	 * around while we're looking through them.
-	 */
-
-	spin_lock_irqsave(&post_wait_lock, flags);
-
-	for(p1 = &post_wait_queue; *p1!=NULL; p1 = &((*p1)->next)) 
-	{
-		q = (*p1);
-		if(q->id == ((context >> 16) & 0x7fff)) {
-			/*
-			 *	Delete it 
-			 */
-			 
-			*p1 = q->next;
-			
-			/*
-			 *	Live or dead ?
-			 */
-			 
-			if(q->wq)
-			{
-				/* Live entry - wakeup and set status */
-				*q->status = status;
-				*q->complete = 1;
-				wake_up(q->wq);
-			}
-			else
-			{
-				/*
-				 *	Free resources. Caller is dead
-				 */
-				if(q->mem[0])
-					kfree(q->mem[0]);
-				if(q->mem[1])
-					kfree(q->mem[1]);
-				printk(KERN_WARNING "i2o_post_wait event completed after timeout.\n");
-			}
-			kfree(q);
-			spin_unlock(&post_wait_lock);
-			return;
-		}
-	}
-	spin_unlock(&post_wait_lock);
-
-	printk(KERN_DEBUG "i2o_post_wait: Bogus reply!\n");
-}
-
-/*	Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
- *
- *	This function can be used for all UtilParamsGet/Set operations.
- *	The OperationList is given in oplist-buffer, 
- *	and results are returned in reslist-buffer.
- *	Note that the minimum sized reslist is 8 bytes and contains
- *	ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
- */
-int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid, 
-                void *oplist, int oplen, void *reslist, int reslen)
-{
-	u32 msg[9]; 
-	u32 *res32 = (u32*)reslist;
-	u32 *restmp = (u32*)reslist;
-	int len = 0;
-	int i = 0;
-	int wait_status;
-	u32 *opmem, *resmem;
-	
-	/* Get DMAable memory */
-	opmem = kmalloc(oplen, GFP_KERNEL);
-	if(opmem == NULL)
-		return -ENOMEM;
-	memcpy(opmem, oplist, oplen);
-	
-	resmem = kmalloc(reslen, GFP_KERNEL);
-	if(resmem == NULL)
-	{
-		kfree(opmem);
-		return -ENOMEM;
-	}
-	
-	msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
-	msg[1] = cmd << 24 | HOST_TID << 12 | tid; 
-	msg[3] = 0;
-	msg[4] = 0;
-	msg[5] = 0x54000000 | oplen;	/* OperationList */
-	msg[6] = virt_to_bus(opmem);
-	msg[7] = 0xD0000000 | reslen;	/* ResultList */
-	msg[8] = virt_to_bus(resmem);
-
-	wait_status = i2o_post_wait_mem(iop, msg, sizeof(msg), 10, opmem, resmem);
-	
-	/*
-	 *	This only looks like a memory leak - don't "fix" it.	
-	 */
-	if(wait_status == -ETIMEDOUT)
-		return wait_status;
-
-	/* Query failed */
-	if(wait_status != 0)
-	{
-		kfree(resmem);
-		kfree(opmem);
-		return wait_status;
-	}
-	
-	memcpy(reslist, resmem, reslen);
-	/*
-	 * Calculate number of bytes of Result LIST
-	 * We need to loop through each Result BLOCK and grab the length
-	 */
-	restmp = res32 + 1;
-	len = 1;
-	for(i = 0; i < (res32[0]&0X0000FFFF); i++)
-	{
-		if(restmp[0]&0x00FF0000)	/* BlockStatus != SUCCESS */
-		{
-			printk(KERN_WARNING "%s - Error:\n  ErrorInfoSize = 0x%02x, " 
-					"BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
-					(cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
-					: "PARAMS_GET",   
-					res32[1]>>24, (res32[1]>>16)&0xFF, res32[1]&0xFFFF);
-	
-			/*
-			 *	If this is the only request,than we return an error
-			 */
-			if((res32[0]&0x0000FFFF) == 1)
-			{
-				return -((res32[1] >> 16) & 0xFF); /* -BlockStatus */
-			}
-		}
-		len += restmp[0] & 0x0000FFFF;	/* Length of res BLOCK */
-		restmp += restmp[0] & 0x0000FFFF;	/* Skip to next BLOCK */
-	}
-	return (len << 2);  /* bytes used by result list */
-}
-
-/*
- *	 Query one scalar group value or a whole scalar group.
- */                  	
-int i2o_query_scalar(struct i2o_controller *iop, int tid, 
-                     int group, int field, void *buf, int buflen)
-{
-	u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
-	u8  resblk[8+buflen]; /* 8 bytes for header */
-	int size;
-
-	if (field == -1)  		/* whole group */
-       		opblk[4] = -1;
-              
-	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, 
-		opblk, sizeof(opblk), resblk, sizeof(resblk));
-		
-	memcpy(buf, resblk+8, buflen);  /* cut off header */
-	
-	if(size>buflen)
-		return buflen;
-	return size;
-}
-
-/*
- *	Set a scalar group value or a whole group.
- */
-int i2o_set_scalar(struct i2o_controller *iop, int tid, 
-		   int group, int field, void *buf, int buflen)
-{
-	u16 *opblk;
-	u8  resblk[8+buflen]; /* 8 bytes for header */
-        int size;
-
-	opblk = kmalloc(buflen+64, GFP_KERNEL);
-	if (opblk == NULL)
-	{
-		printk(KERN_ERR "i2o: no memory for operation buffer.\n");
-		return -ENOMEM;
-	}
-
-	opblk[0] = 1;                        /* operation count */
-	opblk[1] = 0;                        /* pad */
-	opblk[2] = I2O_PARAMS_FIELD_SET;
-	opblk[3] = group;
-
-	if(field == -1) {               /* whole group */
-		opblk[4] = -1;
-		memcpy(opblk+5, buf, buflen);
-	}
-	else                            /* single field */
-	{
-		opblk[4] = 1;
-		opblk[5] = field;
-		memcpy(opblk+6, buf, buflen);
-	}   
-
-	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, 
-				opblk, 12+buflen, resblk, sizeof(resblk));
-
-	kfree(opblk);
-	if(size>buflen)
-		return buflen;
-	return size;
-}
-
-/* 
- * 	if oper == I2O_PARAMS_TABLE_GET, get from all rows 
- * 		if fieldcount == -1 return all fields
- *			ibuf and ibuflen are unused (use NULL, 0)
- * 		else return specific fields
- *  			ibuf contains fieldindexes
- *
- * 	if oper == I2O_PARAMS_LIST_GET, get from specific rows
- * 		if fieldcount == -1 return all fields
- *			ibuf contains rowcount, keyvalues
- * 		else return specific fields
- *			fieldcount is # of fieldindexes
- *  			ibuf contains fieldindexes, rowcount, keyvalues
- *
- *	You could also use directly function i2o_issue_params().
- */
-int i2o_query_table(int oper, struct i2o_controller *iop, int tid, int group,
-		int fieldcount, void *ibuf, int ibuflen,
-		void *resblk, int reslen) 
-{
-	u16 *opblk;
-	int size;
-
-	opblk = kmalloc(10 + ibuflen, GFP_KERNEL);
-	if (opblk == NULL)
-	{
-		printk(KERN_ERR "i2o: no memory for query buffer.\n");
-		return -ENOMEM;
-	}
-
-	opblk[0] = 1;				/* operation count */
-	opblk[1] = 0;				/* pad */
-	opblk[2] = oper;
-	opblk[3] = group;		
-	opblk[4] = fieldcount;
-	memcpy(opblk+5, ibuf, ibuflen);		/* other params */
-
-	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET,iop, tid, 
-				opblk, 10+ibuflen, resblk, reslen);
-
-	kfree(opblk);
-	if(size>reslen)
-		return reslen;
-	return size;
-}
-
-/*
- * 	Clear table group, i.e. delete all rows.
- */
-int i2o_clear_table(struct i2o_controller *iop, int tid, int group)
-{
-	u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group };
-	u8  resblk[32]; /* min 8 bytes for result header */
-
-	return i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, 
-				opblk, sizeof(opblk), resblk, sizeof(resblk));
-}
-
-/*
- * 	Add a new row into a table group.
- *
- * 	if fieldcount==-1 then we add whole rows
- *		buf contains rowcount, keyvalues
- * 	else just specific fields are given, rest use defaults
- *  		buf contains fieldindexes, rowcount, keyvalues
- */	
-int i2o_row_add_table(struct i2o_controller *iop, int tid,
-		    int group, int fieldcount, void *buf, int buflen)
-{
-	u16 *opblk;
-	u8  resblk[32]; /* min 8 bytes for header */
-	int size;
-
-	opblk = kmalloc(buflen+64, GFP_KERNEL);
-	if (opblk == NULL)
-	{
-		printk(KERN_ERR "i2o: no memory for operation buffer.\n");
-		return -ENOMEM;
-	}
-
-	opblk[0] = 1;			/* operation count */
-	opblk[1] = 0;			/* pad */
-	opblk[2] = I2O_PARAMS_ROW_ADD;
-	opblk[3] = group;	
-	opblk[4] = fieldcount;
-	memcpy(opblk+5, buf, buflen);
-
-	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, 
-				opblk, 10+buflen, resblk, sizeof(resblk));
-
-	kfree(opblk);
-	if(size>buflen)
-		return buflen;
-	return size;
-}
-
-
-/*
- * Used for error reporting/debugging purposes.
- * Following fail status are common to all classes.
- * The preserved message must be handled in the reply handler. 
- */
-void i2o_report_fail_status(u8 req_status, u32* msg)
-{
-	static char *FAIL_STATUS[] = { 
-		"0x80",				/* not used */
-		"SERVICE_SUSPENDED", 		/* 0x81 */
-		"SERVICE_TERMINATED", 		/* 0x82 */
-		"CONGESTION",
-		"FAILURE",
-		"STATE_ERROR",
-		"TIME_OUT",
-		"ROUTING_FAILURE",
-		"INVALID_VERSION",
-		"INVALID_OFFSET",
-		"INVALID_MSG_FLAGS",
-		"FRAME_TOO_SMALL",
-		"FRAME_TOO_LARGE",
-		"INVALID_TARGET_ID",
-		"INVALID_INITIATOR_ID",
-		"INVALID_INITIATOR_CONTEX",	/* 0x8F */
-		"UNKNOWN_FAILURE"		/* 0xFF */
-	};
-
-	if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE)
-		printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.", req_status);
-	else
-		printk("TRANSPORT_%s.\n", FAIL_STATUS[req_status & 0x0F]);
-
-	/* Dump some details */
-
-	printk(KERN_ERR "  InitiatorId = %d, TargetId = %d\n",
-		(msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); 
-	printk(KERN_ERR "  LowestVersion = 0x%02X, HighestVersion = 0x%02X\n",
-		(msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
-	printk(KERN_ERR "  FailingHostUnit = 0x%04X,  FailingIOP = 0x%03X\n",
-		msg[5] >> 16, msg[5] & 0xFFF);
-
-	printk(KERN_ERR "  Severity:  0x%02X ", (msg[4] >> 16) & 0xFF); 
-	if (msg[4] & (1<<16))
-		printk("(FormatError), "
-			"this msg can never be delivered/processed.\n");
-	if (msg[4] & (1<<17))
-		printk("(PathError), "
-			"this msg can no longer be delivered/processed.\n");
-	if (msg[4] & (1<<18))
-		printk("(PathState), "
-			"the system state does not allow delivery.\n");
-	if (msg[4] & (1<<19))
-		printk("(Congestion), resources temporarily not available;"
-			"do not retry immediately.\n");
-}
-
-/*
- * Used for error reporting/debugging purposes.
- * Following reply status are common to all classes.
- */
-void i2o_report_common_status(u8 req_status)
-{
-	static char *REPLY_STATUS[] = { 
-		"SUCCESS", 
-		"ABORT_DIRTY", 
-		"ABORT_NO_DATA_TRANSFER",
-		"ABORT_PARTIAL_TRANSFER",
-		"ERROR_DIRTY",
-		"ERROR_NO_DATA_TRANSFER",
-		"ERROR_PARTIAL_TRANSFER",
-		"PROCESS_ABORT_DIRTY",
-		"PROCESS_ABORT_NO_DATA_TRANSFER",
-		"PROCESS_ABORT_PARTIAL_TRANSFER",
-		"TRANSACTION_ERROR",
-		"PROGRESS_REPORT"	
-	};
-
-	if (req_status > I2O_REPLY_STATUS_PROGRESS_REPORT)
-		printk("RequestStatus = %0#2x", req_status);
-	else
-		printk("%s", REPLY_STATUS[req_status]);
-}
-
-/*
- * Used for error reporting/debugging purposes.
- * Following detailed status are valid  for executive class, 
- * utility class, DDM class and for transaction error replies.
- */
-static void i2o_report_common_dsc(u16 detailed_status)
-{
-	static char *COMMON_DSC[] = { 
-		"SUCCESS",
-		"0x01",				// not used
-		"BAD_KEY",
-		"TCL_ERROR",
-		"REPLY_BUFFER_FULL",
-		"NO_SUCH_PAGE",
-		"INSUFFICIENT_RESOURCE_SOFT",
-		"INSUFFICIENT_RESOURCE_HARD",
-		"0x08",				// not used
-		"CHAIN_BUFFER_TOO_LARGE",
-		"UNSUPPORTED_FUNCTION",
-		"DEVICE_LOCKED",
-		"DEVICE_RESET",
-		"INAPPROPRIATE_FUNCTION",
-		"INVALID_INITIATOR_ADDRESS",
-		"INVALID_MESSAGE_FLAGS",
-		"INVALID_OFFSET",
-		"INVALID_PARAMETER",
-		"INVALID_REQUEST",
-		"INVALID_TARGET_ADDRESS",
-		"MESSAGE_TOO_LARGE",
-		"MESSAGE_TOO_SMALL",
-		"MISSING_PARAMETER",
-		"TIMEOUT",
-		"UNKNOWN_ERROR",
-		"UNKNOWN_FUNCTION",
-		"UNSUPPORTED_VERSION",
-		"DEVICE_BUSY",
-		"DEVICE_NOT_AVAILABLE"		
-	};
-
-	if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
-		printk(" / DetailedStatus = %0#4x.\n", detailed_status);
-	else
-		printk(" / %s.\n", COMMON_DSC[detailed_status]);
-}
-
-/*
- * Used for error reporting/debugging purposes
- */
-static void i2o_report_lan_dsc(u16 detailed_status)
-{
-	static char *LAN_DSC[] = {	// Lan detailed status code strings
-		"SUCCESS",
-		"DEVICE_FAILURE",
-		"DESTINATION_NOT_FOUND",
-		"TRANSMIT_ERROR",
-		"TRANSMIT_ABORTED",
-		"RECEIVE_ERROR",
-		"RECEIVE_ABORTED",
-		"DMA_ERROR",
-		"BAD_PACKET_DETECTED",
-		"OUT_OF_MEMORY",
-		"BUCKET_OVERRUN",
-		"IOP_INTERNAL_ERROR",
-		"CANCELED",
-		"INVALID_TRANSACTION_CONTEXT",
-		"DEST_ADDRESS_DETECTED",
-		"DEST_ADDRESS_OMITTED",
-		"PARTIAL_PACKET_RETURNED",
-		"TEMP_SUSPENDED_STATE",	// last Lan detailed status code
-		"INVALID_REQUEST"	// general detailed status code
-	};
-
-	if (detailed_status > I2O_DSC_INVALID_REQUEST)
-		printk(" / %0#4x.\n", detailed_status);
-	else
-		printk(" / %s.\n", LAN_DSC[detailed_status]);
-}
-
-/*
- * Used for error reporting/debugging purposes
- */
-static void i2o_report_util_cmd(u8 cmd)
-{
-	switch (cmd) {
-	case I2O_CMD_UTIL_NOP:
-		printk("UTIL_NOP, ");
-		break;			
-	case I2O_CMD_UTIL_ABORT:
-		printk("UTIL_ABORT, ");
-		break;
-	case I2O_CMD_UTIL_CLAIM:
-		printk("UTIL_CLAIM, ");
-		break;
-	case I2O_CMD_UTIL_RELEASE:
-		printk("UTIL_CLAIM_RELEASE, ");
-		break;
-	case I2O_CMD_UTIL_CONFIG_DIALOG:
-		printk("UTIL_CONFIG_DIALOG, ");
-		break;
-	case I2O_CMD_UTIL_DEVICE_RESERVE:
-		printk("UTIL_DEVICE_RESERVE, ");
-		break;
-	case I2O_CMD_UTIL_DEVICE_RELEASE:
-		printk("UTIL_DEVICE_RELEASE, ");
-		break;
-	case I2O_CMD_UTIL_EVT_ACK:
-		printk("UTIL_EVENT_ACKNOWLEDGE, ");
-		break;
-	case I2O_CMD_UTIL_EVT_REGISTER:
-		printk("UTIL_EVENT_REGISTER, ");
-		break;
-	case I2O_CMD_UTIL_LOCK:
-		printk("UTIL_LOCK, ");
-		break;
-	case I2O_CMD_UTIL_LOCK_RELEASE:
-		printk("UTIL_LOCK_RELEASE, ");
-		break;
-	case I2O_CMD_UTIL_PARAMS_GET:
-		printk("UTIL_PARAMS_GET, ");
-		break;
-	case I2O_CMD_UTIL_PARAMS_SET:
-		printk("UTIL_PARAMS_SET, ");
-		break;
-	case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY:
-		printk("UTIL_REPLY_FAULT_NOTIFY, ");
-		break;
-	default:
-		printk("Cmd = %0#2x, ",cmd);	
-	}
-}
-
-/*
- * Used for error reporting/debugging purposes
- */
-static void i2o_report_exec_cmd(u8 cmd)
-{
-	switch (cmd) {
-	case I2O_CMD_ADAPTER_ASSIGN:
-		printk("EXEC_ADAPTER_ASSIGN, ");
-		break;
-	case I2O_CMD_ADAPTER_READ:
-		printk("EXEC_ADAPTER_READ, ");
-		break;
-	case I2O_CMD_ADAPTER_RELEASE:
-		printk("EXEC_ADAPTER_RELEASE, ");
-		break;
-	case I2O_CMD_BIOS_INFO_SET:
-		printk("EXEC_BIOS_INFO_SET, ");
-		break;
-	case I2O_CMD_BOOT_DEVICE_SET:
-		printk("EXEC_BOOT_DEVICE_SET, ");
-		break;
-	case I2O_CMD_CONFIG_VALIDATE:
-		printk("EXEC_CONFIG_VALIDATE, ");
-		break;
-	case I2O_CMD_CONN_SETUP:
-		printk("EXEC_CONN_SETUP, ");
-		break;
-	case I2O_CMD_DDM_DESTROY:
-		printk("EXEC_DDM_DESTROY, ");
-		break;
-	case I2O_CMD_DDM_ENABLE:
-		printk("EXEC_DDM_ENABLE, ");
-		break;
-	case I2O_CMD_DDM_QUIESCE:
-		printk("EXEC_DDM_QUIESCE, ");
-		break;
-	case I2O_CMD_DDM_RESET:
-		printk("EXEC_DDM_RESET, ");
-		break;
-	case I2O_CMD_DDM_SUSPEND:
-		printk("EXEC_DDM_SUSPEND, ");
-		break;
-	case I2O_CMD_DEVICE_ASSIGN:
-		printk("EXEC_DEVICE_ASSIGN, ");
-		break;
-	case I2O_CMD_DEVICE_RELEASE:
-		printk("EXEC_DEVICE_RELEASE, ");
-		break;
-	case I2O_CMD_HRT_GET:
-		printk("EXEC_HRT_GET, ");
-		break;
-	case I2O_CMD_ADAPTER_CLEAR:
-		printk("EXEC_IOP_CLEAR, ");
-		break;
-	case I2O_CMD_ADAPTER_CONNECT:
-		printk("EXEC_IOP_CONNECT, ");
-		break;
-	case I2O_CMD_ADAPTER_RESET:
-		printk("EXEC_IOP_RESET, ");
-		break;
-	case I2O_CMD_LCT_NOTIFY:
-		printk("EXEC_LCT_NOTIFY, ");
-		break;
-	case I2O_CMD_OUTBOUND_INIT:
-		printk("EXEC_OUTBOUND_INIT, ");
-		break;
-	case I2O_CMD_PATH_ENABLE:
-		printk("EXEC_PATH_ENABLE, ");
-		break;
-	case I2O_CMD_PATH_QUIESCE:
-		printk("EXEC_PATH_QUIESCE, ");
-		break;
-	case I2O_CMD_PATH_RESET:
-		printk("EXEC_PATH_RESET, ");
-		break;
-	case I2O_CMD_STATIC_MF_CREATE:
-		printk("EXEC_STATIC_MF_CREATE, ");
-		break;
-	case I2O_CMD_STATIC_MF_RELEASE:
-		printk("EXEC_STATIC_MF_RELEASE, ");
-		break;
-	case I2O_CMD_STATUS_GET:
-		printk("EXEC_STATUS_GET, ");
-		break;
-	case I2O_CMD_SW_DOWNLOAD:
-		printk("EXEC_SW_DOWNLOAD, ");
-		break;
-	case I2O_CMD_SW_UPLOAD:
-		printk("EXEC_SW_UPLOAD, ");
-		break;
-	case I2O_CMD_SW_REMOVE:
-		printk("EXEC_SW_REMOVE, ");
-		break;
-	case I2O_CMD_SYS_ENABLE:
-		printk("EXEC_SYS_ENABLE, ");
-		break;
-	case I2O_CMD_SYS_MODIFY:
-		printk("EXEC_SYS_MODIFY, ");
-		break;
-	case I2O_CMD_SYS_QUIESCE:
-		printk("EXEC_SYS_QUIESCE, ");
-		break;
-	case I2O_CMD_SYS_TAB_SET:
-		printk("EXEC_SYS_TAB_SET, ");
-		break;
-	default:
-		printk("Cmd = %#02x, ",cmd);	
-	}
-}
-
-/*
- * Used for error reporting/debugging purposes
- */
-static void i2o_report_lan_cmd(u8 cmd)
-{
-	switch (cmd) {
-	case LAN_PACKET_SEND:
-		printk("LAN_PACKET_SEND, "); 
-		break;
-	case LAN_SDU_SEND:
-		printk("LAN_SDU_SEND, ");
-		break;
-	case LAN_RECEIVE_POST:
-		printk("LAN_RECEIVE_POST, ");
-		break;
-	case LAN_RESET:
-		printk("LAN_RESET, ");
-		break;
-	case LAN_SUSPEND:
-		printk("LAN_SUSPEND, ");
-		break;
-	default:
-		printk("Cmd = %0#2x, ",cmd);	
-	}	
-}
-
-/*
- * Used for error reporting/debugging purposes.
- * Report Cmd name, Request status, Detailed Status.
- */
-void i2o_report_status(const char *severity, const char *str, u32 *msg)
-{
-	u8 cmd = (msg[1]>>24)&0xFF;
-	u8 req_status = (msg[4]>>24)&0xFF;
-	u16 detailed_status = msg[4]&0xFFFF;
-	struct i2o_handler *h = i2o_handlers[msg[2] & (MAX_I2O_MODULES-1)];
-
-	printk("%s%s: ", severity, str);
-
-	if (cmd < 0x1F) 			// Utility cmd
-		i2o_report_util_cmd(cmd);
-	
-	else if (cmd >= 0xA0 && cmd <= 0xEF) 	// Executive cmd
-		i2o_report_exec_cmd(cmd);
-	
-	else if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F)
-		i2o_report_lan_cmd(cmd);	// LAN cmd
-	else
-        	printk("Cmd = %0#2x, ", cmd);	// Other cmds
-
-	if (msg[0] & MSG_FAIL) {
-		i2o_report_fail_status(req_status, msg);
-		return;
-	}
-	
-	i2o_report_common_status(req_status);
-
-	if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF))
-		i2o_report_common_dsc(detailed_status);	
-	else if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F)
-		i2o_report_lan_dsc(detailed_status);
-	else
-		printk(" / DetailedStatus = %0#4x.\n", detailed_status); 
-}
-
-/* Used to dump a message to syslog during debugging */
-void i2o_dump_message(u32 *msg)
-{
-#ifdef DRIVERDEBUG
-	int i;
-	printk(KERN_INFO "Dumping I2O message size %d @ %p\n", 
-		msg[0]>>16&0xffff, msg);
-	for(i = 0; i < ((msg[0]>>16)&0xffff); i++)
-		printk(KERN_INFO "  msg[%d] = %0#10x\n", i, msg[i]);
-#endif
-}
-
-/*
- * I2O reboot/shutdown notification.
- *
- * - Call each OSM's reboot notifier (if one exists)
- * - Quiesce each IOP in the system
- *
- * Each IOP has to be quiesced before we can ensure that the system
- * can be properly shutdown as a transaction that has already been
- * acknowledged still needs to be placed in permanent store on the IOP.
- * The SysQuiesce causes the IOP to force all HDMs to complete their
- * transactions before returning, so only at that point is it safe
- * 
- */
-static int i2o_reboot_event(struct notifier_block *n, unsigned long code, void
-*p)
-{
-	int i = 0;
-	struct i2o_controller *c = NULL;
-
-	if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF)
-		return NOTIFY_DONE;
-
-	printk(KERN_INFO "Shutting down I2O system.\n");
-	printk(KERN_INFO 
-		"   This could take a few minutes if there are many devices attached\n");
-
-	for(i = 0; i < MAX_I2O_MODULES; i++)
-	{
-		if(i2o_handlers[i] && i2o_handlers[i]->reboot_notify)
-			i2o_handlers[i]->reboot_notify();
-	}
-
-	for(c = i2o_controller_chain; c; c = c->next)
-	{
-		if(i2o_quiesce_controller(c))
-		{
-			printk(KERN_WARNING "i2o: Could not quiesce %s."  "
-				Verify setup on next system power up.\n", c->name);
-		}
-	}
-
-	printk(KERN_INFO "I2O system down.\n");
-	return NOTIFY_DONE;
-}
-
-
-EXPORT_SYMBOL(i2o_controller_chain);
-EXPORT_SYMBOL(i2o_num_controllers);
-EXPORT_SYMBOL(i2o_find_controller);
-EXPORT_SYMBOL(i2o_unlock_controller);
-EXPORT_SYMBOL(i2o_status_get);
-
-EXPORT_SYMBOL(i2o_install_handler);
-EXPORT_SYMBOL(i2o_remove_handler);
-
-EXPORT_SYMBOL(i2o_claim_device);
-EXPORT_SYMBOL(i2o_release_device);
-EXPORT_SYMBOL(i2o_device_notify_on);
-EXPORT_SYMBOL(i2o_device_notify_off);
-
-EXPORT_SYMBOL(i2o_post_this);
-EXPORT_SYMBOL(i2o_post_wait);
-EXPORT_SYMBOL(i2o_post_wait_mem);
-
-EXPORT_SYMBOL(i2o_query_scalar);
-EXPORT_SYMBOL(i2o_set_scalar);
-EXPORT_SYMBOL(i2o_query_table);
-EXPORT_SYMBOL(i2o_clear_table);
-EXPORT_SYMBOL(i2o_row_add_table);
-EXPORT_SYMBOL(i2o_issue_params);
-
-EXPORT_SYMBOL(i2o_event_register);
-EXPORT_SYMBOL(i2o_event_ack);
-
-EXPORT_SYMBOL(i2o_report_status);
-EXPORT_SYMBOL(i2o_dump_message);
-
-EXPORT_SYMBOL(i2o_get_class_name);
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Red Hat Software");
-MODULE_DESCRIPTION("I2O Core");
-
-
-int init_module(void)
-{
-	printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n");
-	if (i2o_install_handler(&i2o_core_handler) < 0)
-	{
-		printk(KERN_ERR 
-			"i2o_core: Unable to install core handler.\nI2O stack not loaded!");
-		return 0;
-	}
-
-	core_context = i2o_core_handler.context;
-
-	/*
-	 * Attach core to I2O PCI transport (and others as they are developed)
-	 */
-#ifdef CONFIG_I2O_PCI_MODULE
-	if(i2o_pci_core_attach(&i2o_core_functions) < 0)
-		printk(KERN_INFO "i2o: No PCI I2O controllers found\n");
-#endif
-
-	/*
-	 * Initialize event handling thread
-	 */	
-	init_MUTEX_LOCKED(&evt_sem);
-	evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND);
-	if(evt_pid < 0)
-	{
-		printk(KERN_ERR "I2O: Could not create event handler kernel thread\n");
-		i2o_remove_handler(&i2o_core_handler);
-		return 0;
-	}
-	else
-		printk(KERN_INFO "I2O: Event thread created as pid %d\n", evt_pid);
-
-	if(i2o_num_controllers)
-		i2o_sys_init();
-
-	register_reboot_notifier(&i2o_reboot_notifier);
-
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	int stat;
-
-	unregister_reboot_notifier(&i2o_reboot_notifier);
-
-	if(i2o_num_controllers)
-		i2o_sys_shutdown();
-
-	/*
-	 * If this is shutdown time, the thread has already been killed
-	 */
-	if(evt_running) {
-		printk("Terminating i2o threads...");
-		stat = kill_proc(evt_pid, SIGTERM, 1);
-		if(!stat) {
-			printk("waiting...");
-			wait_for_completion(&evt_dead);
-		}
-		printk("done.\n");
-	}
-
-#ifdef CONFIG_I2O_PCI_MODULE
-	i2o_pci_core_detach();
-#endif
-
-	i2o_remove_handler(&i2o_core_handler);
-
-	unregister_reboot_notifier(&i2o_reboot_notifier);
-}
-
-#else
-
-extern int i2o_block_init(void);
-extern int i2o_config_init(void);
-extern int i2o_lan_init(void);
-extern int i2o_pci_init(void);
-extern int i2o_proc_init(void);
-extern int i2o_scsi_init(void);
-
-int __init i2o_init(void)
-{
-	printk(KERN_INFO "Loading I2O Core - (c) Copyright 1999 Red Hat Software\n");
-	
-	if (i2o_install_handler(&i2o_core_handler) < 0)
-	{
-		printk(KERN_ERR 
-			"i2o_core: Unable to install core handler.\nI2O stack not loaded!");
-		return 0;
-	}
-
-	core_context = i2o_core_handler.context;
-
-	/*
-	 * Initialize event handling thread
-	 * We may not find any controllers, but still want this as 
-	 * down the road we may have hot pluggable controllers that
-	 * need to be dealt with.
-	 */	
-	init_MUTEX_LOCKED(&evt_sem);
-	if((evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND)) < 0)
-	{
-		printk(KERN_ERR "I2O: Could not create event handler kernel thread\n");
-		i2o_remove_handler(&i2o_core_handler);
-		return 0;
-	}
-
-
-#ifdef CONFIG_I2O_PCI
-	i2o_pci_init();
-#endif
-
-	if(i2o_num_controllers)
-		i2o_sys_init();
-
-	register_reboot_notifier(&i2o_reboot_notifier);
-
-	i2o_config_init();
-#ifdef CONFIG_I2O_BLOCK
-	i2o_block_init();
-#endif
-#ifdef CONFIG_I2O_LAN
-	i2o_lan_init();
-#endif
-#ifdef CONFIG_I2O_PROC
-	i2o_proc_init();
-#endif
-	return 0;
-}
-
-#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c
--- v2.4.12/linux/drivers/i2o/i2o_lan.c	Mon Aug 27 12:41:41 2001
+++ linux/drivers/i2o/i2o_lan.c	Wed Dec 31 16:00:00 1969
@@ -1,1577 +0,0 @@
-/*
- *	drivers/i2o/i2o_lan.c
- *
- * 	I2O LAN CLASS OSM 		May 26th 2000
- *
- *	(C) Copyright 1999, 2000 	University of Helsinki,
- *		      			Department of Computer Science
- *
- * 	This code is still under development / test.
- *
- *	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.
- *
- *	Authors: 	Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- *	Fixes:		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- *	 		Taneli Vähäkangas <Taneli.Vahakangas@cs.Helsinki.FI>
- *			Deepak Saxena <deepak@plexity.net>
- *
- *	Tested:		in FDDI environment (using SysKonnect's DDM)
- *			in Gigabit Eth environment (using SysKonnect's DDM)
- *			in Fast Ethernet environment (using Intel 82558 DDM)
- *
- *	TODO:		tests for other LAN classes (Token Ring, Fibre Channel)
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/pci.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/fddidevice.h>
-#include <linux/trdevice.h>
-#include <linux/fcdevice.h>
-
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/tqueue.h>
-#include <asm/io.h>
-
-#include <linux/errno.h>
-
-#include <linux/i2o.h>
-#include "i2o_lan.h"
-
-//#define DRIVERDEBUG
-#ifdef DRIVERDEBUG
-#define dprintk(s, args...) printk(s, ## args)
-#else
-#define dprintk(s, args...)
-#endif
-
-/* The following module parameters are used as default values
- * for per interface values located in the net_device private area.
- * Private values are changed via /proc filesystem.
- */
-static u32 max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT;
-static u32 bucket_thresh   = I2O_LAN_BUCKET_THRESH;
-static u32 rx_copybreak    = I2O_LAN_RX_COPYBREAK;
-static u8  tx_batch_mode   = I2O_LAN_TX_BATCH_MODE;
-static u32 i2o_event_mask  = I2O_LAN_EVENT_MASK;
-
-#define MAX_LAN_CARDS 16
-static struct net_device *i2o_landevs[MAX_LAN_CARDS+1];
-static int unit = -1; 	  /* device unit number */
-
-static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m);
-static void i2o_lan_send_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m);
-static int i2o_lan_receive_post(struct net_device *dev);
-static void i2o_lan_receive_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m);
-static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg);
-
-static int i2o_lan_reset(struct net_device *dev);
-static void i2o_lan_handle_event(struct net_device *dev, u32 *msg);
-
-/* Structures to register handlers for the incoming replies. */
-
-static struct i2o_handler i2o_lan_send_handler = {
-	i2o_lan_send_post_reply, 	// For send replies
-	NULL,
-	NULL,
-	NULL,
-	"I2O LAN OSM send",
-	-1,
-	I2O_CLASS_LAN
-};
-static int lan_send_context;
-
-static struct i2o_handler i2o_lan_receive_handler = {
-	i2o_lan_receive_post_reply,	// For receive replies
-	NULL,
-	NULL,
-	NULL,
-	"I2O LAN OSM receive",
-	-1,
-	I2O_CLASS_LAN
-};
-static int lan_receive_context;
-
-static struct i2o_handler i2o_lan_handler = {
-	i2o_lan_reply,			// For other replies
-	NULL,
-	NULL,
-	NULL,
-	"I2O LAN OSM",
-	-1,
-	I2O_CLASS_LAN
-};
-static int lan_context;
-
-DECLARE_TASK_QUEUE(i2o_post_buckets_task);
-struct tq_struct run_i2o_post_buckets_task = {
-	routine: (void (*)(void *)) run_task_queue,
-	data: (void *) 0
-};
-
-/* Functions to handle message failures and transaction errors:
-==============================================================*/
-
-/*
- * i2o_lan_handle_failure(): Fail bit has been set since IOP's message
- * layer cannot deliver the request to the target, or the target cannot
- * process the request.
- */
-static void i2o_lan_handle_failure(struct net_device *dev, u32 *msg)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-
-	u32 *preserved_msg = (u32*)(iop->mem_offset + msg[7]);
-	u32 *sgl_elem = &preserved_msg[4];
-	struct sk_buff *skb = NULL;
-	u8 le_flag;
-
-	i2o_report_status(KERN_INFO, dev->name, msg);
-
-	/* If PacketSend failed, free sk_buffs reserved by upper layers */
-
-	if (msg[1] >> 24 == LAN_PACKET_SEND) {
-		do {
-			skb = (struct sk_buff *)(sgl_elem[1]);
-			dev_kfree_skb_irq(skb);
-
-			atomic_dec(&priv->tx_out);
-
-			le_flag = *sgl_elem >> 31;
-			sgl_elem +=3;
-		} while (le_flag == 0); /* Last element flag not set */
-
-		if (netif_queue_stopped(dev))
-			netif_wake_queue(dev);
-	}
-
-	/* If ReceivePost failed, free sk_buffs we have reserved */
-
-	if (msg[1] >> 24 == LAN_RECEIVE_POST) {
-		do {
-			skb = (struct sk_buff *)(sgl_elem[1]);
-			dev_kfree_skb_irq(skb);
-
-			atomic_dec(&priv->buckets_out);
-
-			le_flag = *sgl_elem >> 31;
-			sgl_elem +=3;
-		} while (le_flag == 0); /* Last element flag not set */
-	}
-
-	/* Release the preserved msg frame by resubmitting it as a NOP */
-
-	preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
-	preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
-	preserved_msg[2] = 0;
-	i2o_post_message(iop, msg[7]);
-}
-/*
- * i2o_lan_handle_transaction_error(): IOP or DDM has rejected the request
- * for general cause (format error, bad function code, insufficient resources,
- * etc.). We get one transaction_error for each failed transaction.
- */
-static void i2o_lan_handle_transaction_error(struct net_device *dev, u32 *msg)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct sk_buff *skb;
-
-	i2o_report_status(KERN_INFO, dev->name, msg);
-
-	/* If PacketSend was rejected, free sk_buff reserved by upper layers */
-
-	if (msg[1] >> 24 == LAN_PACKET_SEND) {
-		skb = (struct sk_buff *)(msg[3]); // TransactionContext
-		dev_kfree_skb_irq(skb);
-		atomic_dec(&priv->tx_out);
-
-		if (netif_queue_stopped(dev))
-			netif_wake_queue(dev);
- 	}
-
-	/* If ReceivePost was rejected, free sk_buff we have reserved */
-
-	if (msg[1] >> 24 == LAN_RECEIVE_POST) {
-		skb = (struct sk_buff *)(msg[3]);
-		dev_kfree_skb_irq(skb);
-		atomic_dec(&priv->buckets_out);
-	}
-}
-
-/*
- * i2o_lan_handle_status(): Common parts of handling a not succeeded request
- * (status != SUCCESS).
- */
-static int i2o_lan_handle_status(struct net_device *dev, u32 *msg)
-{
-	/* Fail bit set? */
-
-	if (msg[0] & MSG_FAIL) {
-		i2o_lan_handle_failure(dev, msg);
-		return -1;
-	}
-
-	/* Message rejected for general cause? */
-
-	if ((msg[4]>>24) == I2O_REPLY_STATUS_TRANSACTION_ERROR) {
-		i2o_lan_handle_transaction_error(dev, msg);
-		return -1;
-	}
-
-	/* Else have to handle it in the callback function */
-
-	return 0;
-}
-
-/* Callback functions called from the interrupt routine:
-=======================================================*/
-
-/*
- * i2o_lan_send_post_reply(): Callback function to handle PostSend replies.
- */
-static void i2o_lan_send_post_reply(struct i2o_handler *h,
-			struct i2o_controller *iop, struct i2o_message *m)
-{
-	u32 *msg = (u32 *)m;
-	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
-	struct net_device *dev = i2o_landevs[unit];
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	u8 trl_count  = msg[3] & 0x000000FF;
-
-	if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) {
-		if (i2o_lan_handle_status(dev, msg))
-			return;
-	}
-
-#ifdef DRIVERDEBUG
-	i2o_report_status(KERN_INFO, dev->name, msg);
-#endif
-
-	/* DDM has handled transmit request(s), free sk_buffs.
-	 * We get similar single transaction reply also in error cases 
-	 * (except if msg failure or transaction error).
-	 */
-	while (trl_count) {
-		dev_kfree_skb_irq((struct sk_buff *)msg[4 + trl_count]);
-		dprintk(KERN_INFO "%s: tx skb freed (trl_count=%d).\n",
-			dev->name, trl_count);
-		atomic_dec(&priv->tx_out);
-		trl_count--;
-	}
-
-	/* If priv->tx_out had reached tx_max_out, the queue was stopped */
-
-	if (netif_queue_stopped(dev))
- 		netif_wake_queue(dev);
-}
-
-/*
- * i2o_lan_receive_post_reply(): Callback function to process incoming packets.
- */
-static void i2o_lan_receive_post_reply(struct i2o_handler *h,
-			struct i2o_controller *iop, struct i2o_message *m)
-{
-	u32 *msg = (u32 *)m;
-	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
-	struct net_device *dev = i2o_landevs[unit];
-
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_bucket_descriptor *bucket = (struct i2o_bucket_descriptor *)&msg[6];
-	struct i2o_packet_info *packet;
-	u8 trl_count = msg[3] & 0x000000FF;
-	struct sk_buff *skb, *old_skb;
-	unsigned long flags = 0;
-
-	if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) {
-		if (i2o_lan_handle_status(dev, msg))
-			return;
-
-		i2o_lan_release_buckets(dev, msg);
-		return;
-	}
-
-#ifdef DRIVERDEBUG
-	i2o_report_status(KERN_INFO, dev->name, msg);
-#endif
-
-	/* Else we are receiving incoming post. */
-
-	while (trl_count--) {
-		skb = (struct sk_buff *)bucket->context;
-		packet = (struct i2o_packet_info *)bucket->packet_info;
-		atomic_dec(&priv->buckets_out);
-
-		/* Sanity checks: Any weird characteristics in bucket? */
-
-		if (packet->flags & 0x0f || ! packet->flags & 0x40) {
-			if (packet->flags & 0x01)
-				printk(KERN_WARNING "%s: packet with errors, error code=0x%02x.\n",
-					dev->name, packet->status & 0xff);
-
-			/* The following shouldn't happen, unless parameters in
-			 * LAN_OPERATION group are changed during the run time.
-			 */
-			 if (packet->flags & 0x0c)
-				printk(KERN_DEBUG "%s: multi-bucket packets not supported!\n", 
-					dev->name);
-					
-			if (! packet->flags & 0x40)
-				printk(KERN_DEBUG "%s: multiple packets in a bucket not supported!\n", 
-					dev->name);
-
-			dev_kfree_skb_irq(skb);
-
-			bucket++;
-			continue;
-		}
-
-		/* Copy short packet to a new skb */
-		
-		if (packet->len < priv->rx_copybreak) {
-			old_skb = skb;
-			skb = (struct sk_buff *)dev_alloc_skb(packet->len+2);
-			if (skb == NULL) {
-				printk(KERN_ERR "%s: Can't allocate skb.\n", dev->name);
-				return;
-			}
-			skb_reserve(skb, 2);
-			memcpy(skb_put(skb, packet->len), old_skb->data, packet->len);
-
-			spin_lock_irqsave(&priv->fbl_lock, flags);
-			if (priv->i2o_fbl_tail < I2O_LAN_MAX_BUCKETS_OUT)
-				priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb;
-			else
-				dev_kfree_skb_irq(old_skb);
-
-			spin_unlock_irqrestore(&priv->fbl_lock, flags);
-		} else
-			skb_put(skb, packet->len);
-
-		/* Deliver to upper layers */
-
-		skb->dev = dev;
-		skb->protocol = priv->type_trans(skb, dev);
-		netif_rx(skb);
-
-		dev->last_rx = jiffies;
-
-		dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered "
-			"to upper level.\n", dev->name, packet->len);
-
-		bucket++; // to next Packet Descriptor Block
-	}
-
-#ifdef DRIVERDEBUG
-	if (msg[5] == 0)
-		printk(KERN_INFO "%s: DDM out of buckets (priv->count = %d)!\n",
-		       dev->name, atomic_read(&priv->buckets_out));
-#endif
-
-	/* If DDM has already consumed bucket_thresh buckets, post new ones */
-
-	if (atomic_read(&priv->buckets_out) <= priv->max_buckets_out - priv->bucket_thresh) {
-		run_i2o_post_buckets_task.data = (void *)dev;
-		queue_task(&run_i2o_post_buckets_task, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-	}
-
-	return;
-}
-
-/*
- * i2o_lan_reply(): Callback function to handle other incoming messages
- * except SendPost and ReceivePost.
- */
-static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
-			  struct i2o_message *m)
-{
-	u32 *msg = (u32 *)m;
-	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
-	struct net_device *dev = i2o_landevs[unit];
-
-	if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) {
-		if (i2o_lan_handle_status(dev, msg))
-			return;
-
-		/* In other error cases just report and continue */
-
-		i2o_report_status(KERN_INFO, dev->name, msg);
-	}
-
-#ifdef DRIVERDEBUG
-	i2o_report_status(KERN_INFO, dev->name, msg);
-#endif
-	switch (msg[1] >> 24) {
-		case LAN_RESET:
-		case LAN_SUSPEND:
-			/* default reply without payload */
-		break;
-
-		case I2O_CMD_UTIL_EVT_REGISTER: 
-		case I2O_CMD_UTIL_EVT_ACK:
-			i2o_lan_handle_event(dev, msg);
-		break;
-
-		case I2O_CMD_UTIL_PARAMS_SET:
-			/* default reply, results in ReplyPayload (not examined) */
-			switch (msg[3] >> 16) {
-			    case 1: dprintk(KERN_INFO "%s: Reply to set MAC filter mask.\n",
-					dev->name);
-			    break;
-			    case 2: dprintk(KERN_INFO "%s: Reply to set MAC table.\n", 
-					dev->name);
-			    break;
-			    default: printk(KERN_WARNING "%s: Bad group 0x%04X\n",
-			 		dev->name,msg[3] >> 16);
-			}
-		break;
-
-		default:
-			printk(KERN_ERR "%s: No handler for the reply.\n",
-		       		dev->name);
-			i2o_report_status(KERN_INFO, dev->name, msg);
-	}
-}
-
-/* Functions used by the above callback functions:
-=================================================*/
-/*
- * i2o_lan_release_buckets(): Free unused buckets (sk_buffs).
- */
-static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	u8 trl_elem_size = (u8)(msg[3]>>8 & 0x000000FF);
-	u8 trl_count = (u8)(msg[3] & 0x000000FF);
-	u32 *pskb = &msg[6];
-
-	while (trl_count--) {
-		dprintk(KERN_DEBUG "%s: Releasing unused rx skb %p (trl_count=%d).\n",
-			dev->name, (struct sk_buff*)(*pskb),trl_count+1);
-		dev_kfree_skb_irq((struct sk_buff *)(*pskb));
-		pskb += 1 + trl_elem_size;
-		atomic_dec(&priv->buckets_out);
-	}
-}
-
-/*
- * i2o_lan_event_reply(): Handle events.
- */
-static void i2o_lan_handle_event(struct net_device *dev, u32 *msg)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-	u32 max_evt_data_size =iop->status_block->inbound_frame_size-5;
-	struct i2o_reply {
-		u32 header[4];
-		u32 evt_indicator;
-		u32 data[max_evt_data_size];
-	} *evt = (struct i2o_reply *)msg;
-	int evt_data_len = ((msg[0]>>16) - 5) * 4; /* real size*/
-
-	printk(KERN_INFO "%s: I2O event - ", dev->name);
-
-	if (msg[1]>>24 == I2O_CMD_UTIL_EVT_ACK) {
-		printk("Event acknowledgement reply.\n");
-		return;
-	}
-
-	/* Else evt->function == I2O_CMD_UTIL_EVT_REGISTER) */
-
-	switch (evt->evt_indicator) {
-	case I2O_EVT_IND_STATE_CHANGE:  {
-		struct state_data {
-			u16 status;
-			u8 state;
-			u8 data;
-		} *evt_data = (struct state_data *)(evt->data[0]);
-
-		printk("State chance 0x%08x.\n", evt->data[0]);
-
-		/* If the DDM is in error state, recovery may be
-		 * possible if status = Transmit or Receive Control
-		 * Unit Inoperable.
-		 */
-		if (evt_data->state==0x05 && evt_data->status==0x0003)
-			i2o_lan_reset(dev);
-		break;
-	}
-
-	case I2O_EVT_IND_FIELD_MODIFIED: {
-		u16 *work16 = (u16 *)evt->data;
-		printk("Group 0x%04x, field %d changed.\n", work16[0], work16[1]);
-		break;
-	}
-
-	case I2O_EVT_IND_VENDOR_EVT: {
-		int i;
-		printk("Vendor event:\n");
-		for (i = 0; i < evt_data_len / 4; i++)
-			printk("   0x%08x\n", evt->data[i]);
-		break;
-	}
-
-	case I2O_EVT_IND_DEVICE_RESET:
-		/* Spec 2.0 p. 6-121:
-		 * The event of _DEVICE_RESET should also be responded
-		 */
-		printk("Device reset.\n");
-		if (i2o_event_ack(iop, msg) < 0)
-			printk("%s: Event Acknowledge timeout.\n", dev->name);
-		break;
-
-#if 0
-	case I2O_EVT_IND_EVT_MASK_MODIFIED:
-		printk("Event mask modified, 0x%08x.\n", evt->data[0]);
-		break;
-
-	case I2O_EVT_IND_GENERAL_WARNING:
-		printk("General warning 0x%04x.\n", evt->data[0]);
-		break;
-
-	case I2O_EVT_IND_CONFIGURATION_FLAG:
-		printk("Configuration requested.\n");
-		break;
-
-	case I2O_EVT_IND_CAPABILITY_CHANGE:
-		printk("Capability change 0x%04x.\n", evt->data[0]);
-		break;
-
-	case I2O_EVT_IND_DEVICE_STATE:
-		printk("Device state changed 0x%08x.\n", evt->data[0]);
-		break;
-#endif
-	case I2O_LAN_EVT_LINK_DOWN:
-		netif_carrier_off(dev); 
-		printk("Link to the physical device is lost.\n");
-		break;
-
-	case I2O_LAN_EVT_LINK_UP:
-		netif_carrier_on(dev); 
-		printk("Link to the physical device is (re)established.\n");
-		break;
-
-	case I2O_LAN_EVT_MEDIA_CHANGE:
-		printk("Media change.\n");
-		break;
-	default:
-		printk("0x%08x. No handler.\n", evt->evt_indicator);
-	}
-}
-
-/*
- * i2o_lan_receive_post(): Post buckets to receive packets.
- */
-static int i2o_lan_receive_post(struct net_device *dev)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-	struct sk_buff *skb;
-	u32 m, *msg;
-	u32 bucket_len = (dev->mtu + dev->hard_header_len);
-	u32 total = priv->max_buckets_out - atomic_read(&priv->buckets_out);
-	u32 bucket_count;
-	u32 *sgl_elem;
-	unsigned long flags;
-
-	/* Send (total/bucket_count) separate I2O requests */
-
-	while (total) {
-		m = I2O_POST_READ32(iop);
-		if (m == 0xFFFFFFFF)
-			return -ETIMEDOUT;
-		msg = (u32 *)(iop->mem_offset + m);
-
-		bucket_count = (total >= priv->sgl_max) ? priv->sgl_max : total;
-		total -= bucket_count;
-		atomic_add(bucket_count, &priv->buckets_out);
-
-		dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN DDM.\n",
-			dev->name, bucket_count, bucket_len);
-
-		/* Fill in the header */
-
-		__raw_writel(I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4, msg);
-		__raw_writel(LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1);
-		__raw_writel(priv->unit << 16 | lan_receive_context, msg+2);
-		__raw_writel(bucket_count, msg+3);
-		sgl_elem = &msg[4];
-
-		/* Fill in the payload - contains bucket_count SGL elements */
-
-		while (bucket_count--) {
-			spin_lock_irqsave(&priv->fbl_lock, flags);
-			if (priv->i2o_fbl_tail >= 0)
-				skb = priv->i2o_fbl[priv->i2o_fbl_tail--];
-			else {
-				skb = dev_alloc_skb(bucket_len + 2);
-				if (skb == NULL) {
-					spin_unlock_irqrestore(&priv->fbl_lock, flags);
-					return -ENOMEM;
-				}
-				skb_reserve(skb, 2);
-			}
-			spin_unlock_irqrestore(&priv->fbl_lock, flags);
-
-			__raw_writel(0x51000000 | bucket_len, sgl_elem);
-			__raw_writel((u32)skb,		      sgl_elem+1);
-			__raw_writel(virt_to_bus(skb->data),  sgl_elem+2);
-			sgl_elem += 3;
-		}
-
-		/* set LE flag and post  */
-		__raw_writel(__raw_readl(sgl_elem-3) | 0x80000000, (sgl_elem-3));
-		i2o_post_message(iop, m);
-	}
-
-	return 0;
-}
-
-/* Functions called from the network stack, and functions called by them:
-========================================================================*/
-
-/*
- * i2o_lan_reset(): Reset the LAN adapter into the operational state and
- * 	restore it to full operation.
- */
-static int i2o_lan_reset(struct net_device *dev)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-	u32 msg[5];
-
-	dprintk(KERN_INFO "%s: LAN RESET MESSAGE.\n", dev->name);
-	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
-	msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid;
-	msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
-	msg[3] = 0; 				 // TransactionContext
-	msg[4] = 0;				 // Keep posted buckets
-
-	if (i2o_post_this(iop, msg, sizeof(msg)) < 0)
-		return -ETIMEDOUT;
-
-	return 0;
-}
-
-/*
- * i2o_lan_suspend(): Put LAN adapter into a safe, non-active state.
- * 	IOP replies to any LAN class message with status error_no_data_transfer
- *	/ suspended.
- */
-static int i2o_lan_suspend(struct net_device *dev)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-	u32 msg[5];
-
-	dprintk(KERN_INFO "%s: LAN SUSPEND MESSAGE.\n", dev->name);
-	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
-	msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid;
-	msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
-	msg[3] = 0; 				 // TransactionContext
-	msg[4] = 1 << 16; 			 // return posted buckets
-
-	if (i2o_post_this(iop, msg, sizeof(msg)) < 0)
-		return -ETIMEDOUT;
-
-	return 0;
-}
-
-/*
- * i2o_set_ddm_parameters:
- * These settings are done to ensure proper initial values for DDM.
- * They can be changed via proc file system or vai configuration utility.
- */
-static void i2o_set_ddm_parameters(struct net_device *dev)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-	u32 val;
-
-	/*
-	 * When PacketOrphanlimit is set to the maximum packet length,
-	 * the packets will never be split into two separate buckets
-	 */
-	val = dev->mtu + dev->hard_header_len;
-	if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0004, 2, &val, sizeof(val)) < 0)
-		printk(KERN_WARNING "%s: Unable to set PacketOrphanLimit.\n",
-		       dev->name);
-	else
-		dprintk(KERN_INFO "%s: PacketOrphanLimit set to %d.\n",
-			dev->name, val);
-
-	/* When RxMaxPacketsBucket = 1, DDM puts only one packet into bucket */
-
-	val = 1;
-	if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0008, 4, &val, sizeof(val)) <0)
-		printk(KERN_WARNING "%s: Unable to set RxMaxPacketsBucket.\n",
-		       dev->name);
-	else
-		dprintk(KERN_INFO "%s: RxMaxPacketsBucket set to %d.\n", 
-			dev->name, val);
-	return;
-}
-
-/* Functions called from the network stack:
-==========================================*/
-
-/*
- * i2o_lan_open(): Open the device to send/receive packets via
- * the network device.
- */
-static int i2o_lan_open(struct net_device *dev)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-	u32 mc_addr_group[64];
-
-	MOD_INC_USE_COUNT;
-
-	if (i2o_claim_device(i2o_dev, &i2o_lan_handler)) {
-		printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name);
-		MOD_DEC_USE_COUNT;
-		return -EAGAIN;
-	}
-	dprintk(KERN_INFO "%s: I2O LAN device (tid=%d) claimed by LAN OSM.\n",
-		dev->name, i2o_dev->lct_data.tid);
-
-	if (i2o_event_register(iop, i2o_dev->lct_data.tid,
-			       priv->unit << 16 | lan_context, 0, priv->i2o_event_mask) < 0)
-		printk(KERN_WARNING "%s: Unable to set the event mask.\n", dev->name);
-
-	i2o_lan_reset(dev);
-
-	/* Get the max number of multicast addresses */
-
-	if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0001, -1,
-			     &mc_addr_group, sizeof(mc_addr_group)) < 0 ) {
-		printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name);
-		MOD_DEC_USE_COUNT;
-		return -EAGAIN;
-	}
-	priv->max_size_mc_table = mc_addr_group[8];
-
-	/* Malloc space for free bucket list to resuse reveive post buckets */
-
-	priv->i2o_fbl = kmalloc(priv->max_buckets_out * sizeof(struct sk_buff *),
-				GFP_KERNEL);
-	if (priv->i2o_fbl == NULL) {
-		MOD_DEC_USE_COUNT;
-		return -ENOMEM;
-	}
-	priv->i2o_fbl_tail = -1;
-	priv->send_active = 0;
-
-	i2o_set_ddm_parameters(dev);
-	i2o_lan_receive_post(dev);
-
-	netif_start_queue(dev);
-
-	return 0;
-}
-
-/*
- * i2o_lan_close(): End the transfering.
- */
-static int i2o_lan_close(struct net_device *dev)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-	int ret = 0;
-
-	netif_stop_queue(dev);
-	i2o_lan_suspend(dev);
-
-	if (i2o_event_register(iop, i2o_dev->lct_data.tid,
-			       priv->unit << 16 | lan_context, 0, 0) < 0)
-		printk(KERN_WARNING "%s: Unable to clear the event mask.\n",
-		       dev->name);
-
-	while (priv->i2o_fbl_tail >= 0)
-		dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]);
-
-	kfree(priv->i2o_fbl);
-
-	if (i2o_release_device(i2o_dev, &i2o_lan_handler)) {
-		printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device "
-		       "(tid=%d).\n", dev->name, i2o_dev->lct_data.tid);
-		ret = -EBUSY;
-	}
-
-	MOD_DEC_USE_COUNT;
-
-	return ret;
-}
-
-/*
- * i2o_lan_tx_timeout(): Tx timeout handler.
- */
-static void i2o_lan_tx_timeout(struct net_device *dev)
-{
- 	if (!netif_queue_stopped(dev))
-		netif_start_queue(dev);
-}
-
-/*
- * i2o_lan_batch_send(): Send packets in batch. 
- * Both i2o_lan_sdu_send and i2o_lan_packet_send use this.
- */
-static void i2o_lan_batch_send(struct net_device *dev)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_controller *iop = priv->i2o_dev->controller;
-
-	spin_lock_irq(&priv->tx_lock);
-	if (priv->tx_count != 0) {
-		dev->trans_start = jiffies;
-		i2o_post_message(iop, priv->m);
-		dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count);
-		priv->tx_count = 0;
-	}
-	priv->send_active = 0;
-	spin_unlock_irq(&priv->tx_lock);
-	MOD_DEC_USE_COUNT;
-}
-
-#ifdef CONFIG_NET_FC
-/*
- * i2o_lan_sdu_send(): Send a packet, MAC header added by the DDM.
- * Must be supported by Fibre Channel, optional for Ethernet/802.3,
- * Token Ring, FDDI
- */
-static int i2o_lan_sdu_send(struct sk_buff *skb, struct net_device *dev)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-	int tickssofar = jiffies - dev->trans_start;
-	u32 m, *msg;
-	u32 *sgl_elem;
-
-	spin_lock_irq(&priv->tx_lock);
-
-	priv->tx_count++;
-	atomic_inc(&priv->tx_out);
-
-	/* 
-	 * If tx_batch_mode = 0x00 forced to immediate mode
-	 * If tx_batch_mode = 0x01 forced to batch mode
-	 * If tx_batch_mode = 0x10 switch automatically, current mode immediate
-	 * If tx_batch_mode = 0x11 switch automatically, current mode batch
-	 *	If gap between two packets is > 0 ticks, switch to immediate
-	 */
-	if (priv->tx_batch_mode >> 1) // switch automatically
-		priv->tx_batch_mode = tickssofar ? 0x02 : 0x03;
-
-	if (priv->tx_count == 1) {
-		m = I2O_POST_READ32(iop);
-		if (m == 0xFFFFFFFF) {
-			spin_unlock_irq(&priv->tx_lock);
-			return 1;
-		}
-		msg = (u32 *)(iop->mem_offset + m);
-		priv->m = m;
-
-		__raw_writel(NINE_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg);
-		__raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1);
-		__raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext
-		__raw_writel(1 << 30 | 1 << 3, msg+3); 		 	  // TransmitControlWord
-
-		__raw_writel(0xD7000000 | skb->len, msg+4);  	     // MAC hdr included
-		__raw_writel((u32)skb, msg+5);  		     // TransactionContext
-		__raw_writel(virt_to_bus(skb->data), msg+6);
-		__raw_writel((u32)skb->mac.raw, msg+7);
-		__raw_writel((u32)skb->mac.raw+4, msg+8);
-
-		if ((priv->tx_batch_mode & 0x01) && !priv->send_active) {
-			priv->send_active = 1;
-			MOD_INC_USE_COUNT;
-			if (schedule_task(&priv->i2o_batch_send_task) == 0)
-				MOD_DEC_USE_COUNT;
-		}
-	} else {  /* Add new SGL element to the previous message frame */
-
-		msg = (u32 *)(iop->mem_offset + priv->m);
-		sgl_elem = &msg[priv->tx_count * 5 + 1];
-
-		__raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 5) | 1<<12 | SGL_OFFSET_4, msg);
-		__raw_writel(__raw_readl(sgl_elem-5) & 0x7FFFFFFF, sgl_elem-5); /* clear LE flag */
-		__raw_writel(0xD5000000 | skb->len, sgl_elem);
-		__raw_writel((u32)skb, sgl_elem+1);
-		__raw_writel(virt_to_bus(skb->data), sgl_elem+2);
-		__raw_writel((u32)(skb->mac.raw), sgl_elem+3);
-		__raw_writel((u32)(skb->mac.raw)+1, sgl_elem+4);
-	}
-
-	/* If tx not in batch mode or frame is full, send immediatelly */
-
-	if (!(priv->tx_batch_mode & 0x01) || priv->tx_count == priv->sgl_max) {
-		dev->trans_start = jiffies;
-		i2o_post_message(iop, priv->m);
-		dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count);
-		priv->tx_count = 0;
-	}
-
-	/* If DDMs TxMaxPktOut reached, stop queueing layer to send more */
-
-	if (atomic_read(&priv->tx_out) >= priv->tx_max_out)
-		netif_stop_queue(dev);
-
-	spin_unlock_irq(&priv->tx_lock);
-	return 0;
-}
-#endif /* CONFIG_NET_FC */
-
-/*
- * i2o_lan_packet_send(): Send a packet as is, including the MAC header.
- *
- * Must be supported by Ethernet/802.3, Token Ring, FDDI, optional for
- * Fibre Channel
- */
-static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-	int tickssofar = jiffies - dev->trans_start;
-	u32 m, *msg;
-	u32 *sgl_elem;
-
-	spin_lock_irq(&priv->tx_lock);
-
-	priv->tx_count++;
-	atomic_inc(&priv->tx_out);
-
-	/* 
-	 * If tx_batch_mode = 0x00 forced to immediate mode
-	 * If tx_batch_mode = 0x01 forced to batch mode
-	 * If tx_batch_mode = 0x10 switch automatically, current mode immediate
-	 * If tx_batch_mode = 0x11 switch automatically, current mode batch
-	 *	If gap between two packets is > 0 ticks, switch to immediate
-	 */
-	if (priv->tx_batch_mode >> 1) // switch automatically
-		priv->tx_batch_mode = tickssofar ? 0x02 : 0x03;
-
-	if (priv->tx_count == 1) {
-		m = I2O_POST_READ32(iop);
-		if (m == 0xFFFFFFFF) {
-			spin_unlock_irq(&priv->tx_lock);
-			return 1;
-		}
-		msg = (u32 *)(iop->mem_offset + m);
-		priv->m = m;
-
-		__raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg);
-		__raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1);
-		__raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext
-		__raw_writel(1 << 30 | 1 << 3, msg+3); 		 	  // TransmitControlWord
-			// bit 30: reply as soon as transmission attempt is complete
-			// bit 3: Suppress CRC generation
-		__raw_writel(0xD5000000 | skb->len, msg+4);  	     // MAC hdr included
-		__raw_writel((u32)skb, msg+5);  		     // TransactionContext
-		__raw_writel(virt_to_bus(skb->data), msg+6);
-
-		if ((priv->tx_batch_mode & 0x01) && !priv->send_active) {
-			priv->send_active = 1;
-			MOD_INC_USE_COUNT;
-			if (schedule_task(&priv->i2o_batch_send_task) == 0)
-				MOD_DEC_USE_COUNT;
-		}
-	} else {  /* Add new SGL element to the previous message frame */
-
-		msg = (u32 *)(iop->mem_offset + priv->m);
-		sgl_elem = &msg[priv->tx_count * 3 + 1];
-
-		__raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 3) | 1<<12 | SGL_OFFSET_4, msg);
-		__raw_writel(__raw_readl(sgl_elem-3) & 0x7FFFFFFF, sgl_elem-3); /* clear LE flag */
-		__raw_writel(0xD5000000 | skb->len, sgl_elem);
-		__raw_writel((u32)skb, sgl_elem+1);
-		__raw_writel(virt_to_bus(skb->data), sgl_elem+2);
-	}
-
-	/* If tx is in immediate mode or frame is full, send now */
-
-	if (!(priv->tx_batch_mode & 0x01) || priv->tx_count == priv->sgl_max) {
-		dev->trans_start = jiffies;
-		i2o_post_message(iop, priv->m);
-		dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count);
-		priv->tx_count = 0;
-	}
-
-	/* If DDMs TxMaxPktOut reached, stop queueing layer to send more */
-
-	if (atomic_read(&priv->tx_out) >= priv->tx_max_out)
-		netif_stop_queue(dev);
-
-	spin_unlock_irq(&priv->tx_lock);
-	return 0;
-}
-
-/*
- * i2o_lan_get_stats(): Fill in the statistics.
- */
-static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-	u64 val64[16];
-	u64 supported_group[4] = { 0, 0, 0, 0 };
-
-	if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0100, -1, val64,
-			     sizeof(val64)) < 0)
-		printk(KERN_INFO "%s: Unable to query LAN_HISTORICAL_STATS.\n", dev->name);
-	else {
-		dprintk(KERN_DEBUG "%s: LAN_HISTORICAL_STATS queried.\n", dev->name);
-		priv->stats.tx_packets = val64[0];
-		priv->stats.tx_bytes   = val64[1];
-		priv->stats.rx_packets = val64[2];
-		priv->stats.rx_bytes   = val64[3];
-		priv->stats.tx_errors  = val64[4];
-		priv->stats.rx_errors  = val64[5];
-		priv->stats.rx_dropped = val64[6];
-	}
-
-	if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0180, -1,
-			     &supported_group, sizeof(supported_group)) < 0)
-		printk(KERN_INFO "%s: Unable to query LAN_SUPPORTED_OPTIONAL_HISTORICAL_STATS.\n", dev->name);
-
-	if (supported_group[2]) {
-		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0183, -1,
-				     val64, sizeof(val64)) < 0)
-			printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n", dev->name);
-		else {
-			dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n", dev->name);
-			priv->stats.multicast	     = val64[4];
-			priv->stats.rx_length_errors = val64[10];
-			priv->stats.rx_crc_errors    = val64[0];
-		}
-	}
-
-	if (i2o_dev->lct_data.sub_class == I2O_LAN_ETHERNET) {
-		u64 supported_stats = 0;
-		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0200, -1,
-				     val64, sizeof(val64)) < 0)
-			printk(KERN_INFO "%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n", dev->name);
-		else {
-			dprintk(KERN_DEBUG "%s: LAN_802_3_HISTORICAL_STATS queried.\n", dev->name);
-	 		priv->stats.transmit_collision = val64[1] + val64[2];
-			priv->stats.rx_frame_errors    = val64[0];
-			priv->stats.tx_carrier_errors  = val64[6];
-		}
-
-		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0280, -1,
-				     &supported_stats, sizeof(supported_stats)) < 0)
-			printk(KERN_INFO "%s: Unable to query LAN_SUPPORTED_802_3_HISTORICAL_STATS.\n", dev->name);
-
-		if (supported_stats != 0) {
-			if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0281, -1,
-					     val64, sizeof(val64)) < 0)
-				printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n", dev->name);
-			else {
-				dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n", dev->name);
-				if (supported_stats & 0x1)
-					priv->stats.rx_over_errors = val64[0];
-				if (supported_stats & 0x4)
-					priv->stats.tx_heartbeat_errors = val64[2];
-			}
-		}
-	}
-
-#ifdef CONFIG_TR
-	if (i2o_dev->lct_data.sub_class == I2O_LAN_TR) {
-		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0300, -1,
-				     val64, sizeof(val64)) < 0)
-			printk(KERN_INFO "%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n", dev->name);
-		else {
-			struct tr_statistics *stats =
-				(struct tr_statistics *)&priv->stats;
-			dprintk(KERN_DEBUG "%s: LAN_802_5_HISTORICAL_STATS queried.\n", dev->name);
-
-			stats->line_errors		= val64[0];
-			stats->internal_errors		= val64[7];
-			stats->burst_errors		= val64[4];
-			stats->A_C_errors		= val64[2];
-			stats->abort_delimiters		= val64[3];
-			stats->lost_frames		= val64[1];
-			/* stats->recv_congest_count	= ?;  FIXME ??*/
-			stats->frame_copied_errors	= val64[5];
-			stats->frequency_errors		= val64[6];
-			stats->token_errors		= val64[9];
-		}
-		/* Token Ring optional stats not yet defined */
-	}
-#endif
-
-#ifdef CONFIG_FDDI
-	if (i2o_dev->lct_data.sub_class == I2O_LAN_FDDI) {
-		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0400, -1,
-				     val64, sizeof(val64)) < 0)
-			printk(KERN_INFO "%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n", dev->name);
-		else {
-			dprintk(KERN_DEBUG "%s: LAN_FDDI_HISTORICAL_STATS queried.\n", dev->name);
-			priv->stats.smt_cf_state = val64[0];
-			memcpy(priv->stats.mac_upstream_nbr, &val64[1], FDDI_K_ALEN);
-			memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN);
-			priv->stats.mac_error_cts = val64[3];
-			priv->stats.mac_lost_cts  = val64[4];
-			priv->stats.mac_rmt_state = val64[5];
-			memcpy(priv->stats.port_lct_fail_cts, &val64[6], 8);
-			memcpy(priv->stats.port_lem_reject_cts, &val64[7], 8);
-			memcpy(priv->stats.port_lem_cts, &val64[8], 8);
-			memcpy(priv->stats.port_pcm_state, &val64[9], 8);
-		}
-		/* FDDI optional stats not yet defined */
-	}
-#endif
-
-#ifdef CONFIG_NET_FC
-	/* Fibre Channel Statistics not yet defined in 1.53 nor 2.0 */
-#endif
-
-	return (struct net_device_stats *)&priv->stats;
-}
-
-/* 
- * i2o_lan_set_mc_filter(): Post a request to set multicast filter.
- */
-int i2o_lan_set_mc_filter(struct net_device *dev, u32 filter_mask)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-	u32 msg[10]; 
-
-	msg[0] = TEN_WORD_MSG_SIZE | SGL_OFFSET_5;
-	msg[1] = I2O_CMD_UTIL_PARAMS_SET << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid;
-	msg[2] = priv->unit << 16 | lan_context;
-	msg[3] = 0x0001 << 16 | 3 ;	// TransactionContext: group&field
-	msg[4] = 0;
-	msg[5] = 0xCC000000 | 16; 			// Immediate data SGL
-	msg[6] = 1;					// OperationCount
-	msg[7] = 0x0001<<16 | I2O_PARAMS_FIELD_SET;	// Group, Operation
-	msg[8] = 3 << 16 | 1; 				// FieldIndex, FieldCount 
-	msg[9] = filter_mask;				// Value
-
-	return i2o_post_this(iop, msg, sizeof(msg));
-}
-
-/* 
- * i2o_lan_set_mc_table(): Post a request to set LAN_MULTICAST_MAC_ADDRESS table.
- */
-int i2o_lan_set_mc_table(struct net_device *dev)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;
-	struct dev_mc_list *mc;
-	u32 msg[10 + 2 * dev->mc_count]; 
-	u8 *work8 = (u8 *)(msg + 10);
-
-	msg[0] = I2O_MESSAGE_SIZE(10 + 2 * dev->mc_count) | SGL_OFFSET_5;
-	msg[1] = I2O_CMD_UTIL_PARAMS_SET << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid;
-	msg[2] = priv->unit << 16 | lan_context;	// InitiatorContext
-	msg[3] = 0x0002 << 16 | (u16)-1;		// TransactionContext
-	msg[4] = 0;					// OperationFlags
-	msg[5] = 0xCC000000 | (16 + 8 * dev->mc_count);	// Immediate data SGL
-	msg[6] = 2;					// OperationCount
-	msg[7] = 0x0002 << 16 | I2O_PARAMS_TABLE_CLEAR;	// Group, Operation
-	msg[8] = 0x0002 << 16 | I2O_PARAMS_ROW_ADD;     // Group, Operation
-	msg[9] = dev->mc_count << 16 | (u16)-1; 	// RowCount, FieldCount
-
-        for (mc = dev->mc_list; mc ; mc = mc->next, work8 += 8) {
-		  memset(work8, 0, 8);
-                  memcpy(work8, mc->dmi_addr, mc->dmi_addrlen); // Values
-	}
-
-	return i2o_post_this(iop, msg, sizeof(msg));
-}
-
-/*
- * i2o_lan_set_multicast_list(): Enable a network device to receive packets
- *      not send to the protocol address.
- */
-static void i2o_lan_set_multicast_list(struct net_device *dev)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	u32 filter_mask;
-
-	if (dev->flags & IFF_PROMISC) {
-		filter_mask = 0x00000002;
-		dprintk(KERN_INFO "%s: Enabling promiscuous mode...\n", dev->name);
-	} else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > priv->max_size_mc_table) {
-		filter_mask = 0x00000004;
-		dprintk(KERN_INFO "%s: Enabling all multicast mode...\n", dev->name);
-	} else if (dev->mc_count) {
-		filter_mask = 0x00000000;
-		dprintk(KERN_INFO "%s: Enabling multicast mode...\n", dev->name);
-		if (i2o_lan_set_mc_table(dev) < 0)
-			printk(KERN_WARNING "%s: Unable to send MAC table.\n", dev->name);
-	} else {
-		filter_mask = 0x00000300; // Broadcast, Multicast disabled
-		dprintk(KERN_INFO "%s: Enabling unicast mode...\n", dev->name);
-	}
-
-	/* Finally copy new FilterMask to DDM */
-
-	if (i2o_lan_set_mc_filter(dev, filter_mask) < 0)
-		printk(KERN_WARNING "%s: Unable to send MAC FilterMask.\n", dev->name);
-}
-
-/*
- * i2o_lan_change_mtu(): Change maximum transfer unit size.
- */
-static int i2o_lan_change_mtu(struct net_device *dev, int new_mtu)
-{
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	struct i2o_device *i2o_dev = priv->i2o_dev;
-	u32 max_pkt_size;
-
-	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid,
-		 	     0x0000, 6, &max_pkt_size, 4) < 0)
-		return -EFAULT;
-
-	if (new_mtu < 68 || new_mtu > 9000 || new_mtu > max_pkt_size)
-		return -EINVAL;
-
-	dev->mtu = new_mtu;
-
-	i2o_lan_suspend(dev);   	// to SUSPENDED state, return buckets
-
-	while (priv->i2o_fbl_tail >= 0) // free buffered buckets
-		dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]);
-
-	i2o_lan_reset(dev);		// to OPERATIONAL state
-	i2o_set_ddm_parameters(dev); 	// reset some parameters
-	i2o_lan_receive_post(dev); 	// post new buckets (new size)
-
-	return 0;
-}
-
-/* Functions to initialize I2O LAN OSM:
-======================================*/
-
-/*
- * i2o_lan_register_device(): Register LAN class device to kernel.
- */
-struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
-{
-	struct net_device *dev = NULL;
-	struct i2o_lan_local *priv = NULL;
-	u8 hw_addr[8];
-	u32 tx_max_out = 0;
-	unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
-	void (*unregister_dev)(struct net_device *dev);
-
-	switch (i2o_dev->lct_data.sub_class) {
-	case I2O_LAN_ETHERNET:
-		dev = init_etherdev(NULL, sizeof(struct i2o_lan_local));
-		if (dev == NULL)
-			return NULL;
-		type_trans = eth_type_trans;
-		unregister_dev = unregister_netdev;
-		break;
-
-#ifdef CONFIG_ANYLAN
-	case I2O_LAN_100VG:
-		printk(KERN_ERR "i2o_lan: 100base VG not yet supported.\n");
-		return NULL;
-		break;
-#endif
-
-#ifdef CONFIG_TR
-	case I2O_LAN_TR:
-		dev = init_trdev(NULL, sizeof(struct i2o_lan_local));
-		if (dev==NULL)
-			return NULL;
-		type_trans = tr_type_trans;
-		unregister_dev = unregister_trdev;
-		break;
-#endif
-
-#ifdef CONFIG_FDDI
-	case I2O_LAN_FDDI:
-	{
-		int size = sizeof(struct net_device) + sizeof(struct i2o_lan_local);
-
-		dev = (struct net_device *) kmalloc(size, GFP_KERNEL);
-		if (dev == NULL)
-			return NULL;
-		memset((char *)dev, 0, size);
-	    	dev->priv = (void *)(dev + 1);
-
-		if (dev_alloc_name(dev, "fddi%d") < 0) {
-			printk(KERN_WARNING "i2o_lan: Too many FDDI devices.\n");
-			kfree(dev);
-			return NULL;
-		}
-		type_trans = fddi_type_trans;
-		unregister_dev = (void *)unregister_netdevice;
-
-		fddi_setup(dev);
-		register_netdev(dev);
-	}
-	break;
-#endif
-
-#ifdef CONFIG_NET_FC
-	case I2O_LAN_FIBRE_CHANNEL:
-		dev = init_fcdev(NULL, sizeof(struct i2o_lan_local));
-		if (dev == NULL)
-			return NULL;
-		type_trans = NULL;
-/* FIXME: Move fc_type_trans() from drivers/net/fc/iph5526.c to net/802/fc.c
- * and export it in include/linux/fcdevice.h
- *		type_trans = fc_type_trans;
- */
-		unregister_dev = (void *)unregister_fcdev;
-		break;
-#endif
-
-	case I2O_LAN_UNKNOWN:
-	default:
-		printk(KERN_ERR "i2o_lan: LAN type 0x%04x not supported.\n",
-		       i2o_dev->lct_data.sub_class);
-		return NULL;
-	}
-
-	priv = (struct i2o_lan_local *)dev->priv;
-	priv->i2o_dev = i2o_dev;
-	priv->type_trans = type_trans;
-	priv->sgl_max = (i2o_dev->controller->status_block->inbound_frame_size - 4) / 3;
-	atomic_set(&priv->buckets_out, 0);
-
-	/* Set default values for user configurable parameters */
-	/* Private values are changed via /proc file system */
-
-	priv->max_buckets_out = max_buckets_out;
-	priv->bucket_thresh   = bucket_thresh;
-	priv->rx_copybreak    = rx_copybreak;
-	priv->tx_batch_mode   = tx_batch_mode & 0x03;
-	priv->i2o_event_mask  = i2o_event_mask;
-
-	priv->tx_lock	      = SPIN_LOCK_UNLOCKED;
-	priv->fbl_lock	      = SPIN_LOCK_UNLOCKED;
-
-	unit++;
-	i2o_landevs[unit] = dev;
-	priv->unit = unit;
-
-	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid,
-			     0x0001, 0, &hw_addr, sizeof(hw_addr)) < 0) {
-		printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name);
-		unit--;
-		unregister_dev(dev);
-		kfree(dev);
-		return NULL;
-	}
-	dprintk(KERN_DEBUG "%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
- 		dev->name, hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3],
-		hw_addr[4], hw_addr[5]);
-
-	dev->addr_len = 6;
-	memcpy(dev->dev_addr, hw_addr, 6);
-
-	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid,
-			     0x0007, 2, &tx_max_out, sizeof(tx_max_out)) < 0) {
-		printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name);
-		unit--;
-		unregister_dev(dev);
-		kfree(dev);
-		return NULL;
-	}
-	dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max_out);
-	priv->tx_max_out = tx_max_out;
-	atomic_set(&priv->tx_out, 0);
-	priv->tx_count = 0;
-
-	INIT_LIST_HEAD(&priv->i2o_batch_send_task.list);
-	priv->i2o_batch_send_task.sync    = 0;
-	priv->i2o_batch_send_task.routine = (void *)i2o_lan_batch_send;
-	priv->i2o_batch_send_task.data    = (void *)dev;
-
-	dev->open		= i2o_lan_open;
-	dev->stop		= i2o_lan_close;
-	dev->get_stats		= i2o_lan_get_stats;
-	dev->set_multicast_list = i2o_lan_set_multicast_list;
-	dev->tx_timeout		= i2o_lan_tx_timeout;
-	dev->watchdog_timeo	= I2O_LAN_TX_TIMEOUT;
-
-#ifdef CONFIG_NET_FC
-	if (i2o_dev->lct_data.sub_class == I2O_LAN_FIBRE_CHANNEL)
-		dev->hard_start_xmit = i2o_lan_sdu_send;
-	else
-#endif
-		dev->hard_start_xmit = i2o_lan_packet_send;
-
-	if (i2o_dev->lct_data.sub_class == I2O_LAN_ETHERNET)
-		dev->change_mtu	= i2o_lan_change_mtu;
-
-	return dev;
-}
-
-#ifdef MODULE
-#define i2o_lan_init	init_module
-#endif
-
-int __init i2o_lan_init(void)
-{
-	struct net_device *dev;
-	int i;
-
-	printk(KERN_INFO "I2O LAN OSM (C) 1999 University of Helsinki.\n");
-
-	/* Module params are used as global defaults for private values */
-
-	if (max_buckets_out > I2O_LAN_MAX_BUCKETS_OUT)
-		max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT;
-	if (bucket_thresh > max_buckets_out)
-		bucket_thresh = max_buckets_out;
-
-	/* Install handlers for incoming replies */
-
-	if (i2o_install_handler(&i2o_lan_send_handler) < 0) {
- 		printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n");
-		return -EINVAL;
-	}
-	lan_send_context = i2o_lan_send_handler.context;
-
-	if (i2o_install_handler(&i2o_lan_receive_handler) < 0) {
- 		printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n");
-		return -EINVAL;
-	}
-	lan_receive_context = i2o_lan_receive_handler.context;
-
-	if (i2o_install_handler(&i2o_lan_handler) < 0) {
- 		printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n");
-		return -EINVAL;
-	}
-	lan_context = i2o_lan_handler.context;
-
-	for(i=0; i <= MAX_LAN_CARDS; i++)
-		i2o_landevs[i] = NULL;
-
-	for (i=0; i < MAX_I2O_CONTROLLERS; i++) {
-		struct i2o_controller *iop = i2o_find_controller(i);
-		struct i2o_device *i2o_dev;
-
-		if (iop==NULL)
-			continue;
-
-		for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next) {
-
-			if (i2o_dev->lct_data.class_id != I2O_CLASS_LAN)
-				continue;
-
-			/* Make sure device not already claimed by an ISM */
-			if (i2o_dev->lct_data.user_tid != 0xFFF)
-				continue;
-
-			if (unit == MAX_LAN_CARDS) {
-				i2o_unlock_controller(iop);
-				printk(KERN_WARNING "i2o_lan: Too many I2O LAN devices.\n");
-				return -EINVAL;
-			}
-
-			dev = i2o_lan_register_device(i2o_dev);
- 			if (dev == NULL) {
-				printk(KERN_ERR "i2o_lan: Unable to register I2O LAN device 0x%04x.\n",
-				       i2o_dev->lct_data.sub_class);
-				continue;
-			}
-
-			printk(KERN_INFO "%s: I2O LAN device registered, "
-				"subclass = 0x%04x, unit = %d, tid = %d.\n",
-				dev->name, i2o_dev->lct_data.sub_class,
-				((struct i2o_lan_local *)dev->priv)->unit,
-				i2o_dev->lct_data.tid);
-		}
-
-		i2o_unlock_controller(iop);
-	}
-
-	dprintk(KERN_INFO "%d I2O LAN devices found and registered.\n", unit+1);
-
-	return 0;
-}
-
-#ifdef MODULE
-
-void cleanup_module(void)
-{
-	int i;
-
-	for (i = 0; i <= unit; i++) {
-		struct net_device *dev = i2o_landevs[i];
-		struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-		struct i2o_device *i2o_dev = priv->i2o_dev;
-
-		switch (i2o_dev->lct_data.sub_class) {
-		case I2O_LAN_ETHERNET:
-			unregister_netdev(dev);
-			break;
-#ifdef CONFIG_FDDI
-		case I2O_LAN_FDDI:
-			unregister_netdevice(dev);
-			break;
-#endif
-#ifdef CONFIG_TR
-		case I2O_LAN_TR:
-			unregister_trdev(dev);
-			break;
-#endif
-#ifdef CONFIG_NET_FC
-		case I2O_LAN_FIBRE_CHANNEL:
-			unregister_fcdev(dev);
-			break;
-#endif
-		default:
-			printk(KERN_WARNING "%s: Spurious I2O LAN subclass 0x%08x.\n",
-			       dev->name, i2o_dev->lct_data.sub_class);
-		}
-
-		dprintk(KERN_INFO "%s: I2O LAN device unregistered.\n",
-			dev->name);
-		kfree(dev);
-	}
-
-	i2o_remove_handler(&i2o_lan_handler);
-	i2o_remove_handler(&i2o_lan_send_handler);
-	i2o_remove_handler(&i2o_lan_receive_handler);
-}
-
-EXPORT_NO_SYMBOLS;
-
-MODULE_AUTHOR("University of Helsinki, Department of Computer Science");
-MODULE_DESCRIPTION("I2O Lan OSM");
-
-MODULE_PARM(max_buckets_out, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i");
-MODULE_PARM_DESC(max_buckets_out, "Total number of buckets to post (1-)");
-MODULE_PARM(bucket_thresh, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i");
-MODULE_PARM_DESC(bucket_thresh, "Bucket post threshold (1-)");
-MODULE_PARM(rx_copybreak, "1-" "i");
-MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy only small frames (1-)");
-MODULE_PARM(tx_batch_mode, "0-2" "i");
-MODULE_PARM_DESC(tx_batch_mode, "0=Send immediatelly, 1=Send in batches, 2=Switch automatically");
-
-#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/i2o_lan.h linux/drivers/i2o/i2o_lan.h
--- v2.4.12/linux/drivers/i2o/i2o_lan.h	Mon Dec 11 13:20:00 2000
+++ linux/drivers/i2o/i2o_lan.h	Wed Dec 31 16:00:00 1969
@@ -1,159 +0,0 @@
-/*
- *   	i2o_lan.h			I2O LAN Class definitions
- *
- *      I2O LAN CLASS OSM       	May 26th 2000
- *
- *      (C) Copyright 1999, 2000	University of Helsinki,
- *					Department of Computer Science
- *
- *      This code is still under development / test.
- *
- *	Author:		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- *			Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- *			Taneli Vähäkangas <Taneli.Vahakangas@cs.Helsinki.FI>
- */
-
-#ifndef _I2O_LAN_H
-#define _I2O_LAN_H
-
-/* Default values for tunable parameters first */
-
-#define I2O_LAN_MAX_BUCKETS_OUT 96
-#define I2O_LAN_BUCKET_THRESH	18	/* 9 buckets in one message */
-#define I2O_LAN_RX_COPYBREAK	200
-#define I2O_LAN_TX_TIMEOUT 	(1*HZ)
-#define I2O_LAN_TX_BATCH_MODE	2	/* 2=automatic, 1=on, 0=off */
-#define I2O_LAN_EVENT_MASK	0	/* 0=None, 0xFFC00002=All */
-
-/* LAN types */
-#define I2O_LAN_ETHERNET	0x0030
-#define I2O_LAN_100VG		0x0040
-#define I2O_LAN_TR		0x0050
-#define I2O_LAN_FDDI		0x0060
-#define I2O_LAN_FIBRE_CHANNEL	0x0070
-#define I2O_LAN_UNKNOWN		0x00000000
-
-/* Connector types */
-
-/* Ethernet */
-#define I2O_LAN_AUI		(I2O_LAN_ETHERNET << 4) + 0x00000001
-#define I2O_LAN_10BASE5		(I2O_LAN_ETHERNET << 4) + 0x00000002
-#define I2O_LAN_FIORL		(I2O_LAN_ETHERNET << 4) + 0x00000003
-#define I2O_LAN_10BASE2		(I2O_LAN_ETHERNET << 4) + 0x00000004
-#define I2O_LAN_10BROAD36	(I2O_LAN_ETHERNET << 4) + 0x00000005
-#define I2O_LAN_10BASE_T	(I2O_LAN_ETHERNET << 4) + 0x00000006
-#define I2O_LAN_10BASE_FP	(I2O_LAN_ETHERNET << 4) + 0x00000007
-#define I2O_LAN_10BASE_FB	(I2O_LAN_ETHERNET << 4) + 0x00000008
-#define I2O_LAN_10BASE_FL	(I2O_LAN_ETHERNET << 4) + 0x00000009
-#define I2O_LAN_100BASE_TX	(I2O_LAN_ETHERNET << 4) + 0x0000000A
-#define I2O_LAN_100BASE_FX	(I2O_LAN_ETHERNET << 4) + 0x0000000B
-#define I2O_LAN_100BASE_T4	(I2O_LAN_ETHERNET << 4) + 0x0000000C
-#define I2O_LAN_1000BASE_SX	(I2O_LAN_ETHERNET << 4) + 0x0000000D
-#define I2O_LAN_1000BASE_LX	(I2O_LAN_ETHERNET << 4) + 0x0000000E
-#define I2O_LAN_1000BASE_CX	(I2O_LAN_ETHERNET << 4) + 0x0000000F
-#define I2O_LAN_1000BASE_T	(I2O_LAN_ETHERNET << 4) + 0x00000010
-
-/* AnyLAN */
-#define I2O_LAN_100VG_ETHERNET	(I2O_LAN_100VG << 4) + 0x00000001
-#define I2O_LAN_100VG_TR	(I2O_LAN_100VG << 4) + 0x00000002
-
-/* Token Ring */
-#define I2O_LAN_4MBIT		(I2O_LAN_TR << 4) + 0x00000001
-#define I2O_LAN_16MBIT		(I2O_LAN_TR << 4) + 0x00000002
-
-/* FDDI */
-#define I2O_LAN_125MBAUD	(I2O_LAN_FDDI << 4) + 0x00000001
-
-/* Fibre Channel */
-#define I2O_LAN_POINT_POINT	(I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000001
-#define I2O_LAN_ARB_LOOP	(I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000002
-#define I2O_LAN_PUBLIC_LOOP	(I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000003
-#define I2O_LAN_FABRIC		(I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000004
-
-#define I2O_LAN_EMULATION	0x00000F00
-#define I2O_LAN_OTHER		0x00000F01
-#define I2O_LAN_DEFAULT		0xFFFFFFFF
-
-/* LAN class functions */
-
-#define LAN_PACKET_SEND		0x3B
-#define LAN_SDU_SEND		0x3D
-#define LAN_RECEIVE_POST	0x3E
-#define LAN_RESET		0x35
-#define LAN_SUSPEND		0x37
-
-/* LAN DetailedStatusCode defines */
-#define I2O_LAN_DSC_SUCCESS			0x00
-#define I2O_LAN_DSC_DEVICE_FAILURE		0x01
-#define I2O_LAN_DSC_DESTINATION_NOT_FOUND	0x02
-#define	I2O_LAN_DSC_TRANSMIT_ERROR		0x03
-#define I2O_LAN_DSC_TRANSMIT_ABORTED		0x04
-#define I2O_LAN_DSC_RECEIVE_ERROR		0x05
-#define I2O_LAN_DSC_RECEIVE_ABORTED		0x06
-#define I2O_LAN_DSC_DMA_ERROR			0x07
-#define I2O_LAN_DSC_BAD_PACKET_DETECTED		0x08
-#define I2O_LAN_DSC_OUT_OF_MEMORY		0x09
-#define I2O_LAN_DSC_BUCKET_OVERRUN		0x0A
-#define I2O_LAN_DSC_IOP_INTERNAL_ERROR		0x0B
-#define I2O_LAN_DSC_CANCELED			0x0C
-#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT	0x0D
-#define I2O_LAN_DSC_DEST_ADDRESS_DETECTED	0x0E
-#define I2O_LAN_DSC_DEST_ADDRESS_OMITTED	0x0F
-#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED	0x10
-#define I2O_LAN_DSC_SUSPENDED			0x11
-
-struct i2o_packet_info {
-	u32 offset : 24;
-	u32 flags  : 8;
-	u32 len    : 24;
-	u32 status : 8;
-};
-
-struct i2o_bucket_descriptor {
-	u32 context; 			/* FIXME: 64bit support */
-	struct i2o_packet_info packet_info[1];
-};
-
-/* Event Indicator Mask Flags for LAN OSM */
-
-#define I2O_LAN_EVT_LINK_DOWN		0x01
-#define I2O_LAN_EVT_LINK_UP		0x02
-#define I2O_LAN_EVT_MEDIA_CHANGE 	0x04
-
-#include <linux/netdevice.h>
-#include <linux/fddidevice.h>
-
-struct i2o_lan_local {
-	u8 unit;
-	struct i2o_device *i2o_dev;
-
-	struct fddi_statistics stats;   /* see also struct net_device_stats */
-	unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
-	atomic_t buckets_out;  		/* nbr of unused buckets on DDM */
-	atomic_t tx_out;		/* outstanding TXes */
-	u8 tx_count;  			/* packets in one TX message frame */
-	u16 tx_max_out;	   		/* DDM's Tx queue len */
-	u8 sgl_max;			/* max SGLs in one message frame */
-	u32 m;				/* IOP address of the batch msg frame */
-
-	struct tq_struct i2o_batch_send_task;
-	int send_active;
-	struct sk_buff **i2o_fbl;	/* Free bucket list (to reuse skbs) */
-	int i2o_fbl_tail;
-	spinlock_t fbl_lock;
-
-	spinlock_t tx_lock;
-
-	u32 max_size_mc_table;		/* max number of multicast addresses */
-
-	/* LAN OSM configurable parameters are here: */
-
-	u16 max_buckets_out;		/* max nbr of buckets to send to DDM */
-	u16 bucket_thresh;		/* send more when this many used */
-	u16 rx_copybreak;
-
-	u8  tx_batch_mode;		/* Set when using batch mode sends */
-	u32 i2o_event_mask;		/* To turn on interesting event flags */
-};
-
-#endif /* _I2O_LAN_H */
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c
--- v2.4.12/linux/drivers/i2o/i2o_pci.c	Mon Aug 27 12:41:41 2001
+++ linux/drivers/i2o/i2o_pci.c	Wed Dec 31 16:00:00 1969
@@ -1,377 +0,0 @@
-/*
- *	Find I2O capable controllers on the PCI bus, and register/install
- *	them with the I2O layer
- *
- *	(C) Copyright 1999   Red Hat Software
- *	
- *	Written by Alan Cox, Building Number Three Ltd
- * 	Modified by Deepak Saxena <deepak@plexity.net>
- * 	Modified by Boji T Kannanthanam <boji.t.kannanthanam@intel.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.
- *
- *	TODO:
- *		Support polled I2O PCI controllers. 
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/i2o.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-
-#ifdef CONFIG_MTRR
-#include <asm/mtrr.h>
-#endif // CONFIG_MTRR
-
-#ifdef MODULE
-/*
- * Core function table
- * See <include/linux/i2o.h> for an explanation
- */
-static struct i2o_core_func_table *core;
-
-/* Core attach function */
-extern int i2o_pci_core_attach(struct i2o_core_func_table *);
-extern void i2o_pci_core_detach(void);
-#endif /* MODULE */
-
-/*
- *	Free bus specific resources
- */
-static void i2o_pci_dispose(struct i2o_controller *c)
-{
-	I2O_IRQ_WRITE32(c,0xFFFFFFFF);
-	if(c->bus.pci.irq > 0)
-		free_irq(c->bus.pci.irq, c);
-	iounmap(((u8 *)c->post_port)-0x40);
-
-#ifdef CONFIG_MTRR
-	if(c->bus.pci.mtrr_reg0 > 0)
-		mtrr_del(c->bus.pci.mtrr_reg0, 0, 0);
-	if(c->bus.pci.mtrr_reg1 > 0)
-		mtrr_del(c->bus.pci.mtrr_reg1, 0, 0);
-#endif
-}
-
-/*
- *	No real bus specific handling yet (note that later we will
- *	need to 'steal' PCI devices on i960 mainboards)
- */
- 
-static int i2o_pci_bind(struct i2o_controller *c, struct i2o_device *dev)
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
-static int i2o_pci_unbind(struct i2o_controller *c, struct i2o_device *dev)
-{
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-/*
- * Bus specific enable/disable functions
- */
-static void i2o_pci_enable(struct i2o_controller *c)
-{
-	I2O_IRQ_WRITE32(c, 0);
-	c->enabled = 1;
-}
-
-static void i2o_pci_disable(struct i2o_controller *c)
-{
-	I2O_IRQ_WRITE32(c, 0xFFFFFFFF);
-	c->enabled = 0;
-}
-
-/*
- *	Bus specific interrupt handler
- */
- 
-static void i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r)
-{
-	struct i2o_controller *c = dev_id;
-#ifdef MODULE
-	core->run_queue(c);
-#else
-	i2o_run_queue(c);
-#endif /* MODULE */
-}	
-
-/*
- *	Install a PCI (or in theory AGP) i2o controller
- *
- * TODO: Add support for polled controllers
- */
-int __init i2o_pci_install(struct pci_dev *dev)
-{
-	struct i2o_controller *c=kmalloc(sizeof(struct i2o_controller),
-						GFP_KERNEL);
-	u8 *mem;
-	u32 memptr = 0;
-	u32 size;
-	
-	int i;
-
-	if(c==NULL)
-	{
-		printk(KERN_ERR "i2o: Insufficient memory to add controller.\n");
-		return -ENOMEM;
-	}
-	memset(c, 0, sizeof(*c));
-
-	for(i=0; i<6; i++)
-	{
-		/* Skip I/O spaces */
-		if(!(pci_resource_flags(dev, i) & IORESOURCE_IO))
-		{
-			memptr = pci_resource_start(dev, i);
-			break;
-		}
-	}
-	
-	if(i==6)
-	{
-		printk(KERN_ERR "i2o: I2O controller has no memory regions defined.\n");
-		kfree(c);
-		return -EINVAL;
-	}
-	
-	size = dev->resource[i].end-dev->resource[i].start+1;	
-	/* Map the I2O controller */
-	
-	printk(KERN_INFO "i2o: PCI I2O controller at 0x%08X size=%d\n", memptr, size);
-	mem = ioremap(memptr, size);
-	if(mem==NULL)
-	{
-		printk(KERN_ERR "i2o: Unable to map controller.\n");
-		kfree(c);
-		return -EINVAL;
-	}
-
-	c->bus.pci.irq = -1;
-	c->bus.pci.queue_buggy = 0;
-	c->bus.pci.dpt = 0;
-	c->bus.pci.short_req = 0;
-	c->bus.pci.pdev = dev;
-
-	c->irq_mask = (volatile u32 *)(mem+0x34);
-	c->post_port = (volatile u32 *)(mem+0x40);
-	c->reply_port = (volatile u32 *)(mem+0x44);
-
-	c->mem_phys = memptr;
-	c->mem_offset = (u32)mem;
-	c->destructor = i2o_pci_dispose;
-	
-	c->bind = i2o_pci_bind;
-	c->unbind = i2o_pci_unbind;
-	c->bus_enable = i2o_pci_enable;
-	c->bus_disable = i2o_pci_disable;
-	
-	c->type = I2O_TYPE_PCI;
-
-	/*
-	 *	Cards that fall apart if you hit them with large I/O
-	 *	loads...
-	 */
-	 
-	if(dev->vendor == PCI_VENDOR_ID_NCR && dev->device == 0x0630)
-	{
-		c->bus.pci.short_req=1;
-		printk(KERN_INFO "I2O: Symbios FC920 workarounds activated.\n");
-	}
-	if(dev->subsystem_vendor == PCI_VENDOR_ID_PROMISE)
-	{
-		c->bus.pci.queue_buggy=1;
-		printk(KERN_INFO "I2O: Promise workarounds activated.\n");
-	}
-
-	/*
-	 *	Cards that go bananas if you quiesce them before you reset
-	 *	them
-	 */
-	 
-	if(dev->vendor == PCI_VENDOR_ID_DPT)
-		c->bus.pci.dpt=1;
-	
-	/* 
-	 * Enable Write Combining MTRR for IOP's memory region
-	 */
-#ifdef CONFIG_MTRR
-	c->bus.pci.mtrr_reg0 =
-		mtrr_add(c->mem_phys, size, MTRR_TYPE_WRCOMB, 1);
-/*
-* If it is an INTEL i960 I/O processor then set the first 64K to Uncacheable
-* since the region contains the Messaging unit which shouldn't be cached.
-*/
-	c->bus.pci.mtrr_reg1 = -1;
-	if(dev->vendor == PCI_VENDOR_ID_INTEL || dev->vendor == PCI_VENDOR_ID_DPT)
-	{
-		printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); 
-		c->bus.pci.mtrr_reg1 =	mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1);
-		if(c->bus.pci.mtrr_reg1< 0)
-			printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n");
-	}
-
-#endif
-
-	I2O_IRQ_WRITE32(c,0xFFFFFFFF);
-
-#ifdef MODULE
-	i = core->install(c);
-#else
-	i = i2o_install_controller(c);
-#endif /* MODULE */
-	
-	if(i<0)
-	{
-		printk(KERN_ERR "i2o: Unable to install controller.\n");
-		kfree(c);
-		iounmap(mem);
-		return i;
-	}
-
-	c->bus.pci.irq = dev->irq;
-	if(c->bus.pci.irq)
-	{
-		i=request_irq(dev->irq, i2o_pci_interrupt, SA_SHIRQ,
-			c->name, c);
-		if(i<0)
-		{
-			printk(KERN_ERR "%s: unable to allocate interrupt %d.\n",
-				c->name, dev->irq);
-			c->bus.pci.irq = -1;
-#ifdef MODULE
-			core->delete(c);
-#else
-			i2o_delete_controller(c);
-#endif /* MODULE */	
-			iounmap(mem);
-			return -EBUSY;
-		}
-	}
-
-	printk(KERN_INFO "%s: Installed at IRQ%d\n", c->name, dev->irq);
-	I2O_IRQ_WRITE32(c,0x0);
-	c->enabled = 1;
-	return 0;	
-}
-
-int __init i2o_pci_scan(void)
-{
-	struct pci_dev *dev;
-	int count=0;
-	
-	printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
-
-	pci_for_each_dev(dev)	
-	{
-		if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O)
-			continue;
-		if((dev->class&0xFF)>1)
-		{
-			printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n");
-			continue;
-		}
-		if (pci_enable_device(dev))
-			continue;
-		printk(KERN_INFO "i2o: I2O controller on bus %d at %d.\n",
-			dev->bus->number, dev->devfn);
-		pci_set_master(dev);
-		if(i2o_pci_install(dev)==0)
-			count++;
-	}
-	if(count)
-		printk(KERN_INFO "i2o: %d I2O controller%s found and installed.\n", count,
-			count==1?"":"s");
-	return count?count:-ENODEV;
-}
-
-#ifdef I2O_HOTPLUG_SUPPORT
-/*
- * Activate a newly found PCI I2O controller
- * Not used now, but will be needed in future for
- * hot plug PCI support
- */
-static void i2o_pci_activate(i2o_controller * c)
-{
-	int i=0;
-	struct i2o_controller *c;
-	
-	if(c->type == I2O_TYPE_PCI)
-	{
-		I2O_IRQ_WRITE32(c,0);
-#ifdef MODULE
-		if(core->activate(c))
-#else
-		if(i2o_activate_controller(c))
-#endif /* MODULE */
-		{
-			printk("%s: Failed to initialize.\n", c->name);
-#ifdef MODULE
-			core->unlock(c);
-			core->delete(c);
-#else
-			i2o_unlock_controller(c);
-			i2o_delete_controller(c);
-#endif
-			continue;
-		}
-	}
-}
-#endif // I2O_HOTPLUG_SUPPORT
-
-#ifdef MODULE
-
-int i2o_pci_core_attach(struct i2o_core_func_table *table)
-{
-	MOD_INC_USE_COUNT;
-
-	core = table;
-
-	return i2o_pci_scan();
-}
-
-void i2o_pci_core_detach(void)
-{
-	core = NULL;
-
-	MOD_DEC_USE_COUNT;
-}
-
-int init_module(void)
-{
-	printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
-	
-	core = NULL;
-
- 	return 0;
- 
-}
-
-void cleanup_module(void)
-{
-}
-
-EXPORT_SYMBOL(i2o_pci_core_attach);
-EXPORT_SYMBOL(i2o_pci_core_detach);
-
-MODULE_AUTHOR("Red Hat Software");
-MODULE_DESCRIPTION("I2O PCI Interface");
-
-#else
-void __init i2o_pci_init(void)
-{
-	printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
-	i2o_pci_scan();
-}
-#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c
--- v2.4.12/linux/drivers/i2o/i2o_proc.c	Mon Aug 27 12:41:41 2001
+++ linux/drivers/i2o/i2o_proc.c	Wed Dec 31 16:00:00 1969
@@ -1,3379 +0,0 @@
-/*
- *   procfs handler for Linux I2O subsystem
- *
- *   (c) Copyright 1999 Deepak Saxena
- *   
- *   Originally written by Deepak Saxena(deepak@plexity.net)
- *
- *   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 is an initial test release. The code is based on the design
- *   of the ide procfs system (drivers/block/ide-proc.c). Some code
- *   taken from i2o-core module by Alan Cox.
- *
- *   DISCLAIMER: This code is still under development/test and may cause
- *   your system to behave unpredictably.  Use at your own discretion.
- *
- *   LAN entries by Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI),
- *		    Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI)
- *   University of Helsinki, Department of Computer Science
- */
-
-/*
- * set tabstop=3
- */
-
-/*
- * TODO List
- *
- * - Add support for any version 2.0 spec changes once 2.0 IRTOS is
- *   is available to test with
- * - Clean up code to use official structure definitions 
- */
-
-// FIXME!
-#define FMT_U64_HEX "0x%08x%08x"
-#define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64))
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/i2o.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/byteorder.h>
-
-#include "i2o_lan.h"
-
-/*
- * Structure used to define /proc entries
- */
-typedef struct _i2o_proc_entry_t
-{
-	char *name;			/* entry name */
-	mode_t mode;			/* mode */
-	read_proc_t *read_proc;		/* read func */
-	write_proc_t *write_proc;	/* write func */
-} i2o_proc_entry;
-
-// #define DRIVERDEBUG
-
-static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_status(char *, char **, off_t, int, int *, void *);
-
-static int i2o_proc_read_hw(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_ddm_table(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_driver_store(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_drivers_stored(char *, char **, off_t, int, int *, void *);
-
-static int i2o_proc_read_groups(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_phys_device(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_claimed(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_users(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_priv_msgs(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_authorized_users(char *, char **, off_t, int, int *, void *);
-
-static int i2o_proc_read_dev_name(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_dev_identity(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_ddm_identity(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_uinfo(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_sgl_limits(char *, char **, off_t, int, int *, void *);
-
-static int i2o_proc_read_sensors(char *, char **, off_t, int, int *, void *);
-
-static int print_serial_number(char *, int, u8 *, int);
-
-static int i2o_proc_create_entries(void *, i2o_proc_entry *,
-				   struct proc_dir_entry *);
-static void i2o_proc_remove_entries(i2o_proc_entry *, struct proc_dir_entry *);
-static int i2o_proc_add_controller(struct i2o_controller *, 
-				   struct proc_dir_entry * );
-static void i2o_proc_remove_controller(struct i2o_controller *, 
-				       struct proc_dir_entry * );
-static void i2o_proc_add_device(struct i2o_device *, struct proc_dir_entry *);
-static void i2o_proc_remove_device(struct i2o_device *);
-static int create_i2o_procfs(void);
-static int destroy_i2o_procfs(void);
-static void i2o_proc_new_dev(struct i2o_controller *, struct i2o_device *);
-static void i2o_proc_dev_del(struct i2o_controller *, struct i2o_device *);
-
-static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *,
-				      void *);
-static int i2o_proc_read_lan_mac_addr(char *, char **, off_t, int, int *,
-				      void *);
-static int i2o_proc_read_lan_mcast_addr(char *, char **, off_t, int, int *,
-					void *);
-static int i2o_proc_read_lan_batch_control(char *, char **, off_t, int, int *,
-					   void *);
-static int i2o_proc_read_lan_operation(char *, char **, off_t, int, int *,
-				       void *);
-static int i2o_proc_read_lan_media_operation(char *, char **, off_t, int,
-					     int *, void *);
-static int i2o_proc_read_lan_alt_addr(char *, char **, off_t, int, int *,
-				      void *);
-static int i2o_proc_read_lan_tx_info(char *, char **, off_t, int, int *,
-				     void *);
-static int i2o_proc_read_lan_rx_info(char *, char **, off_t, int, int *,
-				     void *);
-static int i2o_proc_read_lan_hist_stats(char *, char **, off_t, int, int *,
-					void *);
-static int i2o_proc_read_lan_eth_stats(char *, char **, off_t, int,
-				       int *, void *);
-static int i2o_proc_read_lan_tr_stats(char *, char **, off_t, int, int *,
-				      void *);
-static int i2o_proc_read_lan_fddi_stats(char *, char **, off_t, int, int *,
-					void *);
-
-static struct proc_dir_entry *i2o_proc_dir_root;
-
-/*
- * I2O OSM descriptor
- */
-static struct i2o_handler i2o_proc_handler =
-{
-	NULL,
-	i2o_proc_new_dev,
-	i2o_proc_dev_del,
-	NULL,
-	"I2O procfs Layer",
-	0,
-	0xffffffff	// All classes
-};
-
-/*
- * IOP specific entries...write field just in case someone 
- * ever wants one.
- */
-static i2o_proc_entry generic_iop_entries[] = 
-{
-	{"hrt", S_IFREG|S_IRUGO, i2o_proc_read_hrt, NULL},
-	{"lct", S_IFREG|S_IRUGO, i2o_proc_read_lct, NULL},
-	{"status", S_IFREG|S_IRUGO, i2o_proc_read_status, NULL},
-	{"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL},
-	{"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, NULL},
-	{"driver_store", S_IFREG|S_IRUGO, i2o_proc_read_driver_store, NULL},
-	{"drivers_stored", S_IFREG|S_IRUGO, i2o_proc_read_drivers_stored, NULL},
-	{NULL, 0, NULL, NULL}
-};
-
-/*
- * Device specific entries
- */
-static i2o_proc_entry generic_dev_entries[] = 
-{
-	{"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL},
-	{"phys_dev", S_IFREG|S_IRUGO, i2o_proc_read_phys_device, NULL},
-	{"claimed", S_IFREG|S_IRUGO, i2o_proc_read_claimed, NULL},
-	{"users", S_IFREG|S_IRUGO, i2o_proc_read_users, NULL},
-	{"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, NULL},
-	{"authorized_users", S_IFREG|S_IRUGO, i2o_proc_read_authorized_users, NULL},
-	{"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev_identity, NULL},
-	{"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm_identity, NULL},
-	{"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL},
-	{"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL},
-	{"sensors", S_IFREG|S_IRUGO, i2o_proc_read_sensors, NULL},
-	{NULL, 0, NULL, NULL}
-};
-
-/*
- *  Storage unit specific entries (SCSI Periph, BS) with device names
- */
-static i2o_proc_entry rbs_dev_entries[] = 
-{
-	{"dev_name", S_IFREG|S_IRUGO, i2o_proc_read_dev_name, NULL},
-	{NULL, 0, NULL, NULL}
-};
-
-#define SCSI_TABLE_SIZE	13
-static char *scsi_devices[] = 
-{
-	"Direct-Access Read/Write",
-	"Sequential-Access Storage",
-	"Printer",
-	"Processor",
-	"WORM Device",
-	"CD-ROM Device",
-	"Scanner Device",
-	"Optical Memory Device",
-	"Medium Changer Device",
-	"Communications Device",
-	"Graphics Art Pre-Press Device",
-	"Graphics Art Pre-Press Device",
-	"Array Controller Device"
-};
-
-/* private */
-
-/*
- * Generic LAN specific entries
- * 
- * Should groups with r/w entries have their own subdirectory?
- *
- */
-static i2o_proc_entry lan_entries[] = 
-{
-	{"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL},
-	{"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL},
-	{"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR,
-	 i2o_proc_read_lan_mcast_addr, NULL},
-	{"lan_batch_ctrl", S_IFREG|S_IRUGO|S_IWUSR,
-	 i2o_proc_read_lan_batch_control, NULL},
-	{"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL},
-	{"lan_media_operation", S_IFREG|S_IRUGO,
-	 i2o_proc_read_lan_media_operation, NULL},
-	{"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL},
-	{"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL},
-	{"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL},
-
-	{"lan_hist_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL},
-	{NULL, 0, NULL, NULL}
-};
-
-/*
- * Port specific LAN entries
- * 
- */
-static i2o_proc_entry lan_eth_entries[] = 
-{
-	{"lan_eth_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL},
-	{NULL, 0, NULL, NULL}
-};
-
-static i2o_proc_entry lan_tr_entries[] = 
-{
-	{"lan_tr_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_tr_stats, NULL},
-	{NULL, 0, NULL, NULL}
-};
-
-static i2o_proc_entry lan_fddi_entries[] = 
-{
-	{"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL},
-	{NULL, 0, NULL, NULL}
-};
-
-
-static char *chtostr(u8 *chars, int n)
-{
-	char tmp[256];
-	tmp[0] = 0;
-        return strncat(tmp, (char *)chars, n);
-}
-
-static int i2o_report_query_status(char *buf, int block_status, char *group)
-{
-	switch (block_status)
-	{
-	case -ETIMEDOUT:
-		return sprintf(buf, "Timeout reading group %s.\n",group);
-	case -ENOMEM:
-		return sprintf(buf, "No free memory to read the table.\n");
-	case -I2O_PARAMS_STATUS_INVALID_GROUP_ID:
-		return sprintf(buf, "Group %s not supported.\n", group);
-	default:
-		return sprintf(buf, "Error reading group %s. BlockStatus 0x%02X\n",
-			       group, -block_status);
-	}
-}
-
-static char* bus_strings[] = 
-{ 
-	"Local Bus", 
-	"ISA", 
-	"EISA", 
-	"MCA", 
-	"PCI",
-	"PCMCIA", 
-	"NUBUS", 
-	"CARDBUS"
-};
-
-static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED;
-
-int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len, 
-		      int *eof, void *data)
-{
-	struct i2o_controller *c = (struct i2o_controller *)data;
-	i2o_hrt *hrt = (i2o_hrt *)c->hrt;
-	u32 bus;
-	int count;
-	int i;
-
-	spin_lock(&i2o_proc_lock);
-
-	len = 0;
-
-	if(hrt->hrt_version)
-	{
-		len += sprintf(buf+len, 
-			       "HRT table for controller is too new a version.\n");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	count = hrt->num_entries;
-
-	if((count * hrt->entry_len + 8) > 2048) {
-		printk(KERN_WARNING "i2o_proc: HRT does not fit into buffer\n");
-		len += sprintf(buf+len,
-			       "HRT table too big to fit in buffer.\n");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-	
-	len += sprintf(buf+len, "HRT has %d entries of %d bytes each.\n",
-		       count, hrt->entry_len << 2);
-
-	for(i = 0; i < count; i++)
-	{
-		len += sprintf(buf+len, "Entry %d:\n", i);
-		len += sprintf(buf+len, "   Adapter ID: %0#10x\n", 
-					hrt->hrt_entry[i].adapter_id);
-		len += sprintf(buf+len, "   Controlling tid: %0#6x\n",
-					hrt->hrt_entry[i].parent_tid);
-
-		if(hrt->hrt_entry[i].bus_type != 0x80)
-		{
-			bus = hrt->hrt_entry[i].bus_type;
-			len += sprintf(buf+len, "   %s Information\n", bus_strings[bus]);
-
-			switch(bus)
-			{
-				case I2O_BUS_LOCAL:
-					len += sprintf(buf+len, "     IOBase: %0#6x,",
-								hrt->hrt_entry[i].bus.local_bus.LbBaseIOPort);
-					len += sprintf(buf+len, " MemoryBase: %0#10x\n",
-								hrt->hrt_entry[i].bus.local_bus.LbBaseMemoryAddress);
-					break;
-
-				case I2O_BUS_ISA:
-					len += sprintf(buf+len, "     IOBase: %0#6x,",
-								hrt->hrt_entry[i].bus.isa_bus.IsaBaseIOPort);
-					len += sprintf(buf+len, " MemoryBase: %0#10x,",
-								hrt->hrt_entry[i].bus.isa_bus.IsaBaseMemoryAddress);
-					len += sprintf(buf+len, " CSN: %0#4x,",
-								hrt->hrt_entry[i].bus.isa_bus.CSN);
-					break;
-
-				case I2O_BUS_EISA:
-					len += sprintf(buf+len, "     IOBase: %0#6x,",
-								hrt->hrt_entry[i].bus.eisa_bus.EisaBaseIOPort);
-					len += sprintf(buf+len, " MemoryBase: %0#10x,",
-								hrt->hrt_entry[i].bus.eisa_bus.EisaBaseMemoryAddress);
-					len += sprintf(buf+len, " Slot: %0#4x,",
-								hrt->hrt_entry[i].bus.eisa_bus.EisaSlotNumber);
-					break;
-			 
-				case I2O_BUS_MCA:
-					len += sprintf(buf+len, "     IOBase: %0#6x,",
-								hrt->hrt_entry[i].bus.mca_bus.McaBaseIOPort);
-					len += sprintf(buf+len, " MemoryBase: %0#10x,",
-								hrt->hrt_entry[i].bus.mca_bus.McaBaseMemoryAddress);
-					len += sprintf(buf+len, " Slot: %0#4x,",
-								hrt->hrt_entry[i].bus.mca_bus.McaSlotNumber);
-					break;
-
-				case I2O_BUS_PCI:
-					len += sprintf(buf+len, "     Bus: %0#4x",
-								hrt->hrt_entry[i].bus.pci_bus.PciBusNumber);
-					len += sprintf(buf+len, " Dev: %0#4x",
-								hrt->hrt_entry[i].bus.pci_bus.PciDeviceNumber);
-					len += sprintf(buf+len, " Func: %0#4x",
-								hrt->hrt_entry[i].bus.pci_bus.PciFunctionNumber);
-					len += sprintf(buf+len, " Vendor: %0#6x",
-								hrt->hrt_entry[i].bus.pci_bus.PciVendorID);
-					len += sprintf(buf+len, " Device: %0#6x\n",
-								hrt->hrt_entry[i].bus.pci_bus.PciDeviceID);
-					break;
-
-				default:
-					len += sprintf(buf+len, "      Unsupported Bus Type\n");
-			}
-		}
-		else
-			len += sprintf(buf+len, "   Unknown Bus Type\n");
-	}
-
-	spin_unlock(&i2o_proc_lock);
-	
-	return len;
-}
-
-int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
-	int *eof, void *data)
-{
-	struct i2o_controller *c = (struct i2o_controller*)data;
-	i2o_lct *lct = (i2o_lct *)c->lct;
-	int entries;
-	int i;
-
-#define BUS_TABLE_SIZE 3
-	static char *bus_ports[] =
-	{
-		"Generic Bus",
-		"SCSI Bus",
-		"Fibre Channel Bus"
-	};
-
-	spin_lock(&i2o_proc_lock);
-	len = 0;
-
-	entries = (lct->table_size - 3)/9;
-
-	len += sprintf(buf, "LCT contains %d %s\n", entries,
-						entries == 1 ? "entry" : "entries");
-	if(lct->boot_tid)	
-		len += sprintf(buf+len, "Boot Device @ ID %d\n", lct->boot_tid);
-
-	len += 
-		sprintf(buf+len, "Current Change Indicator: %#10x\n", lct->change_ind);
-
-	for(i = 0; i < entries; i++)
-	{
-		len += sprintf(buf+len, "Entry %d\n", i);
-		len += sprintf(buf+len, "  Class, SubClass  : %s", i2o_get_class_name(lct->lct_entry[i].class_id));
-	
-		/*
-		 *	Classes which we'll print subclass info for
-		 */
-		switch(lct->lct_entry[i].class_id & 0xFFF)
-		{
-			case I2O_CLASS_RANDOM_BLOCK_STORAGE:
-				switch(lct->lct_entry[i].sub_class)
-				{
-					case 0x00:
-						len += sprintf(buf+len, ", Direct-Access Read/Write");
-						break;
-
-					case 0x04:
-						len += sprintf(buf+len, ", WORM Drive");
-						break;
-	
-					case 0x05:
-						len += sprintf(buf+len, ", CD-ROM Drive");
-						break;
-
-					case 0x07:
-						len += sprintf(buf+len, ", Optical Memory Device");
-						break;
-
-					default:
-						len += sprintf(buf+len, ", Unknown (0x%02x)",
-							       lct->lct_entry[i].sub_class);
-						break;
-				}
-				break;
-
-			case I2O_CLASS_LAN:
-				switch(lct->lct_entry[i].sub_class & 0xFF)
-				{
-					case 0x30:
-						len += sprintf(buf+len, ", Ethernet");
-						break;
-
-					case 0x40:
-						len += sprintf(buf+len, ", 100base VG");
-						break;
-
-					case 0x50:
-						len += sprintf(buf+len, ", IEEE 802.5/Token-Ring");
-						break;
-
-					case 0x60:
-						len += sprintf(buf+len, ", ANSI X3T9.5 FDDI");
-						break;
-		
-					case 0x70:
-						len += sprintf(buf+len, ", Fibre Channel");
-						break;
-
-					default:
-						len += sprintf(buf+len, ", Unknown Sub-Class (0x%02x)",
-							       lct->lct_entry[i].sub_class & 0xFF);
-						break;
-				}
-				break;
-
-			case I2O_CLASS_SCSI_PERIPHERAL:
-				if(lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE)
-					len += sprintf(buf+len, ", %s", 
-								scsi_devices[lct->lct_entry[i].sub_class]);
-				else
-					len += sprintf(buf+len, ", Unknown Device Type");
-				break;
-
-			case I2O_CLASS_BUS_ADAPTER_PORT:
-				if(lct->lct_entry[i].sub_class < BUS_TABLE_SIZE)
-					len += sprintf(buf+len, ", %s", 
-								bus_ports[lct->lct_entry[i].sub_class]);
-				else
-					len += sprintf(buf+len, ", Unknown Bus Type");
-				break;
-		}
-		len += sprintf(buf+len, "\n");
-		
-		len += sprintf(buf+len, "  Local TID        : 0x%03x\n", lct->lct_entry[i].tid);
-		len += sprintf(buf+len, "  User TID         : 0x%03x\n", lct->lct_entry[i].user_tid);
-		len += sprintf(buf+len, "  Parent TID       : 0x%03x\n", 
-					lct->lct_entry[i].parent_tid);
-		len += sprintf(buf+len, "  Identity Tag     : 0x%x%x%x%x%x%x%x%x\n",
-					lct->lct_entry[i].identity_tag[0],
-					lct->lct_entry[i].identity_tag[1],
-					lct->lct_entry[i].identity_tag[2],
-					lct->lct_entry[i].identity_tag[3],
-					lct->lct_entry[i].identity_tag[4],
-					lct->lct_entry[i].identity_tag[5],
-					lct->lct_entry[i].identity_tag[6],
-					lct->lct_entry[i].identity_tag[7]);
-		len += sprintf(buf+len, "  Change Indicator : %0#10x\n", 
-				lct->lct_entry[i].change_ind);
-		len += sprintf(buf+len, "  Event Capab Mask : %0#10x\n", 
-				lct->lct_entry[i].device_flags);
-	}
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-int i2o_proc_read_status(char *buf, char **start, off_t offset, int len, 
-			 int *eof, void *data)
-{
-	struct i2o_controller *c = (struct i2o_controller*)data;
-	char prodstr[25];
-	int version;
-	
-	spin_lock(&i2o_proc_lock);
-	len = 0;
-
-	i2o_status_get(c); // reread the status block
-
-	len += sprintf(buf+len,"Organization ID        : %0#6x\n", 
-				c->status_block->org_id);
-
-	version = c->status_block->i2o_version;
-	
-/* FIXME for Spec 2.0
-	if (version == 0x02) {
-		len += sprintf(buf+len,"Lowest I2O version supported: ");
-		switch(workspace[2]) {
-			case 0x00:
-				len += sprintf(buf+len,"1.0\n");
-				break;
-			case 0x01:
-				len += sprintf(buf+len,"1.5\n");
-				break;
-			case 0x02:
-				len += sprintf(buf+len,"2.0\n");
-				break;
-		}
-
-		len += sprintf(buf+len, "Highest I2O version supported: ");
-		switch(workspace[3]) {
-			case 0x00:
-				len += sprintf(buf+len,"1.0\n");
-				break;
-			case 0x01:
-				len += sprintf(buf+len,"1.5\n");
-				break;
-			case 0x02:
-				len += sprintf(buf+len,"2.0\n");
-				break;
-		}
-	}
-*/
-	len += sprintf(buf+len,"IOP ID                 : %0#5x\n", 
-				c->status_block->iop_id);
-	len += sprintf(buf+len,"Host Unit ID           : %0#6x\n",
-				c->status_block->host_unit_id);
-	len += sprintf(buf+len,"Segment Number         : %0#5x\n",
-				c->status_block->segment_number);
-
-	len += sprintf(buf+len, "I2O version            : ");
-	switch (version) {
-		case 0x00:
-			len += sprintf(buf+len,"1.0\n");
-			break;
-		case 0x01:
-			len += sprintf(buf+len,"1.5\n");
-			break;
-		case 0x02:
-			len += sprintf(buf+len,"2.0\n");
-			break;
-		default:
-			len += sprintf(buf+len,"Unknown version\n");
-	}
-
-	len += sprintf(buf+len, "IOP State              : ");
-	switch (c->status_block->iop_state) {
-		case 0x01:
-			len += sprintf(buf+len,"INIT\n");
-			break;
-
-		case 0x02:
-			len += sprintf(buf+len,"RESET\n");
-			break;
-
-		case 0x04:
-			len += sprintf(buf+len,"HOLD\n");
-			break;
-
-		case 0x05:
-			len += sprintf(buf+len,"READY\n");
-			break;
-
-		case 0x08:
-			len += sprintf(buf+len,"OPERATIONAL\n");
-			break;
-
-		case 0x10:
-			len += sprintf(buf+len,"FAILED\n");
-			break;
-
-		case 0x11:
-			len += sprintf(buf+len,"FAULTED\n");
-			break;
-
-		default:
-			len += sprintf(buf+len,"Unknown\n");
-			break;
-	}
-
-	len += sprintf(buf+len,"Messenger Type         : ");
-	switch (c->status_block->msg_type) { 
-		case 0x00:
-			len += sprintf(buf+len,"Memory mapped\n");
-			break;
-		case 0x01:
-			len += sprintf(buf+len,"Memory mapped only\n");
-			break;
-		case 0x02:
-			len += sprintf(buf+len,"Remote only\n");
-			break;
-		case 0x03:
-			len += sprintf(buf+len,"Memory mapped and remote\n");
-			break;
-		default:
-			len += sprintf(buf+len,"Unknown\n");
-	}
-
-	len += sprintf(buf+len,"Inbound Frame Size     : %d bytes\n", 
-				c->status_block->inbound_frame_size<<2);
-	len += sprintf(buf+len,"Max Inbound Frames     : %d\n", 
-				c->status_block->max_inbound_frames);
-	len += sprintf(buf+len,"Current Inbound Frames : %d\n", 
-				c->status_block->cur_inbound_frames);
-	len += sprintf(buf+len,"Max Outbound Frames    : %d\n", 
-				c->status_block->max_outbound_frames);
-
-	/* Spec doesn't say if NULL terminated or not... */
-	memcpy(prodstr, c->status_block->product_id, 24);
-	prodstr[24] = '\0';
-	len += sprintf(buf+len,"Product ID             : %s\n", prodstr);
-	len += sprintf(buf+len,"Expected LCT Size      : %d bytes\n", 
-				c->status_block->expected_lct_size);
-
-	len += sprintf(buf+len,"IOP Capabilities\n");
-	len += sprintf(buf+len,"    Context Field Size Support : ");
-	switch (c->status_block->iop_capabilities & 0x0000003) {
-		case 0:
-			len += sprintf(buf+len,"Supports only 32-bit context fields\n");
-			break;
-		case 1:
-			len += sprintf(buf+len,"Supports only 64-bit context fields\n");
-			break;
-		case 2:
-			len += sprintf(buf+len,"Supports 32-bit and 64-bit context fields, "
-						"but not concurrently\n");
-			break;
-		case 3:
-			len += sprintf(buf+len,"Supports 32-bit and 64-bit context fields "
-						"concurrently\n");
-			break;
-		default:
-			len += sprintf(buf+len,"0x%08x\n",c->status_block->iop_capabilities);
-	}
-	len += sprintf(buf+len,"    Current Context Field Size : ");
-	switch (c->status_block->iop_capabilities & 0x0000000C) {
-		case 0:
-			len += sprintf(buf+len,"not configured\n");
-			break;
-		case 4:
-			len += sprintf(buf+len,"Supports only 32-bit context fields\n");
-			break;
-		case 8:
-			len += sprintf(buf+len,"Supports only 64-bit context fields\n");
-			break;
-		case 12:
-			len += sprintf(buf+len,"Supports both 32-bit or 64-bit context fields "
-						"concurrently\n");
-			break;
-		default:
-			len += sprintf(buf+len,"\n");
-	}
-	len += sprintf(buf+len,"    Inbound Peer Support       : %s\n",
-			(c->status_block->iop_capabilities & 0x00000010) ? "Supported" : "Not supported");
-	len += sprintf(buf+len,"    Outbound Peer Support      : %s\n",
-			(c->status_block->iop_capabilities & 0x00000020) ? "Supported" : "Not supported");
-	len += sprintf(buf+len,"    Peer to Peer Support       : %s\n",
-			(c->status_block->iop_capabilities & 0x00000040) ? "Supported" : "Not supported");
-
-	len += sprintf(buf+len, "Desired private memory size   : %d kB\n", 
-				c->status_block->desired_mem_size>>10);
-	len += sprintf(buf+len, "Allocated private memory size : %d kB\n", 
-				c->status_block->current_mem_size>>10);
-	len += sprintf(buf+len, "Private memory base address   : %0#10x\n", 
-				c->status_block->current_mem_base);
-	len += sprintf(buf+len, "Desired private I/O size      : %d kB\n", 
-				c->status_block->desired_io_size>>10);
-	len += sprintf(buf+len, "Allocated private I/O size    : %d kB\n", 
-				c->status_block->current_io_size>>10);
-	len += sprintf(buf+len, "Private I/O base address      : %0#10x\n", 
-				c->status_block->current_io_base);
-
-	spin_unlock(&i2o_proc_lock);
-
-	return len;
-}
-
-int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, 
-		     int *eof, void *data)
-{
-	struct i2o_controller *c = (struct i2o_controller*)data;
-	static u32 work32[5];
-	static u8 *work8 = (u8*)work32;
-	static u16 *work16 = (u16*)work32;
-	int token;
-	u32 hwcap;
-
-	static char *cpu_table[] =
-	{
-		"Intel 80960 series",
-		"AMD2900 series",
-		"Motorola 68000 series",
-		"ARM series",
-		"MIPS series",
-		"Sparc series",
-		"PowerPC series",
-		"Intel x86 series"
-	};
-
-	spin_lock(&i2o_proc_lock);
-
-	len = 0;
-
-	token = i2o_query_scalar(c, ADAPTER_TID, 0x0000, -1, &work32, sizeof(work32));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0000 IOP Hardware");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf+len, "I2O Vendor ID    : %0#6x\n", work16[0]);
-	len += sprintf(buf+len, "Product ID       : %0#6x\n", work16[1]);
-	len += sprintf(buf+len, "CPU              : ");
-	if(work8[16] > 8)
-		len += sprintf(buf+len, "Unknown\n");
-	else
-		len += sprintf(buf+len, "%s\n", cpu_table[work8[16]]);
-	/* Anyone using ProcessorVersion? */
-	
-	len += sprintf(buf+len, "RAM              : %dkB\n", work32[1]>>10);
-	len += sprintf(buf+len, "Non-Volatile Mem : %dkB\n", work32[2]>>10);
-
-	hwcap = work32[3];
-	len += sprintf(buf+len, "Capabilities : 0x%08x\n", hwcap);
-	len += sprintf(buf+len, "   [%s] Self booting\n",
-			(hwcap&0x00000001) ? "+" : "-");
-	len += sprintf(buf+len, "   [%s] Upgradable IRTOS\n",
-			(hwcap&0x00000002) ? "+" : "-");
-	len += sprintf(buf+len, "   [%s] Supports downloading DDMs\n",
-			(hwcap&0x00000004) ? "+" : "-");
-	len += sprintf(buf+len, "   [%s] Supports installing DDMs\n",
-			(hwcap&0x00000008) ? "+" : "-");
-	len += sprintf(buf+len, "   [%s] Battery-backed RAM\n",
-			(hwcap&0x00000010) ? "+" : "-");
-
-	spin_unlock(&i2o_proc_lock);
-
-	return len;
-}
-
-
-/* Executive group 0003h - Executing DDM List (table) */
-int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len, 
-			    int *eof, void *data)
-{
-	struct i2o_controller *c = (struct i2o_controller*)data;
-	int token;
-	int i;
-
-	typedef struct _i2o_exec_execute_ddm_table {
-		u16 ddm_tid;
-		u8  module_type;
-		u8  reserved;
-		u16 i2o_vendor_id;
-		u16 module_id;
-		u8  module_name_version[28];
-		u32 data_size;
-		u32 code_size;
-	} i2o_exec_execute_ddm_table;
-
-	struct
-	{
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8  block_status;
-		u8  error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		i2o_exec_execute_ddm_table ddm_table[MAX_I2O_MODULES];
-	} result;
-
-	i2o_exec_execute_ddm_table ddm_table;
-
-	spin_lock(&i2o_proc_lock);
-	len = 0;
-
-	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				c, ADAPTER_TID, 
-				0x0003, -1,
-				NULL, 0,
-				&result, sizeof(result));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0003 Executing DDM List");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf+len, "Tid   Module_type     Vendor Mod_id  Module_name             Vrs  Data_size Code_size\n");
-	ddm_table=result.ddm_table[0];
-
-	for(i=0; i < result.row_count; ddm_table=result.ddm_table[++i])
-	{
-		len += sprintf(buf+len, "0x%03x ", ddm_table.ddm_tid & 0xFFF);
-
-		switch(ddm_table.module_type)
-		{
-		case 0x01:
-			len += sprintf(buf+len, "Downloaded DDM  ");
-			break;			
-		case 0x22:
-			len += sprintf(buf+len, "Embedded DDM    ");
-			break;
-		default:
-			len += sprintf(buf+len, "                ");
-		}
-
-		len += sprintf(buf+len, "%-#7x", ddm_table.i2o_vendor_id);
-		len += sprintf(buf+len, "%-#8x", ddm_table.module_id);
-		len += sprintf(buf+len, "%-29s", chtostr(ddm_table.module_name_version, 28));
-		len += sprintf(buf+len, "%9d  ", ddm_table.data_size);
-		len += sprintf(buf+len, "%8d", ddm_table.code_size);
-
-		len += sprintf(buf+len, "\n");
-	}
-
-	spin_unlock(&i2o_proc_lock);
-
-	return len;
-}
-
-
-/* Executive group 0004h - Driver Store (scalar) */
-int i2o_proc_read_driver_store(char *buf, char **start, off_t offset, int len, 
-		     int *eof, void *data)
-{
-	struct i2o_controller *c = (struct i2o_controller*)data;
-	u32 work32[8];
-	int token;
-
-	spin_lock(&i2o_proc_lock);
-
-	len = 0;
-
-	token = i2o_query_scalar(c, ADAPTER_TID, 0x0004, -1, &work32, sizeof(work32));
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0004 Driver Store");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf+len, "Module limit  : %d\n"
-				"Module count  : %d\n"
-				"Current space : %d kB\n"
-				"Free space    : %d kB\n", 
-			work32[0], work32[1], work32[2]>>10, work32[3]>>10);
-
-	spin_unlock(&i2o_proc_lock);
-
-	return len;
-}
-
-
-/* Executive group 0005h - Driver Store Table (table) */
-int i2o_proc_read_drivers_stored(char *buf, char **start, off_t offset,
-				 int len, int *eof, void *data)
-{
-	typedef struct _i2o_driver_store {
-		u16 stored_ddm_index;
-		u8  module_type;
-		u8  reserved;
-		u16 i2o_vendor_id;
-		u16 module_id;
-		u8  module_name_version[28];
-		u8  date[8];
-		u32 module_size;
-		u32 mpb_size;
-		u32 module_flags;
-	} i2o_driver_store_table;
-
-	struct i2o_controller *c = (struct i2o_controller*)data;
-	int token;
-	int i;
-
-	typedef struct
-	{
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8  block_status;
-		u8  error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		i2o_driver_store_table dst[MAX_I2O_MODULES];
-	} i2o_driver_result_table;
-	
-	i2o_driver_result_table *result;
-	i2o_driver_store_table *dst;
-
-	spin_lock(&i2o_proc_lock);
-
-	len = 0;
-	
-	result = kmalloc(sizeof(i2o_driver_result_table), GFP_KERNEL);
-	if(result == NULL)
-		return -ENOMEM;
-
-	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				c, ADAPTER_TID, 0x0005, -1, NULL, 0, 
-				result, sizeof(*result));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0005 DRIVER STORE TABLE");
-		spin_unlock(&i2o_proc_lock);
-		kfree(result);
-		return len;
-	}
-
-	len += sprintf(buf+len, "#  Module_type     Vendor Mod_id  Module_name             Vrs"  
-				"Date     Mod_size Par_size Flags\n");
-	for(i=0, dst=&result->dst[0]; i < result->row_count; dst=&result->dst[++i])
-	{
-		len += sprintf(buf+len, "%-3d", dst->stored_ddm_index);
-		switch(dst->module_type)
-		{
-		case 0x01:
-			len += sprintf(buf+len, "Downloaded DDM  ");
-			break;			
-		case 0x22:
-			len += sprintf(buf+len, "Embedded DDM    ");
-			break;
-		default:
-			len += sprintf(buf+len, "                ");
-		}
-
-#if 0
-		if(c->i2oversion == 0x02)
-			len += sprintf(buf+len, "%-d", dst->module_state);
-#endif
-
-		len += sprintf(buf+len, "%-#7x", dst->i2o_vendor_id);
-		len += sprintf(buf+len, "%-#8x", dst->module_id);
-		len += sprintf(buf+len, "%-29s", chtostr(dst->module_name_version,28));
-		len += sprintf(buf+len, "%-9s", chtostr(dst->date,8));
-		len += sprintf(buf+len, "%8d ", dst->module_size);
-		len += sprintf(buf+len, "%8d ", dst->mpb_size);
-		len += sprintf(buf+len, "0x%04x", dst->module_flags);
-#if 0
-		if(c->i2oversion == 0x02)
-			len += sprintf(buf+len, "%d",
-				       dst->notification_level);
-#endif
-		len += sprintf(buf+len, "\n");
-	}
-
-	spin_unlock(&i2o_proc_lock);
-	kfree(result);
-	return len;
-}
-
-
-/* Generic group F000h - Params Descriptor (table) */
-int i2o_proc_read_groups(char *buf, char **start, off_t offset, int len, 
-			 int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-	int i;
-	u8 properties;
-
-	typedef struct _i2o_group_info
-	{
-		u16 group_number;
-		u16 field_count;
-		u16 row_count;
-		u8  properties;
-		u8  reserved;
-	} i2o_group_info;
-
-	struct
-	{
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8  block_status;
-		u8  error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		i2o_group_info group[256];
-	} result;
-
-	spin_lock(&i2o_proc_lock);
-
-	len = 0;
-
-	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data.tid, 0xF000, -1, NULL, 0,
-				&result, sizeof(result));
-
-	if (token < 0) {
-		len = i2o_report_query_status(buf+len, token, "0xF000 Params Descriptor");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf+len, "#  Group   FieldCount RowCount Type   Add Del Clear\n");
-
-	for (i=0; i < result.row_count; i++)
-	{
-		len += sprintf(buf+len, "%-3d", i);
-		len += sprintf(buf+len, "0x%04X ", result.group[i].group_number);
-		len += sprintf(buf+len, "%10d ", result.group[i].field_count);
-		len += sprintf(buf+len, "%8d ",  result.group[i].row_count);
-
-		properties = result.group[i].properties;
-		if (properties & 0x1)	len += sprintf(buf+len, "Table  ");
-				else	len += sprintf(buf+len, "Scalar ");
-		if (properties & 0x2)	len += sprintf(buf+len, " + ");
-				else	len += sprintf(buf+len, " - ");
-		if (properties & 0x4)	len += sprintf(buf+len, "  + ");
-				else	len += sprintf(buf+len, "  - ");
-		if (properties & 0x8)	len += sprintf(buf+len, "  + ");
-				else	len += sprintf(buf+len, "  - ");
-
-		len += sprintf(buf+len, "\n");
-	}
-
-	if (result.more_flag)
-		len += sprintf(buf+len, "There is more...\n");
-
-	spin_unlock(&i2o_proc_lock);
-
-	return len;
-}
-
-
-/* Generic group F001h - Physical Device Table (table) */
-int i2o_proc_read_phys_device(char *buf, char **start, off_t offset, int len,
-			      int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-	int i;
-
-	struct
-	{
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8  block_status;
-		u8  error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		u32 adapter_id[64];
-	} result;
-
-	spin_lock(&i2o_proc_lock);
-	len = 0;
-
-	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data.tid,
-				0xF001, -1, NULL, 0,
-				&result, sizeof(result));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0xF001 Physical Device Table");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	if (result.row_count)
-		len += sprintf(buf+len, "#  AdapterId\n");
-
-	for (i=0; i < result.row_count; i++)
-	{
-		len += sprintf(buf+len, "%-2d", i);
-		len += sprintf(buf+len, "%#7x\n", result.adapter_id[i]);
-	}
-
-	if (result.more_flag)
-		len += sprintf(buf+len, "There is more...\n");
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* Generic group F002h - Claimed Table (table) */
-int i2o_proc_read_claimed(char *buf, char **start, off_t offset, int len,
-			  int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-	int i;
-
-	struct {
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8  block_status;
-		u8  error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		u16 claimed_tid[64];
-	} result;
-
-	spin_lock(&i2o_proc_lock);
-	len = 0;
-
-	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data.tid,
-				0xF002, -1, NULL, 0,
-				&result, sizeof(result));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0xF002 Claimed Table");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	if (result.row_count)
-		len += sprintf(buf+len, "#  ClaimedTid\n");
-
-	for (i=0; i < result.row_count; i++)
-	{
-		len += sprintf(buf+len, "%-2d", i);
-		len += sprintf(buf+len, "%#7x\n", result.claimed_tid[i]);
-	}
-
-	if (result.more_flag)
-		len += sprintf(buf+len, "There is more...\n");
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* Generic group F003h - User Table (table) */
-int i2o_proc_read_users(char *buf, char **start, off_t offset, int len,
-			int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-	int i;
-
-	typedef struct _i2o_user_table
-	{
-		u16 instance;
-		u16 user_tid;
-		u8 claim_type;
-		u8  reserved1;
-		u16  reserved2;
-	} i2o_user_table;
-
-	struct
-	{
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8  block_status;
-		u8  error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		i2o_user_table user[64];
-	} result;
-
-	spin_lock(&i2o_proc_lock);
-	len = 0;
-
-	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data.tid,
-				0xF003, -1, NULL, 0,
-				&result, sizeof(result));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0xF003 User Table");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf+len, "#  Instance UserTid ClaimType\n");
-
-	for(i=0; i < result.row_count; i++)
-	{
-		len += sprintf(buf+len, "%-3d", i);
-		len += sprintf(buf+len, "%#8x ", result.user[i].instance);
-		len += sprintf(buf+len, "%#7x ", result.user[i].user_tid);
-		len += sprintf(buf+len, "%#9x\n", result.user[i].claim_type);
-	}
-
-	if (result.more_flag)
-		len += sprintf(buf+len, "There is more...\n");
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* Generic group F005h - Private message extensions (table) (optional) */
-int i2o_proc_read_priv_msgs(char *buf, char **start, off_t offset, int len, 
-			    int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-	int i;
-
-	typedef struct _i2o_private
-	{
-		u16 ext_instance;
-		u16 organization_id;
-		u16 x_function_code;
-	} i2o_private;
-
-	struct
-	{
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8  block_status;
-		u8  error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		i2o_private extension[64];
-	} result;
-
-	spin_lock(&i2o_proc_lock);
-
-	len = 0;
-
-	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data.tid,
-				0xF000, -1,
-				NULL, 0,
-				&result, sizeof(result));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0xF005 Private Message Extensions (optional)");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-	
-	len += sprintf(buf+len, "Instance#  OrgId  FunctionCode\n");
-
-	for(i=0; i < result.row_count; i++)
-	{
-		len += sprintf(buf+len, "%0#9x ", result.extension[i].ext_instance);
-		len += sprintf(buf+len, "%0#6x ", result.extension[i].organization_id);
-		len += sprintf(buf+len, "%0#6x",  result.extension[i].x_function_code);
-
-		len += sprintf(buf+len, "\n");
-	}
-
-	if(result.more_flag)
-		len += sprintf(buf+len, "There is more...\n");
-
-	spin_unlock(&i2o_proc_lock);
-
-	return len;
-}
-
-
-/* Generic group F006h - Authorized User Table (table) */
-int i2o_proc_read_authorized_users(char *buf, char **start, off_t offset, int len,
-				   int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-	int i;
-
-	struct
-	{
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8  block_status;
-		u8  error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		u32 alternate_tid[64];
-	} result;
-
-	spin_lock(&i2o_proc_lock);
-	len = 0;
-
-	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data.tid,
-				0xF006, -1,
-				NULL, 0,
-				&result, sizeof(result));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0xF006 Autohorized User Table");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	if (result.row_count)
-		len += sprintf(buf+len, "#  AlternateTid\n");
-
-	for(i=0; i < result.row_count; i++)
-	{
-		len += sprintf(buf+len, "%-2d", i);
-		len += sprintf(buf+len, "%#7x ", result.alternate_tid[i]);
-	}
-
-	if (result.more_flag)
-		len += sprintf(buf+len, "There is more...\n");
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-
-/* Generic group F100h - Device Identity (scalar) */
-int i2o_proc_read_dev_identity(char *buf, char **start, off_t offset, int len, 
-			       int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[128];		// allow for "stuff" + up to 256 byte (max) serial number
-					// == (allow) 512d bytes (max)
-	static u16 *work16 = (u16*)work32;
-	int token;
-
-	spin_lock(&i2o_proc_lock);
-	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				0xF100,	-1,
-				&work32, sizeof(work32));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token ,"0xF100 Device Identity");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-	
-	len += sprintf(buf,     "Device Class  : %s\n", i2o_get_class_name(work16[0]));
-	len += sprintf(buf+len, "Owner TID     : %0#5x\n", work16[2]);
-	len += sprintf(buf+len, "Parent TID    : %0#5x\n", work16[3]);
-	len += sprintf(buf+len, "Vendor info   : %s\n", chtostr((u8 *)(work32+2), 16));
-	len += sprintf(buf+len, "Product info  : %s\n", chtostr((u8 *)(work32+6), 16));
-	len += sprintf(buf+len, "Description   : %s\n", chtostr((u8 *)(work32+10), 16));
-	len += sprintf(buf+len, "Product rev.  : %s\n", chtostr((u8 *)(work32+14), 8));
-
-	len += sprintf(buf+len, "Serial number : ");
-	len = print_serial_number(buf, len,
-			(u8*)(work32+16),
-						/* allow for SNLen plus
-						 * possible trailing '\0'
-						 */
-			sizeof(work32)-(16*sizeof(u32))-2
-				);
-	len +=  sprintf(buf+len, "\n");
-
-	spin_unlock(&i2o_proc_lock);
-
-	return len;
-}
-
-
-int i2o_proc_read_dev_name(char *buf, char **start, off_t offset, int len,
-	int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-
-	if ( d->dev_name[0] == '\0' )
-		return 0;
-
-	len = sprintf(buf, "%s\n", d->dev_name);
-
-	return len;
-}
-
-
-/* Generic group F101h - DDM Identity (scalar) */
-int i2o_proc_read_ddm_identity(char *buf, char **start, off_t offset, int len, 
-			      int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-
-	struct
-	{
-		u16 ddm_tid;
-		u8 module_name[24];
-		u8 module_rev[8];
-		u8 sn_format;
-		u8 serial_number[12];
-		u8 pad[256]; // allow up to 256 byte (max) serial number
-	} result;	
-
-	spin_lock(&i2o_proc_lock);
-	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid, 
-				0xF101,	-1,
-				&result, sizeof(result));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0xF101 DDM Identity");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf,     "Registering DDM TID : 0x%03x\n", result.ddm_tid);
-	len += sprintf(buf+len, "Module name         : %s\n", chtostr(result.module_name, 24));
-	len += sprintf(buf+len, "Module revision     : %s\n", chtostr(result.module_rev, 8));
-
-	len += sprintf(buf+len, "Serial number       : ");
-	len = print_serial_number(buf, len, result.serial_number, sizeof(result)-36);
-				/* allow for SNLen plus possible trailing '\0' */
-
-	len += sprintf(buf+len, "\n");
-
-	spin_unlock(&i2o_proc_lock);
-
-	return len;
-}
-
-/* Generic group F102h - User Information (scalar) */
-int i2o_proc_read_uinfo(char *buf, char **start, off_t offset, int len, 
-			int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-
- 	struct
-	{
-		u8 device_name[64];
-		u8 service_name[64];
-		u8 physical_location[64];
-		u8 instance_number[4];
-	} result;
-
-	spin_lock(&i2o_proc_lock);
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				0xF102,	-1,
-				&result, sizeof(result));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0xF102 User Information");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf,     "Device name     : %s\n", chtostr(result.device_name, 64));
-	len += sprintf(buf+len, "Service name    : %s\n", chtostr(result.service_name, 64));
-	len += sprintf(buf+len, "Physical name   : %s\n", chtostr(result.physical_location, 64));
-	len += sprintf(buf+len, "Instance number : %s\n", chtostr(result.instance_number, 4));
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* Generic group F103h - SGL Operating Limits (scalar) */
-int i2o_proc_read_sgl_limits(char *buf, char **start, off_t offset, int len, 
-			     int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[12];
-	static u16 *work16 = (u16 *)work32;
-	static u8 *work8 = (u8 *)work32;
-	int token;
-
-	spin_lock(&i2o_proc_lock);
-	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid, 
-				 0xF103, -1,
-				 &work32, sizeof(work32));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0xF103 SGL Operating Limits");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf,     "SGL chain size        : %d\n", work32[0]);
-	len += sprintf(buf+len, "Max SGL chain size    : %d\n", work32[1]);
-	len += sprintf(buf+len, "SGL chain size target : %d\n", work32[2]);
-	len += sprintf(buf+len, "SGL frag count        : %d\n", work16[6]);
-	len += sprintf(buf+len, "Max SGL frag count    : %d\n", work16[7]);
-	len += sprintf(buf+len, "SGL frag count target : %d\n", work16[8]);
-
-	if (d->i2oversion == 0x02)
-	{
-		len += sprintf(buf+len, "SGL data alignment    : %d\n", work16[8]);
-		len += sprintf(buf+len, "SGL addr limit        : %d\n", work8[20]);
-		len += sprintf(buf+len, "SGL addr sizes supported : ");
-		if (work8[21] & 0x01)
-			len += sprintf(buf+len, "32 bit ");
-		if (work8[21] & 0x02)
-			len += sprintf(buf+len, "64 bit ");
-		if (work8[21] & 0x04)
-			len += sprintf(buf+len, "96 bit ");
-		if (work8[21] & 0x08)
-			len += sprintf(buf+len, "128 bit ");
-		len += sprintf(buf+len, "\n");
-	}
-
-	spin_unlock(&i2o_proc_lock);
-
-	return len;
-}
-
-/* Generic group F200h - Sensors (scalar) */
-int i2o_proc_read_sensors(char *buf, char **start, off_t offset, int len,
-			  int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-
-	struct
-	{
-		u16 sensor_instance;
-		u8  component;
-		u16 component_instance;
-		u8  sensor_class;
-		u8  sensor_type;
-		u8  scaling_exponent;
-		u32 actual_reading;
-		u32 minimum_reading;
-		u32 low2lowcat_treshold;
-		u32 lowcat2low_treshold;
-		u32 lowwarn2low_treshold;
-		u32 low2lowwarn_treshold;
-		u32 norm2lowwarn_treshold;
-		u32 lowwarn2norm_treshold;
-		u32 nominal_reading;
-		u32 hiwarn2norm_treshold;
-		u32 norm2hiwarn_treshold;
-		u32 high2hiwarn_treshold;
-		u32 hiwarn2high_treshold;
-		u32 hicat2high_treshold;
-		u32 hi2hicat_treshold;
-		u32 maximum_reading;
-		u8  sensor_state;
-		u16 event_enable;
-	} result;
-	
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0xF200, -1,
-				 &result, sizeof(result));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0xF200 Sensors (optional)");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-	
-	len += sprintf(buf+len, "Sensor instance       : %d\n", result.sensor_instance);
-
-	len += sprintf(buf+len, "Component             : %d = ", result.component);
-	switch (result.component)
-	{
-	case 0:	len += sprintf(buf+len, "Other");		
-		break;
-	case 1: len += sprintf(buf+len, "Planar logic Board");
-		break;
-	case 2: len += sprintf(buf+len, "CPU");
-		break;
-	case 3: len += sprintf(buf+len, "Chassis");
-		break;
-	case 4: len += sprintf(buf+len, "Power Supply");
-		break;
-	case 5: len += sprintf(buf+len, "Storage");
-		break;
-	case 6: len += sprintf(buf+len, "External");
-		break;
-	}		
-	len += sprintf(buf+len,"\n");
-
-	len += sprintf(buf+len, "Component instance    : %d\n", result.component_instance);
-	len += sprintf(buf+len, "Sensor class          : %s\n",
-				result.sensor_class ? "Analog" : "Digital");
-	
-	len += sprintf(buf+len, "Sensor type           : %d = ",result.sensor_type);
-	switch (result.sensor_type)
-	{
-	case 0:	len += sprintf(buf+len, "Other\n");
-		break;
-	case 1: len += sprintf(buf+len, "Thermal\n");
-		break;
-	case 2: len += sprintf(buf+len, "DC voltage (DC volts)\n");
-		break;
-	case 3: len += sprintf(buf+len, "AC voltage (AC volts)\n");
-		break;
-	case 4: len += sprintf(buf+len, "DC current (DC amps)\n");
-		break;
-	case 5: len += sprintf(buf+len, "AC current (AC volts)\n");
-		break;
-	case 6: len += sprintf(buf+len, "Door open\n");
-		break;
-	case 7: len += sprintf(buf+len, "Fan operational\n");
-		break;
- 	}			
-
-	len += sprintf(buf+len, "Scaling exponent      : %d\n", result.scaling_exponent);
-	len += sprintf(buf+len, "Actual reading        : %d\n", result.actual_reading);
-	len += sprintf(buf+len, "Minimum reading       : %d\n", result.minimum_reading);
-	len += sprintf(buf+len, "Low2LowCat treshold   : %d\n", result.low2lowcat_treshold);
-	len += sprintf(buf+len, "LowCat2Low treshold   : %d\n", result.lowcat2low_treshold);
-	len += sprintf(buf+len, "LowWarn2Low treshold  : %d\n", result.lowwarn2low_treshold);
-	len += sprintf(buf+len, "Low2LowWarn treshold  : %d\n", result.low2lowwarn_treshold);
-	len += sprintf(buf+len, "Norm2LowWarn treshold : %d\n", result.norm2lowwarn_treshold);
-	len += sprintf(buf+len, "LowWarn2Norm treshold : %d\n", result.lowwarn2norm_treshold);
-	len += sprintf(buf+len, "Nominal reading       : %d\n", result.nominal_reading);
-	len += sprintf(buf+len, "HiWarn2Norm treshold  : %d\n", result.hiwarn2norm_treshold);
-	len += sprintf(buf+len, "Norm2HiWarn treshold  : %d\n", result.norm2hiwarn_treshold);
-	len += sprintf(buf+len, "High2HiWarn treshold  : %d\n", result.high2hiwarn_treshold);
-	len += sprintf(buf+len, "HiWarn2High treshold  : %d\n", result.hiwarn2high_treshold);
-	len += sprintf(buf+len, "HiCat2High treshold   : %d\n", result.hicat2high_treshold);
-	len += sprintf(buf+len, "High2HiCat treshold   : %d\n", result.hi2hicat_treshold);
-	len += sprintf(buf+len, "Maximum reading       : %d\n", result.maximum_reading);
-
-	len += sprintf(buf+len, "Sensor state          : %d = ", result.sensor_state);
-	switch (result.sensor_state)
-	{
-	case 0:	 len += sprintf(buf+len, "Normal\n");
-		 break;
-	case 1:  len += sprintf(buf+len, "Abnormal\n");
-		 break;
-	case 2:  len += sprintf(buf+len, "Unknown\n");
-		 break;
-	case 3:  len += sprintf(buf+len, "Low Catastrophic (LoCat)\n");
-		 break;
-	case 4:  len += sprintf(buf+len, "Low (Low)\n");
-		 break;
-	case 5:  len += sprintf(buf+len, "Low Warning (LoWarn)\n");
-		 break;
-	case 6:  len += sprintf(buf+len, "High Warning (HiWarn)\n");
-		 break;
-	case 7:  len += sprintf(buf+len, "High (High)\n");
-		 break;
-	case 8:  len += sprintf(buf+len, "High Catastrophic (HiCat)\n");
-		 break;
-	}			
-
-	len += sprintf(buf+len, "Event_enable : 0x%02X\n", result.event_enable);
-	len += sprintf(buf+len, "    [%s] Operational state change. \n",
-			(result.event_enable & 0x01) ? "+" : "-" );
-	len += sprintf(buf+len, "    [%s] Low catastrophic. \n",
-			(result.event_enable & 0x02) ? "+" : "-" );
-	len += sprintf(buf+len, "    [%s] Low reading. \n",
-			(result.event_enable & 0x04) ? "+" : "-" );
-	len += sprintf(buf+len, "    [%s] Low warning. \n",
-			(result.event_enable & 0x08) ? "+" : "-" );
-	len += sprintf(buf+len, "    [%s] Change back to normal from out of range state. \n",
-			(result.event_enable & 0x10) ? "+" : "-" );
-	len += sprintf(buf+len, "    [%s] High warning. \n",
-			(result.event_enable & 0x20) ? "+" : "-" );
-	len += sprintf(buf+len, "    [%s] High reading. \n",
-			(result.event_enable & 0x40) ? "+" : "-" );
-	len += sprintf(buf+len, "    [%s] High catastrophic. \n",
-			(result.event_enable & 0x80) ? "+" : "-" );
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-
-static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len)
-{
-	int i;
-
-	/* 19990419 -sralston
-	 *	The I2O v1.5 (and v2.0 so far) "official specification"
-	 *	got serial numbers WRONG!
-	 *	Apparently, and despite what Section 3.4.4 says and
-	 *	Figure 3-35 shows (pg 3-39 in the pdf doc),
-	 *	the convention / consensus seems to be:
-	 *	  + First byte is SNFormat
-	 *	  + Second byte is SNLen (but only if SNFormat==7 (?))
-	 *	  + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format
-	 */
-	switch(serialno[0])
-	{
-		case I2O_SNFORMAT_BINARY:		/* Binary */
-			pos += sprintf(buff+pos, "0x");
-			for(i = 0; i < serialno[1]; i++)
-			{
-				pos += sprintf(buff+pos, "%02X", serialno[2+i]);
-			}
-			break;
-	
-		case I2O_SNFORMAT_ASCII:		/* ASCII */
-			if ( serialno[1] < ' ' )	/* printable or SNLen? */
-			{
-				/* sanity */
-				max_len = (max_len < serialno[1]) ? max_len : serialno[1];
-				serialno[1+max_len] = '\0';
-
-				/* just print it */
-				pos += sprintf(buff+pos, "%s", &serialno[2]);
-			}
-			else
-			{
-				/* print chars for specified length */
-				for(i = 0; i < serialno[1]; i++)
-				{
-					pos += sprintf(buff+pos, "%c", serialno[2+i]);
-				}
-			}
-			break;
-
-		case I2O_SNFORMAT_UNICODE:		/* UNICODE */
-			pos += sprintf(buff+pos, "UNICODE Format.  Can't Display\n");
-			break;
-
-		case I2O_SNFORMAT_LAN48_MAC:		/* LAN-48 MAC Address */
-			pos += sprintf(buff+pos, 
-						"LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X",
-						serialno[2], serialno[3],
-						serialno[4], serialno[5],
-						serialno[6], serialno[7]);
-			break;
-
-		case I2O_SNFORMAT_WAN:			/* WAN MAC Address */
-			/* FIXME: Figure out what a WAN access address looks like?? */
-			pos += sprintf(buff+pos, "WAN Access Address");
-			break;
-
-/* plus new in v2.0 */
-		case I2O_SNFORMAT_LAN64_MAC:		/* LAN-64 MAC Address */
-			/* FIXME: Figure out what a LAN-64 address really looks like?? */
-			pos += sprintf(buff+pos, 
-						"LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X",
-						serialno[8], serialno[9],
-						serialno[2], serialno[3],
-						serialno[4], serialno[5],
-						serialno[6], serialno[7]);
-			break;
-
-
-		case I2O_SNFORMAT_DDM:			/* I2O DDM */
-			pos += sprintf(buff+pos, 
-						"DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh",
-						*(u16*)&serialno[2],
-						*(u16*)&serialno[4],
-						*(u16*)&serialno[6]);
-			break;
-
-		case I2O_SNFORMAT_IEEE_REG64:		/* IEEE Registered (64-bit) */
-		case I2O_SNFORMAT_IEEE_REG128:		/* IEEE Registered (128-bit) */
-			/* FIXME: Figure if this is even close?? */
-			pos += sprintf(buff+pos, 
-						"IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n",
-						*(u32*)&serialno[2],
-						*(u32*)&serialno[6],
-						*(u32*)&serialno[10],
-						*(u32*)&serialno[14]);
-			break;
-
-
-		case I2O_SNFORMAT_UNKNOWN:		/* Unknown 0    */
-		case I2O_SNFORMAT_UNKNOWN2:		/* Unknown 0xff */
-		default:
-			pos += sprintf(buff+pos, "Unknown data format (0x%02x)",
-				       serialno[0]);
-			break;
-	}
-
-	return pos;
-}
-
-const char * i2o_get_connector_type(int conn)
-{
-	int idx = 16;
-	static char *i2o_connector_type[] = {
-		"OTHER",
-		"UNKNOWN",
-		"AUI",
-		"UTP",
-		"BNC",
-		"RJ45",
-		"STP DB9",
-		"FIBER MIC",
-		"APPLE AUI",
-		"MII",
-		"DB9",
-		"HSSDC",
-		"DUPLEX SC FIBER",
-		"DUPLEX ST FIBER",
-		"TNC/BNC",
-		"HW DEFAULT"
-	};
-
-	switch(conn)
-	{
-	case 0x00000000:
-		idx = 0;
-		break;
-	case 0x00000001:
-		idx = 1;
-		break;
-	case 0x00000002:
-		idx = 2;
-		break;
-	case 0x00000003:
-		idx = 3;
-		break;
-	case 0x00000004:
-		idx = 4;
-		break;
-	case 0x00000005:
-		idx = 5;
-		break;
-	case 0x00000006:
-		idx = 6;
-		break;
-	case 0x00000007:
-		idx = 7;
-		break;
-	case 0x00000008:
-		idx = 8;
-		break;
-	case 0x00000009:
-		idx = 9;
-		break;
-	case 0x0000000A:
-		idx = 10;
-		break;
-	case 0x0000000B:
-		idx = 11;
-		break;
-	case 0x0000000C:
-		idx = 12;
-		break;
-	case 0x0000000D:
-		idx = 13;
-		break;
-	case 0x0000000E:
-		idx = 14;
-		break;
-	case 0xFFFFFFFF:
-		idx = 15;
-		break;
-	}
-
-	return i2o_connector_type[idx];
-}
-
-
-const char * i2o_get_connection_type(int conn)
-{
-	int idx = 0;
-	static char *i2o_connection_type[] = {
-		"Unknown",
-		"AUI",
-		"10BASE5",
-		"FIORL",
-		"10BASE2",
-		"10BROAD36",
-		"10BASE-T",
-		"10BASE-FP",
-		"10BASE-FB",
-		"10BASE-FL",
-		"100BASE-TX",
-		"100BASE-FX",
-		"100BASE-T4",
-		"1000BASE-SX",
-		"1000BASE-LX",
-		"1000BASE-CX",
-		"1000BASE-T",
-		"100VG-ETHERNET",
-		"100VG-TOKEN RING",
-		"4MBIT TOKEN RING",
-		"16 Mb Token Ring",
-		"125 MBAUD FDDI",
-		"Point-to-point",
-		"Arbitrated loop",
-		"Public loop",
-		"Fabric",
-		"Emulation",
-		"Other",
-		"HW default"
-	};
-
-	switch(conn)
-	{
-	case I2O_LAN_UNKNOWN:
-		idx = 0;
-		break;
-	case I2O_LAN_AUI:
-		idx = 1;
-		break;
-	case I2O_LAN_10BASE5:
-		idx = 2;
-		break;
-	case I2O_LAN_FIORL:
-		idx = 3;
-		break;
-	case I2O_LAN_10BASE2:
-		idx = 4;
-		break;
-	case I2O_LAN_10BROAD36:
-		idx = 5;
-		break;
-	case I2O_LAN_10BASE_T:
-		idx = 6;
-		break;
-	case I2O_LAN_10BASE_FP:
-		idx = 7;
-		break;
-	case I2O_LAN_10BASE_FB:
-		idx = 8;
-		break;
-	case I2O_LAN_10BASE_FL:
-		idx = 9;
-		break;
-	case I2O_LAN_100BASE_TX:
-		idx = 10;
-		break;
-	case I2O_LAN_100BASE_FX:
-		idx = 11;
-		break;
-	case I2O_LAN_100BASE_T4:
-		idx = 12;
-		break;
-	case I2O_LAN_1000BASE_SX:
-		idx = 13;
-		break;
-	case I2O_LAN_1000BASE_LX:
-		idx = 14;
-		break;
-	case I2O_LAN_1000BASE_CX:
-		idx = 15;
-		break;
-	case I2O_LAN_1000BASE_T:
-		idx = 16;
-		break;
-	case I2O_LAN_100VG_ETHERNET:
-		idx = 17;
-		break;
-	case I2O_LAN_100VG_TR:
-		idx = 18;
-		break;
-	case I2O_LAN_4MBIT:
-		idx = 19;
-		break;
-	case I2O_LAN_16MBIT:
-		idx = 20;
-		break;
-	case I2O_LAN_125MBAUD:
-		idx = 21;
-		break;
-	case I2O_LAN_POINT_POINT:
-		idx = 22;
-		break;
-	case I2O_LAN_ARB_LOOP:
-		idx = 23;
-		break;
-	case I2O_LAN_PUBLIC_LOOP:
-		idx = 24;
-		break;
-	case I2O_LAN_FABRIC:
-		idx = 25;
-		break;
-	case I2O_LAN_EMULATION:
-		idx = 26;
-		break;
-	case I2O_LAN_OTHER:
-		idx = 27;
-		break;
-	case I2O_LAN_DEFAULT:
-		idx = 28;
-		break;
-	}
-
-	return i2o_connection_type[idx];
-}
-
-
-/* LAN group 0000h - Device info (scalar) */
-int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len, 
-			       int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[56];
-	static u8 *work8 = (u8*)work32;
-	static u16 *work16 = (u16*)work32;
-	static u64 *work64 = (u64*)work32;
-	int token;
-
-	spin_lock(&i2o_proc_lock);
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0000, -1, &work32, 56*4);
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token, "0x0000 LAN Device Info");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf, "LAN Type            : ");
-	switch (work16[0])
-	{
-	case 0x0030:
-		len += sprintf(buf+len, "Ethernet, ");
-		break;
-	case 0x0040:
-		len += sprintf(buf+len, "100Base VG, ");
-		break;
-	case 0x0050:
-		len += sprintf(buf+len, "Token Ring, ");
-		break;
-	case 0x0060:
-		len += sprintf(buf+len, "FDDI, ");
-		break;
-	case 0x0070:
-		len += sprintf(buf+len, "Fibre Channel, ");
-		break;
-	default:
-		len += sprintf(buf+len, "Unknown type (0x%04x), ", work16[0]);
-		break;
-	}
-
-	if (work16[1]&0x00000001)
-		len += sprintf(buf+len, "emulated LAN, ");
-	else
-		len += sprintf(buf+len, "physical LAN port, ");
-
-	if (work16[1]&0x00000002)
-		len += sprintf(buf+len, "full duplex\n");
-	else
-		len += sprintf(buf+len, "simplex\n");
-
-	len += sprintf(buf+len, "Address format      : ");
-	switch(work8[4]) {
-	case 0x00:
-		len += sprintf(buf+len, "IEEE 48bit\n");
-		break;
-	case 0x01:
-		len += sprintf(buf+len, "FC IEEE\n");
-		break;
-	default:
-		len += sprintf(buf+len, "Unknown (0x%02x)\n", work8[4]);
-		break;
-	}
-
-	len += sprintf(buf+len, "State               : ");
-	switch(work8[5])
-	{
-	case 0x00:
-		len += sprintf(buf+len, "Unknown\n");
-		break;
-	case 0x01:
-		len += sprintf(buf+len, "Unclaimed\n");
-		break;
-	case 0x02:
-		len += sprintf(buf+len, "Operational\n");
-		break;
-	case 0x03:
-		len += sprintf(buf+len, "Suspended\n");
-		break;
-	case 0x04:
-		len += sprintf(buf+len, "Resetting\n");
-		break;
-	case 0x05:
-		len += sprintf(buf+len, "ERROR: ");
-		if(work16[3]&0x0001)
-			len += sprintf(buf+len, "TxCU inoperative ");
-		if(work16[3]&0x0002)
-			len += sprintf(buf+len, "RxCU inoperative ");
-		if(work16[3]&0x0004)
-			len += sprintf(buf+len, "Local mem alloc ");
-		len += sprintf(buf+len, "\n");
-		break;
-	case 0x06:
-		len += sprintf(buf+len, "Operational no Rx\n");
-		break;
-	case 0x07:
-		len += sprintf(buf+len, "Suspended no Rx\n");
-		break;
-	default:
-		len += sprintf(buf+len, "Unspecified\n");
-		break;
-	}
-
-	len += sprintf(buf+len, "Min packet size     : %d\n", work32[2]);
-	len += sprintf(buf+len, "Max packet size     : %d\n", work32[3]);
-	len += sprintf(buf+len, "HW address          : "
-		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-		       work8[16],work8[17],work8[18],work8[19],
-		       work8[20],work8[21],work8[22],work8[23]);
-
-	len += sprintf(buf+len, "Max Tx wire speed   : %d bps\n", (int)work64[3]);
-	len += sprintf(buf+len, "Max Rx wire speed   : %d bps\n", (int)work64[4]);
-
-	len += sprintf(buf+len, "Min SDU packet size : 0x%08x\n", work32[10]);
-	len += sprintf(buf+len, "Max SDU packet size : 0x%08x\n", work32[11]);
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* LAN group 0001h - MAC address table (scalar) */
-int i2o_proc_read_lan_mac_addr(char *buf, char **start, off_t offset, int len, 
-			       int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[48];
-	static u8 *work8 = (u8*)work32;
-	int token;
-
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0001, -1, &work32, 48*4);
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0001 LAN MAC Address");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf,     "Active address          : "
-		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-		       work8[0],work8[1],work8[2],work8[3],
-		       work8[4],work8[5],work8[6],work8[7]);
-	len += sprintf(buf+len, "Current address         : "
-		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-		       work8[8],work8[9],work8[10],work8[11],
-		       work8[12],work8[13],work8[14],work8[15]);
-	len += sprintf(buf+len, "Functional address mask : "
-		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-		       work8[16],work8[17],work8[18],work8[19],
-		       work8[20],work8[21],work8[22],work8[23]);
-
-	len += sprintf(buf+len,"HW/DDM capabilities : 0x%08x\n", work32[7]);
-	len += sprintf(buf+len,"    [%s] Unicast packets supported\n",
-		       (work32[7]&0x00000001)?"+":"-");
-	len += sprintf(buf+len,"    [%s] Promiscuous mode supported\n",
-		       (work32[7]&0x00000002)?"+":"-");
-	len += sprintf(buf+len,"    [%s] Promiscuous multicast mode supported\n",
-		       (work32[7]&0x00000004)?"+":"-");
-	len += sprintf(buf+len,"    [%s] Broadcast reception disabling supported\n",
-		       (work32[7]&0x00000100)?"+":"-");
-	len += sprintf(buf+len,"    [%s] Multicast reception disabling supported\n",
-		       (work32[7]&0x00000200)?"+":"-");
-	len += sprintf(buf+len,"    [%s] Functional address disabling supported\n",
-		       (work32[7]&0x00000400)?"+":"-");
-	len += sprintf(buf+len,"    [%s] MAC reporting supported\n",
-		       (work32[7]&0x00000800)?"+":"-");
-
-	len += sprintf(buf+len,"Filter mask : 0x%08x\n", work32[6]);
-	len += sprintf(buf+len,"    [%s] Unicast packets disable\n",
-		(work32[6]&0x00000001)?"+":"-");
-	len += sprintf(buf+len,"    [%s] Promiscuous mode enable\n",
-		(work32[6]&0x00000002)?"+":"-");
-	len += sprintf(buf+len,"    [%s] Promiscuous multicast mode enable\n",
-		(work32[6]&0x00000004)?"+":"-");	
-	len += sprintf(buf+len,"    [%s] Broadcast packets disable\n",
-		(work32[6]&0x00000100)?"+":"-");
-	len += sprintf(buf+len,"    [%s] Multicast packets disable\n",
-		(work32[6]&0x00000200)?"+":"-");
-	len += sprintf(buf+len,"    [%s] Functional address disable\n",
-		       (work32[6]&0x00000400)?"+":"-");
-		       
-	if (work32[7]&0x00000800) {
-		len += sprintf(buf+len, "    MAC reporting mode : ");
-		if (work32[6]&0x00000800)
-			len += sprintf(buf+len, "Pass only priority MAC packets to user\n");
-		else if (work32[6]&0x00001000)
-			len += sprintf(buf+len, "Pass all MAC packets to user\n");
-		else if (work32[6]&0x00001800)
-			len += sprintf(buf+len, "Pass all MAC packets (promiscuous) to user\n");
-		else
-			len += sprintf(buf+len, "Do not pass MAC packets to user\n");
-	}
-	len += sprintf(buf+len, "Number of multicast addresses : %d\n", work32[8]);
-	len += sprintf(buf+len, "Perfect filtering for max %d multicast addresses\n",
-		       work32[9]);
-	len += sprintf(buf+len, "Imperfect filtering for max %d multicast addresses\n",
-		       work32[10]);
-
-	spin_unlock(&i2o_proc_lock);
-
-	return len;
-}
-
-/* LAN group 0002h - Multicast MAC address table (table) */
-int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset,
-				 int len, int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-	int i;
-	u8 mc_addr[8];
-
-	struct
-	{
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8  block_status;
-		u8  error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		u8  mc_addr[256][8];
-	} result;	
-
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data.tid, 0x0002, -1, 
-				NULL, 0, &result, sizeof(result));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x002 LAN Multicast MAC Address");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	for (i = 0; i < result.row_count; i++)
-	{
-		memcpy(mc_addr, result.mc_addr[i], 8);
-
-		len += sprintf(buf+len, "MC MAC address[%d]: "
-			       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-			       i, mc_addr[0], mc_addr[1], mc_addr[2],
-			       mc_addr[3], mc_addr[4], mc_addr[5],
-			       mc_addr[6], mc_addr[7]);
-	}
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* LAN group 0003h - Batch Control (scalar) */
-int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset,
-				    int len, int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[9];
-	int token;
-
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0003, -1, &work32, 9*4);
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0003 LAN Batch Control");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf, "Batch mode ");
-	if (work32[0]&0x00000001)
-		len += sprintf(buf+len, "disabled");
-	else
-		len += sprintf(buf+len, "enabled");
-	if (work32[0]&0x00000002)
-		len += sprintf(buf+len, " (current setting)");
-	if (work32[0]&0x00000004)
-		len += sprintf(buf+len, ", forced");
-	else
-		len += sprintf(buf+len, ", toggle");
-	len += sprintf(buf+len, "\n");
-
-	len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]);
-	len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]);
-	len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]);
-	len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]);
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* LAN group 0004h - LAN Operation (scalar) */
-int i2o_proc_read_lan_operation(char *buf, char **start, off_t offset, int len,
-				int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[5];
-	int token;
-
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0004, -1, &work32, 20);
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0004 LAN Operation");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf, "Packet prepadding (32b words) : %d\n", work32[0]);
-	len += sprintf(buf+len, "Transmission error reporting  : %s\n",
-		       (work32[1]&1)?"on":"off");
-	len += sprintf(buf+len, "Bad packet handling           : %s\n",
-				(work32[1]&0x2)?"by host":"by DDM");
-	len += sprintf(buf+len, "Packet orphan limit           : %d\n", work32[2]);
-
-	len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[3]);
-	len += sprintf(buf+len, "    [%s] HW CRC suppression\n",
-			(work32[3]&0x00000004) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] HW IPv4 checksum\n",
-			(work32[3]&0x00000100) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] HW TCP checksum\n",
-			(work32[3]&0x00000200) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] HW UDP checksum\n",
-			(work32[3]&0x00000400) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] HW RSVP checksum\n",
-			(work32[3]&0x00000800) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] HW ICMP checksum\n",
-			(work32[3]&0x00001000) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] Loopback suppression enable\n",
-			(work32[3]&0x00002000) ? "+" : "-");
-
-	len += sprintf(buf+len, "Rx modes : 0x%08x\n", work32[4]);
-	len += sprintf(buf+len, "    [%s] FCS in payload\n",
-			(work32[4]&0x00000004) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] HW IPv4 checksum validation\n",
-			(work32[4]&0x00000100) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] HW TCP checksum validation\n",
-			(work32[4]&0x00000200) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] HW UDP checksum validation\n",
-			(work32[4]&0x00000400) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] HW RSVP checksum validation\n",
-			(work32[4]&0x00000800) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] HW ICMP checksum validation\n",
-			(work32[4]&0x00001000) ? "+" : "-");
- 
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* LAN group 0005h - Media operation (scalar) */
-int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset,
-				      int len, int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-
-	struct
-	{
-		u32 connector_type;
-		u32 connection_type;
-		u64 current_tx_wire_speed;
-		u64 current_rx_wire_speed;
-		u8  duplex_mode;
-		u8  link_status;
-		u8  reserved;
-		u8  duplex_mode_target;
-		u32 connector_type_target;
-		u32 connection_type_target;
-	} result;	
-
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0005, -1, &result, sizeof(result));
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token, "0x0005 LAN Media Operation");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf, "Connector type         : %s\n",
-		       i2o_get_connector_type(result.connector_type));
-	len += sprintf(buf+len, "Connection type        : %s\n",
-		       i2o_get_connection_type(result.connection_type));
-
-	len += sprintf(buf+len, "Current Tx wire speed  : %d bps\n", (int)result.current_tx_wire_speed);
-	len += sprintf(buf+len, "Current Rx wire speed  : %d bps\n", (int)result.current_rx_wire_speed);
-	len += sprintf(buf+len, "Duplex mode            : %s duplex\n",
-			(result.duplex_mode)?"Full":"Half");
-			
-	len += sprintf(buf+len, "Link status            : ");
-	switch (result.link_status)
-	{
-	case 0x00:
-		len += sprintf(buf+len, "Unknown\n");
-		break;
-	case 0x01:
-		len += sprintf(buf+len, "Normal\n");
-		break;
-	case 0x02:
-		len += sprintf(buf+len, "Failure\n");
-		break;
-	case 0x03:
-		len += sprintf(buf+len, "Reset\n");
-		break;
-	default:
-		len += sprintf(buf+len, "Unspecified\n");
-	}
-	
-	len += sprintf(buf+len, "Duplex mode target     : ");
-	switch (result.duplex_mode_target){
-		case 0:
-			len += sprintf(buf+len, "Half duplex\n");
-			break;
-		case 1:
-			len += sprintf(buf+len, "Full duplex\n");
-			break;
-		default:
-			len += sprintf(buf+len, "\n");
-	}
-
-	len += sprintf(buf+len, "Connector type target  : %s\n",
-		       i2o_get_connector_type(result.connector_type_target));
-	len += sprintf(buf+len, "Connection type target : %s\n",
-		       i2o_get_connection_type(result.connection_type_target));
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* LAN group 0006h - Alternate address (table) (optional) */
-int i2o_proc_read_lan_alt_addr(char *buf, char **start, off_t offset, int len,
-			       int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-	int i;
-	u8 alt_addr[8];
-	struct
-	{
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8  block_status;
-		u8  error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		u8  alt_addr[256][8];
-	} result;	
-
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data.tid,
-				0x0006, -1, NULL, 0, &result, sizeof(result));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token, "0x0006 LAN Alternate Address (optional)");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	for (i=0; i < result.row_count; i++)
-	{
-		memcpy(alt_addr,result.alt_addr[i],8);
-		len += sprintf(buf+len, "Alternate address[%d]: "
-			       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-			       i, alt_addr[0], alt_addr[1], alt_addr[2],
-			       alt_addr[3], alt_addr[4], alt_addr[5],
-			       alt_addr[6], alt_addr[7]);
-	}
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-
-/* LAN group 0007h - Transmit info (scalar) */
-int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len, 
-			      int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[8];
-	int token;
-
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0007, -1, &work32, 8*4);
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0007 LAN Transmit Info");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf,     "Tx Max SG elements per packet : %d\n", work32[0]);
-	len += sprintf(buf+len, "Tx Max SG elements per chain  : %d\n", work32[1]);
-	len += sprintf(buf+len, "Tx Max outstanding packets    : %d\n", work32[2]);
-	len += sprintf(buf+len, "Tx Max packets per request    : %d\n", work32[3]);
-
-	len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[4]);
-	len += sprintf(buf+len, "    [%s] No DA in SGL\n",
-				(work32[4]&0x00000002) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] CRC suppression\n",
-				(work32[4]&0x00000004) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] MAC insertion\n",
-				(work32[4]&0x00000010) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] RIF insertion\n",
-				(work32[4]&0x00000020) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] IPv4 checksum generation\n",
-				(work32[4]&0x00000100) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] TCP checksum generation\n",
-				(work32[4]&0x00000200) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] UDP checksum generation\n",
-				(work32[4]&0x00000400) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] RSVP checksum generation\n",
-				(work32[4]&0x00000800) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] ICMP checksum generation\n",
-				(work32[4]&0x00001000) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] Loopback enabled\n",
-				(work32[4]&0x00010000) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] Loopback suppression enabled\n",
-				(work32[4]&0x00020000) ? "+" : "-");
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* LAN group 0008h - Receive info (scalar) */
-int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len, 
-			      int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[8];
-	int token;
-
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0008, -1, &work32, 8*4);
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0008 LAN Receive Info");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf     ,"Rx Max size of chain element : %d\n", work32[0]);
-	len += sprintf(buf+len, "Rx Max Buckets               : %d\n", work32[1]);
-	len += sprintf(buf+len, "Rx Max Buckets in Reply      : %d\n", work32[3]);
-	len += sprintf(buf+len, "Rx Max Packets in Bucket     : %d\n", work32[4]);
-	len += sprintf(buf+len, "Rx Max Buckets in Post       : %d\n", work32[5]);
-
-	len += sprintf(buf+len, "Rx Modes : 0x%08x\n", work32[2]);
-	len += sprintf(buf+len, "    [%s] FCS reception\n",
-				(work32[2]&0x00000004) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] IPv4 checksum validation \n",
-				(work32[2]&0x00000100) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] TCP checksum validation \n",
-				(work32[2]&0x00000200) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] UDP checksum validation \n",
-				(work32[2]&0x00000400) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] RSVP checksum validation \n",
-				(work32[2]&0x00000800) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] ICMP checksum validation \n",
-				(work32[2]&0x00001000) ? "+" : "-");
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-static int i2o_report_opt_field(char *buf, char *field_name,
-				int field_nbr, int supp_fields, u64 *value)
-{
-	if (supp_fields & (1 << field_nbr))
-		return sprintf(buf, "%-24s : " FMT_U64_HEX "\n", field_name, U64_VAL(value));
-	else	
-		return sprintf(buf, "%-24s : Not supported\n", field_name);	
-}
-
-/* LAN group 0100h - LAN Historical statistics (scalar) */
-/* LAN group 0180h - Supported Optional Historical Statistics (scalar) */
-/* LAN group 0182h - Optional Non Media Specific Transmit Historical Statistics (scalar) */
-/* LAN group 0183h - Optional Non Media Specific Receive Historical Statistics (scalar) */
-
-int i2o_proc_read_lan_hist_stats(char *buf, char **start, off_t offset, int len,
-				 int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-
-	struct
-	{
-		u64 tx_packets;
-		u64 tx_bytes;
-		u64 rx_packets;
-		u64 rx_bytes;
-		u64 tx_errors;
-		u64 rx_errors;
-		u64 rx_dropped;
-		u64 adapter_resets;
-		u64 adapter_suspends;
-	} stats;			// 0x0100
-
-	static u64 supp_groups[4];	// 0x0180
-
-	struct
-	{
-		u64 tx_retries;
-		u64 tx_directed_bytes;
-		u64 tx_directed_packets;
-		u64 tx_multicast_bytes;
-		u64 tx_multicast_packets;
-		u64 tx_broadcast_bytes;
-		u64 tx_broadcast_packets;
-		u64 tx_group_addr_packets;
-		u64 tx_short_packets;
-	} tx_stats;			// 0x0182
-
-	struct
-	{
-		u64 rx_crc_errors;
-		u64 rx_directed_bytes;
-		u64 rx_directed_packets;
-		u64 rx_multicast_bytes;
-		u64 rx_multicast_packets;
-		u64 rx_broadcast_bytes;
-		u64 rx_broadcast_packets;
-		u64 rx_group_addr_packets;
-		u64 rx_short_packets;
-		u64 rx_long_packets;
-		u64 rx_runt_packets;
-	} rx_stats;			// 0x0183
-
-	struct
-	{
-		u64 ipv4_generate;
-		u64 ipv4_validate_success;
-		u64 ipv4_validate_errors;
-		u64 tcp_generate;
-		u64 tcp_validate_success;
-		u64 tcp_validate_errors;
-		u64 udp_generate;
-		u64 udp_validate_success;
-		u64 udp_validate_errors;
-		u64 rsvp_generate;
-		u64 rsvp_validate_success;
-		u64 rsvp_validate_errors;		
-		u64 icmp_generate;
-		u64 icmp_validate_success;
-		u64 icmp_validate_errors;
-	} chksum_stats;			// 0x0184
-
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0100, -1, &stats, sizeof(stats));
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x100 LAN Statistics");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf+len, "Tx packets       : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.tx_packets));
-	len += sprintf(buf+len, "Tx bytes         : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.tx_bytes));
-	len += sprintf(buf+len, "Rx packets       : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.rx_packets));
-	len += sprintf(buf+len, "Rx bytes         : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.rx_bytes));
-	len += sprintf(buf+len, "Tx errors        : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.tx_errors));
-	len += sprintf(buf+len, "Rx errors        : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.rx_errors));
-	len += sprintf(buf+len, "Rx dropped       : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.rx_dropped));
-	len += sprintf(buf+len, "Adapter resets   : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.adapter_resets));
-	len += sprintf(buf+len, "Adapter suspends : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.adapter_suspends));
-
-	/* Optional statistics follows */
-	/* Get 0x0180 to see which optional groups/fields are supported */
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0180, -1, &supp_groups, sizeof(supp_groups));
-	
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token, "0x180 LAN Supported Optional Statistics");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	if (supp_groups[1]) /* 0x0182 */
-	{
-		token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 	0x0182, -1, &tx_stats, sizeof(tx_stats));
-
-		if (token < 0) {
-			len += i2o_report_query_status(buf+len, token,"0x182 LAN Optional Tx Historical Statistics");
-			spin_unlock(&i2o_proc_lock);
-			return len;
-		}
-
-		len += sprintf(buf+len, "==== Optional TX statistics (group 0182h)\n");
-
-		len += i2o_report_opt_field(buf+len, "Tx RetryCount",
-					0, supp_groups[1], &tx_stats.tx_retries);
-		len += i2o_report_opt_field(buf+len, "Tx DirectedBytes",
-					1, supp_groups[1], &tx_stats.tx_directed_bytes);
-		len += i2o_report_opt_field(buf+len, "Tx DirectedPackets",
-					2, supp_groups[1], &tx_stats.tx_directed_packets);
-		len += i2o_report_opt_field(buf+len, "Tx MulticastBytes",
-					3, supp_groups[1], &tx_stats.tx_multicast_bytes);
-		len += i2o_report_opt_field(buf+len, "Tx MulticastPackets",
-					4, supp_groups[1], &tx_stats.tx_multicast_packets);
-		len += i2o_report_opt_field(buf+len, "Tx BroadcastBytes",
-					5, supp_groups[1], &tx_stats.tx_broadcast_bytes);
-		len += i2o_report_opt_field(buf+len, "Tx BroadcastPackets",
-					6, supp_groups[1], &tx_stats.tx_broadcast_packets);
-		len += i2o_report_opt_field(buf+len, "Tx TotalGroupAddrPackets",
-					7, supp_groups[1], &tx_stats.tx_group_addr_packets);
-		len += i2o_report_opt_field(buf+len, "Tx TotalPacketsTooShort",
-					8, supp_groups[1], &tx_stats.tx_short_packets);
-	}
-
-	if (supp_groups[2]) /* 0x0183 */
-	{
-		token = i2o_query_scalar(d->controller, d->lct_data.tid,
-					 0x0183, -1, &rx_stats, sizeof(rx_stats));
-		if (token < 0) {
-			len += i2o_report_query_status(buf+len, token,"0x183 LAN Optional Rx Historical Stats");
-			spin_unlock(&i2o_proc_lock);
-			return len;
-		}
-
-		len += sprintf(buf+len, "==== Optional RX statistics (group 0183h)\n");
-
-		len += i2o_report_opt_field(buf+len, "Rx CRCErrorCount",
-					0, supp_groups[2], &rx_stats.rx_crc_errors);
-		len += i2o_report_opt_field(buf+len, "Rx DirectedBytes",
-					1, supp_groups[2], &rx_stats.rx_directed_bytes);
-		len += i2o_report_opt_field(buf+len, "Rx DirectedPackets",
-					2, supp_groups[2], &rx_stats.rx_directed_packets);
-		len += i2o_report_opt_field(buf+len, "Rx MulticastBytes",
-					3, supp_groups[2], &rx_stats.rx_multicast_bytes);
-		len += i2o_report_opt_field(buf+len, "Rx MulticastPackets",
-					4, supp_groups[2], &rx_stats.rx_multicast_packets);
-		len += i2o_report_opt_field(buf+len, "Rx BroadcastBytes",
-					5, supp_groups[2], &rx_stats.rx_broadcast_bytes);
-		len += i2o_report_opt_field(buf+len, "Rx BroadcastPackets",
-					6, supp_groups[2], &rx_stats.rx_broadcast_packets);
-		len += i2o_report_opt_field(buf+len, "Rx TotalGroupAddrPackets",
-					7, supp_groups[2], &rx_stats.rx_group_addr_packets);
-		len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooShort",
-					8, supp_groups[2], &rx_stats.rx_short_packets);
-		len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooLong",
-					9, supp_groups[2], &rx_stats.rx_long_packets);
-		len += i2o_report_opt_field(buf+len, "Rx TotalPacketsRunt",
-					10, supp_groups[2], &rx_stats.rx_runt_packets);
-	}
-	
-	if (supp_groups[3]) /* 0x0184 */
-	{
-		token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 	0x0184, -1, &chksum_stats, sizeof(chksum_stats));
-
-		if (token < 0) {
-			len += i2o_report_query_status(buf+len, token,"0x184 LAN Optional Chksum Historical Stats");
-			spin_unlock(&i2o_proc_lock);
-			return len;
-		}
-
-		len += sprintf(buf+len, "==== Optional CHKSUM statistics (group 0x0184)\n");
-
-		len += i2o_report_opt_field(buf+len, "IPv4 Generate",
-					0, supp_groups[3], &chksum_stats.ipv4_generate);
-		len += i2o_report_opt_field(buf+len, "IPv4 ValidateSuccess",
-					1, supp_groups[3], &chksum_stats.ipv4_validate_success);
-		len += i2o_report_opt_field(buf+len, "IPv4 ValidateError",
-					2, supp_groups[3], &chksum_stats.ipv4_validate_errors);
-		len += i2o_report_opt_field(buf+len, "TCP  Generate",
-					3, supp_groups[3], &chksum_stats.tcp_generate);
-		len += i2o_report_opt_field(buf+len, "TCP  ValidateSuccess",
-					4, supp_groups[3], &chksum_stats.tcp_validate_success);
-		len += i2o_report_opt_field(buf+len, "TCP  ValidateError",
-					5, supp_groups[3], &chksum_stats.tcp_validate_errors);
-		len += i2o_report_opt_field(buf+len, "UDP  Generate",
-					6, supp_groups[3], &chksum_stats.udp_generate);
-		len += i2o_report_opt_field(buf+len, "UDP  ValidateSuccess",
-					7, supp_groups[3], &chksum_stats.udp_validate_success);
-		len += i2o_report_opt_field(buf+len, "UDP  ValidateError",
-					8, supp_groups[3], &chksum_stats.udp_validate_errors);
-		len += i2o_report_opt_field(buf+len, "RSVP Generate",
-					9, supp_groups[3], &chksum_stats.rsvp_generate);
-		len += i2o_report_opt_field(buf+len, "RSVP ValidateSuccess",
-					10, supp_groups[3], &chksum_stats.rsvp_validate_success);
-		len += i2o_report_opt_field(buf+len, "RSVP ValidateError",
-					11, supp_groups[3], &chksum_stats.rsvp_validate_errors);
-		len += i2o_report_opt_field(buf+len, "ICMP Generate",
-					12, supp_groups[3], &chksum_stats.icmp_generate);
-		len += i2o_report_opt_field(buf+len, "ICMP ValidateSuccess",
-					13, supp_groups[3], &chksum_stats.icmp_validate_success);
-		len += i2o_report_opt_field(buf+len, "ICMP ValidateError",
-					14, supp_groups[3], &chksum_stats.icmp_validate_errors);
-	}
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* LAN group 0200h - Required Ethernet Statistics (scalar) */
-/* LAN group 0280h - Optional Ethernet Statistics Supported (scalar) */
-/* LAN group 0281h - Optional Ethernet Historical Statistics (scalar) */
-int i2o_proc_read_lan_eth_stats(char *buf, char **start, off_t offset,
-				int len, int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	int token;
-
-	struct
-	{
-		u64 rx_align_errors;
-		u64 tx_one_collisions;
-		u64 tx_multiple_collisions;
-		u64 tx_deferred;
-		u64 tx_late_collisions;
-		u64 tx_max_collisions;
-		u64 tx_carrier_lost;
-		u64 tx_excessive_deferrals;
-	} stats;	
-
-	static u64 supp_fields;
-	struct
-	{
-		u64 rx_overrun;
-		u64 tx_underrun;
-		u64 tx_heartbeat_failure;	
-	} hist_stats;
-
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0200, -1, &stats, sizeof(stats));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0200 LAN Ethernet Statistics");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf+len, "Rx alignment errors    : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.rx_align_errors));
-	len += sprintf(buf+len, "Tx one collisions      : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.tx_one_collisions));
-	len += sprintf(buf+len, "Tx multicollisions     : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.tx_multiple_collisions));
-	len += sprintf(buf+len, "Tx deferred            : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.tx_deferred));
-	len += sprintf(buf+len, "Tx late collisions     : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.tx_late_collisions));
-	len += sprintf(buf+len, "Tx max collisions      : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.tx_max_collisions));
-	len += sprintf(buf+len, "Tx carrier lost        : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.tx_carrier_lost));
-	len += sprintf(buf+len, "Tx excessive deferrals : " FMT_U64_HEX "\n",
-		       U64_VAL(&stats.tx_excessive_deferrals));
-
-	/* Optional Ethernet statistics follows  */
-	/* Get 0x0280 to see which optional fields are supported */
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0280, -1, &supp_fields, sizeof(supp_fields));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0280 LAN Supported Optional Ethernet Statistics");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	if (supp_fields) /* 0x0281 */
-	{
-		token = i2o_query_scalar(d->controller, d->lct_data.tid,
-					 0x0281, -1, &stats, sizeof(stats));
-
-		if (token < 0) {
-			len += i2o_report_query_status(buf+len, token,"0x0281 LAN Optional Ethernet Statistics");
-			spin_unlock(&i2o_proc_lock);
-			return len;
-		}
-
-		len += sprintf(buf+len, "==== Optional ETHERNET statistics (group 0x0281)\n");
-
-		len += i2o_report_opt_field(buf+len, "Rx Overrun",
-					0, supp_fields, &hist_stats.rx_overrun);
-		len += i2o_report_opt_field(buf+len, "Tx Underrun",
-					1, supp_fields, &hist_stats.tx_underrun);
-		len += i2o_report_opt_field(buf+len, "Tx HeartbeatFailure",
-					2, supp_fields, &hist_stats.tx_heartbeat_failure);
-	}
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* LAN group 0300h - Required Token Ring Statistics (scalar) */
-/* LAN group 0380h, 0381h - Optional Statistics not yet defined (TODO) */
-int i2o_proc_read_lan_tr_stats(char *buf, char **start, off_t offset,
-			       int len, int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	static u64 work64[13];
-	int token;
-
-	static char *ring_status[] =
-	{
-		"",
-		"",
-		"",
-		"",
-		"",
-		"Ring Recovery",
-		"Single Station",
-		"Counter Overflow",
-		"Remove Received",
-		"",
-		"Auto-Removal Error 1",
-		"Lobe Wire Fault",
-		"Transmit Beacon",
-		"Soft Error",
-		"Hard Error",
-		"Signal Loss"
-	};
-
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0300, -1, &work64, sizeof(work64));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0300 Token Ring Statistics");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf,     "LineErrors          : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[0]));
-	len += sprintf(buf+len, "LostFrames          : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[1]));
-	len += sprintf(buf+len, "ACError             : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[2]));
-	len += sprintf(buf+len, "TxAbortDelimiter    : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[3]));
-	len += sprintf(buf+len, "BursErrors          : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[4]));
-	len += sprintf(buf+len, "FrameCopiedErrors   : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[5]));
-	len += sprintf(buf+len, "FrequencyErrors     : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[6]));
-	len += sprintf(buf+len, "InternalErrors      : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[7]));
-	len += sprintf(buf+len, "LastRingStatus      : %s\n", ring_status[work64[8]]);
-	len += sprintf(buf+len, "TokenError          : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[9]));
-	len += sprintf(buf+len, "UpstreamNodeAddress : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[10]));
-	len += sprintf(buf+len, "LastRingID          : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[11]));
-	len += sprintf(buf+len, "LastBeaconType      : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[12]));
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-/* LAN group 0400h - Required FDDI Statistics (scalar) */
-/* LAN group 0480h, 0481h - Optional Statistics, not yet defined (TODO) */
-int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset,
-				 int len, int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	static u64 work64[11];
-	int token;
-
-	static char *conf_state[] =
-	{
-		"Isolated",
-		"Local a",
-		"Local b",
-		"Local ab",
-		"Local s",
-		"Wrap a",
-		"Wrap b",
-		"Wrap ab",
-		"Wrap s",
-		"C-Wrap a",
-		"C-Wrap b",
-		"C-Wrap s",
-		"Through",
-	};
-
-	static char *ring_state[] =
-	{
-		"Isolated",
-		"Non-op",
-		"Rind-op",
-		"Detect",
-		"Non-op-Dup",
-		"Ring-op-Dup",
-		"Directed",
-		"Trace"
-	};
-
-	static char *link_state[] =
-	{
-		"Off",
-		"Break",
-		"Trace",
-		"Connect",
-		"Next",
-		"Signal",
-		"Join",
-		"Verify",
-		"Active",
-		"Maintenance"
-	};
-
-	spin_lock(&i2o_proc_lock);
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->lct_data.tid,
-				 0x0400, -1, &work64, sizeof(work64));
-
-	if (token < 0) {
-		len += i2o_report_query_status(buf+len, token,"0x0400 FDDI Required Statistics");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf+len, "ConfigurationState : %s\n", conf_state[work64[0]]);
-	len += sprintf(buf+len, "UpstreamNode       : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[1]));
-	len += sprintf(buf+len, "DownStreamNode     : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[2]));
-	len += sprintf(buf+len, "FrameErrors        : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[3]));
-	len += sprintf(buf+len, "FramesLost         : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[4]));
-	len += sprintf(buf+len, "RingMgmtState      : %s\n", ring_state[work64[5]]);
-	len += sprintf(buf+len, "LCTFailures        : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[6]));
-	len += sprintf(buf+len, "LEMRejects         : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[7]));
-	len += sprintf(buf+len, "LEMCount           : " FMT_U64_HEX "\n",
-		       U64_VAL(&work64[8]));
-	len += sprintf(buf+len, "LConnectionState   : %s\n",
-		       link_state[work64[9]]);
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-static int i2o_proc_create_entries(void *data, i2o_proc_entry *pentry,
-				   struct proc_dir_entry *parent)
-{
-	struct proc_dir_entry *ent;
-	
-	while(pentry->name != NULL)
-	{
-		ent = create_proc_entry(pentry->name, pentry->mode, parent);
-		if(!ent) return -1;
-
-		ent->data = data;
-		ent->read_proc = pentry->read_proc;
-		ent->write_proc = pentry->write_proc;
-		ent->nlink = 1;
-
-		pentry++;
-	}
-
-	return 0;
-}
-
-static void i2o_proc_remove_entries(i2o_proc_entry *pentry, 
-				    struct proc_dir_entry *parent)
-{
-	while(pentry->name != NULL)
-	{
-		remove_proc_entry(pentry->name, parent);
-		pentry++;
-	}
-}
-
-static int i2o_proc_add_controller(struct i2o_controller *pctrl, 
-				   struct proc_dir_entry *root )
-{
-	struct proc_dir_entry *dir, *dir1;
-	struct i2o_device *dev;
-	char buff[10];
-
-	sprintf(buff, "iop%d", pctrl->unit);
-
-	dir = proc_mkdir(buff, root);
-	if(!dir)
-		return -1;
-
-	pctrl->proc_entry = dir;
-
-	i2o_proc_create_entries(pctrl, generic_iop_entries, dir);
-	
-	for(dev = pctrl->devices; dev; dev = dev->next)
-	{
-		sprintf(buff, "%0#5x", dev->lct_data.tid);
-
-		dir1 = proc_mkdir(buff, dir);
-		dev->proc_entry = dir1;
-
-		if(!dir1)
-			printk(KERN_INFO "i2o_proc: Could not allocate proc dir\n");
-
-		i2o_proc_add_device(dev, dir1);
-	}
-
-	return 0;
-}
-
-void i2o_proc_new_dev(struct i2o_controller *c, struct i2o_device *d)
-{
-	char buff[10];
-
-#ifdef DRIVERDEBUG
-	printk(KERN_INFO "Adding new device to /proc/i2o/iop%d\n", c->unit);
-#endif
-	sprintf(buff, "%0#5x", d->lct_data.tid);
-
-	d->proc_entry = proc_mkdir(buff, c->proc_entry);
-
-	if(!d->proc_entry)
-	{
-		printk(KERN_WARNING "i2o: Could not allocate procdir!\n");
-		return;
-	}
-
-	i2o_proc_add_device(d, d->proc_entry);
-}
-
-void i2o_proc_add_device(struct i2o_device *dev, struct proc_dir_entry *dir)
-{	
-	i2o_proc_create_entries(dev, generic_dev_entries, dir);
-
-	/* Inform core that we want updates about this device's status */
-	i2o_device_notify_on(dev, &i2o_proc_handler);
-	switch(dev->lct_data.class_id)
-	{
-		case I2O_CLASS_SCSI_PERIPHERAL:
-		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
-			i2o_proc_create_entries(dev, rbs_dev_entries, dir);
-			break;
-		case I2O_CLASS_LAN:
-			i2o_proc_create_entries(dev, lan_entries, dir);
-			switch(dev->lct_data.sub_class)
-			{
-				case I2O_LAN_ETHERNET:
-					i2o_proc_create_entries(dev, lan_eth_entries, dir);
-					break;
-				case I2O_LAN_FDDI:
-					i2o_proc_create_entries(dev, lan_fddi_entries, dir);
-					break;
-				case I2O_LAN_TR:
-					i2o_proc_create_entries(dev, lan_tr_entries, dir);
-					break;
-				default:
-					break;
-			}
-			break;
-		default:
-			break;
-	}
-}
-
-static void i2o_proc_remove_controller(struct i2o_controller *pctrl, 
-				       struct proc_dir_entry *parent)
-{
-	char buff[10];
-	struct i2o_device *dev;
-
-	/* Remove unused device entries */
-	for(dev=pctrl->devices; dev; dev=dev->next)
-		i2o_proc_remove_device(dev);
-
-	if(!atomic_read(&pctrl->proc_entry->count))
-	{
-		sprintf(buff, "iop%d", pctrl->unit);
-
-		i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry);
-
-		remove_proc_entry(buff, parent);
-		pctrl->proc_entry = NULL;
-	}
-}
-
-void i2o_proc_remove_device(struct i2o_device *dev)
-{
-	struct proc_dir_entry *de=dev->proc_entry;
-	char dev_id[10];
-
-	sprintf(dev_id, "%0#5x", dev->lct_data.tid);
-
-	i2o_device_notify_off(dev, &i2o_proc_handler);
-	/* Would it be safe to remove _files_ even if they are in use? */
-	if((de) && (!atomic_read(&de->count)))
-	{
-		i2o_proc_remove_entries(generic_dev_entries, de);
-		switch(dev->lct_data.class_id)
-		{
-			case I2O_CLASS_SCSI_PERIPHERAL:
-			case I2O_CLASS_RANDOM_BLOCK_STORAGE:
-				i2o_proc_remove_entries(rbs_dev_entries, de);
-				break;
-			case I2O_CLASS_LAN:
-			{
-				i2o_proc_remove_entries(lan_entries, de);
-				switch(dev->lct_data.sub_class)
-				{
-				case I2O_LAN_ETHERNET:
-					i2o_proc_remove_entries(lan_eth_entries, de);
-					break;
-				case I2O_LAN_FDDI:
-					i2o_proc_remove_entries(lan_fddi_entries, de);
-					break;
-				case I2O_LAN_TR:
-					i2o_proc_remove_entries(lan_tr_entries, de);
-					break;
-				}
-			}
-			remove_proc_entry(dev_id, dev->controller->proc_entry);
-		}
-	}
-}
-	
-void i2o_proc_dev_del(struct i2o_controller *c, struct i2o_device *d)
-{
-#ifdef DRIVERDEBUG
-	printk(KERN_INFO, "Deleting device %d from iop%d\n", 
-		d->lct_data.tid, c->unit);
-#endif
-
-	i2o_proc_remove_device(d);
-}
-
-static int create_i2o_procfs(void)
-{
-	struct i2o_controller *pctrl = NULL;
-	int i;
-
-	i2o_proc_dir_root = proc_mkdir("i2o", 0);
-	if(!i2o_proc_dir_root)
-		return -1;
-
-	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
-	{
-		pctrl = i2o_find_controller(i);
-		if(pctrl)
-		{
-			i2o_proc_add_controller(pctrl, i2o_proc_dir_root);
-			i2o_unlock_controller(pctrl);
-		}
-	};
-
-	return 0;
-}
-
-static int __exit destroy_i2o_procfs(void)
-{
-	struct i2o_controller *pctrl = NULL;
-	int i;
-
-	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
-	{
-		pctrl = i2o_find_controller(i);
-		if(pctrl)
-		{
-			i2o_proc_remove_controller(pctrl, i2o_proc_dir_root);
-			i2o_unlock_controller(pctrl);
-		}
-	}
-
-	if(!atomic_read(&i2o_proc_dir_root->count))
-		remove_proc_entry("i2o", 0);
-	else
-		return -1;
-
-	return 0;
-}
-
-int __init i2o_proc_init(void)
-{
-	if (i2o_install_handler(&i2o_proc_handler) < 0)
-	{
-		printk(KERN_ERR "i2o_proc: Unable to install PROC handler.\n");
-		return 0;
-	}
-
-	if(create_i2o_procfs())
-		return -EBUSY;
-
-	return 0;
-}
-
-MODULE_AUTHOR("Deepak Saxena");
-MODULE_DESCRIPTION("I2O procfs Handler");
-
-static void __exit i2o_proc_exit(void)
-{
-	destroy_i2o_procfs();
-	i2o_remove_handler(&i2o_proc_handler);
-}
-
-#ifdef MODULE
-module_init(i2o_proc_init);
-#endif
-module_exit(i2o_proc_exit);
-
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/i2o_scsi.c linux/drivers/i2o/i2o_scsi.c
--- v2.4.12/linux/drivers/i2o/i2o_scsi.c	Mon Aug 27 12:41:41 2001
+++ linux/drivers/i2o/i2o_scsi.c	Wed Dec 31 16:00:00 1969
@@ -1,912 +0,0 @@
-/* 
- *  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, 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.
- *
- *  Complications for I2O scsi
- *
- *	o	Each (bus,lun) is a logical device in I2O. We keep a map
- *		table. We spoof failed selection for unmapped units
- *	o	Request sense buffers can come back for free. 
- *	o	Scatter gather is a bit dynamic. We have to investigate at
- *		setup time.
- *	o	Some of our resources are dynamically shared. The i2o core
- *		needs a message reservation protocol to avoid swap v net
- *		deadlocking. We need to back off queue requests.
- *	
- *	In general the firmware wants to help. Where its help isn't performance
- *	useful we just ignore the aid. Its not worth the code in truth.
- *
- *	Fixes:
- *		Steve Ralston	:	Scatter gather now works
- *
- *	To Do
- *		64bit cleanups
- *		Fix the resource management problems.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <asm/dma.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/atomic.h>
-#include <linux/blk.h>
-#include <linux/version.h>
-#include <linux/i2o.h>
-#include "../scsi/scsi.h"
-#include "../scsi/hosts.h"
-#include "../scsi/sd.h"
-#include "i2o_scsi.h"
-
-#define VERSION_STRING        "Version 0.0.1"
-
-#define dprintk(x)
-
-#define MAXHOSTS 32
-
-struct i2o_scsi_host
-{
-	struct i2o_controller *controller;
-	s16 task[16][8];		/* Allow 16 devices for now */
-	unsigned long tagclock[16][8];	/* Tag clock for queueing */
-	s16 bus_task;		/* The adapter TID */
-};
-
-static int scsi_context;
-static int lun_done;
-static int i2o_scsi_hosts;
-
-static u32 *retry[32];
-static struct i2o_controller *retry_ctrl[32];
-static struct timer_list retry_timer;
-static int retry_ct = 0;
-
-static atomic_t queue_depth;
-
-/*
- *	SG Chain buffer support...
- */
-
-#define SG_MAX_FRAGS		64
-
-/*
- *	FIXME: we should allocate one of these per bus we find as we
- *	locate them not in a lump at boot.
- */
- 
-typedef struct _chain_buf
-{
-	u32 sg_flags_cnt[SG_MAX_FRAGS];
-	u32 sg_buf[SG_MAX_FRAGS];
-} chain_buf;
-
-#define SG_CHAIN_BUF_SZ sizeof(chain_buf)
-
-#define SG_MAX_BUFS		(i2o_num_controllers * I2O_SCSI_CAN_QUEUE)
-#define SG_CHAIN_POOL_SZ	(SG_MAX_BUFS * SG_CHAIN_BUF_SZ)
-
-static int max_sg_len = 0;
-static chain_buf *sg_chain_pool = NULL;
-static int sg_chain_tag = 0;
-static int sg_max_frags = SG_MAX_FRAGS;
-
-/*
- *	Retry congested frames. This actually needs pushing down into
- *	i2o core. We should only bother the OSM with this when we can't
- *	queue and retry the frame. Or perhaps we should call the OSM
- *	and its default handler should be this in the core, and this
- *	call a 2nd "I give up" handler in the OSM ?
- */
- 
-static void i2o_retry_run(unsigned long f)
-{
-	int i;
-	unsigned long flags;
-	
-	save_flags(flags);
-	cli();
-
-	for(i=0;i<retry_ct;i++)
-		i2o_post_message(retry_ctrl[i], virt_to_bus(retry[i]));
-	retry_ct=0;
-	
-	restore_flags(flags);
-}
-
-static void flush_pending(void)
-{
-	int i;
-	unsigned long flags;
-	
-	save_flags(flags);
-	cli();
-
-	for(i=0;i<retry_ct;i++)
-	{
-		retry[i][0]&=~0xFFFFFF;
-		retry[i][0]|=I2O_CMD_UTIL_NOP<<24;
-		i2o_post_message(retry_ctrl[i],virt_to_bus(retry[i]));
-	}
-	retry_ct=0;
-	
-	restore_flags(flags);
-}
-
-static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
-{
-	Scsi_Cmnd *current_command;
-	u32 *m = (u32 *)msg;
-	u8 as,ds,st;
-	
-	if(m[0] & (1<<13))
-	{
-		printk("IOP fail.\n");
-		printk("From %d To %d Cmd %d.\n",
-			(m[1]>>12)&0xFFF,
-			m[1]&0xFFF,
-			m[1]>>24);
-		printk("Failure Code %d.\n", m[4]>>24);
-		if(m[4]&(1<<16))
-			printk("Format error.\n");
-		if(m[4]&(1<<17))
-			printk("Path error.\n");
-		if(m[4]&(1<<18))
-			printk("Path State.\n");
-		if(m[4]&(1<<18))
-			printk("Congestion.\n");
-		
-		m=(u32 *)bus_to_virt(m[7]);
-		printk("Failing message is %p.\n", m);
-		
-		if((m[4]&(1<<18)) && retry_ct < 32)
-		{
-			retry_ctrl[retry_ct]=c;
-			retry[retry_ct]=m;
-			if(!retry_ct++)
-			{
-				retry_timer.expires=jiffies+1;
-				add_timer(&retry_timer);
-			}
-		}
-		else
-		{
-			/* Create a scsi error for this */
-			current_command = (Scsi_Cmnd *)m[3];
-			printk("Aborted %ld\n", current_command->serial_number);
-
-			spin_lock_irq(&io_request_lock);			
-			current_command->result = DID_ERROR << 16;
-			current_command->scsi_done(current_command);
-			spin_unlock_irq(&io_request_lock);			
-			
-			/* Now flush the message by making it a NOP */
-			m[0]&=0x00FFFFFF;
-			m[0]|=(I2O_CMD_UTIL_NOP)<<24;
-			i2o_post_message(c,virt_to_bus(m));
-		}
-		return;
-	}
-			
-	
-	/*
-	 *	Low byte is device status, next is adapter status,
-	 *	(then one byte reserved), then request status.
-	 */
-	ds=(u8)m[4]; 
-	as=(u8)(m[4]>>8);
-	st=(u8)(m[4]>>24);
-	
-	dprintk(("i2o got a scsi reply %08X: ", m[0]));
-	dprintk(("m[2]=%08X: ", m[2]));
-	dprintk(("m[4]=%08X\n", m[4]));
-
-	if(m[2]&0x80000000)
-	{
-		if(m[2]&0x40000000)
-		{
-			dprintk(("Event.\n"));
-			lun_done=1;
-			return;
-		}
-		printk(KERN_ERR "i2o_scsi: bus reset reply.\n");
-		return;
-	}
-	
-	current_command = (Scsi_Cmnd *)m[3];
-	
-	/*
-	 *	Is this a control request coming back - eg an abort ?
-	 */
-	 
-	if(current_command==NULL)
-	{
-		if(st)
-			dprintk(("SCSI abort: %08X", m[4]));
-		dprintk(("SCSI abort completed.\n"));
-		return;
-	}
-	
-	dprintk(("Completed %ld\n", current_command->serial_number));
-	
-	atomic_dec(&queue_depth);
-	
-	if(st == 0x06)
-	{
-		if(m[5] < current_command->underflow)
-		{
-			int i;
-			printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X\n",
-				m[5], current_command->underflow);
-			printk("Cmd: ");
-			for(i=0;i<15;i++)
-				printk("%02X ", current_command->cmnd[i]);
-			printk(".\n");
-		}
-		else st=0;
-	}
-	
-	if(st)
-	{
-		/* An error has occurred */
-
-		dprintk((KERN_DEBUG "SCSI error %08X", m[4]));
-			
-		if (as == 0x0E) 
-			/* SCSI Reset */
-			current_command->result = DID_RESET << 16;
-		else if (as == 0x0F)
-			current_command->result = DID_PARITY << 16;
-		else
-			current_command->result = DID_ERROR << 16;
-	}
-	else
-		/*
-		 *	It worked maybe ?
-		 */		
-		current_command->result = DID_OK << 16 | ds;
-	spin_lock(&io_request_lock);
-	current_command->scsi_done(current_command);
-	spin_unlock(&io_request_lock);
-	return;
-}
-
-struct i2o_handler i2o_scsi_handler=
-{
-	i2o_scsi_reply,
-	NULL,
-	NULL,
-	NULL,
-	"I2O SCSI OSM",
-	0,
-	I2O_CLASS_SCSI_PERIPHERAL
-};
-
-static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun)
-{
-	u8 reply[8];
-	
-	if(i2o_query_scalar(c, d->lct_data.tid, 0, 3, reply, 4)<0)
-		return -1;
-		
-	*target=reply[0];
-	
-	if(i2o_query_scalar(c, d->lct_data.tid, 0, 4, reply, 8)<0)
-		return -1;
-
-	*lun=reply[1];
-
-	dprintk(("SCSI (%d,%d)\n", *target, *lun));
-	return 0;
-}
-
-void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
-{
-	struct i2o_device *unit;
-	struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata;
-	int lun;
-	int target;
-	
-	h->controller=c;
-	h->bus_task=d->lct_data.tid;
-	
-	for(target=0;target<16;target++)
-		for(lun=0;lun<8;lun++)
-			h->task[target][lun] = -1;
-			
-	for(unit=c->devices;unit!=NULL;unit=unit->next)
-	{
-		dprintk(("Class %03X, parent %d, want %d.\n",
-			unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid));
-			
-		/* Only look at scsi and fc devices */
-		if (    (unit->lct_data.class_id != I2O_CLASS_SCSI_PERIPHERAL)
-		     && (unit->lct_data.class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL)
-		   )
-			continue;
-
-		/* On our bus ? */
-		dprintk(("Found a disk (%d).\n", unit->lct_data.tid));
-		if ((unit->lct_data.parent_tid == d->lct_data.tid)
-		     || (unit->lct_data.parent_tid == d->lct_data.parent_tid)
-		   )
-		{
-			u16 limit;
-			dprintk(("Its ours.\n"));
-			if(i2o_find_lun(c, unit, &target, &lun)==-1)
-			{
-				printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data.tid);
-				continue;
-			}
-			dprintk(("Found disk %d %d.\n", target, lun));
-			h->task[target][lun]=unit->lct_data.tid;
-			h->tagclock[target][lun]=jiffies;
-
-			/* Get the max fragments/request */
-			i2o_query_scalar(c, d->lct_data.tid, 0xF103, 3, &limit, 2);
-			
-			/* sanity */
-			if ( limit == 0 )
-			{
-				printk(KERN_WARNING "i2o_scsi: Ignoring unreasonable SG limit of 0 from IOP!\n");
-				limit = 1;
-			}
-			
-			shpnt->sg_tablesize = limit;
-
-			dprintk(("i2o_scsi: set scatter-gather to %d.\n", 
-				shpnt->sg_tablesize));
-		}
-	}		
-}
-
-int i2o_scsi_detect(Scsi_Host_Template * tpnt)
-{
-	unsigned long flags;
-	struct Scsi_Host *shpnt = NULL;
-	int i;
-	int count;
-
-	printk("i2o_scsi.c: %s\n", VERSION_STRING);
-
-	if(i2o_install_handler(&i2o_scsi_handler)<0)
-	{
-		printk(KERN_ERR "i2o_scsi: Unable to install OSM handler.\n");
-		return 0;
-	}
-	scsi_context = i2o_scsi_handler.context;
-	
-	if((sg_chain_pool = kmalloc(SG_CHAIN_POOL_SZ, GFP_KERNEL)) == NULL)
-	{
-		printk("i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ);
-		printk("i2o_scsi: SG chaining DISABLED!\n");
-		sg_max_frags = 11;
-	}
-	else
-	{
-		printk("  chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool);
-		printk("  (%d byte buffers X %d can_queue X %d i2o controllers)\n",
-				SG_CHAIN_BUF_SZ, I2O_SCSI_CAN_QUEUE, i2o_num_controllers);
-		sg_max_frags = SG_MAX_FRAGS;    // 64
-	}
-	
-	init_timer(&retry_timer);
-	retry_timer.data = 0UL;
-	retry_timer.function = i2o_retry_run;
-	
-//	printk("SCSI OSM at %d.\n", scsi_context);
-
-	for (count = 0, i = 0; i < MAX_I2O_CONTROLLERS; i++)
-	{
-		struct i2o_controller *c=i2o_find_controller(i);
-		struct i2o_device *d;
-		/*
-		 *	This controller doesn't exist.
-		 */
-		
-		if(c==NULL)
-			continue;
-			
-		/*
-		 *	Fixme - we need some altered device locking. This
-		 *	is racing with device addition in theory. Easy to fix.
-		 */
-		
-		for(d=c->devices;d!=NULL;d=d->next)
-		{
-			/*
-			 *	bus_adapter, SCSI (obsolete), or FibreChannel busses only
-			 */
-			if(    (d->lct_data.class_id!=I2O_CLASS_BUS_ADAPTER_PORT)	// bus_adapter
-//			    && (d->lct_data.class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT)	// FC_PORT
-			  )
-				continue;
-		
-			shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host));
-			if(shpnt==NULL)
-				continue;
-			save_flags(flags);
-			cli();
-			shpnt->unique_id = (u32)d;
-			shpnt->io_port = 0;
-			shpnt->n_io_port = 0;
-			shpnt->irq = 0;
-			shpnt->this_id = /* Good question */15;
-			restore_flags(flags);
-			i2o_scsi_init(c, d, shpnt);
-			count++;
-		}
-	}
-	i2o_scsi_hosts = count;
-	
-	if(count==0)
-	{
-		if(sg_chain_pool!=NULL)
-		{
-			kfree(sg_chain_pool);
-			sg_chain_pool = NULL;
-		}
-		flush_pending();
-		del_timer(&retry_timer);
-		i2o_remove_handler(&i2o_scsi_handler);
-	}
-	
-	return count;
-}
-
-int i2o_scsi_release(struct Scsi_Host *host)
-{
-	if(--i2o_scsi_hosts==0)
-	{
-		if(sg_chain_pool!=NULL)
-		{
-			kfree(sg_chain_pool);
-			sg_chain_pool = NULL;
-		}
-		flush_pending();
-		del_timer(&retry_timer);
-		i2o_remove_handler(&i2o_scsi_handler);
-	}
-	return 0;
-}
-
-
-const char *i2o_scsi_info(struct Scsi_Host *SChost)
-{
-	struct i2o_scsi_host *hostdata;
-
-	hostdata = (struct i2o_scsi_host *)SChost->hostdata;
-
-	return(&hostdata->controller->name[0]);
-}
-
-
-/*
- * From the wd93 driver:
- * Returns true if there will be a DATA_OUT phase with this command, 
- * false otherwise.
- * (Thanks to Joerg Dorchain for the research and suggestion.)
- *
- */
-static int is_dir_out(Scsi_Cmnd *cmd)
-{
-	switch (cmd->cmnd[0]) 
-	{
-     		case WRITE_6:           case WRITE_10:          case WRITE_12:
-      		case WRITE_LONG:        case WRITE_SAME:        case WRITE_BUFFER:
-      		case WRITE_VERIFY:      case WRITE_VERIFY_12:      
-      		case COMPARE:           case COPY:              case COPY_VERIFY:
-      		case SEARCH_EQUAL:      case SEARCH_HIGH:       case SEARCH_LOW:
-      		case SEARCH_EQUAL_12:   case SEARCH_HIGH_12:    case SEARCH_LOW_12:      
-      		case FORMAT_UNIT:       case REASSIGN_BLOCKS:   case RESERVE:
-      		case MODE_SELECT:       case MODE_SELECT_10:    case LOG_SELECT:
-      		case SEND_DIAGNOSTIC:   case CHANGE_DEFINITION: case UPDATE_BLOCK:
-      		case SET_WINDOW:        case MEDIUM_SCAN:       case SEND_VOLUME_TAG:
-      		case 0xea:
-        		return 1;
-		default:
-        		return 0;
-	}
-}
-
-int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
-{
-	int i;
-	int tid;
-	struct i2o_controller *c;
-	Scsi_Cmnd *current_command;
-	struct Scsi_Host *host;
-	struct i2o_scsi_host *hostdata;
-	u32 *msg, *mptr;
-	u32 m;
-	u32 *lenptr;
-	int direction;
-	int scsidir;
-	u32 len;
-	u32 reqlen;
-	u32 tag;
-	
-	static int max_qd = 1;
-	
-	/*
-	 *	Do the incoming paperwork
-	 */
-	 
-	host = SCpnt->host;
-	hostdata = (struct i2o_scsi_host *)host->hostdata;
-	SCpnt->scsi_done = done;
-	
-	if(SCpnt->target > 15)
-	{
-		printk(KERN_ERR "i2o_scsi: Wild target %d.\n", SCpnt->target);
-		return -1;
-	}
-	
-	tid = hostdata->task[SCpnt->target][SCpnt->lun];
-	
-	dprintk(("qcmd: Tid = %d\n", tid));
-	
-	current_command = SCpnt;		/* set current command                */
-	current_command->scsi_done = done;	/* set ptr to done function           */
-
-	/* We don't have such a device. Pretend we did the command 
-	   and that selection timed out */
-	
-	if(tid == -1)
-	{
-		SCpnt->result = DID_NO_CONNECT << 16;
-		done(SCpnt);
-		return 0;
-	}
-	
-	dprintk(("Real scsi messages.\n"));
-
-	c = hostdata->controller;
-	
-	/*
-	 *	Obtain an I2O message. Right now we _have_ to obtain one
-	 *	until the scsi layer stuff is cleaned up.
-	 */	
-	 
-	do
-	{
-		mb();
-		m = I2O_POST_READ32(c);
-	}
-	while(m==0xFFFFFFFF);
-	msg = (u32 *)(c->mem_offset + m);
-	
-	/*
-	 *	Put together a scsi execscb message
-	 */
-	
-	len = SCpnt->request_bufflen;
-	direction = 0x00000000;			// SGL IN  (osm<--iop)
-	
-	/*
-	 *	The scsi layer should be handling this stuff
-	 */
-	
-	scsidir = 0x00000000;			// DATA NO XFER
-	if(len)
-	{
-		if(is_dir_out(SCpnt))
-		{
-			direction=0x04000000;	// SGL OUT  (osm-->iop)
-			scsidir  =0x80000000;	// DATA OUT (iop-->dev)
-		}
-		else
-		{
-			scsidir  =0x40000000;	// DATA IN  (iop<--dev)
-		}
-	}
-	
-	__raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]);
-	__raw_writel(scsi_context, &msg[2]);	/* So the I2O layer passes to us */
-	/* Sorry 64bit folks. FIXME */
-	__raw_writel((u32)SCpnt, &msg[3]);	/* We want the SCSI control block back */
-
-	/* LSI_920_PCI_QUIRK
-	 *
-	 *	Intermittant observations of msg frame word data corruption
-	 *	observed on msg[4] after:
-	 *	  WRITE, READ-MODIFY-WRITE
-	 *	operations.  19990606 -sralston
-	 *
-	 *	(Hence we build this word via tag. Its good practice anyway
-	 *	 we don't want fetches over PCI needlessly)
-	 */
-
-	tag=0;
-	
-	/*
-	 *	Attach tags to the devices
-	 */	
-	if(SCpnt->device->tagged_supported)
-	{
-		/*
-		 *	Some drives are too stupid to handle fairness issues
-		 *	with tagged queueing. We throw in the odd ordered
-		 *	tag to stop them starving themselves.
-		 */
-		if((jiffies - hostdata->tagclock[SCpnt->target][SCpnt->lun]) > (5*HZ))
-		{
-			tag=0x01800000;		/* ORDERED! */
-			hostdata->tagclock[SCpnt->target][SCpnt->lun]=jiffies;
-		}
-		else
-		{
-			/* Hmmm...  I always see value of 0 here,
-			 *  of which {HEAD_OF, ORDERED, SIMPLE} are NOT!  -sralston
-			 */
-			if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
-				tag=0x01000000;
-			else if(SCpnt->tag == ORDERED_QUEUE_TAG)
-				tag=0x01800000;
-		}
-	}
-
-	/* Direction, disconnect ok, tag, CDBLen */
-	__raw_writel(scsidir|0x20000000|SCpnt->cmd_len|tag, &msg[4]);
-
-	mptr=msg+5;
-
-	/* 
-	 *	Write SCSI command into the message - always 16 byte block 
-	 */
-	 
-	memcpy_toio(mptr, SCpnt->cmnd, 16);
-	mptr+=4;
-	lenptr=mptr++;		/* Remember me - fill in when we know */
-	
-	reqlen = 12;		// SINGLE SGE
-	
-	/*
-	 *	Now fill in the SGList and command 
-	 *
-	 *	FIXME: we need to set the sglist limits according to the 
-	 *	message size of the I2O controller. We might only have room
-	 *	for 6 or so worst case
-	 */
-	
-	if(SCpnt->use_sg)
-	{
-		struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer;
-		int chain = 0;
-		
-		len = 0;
-
-		if((sg_max_frags > 11) && (SCpnt->use_sg > 11))
-		{
-			chain = 1;
-			/*
-			 *	Need to chain!
-			 */
-			__raw_writel(direction|0xB0000000|(SCpnt->use_sg*2*4), mptr++);
-			__raw_writel(virt_to_bus(sg_chain_pool + sg_chain_tag), mptr);
-			mptr = (u32*)(sg_chain_pool + sg_chain_tag);
-			if (SCpnt->use_sg > max_sg_len)
-			{
-				max_sg_len = SCpnt->use_sg;
-				printk("i2o_scsi: Chain SG! SCpnt=%p, SG_FragCnt=%d, SG_idx=%d\n",
-					SCpnt, SCpnt->use_sg, sg_chain_tag);
-			}
-			if ( ++sg_chain_tag == SG_MAX_BUFS )
-				sg_chain_tag = 0;
-			for(i = 0 ; i < SCpnt->use_sg; i++)
-			{
-				*mptr++=direction|0x10000000|sg->length;
-				len+=sg->length;
-				*mptr++=virt_to_bus(sg->address);
-				sg++;
-			}
-			mptr[-2]=direction|0xD0000000|(sg-1)->length;
-		}
-		else
-		{		
-			for(i = 0 ; i < SCpnt->use_sg; i++)
-			{
-				__raw_writel(direction|0x10000000|sg->length, mptr++);
-				len+=sg->length;
-				__raw_writel(virt_to_bus(sg->address), mptr++);
-				sg++;
-			}
-
-			/* Make this an end of list. Again evade the 920 bug and
-			   unwanted PCI read traffic */
-		
-			__raw_writel(direction|0xD0000000|(sg-1)->length, &mptr[-2]);
-		}
-		
-		if(!chain)
-			reqlen = mptr - msg;
-		
-		__raw_writel(len, lenptr);
-		
-		if(len != SCpnt->underflow)
-			printk("Cmd len %08X Cmd underflow %08X\n",
-				len, SCpnt->underflow);
-	}
-	else
-	{
-		dprintk(("non sg for %p, %d\n", SCpnt->request_buffer,
-				SCpnt->request_bufflen));
-		__raw_writel(len = SCpnt->request_bufflen, lenptr);
-		if(len == 0)
-		{
-			reqlen = 9;
-		}
-		else
-		{
-			__raw_writel(0xD0000000|direction|SCpnt->request_bufflen, mptr++);
-			__raw_writel(virt_to_bus(SCpnt->request_buffer), mptr++);
-		}
-	}
-	
-	/*
-	 *	Stick the headers on 
-	 */
-
-	__raw_writel(reqlen<<16 | SGL_OFFSET_10, msg);
-	
-	/* Queue the message */
-	i2o_post_message(c,m);
-	
-	atomic_inc(&queue_depth);
-	
-	if(atomic_read(&queue_depth)> max_qd)
-	{
-		max_qd=atomic_read(&queue_depth);
-		printk("Queue depth now %d.\n", max_qd);
-	}
-	
-	mb();
-	dprintk(("Issued %ld\n", current_command->serial_number));
-	
-	return 0;
-}
-
-static void internal_done(Scsi_Cmnd * SCpnt)
-{
-	SCpnt->SCp.Status++;
-}
-
-int i2o_scsi_command(Scsi_Cmnd * SCpnt)
-{
-	i2o_scsi_queuecommand(SCpnt, internal_done);
-	SCpnt->SCp.Status = 0;
-	while (!SCpnt->SCp.Status)
-		barrier();
-	return SCpnt->result;
-}
-
-int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
-{
-	struct i2o_controller *c;
-	struct Scsi_Host *host;
-	struct i2o_scsi_host *hostdata;
-	u32 *msg;
-	u32 m;
-	int tid;
-	
-	printk("i2o_scsi: Aborting command block.\n");
-	
-	host = SCpnt->host;
-	hostdata = (struct i2o_scsi_host *)host->hostdata;
-	tid = hostdata->task[SCpnt->target][SCpnt->lun];
-	if(tid==-1)
-	{
-		printk(KERN_ERR "impossible command to abort.\n");
-		return SCSI_ABORT_NOT_RUNNING;
-	}
-	c = hostdata->controller;
-	
-	/*
-	 *	Obtain an I2O message. Right now we _have_ to obtain one
-	 *	until the scsi layer stuff is cleaned up.
-	 */	
-	 
-	do
-	{
-		mb();
-		m = I2O_POST_READ32(c);
-	}
-	while(m==0xFFFFFFFF);
-	msg = (u32 *)(c->mem_offset + m);
-	
-	__raw_writel(FIVE_WORD_MSG_SIZE, &msg[0]);
-	__raw_writel(I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid, &msg[1]);
-	__raw_writel(scsi_context, &msg[2]);
-	__raw_writel(0, &msg[3]);	/* Not needed for an abort */
-	__raw_writel((u32)SCpnt, &msg[4]);	
-	wmb();
-	i2o_post_message(c,m);
-	wmb();
-	return SCSI_ABORT_PENDING;
-}
-
-int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
-{
-	int tid;
-	struct i2o_controller *c;
-	struct Scsi_Host *host;
-	struct i2o_scsi_host *hostdata;
-	u32 m;
-	u32 *msg;
-
-	/*
-	 *	Find the TID for the bus
-	 */
-
-	printk("i2o_scsi: Attempting to reset the bus.\n");
-	
-	host = SCpnt->host;
-	hostdata = (struct i2o_scsi_host *)host->hostdata;
-	tid = hostdata->bus_task;
-	c = hostdata->controller;
-
-	/*
-	 *	Now send a SCSI reset request. Any remaining commands
-	 *	will be aborted by the IOP. We need to catch the reply
-	 *	possibly ?
-	 */
-	 
-	m = I2O_POST_READ32(c);
-	
-	/*
-	 *	No free messages, try again next time - no big deal
-	 */
-	 
-	if(m == 0xFFFFFFFF)
-		return SCSI_RESET_PUNT;
-	
-	msg = (u32 *)(c->mem_offset + m);
-	__raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]);
-	__raw_writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, &msg[1]);
-	__raw_writel(scsi_context|0x80000000, &msg[2]);
-	/* We use the top bit to split controller and unit transactions */
-	/* Now store unit,tid so we can tie the completion back to a specific device */
-	__raw_writel(c->unit << 16 | tid, &msg[3]);
-	wmb();
-	i2o_post_message(c,m);
-	return SCSI_RESET_PENDING;
-}
-
-/*
- *	This is anyones guess quite frankly.
- */
- 
-int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip)
-{
-	int size;
-
-	size = disk->capacity;
-	ip[0] = 64;		/* heads                        */
-	ip[1] = 32;		/* sectors                      */
-	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */
-		ip[0] = 255;	/* heads                        */
-		ip[1] = 63;	/* sectors                      */
-		ip[2] = size / (255 * 63);	/* cylinders                    */
-	}
-	return 0;
-}
-
-MODULE_AUTHOR("Red Hat Software");
-
-static Scsi_Host_Template driver_template = I2OSCSI;
-
-#include "../scsi/scsi_module.c"
diff -u --recursive --new-file v2.4.12/linux/drivers/i2o/i2o_scsi.h linux/drivers/i2o/i2o_scsi.h
--- v2.4.12/linux/drivers/i2o/i2o_scsi.h	Mon Dec 11 13:20:04 2000
+++ linux/drivers/i2o/i2o_scsi.h	Wed Dec 31 16:00:00 1969
@@ -1,47 +0,0 @@
-#ifndef _I2O_SCSI_H
-#define _I2O_SCSI_H
-
-#if !defined(LINUX_VERSION_CODE)
-#include <linux/version.h>
-#endif
-
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
-#include <linux/types.h>
-#include <linux/kdev_t.h>
-
-#define I2O_SCSI_ID 15
-#define I2O_SCSI_CAN_QUEUE 4
-#define I2O_SCSI_CMD_PER_LUN 6
-
-extern int i2o_scsi_detect(Scsi_Host_Template *);
-extern const char *i2o_scsi_info(struct Scsi_Host *);
-extern int i2o_scsi_command(Scsi_Cmnd *);
-extern int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int i2o_scsi_abort(Scsi_Cmnd *);
-extern int i2o_scsi_reset(Scsi_Cmnd *, unsigned int);
-extern int i2o_scsi_bios_param(Disk *, kdev_t, int *);
-extern void i2o_scsi_setup(char *str, int *ints);
-extern int i2o_scsi_release(struct Scsi_Host *host);
-
-#define I2OSCSI {                                          \
-		  next: NULL,				    \
-                  proc_name:         "i2o_scsi",   \
-                  name:              "I2O SCSI Layer", 	    \
-                  detect:            i2o_scsi_detect,       \
-                  release:	     i2o_scsi_release,	    \
-                  info:              i2o_scsi_info,         \
-                  command:           i2o_scsi_command,      \
-                  queuecommand:      i2o_scsi_queuecommand, \
-                  abort:             i2o_scsi_abort,        \
-                  reset:             i2o_scsi_reset,        \
-                  bios_param:        i2o_scsi_bios_param,   \
-                  can_queue:         I2O_SCSI_CAN_QUEUE,    \
-                  this_id:           I2O_SCSI_ID,           \
-                  sg_tablesize:      8,                     \
-                  cmd_per_lun:       I2O_SCSI_CMD_PER_LUN,  \
-                  unchecked_isa_dma: 0,                     \
-                  use_clustering:    ENABLE_CLUSTERING     \
-                  }
-
-#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/ide/hd.c linux/drivers/ide/hd.c
--- v2.4.12/linux/drivers/ide/hd.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/ide/hd.c	Mon Oct 15 13:27:42 2001
@@ -640,7 +640,7 @@
 
          	case BLKGETSIZE:   /* Return device size */
 			return put_user(hd[MINOR(inode->i_rdev)].nr_sects, 
-					(long *) arg);
+					(unsigned long *) arg);
          	case BLKGETSIZE64:
 			return put_user((u64)hd[MINOR(inode->i_rdev)].nr_sects << 9, 
 					(u64 *) arg);
diff -u --recursive --new-file v2.4.12/linux/drivers/ide/hptraid.c linux/drivers/ide/hptraid.c
--- v2.4.12/linux/drivers/ide/hptraid.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/ide/hptraid.c	Mon Oct 15 13:27:42 2001
@@ -15,6 +15,8 @@
    Based on work
    	Copyleft  (C) 2001 by Wilfried Weissmann <wweissmann@gmx.at>
 	Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
+   Based on work done by Søren Schmidt for FreeBSD
+
    
 */
 
@@ -83,8 +85,8 @@
 			if (!arg)  return -EINVAL;
 			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
 			if (MINOR(inode->i_rdev)&15)
-				return put_user(sectors, (long *) arg);
-			return put_user(raid[minor].sectors , (long *) arg);
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
 			break;
 			
 
diff -u --recursive --new-file v2.4.12/linux/drivers/ide/hptraid.h linux/drivers/ide/hptraid.h
--- v2.4.12/linux/drivers/ide/hptraid.h	Sun Sep 23 11:40:57 2001
+++ linux/drivers/ide/hptraid.h	Thu Oct 11 09:43:29 2001
@@ -1,4 +1,32 @@
-
+/*-
+ * Copyright (c) 2000,2001 Søren Schmidt <sos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+                            
 struct highpoint_raid_conf
 {
        int8_t  filler1[32];
diff -u --recursive --new-file v2.4.12/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- v2.4.12/linux/drivers/ide/ide-cd.c	Mon Aug 27 12:41:41 2001
+++ linux/drivers/ide/ide-cd.c	Thu Oct 18 13:18:22 2001
@@ -2409,7 +2409,7 @@
 		 * any other way to detect this...
 		 */
 		if (sense.sense_key == NOT_READY) {
-			if (sense.asc == 0x3a && (!sense.ascq||sense.ascq == 1))
+			if (sense.asc == 0x3a && sense.ascq == 1)
 				return CDS_NO_DISC;
 			else
 				return CDS_TRAY_OPEN;
@@ -3059,3 +3059,4 @@
 
 module_init(ide_cdrom_init);
 module_exit(ide_cdrom_exit);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- v2.4.12/linux/drivers/ide/ide-disk.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/ide/ide-disk.c	Thu Oct 11 09:14:32 2001
@@ -890,3 +890,4 @@
 
 module_init(idedisk_init);
 module_exit(idedisk_exit);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c
--- v2.4.12/linux/drivers/ide/ide-floppy.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/ide/ide-floppy.c	Thu Oct 11 09:14:32 2001
@@ -2116,3 +2116,4 @@
 
 module_init(idefloppy_init);
 module_exit(idefloppy_exit);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
--- v2.4.12/linux/drivers/ide/ide-probe.c	Sun Sep 23 11:40:57 2001
+++ linux/drivers/ide/ide-probe.c	Thu Oct 11 09:14:32 2001
@@ -928,4 +928,5 @@
 {
 	ide_probe = NULL;
 }
+MODULE_LICENSE("GPL");
 #endif /* MODULE */
diff -u --recursive --new-file v2.4.12/linux/drivers/ide/ide.c linux/drivers/ide/ide.c
--- v2.4.12/linux/drivers/ide/ide.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/ide/ide.c	Mon Oct 15 13:27:42 2001
@@ -2661,7 +2661,7 @@
 		}
 
 	 	case BLKGETSIZE:   /* Return device size */
-			return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg);
+			return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (unsigned long *) arg);
 	 	case BLKGETSIZE64:
 			return put_user((u64)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects << 9, (u64 *) arg);
 
@@ -3749,6 +3749,7 @@
 #ifdef MODULE
 char *options = NULL;
 MODULE_PARM(options,"s");
+MODULE_LICENSE("GPL");
 
 static void __init parse_options (char *line)
 {
diff -u --recursive --new-file v2.4.12/linux/drivers/ide/pdcraid.c linux/drivers/ide/pdcraid.c
--- v2.4.12/linux/drivers/ide/pdcraid.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/ide/pdcraid.c	Mon Oct 15 13:27:42 2001
@@ -111,8 +111,8 @@
  			if (!arg)  return -EINVAL;
 			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
 			if (MINOR(inode->i_rdev)&15)
-				return put_user(sectors, (long *) arg);
-			return put_user(raid[minor].sectors , (long *) arg);
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
 			break;
 			
 
diff -u --recursive --new-file v2.4.12/linux/drivers/ide/rapide.c linux/drivers/ide/rapide.c
--- v2.4.12/linux/drivers/ide/rapide.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/ide/rapide.c	Thu Oct 11 09:14:32 2001
@@ -69,6 +69,7 @@
 }
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
 
 int init_module (void)
 {
diff -u --recursive --new-file v2.4.12/linux/drivers/ieee1394/Makefile linux/drivers/ieee1394/Makefile
--- v2.4.12/linux/drivers/ieee1394/Makefile	Tue Oct  9 17:06:51 2001
+++ linux/drivers/ieee1394/Makefile	Wed Oct 17 14:19:20 2001
@@ -4,11 +4,11 @@
 
 O_TARGET := ieee1394drv.o
 
-export-objs := ieee1394_syms.o ohci1394.o
+export-objs := ieee1394_core.o ohci1394.o
 
 list-multi := ieee1394.o
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
-		 highlevel.o csr.o nodemgr.o ieee1394_syms.o
+		 highlevel.o csr.o nodemgr.o
 
 obj-$(CONFIG_IEEE1394) += ieee1394.o
 obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
diff -u --recursive --new-file v2.4.12/linux/drivers/ieee1394/ieee1394.h linux/drivers/ieee1394/ieee1394.h
--- v2.4.12/linux/drivers/ieee1394/ieee1394.h	Mon Dec 11 13:20:17 2000
+++ linux/drivers/ieee1394/ieee1394.h	Wed Oct 17 14:19:20 2001
@@ -47,7 +47,10 @@
 
 #define SPEED_100                0x0
 #define SPEED_200                0x1
-#define SPEED_400                0x2 
+#define SPEED_400                0x2
+
+/* Maps speed values above to a string representation */
+extern const char *hpsb_speedto_str[];
 
 #define SELFID_PWRCL_NO_POWER    0x0
 #define SELFID_PWRCL_PROVIDE_15W 0x1
diff -u --recursive --new-file v2.4.12/linux/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c
--- v2.4.12/linux/drivers/ieee1394/ieee1394_core.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/ieee1394/ieee1394_core.c	Wed Oct 17 14:19:20 2001
@@ -30,6 +30,7 @@
 #include "ieee1394_transactions.h"
 #include "csr.h"
 #include "nodemgr.h"
+#include "ieee1394_hotplug.h"
 
 /*
  * Disable the nodemgr detection and config rom reading functionality.
@@ -38,8 +39,13 @@
 MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
 static int disable_nodemgr = 0;
 
+/* We are GPL, so treat us special */
+MODULE_LICENSE("GPL");
+
 static kmem_cache_t *hpsb_packet_cache;
 
+/* Some globals used */
+const char *hpsb_speedto_str[] = { "S100", "S200", "S400" };
 
 static void dump_packet(const char *text, quadlet_t *data, int size)
 {
@@ -805,3 +811,68 @@
 
 module_init(ieee1394_init);
 module_exit(ieee1394_cleanup);
+
+/* Exported symbols */
+EXPORT_SYMBOL(hpsb_register_lowlevel);
+EXPORT_SYMBOL(hpsb_unregister_lowlevel);
+EXPORT_SYMBOL(hpsb_get_host);
+EXPORT_SYMBOL(hpsb_inc_host_usage);
+EXPORT_SYMBOL(hpsb_dec_host_usage);
+EXPORT_SYMBOL(hpsb_speedto_str);
+
+EXPORT_SYMBOL(alloc_hpsb_packet);
+EXPORT_SYMBOL(free_hpsb_packet);
+EXPORT_SYMBOL(hpsb_send_packet);
+EXPORT_SYMBOL(hpsb_reset_bus);
+EXPORT_SYMBOL(hpsb_bus_reset);
+EXPORT_SYMBOL(hpsb_selfid_received);
+EXPORT_SYMBOL(hpsb_selfid_complete);
+EXPORT_SYMBOL(hpsb_packet_sent);
+EXPORT_SYMBOL(hpsb_packet_received);
+
+EXPORT_SYMBOL(get_tlabel);
+EXPORT_SYMBOL(free_tlabel);
+EXPORT_SYMBOL(fill_async_readquad);
+EXPORT_SYMBOL(fill_async_readquad_resp);
+EXPORT_SYMBOL(fill_async_readblock);
+EXPORT_SYMBOL(fill_async_readblock_resp);
+EXPORT_SYMBOL(fill_async_writequad);
+EXPORT_SYMBOL(fill_async_writeblock);
+EXPORT_SYMBOL(fill_async_write_resp);
+EXPORT_SYMBOL(fill_async_lock);
+EXPORT_SYMBOL(fill_async_lock_resp);
+EXPORT_SYMBOL(fill_iso_packet);
+EXPORT_SYMBOL(fill_phy_packet);
+EXPORT_SYMBOL(hpsb_make_readqpacket);
+EXPORT_SYMBOL(hpsb_make_readbpacket);
+EXPORT_SYMBOL(hpsb_make_writeqpacket);
+EXPORT_SYMBOL(hpsb_make_writebpacket);
+EXPORT_SYMBOL(hpsb_make_lockpacket);
+EXPORT_SYMBOL(hpsb_make_phypacket);
+EXPORT_SYMBOL(hpsb_packet_success);
+EXPORT_SYMBOL(hpsb_make_packet);
+EXPORT_SYMBOL(hpsb_read);
+EXPORT_SYMBOL(hpsb_write);
+EXPORT_SYMBOL(hpsb_lock);
+
+EXPORT_SYMBOL(hpsb_register_highlevel);
+EXPORT_SYMBOL(hpsb_unregister_highlevel);
+EXPORT_SYMBOL(hpsb_register_addrspace);
+EXPORT_SYMBOL(hpsb_listen_channel);
+EXPORT_SYMBOL(hpsb_unlisten_channel);
+EXPORT_SYMBOL(highlevel_read);
+EXPORT_SYMBOL(highlevel_write);
+EXPORT_SYMBOL(highlevel_lock);
+EXPORT_SYMBOL(highlevel_lock64);
+EXPORT_SYMBOL(highlevel_add_host);
+EXPORT_SYMBOL(highlevel_remove_host);
+EXPORT_SYMBOL(highlevel_host_reset);
+EXPORT_SYMBOL(highlevel_add_one_host);
+
+EXPORT_SYMBOL(hpsb_guid_get_entry);
+EXPORT_SYMBOL(hpsb_nodeid_get_entry);
+EXPORT_SYMBOL(hpsb_get_host_by_ne);
+EXPORT_SYMBOL(hpsb_guid_fill_packet);
+EXPORT_SYMBOL(hpsb_register_protocol);
+EXPORT_SYMBOL(hpsb_unregister_protocol);
+EXPORT_SYMBOL(hpsb_release_unit_directory);
diff -u --recursive --new-file v2.4.12/linux/drivers/ieee1394/ieee1394_types.h linux/drivers/ieee1394/ieee1394_types.h
--- v2.4.12/linux/drivers/ieee1394/ieee1394_types.h	Tue Oct  9 17:06:51 2001
+++ linux/drivers/ieee1394/ieee1394_types.h	Wed Oct 17 14:19:20 2001
@@ -20,6 +20,23 @@
 #define INIT_TQ_HEAD(tq) INIT_LIST_HEAD(&(tq))
 #endif
 
+/* This showed up around this time */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,12)
+
+# ifndef MODULE_LICENSE
+# define MODULE_LICENSE(x)
+# endif
+
+# ifndef min
+# define min(x,y) ({ \
+	const typeof(x) _x = (x);       \
+	const typeof(y) _y = (y);       \
+	(void) (&_x == &_y);            \
+	_x < _y ? _x : _y; })
+# endif
+
+#endif /* Linux version < 2.4.12 */
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
 #include <asm/spinlock.h>
 #else
@@ -49,6 +66,10 @@
 #define NODE_MASK 0x003f
 #define LOCAL_BUS 0xffc0
 #define ALL_NODES 0x003f
+
+#define NODE_BUS_FMT    "%d:%d"
+#define NODE_BUS_ARGS(nodeid) \
+	(nodeid & NODE_MASK), ((nodeid & BUS_MASK) >> 6)
 
 #define HPSB_PRINT(level, fmt, args...) printk(level "ieee1394: " fmt "\n" , ## args)
 
diff -u --recursive --new-file v2.4.12/linux/drivers/ieee1394/nodemgr.c linux/drivers/ieee1394/nodemgr.c
--- v2.4.12/linux/drivers/ieee1394/nodemgr.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/ieee1394/nodemgr.c	Wed Oct 17 14:19:20 2001
@@ -27,11 +27,8 @@
 #include "nodemgr.h"
 
 
-#define NODE_BUS_FMT	"%d:%d"
-#define NODE_BUS_ARGS(nodeid) \
-	(nodeid & NODE_MASK), ((nodeid & BUS_MASK) >> 6)
-
-/* Basically what we do here is start off retrieving the bus_info block.
+/* 
+ * Basically what we do here is start off retrieving the bus_info block.
  * From there will fill in some info about the node, verify it is of IEEE
  * 1394 type, and that the crc checks out ok. After that we start off with
  * the root directory, and subdirectories. To do this, we retrieve the
@@ -42,9 +39,7 @@
  * We verify CRC's along the way for each directory/block/leaf. The
  * entire node structure is generic, and simply stores the information in
  * a way that's easy to parse by the protocol interface.
- *
- * XXX: Most of this isn't done yet :)  */
-
+ */
 
 static LIST_HEAD(node_list);
 static rwlock_t node_lock = RW_LOCK_UNLOCKED;
diff -u --recursive --new-file v2.4.12/linux/drivers/ieee1394/sbp2.c linux/drivers/ieee1394/sbp2.c
--- v2.4.12/linux/drivers/ieee1394/sbp2.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/ieee1394/sbp2.c	Wed Oct 17 14:19:20 2001
@@ -130,6 +130,10 @@
  *	  add some init code to the kernel to support this... and modules are much
  *	  more flexible anyway.   ;-)
  *
+ *     - The scsi stack in recent kernels pass down the data transfer
+ *       direction as scsicmd->sc_data_direction, which we should use
+ *       instead of the sbp2scsi_direction_table.
+ *
  *
  * History:
  *
@@ -355,23 +359,23 @@
 
 
 #if CONFIG_IEEE1394_SBP2_DEBUG >= 2
-#define SBP2_DEBUG(fmt, args...)	HPSB_ERR(fmt, ## args)	
-#define SBP2_INFO(fmt, args...)		HPSB_ERR(fmt, ## args)	
-#define SBP2_NOTICE(fmt, args...)	HPSB_ERR(fmt, ## args)	
-#define SBP2_WARN(fmt, args...)		HPSB_ERR(fmt, ## args)
+#define SBP2_DEBUG(fmt, args...)	HPSB_ERR("sbp2: "fmt, ## args)
+#define SBP2_INFO(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
+#define SBP2_NOTICE(fmt, args...)	HPSB_ERR("sbp2: "fmt, ## args)
+#define SBP2_WARN(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
 #elif CONFIG_IEEE1394_SBP2_DEBUG == 1
-#define SBP2_DEBUG(fmt, args...)	HPSB_DEBUG(fmt, ## args)
-#define SBP2_INFO(fmt, args...)		HPSB_INFO(fmt, ## args)
-#define SBP2_NOTICE(fmt, args...)	HPSB_NOTICE(fmt, ## args)
-#define SBP2_WARN(fmt, args...)		HPSB_WARN(fmt, ## args)
+#define SBP2_DEBUG(fmt, args...)	HPSB_DEBUG("sbp2: "fmt, ## args)
+#define SBP2_INFO(fmt, args...)		HPSB_INFO("sbp2: "fmt, ## args)
+#define SBP2_NOTICE(fmt, args...)	HPSB_NOTICE("sbp2: "fmt, ## args)
+#define SBP2_WARN(fmt, args...)		HPSB_WARN("sbp2: "fmt, ## args)
 #else 
-#define SBP2_DEBUG(fmt, args...)	
-#define SBP2_INFO(fmt, args...)	
-#define SBP2_NOTICE(fmt, args...)	
-#define SBP2_WARN(fmt, args...)	
+#define SBP2_DEBUG(fmt, args...)
+#define SBP2_INFO(fmt, args...)
+#define SBP2_NOTICE(fmt, args...)
+#define SBP2_WARN(fmt, args...)
 #endif
 
-#define SBP2_ERR(fmt, args...)		HPSB_ERR(fmt, ## args)
+#define SBP2_ERR(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
 
 /*
  * Spinlock debugging stuff. I'm playing it safe until the driver has been
@@ -393,6 +397,8 @@
 
 Scsi_Host_Template *global_scsi_tpnt = NULL;
 
+static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 };
+
 static LIST_HEAD(sbp2_host_info_list);
 static int sbp2_host_count = 0;
 
@@ -477,7 +483,7 @@
 		packet = alloc_hpsb_packet(8);
 
 		if (!packet) {
-			SBP2_ERR("sbp2: sbp2util_create_request_packet_pool - packet allocation failed!");
+			SBP2_ERR("sbp2util_create_request_packet_pool - packet allocation failed!");
 			return(-ENOMEM);
 		}
 
@@ -593,7 +599,7 @@
 		list_add_tail(&request_packet->list, &hi->sbp2_req_inuse);
 
 	} else {
-		SBP2_ERR("sbp2: sbp2util_allocate_request_packet - no packets available!");
+		SBP2_ERR("sbp2util_allocate_request_packet - no packets available!");
 	}
 	sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);
 
@@ -766,7 +772,7 @@
 		command->linked = 0;
 		list_add_tail(&command->list, &scsi_id->sbp2_command_orb_inuse);
 	} else {
-		SBP2_ERR("sbp2: sbp2util_allocate_command_orb - No orbs available!");
+		SBP2_ERR("sbp2util_allocate_command_orb - No orbs available!");
 	}
 	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
 	return (command);
@@ -825,7 +831,7 @@
  */
 int sbp2_init(void)
 {
-	SBP2_DEBUG("sbp2: sbp2_init");
+	SBP2_DEBUG("sbp2_init");
 
 	/*
 	 * Register our high level driver with 1394 stack
@@ -833,7 +839,7 @@
 	sbp2_hl_handle = hpsb_register_highlevel(SBP2_DEVICE_NAME, &sbp2_hl_ops);
 
 	if (sbp2_hl_handle == NULL) {
-		SBP2_ERR("sbp2: sbp2 failed to register with ieee1394 highlevel");
+		SBP2_ERR("sbp2 failed to register with ieee1394 highlevel");
 		return(-ENOMEM);
 	}
 
@@ -854,7 +860,7 @@
  */
 void sbp2_cleanup(void)
 {
-	SBP2_DEBUG("sbp2: sbp2_cleanup");
+	SBP2_DEBUG("sbp2_cleanup");
 
 	hpsb_unregister_protocol(&sbp2_driver);
 
@@ -869,7 +875,7 @@
 {
 	struct sbp2scsi_host_info *hi;
 
-	SBP2_DEBUG("sbp2: sbp2_probe");
+	SBP2_DEBUG("sbp2_probe");
 	hi = sbp2_find_host_info(ud->ne->host);
 
 	return sbp2_start_device(hi, ud);
@@ -880,7 +886,7 @@
 	struct sbp2scsi_host_info *hi;
 	struct scsi_id_instance_data *scsi_id = ud->driver_data;
 
-	SBP2_DEBUG("sbp2: sbp2_disconnect");
+	SBP2_DEBUG("sbp2_disconnect");
 	hi = sbp2_find_host_info(ud->ne->host);
 
 	if (hi != NULL)
@@ -893,7 +899,7 @@
 	struct scsi_id_instance_data *scsi_id = ud->driver_data;
 	unsigned long flags;
 
-	SBP2_DEBUG("sbp2: sbp2_update");
+	SBP2_DEBUG("sbp2_update");
 	hi = sbp2_find_host_info(ud->ne->host);
 
 	if (sbp2_reconnect_device(hi, scsi_id)) {
@@ -907,7 +913,7 @@
 			 * unvalidated, so that he gets cleaned up
 			 * later.
 			 */
-			SBP2_ERR("sbp2: sbp2_reconnect_device failed!");
+			SBP2_ERR("sbp2_reconnect_device failed!");
 			sbp2_remove_device(hi, scsi_id);
 			return;
 		}
@@ -940,14 +946,14 @@
 	struct sbp2scsi_host_info *hi;
 	unsigned long flags;
 
-	SBP2_DEBUG("sbp2: sbp2_add_host");
+	SBP2_DEBUG("sbp2_add_host");
 
 	/* Allocate some memory for our host info structure */
 	hi = (struct sbp2scsi_host_info *)kmalloc(sizeof(struct sbp2scsi_host_info),
 						  GFP_KERNEL);
 
 	if (hi == NULL) {
-		SBP2_ERR("sbp2: out of memory in sbp2_add_host");
+		SBP2_ERR("out of memory in sbp2_add_host");
 		return;
 	}
 
@@ -962,7 +968,7 @@
 
 	/* Create our request packet pool (pool of packets for use in I/O) */
 	if (sbp2util_create_request_packet_pool(hi)) {
-		SBP2_ERR("sbp2: sbp2util_create_request_packet_pool failed!");
+		SBP2_ERR("sbp2util_create_request_packet_pool failed!");
 		return;
 	}
 
@@ -1005,7 +1011,7 @@
 	unsigned long flags;
 	int i;
 
-	SBP2_DEBUG("sbp2: sbp2_remove_host");
+	SBP2_DEBUG("sbp2_remove_host");
 
 	sbp2_spin_lock(&sbp2_host_info_lock, flags);
 
@@ -1030,7 +1036,7 @@
 		kfree(hi);
 	}
 	else
-		SBP2_ERR("sbp2: attempt to remove unknown host %p", host);
+		SBP2_ERR("attempt to remove unknown host %p", host);
 
 	sbp2_spin_unlock(&sbp2_host_info_lock, flags);
 }
@@ -1045,7 +1051,7 @@
 	struct node_entry *ne;
 	int i;
 
-	SBP2_DEBUG("sbp2: sbp2_start_device");
+	SBP2_DEBUG("sbp2_start_device");
 	ne = ud->ne;
 
 	/*
@@ -1114,7 +1120,7 @@
 
 		kfree(scsi_id);
 alloc_fail_first:
-		SBP2_ERR ("sbp2: Could not allocate memory for scsi_id");
+		SBP2_ERR ("Could not allocate memory for scsi_id");
 		return(-ENOMEM);
 	}
 	SBP2_DMA_ALLOC("consistent DMA region for login ORB");
@@ -1125,7 +1131,7 @@
 	scsi_id->ne = ne;
 	scsi_id->ud = ud;
 	scsi_id->speed_code = SPEED_100;
-	scsi_id->max_payload_size = MAX_PAYLOAD_S100;
+	scsi_id->max_payload_size = sbp2_speedto_maxrec[SPEED_100];
 	ud->driver_data = scsi_id;
 
 	init_waitqueue_head(&scsi_id->sbp2_login_wait);
@@ -1169,7 +1175,7 @@
 		if (!hi->scsi_id[i]) {
 			hi->scsi_id[i] = scsi_id;
 			scsi_id->id = i;
-			SBP2_DEBUG("sbp2: New SBP-2 device inserted, SCSI ID = %x", (unsigned int) i);
+			SBP2_DEBUG("New SBP-2 device inserted, SCSI ID = %x", (unsigned int) i);
 			break;
 		}
 	}
@@ -1178,7 +1184,7 @@
 	 * Create our command orb pool
 	 */
 	if (sbp2util_create_command_orb_pool(scsi_id, hi)) {
-		SBP2_ERR("sbp2: sbp2util_create_command_orb_pool failed!");
+		SBP2_ERR("sbp2util_create_command_orb_pool failed!");
 		sbp2_remove_device(hi, scsi_id);
 		return -ENOMEM;
 	}
@@ -1187,7 +1193,7 @@
 	 * Make sure we are not out of space
 	 */
 	if (i == SBP2SCSI_MAX_SCSI_IDS) {
-		SBP2_ERR("sbp2: No slots left for SBP-2 device");
+		SBP2_ERR("No slots left for SBP-2 device");
 		sbp2_remove_device(hi, scsi_id);
 		return -EBUSY;
 	}
@@ -1201,7 +1207,7 @@
 		 * Login failed... so, just mark him as unvalidated, so
 		 * that he gets cleaned up later.
 		 */
-		SBP2_ERR("sbp2: sbp2_login_device failed");
+		SBP2_ERR("sbp2_login_device failed");
 		sbp2_remove_device(hi, scsi_id);
 		return -EBUSY;
 	}
@@ -1270,7 +1276,7 @@
 		SBP2_DMA_FREE("single logout orb");
 	}
 
-	SBP2_DEBUG("sbp2: Unvalidated SBP-2 device removed, SCSI ID = %d", 
+	SBP2_DEBUG("Unvalidated SBP-2 device removed, SCSI ID = %d", 
 		   scsi_id->id);
 	hi->scsi_id[scsi_id->id] = NULL;
 	kfree(scsi_id);
@@ -1291,43 +1297,43 @@
 	quadlet_t data[2];
 	unsigned long flags;
 
-	SBP2_DEBUG("sbp2: sbp2_login_device");
+	SBP2_DEBUG("sbp2_login_device");
 
 	if (!scsi_id->login_orb) {
-		SBP2_DEBUG("sbp2: sbp2_login_device: login_orb not alloc'd!");
+		SBP2_DEBUG("sbp2_login_device: login_orb not alloc'd!");
 		return(-EIO);
 	}
 
 	/* Set-up login ORB, assume no password */
 	scsi_id->login_orb->password_hi = 0; 
 	scsi_id->login_orb->password_lo = 0;
-	SBP2_DEBUG("sbp2: sbp2_login_device: password_hi/lo initialized");
+	SBP2_DEBUG("sbp2_login_device: password_hi/lo initialized");
 
 	scsi_id->login_orb->login_response_lo = scsi_id->login_response_dma;
 	scsi_id->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
-	SBP2_DEBUG("sbp2: sbp2_login_device: login_response_hi/lo initialized");
+	SBP2_DEBUG("sbp2_login_device: login_response_hi/lo initialized");
 
 	scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST);
 	scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0);	/* One second reconnect time */
 	scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(1);	/* Exclusive access to device */
 	scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1);		/* Notify us of login complete */
-	SBP2_DEBUG("sbp2: sbp2_login_device: lun_misc initialized");
+	SBP2_DEBUG("sbp2_login_device: lun_misc initialized");
 
 	scsi_id->login_orb->passwd_resp_lengths =
 		ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
-	SBP2_DEBUG("sbp2: sbp2_login_device: passwd_resp_lengths initialized");
+	SBP2_DEBUG("sbp2_login_device: passwd_resp_lengths initialized");
 
 	scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO;
 	scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
 					      SBP2_STATUS_FIFO_ADDRESS_HI);
-	SBP2_DEBUG("sbp2: sbp2_login_device: status FIFO initialized");
+	SBP2_DEBUG("sbp2_login_device: status FIFO initialized");
 
 	/*
 	 * Byte swap ORB if necessary
 	 */
 	sbp2util_cpu_to_be32_buffer(scsi_id->login_orb, sizeof(struct sbp2_login_orb));
 
-	SBP2_DEBUG("sbp2: sbp2_login_device: orb byte-swapped");
+	SBP2_DEBUG("sbp2_login_device: orb byte-swapped");
 
 	/*
 	 * Initialize login response and status fifo
@@ -1335,7 +1341,7 @@
 	memset(scsi_id->login_response, 0, sizeof(struct sbp2_login_response));
 	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
 
-	SBP2_DEBUG("sbp2: sbp2_login_device: login_response/status FIFO memset");
+	SBP2_DEBUG("sbp2_login_device: login_response/status FIFO memset");
 
 	/*
 	 * Ok, let's write to the target's management agent register
@@ -1344,9 +1350,9 @@
 	data[1] = scsi_id->login_orb_dma;
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
-	SBP2_DEBUG("sbp2: sbp2_login_device: prepared to write");
+	SBP2_DEBUG("sbp2_login_device: prepared to write");
 	hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8);
-	SBP2_DEBUG("sbp2: sbp2_login_device: written");
+	SBP2_DEBUG("sbp2_login_device: written");
 
 	/*
 	 * Wait for login status... but, only if the device has not
@@ -1360,18 +1366,18 @@
 		sleep_on_timeout(&scsi_id->sbp2_login_wait, 10*HZ);
 	restore_flags(flags);
 
-	SBP2_DEBUG("sbp2: sbp2_login_device: initial check");
+	SBP2_DEBUG("sbp2_login_device: initial check");
 
 	/*
 	 * Match status to the login orb. If they do not match, it's
 	 * probably because the login timed-out.
 	 */
 	if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) {
-		SBP2_ERR("sbp2: Error logging into SBP-2 device - login timed-out");
+		SBP2_ERR("Error logging into SBP-2 device - login timed-out");
 		return(-EIO);
 	}
 
-	SBP2_DEBUG("sbp2: sbp2_login_device: second check");
+	SBP2_DEBUG("sbp2_login_device: second check");
 
 	/*
 	 * Check status
@@ -1380,7 +1386,7 @@
 	    STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
 	    STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
 
-		SBP2_ERR("sbp2: Error logging into SBP-2 device - login failed");
+		SBP2_ERR("Error logging into SBP-2 device - login failed");
 		return(-EIO);
 	}
 
@@ -1393,9 +1399,9 @@
 	/*
 	 * Grab our command block agent address from the login response.
 	 */
-	SBP2_DEBUG("sbp2: command_block_agent_hi = %x",
+	SBP2_DEBUG("command_block_agent_hi = %x",
 		   (unsigned int)scsi_id->login_response->command_block_agent_hi);
-	SBP2_DEBUG("sbp2: command_block_agent_lo = %x",
+	SBP2_DEBUG("command_block_agent_lo = %x",
 		   (unsigned int)scsi_id->login_response->command_block_agent_lo);
 
 	scsi_id->sbp2_command_block_agent_addr =
@@ -1403,7 +1409,7 @@
 	scsi_id->sbp2_command_block_agent_addr |= ((u64)scsi_id->login_response->command_block_agent_lo);
 	scsi_id->sbp2_command_block_agent_addr &= 0x0000ffffffffffffULL;
 
-	SBP2_INFO("sbp2: Logged into SBP-2 device");
+	SBP2_INFO("Logged into SBP-2 device");
 
 	return(0);
 
@@ -1417,7 +1423,7 @@
 {
 	quadlet_t data[2];
 
-	SBP2_DEBUG("sbp2: sbp2_logout_device");
+	SBP2_DEBUG("sbp2_logout_device");
 
 	/*
 	 * Set-up logout ORB
@@ -1455,7 +1461,7 @@
 	/* Wait for device to logout...1 second. */
 	sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ);
 
-	SBP2_INFO("sbp2: Logged out of SBP-2 device");
+	SBP2_INFO("Logged out of SBP-2 device");
 
 	return(0);
 
@@ -1470,7 +1476,7 @@
 	quadlet_t data[2];
 	unsigned long flags;
 
-	SBP2_DEBUG("sbp2: sbp2_reconnect_device");
+	SBP2_DEBUG("sbp2_reconnect_device");
 
 	/*
 	 * Set-up reconnect ORB
@@ -1527,7 +1533,7 @@
 	 * probably because the reconnect timed-out.
 	 */
 	if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) {
-		SBP2_ERR("sbp2: Error reconnecting to SBP-2 device - reconnect timed-out");
+		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");
 		return(-EIO);
 	}
 
@@ -1538,11 +1544,11 @@
 	    STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
 	    STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
 
-		SBP2_ERR("sbp2: Error reconnecting to SBP-2 device - reconnect failed");
+		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect failed");
 		return(-EIO);
 	}
 
-	SBP2_INFO("sbp2: Reconnected to SBP-2 device");
+	SBP2_INFO("Reconnected to SBP-2 device");
 
 	return(0);
 
@@ -1556,7 +1562,7 @@
 {      
 	quadlet_t data;
 
-	SBP2_DEBUG("sbp2: sbp2_set_busy_timeout");
+	SBP2_DEBUG("sbp2_set_busy_timeout");
 
 	/*
 	 * Ok, let's write to the target's busy timeout register
@@ -1564,7 +1570,7 @@
 	data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE);
 
 	if (hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) {
-		SBP2_ERR("sbp2: sbp2_set_busy_timeout error");
+		SBP2_ERR("sbp2_set_busy_timeout error");
 	}
 
 	return(0);
@@ -1580,7 +1586,7 @@
 	struct unit_directory *ud;
 	int i;
 
-	SBP2_DEBUG("sbp2: sbp2_parse_unit_directory");
+	SBP2_DEBUG("sbp2_parse_unit_directory");
 
 	ud = scsi_id->ud;
 
@@ -1593,21 +1599,21 @@
 				CONFIG_ROM_INITIAL_MEMORY_SPACE + 
 				(ud->arb_values[i] << 2);
 
-			SBP2_DEBUG("sbp2: sbp2_management_agent_addr = %x",
+			SBP2_DEBUG("sbp2_management_agent_addr = %x",
 				   (unsigned int) scsi_id->sbp2_management_agent_addr);
 			break;
 
 		case SBP2_COMMAND_SET_SPEC_ID_KEY:
 			/* Command spec organization */
 			scsi_id->sbp2_command_set_spec_id = ud->arb_values[i];
-			SBP2_DEBUG("sbp2: sbp2_command_set_spec_id = %x",
+			SBP2_DEBUG("sbp2_command_set_spec_id = %x",
 				   (unsigned int) scsi_id->sbp2_command_set_spec_id);
 			break;
 
 		case SBP2_COMMAND_SET_KEY:
 			/* Command set used by sbp2 device */
 			scsi_id->sbp2_command_set = ud->arb_values[i];
-			SBP2_DEBUG("sbp2: sbp2_command_set = %x",
+			SBP2_DEBUG("sbp2_command_set = %x",
 				   (unsigned int) scsi_id->sbp2_command_set);
 			break;
 
@@ -1617,7 +1623,7 @@
 			 * that I'm not yet paying attention to)
 			 */
 			scsi_id->sbp2_unit_characteristics = ud->arb_values[i];
-			SBP2_DEBUG("sbp2: sbp2_unit_characteristics = %x",
+			SBP2_DEBUG("sbp2_unit_characteristics = %x",
 				   (unsigned int) scsi_id->sbp2_unit_characteristics);
 			break;
 
@@ -1627,7 +1633,7 @@
 			 * detemining type of sbp2 device)
 			 */
 			scsi_id->sbp2_device_type_and_lun = ud->arb_values[i];
-			SBP2_DEBUG("sbp2: sbp2_device_type_and_lun = %x",
+			SBP2_DEBUG("sbp2_device_type_and_lun = %x",
 				   (unsigned int) scsi_id->sbp2_device_type_and_lun);
 			break;
 
@@ -1642,7 +1648,7 @@
 			scsi_id->sbp2_firmware_revision = ud->arb_values[i];
 			if (scsi_id->sbp2_firmware_revision ==
 			    SBP2_128KB_BROKEN_FIRMWARE) {
-				SBP2_WARN("sbp2: warning: Bridge chipset supports 128KB max transfer size");
+				SBP2_WARN("warning: Bridge chipset supports 128KB max transfer size");
 			}
 			break;
 
@@ -1654,39 +1660,36 @@
 
 /*
  * This function is called in order to determine the max speed and packet
- * size we can use in our ORBs. 
+ * size we can use in our ORBs. Note, that we (the driver and host) only
+ * initiate the transaction. The SBP-2 device actually transfers the data
+ * (by reading from the DMA area we tell it). This means that the SBP-2
+ * device decides the actual maximum data it can transfer. We just tell it
+ * the speed that it needs to use, and the max_rec the host supports, and
+ * it takes care of the rest.
  */
 static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id)
 {
-	u8 speed_code;
-	unsigned int max_rec;
-
-	SBP2_DEBUG("sbp2: sbp2_max_speed_and_size");
+	SBP2_DEBUG("sbp2_max_speed_and_size");
 
-	speed_code = scsi_id->ne->busopt.lnkspd;
-	max_rec = scsi_id->ne->busopt.max_rec;
-
-	/* Bump down our speed if there is a module parameter forcing us slower */
-	if (speed_code > max_speed) {
-		speed_code = max_speed;
-		SBP2_ERR("sbp2: Reducing SBP-2 max speed allowed (%x)", max_speed); 
-	}
-
-	/* Support the devices max_rec and max speed. We choose a setting
-	 * that fits both values, since they may differ.  */
-	if (speed_code >= SPEED_400 && max_rec >= MAX_REC_S400) {
-		HPSB_INFO("sbp2: SBP-2 device max speed S400 and payload 2KB");
-		scsi_id->speed_code = SPEED_400;
-		scsi_id->max_payload_size = MAX_PAYLOAD_S400;
-	} else if (speed_code >= SPEED_200 && max_rec >= MAX_REC_S200) {
-		HPSB_INFO("sbp2: SBP-2 device max speed S200 and payload 1KB");
-		scsi_id->speed_code = SPEED_200;
-		scsi_id->max_payload_size = MAX_PAYLOAD_S200;
-	} else {
-		HPSB_INFO("sbp2: SBP-2 device max speed S100 and payload 512 bytes");
-		scsi_id->speed_code = SPEED_100;
-		scsi_id->max_payload_size = MAX_PAYLOAD_S100;
-	}
+	/* Initial setting comes from the hosts speed map */
+	scsi_id->speed_code = hi->host->speed_map[(hi->host->node_id & NODE_MASK) * 64
+						  + (scsi_id->ne->nodeid & NODE_MASK)];
+
+	/* Bump down our speed if the user requested it */
+	if (scsi_id->speed_code > max_speed) {
+		scsi_id->speed_code = max_speed;
+		SBP2_ERR("Forcing SBP-2 max speed down to %s",
+			 hpsb_speedto_str[scsi_id->speed_code]);
+	}
+
+	/* Payload size is the lesser of what our speed supports and what
+	 * our host supports.  */
+	scsi_id->max_payload_size = min(sbp2_speedto_maxrec[scsi_id->speed_code],
+					(u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1));
+
+	SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [0x%02x/%u]",
+		 NODE_BUS_ARGS(scsi_id->ne->nodeid), hpsb_speedto_str[scsi_id->speed_code],
+		 scsi_id->max_payload_size, 1 << ((u32)scsi_id->max_payload_size + 2));
 
 	return(0);
 }
@@ -1698,7 +1701,7 @@
 {
 	struct sbp2_request_packet *agent_reset_request_packet;
 
-	SBP2_DEBUG("sbp2: sbp2_agent_reset");
+	SBP2_DEBUG("sbp2_agent_reset");
 
 	/*
 	 * Ok, let's write to the target's management agent register
@@ -1710,12 +1713,12 @@
 						       0, ntohl(SBP2_AGENT_RESET_DATA));
 
 	if (!agent_reset_request_packet) {
-		SBP2_ERR("sbp2: sbp2util_allocate_write_request_packet failed");
+		SBP2_ERR("sbp2util_allocate_write_request_packet failed");
 		return(-EIO);
 	}
 
 	if (!hpsb_send_packet(agent_reset_request_packet->packet)) {
-		SBP2_ERR("sbp2: hpsb_send_packet failed");
+		SBP2_ERR("hpsb_send_packet failed");
 		sbp2util_free_request_packet(agent_reset_request_packet); 
 		return(-EIO);
 	}
@@ -1774,7 +1777,7 @@
 	 */
 	if (sbp2scsi_direction_table[*scsi_cmd] == ORB_DIRECTION_NO_DATA_TRANSFER) {
 
-		SBP2_DEBUG("sbp2: No data transfer");
+		SBP2_DEBUG("No data transfer");
 
 		/*
 		 * Handle no data transfer
@@ -1785,14 +1788,14 @@
 
 	} else if (scsi_use_sg) {
 
-		SBP2_DEBUG("sbp2: Use scatter/gather");
+		SBP2_DEBUG("Use scatter/gather");
 
 		/*
 		 * Special case if only one element (and less than 64KB in size)
 		 */
 		if ((scsi_use_sg == 1) && (sgpnt[0].length <= SBP2_MAX_SG_ELEMENT_LENGTH)) {
 
-			SBP2_DEBUG("sbp2: Only one s/g element");
+			SBP2_DEBUG("Only one s/g element");
 			command->dma_dir = dma_dir;
 			command->dma_size = sgpnt[0].length;
 			command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address,
@@ -1856,7 +1859,7 @@
 
 	} else {
 
-		SBP2_DEBUG("sbp2: No scatter/gather");
+		SBP2_DEBUG("No scatter/gather");
 
 		command->dma_dir = dma_dir;
 		command->dma_size = scsi_request_bufflen;
@@ -1977,7 +1980,7 @@
 								SBP2_ORB_POINTER_OFFSET, 8, 0);
 		
 			if (!command_request_packet) {
-				SBP2_ERR("sbp2: sbp2util_allocate_write_request_packet failed");
+				SBP2_ERR("sbp2util_allocate_write_request_packet failed");
 				return(-EIO);
 			}
 		
@@ -1988,7 +1991,7 @@
 			SBP2_ORB_DEBUG("write command agent, command orb %p", command_orb);
 
 			if (!hpsb_send_packet(command_request_packet->packet)) {
-				SBP2_ERR("sbp2: hpsb_send_packet failed");
+				SBP2_ERR("hpsb_send_packet failed");
 				sbp2util_free_request_packet(command_request_packet); 
 				return(-EIO);
 			}
@@ -2024,14 +2027,14 @@
 				0, cpu_to_be32(command->command_orb_dma));
 	
 			if (!command_request_packet) {
-				SBP2_ERR("sbp2: sbp2util_allocate_write_request_packet failed");
+				SBP2_ERR("sbp2util_allocate_write_request_packet failed");
 				return(-EIO);
 			}
 
 			SBP2_ORB_DEBUG("ring doorbell, command orb %p", command_orb);
 
 			if (!hpsb_send_packet(command_request_packet->packet)) {
-				SBP2_ERR("sbp2: hpsb_send_packet failed");
+				SBP2_ERR("hpsb_send_packet failed");
 				sbp2util_free_request_packet(command_request_packet);
 				return(-EIO);
 			}
@@ -2053,10 +2056,10 @@
 	u32 device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16;
 	struct sbp2_command_info *command;
 
-	SBP2_DEBUG("sbp2: sbp2_send_command");
-	SBP2_DEBUG("sbp2: SCSI command = %02x", *cmd);
-	SBP2_DEBUG("sbp2: SCSI transfer size = %x", SCpnt->request_bufflen);
-	SBP2_DEBUG("sbp2: SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg);
+	SBP2_DEBUG("sbp2_send_command");
+	SBP2_DEBUG("SCSI command = %02x", *cmd);
+	SBP2_DEBUG("SCSI transfer size = %x", SCpnt->request_bufflen);
+	SBP2_DEBUG("SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg);
 
 	/*
 	 * Check for broken devices that can't handle greater than 128K
@@ -2236,13 +2239,13 @@
 {
 	unchar new_cmd[16];
 
-	SBP2_DEBUG("sbp2: sbp2_check_sbp2_command");
+	SBP2_DEBUG("sbp2_check_sbp2_command");
 
 	switch (*cmd) {
 		
 		case READ_6:
 
-			SBP2_DEBUG("sbp2: Convert READ_6 to READ_10");
+			SBP2_DEBUG("Convert READ_6 to READ_10");
 
 			/*
 			 * Need to turn read_6 into read_10
@@ -2264,7 +2267,7 @@
 
 		case WRITE_6:
 
-			SBP2_DEBUG("sbp2: Convert WRITE_6 to WRITE_10");
+			SBP2_DEBUG("Convert WRITE_6 to WRITE_10");
 
 			/*
 			 * Need to turn write_6 into write_10
@@ -2286,7 +2289,7 @@
 
 		case MODE_SENSE:
 
-			SBP2_DEBUG("sbp2: Convert MODE_SENSE_6 to MOSE_SENSE_10");
+			SBP2_DEBUG("Convert MODE_SENSE_6 to MOSE_SENSE_10");
 
 			/*
 			 * Need to turn mode_sense_6 into mode_sense_10
@@ -2324,7 +2327,7 @@
  */
 static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data)
 {
-	SBP2_DEBUG("sbp2: sbp2_status_to_sense_data");
+	SBP2_DEBUG("sbp2_status_to_sense_data");
 
 	/*
 	 * Ok, it's pretty ugly...   ;-)
@@ -2360,19 +2363,19 @@
 	u8 *scsi_buf = SCpnt->request_buffer;
 	u32 device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16;
         
-	SBP2_DEBUG("sbp2: sbp2_check_sbp2_response");
+	SBP2_DEBUG("sbp2_check_sbp2_response");
 
 	switch (SCpnt->cmnd[0]) {
 		
 		case INQUIRY:
 
-			SBP2_DEBUG("sbp2: Check Inquiry data");
+			SBP2_DEBUG("Check Inquiry data");
 
 			/*
 			 * Check for Simple Direct Access Device and change it to TYPE_DISK
 			 */
 			if ((scsi_buf[0] & 0x1f) == TYPE_SDAD) {
-				SBP2_DEBUG("sbp2: Changing TYPE_SDAD to TYPE_DISK");
+				SBP2_DEBUG("Changing TYPE_SDAD to TYPE_DISK");
 				scsi_buf[0] &= 0xe0;
 			}
 
@@ -2390,7 +2393,7 @@
 			    (device_type == TYPE_SDAD) ||
 			    (device_type == TYPE_ROM)) {
 
-				SBP2_DEBUG("sbp2: Modify mode sense response (10 byte version)");
+				SBP2_DEBUG("Modify mode sense response (10 byte version)");
 	
 				scsi_buf[0] = scsi_buf[1];	/* Mode data length */
 				scsi_buf[1] = scsi_buf[2];	/* Medium type */
@@ -2428,10 +2431,10 @@
 	u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
 	struct sbp2_command_info *command;
 
-	SBP2_DEBUG("sbp2: sbp2_handle_status_write");
+	SBP2_DEBUG("sbp2_handle_status_write");
 
 	if (!host) {
-		SBP2_ERR("sbp2: host is NULL - this is bad!");
+		SBP2_ERR("host is NULL - this is bad!");
 		return(RCODE_ADDRESS_ERROR);
 	}
 
@@ -2440,7 +2443,7 @@
 	sbp2_spin_unlock(&sbp2_host_info_lock, flags);
 
 	if (!hi) {
-		SBP2_ERR("sbp2: host info is NULL - this is bad!");
+		SBP2_ERR("host info is NULL - this is bad!");
 		return(RCODE_ADDRESS_ERROR);
 	}
 
@@ -2453,14 +2456,14 @@
 		if (hi->scsi_id[i]) {
 			if ((hi->scsi_id[i]->ne->nodeid & NODE_MASK) == (nodeid & NODE_MASK)) {
 				scsi_id = hi->scsi_id[i];
-				SBP2_DEBUG("sbp2: SBP-2 status write from node %x", scsi_id->ne->nodeid);
+				SBP2_DEBUG("SBP-2 status write from node %x", scsi_id->ne->nodeid);
 				break;
 			}
 		}
 	}
 
 	if (!scsi_id) {
-		SBP2_ERR("sbp2: scsi_id is NULL - device is gone?");
+		SBP2_ERR("scsi_id is NULL - device is gone?");
 		sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
 		return(RCODE_ADDRESS_ERROR);
 	}
@@ -2481,7 +2484,7 @@
 	command = sbp2util_find_command_for_orb(scsi_id, scsi_id->status_block.ORB_offset_lo);
 	if (command) {
 
-		SBP2_DEBUG("sbp2: Found status for command ORB");
+		SBP2_DEBUG("Found status for command ORB");
 
 		SBP2_ORB_DEBUG("matched command orb %p", &command->command_orb);
 		outstanding_orb_decr;
@@ -2499,7 +2502,7 @@
 			 */
 			if (STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
 
-				SBP2_DEBUG("sbp2: CHECK CONDITION");
+				SBP2_DEBUG("CHECK CONDITION");
 
 				/*
 				 * Translate SBP-2 status to SCSI sense data
@@ -2518,7 +2521,7 @@
 			/*
 			 * Complete the SCSI command
 			 */
-			SBP2_DEBUG("sbp2: Completing SCSI command");
+			SBP2_DEBUG("Completing SCSI command");
 			sbp2scsi_complete_command(hi, scsi_id, scsi_status, SCpnt, command->Current_done);
 			SBP2_ORB_DEBUG("command orb completed");
 		}
@@ -2555,7 +2558,7 @@
 	struct scsi_id_instance_data *scsi_id = NULL;
 	unsigned long flags;
 
-	SBP2_DEBUG("sbp2: sbp2scsi_queuecommand");
+	SBP2_DEBUG("sbp2scsi_queuecommand");
 
 	/*
 	 * Pull our host info and scsi id instance data from the scsi command
@@ -2563,7 +2566,7 @@
 	hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0];
 
 	if (!hi) {
-		SBP2_ERR("sbp2: sbp2scsi_host_info is NULL - this is bad!");
+		SBP2_ERR("sbp2scsi_host_info is NULL - this is bad!");
 		SCpnt->result = DID_NO_CONNECT << 16;
 		done (SCpnt);
 		return(0);
@@ -2596,7 +2599,7 @@
 	 * (autorequest sense)
 	 */
 	if (SCpnt->cmnd[0] == REQUEST_SENSE) {
-		SBP2_DEBUG("sbp2: REQUEST_SENSE");
+		SBP2_DEBUG("REQUEST_SENSE");
 		memcpy(SCpnt->request_buffer, SCpnt->sense_buffer, SCpnt->request_bufflen);
 		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
 		sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_GOOD, SCpnt, done);
@@ -2608,7 +2611,7 @@
 	 * busy (to be queued later)
 	 */
 	if (!hpsb_node_entry_valid(scsi_id->ne)) {
-		SBP2_ERR("sbp2: Bus reset in progress - rejecting command");
+		SBP2_ERR("Bus reset in progress - rejecting command");
 		SCpnt->result = DID_BUS_BUSY << 16;
 		done (SCpnt);
 		return(0);
@@ -2619,7 +2622,7 @@
 	 */
 	sbp2_spin_lock(&hi->sbp2_command_lock, flags);
 	if (sbp2_send_command(hi, scsi_id, SCpnt, done)) {
-		SBP2_ERR("sbp2: Error sending SCSI command");
+		SBP2_ERR("Error sending SCSI command");
 		sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT, SCpnt, done);
 	}
 	sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
@@ -2638,10 +2641,10 @@
 	struct list_head *lh;
 	struct sbp2_command_info *command;
 
-	SBP2_DEBUG("sbp2: sbp2_complete_all_commands");
+	SBP2_DEBUG("sbp2_complete_all_commands");
 
 	while (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
-		SBP2_DEBUG("sbp2: Found pending command to complete");
+		SBP2_DEBUG("Found pending command to complete");
 		lh = scsi_id->sbp2_command_orb_inuse.next;
 		command = list_entry(lh, struct sbp2_command_info, list);
 		sbp2util_mark_command_completed(scsi_id, command);
@@ -2661,13 +2664,13 @@
 static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 scsi_status,
 				      Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
-	SBP2_DEBUG("sbp2: sbp2scsi_complete_command");
+	SBP2_DEBUG("sbp2scsi_complete_command");
 
 	/*
 	 * Sanity
 	 */
 	if (!SCpnt) {
-		SBP2_ERR("sbp2: SCpnt is NULL");
+		SBP2_ERR("SCpnt is NULL");
 		return;
 	}
 
@@ -2677,7 +2680,7 @@
 	 * bus reset.
 	 */
 	if (!hpsb_node_entry_valid(scsi_id->ne) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
-		SBP2_ERR("sbp2: Bus reset in progress - retry command later");
+		SBP2_ERR("Bus reset in progress - retry command later");
 		return;
 	}
         
@@ -2690,12 +2693,12 @@
 			break;
 
 		case SBP2_SCSI_STATUS_BUSY:
-			SBP2_ERR("sbp2: SBP2_SCSI_STATUS_BUSY");
+			SBP2_ERR("SBP2_SCSI_STATUS_BUSY");
 			SCpnt->result = DID_BUS_BUSY << 16;
 			break;
 
 		case SBP2_SCSI_STATUS_CHECK_CONDITION:
-			SBP2_DEBUG("sbp2: SBP2_SCSI_STATUS_CHECK_CONDITION");
+			SBP2_DEBUG("SBP2_SCSI_STATUS_CHECK_CONDITION");
 			SCpnt->result = CHECK_CONDITION << 1;
 
 			/*
@@ -2706,19 +2709,19 @@
 			break;
 
 		case SBP2_SCSI_STATUS_SELECTION_TIMEOUT:
-			SBP2_ERR("sbp2: SBP2_SCSI_STATUS_SELECTION_TIMEOUT");
+			SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT");
 			SCpnt->result = DID_NO_CONNECT << 16;
 			break;
 
 		case SBP2_SCSI_STATUS_CONDITION_MET:
 		case SBP2_SCSI_STATUS_RESERVATION_CONFLICT:
 		case SBP2_SCSI_STATUS_COMMAND_TERMINATED:
-			SBP2_ERR("sbp2: Bad SCSI status = %x", scsi_status);
+			SBP2_ERR("Bad SCSI status = %x", scsi_status);
 			SCpnt->result = DID_ERROR << 16;
 			break;
 
 		default:
-			SBP2_ERR("sbp2: Unsupported SCSI status = %x", scsi_status);
+			SBP2_ERR("Unsupported SCSI status = %x", scsi_status);
 			SCpnt->result = DID_ERROR << 16;
 	}
 
@@ -2736,7 +2739,7 @@
 	 * can mount the device rw).
 	 */
 	if (mode_sense_hack && SCpnt->result != DID_OK && SCpnt->cmnd[0] == MODE_SENSE) {
-		SBP2_INFO("sbp2: Returning success to mode sense command");
+		SBP2_INFO("Returning success to mode sense command");
 		SCpnt->result = DID_OK;
 		SCpnt->sense_buffer[0] = 0;
 		memset (SCpnt->request_buffer, 0, 8);
@@ -2747,7 +2750,7 @@
 	 * the command as busy so that it will get retried.
 	 */
 	if (!hpsb_node_entry_valid(scsi_id->ne) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
-		SBP2_ERR("sbp2: Completing command with busy (bus reset)");
+		SBP2_ERR("Completing command with busy (bus reset)");
 		SCpnt->result = DID_BUS_BUSY << 16;
 	}
 
@@ -2757,7 +2760,7 @@
 	 * or hot-plug...
 	 */
 	if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) {
-		SBP2_INFO("sbp2: UNIT ATTENTION - return busy");
+		SBP2_INFO("UNIT ATTENTION - return busy");
 		SCpnt->result = DID_BUS_BUSY << 16;
 	}
 
@@ -2780,7 +2783,7 @@
 	struct sbp2_command_info *command;
 	unsigned long flags;
 
-	SBP2_ERR("sbp2: aborting sbp2 command");
+	SBP2_ERR("aborting sbp2 command");
 
 	if (scsi_id) {
 
@@ -2793,7 +2796,7 @@
 		do {
 			command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
 			if (command) {
-				SBP2_DEBUG("sbp2: Found command to abort");
+				SBP2_DEBUG("Found command to abort");
 				sbp2util_mark_command_completed(scsi_id, command);
 				if (command->Current_SCpnt && !command->linked) {
 					void (*done)(Scsi_Cmnd *) = command->Current_done;
@@ -2821,10 +2824,10 @@
 {
 	struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0];
 
-	SBP2_ERR("sbp2: reset requested");
+	SBP2_ERR("reset requested");
 
 	if (hi) {
-		SBP2_ERR("sbp2: generating IEEE-1394 bus reset");
+		SBP2_ERR("Generating IEEE-1394 bus reset");
 		hpsb_reset_bus(hi->host, LONG_RESET);
 	}
 
@@ -2838,7 +2841,7 @@
 {
 	int heads, sectors, cylinders;
 
-	SBP2_DEBUG("sbp2: request for bios parameters");
+	SBP2_DEBUG("Request for bios parameters");
 
 	heads = 64;
 	sectors = 32;
@@ -2862,7 +2865,7 @@
  */
 void sbp2scsi_setup( char *str, int *ints) 
 {
-	SBP2_DEBUG("sbp2: sbp2scsi_setup");
+	SBP2_DEBUG("sbp2scsi_setup");
 	return;
 }
 
@@ -2871,7 +2874,7 @@
  */
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt) 
 {
-	SBP2_DEBUG("sbp2: sbp2scsi_detect");
+	SBP2_DEBUG("sbp2scsi_detect");
 
 	global_scsi_tpnt = tpnt;
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,26)
@@ -2881,7 +2884,7 @@
 	 * Module load option for force one command at a time
 	 */
 	if (serialize_io) {
-		SBP2_ERR("sbp2: Driver forced to serialize I/O (serialize_io = 1)");
+		SBP2_ERR("Driver forced to serialize I/O (serialize_io = 1)");
 		global_scsi_tpnt->can_queue = 1;
 		global_scsi_tpnt->cmd_per_lun = 1;
 	}
@@ -2890,19 +2893,19 @@
 	 * Module load option to limit max size of requests from the scsi drivers
 	 */
 	if (no_large_packets) {
-		SBP2_ERR("sbp2: Driver forced to limit max transfer size (no_large_packets = 1)");
+		SBP2_ERR("Driver forced to limit max transfer size (no_large_packets = 1)");
 		global_scsi_tpnt->sg_tablesize = 0x1f;
 		global_scsi_tpnt->use_clustering = DISABLE_CLUSTERING;
 	}
 
 	if (mode_sense_hack) {
-		SBP2_ERR("sbp2: Mode sense emulation enabled (mode_sense_hack = 1)");
+		SBP2_ERR("Mode sense emulation enabled (mode_sense_hack = 1)");
 	}
 
 	sbp2_init();
 
 	if (!sbp2_host_count) {
-		SBP2_ERR("sbp2: Please load the lower level IEEE-1394 driver (e.g. ohci1394) before sbp2...");
+		SBP2_ERR("Please load the lower level IEEE-1394 driver (e.g. ohci1394) before sbp2...");
 		sbp2_cleanup();
 	}
 
@@ -2921,8 +2924,8 @@
 {
 	struct Scsi_Host *shpnt = NULL;
 
-	SBP2_DEBUG("sbp2: sbp2scsi_register_scsi_host");
-	SBP2_DEBUG("sbp2: sbp2scsi_host_info = %p", hi);
+	SBP2_DEBUG("sbp2scsi_register_scsi_host");
+	SBP2_DEBUG("sbp2scsi_host_info = %p", hi);
 
 	/*
 	 * Let's register with the scsi stack
@@ -2946,7 +2949,7 @@
 /* Called when our module is released */
 static int sbp2scsi_release(struct Scsi_Host *host)
 {
-	SBP2_DEBUG("sbp2: sbp2scsi_release");
+	SBP2_DEBUG("sbp2scsi_release");
 	sbp2_cleanup();
 	return(0);
 }
@@ -2960,6 +2963,7 @@
 MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>");
 MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
 MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
+MODULE_LICENSE("GPL");
 
 /* SCSI host template */
 static Scsi_Host_Template driver_template = {
diff -u --recursive --new-file v2.4.12/linux/drivers/ieee1394/sbp2.h linux/drivers/ieee1394/sbp2.h
--- v2.4.12/linux/drivers/ieee1394/sbp2.h	Tue Oct  9 17:06:51 2001
+++ linux/drivers/ieee1394/sbp2.h	Wed Oct 17 14:19:20 2001
@@ -36,16 +36,6 @@
 #define ORB_DIRECTION_READ_FROM_MEDIA   0x1
 #define ORB_DIRECTION_NO_DATA_TRANSFER  0x2
 
-/* 2^(MAX_PAYLOAD+1) = Maximum data transfer length */
-#define MAX_PAYLOAD_S100		0x7
-#define MAX_PAYLOAD_S200		0x8
-#define MAX_PAYLOAD_S400		0x9
-
-/* Max rec matches node_entry values */
-#define MAX_REC_S100			512
-#define MAX_REC_S200			1024
-#define MAX_REC_S400			2048
-
 #define ORB_SET_NOTIFY(value)                   ((value & 0x1) << 31)
 #define ORB_SET_RQ_FMT(value)                   ((value & 0x3) << 29)
 #define ORB_SET_NODE_ID(value)			((value & 0xffff) << 16)
@@ -268,6 +258,9 @@
  * DOU = OUT data direction
  * DNO = No data transfer
  * DUN = Unknown data direction
+ *
+ * Opcode 0xec (Teac specific "opc execute") possibly should be DNO,
+ * but we'll change it when somebody reports a problem with this.
  */
 #define DIN				ORB_DIRECTION_READ_FROM_MEDIA
 #define DOU				ORB_DIRECTION_WRITE_TO_MEDIA
@@ -280,7 +273,7 @@
 	DIN,DUN,DIN,DIN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU,
 	DOU,DOU,DOU,DNO,DIN,DNO,DNO,DIN,DOU,DOU,DOU,DOU,DIN,DOU,DIN,DOU,
 	DOU,DOU,DIN,DIN,DIN,DNO,DIN,DNO,DNO,DNO,DUN,DNO,DOU,DIN,DNO,DUN,
-	DUN,DIN,DIN,DNO,DOU,DOU,DUN,DUN,DNO,DIN,DIN,DNO,DIN,DOU,DUN,DUN,
+	DUN,DIN,DIN,DNO,DNO,DOU,DUN,DUN,DNO,DIN,DIN,DNO,DIN,DOU,DUN,DUN,
 	DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
 	DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
 	DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
diff -u --recursive --new-file v2.4.12/linux/drivers/input/keybdev.c linux/drivers/input/keybdev.c
--- v2.4.12/linux/drivers/input/keybdev.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/input/keybdev.c	Thu Oct 11 09:14:32 2001
@@ -246,3 +246,4 @@
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("Input driver to keyboard driver binding");
 MODULE_PARM(jp_kbd_109, "i");
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.4.12/linux/drivers/macintosh/macserial.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/macintosh/macserial.c	Mon Oct 15 13:43:24 2001
@@ -2730,6 +2730,8 @@
 
 module_init(macserial_init);
 module_exit(macserial_cleanup);
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
 
 #if 0
 /*
diff -u --recursive --new-file v2.4.12/linux/drivers/macintosh/nvram.c linux/drivers/macintosh/nvram.c
--- v2.4.12/linux/drivers/macintosh/nvram.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/macintosh/nvram.c	Mon Oct 15 13:43:24 2001
@@ -124,3 +124,4 @@
 
 module_init(nvram_init);
 module_exit(nvram_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/macintosh/rtc.c linux/drivers/macintosh/rtc.c
--- v2.4.12/linux/drivers/macintosh/rtc.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/macintosh/rtc.c	Mon Oct 15 13:43:24 2001
@@ -146,3 +146,4 @@
 
 module_init(rtc_init);
 module_exit(rtc_exit);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/md/lvm.c linux/drivers/md/lvm.c
--- v2.4.12/linux/drivers/md/lvm.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/md/lvm.c	Mon Oct 15 13:27:52 2001
@@ -877,7 +877,7 @@
 		/* return device size */
 		P_IOCTL("%s -- lvm_blk_ioctl -- BLKGETSIZE: %u\n",
 			lvm_name, lv_ptr->lv_size);
-		if (put_user(lv_ptr->lv_size, (long *)arg))
+		if (put_user(lv_ptr->lv_size, (unsigned long *)arg))
 			return -EFAULT;
 		break;
 
diff -u --recursive --new-file v2.4.12/linux/drivers/md/md.c linux/drivers/md/md.c
--- v2.4.12/linux/drivers/md/md.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/md/md.c	Wed Oct 17 14:21:00 2001
@@ -542,8 +542,10 @@
 		goto abort;
 	}
 
-	if (calc_sb_csum(sb) != sb->sb_csum)
+	if (calc_sb_csum(sb) != sb->sb_csum) {
 		printk(BAD_CSUM, partition_name(rdev->dev));
+		goto abort;
+	}
 	ret = 0;
 abort:
 	return ret;
@@ -2609,7 +2611,7 @@
 				goto abort;
 			}
 			err = md_put_user(md_hd_struct[minor].nr_sects,
-						(long *) arg);
+						(unsigned long *) arg);
 			goto done;
 
 		case BLKGETSIZE64:	/* Return device size */
diff -u --recursive --new-file v2.4.12/linux/drivers/md/raid1.c linux/drivers/md/raid1.c
--- v2.4.12/linux/drivers/md/raid1.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/md/raid1.c	Wed Oct 17 14:21:00 2001
@@ -1690,7 +1690,8 @@
 		}
 	}
 
-	if (!start_recovery && !(sb->state & (1 << MD_SB_CLEAN))) {
+	if (!start_recovery && !(sb->state & (1 << MD_SB_CLEAN)) &&
+	    (conf->working_disks > 1)) {
 		const char * name = "raid1syncd";
 
 		conf->resync_thread = md_register_thread(raid1syncd, conf,name);
diff -u --recursive --new-file v2.4.12/linux/drivers/md/raid5.c linux/drivers/md/raid5.c
--- v2.4.12/linux/drivers/md/raid5.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/md/raid5.c	Wed Oct 17 14:21:00 2001
@@ -487,22 +487,24 @@
 	PRINTK("raid5_error called\n");
 
 	for (i = 0, disk = conf->disks; i < conf->raid_disks; i++, disk++) {
-		if (disk->dev == dev && disk->operational) {
-			disk->operational = 0;
-			mark_disk_faulty(sb->disks+disk->number);
-			mark_disk_nonsync(sb->disks+disk->number);
-			mark_disk_inactive(sb->disks+disk->number);
-			sb->active_disks--;
-			sb->working_disks--;
-			sb->failed_disks++;
-			mddev->sb_dirty = 1;
-			conf->working_disks--;
-			conf->failed_disks++;
-			md_wakeup_thread(conf->thread);
-			printk (KERN_ALERT
-				"raid5: Disk failure on %s, disabling device."
-				" Operation continuing on %d devices\n",
-				partition_name (dev), conf->working_disks);
+		if (disk->dev == dev) {
+			if (disk->operational) {
+				disk->operational = 0;
+				mark_disk_faulty(sb->disks+disk->number);
+				mark_disk_nonsync(sb->disks+disk->number);
+				mark_disk_inactive(sb->disks+disk->number);
+				sb->active_disks--;
+				sb->working_disks--;
+				sb->failed_disks++;
+				mddev->sb_dirty = 1;
+				conf->working_disks--;
+				conf->failed_disks++;
+				md_wakeup_thread(conf->thread);
+				printk (KERN_ALERT
+					"raid5: Disk failure on %s, disabling device."
+					" Operation continuing on %d devices\n",
+					partition_name (dev), conf->working_disks);
+			}
 			return 0;
 		}
 	}
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/bttv-cards.c linux/drivers/media/video/bttv-cards.c
--- v2.4.12/linux/drivers/media/video/bttv-cards.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/bttv-cards.c	Wed Oct 17 14:19:20 2001
@@ -40,6 +40,8 @@
 
 /* fwd decl */
 static void hauppauge_eeprom(struct bttv *btv);
+static void avermedia_eeprom(struct bttv *btv);
+
 static void init_PXC200(struct bttv *btv);
 #if 0
 static void init_tea5757(struct bttv *btv);
@@ -52,6 +54,7 @@
 static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
 static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
 static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set);
+static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
 
 /* config variables */
 static int triton1=0;
@@ -71,6 +74,10 @@
 
 /* insmod options */
 MODULE_PARM(triton1,"i");
+MODULE_PARM_DESC(triton1,"set ETBF pci config bit "
+		 "[enable bug compatibility for triton1 + others]");
+MODULE_PARM(vsfx,"i");
+MODULE_PARM_DESC(vsfx,"set VSFX pci config bit [yet another chipset flaw workaround]");
 MODULE_PARM(no_overlay,"i");
 MODULE_PARM(card,"1-4i");
 MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
@@ -83,7 +90,6 @@
 MODULE_PARM(gpiomask,"i");
 MODULE_PARM(audioall,"i");
 MODULE_PARM(audiomux,"1-5i");
-MODULE_LICENSE("GPL");
 
 /* kernel args */
 #ifndef MODULE
@@ -127,13 +133,18 @@
 	{ 0x6606107d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
 	{ 0x263610b4, BTTV_STB2,          "STB TV PCI FM, P/N 6000704" },
  	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV3/PCI" },
-	{ 0x405010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV4/PCI" },
-	{ 0x001211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
-	{ 0x3000121a, 0/* no entry yet */,"VoodooTV 200" },
+	{ 0x405010fc, BTTV_GVBCTV4PCI,    "I-O Data Co. GV-BCV4/PCI" },
 
-	{ 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" },
-	{ 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" },
+	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV" },
+	{ 0x001211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
+	{ 0x001c11bd, BTTV_PINNACLE,      "Pinnacle PCTV Sat" },
 
+	{ 0x3000121a, BTTV_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
+	
+	{ 0x3000144f, BTTV_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
+	{ 0x3002144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
+	{ 0x3005144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
+	
 	{ 0x00011461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
 	{ 0x00021461, BTTV_AVERMEDIA98,   "AVermedia TVCapture 98" },
 	{ 0x00031461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
@@ -154,15 +165,15 @@
 	{ 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
 	{ 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
 	{ 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+	{ 0x401615b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
 
     	{ 0x010115cb, BTTV_GMV1,          "AG GMV1" },
-	{ 0x010114c7, 16 /* FIXME */,     "Modular Technology PCTV" },
-	{ 0x18501851, BTTV_CHRONOS_VS2,   "Chronos Video Shuttle II" },
-	{ 0x18511851, 0 /* FIXME */,      "CyberMail AV" },
-	{ 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" },
+	{ 0x010114c7, BTTV_MODTEC_205,    "Modular Technology PCTV" },
+	{ 0x18501851, BTTV_CHRONOS_VS2,   "Flyvideo 98 (LR50)/ Chronos Video Shuttle II" },
+	{ 0x18511851, BTTV_FLYVIDEO98EZ,  "Flyvideo 98EZ (LR51)/ CyberMail AV" },
+	{ 0x18521852, BTTV_TYPHOON_TVIEW, "Flyvideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
 	{ 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
 	{ 0x217d6606, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
-	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV" },
 
 	{ 0, -1, NULL }
 };
@@ -173,7 +184,7 @@
 struct tvcard bttv_tvcards[] = {
 {
 /* ---- card 0x00 ---------------------------------- */
-	name:		" *** UNKNOWN *** ",
+	name:		" *** UNKNOWN/GENERIC *** ",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -192,7 +203,7 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"Hauppauge old",
+	name:		"Hauppauge (bt848)",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -265,7 +276,7 @@
 },{
 
 /* ---- card 0x08 ---------------------------------- */
-	name:		"Fly Video II",
+	name:		"Fly Video II (Bt848)",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -287,12 +298,12 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"Hauppauge new (bt878)",
+	name:		"Hauppauge (bt878)",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	7,
+	gpiomask:	0x0f, /* old: 7 */
 	muxsel:		{ 2, 0, 1, 1},
 	audiomux:	{ 0, 1, 2, 3, 4},
 	needs_tvaudio:	1,
@@ -333,7 +344,7 @@
 	audiomux:	{ 13, 14, 11, 7, 0, 0},
 	needs_tvaudio:	1,
 	pll:		PLL_28,
-	tuner_type:	5,
+	tuner_type:	-1,
 },{
 	name:		"Aimslab VHX",
 	video_inputs:	3,
@@ -452,14 +463,14 @@
 },{
 
 /* ---- card 0x18 ---------------------------------- */
-	name:		"Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)",
+	name:		"[many vendors] CPH05X/06X (bt878)",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0xe00,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{0x400, 0x400, 0x400, 0x400, 0},
+	audiomux:	{0x400, 0x400, 0x400, 0x400, 0xc00},
 	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	-1,
@@ -528,9 +539,9 @@
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0x8dfe00,
+	gpiomask:	0x1800,  //0x8dfe00
 	muxsel:		{2, 3, 1, 1},
-	audiomux:	{ 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },
+	audiomux:	{ 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
@@ -582,31 +593,32 @@
 	tuner_type:	-1,
 	audio_hook:	winfast2000_audio,
 },{
-	name:		"Chronos Video Shuttle II",
+	name:		"Flyvideo 98 (LR50Q) / Chronos Video Shuttle II",
 	video_inputs:	3,
 	audio_inputs:	3,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 0, 0x1000, 0x1000, 0x0800},
+	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
 	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
 
 /* ---- card 0x24 ---------------------------------- */
-	name:		"Typhoon TView TV/FM Tuner",
+	name:		"Flyvideo 98FM (LR50Q) / Typhoon TView TV/FM Tuner",
 	video_inputs:	3,
 	audio_inputs:	3,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 0x800, 0, 0, 0x1800, 0 },
+	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
 	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	-1,
+	has_radio:	1,
 },{
 	name:		"PixelView PlayTV pro",
 	video_inputs:	3,
@@ -620,14 +632,14 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"TView99 CPH063",
+	name:		"TView99 CPH06X",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0x551e00,
 	muxsel:		{ 2, 3, 1, 0},
-	audiomux:	{ 0x551400, 0x551200, 0, 0, 0, 0x551200 },
+	audiomux:	{ 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
 	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	-1,
@@ -668,7 +680,8 @@
 	audiomux:	{ 13, 4, 11, 7, 0, 0},
 	needs_tvaudio:	1,
 	pll:		PLL_28,
-	tuner_type:	5,
+	tuner_type:	-1,
+	has_radio:	1,
 },{
 	name:		"ProVideo PV951", /* pic16c54 */
 	video_inputs:	3,
@@ -742,6 +755,7 @@
 	no_msp34xx:	1,
 	pll:		PLL_35,
 	tuner_type:	1,
+	has_radio:	1,
 },{
 
 /* ---- card 0x30 ---------------------------------- */
@@ -770,7 +784,7 @@
 	tuner_type:	TUNER_ALPS_TSHC6_NTSC,
 	audio_hook:	gvbctv3pci_audio,
 },{
-	name:		"Prolink PV-BT878P+4E (PixelView PlayTV PAK)",
+	name:		"Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -810,7 +824,7 @@
 },{
 	/* Claas Langbehn <claas@bigfoot.com>,
 	   Sven Grothklags <sven@upb.de> */
-	name:		"Typhoon TView RDS / FM Stereo",
+	name:		"Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
 	video_inputs:	3,
 	audio_inputs:	3,
 	tuner:		0,
@@ -821,13 +835,14 @@
 	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	TUNER_PHILIPS_PAL_I,
+	has_radio:	1,
 },{
 	/* Tim Röstermundt <rosterm@uni-muenster.de>
 	   in de.comp.os.unix.linux.hardware:
 		options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
 		audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
 		options tuner type=5 */
-	name:		"Lifetec LT 9415 TV",
+	name:		"Lifetec LT 9415 TV (LR90 Rev.F)",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -841,6 +856,7 @@
 	pll:		PLL_28,
 	tuner_type:	TUNER_PHILIPS_PAL,
 	audio_hook:	lt9415_audio,
+	has_radio:	1,
 },{
 	/* Miguel Angel Alvarez <maacruz@navegalia.com>
 	   old Easy TV BT848 version (model CPH031) */
@@ -866,7 +882,7 @@
 	svhs:           2,
 	gpiomask:       0x1800,
 	muxsel:         { 2, 3, 0, 1},
-	audiomux:       { 0, 0x800, 0, 0, 0x1800, 0 },
+	audiomux:       { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
 	needs_tvaudio:  1,
 	pll:            PLL_28,
 	tuner_type:     5,
@@ -893,7 +909,7 @@
         audio_inputs:   1,
         tuner:          0,
         svhs:           2,
-        gpiomask:       0x0e00,
+        gpiomask:       0xe00,
         muxsel:         { 2, 3, 1, 1},
         audiomux:       { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
         needs_tvaudio:  1,
@@ -1005,7 +1021,93 @@
 	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	TUNER_PHILIPS_PAL,
-}};
+	has_radio:	1,
+},{
+	/* TANAKA Kei <peg00625@nifty.com> */
+	name:           "GV-BCTV4/PCI",
+	video_inputs:   3,
+	audio_inputs:   1,
+	tuner:          0,
+	svhs:           2,
+	gpiomask:       0x010f00,
+	muxsel:         {2, 3, 0, 0},
+	audiomux:       {0x10000, 0, 0x10000, 0, 0, 0},
+	no_msp34xx:     1,
+	pll:            PLL_28,
+	tuner_type:     TUNER_SHARP_2U5JF5540_NTSC,
+	audio_hook:     gvbctv3pci_audio,
+},{
+
+/* ---- card 0x44 ---------------------------------- */
+        name:           "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+	// try "insmod msp3400 simple=0" if you have
+	// sound problems with this card.
+        video_inputs:   4,
+        audio_inputs:   1,
+        tuner:          0,
+        svhs:           -1,
+        gpiomask:       0x4f8a00,
+	                // 0x100000: 1=MSP enabled (0=disable again)
+			// 0x010000: somehow influences tuner picture quality (?)
+        audiomux:       {0x947fff, 0x987fff,0x947fff,0x947fff},
+                        //tvtuner, radio,   external,internal,mute,stereo
+        muxsel:         { 2, 3 ,0 ,1}, /* tuner, Composit, SVid, Composit-on-Svid-adapter*/
+        tuner_type:     TUNER_MT2032,
+	pll:		PLL_28,
+	has_radio:	1,
+},{
+	/* Philip Blundell <pb@nexus.co.uk> */
+	name:           "Active Imaging AIMMS",
+	video_inputs:   1,
+	audio_inputs:   0,
+	tuner:          -1,
+	tuner_type:     -1,
+	pll:            PLL_28,
+	muxsel:         { 2 },
+	gpiomask:       0
+},{
+        /* Tomasz Pyra <hellfire@sedez.iq.pl> */
+        name:           "PV-BT878P+",
+        video_inputs:   3,
+        audio_inputs:   4,
+        tuner:          0,
+        svhs:           2,
+        gpiomask:       15,
+        muxsel:         { 2, 3, 1, 1},
+        audiomux:       { 0, 0, 11, 7, 13, 0},
+        needs_tvaudio:  1,
+        pll:            PLL_28,
+        tuner_type:     25,
+},{
+	name:		"Flyvideo 98EZ (capture only)",
+	video_inputs:	4,
+	audio_inputs:   0,
+	tuner:		-1,
+	svhs:		2,
+	muxsel:		{ 2, 3, 1, 1}, // AV1, AV2, SVHS, CVid adapter on SVHS
+	pll:		PLL_28,
+	no_msp34xx:	1,
+},{
+
+/* ---- card 0x48 ---------------------------------- */
+	/* Dariusz Kowalewski <darekk@automex.pl> */
+	name:		"Prolink PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
+	video_inputs:	3,
+	audio_inputs:	1,
+	tuner:		0,
+	svhs:		2,
+	gpiomask:	0x3f,
+	muxsel:		{ 2, 3, 0, 1 },
+	audiomux:	{ 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
+	needs_tvaudio:  1,
+	no_msp34xx:	1,
+	no_tda9875:	1,
+	pll:		PLL_28,
+	tuner_type:	-1,
+	audio_hook:	pvbt878p9b_audio,
+	has_radio:	1,
+}
+};
 
 const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
 
@@ -1036,17 +1138,17 @@
 		
 		if (type != -1) {
 			/* found it */
-			printk(KERN_INFO "bttv%d: subsystem: %04x:%04x  =>  %s  =>  card=%d\n",
-			       btv->nr, btv->cardid & 0xffff, btv->cardid >> 16,
-			       cards[type].name,cards[type].cardnr);
+			printk(KERN_INFO "bttv%d: detected: %s [card=%d], "
+			       "PCI subsystem ID is %04x:%04x\n",
+			       btv->nr,cards[type].name,cards[type].cardnr,
+			       btv->cardid & 0xffff, btv->cardid >> 16);
 			btv->type = cards[type].cardnr;
 		} else {
 			/* 404 */
 			printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n",
 			       btv->nr, btv->cardid&0xffff, btv->cardid>>16);
 			printk(KERN_DEBUG "please mail id, board name and "
-			       "the correct card= insmod option to "
-			       "kraxel@goldbach.in-berlin.de\n");
+			       "the correct card= insmod option to kraxel@bytesex.org\n");
 		}
 	}
 
@@ -1059,7 +1161,8 @@
 		btv->id,
 		(btv->id==848 && btv->revision==0x12) ? "A" : "",
 		bttv_tvcards[btv->type].name);
-	printk(KERN_INFO "bttv%d: model: %s [%s]\n",btv->nr,btv->video_dev.name,
+	printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->nr,
+	       btv->video_dev.name,btv->type,
 	       (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) ?
 	       "insmod option" : "autodetected");
 
@@ -1128,7 +1231,8 @@
 				btv->type = BTTV_PINNACLEPRO;
 		}
 		if (bttv_verbose)
-			printk("bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
+			printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d "
+			       "radio=%s stereo=%s\n",
 			       btv->nr, id+1, btv->tuner_type,
 			       !btv->has_radio ? "no" :
 				   (btv->has_matchbox ? "matchbox" : "fmtuner"),
@@ -1148,6 +1252,11 @@
                 hauppauge_eeprom(btv);
         }
 
+	if (btv->type == BTTV_AVERMEDIA98 || btv->type == BTTV_AVPHONE98) {
+		bttv_readee(btv,eeprom_data,0xa0);
+		avermedia_eeprom(btv);
+	}
+
  	if (btv->type == BTTV_PXC200)
 		init_PXC200(btv);
 
@@ -1166,7 +1275,13 @@
 			printk("bttv%d: lifetec: tv mono/fm stereo card\n", btv->nr);
 		else
 			printk("bttv%d: lifetec: stereo(TDA9821) card\n",btv->nr);
-		btv->has_radio=1;
+	}
+
+	if (btv->type == BTTV_MAGICTVIEW061) {
+		if(btv->cardid == 0x4002144f) {
+			btv->has_radio=1;
+			printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->nr);
+		}
 	}
 
 	/* pll configuration */
@@ -1210,6 +1325,9 @@
 	if (btv->tuner_type != -1)
 		bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
 
+	if (bttv_tvcards[btv->type].has_radio)
+		btv->has_radio=1;
+
 	/* try to detect audio/fader chips */
 	if (!bttv_tvcards[btv->type].no_msp34xx &&
 	    bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) {
@@ -1217,7 +1335,8 @@
 			request_module("msp3400");
 	}
 
-	if (bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) {
+	if (!bttv_tvcards[btv->type].no_tda9875 &&
+	    bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) {
 		if (autoload)
 			request_module("tda9875");
 	}
@@ -1307,7 +1426,8 @@
 	int blk2,tuner,radio,model;
 
 	if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0)
-		printk("bttv%d: Hauppauge eeprom: invalid\n",btv->nr);
+		printk(KERN_WARNING "bttv%d: Hauppauge eeprom: invalid\n",
+		       btv->nr);
 
 	/* Block 2 starts after len+3 bytes header */
 	blk2 = eeprom_data[1] + 3;
@@ -1323,24 +1443,83 @@
 		btv->has_radio = 1;
 	
 	if (bttv_verbose)
-		printk("bttv%d: Hauppauge eeprom: model=%d, tuner=%s (%d), radio=%s\n",
+		printk(KERN_INFO "bttv%d: Hauppauge eeprom: model=%d, "
+		       "tuner=%s (%d), radio=%s\n",
 		       btv->nr, model, hauppauge_tuner[tuner].name,
 		       btv->tuner_type, radio ? "yes" : "no");
 }
 
-void __devinit bttv_hauppauge_boot_msp34xx(struct bttv *btv)
+// AVermedia specific stuff...
+// from  bktr_card.c
+int tuner_0_table[] = {
+        TUNER_PHILIPS_NTSC,  TUNER_PHILIPS_PAL,
+        TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL,
+        TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL,
+        TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
+        TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL};
+/*
+int tuner_0_fm_table[] = {
+        PHILIPS_FR1236_NTSC,  PHILIPS_FR1216_PAL,
+        PHILIPS_FR1216_PAL,   PHILIPS_FR1216_PAL,
+        PHILIPS_FR1216_PAL,   PHILIPS_FR1216_PAL,
+        PHILIPS_FR1236_SECAM, PHILIPS_FR1236_SECAM,
+        PHILIPS_FR1236_SECAM, PHILIPS_FR1216_PAL};
+*/
+
+int tuner_1_table[] = {
+        TUNER_TEMIC_NTSC,  TUNER_TEMIC_PAL,
+	TUNER_TEMIC_PAL,   TUNER_TEMIC_PAL,
+	TUNER_TEMIC_PAL,   TUNER_TEMIC_PAL,
+        TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, //TUNER_TEMIC_SECAM
+        TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
+
+static void __devinit avermedia_eeprom(struct bttv *btv)
 {
-        /* reset/enable the MSP on some Hauppauge cards */
-        /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */
-        btaor(32, ~32, BT848_GPIO_OUT_EN);
-        btaor(0, ~32, BT848_GPIO_DATA);
+        int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
+
+	tuner_make   = (eeprom_data[0x41] & 0x7);
+        tuner_tv_fm  = (eeprom_data[0x41] & 0x18) >> 3;
+        tuner_format = (eeprom_data[0x42] & 0xf0) >> 4;
+
+	if (tuner_make == 0 || tuner_make == 2)
+		if(tuner_format <=9)
+			tuner = tuner_0_table[tuner_format];
+	if (tuner_make == 1)
+		if(tuner_format <=9)
+			tuner = tuner_1_table[tuner_format];
+	
+	printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=",
+		btv->nr,eeprom_data[0x41],eeprom_data[0x42]);
+	if(tuner) {
+		btv->tuner_type=tuner;
+		printk("%d\n",tuner);
+	} else
+		printk("Unknown type\n");
+}
+
+
+
+/*
+ * reset/enable the MSP on some Hauppauge cards
+ * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
+ *
+ * Hauppauge:  pin  5
+ * Voodoo:     pin 20
+ */
+void __devinit bttv_boot_msp34xx(struct bttv *btv, int pin)
+{
+	int mask = (1 << pin);
+
+        btaor(mask, ~mask, BT848_GPIO_OUT_EN);
+        btaor(0, ~mask, BT848_GPIO_DATA);
         udelay(2500);
-        btaor(32, ~32, BT848_GPIO_DATA);
+        btaor(mask, ~mask, BT848_GPIO_DATA);
 	if (bttv_gpio)
 		bttv_gpio_tracking(btv,"msp34xx");
 
 	if (bttv_verbose)
-		printk("bttv%d: Hauppauge msp34xx: reset line init\n",btv->nr);
+		printk(KERN_INFO "bttv%d: Hauppauge/Voodoo msp34xx: reset line "
+		       "init [%d]\n", btv->nr, pin);
 }
 
 
@@ -1352,9 +1531,9 @@
 
 static void __devinit init_PXC200(struct bttv *btv)
 {
-	static const int vals[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d,
-				    0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
-				    0x00 };
+	static int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d,
+					    0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+					    0x00 };
 	int i,tmp;
 
 	/* Initialise GPIO-connevted stuff */
@@ -1465,7 +1644,7 @@
 	    BUS_IN(btv->mbox_data) && time_before(jiffies, timeout);
 	    schedule());	/* 10 s */
 	if (BUS_IN(btv->mbox_data)) {
-		printk("bttv%d: tea5757: read timeout\n",btv->nr);
+		printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->nr);
 		return -1;
 	}
 	for(timeout = jiffies + HZ/5;
@@ -1706,6 +1885,43 @@
 	}
 }
 
+/*
+ * Dariusz Kowalewski <darekk@automex.pl>
+ * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
+ * revision 9B has on-board TDA9874A sound decoder).
+ */
+static void
+pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+	unsigned int val = 0;
+
+#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0)
+	if (btv->radio_user)
+		return;
+#else
+	if (btv->radio)
+		return;
+#endif
+
+	if (set) {
+		if (v->mode & VIDEO_SOUND_MONO)	{
+			val = 0x01;
+		}
+		if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
+		    || (v->mode & VIDEO_SOUND_STEREO)) {
+			val = 0x02;
+		}
+		if (val) {
+			btaor(val, ~0x03, BT848_GPIO_DATA);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"pvbt878p9b");
+		}
+	} else {
+		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+			  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+	}
+}
+
 /* ----------------------------------------------------------------------- */
 /* motherboard chipset specific stuff                                      */
 
@@ -1717,13 +1933,16 @@
 	/* for 2.4.x we'll use the pci quirks (drivers/pci/quirks.c) */
 	if (pci_pci_problems & PCIPCI_FAIL)
 		pcipci_fail = 1;
-
 	if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
 		triton1 = 1;
-	while ((dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, dev)))
+	if (pci_pci_problems & PCIPCI_VSFX)
 		vsfx = 1;
 
-	/* print warnings about quirks found */
+	/* print which chipset we have */
+	while ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8,dev)))
+		printk(KERN_INFO "bttv: Host bridge is %s\n",dev->name);
+
+	/* print warnings about any quirks found */
 	if (triton1)
 		printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n");
 	if (vsfx)
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- v2.4.12/linux/drivers/media/video/bttv-driver.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/bttv-driver.c	Wed Oct 17 14:19:20 2001
@@ -104,7 +104,7 @@
 MODULE_PARM(vbi_nr,"i");
 
 MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards");
-MODULE_AUTHOR("Ralph  Metzler & Marcus Metzler & Gerd Knorr");
+MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
 MODULE_LICENSE("GPL");
 
 /* kernel args */
@@ -209,9 +209,11 @@
 	unsigned long adr, page;
 
 	mem=vmalloc_32(size);
-	if (mem) 
-	{
-		memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+	if (NULL == mem)
+		printk(KERN_INFO "bttv: vmalloc_32(%ld) failed\n",size);
+	else {
+		/* Clear the ram out, no junk to the user */
+		memset(mem, 0, size);
 	        adr=(unsigned long) mem;
 		while (size > 0) 
                 {
@@ -475,7 +477,13 @@
  	/* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
         { 35468950,
           924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
-          1135, 186, 924, 0x20, 255},
+          1135, 186, 924,
+#ifdef VIDEODAT_HACK
+	  VBI_MAXLINES*2,
+#else
+	  0x20,
+#endif
+	  255},
 
 	/* NTSC */
 	{ 28636363,
@@ -526,7 +534,7 @@
 		       btv->nr,virt_to_bus(po), virt_to_bus(pe));
         
 	*(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0;
-	for (i=0; i<16; i++) 
+	for (i=0; i<VBI_MAXLINES; i++) 
 	{
 		*(po++)=cpu_to_le32(VBI_RISC);
 		*(po++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048));
@@ -535,7 +543,7 @@
 	*(po++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+4));
 
 	*(pe++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(pe++)=0;
-	for (i=16; i<32; i++) 
+	for (i=VBI_MAXLINES; i<VBI_MAXLINES*2; i++) 
 	{
 		*(pe++)=cpu_to_le32(VBI_RISC);
 		*(pe++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048));
@@ -553,23 +561,23 @@
 };
 
 static int palette2fmt[] = {
-       0,
-       BT848_COLOR_FMT_Y8,
-       BT848_COLOR_FMT_RGB8,
-       BT848_COLOR_FMT_RGB16,
-       BT848_COLOR_FMT_RGB24,
-       BT848_COLOR_FMT_RGB32,
-       BT848_COLOR_FMT_RGB15,
-       BT848_COLOR_FMT_YUY2,
-       BT848_COLOR_FMT_BtYUV,
-       -1,
-       -1,
-       -1,
-       BT848_COLOR_FMT_RAW,
-       BT848_COLOR_FMT_YCrCb422,
-       BT848_COLOR_FMT_YCrCb411,
-       BT848_COLOR_FMT_YCrCb422,
-       BT848_COLOR_FMT_YCrCb411,
+	0,
+	BT848_COLOR_FMT_Y8,
+	BT848_COLOR_FMT_RGB8,
+	BT848_COLOR_FMT_RGB16,
+	BT848_COLOR_FMT_RGB24,
+	BT848_COLOR_FMT_RGB32,
+	BT848_COLOR_FMT_RGB15,
+	BT848_COLOR_FMT_YUY2,
+	BT848_COLOR_FMT_YUY2,
+	-1,
+	-1,
+	-1,
+	BT848_COLOR_FMT_RAW,
+	BT848_COLOR_FMT_YCrCb422,
+	BT848_COLOR_FMT_YCrCb411,
+	BT848_COLOR_FMT_YCrCb422,
+	BT848_COLOR_FMT_YCrCb411,
 };
 #define PALETTEFMT_MAX (sizeof(palette2fmt)/sizeof(int))
 
@@ -2626,7 +2634,9 @@
 
 	/* needs to be done before i2c is registered */
         if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878)
-                bttv_hauppauge_boot_msp34xx(btv);
+                bttv_boot_msp34xx(btv,5);
+	if (btv->type == BTTV_VOODOOTV_FM)
+		bttv_boot_msp34xx(btv,20);
 
 	/* register i2c */
         btv->tuner_type=-1;
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/bttv-if.c linux/drivers/media/video/bttv-if.c
--- v2.4.12/linux/drivers/media/video/bttv-if.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/bttv-if.c	Wed Oct 17 14:19:20 2001
@@ -209,7 +209,8 @@
 	if (btv->tuner_type != -1)
 		bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
         if (bttv_verbose)
-		printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name);
+		printk("bttv%d: i2c attach [client=%s,%s]\n",btv->nr,
+		       client->name, (i < I2C_CLIENTS_MAX) ?  "ok" : "failed");
         return 0;
 }
 
@@ -218,14 +219,15 @@
         struct bttv *btv = (struct bttv*)client->adapter->data;
 	int i;
 
-        if (bttv_verbose)
-		printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name);
 	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
 		if (btv->i2c_clients[i] == client) {
 			btv->i2c_clients[i] = NULL;
 			break;
 		}
 	}
+        if (bttv_verbose)
+		printk("bttv%d: i2c detach [client=%s,%s]\n",btv->nr,
+		       client->name, (i < I2C_CLIENTS_MAX) ?  "ok" : "failed");
         return 0;
 }
 
@@ -351,7 +353,6 @@
 	btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap);
 	return btv->i2c_rc;
 }
-MODULE_LICENSE("GPL");
 
 /*
  * Local variables:
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/bttv.h linux/drivers/media/video/bttv.h
--- v2.4.12/linux/drivers/media/video/bttv.h	Sun Aug 12 13:27:59 2001
+++ linux/drivers/media/video/bttv.h	Wed Oct 17 14:19:20 2001
@@ -81,6 +81,13 @@
 #define BTTV_ATI_TVWONDERVE 0x40
 #define BTTV_FLYVIDEO2000   0x41
 #define BTTV_TERRATVALUER   0x42
+#define BTTV_GVBCTV4PCI     0x43
+#define BTTV_VOODOOTV_FM    0x44
+#define BTTV_AIMMS          0x45
+#define BTTV_PV_BT878P_PLUS 0x46
+#define BTTV_FLYVIDEO98EZ   0x47
+#define BTTV_PV_BT878P_9B   0x48
+
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -88,6 +95,7 @@
 #define I2C_TDA8425        0x82
 #define I2C_TDA9840        0x84
 #define I2C_TDA9850        0xb6 /* also used by 9855,9873 */
+#define I2C_TDA9874A       0xb0 /* also used by 9875 */
 #define I2C_TDA9875        0xb0
 #define I2C_HAUPEE         0xa0
 #define I2C_STBEE          0xae
@@ -121,6 +129,7 @@
 
 	/* i2c audio flags */
 	int no_msp34xx:1;
+	int no_tda9875:1;
 	int needs_tvaudio:1;
 
 	/* other settings */
@@ -130,6 +139,7 @@
 #define PLL_35   2
 
 	int tuner_type;
+	int has_radio;
 	void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
 };
 
@@ -142,7 +152,7 @@
 
 /* card-specific funtions */
 extern void tea5757_set_freq(struct bttv *btv, unsigned short freq);
-extern void bttv_hauppauge_boot_msp34xx(struct bttv *btv);
+extern void bttv_boot_msp34xx(struct bttv *btv, int pin);
 
 /* kernel cmd line parse helper */
 extern int bttv_parse(char *str, int max, int *vals);
@@ -195,7 +205,7 @@
 extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
 
 /* i2c */
-#define I2C_CLIENTS_MAX 8
+#define I2C_CLIENTS_MAX 16
 extern void bttv_bit_setscl(void *data, int state);
 extern void bttv_bit_setsda(void *data, int state);
 extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
@@ -205,3 +215,8 @@
 extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
 
 #endif /* _BTTV_H_ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/bttvp.h linux/drivers/media/video/bttvp.h
--- v2.4.12/linux/drivers/media/video/bttvp.h	Sun Aug 12 13:27:59 2001
+++ linux/drivers/media/video/bttvp.h	Wed Oct 17 14:19:20 2001
@@ -25,7 +25,7 @@
 #ifndef _BTTVP_H_
 #define _BTTVP_H_
 
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,72)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,83)
 
 
 #include <linux/types.h>
@@ -62,10 +62,14 @@
 #define O_NONCAP	O_TRUNC
 #endif
 
+#ifdef VIDEODAT_HACK
+# define VBI_MAXLINES   19
+#else
+# define VBI_MAXLINES   16
+#endif
+#define VBIBUF_SIZE     (2048*VBI_MAXLINES*2)
 #define MAX_GBUFFERS	64
 #define RISCMEM_LEN	(32744*2)
-#define VBI_MAXLINES    16
-#define VBIBUF_SIZE     (2048*VBI_MAXLINES*2)
 
 #define BTTV_MAX_FBUF	0x208000
 
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/bw-qcam.c linux/drivers/media/video/bw-qcam.c
--- v2.4.12/linux/drivers/media/video/bw-qcam.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/bw-qcam.c	Thu Oct 11 09:14:32 2001
@@ -1,8 +1,6 @@
 /*
  *    QuickCam Driver For Video4Linux.
  *
- *	This version only works as a module.
- *
  *	Video4Linux conversion work by Alan Cox.
  *	Parport compatibility by Phil Blundell.
  *	Busy loop avoidance by Mark Cooke.
@@ -991,11 +989,20 @@
 MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "s");
 #endif
 
-#ifdef MODULE
-int init_module(void)
+static void __exit exit_bw_qcams(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_cams; i++)
+		close_bwqcam(qcams[i]);
+}
+
+static int __init init_bw_qcams(void)
 {
 	struct parport *port;
+#ifdef MODULE
 	int n;
+	
 	if(parport[0] && strncmp(parport[0], "auto", 4)){
 		/* user gave parport parameters */
 		for(n=0; parport[n] && n<MAX_CAMS; n++){
@@ -1033,22 +1040,14 @@
 	}
 
 	return (num_cams)?0:-ENODEV;
-}
-
-void cleanup_module(void)
-{
-	unsigned int i;
-	for (i = 0; i < num_cams; i++)
-		close_bwqcam(qcams[i]);
-}
 #else
-int __init init_bw_qcams(struct video_init *unused)
-{
-	struct parport *port;
-
 	for (port = parport_enumerate(); port; port=port->next)
 		init_bwqcam(port);
 	return 0;
-}
 #endif
+}
+
+module_init(init_bw_qcams);
+module_exit(exit_bw_qcams);
+
 MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/id.h linux/drivers/media/video/id.h
--- v2.4.12/linux/drivers/media/video/id.h	Sun Nov 12 20:47:19 2000
+++ linux/drivers/media/video/id.h	Wed Oct 17 14:19:20 2001
@@ -24,3 +24,6 @@
 #ifndef  I2C_DRIVERID_TDA7432
 # define I2C_DRIVERID_TDA7432 I2C_DRIVERID_EXP0+6
 #endif
+#ifndef  I2C_DRIVERID_TDA9874A
+# define I2C_DRIVERID_TDA9874A I2C_DRIVERID_EXP0+7
+#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/msp3400.c linux/drivers/media/video/msp3400.c
--- v2.4.12/linux/drivers/media/video/msp3400.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/msp3400.c	Wed Oct 17 14:19:20 2001
@@ -1,7 +1,7 @@
 /*
  * programming the msp34* sound processor family
  *
- * (c) 1997-2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
  *
  * what works and what doesn't:
  *
@@ -97,7 +97,6 @@
 	int nicam_on;
 	int acb;
 	int main, second;	/* sound carrier */
-	int scart;              /* input is scart (extern) */
 
 	int muted;
 	int left, right;	/* volume */
@@ -131,8 +130,10 @@
 MODULE_PARM(simple,"i");
 MODULE_PARM(amsound,"i");
 MODULE_PARM(dolby,"i");
-MODULE_LICENSE("GPL");
 
+MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
 
 /* ---------------------------------------------------------------------- */
 
@@ -231,6 +232,7 @@
 #define MSP_MODE_FM_NICAM2   6
 #define MSP_MODE_AM_NICAM    7
 #define MSP_MODE_BTSC        8
+#define MSP_MODE_EXTERN      9
 
 static struct MSP_INIT_DATA_DEM {
 	int fir1[6];
@@ -443,6 +445,8 @@
 			       msp_init_data[type].dfp_src);
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,
 			       msp_init_data[type].dfp_src);
+		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,
+			       msp_init_data[type].dfp_src);
 	}
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,
 		       msp_init_data[type].dfp_src);
@@ -507,6 +511,13 @@
 		dprintk("msp3400: BTSC setstereo: %d\n",mode);
 		nicam=0x0300;
 		break;
+	case MSP_MODE_EXTERN:
+		dprintk("msp3400: extern setstereo: %d\n", mode);
+		nicam = 0x0200;
+		break;
+	case MSP_MODE_FM_RADIO:
+		dprintk("msp3400: FM-Radio setstereo: %d\n", mode);
+		break;
 	default:
 		dprintk("msp3400: mono setstereo\n");
 		return;
@@ -537,8 +548,8 @@
 		src = 0x0010 | nicam;
 		break;
 	}
-	if (msp->scart)
-		src |= 0x0200;
+	dprintk("msp3400: setstereo final source/matrix = 0x%x\n", src);
+
 	if (dolby) {
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620);
@@ -727,14 +738,14 @@
 {
 	struct i2c_client *client = data;
 	struct msp3400c *msp = client->data;
-    
+	
 	struct CARRIER_DETECT *cd;
-	int                   count, max1,max2,val1,val2, val,this;
-    
+	int count, max1,max2,val1,val2, val,this;
+	
 #ifdef CONFIG_SMP
 	lock_kernel();
 #endif
-    
+	
 	daemonize();
 	sigfillset(&current->blocked);
 	strcpy(current->comm,"msp3400");
@@ -748,7 +759,7 @@
 	printk("msp3400: daemon started\n");
 	if(msp->notify != NULL)
 		up(msp->notify);
-		
+
 	for (;;) {
 		if (msp->rmmod)
 			goto done;
@@ -760,9 +771,8 @@
 		if (msp->rmmod || signal_pending(current))
 			goto done;
 
-		if (VIDEO_MODE_RADIO == msp->norm)
-			continue;  /* nothing to do */
-		if (msp->scart)
+		if (VIDEO_MODE_RADIO == msp->norm ||
+		    MSP_MODE_EXTERN  == msp->mode)
 			continue;  /* nothing to do */
 	
 		msp->active = 1;
@@ -780,10 +790,9 @@
 			goto done;
 		
 	restart:
-		if (msp->scart)
-			continue;
-		if (VIDEO_MODE_RADIO == msp->norm)
-			continue;
+		if (VIDEO_MODE_RADIO == msp->norm ||
+		    MSP_MODE_EXTERN  == msp->mode)
+			continue;  /* nothing to do */
 		msp->restart = 0;
 		msp3400c_setvolume(client, msp->muted, 0, 0);
 		msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
@@ -1018,7 +1027,7 @@
 		if (msp->rmmod || signal_pending(current))
 			goto done;
 
-		if (msp->scart)
+		if (msp->mode == MSP_MODE_EXTERN)
 			continue;
 		
 		msp->active = 1;
@@ -1036,7 +1045,7 @@
 			goto done;
 
 	restart:
-		if (msp->scart)
+		if (msp->mode == MSP_MODE_EXTERN)
 			continue;
 		msp->restart = 0;
 		del_timer(&msp->wake_stereo);
@@ -1159,6 +1168,8 @@
 			/* scart routing */
 			msp3400c_set_scart(client,SCART_IN2,0);
 			msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220);
+			msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0220);
+			msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0220);
 			break;
 		case 0x0003:
 			msp->mode   = MSP_MODE_FM_TERRA;
@@ -1353,7 +1364,19 @@
 	return 0;
 }
 
-static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
+static void msp_wake_thread(struct i2c_client *client)
+{
+	struct msp3400c *msp  = (struct msp3400c*)client->data;
+
+	msp3400c_setvolume(client,msp->muted,0,0);
+	msp->watch_stereo=0;
+	del_timer(&msp->wake_stereo);
+	if (msp->active)
+		msp->restart = 1;
+	wake_up_interruptible(&msp->wq);
+}
+
+static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct msp3400c *msp  = (struct msp3400c*)client->data;
         __u16           *sarg = arg;
@@ -1368,21 +1391,24 @@
 		     - IN1 is often used for external input
 		     - Hauppauge uses IN2 for the radio */
 		dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg);
-		msp->scart = 0;
 		switch (*sarg) {
 		case AUDIO_RADIO:
+			msp->mode   = MSP_MODE_FM_RADIO;
+			msp->stereo = VIDEO_SOUND_STEREO;
 			msp3400c_set_scart(client,SCART_IN2,0);
 			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
 			msp3400c_setstereo(client,msp->stereo);
 			break;
 		case AUDIO_EXTERN:
-			msp->scart = 1;
+			msp->mode   = MSP_MODE_EXTERN;
+			msp->stereo = VIDEO_SOUND_STEREO;
 			msp3400c_set_scart(client,SCART_IN1,0);
 			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
 			msp3400c_setstereo(client,msp->stereo);
 			break;
 		case AUDIO_TUNER:
-			msp3400c_setstereo(client,msp->stereo);
+			msp->mode   = -1;
+			msp_wake_thread(client);
 			break;
 		default:
 			if (*sarg & AUDIO_MUTE)
@@ -1400,8 +1426,7 @@
 		dprintk("msp34xx: switching to radio mode\n");
 		if (msp->simple) {
 			/* the thread will do for us */
-			msp3400c_setvolume(client,msp->muted,0,0);
-			wake_up_interruptible(&msp->wq);
+			msp_wake_thread(client);
 		} else {
 			/* set msp3400 to FM radio mode */
 			msp3400c_setmode(client,MSP_MODE_FM_RADIO);
@@ -1457,6 +1482,8 @@
 			(va->volume ? va->volume : 1);
 		va->balance=(msp->left<msp->right)?
 			(65535-va->balance) : va->balance;
+		if (0 == va->volume)
+			va->balance = 32768;
 		va->bass = msp->bass;
 		va->treble = msp->treble;
 
@@ -1500,12 +1527,7 @@
 	case VIDIOCSFREQ:
 	{
 		/* new channel -- kick audio carrier scan */
-		msp3400c_setvolume(client,msp->muted,0,0);
-		msp->watch_stereo=0;
-		del_timer(&msp->wake_stereo);
-		if (msp->active)
-			msp->restart = 1;
-		wake_up_interruptible(&msp->wq);
+		msp_wake_thread(client);
 		break;
 	}
 
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/planb.c linux/drivers/media/video/planb.c
--- v2.4.12/linux/drivers/media/video/planb.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/planb.c	Thu Oct 11 09:14:32 2001
@@ -55,12 +55,18 @@
 #include "planb.h"
 #include "saa7196.h"
 
-
 /* Would you mind for some ugly debugging? */
-//#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */
-#define DEBUG(x...) 		/* Don't debug driver */	
-//#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */
+#if 0
+#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */
+#else
+#define DEBUG(x...) 		/* Don't debug driver */
+#endif
+
+#if 0
+#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */
+#endif
 #define IDEBUG(x...) 		/* Don't debug interrupt part */
+#endif
 
 /* Ever seen a Mac with more than 1 of these? */
 #define PLANB_MAX 1
@@ -2271,14 +2277,8 @@
 	}
 }
 
-#ifdef MODULE
-
-int init_module(void)
-{
-#else
-int __init init_planbs(struct video_init *unused)
+static int __init init_planbs(void)
 {
-#endif
 	int i;
   
 	if (find_planb()<=0)
@@ -2296,11 +2296,10 @@
 	return 0;
 }
 
-#ifdef MODULE
-
-void cleanup_module(void)
+static void __exit exit_planbs(void)
 {
 	release_planb();
 }
 
-#endif
+module_init(init_planbs);
+module_exit(exit_planbs);
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/saa7110.c linux/drivers/media/video/saa7110.c
--- v2.4.12/linux/drivers/media/video/saa7110.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/saa7110.c	Thu Oct 11 09:14:32 2001
@@ -306,7 +306,7 @@
 				saa7110_write(decoder, 0x0D, 0x06);
 				saa7110_write(decoder, 0x11, 0x2C);
 				saa7110_write(decoder, 0x30, 0x81);
-saa7110_write(decoder, 0x2A, 0xDF);
+				saa7110_write(decoder, 0x2A, 0xDF);
 				break;
 			 case VIDEO_MODE_PAL:
 				saa7110_write(decoder, 0x0D, 0x06);
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/tda7432.c linux/drivers/media/video/tda7432.c
--- v2.4.12/linux/drivers/media/video/tda7432.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/tda7432.c	Wed Oct 17 14:19:20 2001
@@ -52,7 +52,6 @@
 MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip");
 MODULE_LICENSE("GPL");
 
-
 MODULE_PARM(debug,"i");
 MODULE_PARM(loudness,"i");
 static int loudness = 0; /* disable loudness by default */
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/tda9875.c linux/drivers/media/video/tda9875.c
--- v2.4.12/linux/drivers/media/video/tda9875.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/tda9875.c	Wed Oct 17 14:19:20 2001
@@ -36,7 +36,6 @@
 MODULE_PARM(debug,"i");
 MODULE_LICENSE("GPL");
 
-
 static int debug = 0;	/* insmod parameter */
 
 /* Addresses to scan */
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/tuner.c linux/drivers/media/video/tuner.c
--- v2.4.12/linux/drivers/media/video/tuner.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/tuner.c	Wed Oct 17 14:19:20 2001
@@ -30,25 +30,29 @@
 	force
 };
 
-static int debug =  0; /* insmod parameter */
-static int type  = -1; /* insmod parameter */
-
+/* insmod options */
+static int debug =  0;
+static int type  = -1;
 static int addr  =  0;
 static char *pal =  "b";
-static int this_adap;
 static int tv_range[2]    = { 44, 958 };
 static int radio_range[2] = { 65, 108 };
-
-#define dprintk     if (debug) printk
-
 MODULE_PARM(debug,"i");
 MODULE_PARM(type,"i");
 MODULE_PARM(addr,"i");
 MODULE_PARM(tv_range,"2i");
 MODULE_PARM(radio_range,"2i");
 MODULE_PARM(pal,"s");
+
+#define optimize_vco 1
+
+MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
 MODULE_LICENSE("GPL");
 
+static int this_adap;
+#define dprintk     if (debug) printk
+
 struct tuner
 {
 	int type;            /* chip type */
@@ -56,12 +60,15 @@
 	int std;
 
 	int radio;
-	int mode;            /* PAL(0)/SECAM(1) mode (PHILIPS_SECAM only) */
+	int mode;            /* current norm for multi-norm tuners */
+	int xogc;	     // only for MT2032
 };
 
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
+/* ---------------------------------------------------------------------- */
+
 /* tv standard selection for Temic 4046 FM5
    this value takes the low bits of control byte 2
    from datasheet Rev.01, Feb.00 
@@ -154,13 +161,13 @@
 	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
         { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
 	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
-	{ "Temic PAL_I (4006FH5)", TEMIC, PAL_I,
+	{ "Temic PAL_BG (4006FH5)", TEMIC, PAL,
 	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, 
   	{ "Alps TSCH6",Alps,NTSC,
   	  16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
 
   	{ "Temic PAL_DK (4016 FY5)",TEMIC,PAL,
-  	  16*136.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
+  	  16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
   	{ "Philips NTSC_M (MK2)",Philips,NTSC,
   	  16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
         { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
@@ -191,7 +198,24 @@
 	{ "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL,
 	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
 	{ "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL,
-	  16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}
+	  16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+	{ "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */
+	  16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940},
+
+	{ "Samsung PAL TCPM9091PD27", Samsung, PAL,  /* from sourceforge v3tv */
+          16*169,16*464,0xA0,0x90,0x30,0x8e,623},
+	{ "MT2032 universal", Microtune,PAL|NTSC,
+               0,0,0,0,0,0,0},
+	{ "Temic PAL_BG (4106 FH5)", TEMIC, PAL,
+          16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+	{ "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL,
+          16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
+
+	{ "Temic NTSC (4136 FY5)", TEMIC, NTSC,
+          16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
+        { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
+          16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
+	
 };
 #define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
 
@@ -201,6 +225,11 @@
 {
 	unsigned char byte;
 
+	struct tuner *t = (struct tuner*)c->data;
+
+        if (t->type == TUNER_MT2032)
+		return 0;
+
 	if (1 != i2c_master_recv(c,&byte,1))
 		return 0;
 	return byte;
@@ -241,6 +270,315 @@
         return (tuner_getstatus (c) & TUNER_MODE) >> 3;
 }
 #endif
+// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
+int mt2032_init(struct i2c_client *c)
+{
+        unsigned char buf[21];
+        int ret,xogc,xok=0;
+	struct tuner *t = (struct tuner*)c->data;
+
+        buf[0]=0;
+        ret=i2c_master_send(c,buf,1);
+        i2c_master_recv(c,buf,21);
+
+        printk("MT2032: Companycode=%02x%02x Part=%02x Revision=%02x\n",
+                buf[0x11],buf[0x12],buf[0x13],buf[0x14]);
+
+        if(debug) {
+                int i;
+                printk("MT2032 hexdump:\n");
+                for(i=0;i<21;i++) {
+                        printk(" %02x",buf[i]);
+                        if(((i+1)%8)==0) printk(" ");
+                        if(((i+1)%16)==0) printk("\n ");
+                }
+                printk("\n ");
+        }
+
+        // Initialize Registers per spec.
+        buf[1]=2; // Index to register 2
+        buf[2]=0xff;
+        buf[3]=0x0f;
+        buf[4]=0x1f;
+        ret=i2c_master_send(c,buf+1,4);
+
+        buf[5]=6; // Index register 6
+        buf[6]=0xe4;
+        buf[7]=0x8f;
+        buf[8]=0xc3;
+        buf[9]=0x4e;
+        buf[10]=0xec;
+        ret=i2c_master_send(c,buf+5,6);
+
+        buf[12]=13;  // Index register 13
+        buf[13]=0x32;
+        ret=i2c_master_send(c,buf+12,2);
+
+        // Adjust XOGC (register 7), wait for XOK
+        xogc=7;
+        do {
+		dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07);
+                mdelay(10);
+                buf[0]=0x0e;
+                i2c_master_send(c,buf,1);
+                i2c_master_recv(c,buf,1);
+                xok=buf[0]&0x01;
+                dprintk("mt2032: xok = 0x%02x\n",xok);
+                if (xok == 1) break;
+
+                xogc--;
+                dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07);
+                if (xogc == 3) {
+                        xogc=4; // min. 4 per spec
+                        break;
+                }
+                buf[0]=0x07;
+                buf[1]=0x88 + xogc;
+                ret=i2c_master_send(c,buf,2);
+                if (ret!=2)
+                        printk("mt2032_init failed with %d\n",ret);
+        } while (xok != 1 );
+	t->xogc=xogc;
+
+        return(1);
+}
+
+
+// IsSpurInBand()?
+int mt2032_spurcheck(int f1, int f2, int spectrum_from,int spectrum_to)
+{
+	int n1=1,n2,f;
+
+	f1=f1/1000; //scale to kHz to avoid 32bit overflows
+	f2=f2/1000;
+	spectrum_from/=1000;
+	spectrum_to/=1000;
+
+	dprintk("spurcheck f1=%d f2=%d  from=%d to=%d\n",f1,f2,spectrum_from,spectrum_to);
+
+	do {
+	    n2=-n1;
+	    f=n1*(f1-f2);
+	    do {
+		n2--;
+		f=f-f2;
+		dprintk(" spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f);
+
+		if( (f>spectrum_from) && (f<spectrum_to))
+			printk("mt2032 spurcheck triggered: %d\n",n1);
+	    } while ( (f>(f2-spectrum_to)) || (n2>-5));
+	    n1++;
+	} while (n1<5);
+
+	return 1;
+}
+
+int mt2032_compute_freq(int rfin, int if1, int if2, int spectrum_from,
+	int spectrum_to, unsigned char *buf, int *ret_sel, int xogc) //all in Hz
+{
+        int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
+		desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
+
+        fref= 5250 *1000; //5.25MHz
+	desired_lo1=rfin+if1;
+
+	lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000);
+        lo1n=lo1/8;
+        lo1a=lo1-(lo1n*8);
+
+        s=rfin/1000/1000+1090;
+
+	if(optimize_vco) {
+		if(s>1890) sel=0;
+		else if(s>1720) sel=1;
+		else if(s>1530) sel=2;
+		else if(s>1370) sel=3;
+		else sel=4; // >1090
+	}
+	else {
+        	if(s>1790) sel=0; // <1958
+        	else if(s>1617) sel=1;
+        	else if(s>1449) sel=2;
+        	else if(s>1291) sel=3;
+        	else sel=4; // >1090
+	}
+	*ret_sel=sel;
+
+        lo1freq=(lo1a+8*lo1n)*fref;
+
+        dprintk("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n",
+		rfin,lo1,lo1n,lo1a,sel,lo1freq);
+
+        desired_lo2=lo1freq-rfin-if2;
+        lo2=(desired_lo2)/fref;
+        lo2n=lo2/8;
+        lo2a=lo2-(lo2n*8);
+        lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
+        lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
+
+        dprintk("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
+		rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
+
+        if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
+                printk("mt2032: frequency parameters out of range: %d %d %d %d\n",
+		       lo1a, lo1n, lo2a,lo2n);
+                return(-1);
+        }
+
+	mt2032_spurcheck(lo1freq, desired_lo2,  spectrum_from, spectrum_to);
+	// should recalculate lo1 (one step up/down)
+
+	// set up MT2032 register map for transfer over i2c
+	buf[0]=lo1n-1;
+	buf[1]=lo1a | (sel<<4);
+	buf[2]=0x86; // LOGC
+	buf[3]=0x0f; //reserved
+	buf[4]=0x1f;
+	buf[5]=(lo2n-1) | (lo2a<<5);
+ 	if(rfin >400*1000*1000)
+                buf[6]=0xe4;
+        else
+                buf[6]=0xf4; // set PKEN per rev 1.2 
+	buf[7]=8+xogc;
+	buf[8]=0xc3; //reserved
+	buf[9]=0x4e; //reserved
+	buf[10]=0xec; //reserved
+	buf[11]=(lo2num&0xff);
+	buf[12]=(lo2num>>8) |0x80; // Lo2RST
+
+	return 0;
+}
+
+int mt2032_check_lo_lock(struct i2c_client *c)
+{
+	int try,lock=0;
+	unsigned char buf[2];
+	for(try=0;try<10;try++) {
+		buf[0]=0x0e;
+		i2c_master_send(c,buf,1);
+		i2c_master_recv(c,buf,1);
+		dprintk("mt2032 Reg.E=0x%02x\n",buf[0]);
+		lock=buf[0] &0x06;
+		
+		if (lock==6)
+			break;
+		
+		dprintk("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]);
+		udelay(1000);
+	}
+        return lock;
+}
+
+int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
+{
+	unsigned char buf[2];
+	int tad1;
+
+	buf[0]=0x0f;
+	i2c_master_send(c,buf,1);
+	i2c_master_recv(c,buf,1);
+	dprintk("mt2032 Reg.F=0x%02x\n",buf[0]);
+	tad1=buf[0]&0x07;
+
+	if(tad1 ==0) return lock;
+	if(tad1 ==1) return lock;
+
+	if(tad1==2) {
+		if(sel==0) 
+			return lock;
+		else sel--;
+	}
+	else {
+		if(sel<4)
+			sel++;
+		else
+			return lock;
+	}
+
+	dprintk("mt2032 optimize_vco: sel=%d\n",sel);
+
+	buf[0]=0x0f;
+	buf[1]=sel;
+        i2c_master_send(c,buf,2);
+	lock=mt2032_check_lo_lock(c);
+	return lock;
+}
+
+
+void mt2032_set_if_freq(struct i2c_client *c,int rfin, int if1, int if2, int from, int to)
+{
+	unsigned char buf[21];
+	int lint_try,ret,sel,lock=0;
+	struct tuner *t = (struct tuner*)c->data;
+
+	dprintk("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",rfin,if1,if2,from,to);
+
+        buf[0]=0;
+        ret=i2c_master_send(c,buf,1);
+        i2c_master_recv(c,buf,21);
+
+	buf[0]=0;
+	ret=mt2032_compute_freq(rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
+	if (ret<0)
+		return;
+
+        // send only the relevant registers per Rev. 1.2
+        buf[0]=0;
+        ret=i2c_master_send(c,buf,4);
+        buf[5]=5;
+        ret=i2c_master_send(c,buf+5,4);
+        buf[11]=11;
+        ret=i2c_master_send(c,buf+11,3);
+        if(ret!=3)
+                printk("mt2032_set_if_freq failed with %d\n",ret);
+
+	// wait for PLLs to lock (per manual), retry LINT if not.
+	for(lint_try=0; lint_try<2; lint_try++) {
+		lock=mt2032_check_lo_lock(c);
+		
+		if(optimize_vco)
+			lock=mt2032_optimize_vco(c,sel,lock);
+		if(lock==6) break;
+		
+		printk("mt2032: re-init PLLs by LINT\n"); 
+		buf[0]=7; 
+		buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs
+		i2c_master_send(c,buf,2);
+		mdelay(10);
+		buf[1]=8+t->xogc;
+		i2c_master_send(c,buf,2);
+        }
+
+	if (lock!=6)
+		printk("MT2032 Fatal Error: PLLs didn't lock.\n");
+
+	buf[0]=2;
+	buf[1]=0x20; // LOGC for optimal phase noise
+	ret=i2c_master_send(c,buf,2);
+	if (ret!=2)
+		printk("mt2032_set_if_freq2 failed with %d\n",ret);
+}
+
+
+void mt2032_set_tv_freq(struct i2c_client *c, int freq, int norm)
+{
+	int if2,from,to;
+
+	// signal bandwidth and picture carrier
+	if(norm==VIDEO_MODE_NTSC) {
+		from=40750*1000;
+		to=46750*1000;
+		if2=45750*1000; 
+	}
+	else {  // Pal 
+		from=32900*1000;
+		to=39900*1000;
+		if2=38900*1000;
+	}
+
+        mt2032_set_if_freq(c,freq* 1000*1000/16, 1090*1000*1000, if2, from, to);
+}
+
 
 // Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz
 static void set_tv_freq(struct i2c_client *c, int freq)
@@ -252,6 +590,15 @@
         unsigned char buffer[4];
 	int rc;
 
+	if (t->type == -1) {
+		printk("tuner: tuner type not set\n");
+		return;
+	}
+	if (t->type == TUNER_MT2032) {
+		mt2032_set_tv_freq(c,freq,t->mode);
+		return;
+	}
+
 	if (freq < tv_range[0]*16 || freq > tv_range[1]*16) {
 		/* FIXME: better do that chip-specific, but
 		   right now we don't have that in the config
@@ -259,10 +606,6 @@
 		   check at all */
 		printk("tuner: TV freq (%d.%02d) out of range (%d-%d)\n",
 		       freq/16,freq%16*100/16,tv_range[0],tv_range[1]);
-	}
-
-	if (t->type == -1) {
-		printk("tuner: tuner type not set\n");
 		return;
 	}
 
@@ -282,7 +625,7 @@
 		/* 0x02 -> PAL BDGHI / SECAM L */
 		/* 0x04 -> ??? PAL others / SECAM others ??? */
 		config &= ~0x02;
-		if (t->mode)
+		if (t->mode == VIDEO_MODE_SECAM)
 			config |= 0x02;
 		break;
 
@@ -366,6 +709,15 @@
 
 }
 
+static void mt2032_set_radio_freq(struct i2c_client *c,int freq)
+{               
+        int if2;
+
+        if2=10700*1000; //  10.7MHz FM intermediate frequency
+
+        mt2032_set_if_freq(c,freq* 1000*1000/16, 1085*1000*1000,if2,if2,if2);
+}
+
 static void set_radio_freq(struct i2c_client *c, int freq)
 {
 	u8 config;
@@ -386,6 +738,11 @@
 		return;
 	}
 
+        if (t->type == TUNER_MT2032) {
+                mt2032_set_radio_freq(c,freq);
+		return;
+	}
+
 	tun=&tuners[t->type];
 	config = 0xa4 /* 0xa5 */; /* bit 0 is AFC (set) vs. RF-Signal (clear) */
 	div=freq + (int)(16*10.7);
@@ -448,6 +805,9 @@
 		t->type = -1;
 	}
         i2c_attach_client(client);
+        if (t->type == TUNER_MT2032)
+                 mt2032_init(client);
+
 	MOD_INC_USE_COUNT;
 
 	return 0;
@@ -497,6 +857,8 @@
 		dprintk("tuner: type set to %d (%s)\n",
                         t->type,tuners[t->type].name);
 		strncpy(client->name, tuners[t->type].name, sizeof(client->name));
+		if (t->type == TUNER_MT2032)
+                        mt2032_init(client);
 		break;
 	case AUDC_SET_RADIO:
 		t->radio = 1;
@@ -508,12 +870,11 @@
 	case VIDIOCSCHAN:
 	{
 		struct video_channel *vc = arg;
-		
+
 		t->radio = 0;
-		if (t->type == TUNER_PHILIPS_SECAM) {
-			t->mode = (vc->norm == VIDEO_MODE_SECAM) ? 1 : 0;
+		t->mode = vc->norm;
+		if (t->freq)
 			set_tv_freq(client,t->freq);
-		}
 		return 0;
 	}
 	case VIDIOCSFREQ:
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/tuner.h linux/drivers/media/video/tuner.h
--- v2.4.12/linux/drivers/media/video/tuner.h	Sun Aug 12 13:27:59 2001
+++ linux/drivers/media/video/tuner.h	Wed Oct 17 14:19:20 2001
@@ -22,29 +22,29 @@
 #ifndef _TUNER_H
 #define _TUNER_H
 
-#define TUNER_TEMIC_PAL     0        /* 4002 FH5_9483 */
+#define TUNER_TEMIC_PAL     0        /* 4002 FH5 (3X 7756, 9483) */
 #define TUNER_PHILIPS_PAL_I 1
 #define TUNER_PHILIPS_NTSC  2
 #define TUNER_PHILIPS_SECAM 3		/* you must actively select B/G, L, L` */
 #define TUNER_ABSENT        4
 #define TUNER_PHILIPS_PAL   5
-#define TUNER_TEMIC_NTSC    6        /* 4032 FY5_7004 */
-#define TUNER_TEMIC_PAL_I   7        /* 4062 FY5_9957 */
-#define TUNER_TEMIC_4036FY5_NTSC 8   /* 4036 FY5      */
+#define TUNER_TEMIC_NTSC    6        /* 4032 FY5 (3X 7004, 9498, 9789)  */
+#define TUNER_TEMIC_PAL_I   7        /* 4062 FY5 (3X 8501, 9957)        */
+#define TUNER_TEMIC_4036FY5_NTSC 8   /* 4036 FY5 (3X 1223, 1981, 7686)  */
 #define TUNER_ALPS_TSBH1_NTSC 	 9
 #define TUNER_ALPS_TSBE1_PAL 	10
 #define TUNER_ALPS_TSBB5_PAL_I 	11
 #define TUNER_ALPS_TSBE5_PAL 	12
 #define TUNER_ALPS_TSBC5_PAL 	13
-#define TUNER_TEMIC_4006FH5_PAL	14   /* 4006 FH5      */
+#define TUNER_TEMIC_4006FH5_PAL	14   /* 4006 FH5 (3X 9500, 9501, 7291)     */
 #define TUNER_ALPS_TSHC6_NTSC 	15
-#define TUNER_TEMIC_PAL_DK	16   /* 4016 FY5      */
+#define TUNER_TEMIC_PAL_DK	16   /* 4016 FY5 (3X 1392, 1393)     */
 #define TUNER_PHILIPS_NTSC_M	17
-#define TUNER_TEMIC_4066FY5_PAL_I       18
-#define TUNER_TEMIC_4006FN5_MULTI_PAL   19  /* B/G, I and D/K autodetected */
-#define TUNER_TEMIC_4009FR5_PAL         20  /* incl. FM radio */
-#define TUNER_TEMIC_4039FR5_NTSC        21  /* incl. FM radio */
-#define TUNER_TEMIC_4046FM5             22  /* you must actively select B/G, D/K, I, L, L` !  */
+#define TUNER_TEMIC_4066FY5_PAL_I       18  /* 4066 FY5 (3X 7032, 7035) */
+#define TUNER_TEMIC_4006FN5_MULTI_PAL   19  /* B/G, I and D/K autodetected (3X 7595, 7606, 7657)*/
+#define TUNER_TEMIC_4009FR5_PAL         20  /* incl. FM radio (3X 7607, 7488, 7711)*/
+#define TUNER_TEMIC_4039FR5_NTSC        21  /* incl. FM radio (3X 7246, 7578, 7732)*/
+#define TUNER_TEMIC_4046FM5             22  /* you must actively select B/G, D/K, I, L, L` !  (3X 7804, 7806, 8103, 8104)*/
 #define TUNER_PHILIPS_PAL_DK		23
 #define TUNER_PHILIPS_FQ1216ME		24  /* you must actively select B/G/D/K, I, L, L` */
 #define TUNER_LG_PAL_I_FM	25
@@ -52,7 +52,15 @@
 #define TUNER_LG_NTSC_FM	27
 #define TUNER_LG_PAL_FM		28
 #define TUNER_LG_PAL		29
-#define TUNER_TEMIC_4009FN5_MULTI_PAL_FM	30  /* B/G, I and D/K autodetected */
+#define TUNER_TEMIC_4009FN5_MULTI_PAL_FM	30  /* B/G, I and D/K autodetected (3X 8155, 8160, 8163)*/
+#define TUNER_SHARP_2U5JF5540_NTSC  31
+#define TUNER_Samsung_PAL_TCPM9091PD27 32
+#define TUNER_MT2032 33
+#define TUNER_TEMIC_4106FH5 	34	/* 4106 FH5 (3X 7808, 7865)*/
+#define TUNER_TEMIC_4012FY5	35	/* 4012 FY5 (3X 0971, 1099)*/
+#define TUNER_TEMIC_4136FY5	36	/* 4136 FY5 (3X 7708, 7746)*/
+#define TUNER_LG_PAL_NEW_TAPC   37
+
 
 
 #define NOTUNER 0
@@ -67,6 +75,9 @@
 #define Sony    3
 #define Alps    4
 #define LGINNOTEK 5
+#define SHARP   6
+#define Samsung 7
+#define Microtune 8
 
 #define TUNER_SET_TYPE               _IOW('t',1,int)    /* set tuner type */
 #define TUNER_SET_TVFREQ             _IOW('t',2,int)    /* set tv freq */
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/tvaudio.c linux/drivers/media/video/tvaudio.c
--- v2.4.12/linux/drivers/media/video/tvaudio.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/tvaudio.c	Wed Oct 17 14:19:20 2001
@@ -42,6 +42,9 @@
 
 #define dprintk  if (debug) printk
 
+MODULE_DESCRIPTION("device driver for various i2c TV sound decoder / audiomux chips");
+MODULE_AUTHOR("Eric Sandeen, Steve VanDeBogart, Greg Alexander, Gerd Knorr");
+MODULE_LICENSE("GPL");
 
 /* ---------------------------------------------------------------------- */
 /* our structs                                                            */
@@ -51,6 +54,7 @@
 struct CHIPSTATE;
 typedef int  (*getvalue)(int);
 typedef int  (*checkit)(struct CHIPSTATE*);
+typedef int  (*initialize)(struct CHIPSTATE*);
 typedef int  (*getmode)(struct CHIPSTATE*);
 typedef void (*setmode)(struct CHIPSTATE*, int mode);
 typedef void (*checkmode)(struct CHIPSTATE*);
@@ -70,6 +74,7 @@
 
 	int        *insmodopt;
 	checkit    checkit;
+	initialize initialize;
 	int        flags;
 #define CHIP_HAS_VOLUME      1
 #define CHIP_HAS_BASSTREBLE  2
@@ -134,6 +139,7 @@
 	I2C_TDA9840   >> 1,
 	I2C_TDA985x_L >> 1,
 	I2C_TDA985x_H >> 1,
+	I2C_TDA9874A  >> 1,
 	I2C_PIC16C54  >> 1,
 	I2C_CLIENT_END };
 static unsigned short normal_i2c_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
@@ -216,7 +222,7 @@
                 { chip->c.addr, 0,        1, write },
                 { chip->c.addr, I2C_M_RD, 1, read  }
         };
-        write[1] = subaddr;
+        write[0] = subaddr;
 
 	if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
 		printk(KERN_WARNING "%s: I/O error (read2)\n",
@@ -323,6 +329,8 @@
 
 	if (mode & VIDEO_SOUND_LANG1)
 		desc->setmode(chip,VIDEO_SOUND_LANG1);
+	else if (mode & VIDEO_SOUND_LANG2)
+		desc->setmode(chip,VIDEO_SOUND_LANG2);
 	else if (mode & VIDEO_SOUND_STEREO)
 		desc->setmode(chip,VIDEO_SOUND_STEREO);
 	else
@@ -695,6 +703,7 @@
 		return;
 	}
 
+	chip_write(chip, TDA9873_SW, sw_data);
 	dprintk("tda9873_setmode(): req. mode %d; chip_write: %d\n",
 		mode, sw_data);
 }
@@ -710,6 +719,181 @@
 
 
 /* ---------------------------------------------------------------------- */
+/* audio chip description - defines+functions for tda9874a                */
+/* Dariusz Kowalewski <darekk@automex.pl>                                 */
+
+/* Subaddresses for TDA9874A (slave rx) */
+#define TDA9874A_AGCGR		0x00	/* AGC gain */
+#define TDA9874A_GCONR		0x01	/* general config */
+#define TDA9874A_MSR		0x02	/* monitor select */
+#define TDA9874A_C1FRA		0x03	/* carrier 1 freq. */
+#define TDA9874A_C1FRB		0x04	/* carrier 1 freq. */
+#define TDA9874A_C1FRC		0x05	/* carrier 1 freq. */
+#define TDA9874A_C2FRA		0x06	/* carrier 2 freq. */
+#define TDA9874A_C2FRB		0x07	/* carrier 2 freq. */
+#define TDA9874A_C2FRC		0x08	/* carrier 2 freq. */
+#define TDA9874A_DCR		0x09	/* demodulator config */
+#define TDA9874A_FMER		0x0a	/* FM de-emphasis */
+#define TDA9874A_FMMR		0x0b	/* FM dematrix */
+#define TDA9874A_C1OLAR		0x0c	/* ch.1 output level adj. */
+#define TDA9874A_C2OLAR		0x0d	/* ch.2 output level adj. */
+#define TDA9874A_NCONR		0x0e	/* NICAM config */
+#define TDA9874A_NOLAR		0x0f	/* NICAM output level adj. */
+#define TDA9874A_NLELR		0x10	/* NICAM lower error limit */
+#define TDA9874A_NUELR		0x11	/* NICAM upper error limit */
+#define TDA9874A_AMCONR		0x12	/* audio mute control */
+#define TDA9874A_SDACOSR	0x13	/* stereo DAC output select */
+#define TDA9874A_AOSR		0x14	/* analog output select */
+#define TDA9874A_DAICONR	0x15	/* digital audio interface config */
+#define TDA9874A_I2SOSR		0x16	/* I2S-bus output select */
+#define TDA9874A_I2SOLAR	0x17	/* I2S-bus output level adj. */
+#define TDA9874A_MDACOSR	0x18	/* mono DAC output select */
+#define TDA9874A_ESP		0xFF	/* easy standard progr. */
+
+/* Subaddresses for TDA9874A (slave tx) */
+#define TDA9874A_DSR		0x00	/* device status */
+#define TDA9874A_NSR		0x01	/* NICAM status */
+#define TDA9874A_NECR		0x02	/* NICAM error count */
+#define TDA9874A_DR1		0x03	/* add. data LSB */
+#define TDA9874A_DR2		0x04	/* add. data MSB */
+#define TDA9874A_LLRA		0x05	/* monitor level read-out LSB */
+#define TDA9874A_LLRB		0x06	/* monitor level read-out MSB */
+#define TDA9874A_SIFLR		0x07	/* SIF level */
+#define TDA9874A_TR2		252	/* test reg. 2 */
+#define TDA9874A_TR1		253	/* test reg. 1 */
+#define TDA9874A_DIC		254	/* device id. code */
+#define TDA9874A_SIC		255	/* software id. code */
+
+
+static int tda9874a_mode = 1;		/* 0: A2, 1: NICAM */
+static int tda9874a_GCONR = 0xc0;	/* default config. input pin: SIFSEL=0 */
+static int tda9874a_ESP = 0x07;		/* default standard: NICAM D/K */
+
+/* insmod options for tda9874a */
+static int tda9874a_SIF = -1;
+static int tda9874a_STD = -1;
+MODULE_PARM(tda9874a_SIF,"i");
+MODULE_PARM(tda9874a_STD,"i");
+
+
+static int tda9874a_setup(struct CHIPSTATE *chip)
+{
+	chip_write(chip, TDA9874A_AGCGR, 0x00); /* 0 dB */
+	chip_write(chip, TDA9874A_GCONR, tda9874a_GCONR);
+	chip_write(chip, TDA9874A_MSR, (tda9874a_mode) ? 0x03:0x02);
+	chip_write(chip, TDA9874A_FMMR, 0x80);
+	chip_write(chip, TDA9874A_C1OLAR, 0x00); /* 0 dB */
+	chip_write(chip, TDA9874A_C2OLAR, 0x00); /* 0 dB */
+	chip_write(chip, TDA9874A_NCONR, 0x00); /* not 0x04 as doc. table 10 says! */
+	chip_write(chip, TDA9874A_NOLAR, 0x00); /* 0 dB */
+	chip_write(chip, TDA9874A_AMCONR, 0xf9);
+	chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); /* 0x81 */
+	chip_write(chip, TDA9874A_AOSR, 0x80);
+	chip_write(chip, TDA9874A_MDACOSR, (tda9874a_mode) ? 0x82:0x80);
+	chip_write(chip, TDA9874A_ESP, tda9874a_ESP);
+
+	return 1;
+}
+
+int tda9874a_getmode(struct CHIPSTATE *chip)
+{
+	int dsr,nsr,mode;
+
+	mode = VIDEO_SOUND_MONO;
+
+	if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR)))
+		return mode;
+	if(-1 == (nsr = chip_read2(chip,TDA9874A_NSR)))
+		return mode;
+
+	if(tda9874a_mode) {
+		/* check also DSR.RSSF and DSR.AMSTAT bits? */
+		if(nsr & 0x02) /* NSR.S/MB */
+			mode |= VIDEO_SOUND_STEREO;
+		if(nsr & 0x01) /* NSR.D/SB */ 
+			mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+	} else {
+		if(dsr & 0x02) /* DSR.IDSTE */
+			mode |= VIDEO_SOUND_STEREO;
+		if(dsr & 0x04) /* DSR.IDDUA */
+			mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+	}
+
+	dprintk("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, return: %d.\n",
+		 dsr, nsr, mode);
+	return mode;
+}
+
+void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
+{
+	int aosr=0x80,mdacosr=0x82;
+
+	/* note: TDA9874A has auto-select function for audio output */
+	switch(mode) {
+	case VIDEO_SOUND_MONO:
+	case VIDEO_SOUND_STEREO:
+		break;
+	case VIDEO_SOUND_LANG1:
+		aosr = 0x80; /* dual A/A */
+		mdacosr = (tda9874a_mode) ? 0x82:0x80;
+		break;
+	case VIDEO_SOUND_LANG2:
+		aosr = 0xa0; /* dual B/B */
+		mdacosr = (tda9874a_mode) ? 0x83:0x81;
+		break;
+	default:
+		chip->mode = 0;
+		return;
+	}
+
+	chip_write(chip, TDA9874A_AOSR, aosr);
+	chip_write(chip, TDA9874A_MDACOSR, mdacosr);
+
+	dprintk("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
+		mode, aosr, mdacosr);
+}
+
+int tda9874a_checkit(struct CHIPSTATE *chip)
+{
+	int dic,sic;	/* device id. and software id. codes */
+
+	if(-1 == (dic = chip_read2(chip,TDA9874A_DIC)))
+		return 0;
+	if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
+		return 0;
+
+	dprintk("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
+
+	return((dic & 0xff) == 0x11);
+}
+
+int tda9874a_initialize(struct CHIPSTATE *chip)
+{
+	if(tda9874a_SIF != -1) {
+		if(tda9874a_SIF == 1)
+			tda9874a_GCONR = 0xc0;	/* sound IF input 1 */
+		else if(tda9874a_SIF == 2)
+			tda9874a_GCONR = 0xc1;	/* sound IF input 2 */
+		else
+			printk(KERN_WARNING "tda9874a: SIF parameter must be 1 or 2.\n");
+	}
+
+	if(tda9874a_STD != -1) {
+		if((tda9874a_STD >= 0)&&(tda9874a_STD <= 8)) {
+			tda9874a_ESP = tda9874a_STD;
+			tda9874a_mode = (tda9874a_STD < 5) ? 0 : 1;
+		} else {
+			printk(KERN_WARNING "tda9874a: STD parameter must be between 0 and 8.\n");
+		}
+	}
+
+	tda9874a_setup(chip);
+
+	return 0;
+}
+
+
+/* ---------------------------------------------------------------------- */
 /* audio chip descriptions - defines+functions for tea6420                */
 
 #define TEA6300_VL         0x00  /* volume left */
@@ -779,6 +963,7 @@
 int tda9850  = 1;
 int tda9855  = 1;
 int tda9873  = 1;
+int tda9874a = 1;
 int tea6300  = 0;
 int tea6420  = 1;
 int pic16c54 = 1;
@@ -787,6 +972,7 @@
 MODULE_PARM(tda9850,"i");
 MODULE_PARM(tda9855,"i");
 MODULE_PARM(tda9873,"i");
+MODULE_PARM(tda9874a,"i");
 MODULE_PARM(tea6300,"i");
 MODULE_PARM(tea6420,"i");
 MODULE_PARM(pic16c54,"i");
@@ -829,6 +1015,19 @@
 		
 	},
 	{
+		name:       "tda9874a",
+		id:         I2C_DRIVERID_TDA9874A,
+		checkit:    tda9874a_checkit,
+		initialize: tda9874a_initialize,
+		insmodopt:  &tda9874a,
+		addr_lo:    I2C_TDA9874A >> 1,
+		addr_hi:    I2C_TDA9874A >> 1,
+
+		getmode:    tda9874a_getmode,
+		setmode:    tda9874a_setmode,
+		checkmode:  generic_checkmode,
+	},
+	{
 		name:       "tda9850",
 		id:         I2C_DRIVERID_TDA9850,
 		insmodopt:  &tda9850,
@@ -991,7 +1190,11 @@
 	i2c_attach_client(&chip->c);
 
 	/* initialization  */
-	chip_cmd(chip,"init",&desc->init);
+	if (desc->initialize != NULL)
+		desc->initialize(chip);
+	else
+		chip_cmd(chip,"init",&desc->init);
+
 	if (desc->flags & CHIP_HAS_VOLUME) {
 		chip->left   = desc->leftinit   ? desc->leftinit   : 65536;
 		chip->right  = desc->rightinit  ? desc->rightinit  : 65536;
@@ -1168,7 +1371,6 @@
 
 module_init(audiochip_init_module);
 module_exit(audiochip_cleanup_module);
-MODULE_LICENSE("GPL");
 
 /*
  * Local variables:
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/tvaudio.h linux/drivers/media/video/tvaudio.h
--- v2.4.12/linux/drivers/media/video/tvaudio.h	Sun Nov 12 20:47:19 2000
+++ linux/drivers/media/video/tvaudio.h	Wed Oct 17 14:19:20 2001
@@ -6,6 +6,7 @@
 #define I2C_TDA9840        0x84
 #define I2C_TDA985x_L      0xb4 /* also used by 9873 */
 #define I2C_TDA985x_H      0xb6
+#define I2C_TDA9874A       0xb0 /* also used by 9875 */
 
 #define I2C_TEA6300        0x80
 #define I2C_TEA6420	   0x98
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/tvmixer.c linux/drivers/media/video/tvmixer.c
--- v2.4.12/linux/drivers/media/video/tvmixer.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/tvmixer.c	Wed Oct 17 14:19:20 2001
@@ -26,6 +26,9 @@
 MODULE_PARM(debug,"i");
 MODULE_PARM(devnr,"i");
 
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
+
 /* ----------------------------------------------------------------------- */
 
 struct TVMIXER {
@@ -39,27 +42,6 @@
 static int tvmixer_adapters(struct i2c_adapter *adap);
 static int tvmixer_clients(struct i2c_client *client);
 
-static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int tvmixer_open(struct inode *inode, struct file *file);
-static int tvmixer_release(struct inode *inode, struct file *file);
-
-
-static struct i2c_driver driver = {
-	name:            "tv card mixer driver",
-        id:              I2C_DRIVERID_TVMIXER,
-	flags:           I2C_DF_DUMMY,
-        attach_adapter:  tvmixer_adapters,
-        detach_client:   tvmixer_clients,
-};
-
-static struct file_operations tvmixer_fops = {
-	owner:		THIS_MODULE,
-	llseek:         no_llseek,
-	ioctl:          tvmixer_ioctl,
-	open:           tvmixer_open,
-	release:        tvmixer_release,
-};
-
 /* ----------------------------------------------------------------------- */
 
 static int mix_to_v4l(int i)
@@ -232,6 +214,23 @@
 	return 0;
 }
 
+
+static struct i2c_driver driver = {
+	name:            "tv card mixer driver",
+        id:              I2C_DRIVERID_TVMIXER,
+	flags:           I2C_DF_DUMMY,
+        attach_adapter:  tvmixer_adapters,
+        detach_client:   tvmixer_clients,
+};
+
+static struct file_operations tvmixer_fops = {
+	owner:		THIS_MODULE,
+	llseek:         no_llseek,
+	ioctl:          tvmixer_ioctl,
+	open:           tvmixer_open,
+	release:        tvmixer_release,
+};
+
 /* ----------------------------------------------------------------------- */
 
 static int tvmixer_adapters(struct i2c_adapter *adap)
@@ -355,4 +354,3 @@
  * c-basic-offset: 8
  * End:
  */
-MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/media/video/videodev.c linux/drivers/media/video/videodev.c
--- v2.4.12/linux/drivers/media/video/videodev.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/media/video/videodev.c	Thu Oct 11 09:14:32 2001
@@ -63,29 +63,6 @@
 #endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
 
 
-#ifdef CONFIG_VIDEO_BWQCAM
-extern int init_bw_qcams(struct video_init *);
-#endif
-#ifdef CONFIG_VIDEO_CPIA
-extern int cpia_init(struct video_init *);
-#endif
-#ifdef CONFIG_VIDEO_PLANB
-extern int init_planbs(struct video_init *);
-#endif
-
-static struct video_init video_init_list[]={
-#ifdef CONFIG_VIDEO_BWQCAM
-	{"bw-qcam", init_bw_qcams},
-#endif	
-#ifdef CONFIG_VIDEO_CPIA
-	{"cpia", cpia_init},
-#endif	
-#ifdef CONFIG_VIDEO_PLANB
-	{"planb", init_planbs},
-#endif
-	{"end", NULL}
-};
-
 /*
  *	Read will do some smarts later on. Buffer pin etc.
  */
@@ -118,7 +95,7 @@
 
 /*
  *	Poll to see if we're readable, can probably be used for timing on incoming
- *  frames, etc..
+ *	frames, etc..
  */
 
 static unsigned int video_poll(struct file *file, poll_table * wait)
@@ -222,8 +199,7 @@
 /*
  *	We need to do MMAP support
  */
- 
- 
+  
 int video_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	int ret = -EINVAL;
@@ -548,8 +524,6 @@
  
 static int __init videodev_init(void)
 {
-	struct video_init *vfli = video_init_list;
-	
 	printk(KERN_INFO "Linux video capture interface: v1.00\n");
 	if(devfs_register_chrdev(VIDEO_MAJOR,"video_capture", &video_fops))
 	{
@@ -557,19 +531,10 @@
 		return -EIO;
 	}
 
-	/*
-	 *	Init kernel installed video drivers
-	 */
-	 	
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 	videodev_proc_create ();
 #endif
 	
-	while(vfli->init!=NULL)
-	{
-		vfli->init(vfli);
-		vfli++;
-	}
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.12/linux/drivers/message/fusion/isense.c linux/drivers/message/fusion/isense.c
--- v2.4.12/linux/drivers/message/fusion/isense.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/message/fusion/isense.c	Thu Oct 11 09:14:32 2001
@@ -87,6 +87,7 @@
 EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
+MODULE_LICENSE("GPL");
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 int __init isense_init(void)
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/Config.in linux/drivers/message/i2o/Config.in
--- v2.4.12/linux/drivers/message/i2o/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/Config.in	Wed Apr 12 09:38:53 2000
@@ -0,0 +1,16 @@
+mainmenu_option next_comment
+comment 'I2O device support'
+
+tristate 'I2O support' CONFIG_I2O
+
+if [ "$CONFIG_PCI" = "y" ]; then
+   dep_tristate '  I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O
+fi
+dep_tristate '  I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O
+if [ "$CONFIG_NET" = "y" ]; then
+   dep_tristate '  I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O
+fi
+dep_tristate '  I2O SCSI OSM' CONFIG_I2O_SCSI $CONFIG_I2O $CONFIG_SCSI
+dep_tristate '  I2O /proc support' CONFIG_I2O_PROC $CONFIG_I2O
+
+endmenu
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/Makefile linux/drivers/message/i2o/Makefile
--- v2.4.12/linux/drivers/message/i2o/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/Makefile	Fri Dec 29 14:07:21 2000
@@ -0,0 +1,20 @@
+#
+# Makefile for the kernel I2O OSM.
+#
+# Note : at this point, these files are compiled on all systems.
+# In the future, some of these should be built conditionally.
+#
+
+O_TARGET := i2o.o
+
+export-objs	:= i2o_pci.o i2o_core.o i2o_config.o i2o_block.o i2o_lan.o i2o_scsi.o i2o_proc.o
+
+obj-$(CONFIG_I2O_PCI)	+= i2o_pci.o
+obj-$(CONFIG_I2O)	+= i2o_core.o i2o_config.o
+obj-$(CONFIG_I2O_BLOCK)	+= i2o_block.o
+obj-$(CONFIG_I2O_LAN)	+= i2o_lan.o
+obj-$(CONFIG_I2O_SCSI)	+= i2o_scsi.o
+obj-$(CONFIG_I2O_PROC)	+= i2o_proc.o
+
+include $(TOPDIR)/Rules.make
+
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/README linux/drivers/message/i2o/README
--- v2.4.12/linux/drivers/message/i2o/README	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/README	Mon Jun 19 13:30:55 2000
@@ -0,0 +1,98 @@
+
+	Linux I2O Support	(c) Copyright 1999 Red Hat Software
+					and others.
+
+	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.
+
+AUTHORS (so far)
+
+Alan Cox, Building Number Three Ltd.
+	Core code, SCSI and Block OSMs
+
+Steve Ralston, LSI Logic Corp.
+	Debugging SCSI and Block OSM
+
+Deepak Saxena, Intel Corp.
+	Various core/block extensions
+	/proc interface, bug fixes
+	Ioctl interfaces for control
+	Debugging LAN OSM
+
+Philip Rumpf
+	Fixed assorted dumb SMP locking bugs
+
+Juha Sievanen, University of Helsinki Finland
+	LAN OSM code
+	/proc interface to LAN class
+	Bug fixes
+	Core code extensions
+
+Auvo Häkkinen, University of Helsinki Finland
+	LAN OSM code
+	/Proc interface to LAN class
+	Bug fixes
+	Core code extensions
+
+Taneli Vähäkangas, University of Helsinki Finland
+	Fixes to i2o_config
+
+CREDITS
+
+	This work was made possible by 
+
+Red Hat Software
+	Funding for the Building #3 part of the project
+
+Symbios Logic (Now LSI)
+	Host adapters, hints, known to work platforms when I hit
+	compatibility problems
+
+BoxHill Corporation
+	Loan of initial FibreChannel disk array used for development work.
+
+European Comission
+	Funding the work done by the University of Helsinki
+
+SysKonnect
+        Loan of FDDI and Gigabit Ethernet cards
+
+ASUSTeK
+        Loan of I2O motherboard 
+
+STATUS:
+
+o	The core setup works within limits.
+o	The scsi layer seems to almost work. 
+           I'm still chasing down the hang bug.
+o	The block OSM is mostly functional
+o	LAN OSM works with FDDI and Ethernet cards.
+
+TO DO:
+
+General:
+o	Provide hidden address space if asked
+o	Long term message flow control
+o	PCI IOP's without interrupts are not supported yet
+o	Push FAIL handling into the core
+o	DDM control interfaces for module load etc
+o       Add I2O 2.0 support (Deffered to 2.5 kernel)
+
+Block:
+o	Multiple major numbers
+o	Read ahead and cache handling stuff. Talk to Ingo and people
+o	Power management
+o	Finish Media changers
+
+SCSI:
+o	Find the right way to associate drives/luns/busses
+
+Lan:	
+o	Performance tuning
+o	Test Fibre Channel code
+
+Tape:
+o	Anyone seen anything implementing this ?
+           (D.S: Will attempt to do so if spare cycles permit)
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/README.ioctl linux/drivers/message/i2o/README.ioctl
--- v2.4.12/linux/drivers/message/i2o/README.ioctl	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/README.ioctl	Mon Jun 19 13:30:55 2000
@@ -0,0 +1,394 @@
+
+Linux I2O User Space Interface
+rev 0.3 - 04/20/99
+
+=============================================================================
+Originally written by Deepak Saxena(deepak@plexity.net)
+Currently maintained by Deepak Saxena(deepak@plexity.net)
+=============================================================================
+
+I. Introduction
+
+The Linux I2O subsystem provides a set of ioctl() commands that can be
+utilized by user space applications to communicate with IOPs and devices
+on individual IOPs. This document defines the specific ioctl() commands
+that are available to the user and provides examples of their uses.
+
+This document assumes the reader is familiar with or has access to the 
+I2O specification as no I2O message parameters are outlined.  For information 
+on the specification, see http://www.i2osig.org
+
+This document and the I2O user space interface are currently maintained
+by Deepak Saxena.  Please send all comments, errata, and bug fixes to
+deepak@csociety.purdue.edu
+
+II. IOP Access
+
+Access to the I2O subsystem is provided through the device file named 
+/dev/i2o/ctl.  This file is a character file with major number 10 and minor
+number 166.  It can be created through the following command:
+
+   mknod /dev/i2o/ctl c 10 166
+
+III. Determining the IOP Count
+
+   SYNOPSIS 
+
+   ioctl(fd, I2OGETIOPS,  int *count);
+
+   u8 count[MAX_I2O_CONTROLLERS];
+
+   DESCRIPTION
+
+   This function returns the system's active IOP table.  count should
+   point to a buffer containing MAX_I2O_CONTROLLERS entries.  Upon 
+   returning, each entry will contain a non-zero value if the given
+   IOP unit is active, and NULL if it is inactive or non-existent.
+
+   RETURN VALUE.
+
+   Returns 0 if no errors occur, and -1 otherwise.  If an error occurs,
+   errno is set appropriately:
+
+     EFAULT   Invalid user space pointer was passed
+
+IV. Getting Hardware Resource Table
+
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OHRTGET, struct i2o_cmd_hrt *hrt);
+
+      struct i2o_cmd_hrtlct
+      {
+         u32   iop;      /* IOP unit number */
+         void  *resbuf;  /* Buffer for result */
+         u32   *reslen;  /* Buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function returns the Hardware Resource Table of the IOP specified 
+   by hrt->iop in the buffer pointed to by hrt->resbuf. The actual size of 
+   the data is written into *(hrt->reslen).
+
+   RETURNS
+
+   This function returns 0 if no errors occur. If an error occurs, -1 
+   is returned and errno is set appropriately:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(hrt->reslen)
+  
+V. Getting Logical Configuration Table
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OLCTGET, struct i2o_cmd_lct *lct);
+
+      struct i2o_cmd_hrtlct
+      {
+         u32   iop;      /* IOP unit number */
+         void  *resbuf;  /* Buffer for result */
+         u32   *reslen;  /* Buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function returns the Logical Configuration Table of the IOP specified
+   by lct->iop in the buffer pointed to by lct->resbuf. The actual size of 
+   the data is written into *(lct->reslen).
+
+   RETURNS
+
+   This function returns 0 if no errors occur. If an error occurs, -1 
+   is returned and errno is set appropriately:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(lct->reslen)
+
+VI. Settting Parameters
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OPARMSET, struct i2o_parm_setget *ops);
+
+      struct i2o_cmd_psetget
+      {
+         u32   iop;      /* IOP unit number */
+         u32   tid;      /* Target device TID */
+         void  *opbuf;   /* Operation List buffer */
+         u32   oplen;    /* Operation List buffer length in bytes */
+         void  *resbuf;  /* Result List buffer */
+         u32   *reslen;  /* Result List buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function posts a UtilParamsSet message to the device identified
+   by ops->iop and ops->tid.  The operation list for the message is 
+   sent through the ops->opbuf buffer, and the result list is written
+   into the buffer pointed to by ops->resbuf.  The number of bytes 
+   written is placed into *(ops->reslen). 
+
+   RETURNS
+
+   The return value is the size in bytes of the data written into
+   ops->resbuf if no errors occur.  If an error occurs, -1 is returned 
+   and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+   A return value of 0 does not mean that the value was actually
+   changed properly on the IOP.  The user should check the result
+   list to determine the specific status of the transaction.
+
+VII. Getting Parameters
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OPARMGET, struct i2o_parm_setget *ops);
+
+      struct i2o_parm_setget
+      {
+         u32   iop;      /* IOP unit number */
+         u32   tid;      /* Target device TID */
+         void  *opbuf;   /* Operation List buffer */
+         u32   oplen;    /* Operation List buffer length in bytes */
+         void  *resbuf;  /* Result List buffer */
+         u32   *reslen;  /* Result List buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function posts a UtilParamsGet message to the device identified
+   by ops->iop and ops->tid.  The operation list for the message is 
+   sent through the ops->opbuf buffer, and the result list is written
+   into the buffer pointed to by ops->resbuf.  The actual size of data
+   written is placed into *(ops->reslen).
+
+   RETURNS
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+   A return value of 0 does not mean that the value was actually
+   properly retreived.  The user should check the result list 
+   to determine the specific status of the transaction.
+
+VIII. Downloading Software
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OSWDL, struct i2o_sw_xfer *sw);
+
+      struct i2o_sw_xfer
+      {
+         u32   iop;       /* IOP unit number */
+         u8    flags;     /* DownloadFlags field */
+         u8    sw_type;   /* Software type */
+         u32   sw_id;     /* Software ID */
+         void  *buf;      /* Pointer to software buffer */
+         u32   *swlen;    /* Length of software buffer */        
+         u32   *maxfrag;  /* Number of fragments */
+         u32   *curfrag;  /* Current fragment number */
+      };
+
+   DESCRIPTION
+
+   This function downloads a software fragment pointed by sw->buf
+   to the iop identified by sw->iop. The DownloadFlags, SwID, SwType
+   and SwSize fields of the ExecSwDownload message are filled in with
+   the values of sw->flags, sw->sw_id, sw->sw_type and *(sw->swlen).
+
+   The fragments _must_ be sent in order and be 8K in size. The last
+   fragment _may_ be shorter, however. The kernel will compute its
+   size based on information in the sw->swlen field.
+
+   Please note that SW transfers can take a long time.
+
+   RETURNS
+
+   This function returns 0 no errors occur. If an error occurs, -1 
+   is returned and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+IX. Uploading Software
+   
+   SYNOPSIS 
+
+   ioctl(fd, I2OSWUL, struct i2o_sw_xfer *sw);
+
+      struct i2o_sw_xfer
+      {
+         u32   iop;      /* IOP unit number */
+         u8    flags; 	 /* UploadFlags */
+         u8    sw_type;  /* Software type */
+         u32   sw_id;    /* Software ID */
+         void  *buf;     /* Pointer to software buffer */
+         u32   *swlen;   /* Length of software buffer */        
+         u32   *maxfrag; /* Number of fragments */
+         u32   *curfrag; /* Current fragment number */
+      };
+
+   DESCRIPTION
+
+   This function uploads a software fragment from the IOP identified
+   by sw->iop, sw->sw_type, sw->sw_id and optionally sw->swlen fields.
+   The UploadFlags, SwID, SwType and SwSize fields of the ExecSwUpload
+   message are filled in with the values of sw->flags, sw->sw_id,
+   sw->sw_type and *(sw->swlen).
+
+   The fragments _must_ be requested in order and be 8K in size. The
+   user is responsible for allocating memory pointed by sw->buf. The
+   last fragment _may_ be shorter.
+
+   Please note that SW transfers can take a long time.
+
+   RETURNS
+
+   This function returns 0 if no errors occur.  If an error occurs, -1
+   is returned and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+         
+X. Removing Software
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OSWDEL, struct i2o_sw_xfer *sw);
+
+      struct i2o_sw_xfer
+      {
+         u32   iop;      /* IOP unit number */
+         u8    flags; 	 /* RemoveFlags */
+         u8    sw_type;  /* Software type */
+         u32   sw_id;    /* Software ID */
+         void  *buf;     /* Unused */
+         u32   *swlen;   /* Length of the software data */        
+         u32   *maxfrag; /* Unused */
+         u32   *curfrag; /* Unused */
+      };
+
+   DESCRIPTION
+
+   This function removes software from the IOP identified by sw->iop.
+   The RemoveFlags, SwID, SwType and SwSize fields of the ExecSwRemove message 
+   are filled in with the values of sw->flags, sw->sw_id, sw->sw_type and 
+   *(sw->swlen). Give zero in *(sw->len) if the value is unknown. IOP uses 
+   *(sw->swlen) value to verify correct identication of the module to remove. 
+   The actual size of the module is written into *(sw->swlen).
+
+   RETURNS
+
+   This function returns 0 if no errors occur.  If an error occurs, -1
+   is returned and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+X. Validating Configuration
+
+   SYNOPSIS
+
+   ioctl(fd, I2OVALIDATE, int *iop);
+	u32 iop;
+
+   DESCRIPTION
+
+   This function posts an ExecConfigValidate message to the controller
+   identified by iop. This message indicates that the the current
+   configuration is accepted. The iop changes the status of suspect drivers 
+   to valid and may delete old drivers from its store.
+
+   RETURNS
+
+   This function returns 0 if no erro occur.  If an error occurs, -1 is
+   returned and errno is set appropriatly:
+
+      ETIMEDOUT   Timeout waiting for reply message
+      ENXIO       Invalid IOP number
+
+XI. Configuration Dialog
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OHTML, struct i2o_html *htquery);
+      struct i2o_html
+      {
+         u32   iop;      /* IOP unit number */
+         u32   tid;      /* Target device ID */
+         u32   page;     /* HTML page */
+         void  *resbuf;  /* Buffer for reply HTML page */
+         u32   *reslen;  /* Length in bytes of reply buffer */
+         void  *qbuf;    /* Pointer to HTTP query string */
+         u32   qlen;     /* Length in bytes of query string buffer */        
+      };
+
+   DESCRIPTION
+
+   This function posts an UtilConfigDialog message to the device identified
+   by htquery->iop and htquery->tid.  The requested HTML page number is 
+   provided by the htquery->page field, and the resultant data is stored 
+   in the buffer pointed to by htquery->resbuf.  If there is an HTTP query 
+   string that is to be sent to the device, it should be sent in the buffer
+   pointed to by htquery->qbuf.  If there is no query string, this field
+   should be set to NULL. The actual size of the reply received is written
+   into *(htquery->reslen).
+  
+   RETURNS
+
+   This function returns 0 if no error occur. If an error occurs, -1
+   is returned and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+XII. Events
+
+    In the process of determining this.  Current idea is to have use
+    the select() interface to allow user apps to periodically poll
+    the /dev/i2o/ctl device for events.  When select() notifies the user
+    that an event is available, the user would call read() to retrieve
+    a list of all the events that are pending for the specific device.
+
+=============================================================================
+Revision History
+=============================================================================
+
+Rev 0.1 - 04/01/99
+- Initial revision
+
+Rev 0.2 - 04/06/99
+- Changed return values to match UNIX ioctl() standard.  Only return values
+  are 0 and -1.  All errors are reported through errno.
+- Added summary of proposed possible event interfaces
+
+Rev 0.3 - 04/20/99
+- Changed all ioctls() to use pointers to user data instead of actual data
+- Updated error values to match the code
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/i2o_block.c linux/drivers/message/i2o/i2o_block.c
--- v2.4.12/linux/drivers/message/i2o/i2o_block.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/i2o_block.c	Mon Oct 15 13:27:51 2001
@@ -0,0 +1,2051 @@
+/*
+ * I2O Random Block Storage Class OSM
+ *
+ * (C) Copyright 1999 Red Hat Software
+ *	
+ * Written by Alan Cox, Building Number Three Ltd
+ *
+ * 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 is a beta test release. Most of the good code was taken
+ * from the nbd driver by Pavel Machek, who in turn took some of it
+ * from loop.c. Isn't free software great for reusability 8)
+ *
+ * Fixes/additions:
+ *	Steve Ralston:	
+ *		Multiple device handling error fixes,
+ *		Added a queue depth.
+ *	Alan Cox:	
+ *		FC920 has an rmw bug. Dont or in the end marker.
+ *		Removed queue walk, fixed for 64bitness.
+ *	Deepak Saxena:
+ *		Independent queues per IOP
+ *		Support for dynamic device creation/deletion
+ *		Code cleanup	
+ *    		Support for larger I/Os through merge* functions 
+ *       	(taken from DAC960 driver)
+ *	Boji T Kannanthanam:
+ *		Set the I2O Block devices to be detected in increasing 
+ *		order of TIDs during boot.
+ *		Search and set the I2O block device that we boot off from  as
+ *		the first device to be claimed (as /dev/i2o/hda)
+ *		Properly attach/detach I2O gendisk structure from the system
+ *		gendisk list. The I2O block devices now appear in 
+ * 		/proc/partitions.
+ *
+ *	To do:
+ *		Serial number scanning to find duplicates for FC multipathing
+ */
+
+#include <linux/major.h>
+
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/ioctl.h>
+#include <linux/i2o.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/hdreg.h>
+
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <linux/completion.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <linux/smp_lock.h>
+#include <linux/wait.h>
+
+#define MAJOR_NR I2O_MAJOR
+
+#include <linux/blk.h>
+
+#define MAX_I2OB	16
+
+#define MAX_I2OB_DEPTH	128
+#define MAX_I2OB_RETRIES 4
+
+//#define DRIVERDEBUG
+#ifdef DRIVERDEBUG
+#define DEBUG( s )
+#else
+#define DEBUG( s ) printk( s ) 
+#endif
+
+/*
+ * Events that this OSM is interested in
+ */
+#define I2OB_EVENT_MASK		(I2O_EVT_IND_BSA_VOLUME_LOAD |	\
+				 I2O_EVT_IND_BSA_VOLUME_UNLOAD | \
+				 I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ | \
+				 I2O_EVT_IND_BSA_CAPACITY_CHANGE | \
+				 I2O_EVT_IND_BSA_SCSI_SMART )
+
+
+/*
+ * I2O Block Error Codes - should be in a header file really...
+ */
+#define I2O_BSA_DSC_SUCCESS             0x0000
+#define I2O_BSA_DSC_MEDIA_ERROR         0x0001
+#define I2O_BSA_DSC_ACCESS_ERROR        0x0002
+#define I2O_BSA_DSC_DEVICE_FAILURE      0x0003
+#define I2O_BSA_DSC_DEVICE_NOT_READY    0x0004
+#define I2O_BSA_DSC_MEDIA_NOT_PRESENT   0x0005
+#define I2O_BSA_DSC_MEDIA_LOCKED        0x0006
+#define I2O_BSA_DSC_MEDIA_FAILURE       0x0007
+#define I2O_BSA_DSC_PROTOCOL_FAILURE    0x0008
+#define I2O_BSA_DSC_BUS_FAILURE         0x0009
+#define I2O_BSA_DSC_ACCESS_VIOLATION    0x000A
+#define I2O_BSA_DSC_WRITE_PROTECTED     0x000B
+#define I2O_BSA_DSC_DEVICE_RESET        0x000C
+#define I2O_BSA_DSC_VOLUME_CHANGED      0x000D
+#define I2O_BSA_DSC_TIMEOUT             0x000E
+
+/*
+ *	Some of these can be made smaller later
+ */
+
+static int i2ob_blksizes[MAX_I2OB<<4];
+static int i2ob_hardsizes[MAX_I2OB<<4];
+static int i2ob_sizes[MAX_I2OB<<4];
+static int i2ob_media_change_flag[MAX_I2OB];
+static u32 i2ob_max_sectors[MAX_I2OB<<4];
+
+static int i2ob_context;
+
+/*
+ * I2O Block device descriptor 
+ */
+struct i2ob_device
+{
+	struct i2o_controller *controller;
+	struct i2o_device *i2odev;
+	int unit;
+	int tid;
+	int flags;
+	int refcnt;
+	struct request *head, *tail;
+	request_queue_t *req_queue;
+	int max_segments;
+	int done_flag;
+	int constipated;
+	int depth;
+};
+
+/*
+ *	FIXME:
+ *	We should cache align these to avoid ping-ponging lines on SMP
+ *	boxes under heavy I/O load...
+ */
+struct i2ob_request
+{
+	struct i2ob_request *next;
+	struct request *req;
+	int num;
+};
+
+/*
+ * Per IOP requst queue information
+ *
+ * We have a separate requeust_queue_t per IOP so that a heavilly
+ * loaded I2O block device on an IOP does not starve block devices
+ * across all I2O controllers.
+ * 
+ */
+struct i2ob_iop_queue
+{
+	atomic_t queue_depth;
+	struct i2ob_request request_queue[MAX_I2OB_DEPTH];
+	struct i2ob_request *i2ob_qhead;
+	request_queue_t req_queue;
+};
+static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS];
+static struct i2ob_request *i2ob_backlog[MAX_I2O_CONTROLLERS];
+static struct i2ob_request *i2ob_backlog_tail[MAX_I2O_CONTROLLERS];
+
+/*
+ *	Each I2O disk is one of these.
+ */
+
+static struct i2ob_device i2ob_dev[MAX_I2OB<<4];
+static int i2ob_dev_count = 0;
+static struct hd_struct i2ob[MAX_I2OB<<4];
+static struct gendisk i2ob_gendisk;	/* Declared later */
+
+/*
+ * Mutex and spin lock for event handling synchronization
+ * evt_msg contains the last event.
+ */
+static DECLARE_MUTEX_LOCKED(i2ob_evt_sem);
+static DECLARE_COMPLETION(i2ob_thread_dead);
+static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED;
+static u32 evt_msg[MSG_FRAME_SIZE>>2];
+
+static struct timer_list i2ob_timer;
+static int i2ob_timer_started = 0;
+
+static void i2o_block_reply(struct i2o_handler *, struct i2o_controller *,
+	 struct i2o_message *);
+static void i2ob_new_device(struct i2o_controller *, struct i2o_device *);
+static void i2ob_del_device(struct i2o_controller *, struct i2o_device *);
+static void i2ob_reboot_event(void);
+static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int);
+static void i2ob_end_request(struct request *);
+static void i2ob_request(request_queue_t *);
+static int i2ob_backlog_request(struct i2o_controller *, struct i2ob_device *);
+static int i2ob_init_iop(unsigned int);
+static request_queue_t* i2ob_get_queue(kdev_t);
+static int i2ob_query_device(struct i2ob_device *, int, int, void*, int);
+static int do_i2ob_revalidate(kdev_t, int);
+static int i2ob_evt(void *);
+
+static int evt_pid = 0;
+static int evt_running = 0;
+static int scan_unit = 0;
+
+/*
+ * I2O OSM registration structure...keeps getting bigger and bigger :)
+ */
+static struct i2o_handler i2o_block_handler =
+{
+	i2o_block_reply,
+	i2ob_new_device,
+	i2ob_del_device,
+	i2ob_reboot_event,
+	"I2O Block OSM",
+	0,
+	I2O_CLASS_RANDOM_BLOCK_STORAGE
+};
+
+/*
+ *	Get a message
+ */
+
+static u32 i2ob_get(struct i2ob_device *dev)
+{
+	struct i2o_controller *c=dev->controller;
+   	return I2O_POST_READ32(c);
+}
+ 
+/*
+ *	Turn a Linux block request into an I2O block read/write.
+ */
+
+static int i2ob_send(u32 m, struct i2ob_device *dev, struct i2ob_request *ireq, u32 base, int unit)
+{
+	struct i2o_controller *c = dev->controller;
+	int tid = dev->tid;
+	unsigned long msg;
+	unsigned long mptr;
+	u64 offset;
+	struct request *req = ireq->req;
+	struct buffer_head *bh = req->bh;
+	int count = req->nr_sectors<<9;
+	char *last = NULL;
+	unsigned short size = 0;
+
+	// printk(KERN_INFO "i2ob_send called\n");
+	/* Map the message to a virtual address */
+	msg = c->mem_offset + m;
+	
+	/*
+	 * Build the message based on the request.
+	 */
+	__raw_writel(i2ob_context|(unit<<8), msg+8);
+	__raw_writel(ireq->num, msg+12);
+	__raw_writel(req->nr_sectors << 9, msg+20);
+
+	/* 
+	 * Mask out partitions from now on
+	 */
+	unit &= 0xF0;
+		
+	/* This can be optimised later - just want to be sure its right for
+	   starters */
+	offset = ((u64)(req->sector+base)) << 9;
+	__raw_writel( offset & 0xFFFFFFFF, msg+24);
+	__raw_writel(offset>>32, msg+28);
+	mptr=msg+32;
+	
+	if(req->cmd == READ)
+	{
+		__raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4);
+		while(bh!=NULL)
+		{
+			if(bh->b_data == last) {
+				size += bh->b_size;
+				last += bh->b_size;
+				if(bh->b_reqnext)
+					__raw_writel(0x14000000|(size), mptr-8);
+				else
+					__raw_writel(0xD4000000|(size), mptr-8);
+			}
+			else
+			{
+				if(bh->b_reqnext)
+					__raw_writel(0x10000000|(bh->b_size), mptr);
+				else
+					__raw_writel(0xD0000000|(bh->b_size), mptr);
+				__raw_writel(virt_to_bus(bh->b_data), mptr+4);
+				mptr += 8;	
+				size = bh->b_size;
+				last = bh->b_data + size;
+			}
+
+			count -= bh->b_size;
+			bh = bh->b_reqnext;
+		}
+		/*
+		 *	Heuristic for now since the block layer doesnt give
+		 *	us enough info. If its a big write assume sequential
+		 *	readahead on controller. If its small then don't read
+		 *	ahead but do use the controller cache.
+		 */
+		if(size >= 8192)
+			__raw_writel((8<<24)|(1<<16)|8, msg+16);
+		else
+			__raw_writel((8<<24)|(1<<16)|4, msg+16);
+	}
+	else if(req->cmd == WRITE)
+	{
+		__raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4);
+		while(bh!=NULL)
+		{
+			if(bh->b_data == last) {
+				size += bh->b_size;
+				last += bh->b_size;
+				if(bh->b_reqnext)
+					__raw_writel(0x14000000|(size), mptr-8);
+				else
+					__raw_writel(0xD4000000|(size), mptr-8);
+			}
+			else
+			{
+				if(bh->b_reqnext)
+					__raw_writel(0x14000000|(bh->b_size), mptr);
+				else
+					__raw_writel(0xD4000000|(bh->b_size), mptr);
+				__raw_writel(virt_to_bus(bh->b_data), mptr+4);
+				mptr += 8;	
+				size = bh->b_size;
+				last = bh->b_data + size;
+			}
+
+			count -= bh->b_size;
+			bh = bh->b_reqnext;
+		}
+
+		if(c->battery)
+		{
+			
+			if(size>16384)
+				__raw_writel(4, msg+16);
+			else
+				/* 
+				 * Allow replies to come back once data is cached in the controller
+				 * This allows us to handle writes quickly thus giving more of the
+				 * queue to reads.
+				 */
+				__raw_writel(16, msg+16);
+		}
+		else
+		{
+			/* Large write, don't cache */
+			if(size>8192)
+				__raw_writel(4, msg+16);
+			else
+			/* write through */
+				__raw_writel(8, msg+16);
+		}
+	}
+	__raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg);
+	
+	if(count != 0)
+	{
+		printk(KERN_ERR "Request count botched by %d.\n", count);
+	}
+
+	i2o_post_message(c,m);
+	atomic_inc(&i2ob_queues[c->unit]->queue_depth);
+
+	return 0;
+}
+
+/*
+ *	Remove a request from the _locked_ request list. We update both the
+ *	list chain and if this is the last item the tail pointer. Caller
+ *	must hold the lock.
+ */
+ 
+static inline void i2ob_unhook_request(struct i2ob_request *ireq, 
+	unsigned int iop)
+{
+	ireq->next = i2ob_queues[iop]->i2ob_qhead;
+	i2ob_queues[iop]->i2ob_qhead = ireq;
+}
+
+/*
+ *	Request completion handler
+ */
+ 
+static inline void i2ob_end_request(struct request *req)
+{
+	/*
+	 * Loop until all of the buffers that are linked
+	 * to this request have been marked updated and
+	 * unlocked.
+	 */
+
+	while (end_that_request_first( req, !req->errors, "i2o block" ));
+
+	/*
+	 * It is now ok to complete the request.
+	 */
+	end_that_request_last( req );
+}
+
+/*
+ * Request merging functions
+ */
+static inline int i2ob_new_segment(request_queue_t *q, struct request *req,
+				  int __max_segments)
+{
+	int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments;
+
+	if (__max_segments < max_segments)
+		max_segments = __max_segments;
+
+	if (req->nr_segments < max_segments) {
+		req->nr_segments++;
+		return 1;
+	}
+	return 0;
+}
+
+static int i2ob_back_merge(request_queue_t *q, struct request *req, 
+			     struct buffer_head *bh, int __max_segments)
+{
+	if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data)
+		return 1;
+	return i2ob_new_segment(q, req, __max_segments);
+}
+
+static int i2ob_front_merge(request_queue_t *q, struct request *req, 
+			      struct buffer_head *bh, int __max_segments)
+{
+	if (bh->b_data + bh->b_size == req->bh->b_data)
+		return 1;
+	return i2ob_new_segment(q, req, __max_segments);
+}
+
+static int i2ob_merge_requests(request_queue_t *q,
+				struct request *req,
+				struct request *next,
+				int __max_segments)
+{
+	int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments;
+	int total_segments = req->nr_segments + next->nr_segments;
+
+	if (__max_segments < max_segments)
+		max_segments = __max_segments;
+
+	if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
+		total_segments--;
+    
+	if (total_segments > max_segments)
+		return 0;
+
+	req->nr_segments = total_segments;
+	return 1;
+}
+
+static int i2ob_flush(struct i2o_controller *c, struct i2ob_device *d, int unit)
+{
+	unsigned long msg;
+	u32 m = i2ob_get(d);
+	
+	if(m == 0xFFFFFFFF)
+		return -1;
+		
+	msg = c->mem_offset + m;
+
+	/*
+	 *	Ask the controller to write the cache back. This sorts out
+	 *	the supertrak firmware flaw and also does roughly the right
+	 *	thing for other cases too.
+	 */
+	 	
+	__raw_writel(FIVE_WORD_MSG_SIZE|SGL_OFFSET_0, msg);
+	__raw_writel(I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|d->tid, msg+4);
+	__raw_writel(i2ob_context|(unit<<8), msg+8);
+	__raw_writel(0, msg+12);
+	__raw_writel(60<<16, msg+16);
+	
+	i2o_post_message(c,m);
+	return 0;
+}
+			
+/*
+ *	OSM reply handler. This gets all the message replies
+ */
+
+static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
+{
+	unsigned long flags;
+	struct i2ob_request *ireq = NULL;
+	u8 st;
+	u32 *m = (u32 *)msg;
+	u8 unit = (m[2]>>8)&0xF0;	/* low 4 bits are partition */
+	struct i2ob_device *dev = &i2ob_dev[(unit&0xF0)];
+	
+	/*
+	 * FAILed message
+	 */
+	if(m[0] & (1<<13))
+	{
+		/*
+		 * FAILed message from controller
+		 * We increment the error count and abort it
+		 *
+		 * In theory this will never happen.  The I2O block class
+		 * speficiation states that block devices never return
+		 * FAILs but instead use the REQ status field...but
+		 * better be on the safe side since no one really follows
+		 * the spec to the book :)
+		 */
+		ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
+		ireq->req->errors++;
+
+		spin_lock_irqsave(&io_request_lock, flags);
+		i2ob_unhook_request(ireq, c->unit);
+		i2ob_end_request(ireq->req);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	
+		/* Now flush the message by making it a NOP */
+		m[0]&=0x00FFFFFF;
+		m[0]|=(I2O_CMD_UTIL_NOP)<<24;
+		i2o_post_message(c,virt_to_bus(m));
+
+		return;
+	}
+
+	if(msg->function == I2O_CMD_UTIL_EVT_REGISTER)
+	{
+		spin_lock(&i2ob_evt_lock);
+		memcpy(evt_msg, msg, (m[0]>>16)<<2);
+		spin_unlock(&i2ob_evt_lock);
+		up(&i2ob_evt_sem);
+		return;
+	}
+
+	if(msg->function == I2O_CMD_BLOCK_CFLUSH)
+	{
+		spin_lock_irqsave(&io_request_lock, flags);
+		dev->constipated=0;
+		DEBUG(("unconstipated\n"));
+		if(i2ob_backlog_request(c, dev)==0)
+			i2ob_request(dev->req_queue);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+
+	if(!dev->i2odev)
+	{
+		/*
+		 * This is HACK, but Intel Integrated RAID allows user
+		 * to delete a volume that is claimed, locked, and in use 
+		 * by the OS. We have to check for a reply from a
+		 * non-existent device and flag it as an error or the system 
+		 * goes kaput...
+		 */
+		ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
+		ireq->req->errors++;
+		printk(KERN_WARNING "I2O Block: Data transfer to deleted device!\n");
+		spin_lock_irqsave(&io_request_lock, flags);
+		i2ob_unhook_request(ireq, c->unit);
+		i2ob_end_request(ireq->req);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}	
+
+	/*
+	 *	Lets see what is cooking. We stuffed the
+	 *	request in the context.
+	 */
+		 
+	ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
+	st=m[4]>>24;
+
+	if(st!=0)
+	{
+		int err;
+		char *bsa_errors[] = 
+		{ 
+			"Success", 
+			"Media Error", 
+			"Failure communicating to device",
+			"Device Failure",
+			"Device is not ready",
+			"Media not present",
+			"Media is locked by another user",
+			"Media has failed",
+			"Failure communicating to device",
+			"Device bus failure",
+			"Device is locked by another user",
+			"Device is write protected",
+			"Device has reset",
+			"Volume has changed, waiting for acknowledgement"
+		};
+				
+		err = m[4]&0xFFFF;
+		
+		/*
+		 *	Device not ready means two things. One is that the
+		 *	the thing went offline (but not a removal media)
+		 *
+		 *	The second is that you have a SuperTrak 100 and the
+		 *	firmware got constipated. Unlike standard i2o card
+		 *	setups the supertrak returns an error rather than
+		 *	blocking for the timeout in these cases.
+		 */
+		 
+		
+		spin_lock_irqsave(&io_request_lock, flags);
+		if(err==4)
+		{
+			/*
+			 *	Time to uncork stuff
+			 */
+			
+			if(!dev->constipated)
+			{
+				dev->constipated = 1;
+				DEBUG(("constipated\n"));
+				/* Now pull the chain */
+				if(i2ob_flush(c, dev, unit)<0)
+				{
+					DEBUG(("i2ob: Unable to queue flush. Retrying I/O immediately.\n"));
+					dev->constipated=0;
+				}
+				DEBUG(("flushing\n"));
+			}
+			
+			/*
+			 *	Recycle the request
+			 */
+			 
+//			i2ob_unhook_request(ireq, c->unit);
+			
+			/*
+			 *	Place it on the recycle queue
+			 */
+			 
+			ireq->next = NULL;
+			if(i2ob_backlog_tail[c->unit]!=NULL)
+				i2ob_backlog_tail[c->unit]->next = ireq;
+			else
+				i2ob_backlog[c->unit] = ireq;			
+			i2ob_backlog_tail[c->unit] = ireq;
+			
+			atomic_dec(&i2ob_queues[c->unit]->queue_depth);
+
+			/*
+			 *	If the constipator flush failed we want to
+			 *	poke the queue again. 
+			 */
+			 
+			i2ob_request(dev->req_queue);
+			spin_unlock_irqrestore(&io_request_lock, flags);
+			
+			/*
+			 *	and out
+			 */
+			 
+			return;	
+		}
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, 
+			bsa_errors[m[4]&0XFFFF]);
+		if(m[4]&0x00FF0000)
+			printk(" - DDM attempted %d retries", (m[4]>>16)&0x00FF );
+		printk(".\n");
+		ireq->req->errors++;	
+	}
+	else
+		ireq->req->errors = 0;
+
+	/*
+	 *	Dequeue the request. We use irqsave locks as one day we
+	 *	may be running polled controllers from a BH...
+	 */
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	i2ob_unhook_request(ireq, c->unit);
+	i2ob_end_request(ireq->req);
+	atomic_dec(&i2ob_queues[c->unit]->queue_depth);
+
+	/*
+	 *	We may be able to do more I/O
+	 */
+
+	if(i2ob_backlog_request(c, dev)==0)
+		i2ob_request(dev->req_queue);
+
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/* 
+ * Event handler.  Needs to be a separate thread b/c we may have
+ * to do things like scan a partition table, or query parameters
+ * which cannot be done from an interrupt or from a bottom half.
+ */
+static int i2ob_evt(void *dummy)
+{
+	unsigned int evt;
+	unsigned long flags;
+	int unit;
+	int i;
+	//The only event that has data is the SCSI_SMART event.
+	struct i2o_reply {
+		u32 header[4];
+		u32 evt_indicator;
+		u8 ASC;
+		u8 ASCQ;
+		u8 data[16];
+		} *evt_local;
+
+	lock_kernel();
+	daemonize();
+	unlock_kernel();
+
+	strcpy(current->comm, "i2oblock");
+	evt_running = 1;
+
+	while(1)
+	{
+		if(down_interruptible(&i2ob_evt_sem))
+		{
+			evt_running = 0;
+			printk("exiting...");
+			break;
+		}
+
+		/*
+		 * Keep another CPU/interrupt from overwriting the 
+		 * message while we're reading it
+		 *
+		 * We stuffed the unit in the TxContext and grab the event mask
+		 * None of the BSA we care about events have EventData
+		 */
+		spin_lock_irqsave(&i2ob_evt_lock, flags);
+		evt_local = (struct i2o_reply *)evt_msg;
+		spin_unlock_irqrestore(&i2ob_evt_lock, flags);
+
+		unit = evt_local->header[3];
+		evt = evt_local->evt_indicator;
+
+		switch(evt)
+		{
+			/*
+			 * New volume loaded on same TID, so we just re-install.
+			 * The TID/controller don't change as it is the same
+			 * I2O device.  It's just new media that we have to
+			 * rescan.
+			 */
+			case I2O_EVT_IND_BSA_VOLUME_LOAD:
+			{
+				i2ob_install_device(i2ob_dev[unit].i2odev->controller, 
+					i2ob_dev[unit].i2odev, unit);
+				break;
+			}
+
+			/*
+			 * No media, so set all parameters to 0 and set the media
+			 * change flag. The I2O device is still valid, just doesn't
+			 * have media, so we don't want to clear the controller or
+			 * device pointer.
+			 */
+			case I2O_EVT_IND_BSA_VOLUME_UNLOAD:
+			{
+				for(i = unit; i <= unit+15; i++)
+				{
+					i2ob_sizes[i] = 0;
+					i2ob_hardsizes[i] = 0;
+					i2ob_max_sectors[i] = 0;
+					i2ob[i].nr_sects = 0;
+					i2ob_gendisk.part[i].nr_sects = 0;
+				}
+				i2ob_media_change_flag[unit] = 1;
+				break;
+			}
+
+			case I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ:
+				printk(KERN_WARNING "%s: Attempt to eject locked media\n", 
+					i2ob_dev[unit].i2odev->dev_name);
+				break;
+
+			/*
+			 * The capacity has changed and we are going to be
+			 * updating the max_sectors and other information 
+			 * about this disk.  We try a revalidate first. If
+			 * the block device is in use, we don't want to
+			 * do that as there may be I/Os bound for the disk
+			 * at the moment.  In that case we read the size 
+			 * from the device and update the information ourselves
+			 * and the user can later force a partition table
+			 * update through an ioctl.
+			 */
+			case I2O_EVT_IND_BSA_CAPACITY_CHANGE:
+			{
+				u64 size;
+
+				if(do_i2ob_revalidate(MKDEV(MAJOR_NR, unit),0) != -EBUSY)
+					continue;
+
+	  			if(i2ob_query_device(&i2ob_dev[unit], 0x0004, 0, &size, 8) !=0 )
+					i2ob_query_device(&i2ob_dev[unit], 0x0000, 4, &size, 8);
+
+				spin_lock_irqsave(&io_request_lock, flags);	
+				i2ob_sizes[unit] = (int)(size>>10);
+				i2ob_gendisk.part[unit].nr_sects = size>>9;
+				i2ob[unit].nr_sects = (int)(size>>9);
+				spin_unlock_irqrestore(&io_request_lock, flags);	
+				break;
+			}
+
+			/* 
+			 * We got a SCSI SMART event, we just log the relevant
+			 * information and let the user decide what they want
+			 * to do with the information.
+			 */
+			case I2O_EVT_IND_BSA_SCSI_SMART:
+			{
+				char buf[16];
+				printk(KERN_INFO "I2O Block: %s received a SCSI SMART Event\n",i2ob_dev[unit].i2odev->dev_name);
+				evt_local->data[16]='\0';
+				sprintf(buf,"%s",&evt_local->data[0]);
+				printk(KERN_INFO "      Disk Serial#:%s\n",buf);
+				printk(KERN_INFO "      ASC 0x%02x \n",evt_local->ASC);
+				printk(KERN_INFO "      ASCQ 0x%02x \n",evt_local->ASCQ);
+				break;
+			}
+		
+			/*
+			 *	Non event
+			 */
+			 
+			case 0:
+				break;
+				
+			/*
+			 * An event we didn't ask for.  Call the card manufacturer
+			 * and tell them to fix their firmware :)
+			 */
+			default:
+				printk(KERN_INFO "%s: Received event %d we didn't register for\n"
+					KERN_INFO "   Blame the I2O card manufacturer 8)\n", 
+					i2ob_dev[unit].i2odev->dev_name, evt);
+				break;
+		}
+	};
+
+	complete_and_exit(&i2ob_thread_dead,0);
+	return 0;
+}
+
+/*
+ * The timer handler will attempt to restart requests 
+ * that are queued to the driver.  This handler
+ * currently only gets called if the controller
+ * had no more room in its inbound fifo.  
+ */
+
+static void i2ob_timer_handler(unsigned long q)
+{
+	unsigned long flags;
+
+	/*
+	 * We cannot touch the request queue or the timer
+         * flag without holding the io_request_lock.
+	 */
+	spin_lock_irqsave(&io_request_lock,flags);
+
+	/* 
+	 * Clear the timer started flag so that 
+	 * the timer can be queued again.
+	 */
+	i2ob_timer_started = 0;
+
+	/* 
+	 * Restart any requests.
+	 */
+	i2ob_request((request_queue_t*)q);
+
+	/* 
+	 * Free the lock.
+	 */
+	spin_unlock_irqrestore(&io_request_lock,flags);
+}
+
+static int i2ob_backlog_request(struct i2o_controller *c, struct i2ob_device *dev)
+{
+	u32 m;
+	struct i2ob_request *ireq;
+	
+	while((ireq=i2ob_backlog[c->unit])!=NULL)
+	{
+		int unit;
+
+		if(atomic_read(&i2ob_queues[c->unit]->queue_depth) > dev->depth/4)
+			break;
+
+		m = i2ob_get(dev);
+		if(m == 0xFFFFFFFF)
+			break;
+
+		i2ob_backlog[c->unit] = ireq->next;
+		if(i2ob_backlog[c->unit] == NULL)
+			i2ob_backlog_tail[c->unit] = NULL;
+			
+		unit = MINOR(ireq->req->rq_dev);
+		i2ob_send(m, dev, ireq, i2ob[unit].start_sect, unit);
+	}
+	if(i2ob_backlog[c->unit])
+		return 1;
+	return 0;
+}
+
+/*
+ *	The I2O block driver is listed as one of those that pulls the
+ *	front entry off the queue before processing it. This is important
+ *	to remember here. If we drop the io lock then CURRENT will change
+ *	on us. We must unlink CURRENT in this routine before we return, if
+ *	we use it.
+ */
+
+static void i2ob_request(request_queue_t *q)
+{
+	struct request *req;
+	struct i2ob_request *ireq;
+	int unit;
+	struct i2ob_device *dev;
+	u32 m;
+	
+	
+	while (!list_empty(&q->queue_head)) {
+		/*
+		 *	On an IRQ completion if there is an inactive
+		 *	request on the queue head it means it isnt yet
+		 *	ready to dispatch.
+		 */
+		req = blkdev_entry_next_request(&q->queue_head);
+
+		if(req->rq_status == RQ_INACTIVE)
+			return;
+			
+		unit = MINOR(req->rq_dev);
+		dev = &i2ob_dev[(unit&0xF0)];
+
+		/* 
+		 *	Queue depths probably belong with some kind of 
+		 *	generic IOP commit control. Certainly its not right 
+		 *	its global!  
+		 */
+		if(atomic_read(&i2ob_queues[dev->unit]->queue_depth) >= dev->depth)
+			break;
+		
+		/*
+		 *	Is the channel constipated ?
+		 */
+
+		if(i2ob_backlog[dev->unit]!=NULL)
+			break;
+			
+		/* Get a message */
+		m = i2ob_get(dev);
+
+		if(m==0xFFFFFFFF)
+		{
+			/* 
+			 * See if the timer has already been queued.
+			 */
+			if (!i2ob_timer_started)
+			{
+				DEBUG((KERN_ERR "i2ob: starting timer\n"));
+
+				/*
+				 * Set the timer_started flag to insure
+				 * that the timer is only queued once.
+				 * Queing it more than once will corrupt
+				 * the timer queue.
+				 */
+				i2ob_timer_started = 1;
+
+				/* 
+				 * Set up the timer to expire in
+				 * 500ms.
+				 */
+				i2ob_timer.expires = jiffies + (HZ >> 1);
+				i2ob_timer.data = (unsigned int)q;
+
+				/*
+				 * Start it.
+				 */
+				 
+				add_timer(&i2ob_timer);
+				return;
+			}
+		}
+
+		/*
+		 * Everything ok, so pull from kernel queue onto our queue
+		 */
+		req->errors = 0;
+		blkdev_dequeue_request(req);	
+		req->waiting = NULL;
+		
+		ireq = i2ob_queues[dev->unit]->i2ob_qhead;
+		i2ob_queues[dev->unit]->i2ob_qhead = ireq->next;
+		ireq->req = req;
+
+		i2ob_send(m, dev, ireq, i2ob[unit].start_sect, (unit&0xF0));
+	}
+}
+
+
+/*
+ *	SCSI-CAM for ioctl geometry mapping
+ *	Duplicated with SCSI - this should be moved into somewhere common
+ *	perhaps genhd ?
+ *
+ * LBA -> CHS mapping table taken from:
+ *
+ * "Incorporating the I2O Architecture into BIOS for Intel Architecture 
+ *  Platforms" 
+ *
+ * This is an I2O document that is only available to I2O members,
+ * not developers.
+ *
+ * From my understanding, this is how all the I2O cards do this
+ *
+ * Disk Size      | Sectors | Heads | Cylinders
+ * ---------------+---------+-------+-------------------
+ * 1 < X <= 528M  | 63      | 16    | X/(63 * 16 * 512)
+ * 528M < X <= 1G | 63      | 32    | X/(63 * 32 * 512)
+ * 1 < X <528M    | 63      | 16    | X/(63 * 16 * 512)
+ * 1 < X <528M    | 63      | 16    | X/(63 * 16 * 512)
+ *
+ */
+#define	BLOCK_SIZE_528M		1081344
+#define	BLOCK_SIZE_1G		2097152
+#define	BLOCK_SIZE_21G		4403200
+#define	BLOCK_SIZE_42G		8806400
+#define	BLOCK_SIZE_84G		17612800
+
+static void i2o_block_biosparam(
+	unsigned long capacity,
+	unsigned short *cyls,
+	unsigned char *hds,
+	unsigned char *secs) 
+{ 
+	unsigned long heads, sectors, cylinders; 
+
+	sectors = 63L;      			/* Maximize sectors per track */ 
+	if(capacity <= BLOCK_SIZE_528M)
+		heads = 16;
+	else if(capacity <= BLOCK_SIZE_1G)
+		heads = 32;
+	else if(capacity <= BLOCK_SIZE_21G)
+		heads = 64;
+	else if(capacity <= BLOCK_SIZE_42G)
+		heads = 128;
+	else
+		heads = 255;
+
+	cylinders = capacity / (heads * sectors);
+
+	*cyls = (unsigned short) cylinders;	/* Stuff return values */ 
+	*secs = (unsigned char) sectors; 
+	*hds  = (unsigned char) heads; 
+}
+
+
+/*
+ *	Rescan the partition tables
+ */
+ 
+static int do_i2ob_revalidate(kdev_t dev, int maxu)
+{
+	int minor=MINOR(dev);
+	int i;
+	
+	minor&=0xF0;
+
+	i2ob_dev[minor].refcnt++;
+	if(i2ob_dev[minor].refcnt>maxu+1)
+	{
+		i2ob_dev[minor].refcnt--;
+		return -EBUSY;
+	}
+	
+	for( i = 15; i>=0 ; i--)
+	{
+		int m = minor+i;
+		invalidate_device(MKDEV(MAJOR_NR, m), 1);
+		i2ob_gendisk.part[m].start_sect = 0;
+		i2ob_gendisk.part[m].nr_sects = 0;
+	}
+
+	/*
+	 *	Do a physical check and then reconfigure
+	 */
+	 
+	i2ob_install_device(i2ob_dev[minor].controller, i2ob_dev[minor].i2odev,
+		minor);
+	i2ob_dev[minor].refcnt--;
+	return 0;
+}
+
+/*
+ *	Issue device specific ioctl calls.
+ */
+
+static int i2ob_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	struct i2ob_device *dev;
+	int minor;
+
+	/* Anyone capable of this syscall can do *real bad* things */
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!inode)
+		return -EINVAL;
+	minor = MINOR(inode->i_rdev);
+	if (minor >= (MAX_I2OB<<4))
+		return -ENODEV;
+
+	dev = &i2ob_dev[minor];
+	switch (cmd) {
+		case BLKGETSIZE:
+			return put_user(i2ob[minor].nr_sects, (unsigned long *) arg);
+		case BLKGETSIZE64:
+			return put_user((u64)i2ob[minor].nr_sects << 9, (u64 *)arg);
+
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry g;
+			int u=minor&0xF0;
+			i2o_block_biosparam(i2ob_sizes[u]<<1, 
+				&g.cylinders, &g.heads, &g.sectors);
+			g.start = i2ob[minor].start_sect;
+			return copy_to_user((void *)arg,&g, sizeof(g))?-EFAULT:0;
+		}
+	
+		case BLKRRPART:
+			if(!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			return do_i2ob_revalidate(inode->i_rdev,1);
+			
+		case BLKFLSBUF:
+		case BLKROSET:
+		case BLKROGET:
+		case BLKRASET:
+		case BLKRAGET:
+		case BLKPG:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+			
+		default:
+			return -EINVAL;
+	}
+}
+
+/*
+ *	Close the block device down
+ */
+ 
+static int i2ob_release(struct inode *inode, struct file *file)
+{
+	struct i2ob_device *dev;
+	int minor;
+
+	minor = MINOR(inode->i_rdev);
+	if (minor >= (MAX_I2OB<<4))
+		return -ENODEV;
+	dev = &i2ob_dev[(minor&0xF0)];
+
+	/*
+	 * This is to deail with the case of an application
+	 * opening a device and then the device dissapears while
+	 * it's in use, and then the application tries to release
+	 * it.  ex: Unmounting a deleted RAID volume at reboot. 
+	 * If we send messages, it will just cause FAILs since
+	 * the TID no longer exists.
+	 */
+	if(!dev->i2odev)
+		return 0;
+
+	if (dev->refcnt <= 0)
+		printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt);
+	dev->refcnt--;
+	if(dev->refcnt==0)
+	{
+		/*
+		 *	Flush the onboard cache on unmount
+		 */
+		u32 msg[5];
+		int *query_done = &dev->done_flag;
+		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid;
+		msg[2] = i2ob_context|0x40000000;
+		msg[3] = (u32)query_done;
+		msg[4] = 60<<16;
+		DEBUG("Flushing...");
+		i2o_post_wait(dev->controller, msg, 20, 60);
+
+		/*
+		 *	Unlock the media
+		 */
+		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid;
+		msg[2] = i2ob_context|0x40000000;
+		msg[3] = (u32)query_done;
+		msg[4] = -1;
+		DEBUG("Unlocking...");
+		i2o_post_wait(dev->controller, msg, 20, 2);
+		DEBUG("Unlocked.\n");
+	
+		/*
+ 		 * Now unclaim the device.
+		 */
+
+		if (i2o_release_device(dev->i2odev, &i2o_block_handler))
+			printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n");
+		
+		DEBUG("Unclaim\n");
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ *	Open the block device.
+ */
+ 
+static int i2ob_open(struct inode *inode, struct file *file)
+{
+	int minor;
+	struct i2ob_device *dev;
+	
+	if (!inode)
+		return -EINVAL;
+	minor = MINOR(inode->i_rdev);
+	if (minor >= MAX_I2OB<<4)
+		return -ENODEV;
+	dev=&i2ob_dev[(minor&0xF0)];
+
+	if(!dev->i2odev)	
+		return -ENODEV;
+	
+	if(dev->refcnt++==0)
+	{ 
+		u32 msg[6];
+		
+		DEBUG("Claim ");
+		if(i2o_claim_device(dev->i2odev, &i2o_block_handler))
+		{
+			dev->refcnt--;
+			printk(KERN_INFO "I2O Block: Could not open device\n");
+			return -EBUSY;
+		}
+		DEBUG("Claimed ");
+		
+		/*
+		 *	Mount the media if needed. Note that we don't use
+		 *	the lock bit. Since we have to issue a lock if it
+		 *	refuses a mount (quite possible) then we might as
+		 *	well just send two messages out.
+		 */
+		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;		
+		msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid;
+		msg[4] = -1;
+		msg[5] = 0;
+		DEBUG("Mount ");
+		i2o_post_wait(dev->controller, msg, 24, 2);
+
+		/*
+		 *	Lock the media
+		 */
+		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid;
+		msg[4] = -1;
+		DEBUG("Lock ");
+		i2o_post_wait(dev->controller, msg, 20, 2);
+		DEBUG("Ready.\n");
+	}		
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*
+ *	Issue a device query
+ */
+ 
+static int i2ob_query_device(struct i2ob_device *dev, int table, 
+	int field, void *buf, int buflen)
+{
+	return i2o_query_scalar(dev->controller, dev->tid,
+		table, field, buf, buflen);
+}
+
+
+/*
+ *	Install the I2O block device we found.
+ */
+ 
+static int i2ob_install_device(struct i2o_controller *c, struct i2o_device *d, int unit)
+{
+	u64 size;
+	u32 blocksize;
+	u32 limit;
+	u8 type;
+	u32 flags, status;
+	struct i2ob_device *dev=&i2ob_dev[unit];
+	int i;
+
+	/*
+	 * For logging purposes...
+	 */
+	printk(KERN_INFO "i2ob: Installing tid %d device at unit %d\n", 
+			d->lct_data.tid, unit);	
+
+	/*
+	 *	Ask for the current media data. If that isn't supported
+	 *	then we ask for the device capacity data
+	 */
+	if(i2ob_query_device(dev, 0x0004, 1, &blocksize, 4) != 0
+	  || i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 )
+	{
+		i2ob_query_device(dev, 0x0000, 3, &blocksize, 4);
+		i2ob_query_device(dev, 0x0000, 4, &size, 8);
+	}
+	
+	i2ob_query_device(dev, 0x0000, 5, &flags, 4);
+	i2ob_query_device(dev, 0x0000, 6, &status, 4);
+	i2ob_sizes[unit] = (int)(size>>10);
+	for(i=unit; i <= unit+15 ; i++)
+		i2ob_hardsizes[i] = blocksize;
+	i2ob_gendisk.part[unit].nr_sects = size>>9;
+	i2ob[unit].nr_sects = (int)(size>>9);
+
+	/* Set limit based on inbound frame size */
+	limit = (d->controller->status_block->inbound_frame_size - 8)/2;
+	limit = limit<<9;
+
+	/*
+	 * Max number of Scatter-Gather Elements
+	 */	
+
+	for(i=unit;i<=unit+15;i++)
+	{
+		if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.queue_buggy)
+		{
+			i2ob_max_sectors[i] = 32;
+			i2ob_dev[i].max_segments = 8;
+			i2ob_dev[i].depth = 4;
+		}
+		else if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.short_req)
+		{
+			i2ob_max_sectors[i] = 8;
+			i2ob_dev[i].max_segments = 8;
+		}
+		else
+		{
+			/* MAX_SECTORS was used but 255 is a dumb number for
+			   striped RAID */
+			i2ob_max_sectors[i]=256;
+			i2ob_dev[i].max_segments = (d->controller->status_block->inbound_frame_size - 8)/2;
+		}
+	}
+
+	printk(KERN_INFO "Max segments set to %d\n", 
+				i2ob_dev[unit].max_segments);
+	printk(KERN_INFO "Byte limit is %d.\n", limit);
+
+	i2ob_query_device(dev, 0x0000, 0, &type, 1);
+	
+	sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4));
+
+	printk(KERN_INFO "%s: ", d->dev_name);
+	switch(type)
+	{
+		case 0: printk("Disk Storage");break;
+		case 4: printk("WORM");break;
+		case 5: printk("CD-ROM");break;
+		case 7:	printk("Optical device");break;
+		default:
+			printk("Type %d", type);
+	}
+	if(status&(1<<10))
+		printk("(RAID)");
+	if(((flags & (1<<3)) && !(status & (1<<3))) ||
+	   ((flags & (1<<4)) && !(status & (1<<4))))
+	{
+		printk(KERN_INFO " Not loaded.\n");
+		return 1;
+	}
+	printk("- %dMb, %d byte sectors",
+		(int)(size>>20), blocksize);
+	if(status&(1<<0))
+	{
+		u32 cachesize;
+		i2ob_query_device(dev, 0x0003, 0, &cachesize, 4);
+		cachesize>>=10;
+		if(cachesize>4095)
+			printk(", %dMb cache", cachesize>>10);
+		else
+			printk(", %dKb cache", cachesize);
+		
+	}
+	printk(".\n");
+	printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", 
+		d->dev_name, i2ob_max_sectors[unit]);
+
+	/* 
+	 * If this is the first I2O block device found on this IOP,
+	 * we need to initialize all the queue data structures
+	 * before any I/O can be performed. If it fails, this
+	 * device is useless.
+	 */
+	if(!i2ob_queues[c->unit]) {
+		if(i2ob_init_iop(c->unit))
+			return 1;
+	}
+
+	/* 
+	 * This will save one level of lookup/indirection in critical 
+	 * code so that we can directly get the queue ptr from the
+	 * device instead of having to go the IOP data structure.
+	 */
+	dev->req_queue = &i2ob_queues[c->unit]->req_queue;
+
+	grok_partitions(&i2ob_gendisk, unit>>4, 1<<4, (long)(size>>9));
+
+	/*
+	 * Register for the events we're interested in and that the
+	 * device actually supports.
+	 */
+	i2o_event_register(c, d->lct_data.tid, i2ob_context, unit, 
+		(I2OB_EVENT_MASK & d->lct_data.event_capabilities));
+
+	return 0;
+}
+
+/*
+ * Initialize IOP specific queue structures.  This is called
+ * once for each IOP that has a block device sitting behind it.
+ */
+static int i2ob_init_iop(unsigned int unit)
+{
+	int i;
+
+	i2ob_queues[unit] = (struct i2ob_iop_queue*)
+		kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC);
+	if(!i2ob_queues[unit])
+	{
+		printk(KERN_WARNING
+			"Could not allocate request queue for I2O block device!\n");
+		return -1;
+	}
+
+	for(i = 0; i< MAX_I2OB_DEPTH; i++)
+	{
+		i2ob_queues[unit]->request_queue[i].next = 
+			&i2ob_queues[unit]->request_queue[i+1];
+		i2ob_queues[unit]->request_queue[i].num = i;
+	}
+	
+	/* Queue is MAX_I2OB + 1... */
+	i2ob_queues[unit]->request_queue[i].next = NULL;
+	i2ob_queues[unit]->i2ob_qhead = &i2ob_queues[unit]->request_queue[0];
+	atomic_set(&i2ob_queues[unit]->queue_depth, 0);
+
+	blk_init_queue(&i2ob_queues[unit]->req_queue, i2ob_request);
+	blk_queue_headactive(&i2ob_queues[unit]->req_queue, 0);
+	i2ob_queues[unit]->req_queue.back_merge_fn = i2ob_back_merge;
+	i2ob_queues[unit]->req_queue.front_merge_fn = i2ob_front_merge;
+	i2ob_queues[unit]->req_queue.merge_requests_fn = i2ob_merge_requests;
+	i2ob_queues[unit]->req_queue.queuedata = &i2ob_queues[unit];
+
+	return 0;
+}
+
+/*
+ * Get the request queue for the given device.
+ */	
+static request_queue_t* i2ob_get_queue(kdev_t dev)
+{
+	int unit = MINOR(dev)&0xF0;
+
+	return i2ob_dev[unit].req_queue;
+}
+
+/*
+ * Probe the I2O subsytem for block class devices
+ */
+static void i2ob_scan(int bios)
+{
+	int i;
+	int warned = 0;
+
+	struct i2o_device *d, *b=NULL;
+	struct i2o_controller *c;
+	struct i2ob_device *dev;
+		
+	for(i=0; i< MAX_I2O_CONTROLLERS; i++)
+	{
+		c=i2o_find_controller(i);
+	
+		if(c==NULL)
+			continue;
+
+	/*
+	 *    The device list connected to the I2O Controller is doubly linked
+	 * Here we traverse the end of the list , and start claiming devices
+	 * from that end. This assures that within an I2O controller atleast
+	 * the newly created volumes get claimed after the older ones, thus
+	 * mapping to same major/minor (and hence device file name) after 
+	 * every reboot.
+	 * The exception being: 
+	 * 1. If there was a TID reuse.
+	 * 2. There was more than one I2O controller. 
+	 */
+
+	if(!bios)
+	{
+		for (d=c->devices;d!=NULL;d=d->next)
+		if(d->next == NULL)
+			b = d;
+	}
+	else
+		b = c->devices;
+
+	while(b != NULL)
+	{
+		d=b;
+		if(bios)
+			b = b->next;
+		else
+			b = b->prev;
+
+			if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE)
+				continue;
+
+			if(d->lct_data.user_tid != 0xFFF)
+				continue;
+
+			if(bios)
+			{
+				if(d->lct_data.bios_info != 0x80)
+					continue;
+				printk(KERN_INFO "Claiming as Boot device: Controller %d, TID %d\n", c->unit, d->lct_data.tid);
+			}
+			else
+			{
+				if(d->lct_data.bios_info == 0x80)
+					continue; /*Already claimed on pass 1 */
+			}
+
+			if(i2o_claim_device(d, &i2o_block_handler))
+			{
+				printk(KERN_WARNING "i2o_block: Controller %d, TID %d\n", c->unit,
+					d->lct_data.tid);
+				printk(KERN_WARNING "\t%sevice refused claim! Skipping installation\n", bios?"Boot d":"D");
+				continue;
+			}
+
+			if(scan_unit<MAX_I2OB<<4)
+			{
+ 				/*
+				 * Get the device and fill in the
+				 * Tid and controller.
+				 */
+				dev=&i2ob_dev[scan_unit];
+				dev->i2odev = d; 
+				dev->controller = c;
+				dev->unit = c->unit;
+				dev->tid = d->lct_data.tid;
+
+				if(i2ob_install_device(c,d,scan_unit))
+					printk(KERN_WARNING "Could not install I2O block device\n");
+				else
+				{
+					scan_unit+=16;
+					i2ob_dev_count++;
+
+					/* We want to know when device goes away */
+					i2o_device_notify_on(d, &i2o_block_handler);
+				}
+			}
+			else
+			{
+				if(!warned++)
+					printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", scan_unit>>4);
+			}
+			i2o_release_device(d, &i2o_block_handler);
+		}
+		i2o_unlock_controller(c);
+	}
+}
+
+static void i2ob_probe(void)
+{
+	/*
+	 *      Some overhead/redundancy involved here, while trying to
+	 *      claim the first boot volume encountered as /dev/i2o/hda
+	 *      everytime. All the i2o_controllers are searched and the
+	 *      first i2o block device marked as bootable is claimed
+	 *      If an I2O block device was booted off , the bios sets
+	 *      its bios_info field to 0x80, this what we search for.
+	 *      Assuming that the bootable volume is /dev/i2o/hda
+	 *      everytime will prevent any kernel panic while mounting
+	 *      root partition
+	 */
+
+	printk(KERN_INFO "i2o_block: Checking for Boot device...\n");
+	i2ob_scan(1);
+
+	/*
+	 *      Now the remainder.
+	 */
+	printk(KERN_INFO "i2o_block: Checking for I2O Block devices...\n");
+	i2ob_scan(0);
+}
+
+
+/*
+ * New device notification handler.  Called whenever a new
+ * I2O block storage device is added to the system.
+ * 
+ * Should we spin lock around this to keep multiple devs from 
+ * getting updated at the same time? 
+ * 
+ */
+void i2ob_new_device(struct i2o_controller *c, struct i2o_device *d)
+{
+	struct i2ob_device *dev;
+	int unit = 0;
+
+	printk(KERN_INFO "i2o_block: New device detected\n");
+	printk(KERN_INFO "   Controller %d Tid %d\n",c->unit, d->lct_data.tid);
+
+	/* Check for available space */
+	if(i2ob_dev_count>=MAX_I2OB<<4)
+	{
+		printk(KERN_ERR "i2o_block: No more devices allowed!\n");
+		return;
+	}
+	for(unit = 0; unit < (MAX_I2OB<<4); unit += 16)
+	{
+		if(!i2ob_dev[unit].i2odev)
+			break;
+	}
+
+	if(i2o_claim_device(d, &i2o_block_handler))
+	{
+		printk(KERN_INFO 
+			"i2o_block: Unable to claim device. Installation aborted\n");
+		return;
+	}
+
+	dev = &i2ob_dev[unit];
+	dev->i2odev = d; 
+	dev->controller = c;
+	dev->tid = d->lct_data.tid;
+
+	if(i2ob_install_device(c,d,unit))
+		printk(KERN_ERR "i2o_block: Could not install new device\n");
+	else	
+	{
+		i2ob_dev_count++;
+		i2o_device_notify_on(d, &i2o_block_handler);
+	}
+
+	i2o_release_device(d, &i2o_block_handler);
+ 
+	return;
+}
+
+/*
+ * Deleted device notification handler.  Called when a device we
+ * are talking to has been deleted by the user or some other
+ * mysterious fource outside the kernel.
+ */
+void i2ob_del_device(struct i2o_controller *c, struct i2o_device *d)
+{	
+	int unit = 0;
+	int i = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	/*
+	 * Need to do this...we somtimes get two events from the IRTOS
+	 * in a row and that causes lots of problems.
+	 */
+	i2o_device_notify_off(d, &i2o_block_handler);
+
+	printk(KERN_INFO "I2O Block Device Deleted\n");
+
+	for(unit = 0; unit < MAX_I2OB<<4; unit += 16)
+	{
+		if(i2ob_dev[unit].i2odev == d)
+		{
+			printk(KERN_INFO "  /dev/%s: Controller %d Tid %d\n", 
+				d->dev_name, c->unit, d->lct_data.tid);
+			break;
+		}
+	}
+	if(unit >= MAX_I2OB<<4)
+	{
+		printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n");
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+
+	/* 
+	 * This will force errors when i2ob_get_queue() is called
+	 * by the kenrel.
+	 */
+	i2ob_dev[unit].req_queue = NULL;
+	for(i = unit; i <= unit+15; i++)
+	{
+		i2ob_dev[i].i2odev = NULL;
+		i2ob_sizes[i] = 0;
+		i2ob_hardsizes[i] = 0;
+		i2ob_max_sectors[i] = 0;
+		i2ob[i].nr_sects = 0;
+		i2ob_gendisk.part[i].nr_sects = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	/*
+	 * Sync the device...this will force all outstanding I/Os
+	 * to attempt to complete, thus causing error messages.
+	 * We have to do this as the user could immediatelly create
+	 * a new volume that gets assigned the same minor number.
+	 * If there are still outstanding writes to the device,
+	 * that could cause data corruption on the new volume!
+	 *
+	 * The truth is that deleting a volume that you are currently
+	 * accessing will do _bad things_ to your system.  This 
+	 * handler will keep it from crashing, but must probably 
+	 * you'll have to do a 'reboot' to get the system running
+	 * properly.  Deleting disks you are using is dumb.  
+	 * Umount them first and all will be good!
+	 *
+	 * It's not this driver's job to protect the system from
+	 * dumb user mistakes :)
+	 */
+	if(i2ob_dev[unit].refcnt)
+		fsync_dev(MKDEV(MAJOR_NR,unit));
+
+	/*
+	 * Decrease usage count for module
+	 */	
+	while(i2ob_dev[unit].refcnt--)
+		MOD_DEC_USE_COUNT;
+
+	i2ob_dev[unit].refcnt = 0;
+	
+	i2ob_dev[i].tid = 0;
+
+	/* 
+	 * Do we need this?
+	 * The media didn't really change...the device is just gone
+	 */
+	i2ob_media_change_flag[unit] = 1;
+
+	i2ob_dev_count--;	
+}
+
+/*
+ *	Have we seen a media change ?
+ */
+static int i2ob_media_change(kdev_t dev)
+{
+	int i=MINOR(dev);
+	i>>=4;
+	if(i2ob_media_change_flag[i])
+	{
+		i2ob_media_change_flag[i]=0;
+		return 1;
+	}
+	return 0;
+}
+
+static int i2ob_revalidate(kdev_t dev)
+{
+	return do_i2ob_revalidate(dev, 0);
+}
+
+/*
+ * Reboot notifier.  This is called by i2o_core when the system
+ * shuts down.
+ */
+static void i2ob_reboot_event(void)
+{
+	int i;
+	
+	for(i=0;i<MAX_I2OB;i++)
+	{
+		struct i2ob_device *dev=&i2ob_dev[(i<<4)];
+		
+		if(dev->refcnt!=0)
+		{
+			/*
+			 *	Flush the onboard cache
+			 */
+			u32 msg[5];
+			int *query_done = &dev->done_flag;
+			msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+			msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid;
+			msg[2] = i2ob_context|0x40000000;
+			msg[3] = (u32)query_done;
+			msg[4] = 60<<16;
+			
+			DEBUG("Flushing...");
+			i2o_post_wait(dev->controller, msg, 20, 60);
+
+			DEBUG("Unlocking...");
+			/*
+			 *	Unlock the media
+			 */
+			msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+			msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid;
+			msg[2] = i2ob_context|0x40000000;
+			msg[3] = (u32)query_done;
+			msg[4] = -1;
+			i2o_post_wait(dev->controller, msg, 20, 2);
+			
+			DEBUG("Unlocked.\n");
+		}
+	}	
+}
+
+static struct block_device_operations i2ob_fops =
+{
+	open:			i2ob_open,
+	release:		i2ob_release,
+	ioctl:			i2ob_ioctl,
+	check_media_change:	i2ob_media_change,
+	revalidate:		i2ob_revalidate,
+};
+
+static struct gendisk i2ob_gendisk = 
+{
+	major:		MAJOR_NR,
+	major_name:	"i2o/hd",
+	minor_shift:	4,
+	max_p:		1<<4,
+	part:		i2ob,
+	sizes:		i2ob_sizes,
+	nr_real:	MAX_I2OB,
+	fops:		&i2ob_fops,
+};
+
+
+/*
+ * And here should be modules and kernel interface 
+ *  (Just smiley confuses emacs :-)
+ */
+
+#ifdef MODULE
+#define i2o_block_init init_module
+#endif
+
+int i2o_block_init(void)
+{
+	int i;
+
+	printk(KERN_INFO "I2O Block Storage OSM v0.9\n");
+	printk(KERN_INFO "   (c) Copyright 1999-2001 Red Hat Software.\n");
+	
+	/*
+	 *	Register the block device interfaces
+	 */
+
+	if (register_blkdev(MAJOR_NR, "i2o_block", &i2ob_fops)) {
+		printk(KERN_ERR "Unable to get major number %d for i2o_block\n",
+		       MAJOR_NR);
+		return -EIO;
+	}
+#ifdef MODULE
+	printk(KERN_INFO "i2o_block: registered device at major %d\n", MAJOR_NR);
+#endif
+
+	/*
+	 *	Now fill in the boiler plate
+	 */
+	 
+	blksize_size[MAJOR_NR] = i2ob_blksizes;
+	hardsect_size[MAJOR_NR] = i2ob_hardsizes;
+	blk_size[MAJOR_NR] = i2ob_sizes;
+	max_sectors[MAJOR_NR] = i2ob_max_sectors;
+	blk_dev[MAJOR_NR].queue = i2ob_get_queue;
+	
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), i2ob_request);
+	blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
+
+	for (i = 0; i < MAX_I2OB << 4; i++) {
+		i2ob_dev[i].refcnt = 0;
+		i2ob_dev[i].flags = 0;
+		i2ob_dev[i].controller = NULL;
+		i2ob_dev[i].i2odev = NULL;
+		i2ob_dev[i].tid = 0;
+		i2ob_dev[i].head = NULL;
+		i2ob_dev[i].tail = NULL;
+		i2ob_dev[i].depth = MAX_I2OB_DEPTH;
+		i2ob_blksizes[i] = 1024;
+		i2ob_max_sectors[i] = 2;
+	}
+	
+	/*
+	 *	Set up the queue
+	 */
+	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
+	{
+		i2ob_queues[i] = NULL;
+	}
+
+	/*
+	 *	Timers
+	 */
+	 
+	init_timer(&i2ob_timer);
+	i2ob_timer.function = i2ob_timer_handler;
+	i2ob_timer.data = 0;
+	
+	/*
+	 *	Register the OSM handler as we will need this to probe for
+	 *	drives, geometry and other goodies.
+	 */
+
+	if(i2o_install_handler(&i2o_block_handler)<0)
+	{
+		unregister_blkdev(MAJOR_NR, "i2o_block");
+		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+		printk(KERN_ERR "i2o_block: unable to register OSM.\n");
+		return -EINVAL;
+	}
+	i2ob_context = i2o_block_handler.context;	 
+
+	/*
+	 * Initialize event handling thread
+	 */
+	init_MUTEX_LOCKED(&i2ob_evt_sem);
+	evt_pid = kernel_thread(i2ob_evt, NULL, CLONE_SIGHAND);
+	if(evt_pid < 0)
+	{
+		printk(KERN_ERR 
+			"i2o_block: Could not initialize event thread.  Aborting\n");
+		i2o_remove_handler(&i2o_block_handler);
+		return 0;
+	}
+
+	/*
+	 *	Finally see what is actually plugged in to our controllers
+	 */
+	for (i = 0; i < MAX_I2OB; i++)
+		register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4,
+			&i2ob_fops, 0);
+	i2ob_probe();
+
+	/*
+	 *	Adding i2ob_gendisk into the gendisk list.
+	 */
+	add_gendisk(&i2ob_gendisk);
+
+	return 0;
+}
+
+#ifdef MODULE
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR("Red Hat Software");
+MODULE_DESCRIPTION("I2O Block Device OSM");
+
+void cleanup_module(void)
+{
+	struct gendisk *gdp;
+	int i;
+	
+	if(evt_running) {
+		printk(KERN_INFO "Killing I2O block threads...");
+		i = kill_proc(evt_pid, SIGTERM, 1);
+		if(!i) {
+			printk("waiting...");
+		}
+		/* Be sure it died */
+		wait_for_completion(&i2ob_thread_dead);
+		printk("done.\n");
+	}
+
+	/*
+	 * Unregister for updates from any devices..otherwise we still
+	 * get them and the core jumps to random memory :O
+	 */
+	if(i2ob_dev_count) {
+		struct i2o_device *d;
+		for(i = 0; i < MAX_I2OB; i++)
+		if((d=i2ob_dev[i<<4].i2odev)) {
+			i2o_device_notify_off(d, &i2o_block_handler);
+			i2o_event_register(d->controller, d->lct_data.tid, 
+				i2ob_context, i<<4, 0);
+		}
+	}
+	
+	/*
+	 *	We may get further callbacks for ourself. The i2o_core
+	 *	code handles this case reasonably sanely. The problem here
+	 *	is we shouldn't get them .. but a couple of cards feel 
+	 *	obliged to tell us stuff we dont care about.
+	 *
+	 *	This isnt ideal at all but will do for now.
+	 */
+	 
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ);
+	
+	/*
+	 *	Flush the OSM
+	 */
+
+	i2o_remove_handler(&i2o_block_handler);
+		 
+	/*
+	 *	Return the block device
+	 */
+	if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0)
+		printk("i2o_block: cleanup_module failed\n");
+
+	/*
+	 * free request queue
+	 */
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+
+	del_gendisk(&i2ob_gendisk);
+}
+#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/i2o_config.c linux/drivers/message/i2o/i2o_config.c
--- v2.4.12/linux/drivers/message/i2o/i2o_config.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/i2o_config.c	Thu Aug 16 09:50:15 2001
@@ -0,0 +1,965 @@
+/*
+ * I2O Configuration Interface Driver
+ *
+ * (C) Copyright 1999   Red Hat Software
+ *	
+ * Written by Alan Cox, Building Number Three Ltd
+ *
+ * Modified 04/20/1999 by Deepak Saxena
+ *   - Added basic ioctl() support
+ * Modified 06/07/1999 by Deepak Saxena
+ *   - Added software download ioctl (still testing)
+ * Modified 09/10/1999 by Auvo Häkkinen
+ *   - Changes to i2o_cfg_reply(), ioctl_parms()
+ *   - Added ioct_validate()
+ * Modified 09/30/1999 by Taneli Vähäkangas
+ *   - Fixed ioctl_swdl()
+ * Modified 10/04/1999 by Taneli Vähäkangas
+ *   - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
+ * Modified 11/18/199 by Deepak Saxena
+ *   - Added event managmenet support
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/i2o.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+static int i2o_cfg_context = -1;
+static void *page_buf;
+static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED;
+struct wait_queue *i2o_wait_queue;
+
+#define MODINC(x,y) (x = x++ % y)
+
+struct i2o_cfg_info
+{
+	struct file* fp;
+	struct fasync_struct *fasync;
+	struct i2o_evt_info event_q[I2O_EVT_Q_LEN];
+	u16		q_in;		// Queue head index
+	u16		q_out;		// Queue tail index
+	u16		q_len;		// Queue length
+	u16		q_lost;		// Number of lost events
+	u32		q_id;		// Event queue ID...used as tx_context
+	struct	i2o_cfg_info *next;
+};
+static struct i2o_cfg_info *open_files = NULL;
+static int i2o_cfg_info_id = 0;
+
+static int ioctl_getiops(unsigned long);
+static int ioctl_gethrt(unsigned long);
+static int ioctl_getlct(unsigned long);
+static int ioctl_parms(unsigned long, unsigned int);
+static int ioctl_html(unsigned long);
+static int ioctl_swdl(unsigned long);
+static int ioctl_swul(unsigned long);
+static int ioctl_swdel(unsigned long);
+static int ioctl_validate(unsigned long); 
+static int ioctl_evt_reg(unsigned long, struct file *);
+static int ioctl_evt_get(unsigned long, struct file *);
+static int cfg_fasync(int, struct file*, int);
+
+/*
+ *	This is the callback for any message we have posted. The message itself
+ *	will be returned to the message pool when we return from the IRQ
+ *
+ *	This runs in irq context so be short and sweet.
+ */
+static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m)
+{
+	u32 *msg = (u32 *)m;
+
+	if (msg[0] & MSG_FAIL) {
+		u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]);
+
+		printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n");
+
+		/* Release the preserved msg frame by resubmitting it as a NOP */
+
+		preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+		preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
+		preserved_msg[2] = 0;
+		i2o_post_message(c, msg[7]);
+	}
+
+	if (msg[4] >> 24)  // ReqStatus != SUCCESS
+		i2o_report_status(KERN_INFO,"i2o_config", msg);
+
+	if(m->function == I2O_CMD_UTIL_EVT_REGISTER)
+	{
+		struct i2o_cfg_info *inf;
+
+		for(inf = open_files; inf; inf = inf->next)
+			if(inf->q_id == msg[3])
+				break;
+
+		//
+		// If this is the case, it means that we're getting
+		// events for a file descriptor that's been close()'d
+		// w/o the user unregistering for events first.
+		// The code currently assumes that the user will 
+		// take care of unregistering for events before closing
+		// a file.
+		// 
+		// TODO: 
+		// Should we track event registartion and deregister
+		// for events when a file is close()'d so this doesn't
+		// happen? That would get rid of the search through
+		// the linked list since file->private_data could point
+		// directly to the i2o_config_info data structure...but
+		// it would mean having all sorts of tables to track
+		// what each file is registered for...I think the
+		// current method is simpler. - DS
+		//			
+		if(!inf)
+			return;
+
+		inf->event_q[inf->q_in].id.iop = c->unit;
+		inf->event_q[inf->q_in].id.tid = m->target_tid;
+		inf->event_q[inf->q_in].id.evt_mask = msg[4];
+
+		//
+		// Data size = msg size - reply header
+		//
+		inf->event_q[inf->q_in].data_size = (m->size - 5) * 4;
+		if(inf->event_q[inf->q_in].data_size)
+			memcpy(inf->event_q[inf->q_in].evt_data, 
+				(unsigned char *)(msg + 5),
+				inf->event_q[inf->q_in].data_size);
+
+		spin_lock(&i2o_config_lock);
+		MODINC(inf->q_in, I2O_EVT_Q_LEN);
+		if(inf->q_len == I2O_EVT_Q_LEN)
+		{
+			MODINC(inf->q_out, I2O_EVT_Q_LEN);
+			inf->q_lost++;
+		}
+		else
+		{
+			// Keep I2OEVTGET on another CPU from touching this
+			inf->q_len++;
+		}
+		spin_unlock(&i2o_config_lock);
+		
+
+//		printk(KERN_INFO "File %p w/id %d has %d events\n",
+//			inf->fp, inf->q_id, inf->q_len);	
+
+		kill_fasync(&inf->fasync, SIGIO, POLL_IN);
+	}
+
+	return;
+}
+
+/*
+ *	Each of these describes an i2o message handler. They are
+ *	multiplexed by the i2o_core code
+ */
+ 
+struct i2o_handler cfg_handler=
+{
+	i2o_cfg_reply,
+	NULL,
+	NULL,
+	NULL,
+	"Configuration",
+	0,
+	0xffffffff	// All classes
+};
+
+static ssize_t cfg_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	printk(KERN_INFO "i2o_config write not yet supported\n");
+
+	return 0;
+}
+
+
+static ssize_t cfg_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+	return 0;
+}
+
+/*
+ * IOCTL Handler
+ */
+static int cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
+	unsigned long arg)
+{
+	int ret;
+
+	switch(cmd)
+	{	
+		case I2OGETIOPS:
+			ret = ioctl_getiops(arg);
+			break;
+
+		case I2OHRTGET:
+			ret = ioctl_gethrt(arg);
+			break;
+
+		case I2OLCTGET:
+			ret = ioctl_getlct(arg);
+			break;
+
+		case I2OPARMSET:
+			ret = ioctl_parms(arg, I2OPARMSET);
+			break;
+
+		case I2OPARMGET:
+			ret = ioctl_parms(arg, I2OPARMGET);
+			break;
+
+		case I2OSWDL:
+			ret = ioctl_swdl(arg);
+			break;
+
+		case I2OSWUL:
+			ret = ioctl_swul(arg);
+			break;
+
+		case I2OSWDEL:
+			ret = ioctl_swdel(arg);
+			break;
+
+		case I2OVALIDATE:
+			ret = ioctl_validate(arg);
+			break;
+			
+		case I2OHTML:
+			ret = ioctl_html(arg);
+			break;
+
+		case I2OEVTREG:
+			ret = ioctl_evt_reg(arg, fp);
+			break;
+
+		case I2OEVTGET:
+			ret = ioctl_evt_get(arg, fp);
+			break;
+
+		default:
+			ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int ioctl_getiops(unsigned long arg)
+{
+	u8 *user_iop_table = (u8*)arg;
+	struct i2o_controller *c = NULL;
+	int i;
+	u8 foo[MAX_I2O_CONTROLLERS];
+
+	if(!access_ok(VERIFY_WRITE, user_iop_table,  MAX_I2O_CONTROLLERS))
+		return -EFAULT;
+
+	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
+	{
+		c = i2o_find_controller(i);
+		if(c)
+		{
+			foo[i] = 1;
+			i2o_unlock_controller(c);
+		}
+		else
+		{
+			foo[i] = 0;
+		}
+	}
+
+	__copy_to_user(user_iop_table, foo, MAX_I2O_CONTROLLERS);
+	return 0;
+}
+
+int ioctl_gethrt(unsigned long arg)
+{
+	struct i2o_controller *c;
+	struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg;
+	struct i2o_cmd_hrtlct kcmd;
+	i2o_hrt *hrt;
+	int len;
+	u32 reslen;
+	int ret = 0;
+
+	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))
+		return -EFAULT;
+
+	if(get_user(reslen, kcmd.reslen) < 0)
+		return -EFAULT;
+
+	if(kcmd.resbuf == NULL)
+		return -EFAULT;
+
+	c = i2o_find_controller(kcmd.iop);
+	if(!c)
+		return -ENXIO;
+		
+	hrt = (i2o_hrt *)c->hrt;
+
+	i2o_unlock_controller(c);
+
+	len = 8 + ((hrt->entry_len * hrt->num_entries) << 2);
+	
+	/* We did a get user...so assuming mem is ok...is this bad? */
+	put_user(len, kcmd.reslen);
+	if(len > reslen)
+		ret = -ENOBUFS;	
+	if(copy_to_user(kcmd.resbuf, (void*)hrt, len))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+int ioctl_getlct(unsigned long arg)
+{
+	struct i2o_controller *c;
+	struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg;
+	struct i2o_cmd_hrtlct kcmd;
+	i2o_lct *lct;
+	int len;
+	int ret = 0;
+	u32 reslen;
+
+	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))
+		return -EFAULT;
+
+	if(get_user(reslen, kcmd.reslen) < 0)
+		return -EFAULT;
+
+	if(kcmd.resbuf == NULL)
+		return -EFAULT;
+
+	c = i2o_find_controller(kcmd.iop);
+	if(!c)
+		return -ENXIO;
+
+	lct = (i2o_lct *)c->lct;
+	i2o_unlock_controller(c);
+
+	len = (unsigned int)lct->table_size << 2;
+	put_user(len, kcmd.reslen);
+	if(len > reslen)
+		ret = -ENOBUFS;	
+	else if(copy_to_user(kcmd.resbuf, (void*)lct, len))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int ioctl_parms(unsigned long arg, unsigned int type)
+{
+	int ret = 0;
+	struct i2o_controller *c;
+	struct i2o_cmd_psetget *cmd = (struct i2o_cmd_psetget*)arg;
+	struct i2o_cmd_psetget kcmd;
+	u32 reslen;
+	u8 *ops;
+	u8 *res;
+	int len;
+
+	u32 i2o_cmd = (type == I2OPARMGET ? 
+				I2O_CMD_UTIL_PARAMS_GET :
+				I2O_CMD_UTIL_PARAMS_SET);
+
+	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget)))
+		return -EFAULT;
+
+	if(get_user(reslen, kcmd.reslen))
+		return -EFAULT;
+
+	c = i2o_find_controller(kcmd.iop);
+	if(!c)
+		return -ENXIO;
+
+	ops = (u8*)kmalloc(kcmd.oplen, GFP_KERNEL);
+	if(!ops)
+	{
+		i2o_unlock_controller(c);
+		return -ENOMEM;
+	}
+
+	if(copy_from_user(ops, kcmd.opbuf, kcmd.oplen))
+	{
+		i2o_unlock_controller(c);
+		kfree(ops);
+		return -EFAULT;
+	}
+
+	/*
+	 * It's possible to have a _very_ large table
+	 * and that the user asks for all of it at once...
+	 */
+	res = (u8*)kmalloc(65536, GFP_KERNEL);
+	if(!res)
+	{
+		i2o_unlock_controller(c);
+		kfree(ops);
+		return -ENOMEM;
+	}
+
+	len = i2o_issue_params(i2o_cmd, c, kcmd.tid, 
+				ops, kcmd.oplen, res, 65536);
+	i2o_unlock_controller(c);
+	kfree(ops);
+        
+	if (len < 0) {
+		kfree(res);
+		return -EAGAIN;
+	}
+
+	put_user(len, kcmd.reslen);
+	if(len > reslen)
+		ret = -ENOBUFS;
+	else if(copy_to_user(cmd->resbuf, res, len))
+		ret = -EFAULT;
+
+	kfree(res);
+
+	return ret;
+}
+
+int ioctl_html(unsigned long arg)
+{
+	struct i2o_html *cmd = (struct i2o_html*)arg;
+	struct i2o_html kcmd;
+	struct i2o_controller *c;
+	u8 *res = NULL;
+	void *query = NULL;
+	int ret = 0;
+	int token;
+	u32 len;
+	u32 reslen;
+	u32 msg[MSG_FRAME_SIZE/4];
+
+	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_html)))
+	{
+		printk(KERN_INFO "i2o_config: can't copy html cmd\n");
+		return -EFAULT;
+	}
+
+	if(get_user(reslen, kcmd.reslen) < 0)
+	{
+		printk(KERN_INFO "i2o_config: can't copy html reslen\n");
+		return -EFAULT;
+	}
+
+	if(!kcmd.resbuf)		
+	{
+		printk(KERN_INFO "i2o_config: NULL html buffer\n");
+		return -EFAULT;
+	}
+
+	c = i2o_find_controller(kcmd.iop);
+	if(!c)
+		return -ENXIO;
+
+	if(kcmd.qlen) /* Check for post data */
+	{
+		query = kmalloc(kcmd.qlen, GFP_KERNEL);
+		if(!query)
+		{
+			i2o_unlock_controller(c);
+			return -ENOMEM;
+		}
+		if(copy_from_user(query, kcmd.qbuf, kcmd.qlen))
+		{
+			i2o_unlock_controller(c);
+			printk(KERN_INFO "i2o_config: could not get query\n");
+			kfree(query);
+			return -EFAULT;
+		}
+	}
+
+	res = kmalloc(65536, GFP_KERNEL);
+	if(!res)
+	{
+		i2o_unlock_controller(c);
+		kfree(query);
+		return -ENOMEM;
+	}
+
+	msg[1] = (I2O_CMD_UTIL_CONFIG_DIALOG << 24)|HOST_TID<<12|kcmd.tid;
+	msg[2] = i2o_cfg_context;
+	msg[3] = 0;
+	msg[4] = kcmd.page;
+	msg[5] = 0xD0000000|65536;
+	msg[6] = virt_to_bus(res);
+	if(!kcmd.qlen) /* Check for post data */
+		msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5;
+	else
+	{
+		msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
+		msg[5] = 0x50000000|65536;
+		msg[7] = 0xD4000000|(kcmd.qlen);
+		msg[8] = virt_to_bus(query);
+	}
+	/*
+	Wait for a considerable time till the Controller 
+	does its job before timing out. The controller might
+	take more time to process this request if there are
+	many devices connected to it.
+	*/
+	token = i2o_post_wait_mem(c, msg, 9*4, 400, query, res);
+	if(token < 0)
+	{
+		printk(KERN_DEBUG "token = %#10x\n", token);
+		i2o_unlock_controller(c);
+		
+		if(token != -ETIMEDOUT)
+		{
+			kfree(res);
+			if(kcmd.qlen) kfree(query);
+		}
+
+		return token;
+	}
+	i2o_unlock_controller(c);
+
+	len = strnlen(res, 65536);
+	put_user(len, kcmd.reslen);
+	if(len > reslen)
+		ret = -ENOMEM;
+	if(copy_to_user(kcmd.resbuf, res, len))
+		ret = -EFAULT;
+
+	kfree(res);
+	if(kcmd.qlen) 
+		kfree(query);
+
+	return ret;
+}
+ 
+int ioctl_swdl(unsigned long arg)
+{
+	struct i2o_sw_xfer kxfer;
+	struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg;
+	unsigned char maxfrag = 0, curfrag = 1;
+	unsigned char *buffer;
+	u32 msg[9];
+	unsigned int status = 0, swlen = 0, fragsize = 8192;
+	struct i2o_controller *c;
+
+	if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
+		return -EFAULT;
+
+	if(get_user(swlen, kxfer.swlen) < 0)
+		return -EFAULT;
+
+	if(get_user(maxfrag, kxfer.maxfrag) < 0)
+		return -EFAULT;
+
+	if(get_user(curfrag, kxfer.curfrag) < 0)
+		return -EFAULT;
+
+	if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192;
+
+	if(!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize))
+		return -EFAULT;
+	
+	c = i2o_find_controller(kxfer.iop);
+	if(!c)
+		return -ENXIO;
+
+	buffer=kmalloc(fragsize, GFP_KERNEL);
+	if (buffer==NULL)
+	{
+		i2o_unlock_controller(c);
+		return -ENOMEM;
+	}
+	__copy_from_user(buffer, kxfer.buf, fragsize);
+
+	msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7;
+	msg[1]= I2O_CMD_SW_DOWNLOAD<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2]= (u32)cfg_handler.context;
+	msg[3]= 0;
+	msg[4]= (((u32)kxfer.flags)<<24) | (((u32)kxfer.sw_type)<<16) |
+		(((u32)maxfrag)<<8) | (((u32)curfrag));
+	msg[5]= swlen;
+	msg[6]= kxfer.sw_id;
+	msg[7]= (0xD0000000 | fragsize);
+	msg[8]= virt_to_bus(buffer);
+
+//	printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
+	status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL);
+
+	i2o_unlock_controller(c);
+	if(status != -ETIMEDOUT)
+		kfree(buffer);
+	
+	if (status != I2O_POST_WAIT_OK)
+	{
+		// it fails if you try and send frags out of order
+		// and for some yet unknown reasons too
+		printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status);
+		return status;
+	}
+
+	return 0;
+}
+
+int ioctl_swul(unsigned long arg)
+{
+	struct i2o_sw_xfer kxfer;
+	struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg;
+	unsigned char maxfrag = 0, curfrag = 1;
+	unsigned char *buffer;
+	u32 msg[9];
+	unsigned int status = 0, swlen = 0, fragsize = 8192;
+	struct i2o_controller *c;
+	
+	if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
+		return -EFAULT;
+		
+	if(get_user(swlen, kxfer.swlen) < 0)
+		return -EFAULT;
+		
+	if(get_user(maxfrag, kxfer.maxfrag) < 0)
+		return -EFAULT;
+		
+	if(get_user(curfrag, kxfer.curfrag) < 0)
+		return -EFAULT;
+	
+	if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192;
+	
+	if(!kxfer.buf || !access_ok(VERIFY_WRITE, kxfer.buf, fragsize))
+		return -EFAULT;
+		
+	c = i2o_find_controller(kxfer.iop);
+	if(!c)
+		return -ENXIO;
+		
+	buffer=kmalloc(fragsize, GFP_KERNEL);
+	if (buffer==NULL)
+	{
+		i2o_unlock_controller(c);
+		return -ENOMEM;
+	}
+	
+	msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7;
+	msg[1]= I2O_CMD_SW_UPLOAD<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2]= (u32)cfg_handler.context;
+	msg[3]= 0;
+	msg[4]= (u32)kxfer.flags<<24|(u32)kxfer.sw_type<<16|(u32)maxfrag<<8|(u32)curfrag;
+	msg[5]= swlen;
+	msg[6]= kxfer.sw_id;
+	msg[7]= (0xD0000000 | fragsize);
+	msg[8]= virt_to_bus(buffer);
+	
+//	printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
+	status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL);
+	i2o_unlock_controller(c);
+	
+	if (status != I2O_POST_WAIT_OK)
+	{
+		if(status != -ETIMEDOUT)
+			kfree(buffer);
+		printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status);
+		return status;
+	}
+	
+	__copy_to_user(kxfer.buf, buffer, fragsize);
+	kfree(buffer);
+	
+	return 0;
+}
+
+int ioctl_swdel(unsigned long arg)
+{
+	struct i2o_controller *c;
+	struct i2o_sw_xfer kxfer, *pxfer = (struct i2o_sw_xfer *)arg;
+	u32 msg[7];
+	unsigned int swlen;
+	int token;
+	
+	if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
+		return -EFAULT;
+		
+	if (get_user(swlen, kxfer.swlen) < 0)
+		return -EFAULT;
+		
+	c = i2o_find_controller(kxfer.iop);
+	if (!c)
+		return -ENXIO;
+
+	msg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+	msg[1] = I2O_CMD_SW_REMOVE<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2] = (u32)i2o_cfg_context;
+	msg[3] = 0;
+	msg[4] = (u32)kxfer.flags<<24 | (u32)kxfer.sw_type<<16;
+	msg[5] = swlen;
+	msg[6] = kxfer.sw_id;
+
+	token = i2o_post_wait(c, msg, sizeof(msg), 10);
+	i2o_unlock_controller(c);
+	
+	if (token != I2O_POST_WAIT_OK)
+	{
+		printk(KERN_INFO "i2o_config: swdel failed, DetailedStatus = %d\n", token);
+		return -ETIMEDOUT;
+	}
+	
+	return 0;
+}
+
+int ioctl_validate(unsigned long arg)
+{
+        int token;
+        int iop = (int)arg;
+        u32 msg[4];
+        struct i2o_controller *c;
+
+        c=i2o_find_controller(iop);
+        if (!c)
+                return -ENXIO;
+
+        msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+        msg[1] = I2O_CMD_CONFIG_VALIDATE<<24 | HOST_TID<<12 | iop;
+        msg[2] = (u32)i2o_cfg_context;
+        msg[3] = 0;
+
+        token = i2o_post_wait(c, msg, sizeof(msg), 10);
+        i2o_unlock_controller(c);
+
+        if (token != I2O_POST_WAIT_OK)
+        {
+                printk(KERN_INFO "Can't validate configuration, ErrorStatus = %d\n",
+                	token);
+                return -ETIMEDOUT;
+        }
+
+        return 0;
+}   
+
+static int ioctl_evt_reg(unsigned long arg, struct file *fp)
+{
+	u32 msg[5];
+	struct i2o_evt_id *pdesc = (struct i2o_evt_id *)arg;
+	struct i2o_evt_id kdesc;
+	struct i2o_controller *iop;
+	struct i2o_device *d;
+
+	if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id)))
+		return -EFAULT;
+
+	/* IOP exists? */
+	iop = i2o_find_controller(kdesc.iop);
+	if(!iop)
+		return -ENXIO;
+	i2o_unlock_controller(iop);
+
+	/* Device exists? */
+	for(d = iop->devices; d; d = d->next)
+		if(d->lct_data.tid == kdesc.tid)
+			break;
+
+	if(!d)
+		return -ENODEV;
+
+	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | kdesc.tid;
+	msg[2] = (u32)i2o_cfg_context;
+	msg[3] = (u32)fp->private_data;
+	msg[4] = kdesc.evt_mask;
+
+	i2o_post_this(iop, msg, 20);
+
+	return 0;
+}	
+
+static int ioctl_evt_get(unsigned long arg, struct file *fp)
+{
+	u32 id = (u32)fp->private_data;
+	struct i2o_cfg_info *p = NULL;
+	struct i2o_evt_get *uget = (struct i2o_evt_get*)arg;
+	struct i2o_evt_get kget;
+	unsigned long flags;
+
+	for(p = open_files; p; p = p->next)
+		if(p->q_id == id)
+			break;
+
+	if(!p->q_len)
+	{
+		return -ENOENT;
+		return 0;
+	}
+
+	memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info));
+	MODINC(p->q_out, I2O_EVT_Q_LEN);
+	spin_lock_irqsave(&i2o_config_lock, flags);
+	p->q_len--;
+	kget.pending = p->q_len;
+	kget.lost = p->q_lost;
+	spin_unlock_irqrestore(&i2o_config_lock, flags);
+
+	if(copy_to_user(uget, &kget, sizeof(struct i2o_evt_get)))
+		return -EFAULT;
+	return 0;
+}
+
+static int cfg_open(struct inode *inode, struct file *file)
+{
+	struct i2o_cfg_info *tmp = 
+		(struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), GFP_KERNEL);
+	unsigned long flags;
+
+	if(!tmp)
+		return -ENOMEM;
+
+	file->private_data = (void*)(i2o_cfg_info_id++);
+	tmp->fp = file;
+	tmp->fasync = NULL;
+	tmp->q_id = (u32)file->private_data;
+	tmp->q_len = 0;
+	tmp->q_in = 0;
+	tmp->q_out = 0;
+	tmp->q_lost = 0;
+	tmp->next = open_files;
+
+	spin_lock_irqsave(&i2o_config_lock, flags);
+	open_files = tmp;
+	spin_unlock_irqrestore(&i2o_config_lock, flags);
+	
+	return 0;
+}
+
+static int cfg_release(struct inode *inode, struct file *file)
+{
+	u32 id = (u32)file->private_data;
+	struct i2o_cfg_info *p1, *p2;
+	unsigned long flags;
+
+	lock_kernel();
+	p1 = p2 = NULL;
+
+	spin_lock_irqsave(&i2o_config_lock, flags);
+	for(p1 = open_files; p1; )
+	{
+		if(p1->q_id == id)
+		{
+
+			if(p1->fasync)
+				cfg_fasync(-1, file, 0);
+			if(p2)
+				p2->next = p1->next;
+			else
+				open_files = p1->next;
+
+			kfree(p1);
+			break;
+		}
+		p2 = p1;
+		p1 = p1->next;
+	}
+	spin_unlock_irqrestore(&i2o_config_lock, flags);
+	unlock_kernel();
+
+	return 0;
+}
+
+static int cfg_fasync(int fd, struct file *fp, int on)
+{
+	u32 id = (u32)fp->private_data;
+	struct i2o_cfg_info *p;
+
+	for(p = open_files; p; p = p->next)
+		if(p->q_id == id)
+			break;
+
+	if(!p)
+		return -EBADF;
+
+	return fasync_helper(fd, fp, on, &p->fasync);
+}
+
+static struct file_operations config_fops =
+{
+	owner:		THIS_MODULE,
+	llseek:		no_llseek,
+	read:		cfg_read,
+	write:		cfg_write,
+	ioctl:		cfg_ioctl,
+	open:		cfg_open,
+	release:	cfg_release,
+	fasync:		cfg_fasync,
+};
+
+static struct miscdevice i2o_miscdev = {
+	I2O_MINOR,
+	"i2octl",
+	&config_fops
+};	
+
+#ifdef MODULE
+int init_module(void)
+#else
+int __init i2o_config_init(void)
+#endif
+{
+	printk(KERN_INFO "I2O configuration manager v 0.04.\n");
+	printk(KERN_INFO "  (C) Copyright 1999 Red Hat Software\n");
+	
+	if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL)
+	{
+		printk(KERN_ERR "i2o_config: no memory for page buffer.\n");
+		return -ENOBUFS;
+	}
+	if(misc_register(&i2o_miscdev)==-1)
+	{
+		printk(KERN_ERR "i2o_config: can't register device.\n");
+		kfree(page_buf);
+		return -EBUSY;
+	}
+	/*
+	 *	Install our handler
+	 */
+	if(i2o_install_handler(&cfg_handler)<0)
+	{
+		kfree(page_buf);
+		printk(KERN_ERR "i2o_config: handler register failed.\n");
+		misc_deregister(&i2o_miscdev);
+		return -EBUSY;
+	}
+	/*
+	 *	The low 16bits of the transaction context must match this
+	 *	for everything we post. Otherwise someone else gets our mail
+	 */
+	i2o_cfg_context = cfg_handler.context;
+	return 0;
+}
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+	misc_deregister(&i2o_miscdev);
+	
+	if(page_buf)
+		kfree(page_buf);
+	if(i2o_cfg_context != -1)
+		i2o_remove_handler(&cfg_handler);
+}
+ 
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR("Red Hat Software");
+MODULE_DESCRIPTION("I2O Configuration");
+
+#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/i2o_core.c linux/drivers/message/i2o/i2o_core.c
--- v2.4.12/linux/drivers/message/i2o/i2o_core.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/i2o_core.c	Fri Oct 19 08:32:28 2001
@@ -0,0 +1,3564 @@
+/*
+ * Core I2O structure management 
+ * 
+ * (C) Copyright 1999   Red Hat Software 
+ *
+ * Written by Alan Cox, Building Number Three Ltd 
+ * 
+ * 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.  
+ * 
+ * A lot of the I2O message side code from this is taken from the 
+ * Red Creek RCPCI45 adapter driver by Red Creek Communications 
+ * 
+ * Fixes by: 
+ *		Philipp Rumpf 
+ *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> 
+ *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> 
+ *		Deepak Saxena <deepak@plexity.net> 
+ *		Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include <linux/i2o.h>
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+
+#include <linux/bitops.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <asm/semaphore.h>
+#include <linux/completion.h>
+
+#include <asm/io.h>
+#include <linux/reboot.h>
+
+#include "i2o_lan.h"
+
+//#define DRIVERDEBUG
+
+#ifdef DRIVERDEBUG
+#define dprintk(s, args...) printk(s, ## args)
+#else
+#define dprintk(s, args...)
+#endif
+
+/* OSM table */
+static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES];
+
+/* Controller list */
+static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];
+struct i2o_controller *i2o_controller_chain;
+int i2o_num_controllers;
+
+/* Initiator Context for Core message */
+static int core_context;
+
+/* Initialization && shutdown functions */
+static void i2o_sys_init(void);
+static void i2o_sys_shutdown(void);
+static int i2o_reset_controller(struct i2o_controller *);
+static int i2o_reboot_event(struct notifier_block *, unsigned long , void *);
+static int i2o_online_controller(struct i2o_controller *);
+static int i2o_init_outbound_q(struct i2o_controller *);
+static int i2o_post_outbound_messages(struct i2o_controller *);
+
+/* Reply handler */
+static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *,
+			   struct i2o_message *);
+
+/* Various helper functions */
+static int i2o_lct_get(struct i2o_controller *);
+static int i2o_lct_notify(struct i2o_controller *);
+static int i2o_hrt_get(struct i2o_controller *);
+
+static int i2o_build_sys_table(void);
+static int i2o_systab_send(struct i2o_controller *c);
+
+/* I2O core event handler */
+static int i2o_core_evt(void *);
+static int evt_pid;
+static int evt_running;
+
+/* Dynamic LCT update handler */
+static int i2o_dyn_lct(void *);
+
+void i2o_report_controller_unit(struct i2o_controller *, struct i2o_device *);
+
+/*
+ * I2O System Table.  Contains information about
+ * all the IOPs in the system.  Used to inform IOPs
+ * about each other's existence.
+ *
+ * sys_tbl_ver is the CurrentChangeIndicator that is
+ * used by IOPs to track changes.
+ */
+static struct i2o_sys_tbl *sys_tbl;
+static int sys_tbl_ind;
+static int sys_tbl_len;
+
+/*
+ * This spin lock is used to keep a device from being
+ * added and deleted concurrently across CPUs or interrupts.
+ * This can occur when a user creates a device and immediatelly
+ * deletes it before the new_dev_notify() handler is called.
+ */
+static spinlock_t i2o_dev_lock = SPIN_LOCK_UNLOCKED;
+
+#ifdef MODULE
+/* 
+ * Function table to send to bus specific layers
+ * See <include/linux/i2o.h> for explanation of this
+ */
+static struct i2o_core_func_table i2o_core_functions =
+{
+	i2o_install_controller,
+	i2o_activate_controller,
+	i2o_find_controller,
+	i2o_unlock_controller,
+	i2o_run_queue,
+	i2o_delete_controller
+};
+
+#ifdef CONFIG_I2O_PCI_MODULE
+extern int i2o_pci_core_attach(struct i2o_core_func_table *);
+extern void i2o_pci_core_detach(void);
+#endif /* CONFIG_I2O_PCI_MODULE */
+
+#endif /* MODULE */
+
+/*
+ * Structures and definitions for synchronous message posting.
+ * See i2o_post_wait() for description.
+ */ 
+struct i2o_post_wait_data
+{
+	int *status;		/* Pointer to status block on caller stack */
+	int *complete;		/* Pointer to completion flag on caller stack */
+	u32 id;			/* Unique identifier */
+	wait_queue_head_t *wq;	/* Wake up for caller (NULL for dead) */
+	struct i2o_post_wait_data *next;	/* Chain */
+	void *mem[2];		/* Memory blocks to recover on failure path */
+};
+static struct i2o_post_wait_data *post_wait_queue;
+static u32 post_wait_id;	// Unique ID for each post_wait
+static spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED;
+static void i2o_post_wait_complete(u32, int);
+
+/* OSM descriptor handler */ 
+static struct i2o_handler i2o_core_handler =
+{
+	(void *)i2o_core_reply,
+	NULL,
+	NULL,
+	NULL,
+	"I2O core layer",
+	0,
+	I2O_CLASS_EXECUTIVE
+};
+
+/*
+ * Used when queueing a reply to be handled later
+ */
+ 
+struct reply_info
+{
+	struct i2o_controller *iop;
+	u32 msg[MSG_FRAME_SIZE];
+};
+static struct reply_info evt_reply;
+static struct reply_info events[I2O_EVT_Q_LEN];
+static int evt_in;
+static int evt_out;
+static int evt_q_len;
+#define MODINC(x,y) ((x) = ((x) + 1) % (y))
+
+/*
+ * I2O configuration spinlock. This isnt a big deal for contention
+ * so we have one only
+ */
+
+static DECLARE_MUTEX(i2o_configuration_lock);
+
+/* 
+ * Event spinlock.  Used to keep event queue sane and from
+ * handling multiple events simultaneously.
+ */
+static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Semaphore used to synchronize event handling thread with 
+ * interrupt handler.
+ */
+ 
+static DECLARE_MUTEX(evt_sem);
+static DECLARE_COMPLETION(evt_dead);
+DECLARE_WAIT_QUEUE_HEAD(evt_wait);
+
+static struct notifier_block i2o_reboot_notifier =
+{
+        i2o_reboot_event,
+        NULL,
+        0
+};
+
+/*
+ *	Config options
+ */
+
+static int verbose;
+MODULE_PARM(verbose, "i");
+
+/*
+ * I2O Core reply handler
+ */
+static void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,
+		    struct i2o_message *m)
+{
+	u32 *msg=(u32 *)m;
+	u32 status;
+	u32 context = msg[2];
+
+	if (msg[0] & MSG_FAIL) // Fail bit is set
+	{
+		u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]);
+
+		i2o_report_status(KERN_INFO, "i2o_core", msg);
+		i2o_dump_message(preserved_msg);
+
+		/* If the failed request needs special treatment,
+		 * it should be done here. */
+
+                /* Release the preserved msg by resubmitting it as a NOP */
+
+		preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+		preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
+		preserved_msg[2] = 0;
+		i2o_post_message(c, msg[7]);
+
+		/* If reply to i2o_post_wait failed, return causes a timeout */
+
+		return;
+	}       
+
+#ifdef DRIVERDEBUG
+	i2o_report_status(KERN_INFO, "i2o_core", msg);
+#endif
+
+	if(msg[2]&0x80000000)	// Post wait message
+	{
+		if (msg[4] >> 24)
+			status = (msg[4] & 0xFFFF);
+		else
+			status = I2O_POST_WAIT_OK;
+	
+		i2o_post_wait_complete(context, status);
+		return;
+	}
+
+	if(m->function == I2O_CMD_UTIL_EVT_REGISTER)
+	{
+		memcpy(events[evt_in].msg, msg, (msg[0]>>16)<<2);
+		events[evt_in].iop = c;
+
+		spin_lock(&i2o_evt_lock);
+		MODINC(evt_in, I2O_EVT_Q_LEN);
+		if(evt_q_len == I2O_EVT_Q_LEN)
+			MODINC(evt_out, I2O_EVT_Q_LEN);
+		else
+			evt_q_len++;
+		spin_unlock(&i2o_evt_lock);
+
+		up(&evt_sem);
+		wake_up_interruptible(&evt_wait);
+		return;
+	}
+
+	if(m->function == I2O_CMD_LCT_NOTIFY)
+	{
+		up(&c->lct_sem);
+		return;
+	}
+
+	/*
+	 * If this happens, we want to dump the message to the syslog so
+	 * it can be sent back to the card manufacturer by the end user
+	 * to aid in debugging.
+	 * 
+	 */
+	printk(KERN_WARNING "%s: Unsolicited message reply sent to core!"
+			"Message dumped to syslog\n", 
+			c->name);
+	i2o_dump_message(msg);
+
+	return;
+}
+
+/**
+ *	i2o_install_handler - install a message handler
+ *	@h: Handler structure
+ *
+ *	Install an I2O handler - these handle the asynchronous messaging
+ *	from the card once it has initialised. If the table of handlers is
+ *	full then -ENOSPC is returned. On a success 0 is returned and the
+ *	context field is set by the function. The structure is part of the
+ *	system from this time onwards. It must not be freed until it has
+ *	been uninstalled
+ */
+ 
+int i2o_install_handler(struct i2o_handler *h)
+{
+	int i;
+	down(&i2o_configuration_lock);
+	for(i=0;i<MAX_I2O_MODULES;i++)
+	{
+		if(i2o_handlers[i]==NULL)
+		{
+			h->context = i;
+			i2o_handlers[i]=h;
+			up(&i2o_configuration_lock);
+			return 0;
+		}
+	}
+	up(&i2o_configuration_lock);
+	return -ENOSPC;
+}
+
+/**
+ *	i2o_remove_handler - remove an i2o message handler
+ *	@h: handler
+ *
+ *	Remove a message handler previously installed with i2o_install_handler.
+ *	After this function returns the handler object can be freed or re-used
+ */
+ 
+int i2o_remove_handler(struct i2o_handler *h)
+{
+	i2o_handlers[h->context]=NULL;
+	return 0;
+}
+	
+
+/*
+ *	Each I2O controller has a chain of devices on it.
+ * Each device has a pointer to it's LCT entry to be used
+ * for fun purposes.
+ */
+
+/**
+ *	i2o_install_device	-	attach a device to a controller
+ *	@c: controller
+ *	@d: device
+ * 	
+ *	Add a new device to an i2o controller. This can be called from
+ *	non interrupt contexts only. It adds the device and marks it as
+ *	unclaimed. The device memory becomes part of the kernel and must
+ *	be uninstalled before being freed or reused. Zero is returned
+ *	on success.
+ */
+ 
+int i2o_install_device(struct i2o_controller *c, struct i2o_device *d)
+{
+	int i;
+
+	down(&i2o_configuration_lock);
+	d->controller=c;
+	d->owner=NULL;
+	d->next=c->devices;
+	d->prev=NULL;
+	if (c->devices != NULL)
+		c->devices->prev=d;
+	c->devices=d;
+	*d->dev_name = 0;
+
+	for(i = 0; i < I2O_MAX_MANAGERS; i++)
+		d->managers[i] = NULL;
+
+	up(&i2o_configuration_lock);
+	return 0;
+}
+
+/* we need this version to call out of i2o_delete_controller */
+
+int __i2o_delete_device(struct i2o_device *d)
+{
+	struct i2o_device **p;
+	int i;
+
+	p=&(d->controller->devices);
+
+	/*
+	 *	Hey we have a driver!
+	 * Check to see if the driver wants us to notify it of 
+	 * device deletion. If it doesn't we assume that it
+	 * is unsafe to delete a device with an owner and 
+	 * fail.
+	 */
+	if(d->owner)
+	{
+		if(d->owner->dev_del_notify)
+		{
+			dprintk(KERN_INFO "Device has owner, notifying\n");
+			d->owner->dev_del_notify(d->controller, d);
+			if(d->owner)
+			{
+				printk(KERN_WARNING 
+					"Driver \"%s\" did not release device!\n", d->owner->name);
+				return -EBUSY;
+			}
+		}
+		else
+			return -EBUSY;
+	}
+
+	/*
+	 * Tell any other users who are talking to this device
+	 * that it's going away.  We assume that everything works.
+	 */
+	for(i=0; i < I2O_MAX_MANAGERS; i++)
+	{
+		if(d->managers[i] && d->managers[i]->dev_del_notify)
+			d->managers[i]->dev_del_notify(d->controller, d);
+	}
+	 			
+	while(*p!=NULL)
+	{
+		if(*p==d)
+		{
+			/*
+			 *	Destroy
+			 */
+			*p=d->next;
+			kfree(d);
+			return 0;
+		}
+		p=&((*p)->next);
+	}
+	printk(KERN_ERR "i2o_delete_device: passed invalid device.\n");
+	return -EINVAL;
+}
+
+/**
+ *	i2o_delete_device	-	remove an i2o device
+ *	@d: device to remove
+ *
+ *	This function unhooks a device from a controller. The device
+ *	will not be unhooked if it has an owner who does not wish to free
+ *	it, or if the owner lacks a dev_del_notify function. In that case
+ *	-EBUSY is returned. On success 0 is returned. Other errors cause
+ *	negative errno values to be returned
+ */
+ 
+int i2o_delete_device(struct i2o_device *d)
+{
+	int ret;
+
+	down(&i2o_configuration_lock);
+
+	/*
+	 *	Seek, locate
+	 */
+
+	ret = __i2o_delete_device(d);
+
+	up(&i2o_configuration_lock);
+
+	return ret;
+}
+
+/**
+ *	i2o_install_controller	-	attach a controller
+ *	@c: controller
+ * 	
+ *	Add a new controller to the i2o layer. This can be called from
+ *	non interrupt contexts only. It adds the controller and marks it as
+ *	unused with no devices. If the tables are full or memory allocations
+ *	fail then a negative errno code is returned. On success zero is
+ *	returned and the controller is bound to the system. The structure
+ *	must not be freed or reused until being uninstalled.
+ */
+ 
+int i2o_install_controller(struct i2o_controller *c)
+{
+	int i;
+	down(&i2o_configuration_lock);
+	for(i=0;i<MAX_I2O_CONTROLLERS;i++)
+	{
+		if(i2o_controllers[i]==NULL)
+		{
+			c->dlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL);
+			if(c->dlct==NULL)
+			{
+				up(&i2o_configuration_lock);
+				return -ENOMEM;
+			}
+			i2o_controllers[i]=c;
+			c->devices = NULL;
+			c->next=i2o_controller_chain;
+			i2o_controller_chain=c;
+			c->unit = i;
+			c->page_frame = NULL;
+			c->hrt = NULL;
+			c->lct = NULL;
+			c->status_block = NULL;
+			sprintf(c->name, "i2o/iop%d", i);
+			i2o_num_controllers++;
+			init_MUTEX_LOCKED(&c->lct_sem);
+			up(&i2o_configuration_lock);
+			return 0;
+		}
+	}
+	printk(KERN_ERR "No free i2o controller slots.\n");
+	up(&i2o_configuration_lock);
+	return -EBUSY;
+}
+
+/**
+ *	i2o_delete_controller	- delete a controller
+ *	@c: controller
+ *	
+ *	Remove an i2o controller from the system. If the controller or its
+ *	devices are busy then -EBUSY is returned. On a failure a negative
+ *	errno code is returned. On success zero is returned.
+ */
+  
+int i2o_delete_controller(struct i2o_controller *c)
+{
+	struct i2o_controller **p;
+	int users;
+	char name[16];
+	int stat;
+
+	dprintk(KERN_INFO "Deleting controller %s\n", c->name);
+
+	/*
+	 * Clear event registration as this can cause weird behavior
+	 */
+	if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL)
+		i2o_event_register(c, core_context, 0, 0, 0);
+
+	down(&i2o_configuration_lock);
+	if((users=atomic_read(&c->users)))
+	{
+		dprintk(KERN_INFO "I2O: %d users for controller %s\n", users,
+			c->name);
+		up(&i2o_configuration_lock);
+		return -EBUSY;
+	}
+	while(c->devices)
+	{
+		if(__i2o_delete_device(c->devices)<0)
+		{
+			/* Shouldnt happen */
+			c->bus_disable(c);
+			up(&i2o_configuration_lock);
+			return -EBUSY;
+		}
+	}
+
+	/*
+	 * If this is shutdown time, the thread's already been killed
+	 */
+	if(c->lct_running) {
+		stat = kill_proc(c->lct_pid, SIGTERM, 1);
+		if(!stat) {
+			int count = 10 * 100;
+			while(c->lct_running && --count) {
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(1);
+			}
+		
+			if(!count)
+				printk(KERN_ERR 
+					"%s: LCT thread still running!\n", 
+					c->name);
+		}
+	}
+
+	p=&i2o_controller_chain;
+
+	while(*p)
+	{
+		if(*p==c)
+		{
+ 			/* Ask the IOP to switch to RESET state */
+			i2o_reset_controller(c);
+
+			/* Release IRQ */
+			c->destructor(c);
+
+			*p=c->next;
+			up(&i2o_configuration_lock);
+
+			if(c->page_frame)
+				kfree(c->page_frame);
+			if(c->hrt)
+				kfree(c->hrt);
+			if(c->lct)
+				kfree(c->lct);
+			if(c->status_block)
+				kfree(c->status_block);
+			if(c->dlct)
+				kfree(c->dlct);
+
+			i2o_controllers[c->unit]=NULL;
+			memcpy(name, c->name, strlen(c->name)+1);
+			kfree(c);
+			dprintk(KERN_INFO "%s: Deleted from controller chain.\n", name);
+			
+			i2o_num_controllers--;
+			return 0;
+		}
+		p=&((*p)->next);
+	}
+	up(&i2o_configuration_lock);
+	printk(KERN_ERR "i2o_delete_controller: bad pointer!\n");
+	return -ENOENT;
+}
+
+/**
+ *	i2o_unlock_controller	-	unlock a controller
+ *	@c: controller to unlock
+ *
+ *	Take a lock on an i2o controller. This prevents it being deleted.
+ *	i2o controllers are not refcounted so a deletion of an in use device
+ *	will fail, not take affect on the last dereference.
+ */
+ 
+void i2o_unlock_controller(struct i2o_controller *c)
+{
+	atomic_dec(&c->users);
+}
+
+/**
+ *	i2o_find_controller - return a locked controller
+ *	@n: controller number
+ *
+ *	Returns a pointer to the controller object. The controller is locked
+ *	on return. NULL is returned if the controller is not found.
+ */
+ 
+struct i2o_controller *i2o_find_controller(int n)
+{
+	struct i2o_controller *c;
+	
+	if(n<0 || n>=MAX_I2O_CONTROLLERS)
+		return NULL;
+	
+	down(&i2o_configuration_lock);
+	c=i2o_controllers[n];
+	if(c!=NULL)
+		atomic_inc(&c->users);
+	up(&i2o_configuration_lock);
+	return c;
+}
+
+/**
+ *	i2o_issue_claim	- claim or release a device
+ *	@cmd: command
+ *	@c: controller to claim for
+ *	@tid: i2o task id
+ *	@type: type of claim
+ *
+ *	Issue I2O UTIL_CLAIM and UTIL_RELEASE messages. The message to be sent
+ *	is set by cmd. The tid is the task id of the object to claim and the
+ *	type is the claim type (see the i2o standard)
+ *
+ *	Zero is returned on success.
+ */
+ 
+static int i2o_issue_claim(u32 cmd, struct i2o_controller *c, int tid, u32 type)
+{
+	u32 msg[5];
+
+	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+	msg[1] = cmd << 24 | HOST_TID<<12 | tid;
+	msg[3] = 0;
+	msg[4] = type;
+	
+	return i2o_post_wait(c, msg, sizeof(msg), 60);
+}
+
+/*
+ * 	i2o_claim_device - claim a device for use by an OSM
+ *	@d: device to claim
+ *	@h: handler for this device
+ *
+ *	Do the leg work to assign a device to a given OSM on Linux. The
+ *	kernel updates the internal handler data for the device and then
+ *	performs an I2O claim for the device, attempting to claim the
+ *	device as primary. If the attempt fails a negative errno code
+ *	is returned. On success zero is returned.
+ */
+ 
+int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h)
+{
+	down(&i2o_configuration_lock);
+	if (d->owner) {
+		printk(KERN_INFO "Device claim called, but dev already owned by %s!",
+		       h->name);
+		up(&i2o_configuration_lock);
+		return -EBUSY;
+	}
+	d->owner=h;
+
+	if(i2o_issue_claim(I2O_CMD_UTIL_CLAIM ,d->controller,d->lct_data.tid, 
+			   I2O_CLAIM_PRIMARY))
+	{
+		d->owner = NULL;
+		return -EBUSY;
+	}
+	up(&i2o_configuration_lock);
+	return 0;
+}
+
+/**
+ *	i2o_release_device - release a device that the OSM is using
+ *	@d: device to claim
+ *	@h: handler for this device
+ *
+ *	Drop a claim by an OSM on a given I2O device. The handler is cleared
+ *	and 0 is returned on success.
+ *
+ *	AC - some devices seem to want to refuse an unclaim until they have
+ *	finished internal processing. It makes sense since you don't want a
+ *	new device to go reconfiguring the entire system until you are done.
+ *	Thus we are prepared to wait briefly.
+ */
+
+int i2o_release_device(struct i2o_device *d, struct i2o_handler *h)
+{
+	int err = 0;
+	int tries;
+
+	down(&i2o_configuration_lock);
+	if (d->owner != h) {
+		printk(KERN_INFO "Claim release called, but not owned by %s!\n",
+		       h->name);
+		up(&i2o_configuration_lock);
+		return -ENOENT;
+	}	
+
+	for(tries=0;tries<10;tries++)
+	{
+		d->owner = NULL;
+
+		/*
+		 *	If the controller takes a nonblocking approach to
+		 *	releases we have to sleep/poll for a few times.
+		 */
+		 
+		if((err=i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, I2O_CLAIM_PRIMARY)) )
+		{
+			err = -ENXIO;
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(HZ);
+		}
+		else
+		{
+			err=0;
+			break;
+		}
+	}
+	up(&i2o_configuration_lock);
+	return err;
+}
+
+/**
+ * 	i2o_device_notify_on	-	Enable deletion notifiers
+ *	@d: device for notification
+ *	@h: handler to install
+ *
+ *	Called by OSMs to let the core know that they want to be
+ *	notified if the given device is deleted from the system.
+ */
+
+int i2o_device_notify_on(struct i2o_device *d, struct i2o_handler *h)
+{
+	int i;
+
+	if(d->num_managers == I2O_MAX_MANAGERS)
+		return -ENOSPC;
+
+	for(i = 0; i < I2O_MAX_MANAGERS; i++)
+	{
+		if(!d->managers[i])
+		{
+			d->managers[i] = h;
+			break;
+		}
+	}
+	
+	d->num_managers++;
+	
+	return 0;
+}
+
+/**
+ * 	i2o_device_notify_off	-	Remove deletion notifiers
+ *	@d: device for notification
+ *	@h: handler to remove
+ *
+ * Called by OSMs to let the core know that they no longer
+ * are interested in the fate of the given device.
+ */
+int i2o_device_notify_off(struct i2o_device *d, struct i2o_handler *h)
+{
+	int i;
+
+	for(i=0; i < I2O_MAX_MANAGERS; i++)
+	{
+		if(d->managers[i] == h)
+		{
+			d->managers[i] = NULL;
+			d->num_managers--;
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
+/**
+ *	i2o_event_register	-	register interest in an event
+ * 	@c: Controller to register interest with
+ *	@tid: I2O task id
+ *	@init_context: initiator context to use with this notifier
+ *	@tr_context: transaction context to use with this notifier
+ *	@evt_mask: mask of events
+ *
+ *	Create and posts an event registration message to the task. No reply
+ *	is waited for, or expected. Errors in posting will be reported.
+ */
+ 
+int i2o_event_register(struct i2o_controller *c, u32 tid, 
+		u32 init_context, u32 tr_context, u32 evt_mask)
+{
+	u32 msg[5];	// Not performance critical, so we just 
+			// i2o_post_this it instead of building it
+			// in IOP memory
+	
+	msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | tid;
+	msg[2] = init_context;
+	msg[3] = tr_context;
+	msg[4] = evt_mask;
+
+	return i2o_post_this(c, msg, sizeof(msg));
+}
+
+/*
+ * 	i2o_event_ack	-	acknowledge an event
+ *	@c: controller 
+ *	@msg: pointer to the UTIL_EVENT_REGISTER reply we received
+ *
+ *	We just take a pointer to the original UTIL_EVENT_REGISTER reply
+ *	message and change the function code since that's what spec
+ *	describes an EventAck message looking like.
+ */
+ 
+int i2o_event_ack(struct i2o_controller *c, u32 *msg)
+{
+	struct i2o_message *m = (struct i2o_message *)msg;
+
+	m->function = I2O_CMD_UTIL_EVT_ACK;
+
+	return i2o_post_wait(c, msg, m->size * 4, 2);
+}
+
+/*
+ * Core event handler.  Runs as a separate thread and is woken
+ * up whenever there is an Executive class event.
+ */
+static int i2o_core_evt(void *reply_data)
+{
+	struct reply_info *reply = (struct reply_info *) reply_data;
+	u32 *msg = reply->msg;
+	struct i2o_controller *c = NULL;
+	unsigned long flags;
+
+	lock_kernel();
+	daemonize();
+	unlock_kernel();
+
+	strcpy(current->comm, "i2oevtd");
+	evt_running = 1;
+
+	while(1)
+	{
+		if(down_interruptible(&evt_sem))
+		{
+			dprintk(KERN_INFO "I2O event thread dead\n");
+			printk("exiting...");
+			evt_running = 0;
+			complete_and_exit(&evt_dead, 0);
+		}
+
+		/* 
+		 * Copy the data out of the queue so that we don't have to lock
+		 * around the whole function and just around the qlen update
+		 */
+		spin_lock_irqsave(&i2o_evt_lock, flags);
+		memcpy(reply, &events[evt_out], sizeof(struct reply_info));
+		MODINC(evt_out, I2O_EVT_Q_LEN);
+		evt_q_len--;
+		spin_unlock_irqrestore(&i2o_evt_lock, flags);
+	
+		c = reply->iop;
+	 	dprintk(KERN_INFO "I2O IRTOS EVENT: iop%d, event %#10x\n", c->unit, msg[4]);
+
+		/* 
+		 * We do not attempt to delete/quiesce/etc. the controller if
+		 * some sort of error indidication occurs.  We may want to do
+		 * so in the future, but for now we just let the user deal with 
+		 * it.  One reason for this is that what to do with an error
+		 * or when to send what ærror is not really agreed on, so
+		 * we get errors that may not be fatal but just look like they
+		 * are...so let the user deal with it.
+		 */
+		switch(msg[4])
+		{
+			case I2O_EVT_IND_EXEC_RESOURCE_LIMITS:
+				printk(KERN_ERR "%s: Out of resources\n", c->name);
+				break;
+
+			case I2O_EVT_IND_EXEC_POWER_FAIL:
+				printk(KERN_ERR "%s: Power failure\n", c->name);
+				break;
+
+			case I2O_EVT_IND_EXEC_HW_FAIL:
+			{
+				char *fail[] = 
+					{ 
+						"Unknown Error",
+						"Power Lost",
+						"Code Violation",
+						"Parity Error",
+						"Code Execution Exception",
+						"Watchdog Timer Expired" 
+					};
+
+				if(msg[5] <= 6)
+					printk(KERN_ERR "%s: Hardware Failure: %s\n", 
+						c->name, fail[msg[5]]);
+				else
+					printk(KERN_ERR "%s: Unknown Hardware Failure\n", c->name);
+
+				break;
+			}
+
+			/*
+		 	 * New device created
+		 	 * - Create a new i2o_device entry
+		 	 * - Inform all interested drivers about this device's existence
+		 	 */
+			case I2O_EVT_IND_EXEC_NEW_LCT_ENTRY:
+			{
+				struct i2o_device *d = (struct i2o_device *)
+					kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
+				int i;
+
+				if (d == NULL) {
+					printk(KERN_EMERG "i2oevtd: out of memory\n");
+					break;
+				}
+				memcpy(&d->lct_data, &msg[5], sizeof(i2o_lct_entry));
+	
+				d->next = NULL;
+				d->controller = c;
+				d->flags = 0;
+	
+				i2o_report_controller_unit(c, d);
+				i2o_install_device(c,d);
+	
+				for(i = 0; i < MAX_I2O_MODULES; i++)
+				{
+					if(i2o_handlers[i] && 
+						i2o_handlers[i]->new_dev_notify &&
+						(i2o_handlers[i]->class&d->lct_data.class_id))
+						{
+						spin_lock(&i2o_dev_lock);
+						i2o_handlers[i]->new_dev_notify(c,d);
+						spin_unlock(&i2o_dev_lock);
+						}
+				}
+			
+				break;
+			}
+	
+			/*
+ 		 	 * LCT entry for a device has been modified, so update it
+		 	 * internally.
+		 	 */
+			case I2O_EVT_IND_EXEC_MODIFIED_LCT:
+			{
+				struct i2o_device *d;
+				i2o_lct_entry *new_lct = (i2o_lct_entry *)&msg[5];
+
+				for(d = c->devices; d; d = d->next)
+				{
+					if(d->lct_data.tid == new_lct->tid)
+					{
+						memcpy(&d->lct_data, new_lct, sizeof(i2o_lct_entry));
+						break;
+					}
+				}
+				break;
+			}
+	
+			case I2O_EVT_IND_CONFIGURATION_FLAG:
+				printk(KERN_WARNING "%s requires user configuration\n", c->name);
+				break;
+	
+			case I2O_EVT_IND_GENERAL_WARNING:
+				printk(KERN_WARNING "%s: Warning notification received!"
+					"Check configuration for errors!\n", c->name);
+				break;
+				
+			case I2O_EVT_IND_EVT_MASK_MODIFIED:
+				/* Well I guess that was us hey .. */
+				break;
+					
+			default:
+				printk(KERN_WARNING "%s: No handler for event (0x%08x)\n", c->name, msg[4]);
+				break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Dynamic LCT update.  This compares the LCT with the currently
+ * installed devices to check for device deletions..this needed b/c there
+ * is no DELETED_LCT_ENTRY EventIndicator for the Executive class so
+ * we can't just have the event handler do this...annoying
+ *
+ * This is a hole in the spec that will hopefully be fixed someday.
+ */
+static int i2o_dyn_lct(void *foo)
+{
+	struct i2o_controller *c = (struct i2o_controller *)foo;
+	struct i2o_device *d = NULL;
+	struct i2o_device *d1 = NULL;
+	int i = 0;
+	int found = 0;
+	int entries;
+	void *tmp;
+	char name[16];
+
+	lock_kernel();
+	daemonize();
+	unlock_kernel();
+
+	sprintf(name, "iop%d_lctd", c->unit);
+	strcpy(current->comm, name);	
+	
+	c->lct_running = 1;
+
+	while(1)
+	{
+		down_interruptible(&c->lct_sem);
+		if(signal_pending(current))
+		{
+			dprintk(KERN_ERR "%s: LCT thread dead\n", c->name);
+			c->lct_running = 0;
+			return 0;
+		}
+
+		entries = c->dlct->table_size;
+		entries -= 3;
+		entries /= 9;
+
+		dprintk(KERN_INFO "%s: Dynamic LCT Update\n",c->name);
+		dprintk(KERN_INFO "%s: Dynamic LCT contains %d entries\n", c->name, entries);
+
+		if(!entries)
+		{
+			printk(KERN_INFO "%s: Empty LCT???\n", c->name);
+			continue;
+		}
+
+		/*
+		 * Loop through all the devices on the IOP looking for their
+		 * LCT data in the LCT.  We assume that TIDs are not repeated.
+		 * as that is the only way to really tell.  It's been confirmed
+		 * by the IRTOS vendor(s?) that TIDs are not reused until they 
+		 * wrap arround(4096), and I doubt a system will up long enough
+		 * to create/delete that many devices.
+		 */
+		for(d = c->devices; d; )
+		{
+			found = 0;
+			d1 = d->next;
+			
+			for(i = 0; i < entries; i++) 
+			{ 
+				if(d->lct_data.tid == c->dlct->lct_entry[i].tid) 
+				{ 
+					found = 1; 
+					break; 
+				} 
+			} 
+			if(!found) 
+			{
+				dprintk(KERN_INFO "i2o_core: Deleted device!\n"); 
+				spin_lock(&i2o_dev_lock);
+				i2o_delete_device(d); 
+				spin_unlock(&i2o_dev_lock);
+			} 
+			d = d1; 
+		}
+
+		/* 
+		 * Tell LCT to renotify us next time there is a change
+	 	 */
+		i2o_lct_notify(c);
+
+		/*
+		 * Copy new LCT into public LCT
+		 *
+		 * Possible race if someone is reading LCT while  we are copying 
+		 * over it. If this happens, we'll fix it then. but I doubt that
+		 * the LCT will get updated often enough or will get read by
+		 * a user often enough to worry.
+		 */
+		if(c->lct->table_size < c->dlct->table_size)
+		{
+			tmp = c->lct;
+			c->lct = kmalloc(c->dlct->table_size<<2, GFP_KERNEL);
+			if(!c->lct)
+			{
+				printk(KERN_ERR "%s: No memory for LCT!\n", c->name);
+				c->lct = tmp;
+				continue;
+			}
+			kfree(tmp);
+		}
+		memcpy(c->lct, c->dlct, c->dlct->table_size<<2);
+	}
+
+	return 0;
+}
+
+/**
+ *	i2o_run_queue	-	process pending events on a controller
+ *	@c: controller to process
+ *
+ *	This is called by the bus specific driver layer when an interrupt
+ *	or poll of this card interface is desired.
+ */
+ 
+void i2o_run_queue(struct i2o_controller *c)
+{
+	struct i2o_message *m;
+	u32 mv;
+	u32 *msg;
+
+	/*
+	 * Old 960 steppings had a bug in the I2O unit that caused
+	 * the queue to appear empty when it wasn't.
+	 */
+	if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF)
+		mv=I2O_REPLY_READ32(c);
+
+	while(mv!=0xFFFFFFFF)
+	{
+		struct i2o_handler *i;
+		m=(struct i2o_message *)bus_to_virt(mv);
+		msg=(u32*)m;
+
+		i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)];
+		if(i && i->reply)
+			i->reply(i,c,m);
+		else
+		{
+			printk(KERN_WARNING "I2O: Spurious reply to handler %d\n", 
+				m->initiator_context&(MAX_I2O_MODULES-1));
+		}	
+	 	i2o_flush_reply(c,mv);
+		mb();
+
+		/* That 960 bug again... */	
+		if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF)
+			mv=I2O_REPLY_READ32(c);
+	}		
+}
+
+
+/**
+ *	i2o_get_class_name - 	do i2o class name lookup
+ *	@class: class number
+ *
+ *	Return a descriptive string for an i2o class
+ */
+ 
+const char *i2o_get_class_name(int class)
+{
+	int idx = 16;
+	static char *i2o_class_name[] = {
+		"Executive",
+		"Device Driver Module",
+		"Block Device",
+		"Tape Device",
+		"LAN Interface",
+		"WAN Interface",
+		"Fibre Channel Port",
+		"Fibre Channel Device",
+		"SCSI Device",
+		"ATE Port",
+		"ATE Device",
+		"Floppy Controller",
+		"Floppy Device",
+		"Secondary Bus Port",
+		"Peer Transport Agent",
+		"Peer Transport",
+		"Unknown"
+	};
+	
+	switch(class&0xFFF)
+	{
+		case I2O_CLASS_EXECUTIVE:
+			idx = 0; break;
+		case I2O_CLASS_DDM:
+			idx = 1; break;
+		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+			idx = 2; break;
+		case I2O_CLASS_SEQUENTIAL_STORAGE:
+			idx = 3; break;
+		case I2O_CLASS_LAN:
+			idx = 4; break;
+		case I2O_CLASS_WAN:
+			idx = 5; break;
+		case I2O_CLASS_FIBRE_CHANNEL_PORT:
+			idx = 6; break;
+		case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL:
+			idx = 7; break;
+		case I2O_CLASS_SCSI_PERIPHERAL:
+			idx = 8; break;
+		case I2O_CLASS_ATE_PORT:
+			idx = 9; break;
+		case I2O_CLASS_ATE_PERIPHERAL:
+			idx = 10; break;
+		case I2O_CLASS_FLOPPY_CONTROLLER:
+			idx = 11; break;
+		case I2O_CLASS_FLOPPY_DEVICE:
+			idx = 12; break;
+		case I2O_CLASS_BUS_ADAPTER_PORT:
+			idx = 13; break;
+		case I2O_CLASS_PEER_TRANSPORT_AGENT:
+			idx = 14; break;
+		case I2O_CLASS_PEER_TRANSPORT:
+			idx = 15; break;
+	}
+
+	return i2o_class_name[idx];
+}
+
+
+/**
+ *	i2o_wait_message	-	obtain an i2o message from the IOP
+ *	@c: controller
+ *	@why: explanation 
+ *
+ *	This function waits up to 5 seconds for a message slot to be
+ *	available. If no message is available it prints an error message
+ *	that is expected to be what the message will be used for (eg
+ *	"get_status"). 0xFFFFFFFF is returned on a failure.
+ *
+ *	On a success the message is returned. This is the physical page
+ *	frame offset address from the read port. (See the i2o spec)
+ */
+ 
+u32 i2o_wait_message(struct i2o_controller *c, char *why)
+{
+	long time=jiffies;
+	u32 m;
+	while((m=I2O_POST_READ32(c))==0xFFFFFFFF)
+	{
+		if((jiffies-time)>=5*HZ)
+		{
+			dprintk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", 
+				c->name, why);
+			return 0xFFFFFFFF;
+		}
+		schedule();
+		barrier();
+	}
+	return m;
+}
+	
+/**
+ *	i2o_report_controller_unit - print information about a tid
+ *	@c: controller
+ *	@d: device
+ *	
+ *	Dump an information block associated with a given unit (TID). The
+ *	tables are read and a block of text is output to printk that is
+ *	formatted intended for the user.
+ */
+ 
+void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d)
+{
+	char buf[64];
+	char str[22];
+	int ret;
+	int unit = d->lct_data.tid;
+
+	if(verbose==0)
+		return;
+		
+	printk(KERN_INFO "Target ID %d.\n", unit);
+	if((ret=i2o_query_scalar(c, unit, 0xF100, 3, buf, 16))>=0)
+	{
+		buf[16]=0;
+		printk(KERN_INFO "     Vendor: %s\n", buf);
+	}
+	if((ret=i2o_query_scalar(c, unit, 0xF100, 4, buf, 16))>=0)
+	{
+		buf[16]=0;
+		printk(KERN_INFO "     Device: %s\n", buf);
+	}
+	if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0)
+	{
+		buf[16]=0;
+		printk(KERN_INFO "     Description: %s\n", buf);
+	}
+	if((ret=i2o_query_scalar(c, unit, 0xF100, 6, buf, 8))>=0)
+	{
+		buf[8]=0;
+		printk(KERN_INFO "        Rev: %s\n", buf);
+	}
+
+	printk(KERN_INFO "    Class: ");
+	sprintf(str, "%-21s", i2o_get_class_name(d->lct_data.class_id));
+	printk("%s\n", str);
+		
+	printk(KERN_INFO "  Subclass: 0x%04X\n", d->lct_data.sub_class);
+	printk(KERN_INFO "     Flags: ");
+		
+	if(d->lct_data.device_flags&(1<<0))
+		printk("C");		// ConfigDialog requested
+	if(d->lct_data.device_flags&(1<<1))
+		printk("U");		// Multi-user capable
+	if(!(d->lct_data.device_flags&(1<<4)))
+		printk("P");		// Peer service enabled!
+	if(!(d->lct_data.device_flags&(1<<5)))
+		printk("M");		// Mgmt service enabled!
+	printk("\n");
+			
+}
+
+
+/*
+ *	Parse the hardware resource table. Right now we print it out
+ *	and don't do a lot with it. We should collate these and then
+ *	interact with the Linux resource allocation block.
+ *
+ *	Lets prove we can read it first eh ?
+ *
+ *	This is full of endianisms!
+ */
+ 
+static int i2o_parse_hrt(struct i2o_controller *c)
+{
+#ifdef DRIVERDEBUG
+	u32 *rows=(u32*)c->hrt;
+	u8 *p=(u8 *)c->hrt;
+	u8 *d;
+	int count;
+	int length;
+	int i;
+	int state;
+	
+	if(p[3]!=0)
+	{
+		printk(KERN_ERR "%s: HRT table for controller is too new a version.\n",
+			c->name);
+		return -1;
+	}
+		
+	count=p[0]|(p[1]<<8);
+	length = p[2];
+	
+	printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n",
+		c->name, count, length<<2);
+
+	rows+=2;
+	
+	for(i=0;i<count;i++)
+	{
+		printk(KERN_INFO "Adapter %08X: ", rows[0]);
+		p=(u8 *)(rows+1);
+		d=(u8 *)(rows+2);
+		state=p[1]<<8|p[0];
+		
+		printk("TID %04X:[", state&0xFFF);
+		state>>=12;
+		if(state&(1<<0))
+			printk("H");		/* Hidden */
+		if(state&(1<<2))
+		{
+			printk("P");		/* Present */
+			if(state&(1<<1))
+				printk("C");	/* Controlled */
+		}
+		if(state>9)
+			printk("*");		/* Hard */
+		
+		printk("]:");
+		
+		switch(p[3]&0xFFFF)
+		{
+			case 0:
+				/* Adapter private bus - easy */
+				printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", 
+					p[2], d[1]<<8|d[0], *(u32 *)(d+4));
+				break;
+			case 1:
+				/* ISA bus */
+				printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X",
+					p[2], d[2], d[1]<<8|d[0], *(u32 *)(d+4));
+				break;
+					
+			case 2: /* EISA bus */
+				printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
+					p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4));
+				break;
+
+			case 3: /* MCA bus */
+				printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
+					p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4));
+				break;
+
+			case 4: /* PCI bus */
+				printk("PCI %d: Bus %d Device %d Function %d",
+					p[2], d[2], d[1], d[0]);
+				break;
+
+			case 0x80: /* Other */
+			default:
+				printk("Unsupported bus type.");
+				break;
+		}
+		printk("\n");
+		rows+=length;
+	}
+#endif
+	return 0;
+}
+	
+/*
+ *	The logical configuration table tells us what we can talk to
+ *	on the board. Most of the stuff isn't interesting to us. 
+ */
+
+static int i2o_parse_lct(struct i2o_controller *c)
+{
+	int i;
+	int max;
+	int tid;
+	struct i2o_device *d;
+	i2o_lct *lct = c->lct;
+
+	if (lct == NULL) {
+		printk(KERN_ERR "%s: LCT is empty???\n", c->name);
+		return -1;
+	}
+
+	max = lct->table_size;
+	max -= 3;
+	max /= 9;
+	
+	printk(KERN_INFO "%s: LCT has %d entries.\n", c->name, max);
+	
+	if(lct->iop_flags&(1<<0))
+		printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name);
+		
+	for(i=0;i<max;i++)
+	{
+		d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
+		if(d==NULL)
+		{
+			printk(KERN_CRIT "i2o_core: Out of memory for I2O device data.\n");
+			return -ENOMEM;
+		}
+		
+		d->controller = c;
+		d->next = NULL;
+
+		memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry));
+
+		d->flags = 0;
+		tid = d->lct_data.tid;
+		
+		i2o_report_controller_unit(c, d);
+		
+		i2o_install_device(c, d);
+	}
+	return 0;
+}
+
+
+/**
+ *	i2o_quiesce_controller - quiesce controller
+ *	@c: controller 
+ *
+ *	Quiesce an IOP. Causes IOP to make external operation quiescent
+ *	(i2o 'READY' state). Internal operation of the IOP continues normally.
+ */
+ 
+int i2o_quiesce_controller(struct i2o_controller *c)
+{
+	u32 msg[4];
+	int ret;
+
+	i2o_status_get(c);
+
+	/* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
+
+	if ((c->status_block->iop_state != ADAPTER_STATE_READY) &&
+		(c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL))
+	{
+		return 0;
+	}
+
+	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1] = I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
+	msg[3] = 0;
+
+	/* Long timeout needed for quiesce if lots of devices */
+
+	if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240)))
+		printk(KERN_INFO "%s: Unable to quiesce (status=%#x).\n",
+			c->name, -ret);
+	else
+		dprintk(KERN_INFO "%s: Quiesced.\n", c->name);
+
+	i2o_status_get(c); // Entered READY state
+	return ret;
+}
+
+/**
+ *	i2o_enable_controller - move controller from ready to operational
+ *	@c: controller
+ *
+ *	Enable IOP. This allows the IOP to resume external operations and
+ *	reverses the effect of a quiesce. In the event of an error a negative
+ *	errno code is returned.
+ */
+ 
+int i2o_enable_controller(struct i2o_controller *c)
+{
+	u32 msg[4];
+	int ret;
+
+	i2o_status_get(c);
+	
+	/* Enable only allowed on READY state */	
+	if(c->status_block->iop_state != ADAPTER_STATE_READY)
+		return -EINVAL;
+
+	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID;
+
+	/* How long of a timeout do we need? */
+
+	if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240)))
+		printk(KERN_ERR "%s: Could not enable (status=%#x).\n",
+			c->name, -ret);
+	else
+		dprintk(KERN_INFO "%s: Enabled.\n", c->name);
+
+	i2o_status_get(c); // entered OPERATIONAL state
+
+	return ret;
+}
+
+/**
+ *	i2o_clear_controller	-	clear a controller
+ *	@c: controller
+ *
+ *	Clear an IOP to HOLD state, ie. terminate external operations, clear all
+ *	input queues and prepare for a system restart. IOP's internal operation
+ *	continues normally and the outbound queue is alive.
+ *	The IOP is not expected to rebuild its LCT.
+ */
+ 
+int i2o_clear_controller(struct i2o_controller *c)
+{
+	struct i2o_controller *iop;
+	u32 msg[4];
+	int ret;
+
+	/* Quiesce all IOPs first */
+
+	for (iop = i2o_controller_chain; iop; iop = iop->next)
+		i2o_quiesce_controller(iop);
+
+	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID;
+	msg[3]=0;
+
+	if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30)))
+		printk(KERN_INFO "%s: Unable to clear (status=%#x).\n",
+			c->name, -ret);
+	else
+		dprintk(KERN_INFO "%s: Cleared.\n",c->name);
+
+	i2o_status_get(c);
+
+	/* Enable other IOPs */
+
+	for (iop = i2o_controller_chain; iop; iop = iop->next)
+		if (iop != c)
+			i2o_enable_controller(iop);
+
+	return ret;
+}
+
+
+/**
+ *	i2o_reset_controller	-	reset an IOP
+ *	@c: controller to reset
+ *
+ *	Reset the IOP into INIT state and wait until IOP gets into RESET state.
+ *	Terminate all external operations, clear IOP's inbound and outbound
+ *	queues, terminate all DDMs, and reload the IOP's operating environment
+ *	and all local DDMs. The IOP rebuilds its LCT.
+ */
+ 
+static int i2o_reset_controller(struct i2o_controller *c)
+{
+	struct i2o_controller *iop;
+	u32 m;
+	u8 *status;
+	u32 *msg;
+	long time;
+
+	/* Quiesce all IOPs first */
+
+	for (iop = i2o_controller_chain; iop; iop = iop->next)
+	{
+		if(iop->type != I2O_TYPE_PCI || !iop->bus.pci.dpt)
+			i2o_quiesce_controller(iop);
+	}
+
+	m=i2o_wait_message(c, "AdapterReset");
+	if(m==0xFFFFFFFF)	
+		return -ETIMEDOUT;
+	msg=(u32 *)(c->mem_offset+m);
+	
+	status=(void *)kmalloc(4, GFP_KERNEL);
+	if(status==NULL) {
+		printk(KERN_ERR "IOP reset failed - no free memory.\n");
+		return -ENOMEM;
+	}
+	memset(status, 0, 4);
+	
+	msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
+	msg[2]=core_context;
+	msg[3]=0;
+	msg[4]=0;
+	msg[5]=0;
+	msg[6]=virt_to_bus(status);
+	msg[7]=0;	/* 64bit host FIXME */
+
+	i2o_post_message(c,m);
+
+	/* Wait for a reply */
+	time=jiffies;
+	while(*status==0)
+	{
+		if((jiffies-time)>=20*HZ)
+		{
+			printk(KERN_ERR "IOP reset timeout.\n");
+			// Better to leak this for safety: kfree(status);
+			return -ETIMEDOUT;
+		}
+		schedule();
+		barrier();
+	}
+
+	if (*status==I2O_CMD_IN_PROGRESS)
+	{ 
+		/* 
+		 * Once the reset is sent, the IOP goes into the INIT state 
+		 * which is indeterminate.  We need to wait until the IOP 
+		 * has rebooted before we can let the system talk to 
+		 * it. We read the inbound Free_List until a message is 
+		 * available.  If we can't read one in the given ammount of 
+		 * time, we assume the IOP could not reboot properly.  
+		 */ 
+
+		dprintk(KERN_INFO "%s: Reset in progress, waiting for reboot...\n",
+			c->name); 
+
+		time = jiffies; 
+		m = I2O_POST_READ32(c); 
+		while(m == 0XFFFFFFFF) 
+		{ 
+			if((jiffies-time) >= 30*HZ)
+			{
+				printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n", 
+						c->name); 
+				return -ETIMEDOUT; 
+			} 
+			schedule(); 
+			barrier(); 
+			m = I2O_POST_READ32(c); 
+		}
+		i2o_flush_reply(c,m);
+	}
+
+	/* If IopReset was rejected or didn't perform reset, try IopClear */
+
+	i2o_status_get(c);
+	if (status[0] == I2O_CMD_REJECTED || 
+		c->status_block->iop_state != ADAPTER_STATE_RESET)
+	{
+		printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name);
+		i2o_clear_controller(c);
+	}
+	else
+		dprintk(KERN_INFO "%s: Reset completed.\n", c->name);
+
+	/* Enable other IOPs */
+
+	for (iop = i2o_controller_chain; iop; iop = iop->next)
+		if (iop != c)
+			i2o_enable_controller(iop);
+
+	kfree(status);
+	return 0;
+}
+
+
+/**
+ * 	i2o_status_get	-	get the status block for the IOP
+ *	@c: controller
+ *
+ *	Issue a status query on the controller. This updates the
+ *	attached status_block. If the controller fails to reply or an
+ *	error occurs then a negative errno code is returned. On success
+ *	zero is returned and the status_blok is updated.
+ */
+ 
+int i2o_status_get(struct i2o_controller *c)
+{
+	long time;
+	u32 m;
+	u32 *msg;
+	u8 *status_block;
+
+	if (c->status_block == NULL) 
+	{
+		c->status_block = (i2o_status_block *)
+			kmalloc(sizeof(i2o_status_block),GFP_KERNEL);
+		if (c->status_block == NULL)
+		{
+			printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n",
+				c->name);
+			return -ENOMEM;
+		}
+	}
+
+	status_block = (u8*)c->status_block;
+	memset(c->status_block,0,sizeof(i2o_status_block));
+	
+	m=i2o_wait_message(c, "StatusGet");
+	if(m==0xFFFFFFFF)
+		return -ETIMEDOUT;	
+	msg=(u32 *)(c->mem_offset+m);
+
+	msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID;
+	msg[2]=core_context;
+	msg[3]=0;
+	msg[4]=0;
+	msg[5]=0;
+	msg[6]=virt_to_bus(c->status_block);
+	msg[7]=0;   /* 64bit host FIXME */
+	msg[8]=sizeof(i2o_status_block); /* always 88 bytes */
+
+	i2o_post_message(c,m);
+
+	/* Wait for a reply */
+
+	time=jiffies;
+	while(status_block[87]!=0xFF)
+	{
+		if((jiffies-time)>=5*HZ)
+		{
+			printk(KERN_ERR "%s: Get status timeout.\n",c->name);
+			return -ETIMEDOUT;
+		}
+		schedule();
+		barrier();
+	}
+
+#ifdef DRIVERDEBUG
+	printk(KERN_INFO "%s: State = ", c->name);
+	switch (c->status_block->iop_state) {
+		case 0x01:  
+			printk("INIT\n");
+			break;
+		case 0x02:
+			printk("RESET\n");
+			break;
+		case 0x04:
+			printk("HOLD\n");
+			break;
+		case 0x05:
+			printk("READY\n");
+			break;
+		case 0x08:
+			printk("OPERATIONAL\n");
+			break;
+		case 0x10:
+			printk("FAILED\n");
+			break;
+		case 0x11:
+			printk("FAULTED\n");
+			break;
+		default: 
+			printk("%x (unknown !!)\n",c->status_block->iop_state);
+}     
+#endif   
+
+	return 0;
+}
+
+/*
+ * Get the Hardware Resource Table for the device.
+ * The HRT contains information about possible hidden devices
+ * but is mostly useless to us 
+ */
+int i2o_hrt_get(struct i2o_controller *c)
+{
+	u32 msg[6];
+	int ret, size = sizeof(i2o_hrt);
+
+	/* First read just the header to figure out the real size */
+
+	do  {
+		if (c->hrt == NULL) {
+			c->hrt=kmalloc(size, GFP_KERNEL);
+			if (c->hrt == NULL) {
+				printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name);
+				return -ENOMEM;
+			}
+		}
+
+		msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
+		msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
+		msg[3]= 0;
+		msg[4]= (0xD0000000 | size);	/* Simple transaction */
+		msg[5]= virt_to_bus(c->hrt);	/* Dump it here */
+
+		ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL);
+		
+		if(ret == -ETIMEDOUT)
+		{
+			/* The HRT block we used is in limbo somewhere. When the iop wakes up
+			   we will recover it */
+			c->hrt = NULL;
+			return ret;
+		}
+		
+		if(ret<0)
+		{
+			printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n",
+				c->name, -ret);	
+			return ret;
+		}
+
+		if (c->hrt->num_entries * c->hrt->entry_len << 2 > size) {
+			size = c->hrt->num_entries * c->hrt->entry_len << 2;
+			kfree(c->hrt);
+			c->hrt = NULL;
+		}
+	} while (c->hrt == NULL);
+
+	i2o_parse_hrt(c); // just for debugging
+
+	return 0;
+}
+
+/*
+ * Send the I2O System Table to the specified IOP
+ *
+ * The system table contains information about all the IOPs in the
+ * system.  It is build and then sent to each IOP so that IOPs can
+ * establish connections between each other.
+ *
+ */
+static int i2o_systab_send(struct i2o_controller *iop)
+{
+	u32 msg[12];
+	int ret;
+	u32 *privbuf = kmalloc(16, GFP_KERNEL);
+	if(privbuf == NULL)
+		return -ENOMEM;
+	
+	if(iop->type == I2O_TYPE_PCI)
+	{
+		struct resource *root;
+		
+		if(iop->status_block->current_mem_size < iop->status_block->desired_mem_size)
+		{
+			struct resource *res = &iop->mem_resource;
+			res->name = iop->pdev->bus->name;
+			res->flags = IORESOURCE_MEM;
+			res->start = 0;
+			res->end = 0;
+			printk("%s: requires private memory resources.\n", iop->name);
+			root = pci_find_parent_resource(iop->pdev, res);
+			if(root==NULL)
+				printk("Can't find parent resource!\n");
+			if(root && allocate_resource(root, res, 
+					iop->status_block->desired_mem_size,
+					iop->status_block->desired_mem_size,
+					iop->status_block->desired_mem_size,
+					1<<20,	/* Unspecified, so use 1Mb and play safe */
+					NULL,
+					NULL)>=0)
+			{
+				iop->mem_alloc = 1;
+				iop->status_block->current_mem_size = 1 + res->end - res->start;
+				iop->status_block->current_mem_base = res->start;
+				printk(KERN_INFO "%s: allocated %ld bytes of PCI memory at 0x%08lX.\n", 
+					iop->name, 1+res->end-res->start, res->start);
+			}
+		}
+		if(iop->status_block->current_io_size < iop->status_block->desired_io_size)
+		{
+			struct resource *res = &iop->io_resource;
+			res->name = iop->pdev->bus->name;
+			res->flags = IORESOURCE_IO;
+			res->start = 0;
+			res->end = 0;
+			printk("%s: requires private memory resources.\n", iop->name);
+			root = pci_find_parent_resource(iop->pdev, res);
+			if(root==NULL)
+				printk("Can't find parent resource!\n");
+			if(root &&  allocate_resource(root, res, 
+					iop->status_block->desired_io_size,
+					iop->status_block->desired_io_size,
+					iop->status_block->desired_io_size,
+					1<<20,	/* Unspecified, so use 1Mb and play safe */
+					NULL,
+					NULL)>=0)
+			{
+				iop->io_alloc = 1;
+				iop->status_block->current_io_size = 1 + res->end - res->start;
+				iop->status_block->current_mem_base = res->start;
+				printk(KERN_INFO "%s: allocated %ld bytes of PCI I/O at 0x%08lX.\n", 
+					iop->name, 1+res->end-res->start, res->start);
+			}
+		}
+	}
+	else
+	{	
+		privbuf[0] = iop->status_block->current_mem_base;
+		privbuf[1] = iop->status_block->current_mem_size;
+		privbuf[2] = iop->status_block->current_io_base;
+		privbuf[3] = iop->status_block->current_io_size;
+	}
+
+	msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
+	msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[3] = 0;
+	msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
+	msg[5] = 0;                               /* Segment 0 */
+
+	/* 
+ 	 * Provide three SGL-elements:
+ 	 * System table (SysTab), Private memory space declaration and 
+ 	 * Private i/o space declaration  
+ 	 *
+ 	 * FIXME: provide these for controllers needing them
+ 	 */
+	msg[6] = 0x54000000 | sys_tbl_len;
+	msg[7] = virt_to_bus(sys_tbl);
+	msg[8] = 0x54000000 | 8;
+	msg[9] = virt_to_bus(privbuf);
+	msg[10] = 0xD4000000 | 8;
+	msg[11] = virt_to_bus(privbuf+2);
+
+	ret=i2o_post_wait_mem(iop, msg, sizeof(msg), 120, privbuf, NULL);
+	
+	if(ret==-ETIMEDOUT)
+	{
+		printk(KERN_ERR "%s: SysTab setup timed out.\n", iop->name);
+	}
+	else if(ret<0)
+	{
+		printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n", 
+			iop->name, -ret);
+		kfree(privbuf);
+	}
+	else
+	{
+		dprintk(KERN_INFO "%s: SysTab set.\n", iop->name);
+		kfree(privbuf);
+	}
+	i2o_status_get(iop); // Entered READY state
+
+	return ret;	
+
+ }
+
+/*
+ * Initialize I2O subsystem.
+ */
+static void __init i2o_sys_init(void)
+{
+	struct i2o_controller *iop, *niop = NULL;
+
+	printk(KERN_INFO "Activating I2O controllers...\n");
+	printk(KERN_INFO "This may take a few minutes if there are many devices\n");
+	
+	/* In INIT state, Activate IOPs */
+	for (iop = i2o_controller_chain; iop; iop = niop) {
+		dprintk(KERN_INFO "Calling i2o_activate_controller for %s...\n", 
+			iop->name);
+		niop = iop->next;
+		if (i2o_activate_controller(iop) < 0)
+			i2o_delete_controller(iop);
+	}
+
+	/* Active IOPs in HOLD state */
+
+rebuild_sys_tab:
+	if (i2o_controller_chain == NULL)
+		return;
+
+	/*
+	 * If build_sys_table fails, we kill everything and bail
+	 * as we can't init the IOPs w/o a system table
+	 */	
+	dprintk(KERN_INFO "i2o_core: Calling i2o_build_sys_table...\n");
+	if (i2o_build_sys_table() < 0) {
+		i2o_sys_shutdown();
+		return;
+	}
+
+	/* If IOP don't get online, we need to rebuild the System table */
+	for (iop = i2o_controller_chain; iop; iop = niop) {
+		niop = iop->next;
+		dprintk(KERN_INFO "Calling i2o_online_controller for %s...\n", iop->name);
+		if (i2o_online_controller(iop) < 0) {
+			i2o_delete_controller(iop);	
+			goto rebuild_sys_tab;
+		}
+	}
+	
+	/* Active IOPs now in OPERATIONAL state */
+
+	/*
+	 * Register for status updates from all IOPs
+	 */
+	for(iop = i2o_controller_chain; iop; iop=iop->next) {
+
+		/* Create a kernel thread to deal with dynamic LCT updates */
+		iop->lct_pid = kernel_thread(i2o_dyn_lct, iop, CLONE_SIGHAND);
+	
+		/* Update change ind on DLCT */
+		iop->dlct->change_ind = iop->lct->change_ind;
+
+		/* Start dynamic LCT updates */
+		i2o_lct_notify(iop);
+
+		/* Register for all events from IRTOS */
+		i2o_event_register(iop, core_context, 0, 0, 0xFFFFFFFF);
+	}
+}
+
+/**
+ *	i2o_sys_shutdown - shutdown I2O system
+ *
+ *	Bring down each i2o controller and then return. Each controller
+ *	is taken through an orderly shutdown
+ */
+ 
+static void i2o_sys_shutdown(void)
+{
+	struct i2o_controller *iop, *niop;
+
+	/* Delete all IOPs from the controller chain */
+	/* that will reset all IOPs too */
+
+	for (iop = i2o_controller_chain; iop; iop = niop) {
+		niop = iop->next;
+		i2o_delete_controller(iop);
+	}
+}
+
+/**
+ *	i2o_activate_controller	-	bring controller up to HOLD
+ *	@iop: controller
+ *
+ *	This function brings an I2O controller into HOLD state. The adapter
+ *	is reset if neccessary and then the queues and resource table
+ *	are read. -1 is returned on a failure, 0 on success.
+ *	
+ */
+ 
+int i2o_activate_controller(struct i2o_controller *iop)
+{
+	/* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */
+	/* In READY state, Get status */
+
+	if (i2o_status_get(iop) < 0) {
+		printk(KERN_INFO "Unable to obtain status of %s, "
+			"attempting a reset.\n", iop->name);
+		if (i2o_reset_controller(iop) < 0)
+			return -1;
+	}
+
+	if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED) {
+		printk(KERN_CRIT "%s: hardware fault\n", iop->name);
+		return -1;
+	}
+
+	if (iop->status_block->i2o_version > I2OVER15) {
+		printk(KERN_ERR "%s: Not running vrs. 1.5. of the I2O Specification.\n",
+			iop->name);
+		return -1;
+	}
+
+	if (iop->status_block->iop_state == ADAPTER_STATE_READY ||
+	    iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
+	    iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
+	    iop->status_block->iop_state == ADAPTER_STATE_FAILED)
+	{
+		dprintk(KERN_INFO "%s: Already running, trying to reset...\n",
+			iop->name);
+		if (i2o_reset_controller(iop) < 0)
+			return -1;
+	}
+
+	if (i2o_init_outbound_q(iop) < 0)
+		return -1;
+
+	if (i2o_post_outbound_messages(iop)) 
+		return -1;
+
+	/* In HOLD state */
+	
+	if (i2o_hrt_get(iop) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+/**
+ *	i2o_init_outbound_queue	- setup the outbound queue
+ *	@c: controller
+ *
+ *	Clear and (re)initialize IOP's outbound queue. Returns 0 on
+ *	success or a negative errno code on a failure.
+ */
+ 
+int i2o_init_outbound_q(struct i2o_controller *c)
+{
+	u8 *status;
+	u32 m;
+	u32 *msg;
+	u32 time;
+
+	dprintk(KERN_INFO "%s: Initializing Outbound Queue...\n", c->name);
+	m=i2o_wait_message(c, "OutboundInit");
+	if(m==0xFFFFFFFF)
+		return -ETIMEDOUT;
+	msg=(u32 *)(c->mem_offset+m);
+
+	status = kmalloc(4,GFP_KERNEL);
+	if (status==NULL) {
+		printk(KERN_ERR "%s: Outbound Queue initialization failed - no free memory.\n",
+			c->name);
+		return -ENOMEM;
+	}
+	memset(status, 0, 4);
+
+	msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6;
+	msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2]= core_context;
+	msg[3]= 0x0106;				/* Transaction context */
+	msg[4]= 4096;				/* Host page frame size */
+	/* Frame size is in words. Pick 128, its what everyone elses uses and
+		other sizes break some adapters. */
+	msg[5]= MSG_FRAME_SIZE<<16|0x80;	/* Outbound msg frame size and Initcode */
+	msg[6]= 0xD0000004;			/* Simple SG LE, EOB */
+	msg[7]= virt_to_bus(status);
+
+	i2o_post_message(c,m);
+	
+	barrier();
+	time=jiffies;
+	while(status[0] < I2O_CMD_REJECTED)
+	{
+		if((jiffies-time)>=30*HZ)
+		{
+			if(status[0]==0x00)
+				printk(KERN_ERR "%s: Ignored queue initialize request.\n",
+					c->name);
+			else  
+				printk(KERN_ERR "%s: Outbound queue initialize timeout.\n",
+					c->name);
+			kfree(status);
+			return -ETIMEDOUT;
+		}  
+		schedule();
+		barrier();
+	}  
+
+	if(status[0] != I2O_CMD_COMPLETED)
+	{
+		printk(KERN_ERR "%s: IOP outbound initialise failed.\n", c->name);
+		kfree(status);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+/**
+ *	i2o_post_outbound_messages	-	fill message queue
+ *	@c: controller
+ *
+ *	Allocate a message frame and load the messages into the IOP. The
+ *	function returns zero on success or a negative errno code on
+ *	failure.
+ */
+
+int i2o_post_outbound_messages(struct i2o_controller *c)
+{
+	int i;
+	u32 m;
+	/* Alloc space for IOP's outbound queue message frames */
+
+	c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
+	if(c->page_frame==NULL) {
+		printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n",
+			c->name);
+		return -ENOMEM;
+	}
+	m=virt_to_bus(c->page_frame);
+
+	/* Post frames */
+
+	for(i=0; i< NMBR_MSG_FRAMES; i++) {
+		I2O_REPLY_WRITE32(c,m);
+		mb();
+		m += MSG_FRAME_SIZE;
+	}
+
+	return 0;
+}
+
+/*
+ * Get the IOP's Logical Configuration Table
+ */
+int i2o_lct_get(struct i2o_controller *c)
+{
+	u32 msg[8];
+	int ret, size = c->status_block->expected_lct_size;
+
+	do {
+		if (c->lct == NULL) {
+			c->lct = kmalloc(size, GFP_KERNEL);
+			if(c->lct == NULL) {
+				printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
+					c->name);
+				return -ENOMEM;
+			}
+		}
+		memset(c->lct, 0, size);
+
+		msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
+		msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
+		/* msg[2] filled in i2o_post_wait */
+		msg[3] = 0;
+		msg[4] = 0xFFFFFFFF;	/* All devices */
+		msg[5] = 0x00000000;	/* Report now */
+		msg[6] = 0xD0000000|size;
+		msg[7] = virt_to_bus(c->lct);
+
+		ret=i2o_post_wait_mem(c, msg, sizeof(msg), 120, c->lct, NULL);
+		
+		if(ret == -ETIMEDOUT)
+		{
+			c->lct = NULL;
+			return ret;
+		}
+		
+		if(ret<0)
+		{
+			printk(KERN_ERR "%s: LCT Get failed (status=%#x.\n", 
+				c->name, -ret);	
+			return ret;
+		}
+
+		if (c->lct->table_size << 2 > size) {
+			size = c->lct->table_size << 2;
+			kfree(c->lct);
+			c->lct = NULL;
+		}
+	} while (c->lct == NULL);
+
+        if ((ret=i2o_parse_lct(c)) < 0)
+                return ret;
+
+	return 0;
+}
+
+/*
+ * Like above, but used for async notification.  The main
+ * difference is that we keep track of the CurrentChangeIndiicator
+ * so that we only get updates when it actually changes.
+ *
+ */
+int i2o_lct_notify(struct i2o_controller *c)
+{
+	u32 msg[8];
+
+	msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
+	msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2] = core_context;
+	msg[3] = 0xDEADBEEF;	
+	msg[4] = 0xFFFFFFFF;	/* All devices */
+	msg[5] = c->dlct->change_ind+1;	/* Next change */
+	msg[6] = 0xD0000000|8192;
+	msg[7] = virt_to_bus(c->dlct);
+
+	return i2o_post_this(c, msg, sizeof(msg));
+}
+		
+/*
+ *	Bring a controller online into OPERATIONAL state. 
+ */
+ 
+int i2o_online_controller(struct i2o_controller *iop)
+{
+	u32 v;
+	
+	if (i2o_systab_send(iop) < 0)
+		return -1;
+
+	/* In READY state */
+
+	dprintk(KERN_INFO "%s: Attempting to enable...\n", iop->name);
+	if (i2o_enable_controller(iop) < 0)
+		return -1;
+
+	/* In OPERATIONAL state  */
+
+	dprintk(KERN_INFO "%s: Attempting to get/parse lct...\n", iop->name);
+	if (i2o_lct_get(iop) < 0)
+		return -1;
+
+	/* Check battery status */
+	 
+	iop->battery = 0;
+	if(i2o_query_scalar(iop, ADAPTER_TID, 0x0000, 4, &v, 4)>=0)
+	{
+		if(v&16)
+			iop->battery = 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Build system table
+ *
+ * The system table contains information about all the IOPs in the
+ * system (duh) and is used by the Executives on the IOPs to establish
+ * peer2peer connections.  We're not supporting peer2peer at the moment,
+ * but this will be needed down the road for things like lan2lan forwarding.
+ */
+static int i2o_build_sys_table(void)
+{
+	struct i2o_controller *iop = NULL;
+	struct i2o_controller *niop = NULL;
+	int count = 0;
+
+	sys_tbl_len = sizeof(struct i2o_sys_tbl) +	// Header + IOPs
+				(i2o_num_controllers) *
+					sizeof(struct i2o_sys_tbl_entry);
+
+	if(sys_tbl)
+		kfree(sys_tbl);
+
+	sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL);
+	if(!sys_tbl) {
+		printk(KERN_CRIT "SysTab Set failed. Out of memory.\n");
+		return -ENOMEM;
+	}
+	memset((void*)sys_tbl, 0, sys_tbl_len);
+
+	sys_tbl->num_entries = i2o_num_controllers;
+	sys_tbl->version = I2OVERSION; /* TODO: Version 2.0 */
+	sys_tbl->change_ind = sys_tbl_ind++;
+
+	for(iop = i2o_controller_chain; iop; iop = niop)
+	{
+		niop = iop->next;
+
+		/* 
+		 * Get updated IOP state so we have the latest information
+		 *
+		 * We should delete the controller at this point if it
+		 * doesn't respond since  if it's not on the system table 
+		 * it is techninically not part of the I2O subsyßtem...
+		 */
+		if(i2o_status_get(iop)) {
+			printk(KERN_ERR "%s: Deleting b/c could not get status while"
+				"attempting to build system table\n", iop->name);
+			i2o_delete_controller(iop);		
+			sys_tbl->num_entries--;
+			continue; // try the next one
+		}
+
+		sys_tbl->iops[count].org_id = iop->status_block->org_id;
+		sys_tbl->iops[count].iop_id = iop->unit + 2;
+		sys_tbl->iops[count].seg_num = 0;
+		sys_tbl->iops[count].i2o_version = 
+				iop->status_block->i2o_version;
+		sys_tbl->iops[count].iop_state = 
+				iop->status_block->iop_state;
+		sys_tbl->iops[count].msg_type = 
+				iop->status_block->msg_type;
+		sys_tbl->iops[count].frame_size = 
+				iop->status_block->inbound_frame_size;
+		sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??
+		sys_tbl->iops[count].iop_capabilities = 
+				iop->status_block->iop_capabilities;
+		sys_tbl->iops[count].inbound_low = 
+				(u32)virt_to_bus(iop->post_port);
+		sys_tbl->iops[count].inbound_high = 0;	// TODO: 64-bit support
+
+		count++;
+	}
+
+#ifdef DRIVERDEBUG
+{
+	u32 *table;
+	table = (u32*)sys_tbl;
+	for(count = 0; count < (sys_tbl_len >>2); count++)
+		printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]);
+}
+#endif
+
+	return 0;
+}
+
+
+/*
+ *	Run time support routines
+ */
+ 
+/*
+ *	Generic "post and forget" helpers. This is less efficient - we do
+ *	a memcpy for example that isnt strictly needed, but for most uses
+ *	this is simply not worth optimising
+ */
+
+int i2o_post_this(struct i2o_controller *c, u32 *data, int len)
+{
+	u32 m;
+	u32 *msg;
+	unsigned long t=jiffies;
+
+	do
+	{
+		mb();
+		m = I2O_POST_READ32(c);
+	}
+	while(m==0xFFFFFFFF && (jiffies-t)<HZ);
+	
+	if(m==0xFFFFFFFF)
+	{
+		printk(KERN_ERR "%s: Timeout waiting for message frame!\n",
+		       c->name);
+		return -ETIMEDOUT;
+	}
+	msg = (u32 *)(c->mem_offset + m);
+ 	memcpy_toio(msg, data, len);
+	i2o_post_message(c,m);
+	return 0;
+}
+
+/**
+ * 	i2o_post_wait_mem	-	I2O query/reply with DMA buffers
+ *	@c: controller
+ *	@msg: message to send
+ *	@len: length of message
+ *	@timeout: time in seconds to wait
+ *	@mem1: attached memory buffer 1
+ *	@mem2: attached memory buffer 2
+ *
+ * 	This core API allows an OSM to post a message and then be told whether
+ *	or not the system received a successful reply. 
+ *
+ *	If the message times out then the value '-ETIMEDOUT' is returned. This
+ *	is a special case. In this situation the message may (should) complete
+ *	at an indefinite time in the future. When it completes it will use the
+ *	memory buffers attached to the request. If -ETIMEDOUT is returned then
+ *	the memory buffers must not be freed. Instead the event completion will
+ *	free them for you. In all other cases the buffers are your problem.
+ *
+ *	Pass NULL for unneeded buffers.
+ */
+ 
+int i2o_post_wait_mem(struct i2o_controller *c, u32 *msg, int len, int timeout, void *mem1, void *mem2)
+{
+	DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post);
+	int complete = 0;
+	int status;
+	unsigned long flags = 0;
+	struct i2o_post_wait_data *wait_data =
+		kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL);
+
+	if(!wait_data)
+		return -ENOMEM;
+
+	/*
+	 *	Create a new notification object
+	 */
+	wait_data->status = &status;
+	wait_data->complete = &complete;
+	wait_data->mem[0] = mem1;
+	wait_data->mem[1] = mem2;
+	/* 
+	 *	Queue the event with its unique id
+	 */
+	spin_lock_irqsave(&post_wait_lock, flags);
+
+	wait_data->next = post_wait_queue;
+	post_wait_queue = wait_data;
+	wait_data->id = (++post_wait_id) & 0x7fff;
+	wait_data->wq = &wq_i2o_post;
+
+	spin_unlock_irqrestore(&post_wait_lock, flags);
+
+	/*
+	 *	Fill in the message id
+	 */
+	 
+	msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16);
+	
+	/*
+	 *	Post the message to the controller. At some point later it 
+	 *	will return. If we time out before it returns then
+	 *	complete will be zero.  From the point post_this returns
+	 *	the wait_data may have been deleted.
+	 */
+	if ((status = i2o_post_this(c, msg, len))==0) {
+		sleep_on_timeout(&wq_i2o_post, HZ * timeout);
+	}  
+	else
+		return -EIO;
+		
+	if(signal_pending(current))
+		status = -EINTR;
+		
+	spin_lock_irqsave(&post_wait_lock, flags);
+	barrier();	/* Be sure we see complete as it is locked */
+	if(!complete)
+	{
+		/* 
+		 *	Mark the entry dead. We cannot remove it. This is important.
+		 *	When it does terminate (which it must do if the controller hasnt
+		 *	died..) then it will otherwise scribble on stuff.
+		 *	!complete lets us safely check if the entry is still
+		 *	allocated and thus we can write into it
+		 */
+		wait_data->wq = NULL;
+		status = -ETIMEDOUT;
+	}
+	else
+	{
+		/* Debugging check - remove me soon */
+		if(status == -ETIMEDOUT)
+		{
+			printk("TIMEDOUT BUG!\n");
+			status = -EIO;
+		}
+	}
+	/* And the wait_data is not leaked either! */	 
+	spin_unlock_irqrestore(&post_wait_lock, flags);
+	return status;
+}
+
+/**
+ * 	i2o_post_wait		-	I2O query/reply
+ *	@c: controller
+ *	@msg: message to send
+ *	@len: length of message
+ *	@timeout: time in seconds to wait
+ *
+ * 	This core API allows an OSM to post a message and then be told whether
+ *	or not the system received a successful reply. 
+ */
+ 
+int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout)
+{
+	return i2o_post_wait_mem(c, msg, len, timeout, NULL, NULL);
+}
+
+/*
+ * i2o_post_wait is completed and we want to wake up the 
+ * sleeping proccess. Called by core's reply handler.
+ */
+
+static void i2o_post_wait_complete(u32 context, int status)
+{
+	struct i2o_post_wait_data **p1, *q;
+	unsigned long flags;
+	
+	/* 
+	 * We need to search through the post_wait 
+	 * queue to see if the given message is still
+	 * outstanding.  If not, it means that the IOP 
+	 * took longer to respond to the message than we 
+	 * had allowed and timer has already expired.  
+	 * Not much we can do about that except log
+	 * it for debug purposes, increase timeout, and recompile
+	 *
+	 * Lock needed to keep anyone from moving queue pointers 
+	 * around while we're looking through them.
+	 */
+
+	spin_lock_irqsave(&post_wait_lock, flags);
+
+	for(p1 = &post_wait_queue; *p1!=NULL; p1 = &((*p1)->next)) 
+	{
+		q = (*p1);
+		if(q->id == ((context >> 16) & 0x7fff)) {
+			/*
+			 *	Delete it 
+			 */
+			 
+			*p1 = q->next;
+			
+			/*
+			 *	Live or dead ?
+			 */
+			 
+			if(q->wq)
+			{
+				/* Live entry - wakeup and set status */
+				*q->status = status;
+				*q->complete = 1;
+				wake_up(q->wq);
+			}
+			else
+			{
+				/*
+				 *	Free resources. Caller is dead
+				 */
+				if(q->mem[0])
+					kfree(q->mem[0]);
+				if(q->mem[1])
+					kfree(q->mem[1]);
+				printk(KERN_WARNING "i2o_post_wait event completed after timeout.\n");
+			}
+			kfree(q);
+			spin_unlock(&post_wait_lock);
+			return;
+		}
+	}
+	spin_unlock(&post_wait_lock);
+
+	printk(KERN_DEBUG "i2o_post_wait: Bogus reply!\n");
+}
+
+/*	Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
+ *
+ *	This function can be used for all UtilParamsGet/Set operations.
+ *	The OperationList is given in oplist-buffer, 
+ *	and results are returned in reslist-buffer.
+ *	Note that the minimum sized reslist is 8 bytes and contains
+ *	ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
+ */
+int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid, 
+                void *oplist, int oplen, void *reslist, int reslen)
+{
+	u32 msg[9]; 
+	u32 *res32 = (u32*)reslist;
+	u32 *restmp = (u32*)reslist;
+	int len = 0;
+	int i = 0;
+	int wait_status;
+	u32 *opmem, *resmem;
+	
+	/* Get DMAable memory */
+	opmem = kmalloc(oplen, GFP_KERNEL);
+	if(opmem == NULL)
+		return -ENOMEM;
+	memcpy(opmem, oplist, oplen);
+	
+	resmem = kmalloc(reslen, GFP_KERNEL);
+	if(resmem == NULL)
+	{
+		kfree(opmem);
+		return -ENOMEM;
+	}
+	
+	msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
+	msg[1] = cmd << 24 | HOST_TID << 12 | tid; 
+	msg[3] = 0;
+	msg[4] = 0;
+	msg[5] = 0x54000000 | oplen;	/* OperationList */
+	msg[6] = virt_to_bus(opmem);
+	msg[7] = 0xD0000000 | reslen;	/* ResultList */
+	msg[8] = virt_to_bus(resmem);
+
+	wait_status = i2o_post_wait_mem(iop, msg, sizeof(msg), 10, opmem, resmem);
+	
+	/*
+	 *	This only looks like a memory leak - don't "fix" it.	
+	 */
+	if(wait_status == -ETIMEDOUT)
+		return wait_status;
+
+	/* Query failed */
+	if(wait_status != 0)
+	{
+		kfree(resmem);
+		kfree(opmem);
+		return wait_status;
+	}
+	
+	memcpy(reslist, resmem, reslen);
+	/*
+	 * Calculate number of bytes of Result LIST
+	 * We need to loop through each Result BLOCK and grab the length
+	 */
+	restmp = res32 + 1;
+	len = 1;
+	for(i = 0; i < (res32[0]&0X0000FFFF); i++)
+	{
+		if(restmp[0]&0x00FF0000)	/* BlockStatus != SUCCESS */
+		{
+			printk(KERN_WARNING "%s - Error:\n  ErrorInfoSize = 0x%02x, " 
+					"BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
+					(cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
+					: "PARAMS_GET",   
+					res32[1]>>24, (res32[1]>>16)&0xFF, res32[1]&0xFFFF);
+	
+			/*
+			 *	If this is the only request,than we return an error
+			 */
+			if((res32[0]&0x0000FFFF) == 1)
+			{
+				return -((res32[1] >> 16) & 0xFF); /* -BlockStatus */
+			}
+		}
+		len += restmp[0] & 0x0000FFFF;	/* Length of res BLOCK */
+		restmp += restmp[0] & 0x0000FFFF;	/* Skip to next BLOCK */
+	}
+	return (len << 2);  /* bytes used by result list */
+}
+
+/*
+ *	 Query one scalar group value or a whole scalar group.
+ */                  	
+int i2o_query_scalar(struct i2o_controller *iop, int tid, 
+                     int group, int field, void *buf, int buflen)
+{
+	u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
+	u8  resblk[8+buflen]; /* 8 bytes for header */
+	int size;
+
+	if (field == -1)  		/* whole group */
+       		opblk[4] = -1;
+              
+	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, 
+		opblk, sizeof(opblk), resblk, sizeof(resblk));
+		
+	memcpy(buf, resblk+8, buflen);  /* cut off header */
+	
+	if(size>buflen)
+		return buflen;
+	return size;
+}
+
+/*
+ *	Set a scalar group value or a whole group.
+ */
+int i2o_set_scalar(struct i2o_controller *iop, int tid, 
+		   int group, int field, void *buf, int buflen)
+{
+	u16 *opblk;
+	u8  resblk[8+buflen]; /* 8 bytes for header */
+        int size;
+
+	opblk = kmalloc(buflen+64, GFP_KERNEL);
+	if (opblk == NULL)
+	{
+		printk(KERN_ERR "i2o: no memory for operation buffer.\n");
+		return -ENOMEM;
+	}
+
+	opblk[0] = 1;                        /* operation count */
+	opblk[1] = 0;                        /* pad */
+	opblk[2] = I2O_PARAMS_FIELD_SET;
+	opblk[3] = group;
+
+	if(field == -1) {               /* whole group */
+		opblk[4] = -1;
+		memcpy(opblk+5, buf, buflen);
+	}
+	else                            /* single field */
+	{
+		opblk[4] = 1;
+		opblk[5] = field;
+		memcpy(opblk+6, buf, buflen);
+	}   
+
+	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, 
+				opblk, 12+buflen, resblk, sizeof(resblk));
+
+	kfree(opblk);
+	if(size>buflen)
+		return buflen;
+	return size;
+}
+
+/* 
+ * 	if oper == I2O_PARAMS_TABLE_GET, get from all rows 
+ * 		if fieldcount == -1 return all fields
+ *			ibuf and ibuflen are unused (use NULL, 0)
+ * 		else return specific fields
+ *  			ibuf contains fieldindexes
+ *
+ * 	if oper == I2O_PARAMS_LIST_GET, get from specific rows
+ * 		if fieldcount == -1 return all fields
+ *			ibuf contains rowcount, keyvalues
+ * 		else return specific fields
+ *			fieldcount is # of fieldindexes
+ *  			ibuf contains fieldindexes, rowcount, keyvalues
+ *
+ *	You could also use directly function i2o_issue_params().
+ */
+int i2o_query_table(int oper, struct i2o_controller *iop, int tid, int group,
+		int fieldcount, void *ibuf, int ibuflen,
+		void *resblk, int reslen) 
+{
+	u16 *opblk;
+	int size;
+
+	opblk = kmalloc(10 + ibuflen, GFP_KERNEL);
+	if (opblk == NULL)
+	{
+		printk(KERN_ERR "i2o: no memory for query buffer.\n");
+		return -ENOMEM;
+	}
+
+	opblk[0] = 1;				/* operation count */
+	opblk[1] = 0;				/* pad */
+	opblk[2] = oper;
+	opblk[3] = group;		
+	opblk[4] = fieldcount;
+	memcpy(opblk+5, ibuf, ibuflen);		/* other params */
+
+	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET,iop, tid, 
+				opblk, 10+ibuflen, resblk, reslen);
+
+	kfree(opblk);
+	if(size>reslen)
+		return reslen;
+	return size;
+}
+
+/*
+ * 	Clear table group, i.e. delete all rows.
+ */
+int i2o_clear_table(struct i2o_controller *iop, int tid, int group)
+{
+	u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group };
+	u8  resblk[32]; /* min 8 bytes for result header */
+
+	return i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, 
+				opblk, sizeof(opblk), resblk, sizeof(resblk));
+}
+
+/*
+ * 	Add a new row into a table group.
+ *
+ * 	if fieldcount==-1 then we add whole rows
+ *		buf contains rowcount, keyvalues
+ * 	else just specific fields are given, rest use defaults
+ *  		buf contains fieldindexes, rowcount, keyvalues
+ */	
+int i2o_row_add_table(struct i2o_controller *iop, int tid,
+		    int group, int fieldcount, void *buf, int buflen)
+{
+	u16 *opblk;
+	u8  resblk[32]; /* min 8 bytes for header */
+	int size;
+
+	opblk = kmalloc(buflen+64, GFP_KERNEL);
+	if (opblk == NULL)
+	{
+		printk(KERN_ERR "i2o: no memory for operation buffer.\n");
+		return -ENOMEM;
+	}
+
+	opblk[0] = 1;			/* operation count */
+	opblk[1] = 0;			/* pad */
+	opblk[2] = I2O_PARAMS_ROW_ADD;
+	opblk[3] = group;	
+	opblk[4] = fieldcount;
+	memcpy(opblk+5, buf, buflen);
+
+	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, 
+				opblk, 10+buflen, resblk, sizeof(resblk));
+
+	kfree(opblk);
+	if(size>buflen)
+		return buflen;
+	return size;
+}
+
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Following fail status are common to all classes.
+ * The preserved message must be handled in the reply handler. 
+ */
+void i2o_report_fail_status(u8 req_status, u32* msg)
+{
+	static char *FAIL_STATUS[] = { 
+		"0x80",				/* not used */
+		"SERVICE_SUSPENDED", 		/* 0x81 */
+		"SERVICE_TERMINATED", 		/* 0x82 */
+		"CONGESTION",
+		"FAILURE",
+		"STATE_ERROR",
+		"TIME_OUT",
+		"ROUTING_FAILURE",
+		"INVALID_VERSION",
+		"INVALID_OFFSET",
+		"INVALID_MSG_FLAGS",
+		"FRAME_TOO_SMALL",
+		"FRAME_TOO_LARGE",
+		"INVALID_TARGET_ID",
+		"INVALID_INITIATOR_ID",
+		"INVALID_INITIATOR_CONTEX",	/* 0x8F */
+		"UNKNOWN_FAILURE"		/* 0xFF */
+	};
+
+	if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE)
+		printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.", req_status);
+	else
+		printk("TRANSPORT_%s.\n", FAIL_STATUS[req_status & 0x0F]);
+
+	/* Dump some details */
+
+	printk(KERN_ERR "  InitiatorId = %d, TargetId = %d\n",
+		(msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); 
+	printk(KERN_ERR "  LowestVersion = 0x%02X, HighestVersion = 0x%02X\n",
+		(msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
+	printk(KERN_ERR "  FailingHostUnit = 0x%04X,  FailingIOP = 0x%03X\n",
+		msg[5] >> 16, msg[5] & 0xFFF);
+
+	printk(KERN_ERR "  Severity:  0x%02X ", (msg[4] >> 16) & 0xFF); 
+	if (msg[4] & (1<<16))
+		printk("(FormatError), "
+			"this msg can never be delivered/processed.\n");
+	if (msg[4] & (1<<17))
+		printk("(PathError), "
+			"this msg can no longer be delivered/processed.\n");
+	if (msg[4] & (1<<18))
+		printk("(PathState), "
+			"the system state does not allow delivery.\n");
+	if (msg[4] & (1<<19))
+		printk("(Congestion), resources temporarily not available;"
+			"do not retry immediately.\n");
+}
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Following reply status are common to all classes.
+ */
+void i2o_report_common_status(u8 req_status)
+{
+	static char *REPLY_STATUS[] = { 
+		"SUCCESS", 
+		"ABORT_DIRTY", 
+		"ABORT_NO_DATA_TRANSFER",
+		"ABORT_PARTIAL_TRANSFER",
+		"ERROR_DIRTY",
+		"ERROR_NO_DATA_TRANSFER",
+		"ERROR_PARTIAL_TRANSFER",
+		"PROCESS_ABORT_DIRTY",
+		"PROCESS_ABORT_NO_DATA_TRANSFER",
+		"PROCESS_ABORT_PARTIAL_TRANSFER",
+		"TRANSACTION_ERROR",
+		"PROGRESS_REPORT"	
+	};
+
+	if (req_status > I2O_REPLY_STATUS_PROGRESS_REPORT)
+		printk("RequestStatus = %0#2x", req_status);
+	else
+		printk("%s", REPLY_STATUS[req_status]);
+}
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Following detailed status are valid  for executive class, 
+ * utility class, DDM class and for transaction error replies.
+ */
+static void i2o_report_common_dsc(u16 detailed_status)
+{
+	static char *COMMON_DSC[] = { 
+		"SUCCESS",
+		"0x01",				// not used
+		"BAD_KEY",
+		"TCL_ERROR",
+		"REPLY_BUFFER_FULL",
+		"NO_SUCH_PAGE",
+		"INSUFFICIENT_RESOURCE_SOFT",
+		"INSUFFICIENT_RESOURCE_HARD",
+		"0x08",				// not used
+		"CHAIN_BUFFER_TOO_LARGE",
+		"UNSUPPORTED_FUNCTION",
+		"DEVICE_LOCKED",
+		"DEVICE_RESET",
+		"INAPPROPRIATE_FUNCTION",
+		"INVALID_INITIATOR_ADDRESS",
+		"INVALID_MESSAGE_FLAGS",
+		"INVALID_OFFSET",
+		"INVALID_PARAMETER",
+		"INVALID_REQUEST",
+		"INVALID_TARGET_ADDRESS",
+		"MESSAGE_TOO_LARGE",
+		"MESSAGE_TOO_SMALL",
+		"MISSING_PARAMETER",
+		"TIMEOUT",
+		"UNKNOWN_ERROR",
+		"UNKNOWN_FUNCTION",
+		"UNSUPPORTED_VERSION",
+		"DEVICE_BUSY",
+		"DEVICE_NOT_AVAILABLE"		
+	};
+
+	if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
+		printk(" / DetailedStatus = %0#4x.\n", detailed_status);
+	else
+		printk(" / %s.\n", COMMON_DSC[detailed_status]);
+}
+
+/*
+ * Used for error reporting/debugging purposes
+ */
+static void i2o_report_lan_dsc(u16 detailed_status)
+{
+	static char *LAN_DSC[] = {	// Lan detailed status code strings
+		"SUCCESS",
+		"DEVICE_FAILURE",
+		"DESTINATION_NOT_FOUND",
+		"TRANSMIT_ERROR",
+		"TRANSMIT_ABORTED",
+		"RECEIVE_ERROR",
+		"RECEIVE_ABORTED",
+		"DMA_ERROR",
+		"BAD_PACKET_DETECTED",
+		"OUT_OF_MEMORY",
+		"BUCKET_OVERRUN",
+		"IOP_INTERNAL_ERROR",
+		"CANCELED",
+		"INVALID_TRANSACTION_CONTEXT",
+		"DEST_ADDRESS_DETECTED",
+		"DEST_ADDRESS_OMITTED",
+		"PARTIAL_PACKET_RETURNED",
+		"TEMP_SUSPENDED_STATE",	// last Lan detailed status code
+		"INVALID_REQUEST"	// general detailed status code
+	};
+
+	if (detailed_status > I2O_DSC_INVALID_REQUEST)
+		printk(" / %0#4x.\n", detailed_status);
+	else
+		printk(" / %s.\n", LAN_DSC[detailed_status]);
+}
+
+/*
+ * Used for error reporting/debugging purposes
+ */
+static void i2o_report_util_cmd(u8 cmd)
+{
+	switch (cmd) {
+	case I2O_CMD_UTIL_NOP:
+		printk("UTIL_NOP, ");
+		break;			
+	case I2O_CMD_UTIL_ABORT:
+		printk("UTIL_ABORT, ");
+		break;
+	case I2O_CMD_UTIL_CLAIM:
+		printk("UTIL_CLAIM, ");
+		break;
+	case I2O_CMD_UTIL_RELEASE:
+		printk("UTIL_CLAIM_RELEASE, ");
+		break;
+	case I2O_CMD_UTIL_CONFIG_DIALOG:
+		printk("UTIL_CONFIG_DIALOG, ");
+		break;
+	case I2O_CMD_UTIL_DEVICE_RESERVE:
+		printk("UTIL_DEVICE_RESERVE, ");
+		break;
+	case I2O_CMD_UTIL_DEVICE_RELEASE:
+		printk("UTIL_DEVICE_RELEASE, ");
+		break;
+	case I2O_CMD_UTIL_EVT_ACK:
+		printk("UTIL_EVENT_ACKNOWLEDGE, ");
+		break;
+	case I2O_CMD_UTIL_EVT_REGISTER:
+		printk("UTIL_EVENT_REGISTER, ");
+		break;
+	case I2O_CMD_UTIL_LOCK:
+		printk("UTIL_LOCK, ");
+		break;
+	case I2O_CMD_UTIL_LOCK_RELEASE:
+		printk("UTIL_LOCK_RELEASE, ");
+		break;
+	case I2O_CMD_UTIL_PARAMS_GET:
+		printk("UTIL_PARAMS_GET, ");
+		break;
+	case I2O_CMD_UTIL_PARAMS_SET:
+		printk("UTIL_PARAMS_SET, ");
+		break;
+	case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY:
+		printk("UTIL_REPLY_FAULT_NOTIFY, ");
+		break;
+	default:
+		printk("Cmd = %0#2x, ",cmd);	
+	}
+}
+
+/*
+ * Used for error reporting/debugging purposes
+ */
+static void i2o_report_exec_cmd(u8 cmd)
+{
+	switch (cmd) {
+	case I2O_CMD_ADAPTER_ASSIGN:
+		printk("EXEC_ADAPTER_ASSIGN, ");
+		break;
+	case I2O_CMD_ADAPTER_READ:
+		printk("EXEC_ADAPTER_READ, ");
+		break;
+	case I2O_CMD_ADAPTER_RELEASE:
+		printk("EXEC_ADAPTER_RELEASE, ");
+		break;
+	case I2O_CMD_BIOS_INFO_SET:
+		printk("EXEC_BIOS_INFO_SET, ");
+		break;
+	case I2O_CMD_BOOT_DEVICE_SET:
+		printk("EXEC_BOOT_DEVICE_SET, ");
+		break;
+	case I2O_CMD_CONFIG_VALIDATE:
+		printk("EXEC_CONFIG_VALIDATE, ");
+		break;
+	case I2O_CMD_CONN_SETUP:
+		printk("EXEC_CONN_SETUP, ");
+		break;
+	case I2O_CMD_DDM_DESTROY:
+		printk("EXEC_DDM_DESTROY, ");
+		break;
+	case I2O_CMD_DDM_ENABLE:
+		printk("EXEC_DDM_ENABLE, ");
+		break;
+	case I2O_CMD_DDM_QUIESCE:
+		printk("EXEC_DDM_QUIESCE, ");
+		break;
+	case I2O_CMD_DDM_RESET:
+		printk("EXEC_DDM_RESET, ");
+		break;
+	case I2O_CMD_DDM_SUSPEND:
+		printk("EXEC_DDM_SUSPEND, ");
+		break;
+	case I2O_CMD_DEVICE_ASSIGN:
+		printk("EXEC_DEVICE_ASSIGN, ");
+		break;
+	case I2O_CMD_DEVICE_RELEASE:
+		printk("EXEC_DEVICE_RELEASE, ");
+		break;
+	case I2O_CMD_HRT_GET:
+		printk("EXEC_HRT_GET, ");
+		break;
+	case I2O_CMD_ADAPTER_CLEAR:
+		printk("EXEC_IOP_CLEAR, ");
+		break;
+	case I2O_CMD_ADAPTER_CONNECT:
+		printk("EXEC_IOP_CONNECT, ");
+		break;
+	case I2O_CMD_ADAPTER_RESET:
+		printk("EXEC_IOP_RESET, ");
+		break;
+	case I2O_CMD_LCT_NOTIFY:
+		printk("EXEC_LCT_NOTIFY, ");
+		break;
+	case I2O_CMD_OUTBOUND_INIT:
+		printk("EXEC_OUTBOUND_INIT, ");
+		break;
+	case I2O_CMD_PATH_ENABLE:
+		printk("EXEC_PATH_ENABLE, ");
+		break;
+	case I2O_CMD_PATH_QUIESCE:
+		printk("EXEC_PATH_QUIESCE, ");
+		break;
+	case I2O_CMD_PATH_RESET:
+		printk("EXEC_PATH_RESET, ");
+		break;
+	case I2O_CMD_STATIC_MF_CREATE:
+		printk("EXEC_STATIC_MF_CREATE, ");
+		break;
+	case I2O_CMD_STATIC_MF_RELEASE:
+		printk("EXEC_STATIC_MF_RELEASE, ");
+		break;
+	case I2O_CMD_STATUS_GET:
+		printk("EXEC_STATUS_GET, ");
+		break;
+	case I2O_CMD_SW_DOWNLOAD:
+		printk("EXEC_SW_DOWNLOAD, ");
+		break;
+	case I2O_CMD_SW_UPLOAD:
+		printk("EXEC_SW_UPLOAD, ");
+		break;
+	case I2O_CMD_SW_REMOVE:
+		printk("EXEC_SW_REMOVE, ");
+		break;
+	case I2O_CMD_SYS_ENABLE:
+		printk("EXEC_SYS_ENABLE, ");
+		break;
+	case I2O_CMD_SYS_MODIFY:
+		printk("EXEC_SYS_MODIFY, ");
+		break;
+	case I2O_CMD_SYS_QUIESCE:
+		printk("EXEC_SYS_QUIESCE, ");
+		break;
+	case I2O_CMD_SYS_TAB_SET:
+		printk("EXEC_SYS_TAB_SET, ");
+		break;
+	default:
+		printk("Cmd = %#02x, ",cmd);	
+	}
+}
+
+/*
+ * Used for error reporting/debugging purposes
+ */
+static void i2o_report_lan_cmd(u8 cmd)
+{
+	switch (cmd) {
+	case LAN_PACKET_SEND:
+		printk("LAN_PACKET_SEND, "); 
+		break;
+	case LAN_SDU_SEND:
+		printk("LAN_SDU_SEND, ");
+		break;
+	case LAN_RECEIVE_POST:
+		printk("LAN_RECEIVE_POST, ");
+		break;
+	case LAN_RESET:
+		printk("LAN_RESET, ");
+		break;
+	case LAN_SUSPEND:
+		printk("LAN_SUSPEND, ");
+		break;
+	default:
+		printk("Cmd = %0#2x, ",cmd);	
+	}	
+}
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Report Cmd name, Request status, Detailed Status.
+ */
+void i2o_report_status(const char *severity, const char *str, u32 *msg)
+{
+	u8 cmd = (msg[1]>>24)&0xFF;
+	u8 req_status = (msg[4]>>24)&0xFF;
+	u16 detailed_status = msg[4]&0xFFFF;
+	struct i2o_handler *h = i2o_handlers[msg[2] & (MAX_I2O_MODULES-1)];
+
+	printk("%s%s: ", severity, str);
+
+	if (cmd < 0x1F) 			// Utility cmd
+		i2o_report_util_cmd(cmd);
+	
+	else if (cmd >= 0xA0 && cmd <= 0xEF) 	// Executive cmd
+		i2o_report_exec_cmd(cmd);
+	
+	else if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F)
+		i2o_report_lan_cmd(cmd);	// LAN cmd
+	else
+        	printk("Cmd = %0#2x, ", cmd);	// Other cmds
+
+	if (msg[0] & MSG_FAIL) {
+		i2o_report_fail_status(req_status, msg);
+		return;
+	}
+	
+	i2o_report_common_status(req_status);
+
+	if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF))
+		i2o_report_common_dsc(detailed_status);	
+	else if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F)
+		i2o_report_lan_dsc(detailed_status);
+	else
+		printk(" / DetailedStatus = %0#4x.\n", detailed_status); 
+}
+
+/* Used to dump a message to syslog during debugging */
+void i2o_dump_message(u32 *msg)
+{
+#ifdef DRIVERDEBUG
+	int i;
+	printk(KERN_INFO "Dumping I2O message size %d @ %p\n", 
+		msg[0]>>16&0xffff, msg);
+	for(i = 0; i < ((msg[0]>>16)&0xffff); i++)
+		printk(KERN_INFO "  msg[%d] = %0#10x\n", i, msg[i]);
+#endif
+}
+
+/*
+ * I2O reboot/shutdown notification.
+ *
+ * - Call each OSM's reboot notifier (if one exists)
+ * - Quiesce each IOP in the system
+ *
+ * Each IOP has to be quiesced before we can ensure that the system
+ * can be properly shutdown as a transaction that has already been
+ * acknowledged still needs to be placed in permanent store on the IOP.
+ * The SysQuiesce causes the IOP to force all HDMs to complete their
+ * transactions before returning, so only at that point is it safe
+ * 
+ */
+static int i2o_reboot_event(struct notifier_block *n, unsigned long code, void
+*p)
+{
+	int i = 0;
+	struct i2o_controller *c = NULL;
+
+	if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF)
+		return NOTIFY_DONE;
+
+	printk(KERN_INFO "Shutting down I2O system.\n");
+	printk(KERN_INFO 
+		"   This could take a few minutes if there are many devices attached\n");
+
+	for(i = 0; i < MAX_I2O_MODULES; i++)
+	{
+		if(i2o_handlers[i] && i2o_handlers[i]->reboot_notify)
+			i2o_handlers[i]->reboot_notify();
+	}
+
+	for(c = i2o_controller_chain; c; c = c->next)
+	{
+		if(i2o_quiesce_controller(c))
+		{
+			printk(KERN_WARNING "i2o: Could not quiesce %s."  "
+				Verify setup on next system power up.\n", c->name);
+		}
+	}
+
+	printk(KERN_INFO "I2O system down.\n");
+	return NOTIFY_DONE;
+}
+
+
+EXPORT_SYMBOL(i2o_controller_chain);
+EXPORT_SYMBOL(i2o_num_controllers);
+EXPORT_SYMBOL(i2o_find_controller);
+EXPORT_SYMBOL(i2o_unlock_controller);
+EXPORT_SYMBOL(i2o_status_get);
+
+EXPORT_SYMBOL(i2o_install_handler);
+EXPORT_SYMBOL(i2o_remove_handler);
+
+EXPORT_SYMBOL(i2o_claim_device);
+EXPORT_SYMBOL(i2o_release_device);
+EXPORT_SYMBOL(i2o_device_notify_on);
+EXPORT_SYMBOL(i2o_device_notify_off);
+
+EXPORT_SYMBOL(i2o_post_this);
+EXPORT_SYMBOL(i2o_post_wait);
+EXPORT_SYMBOL(i2o_post_wait_mem);
+
+EXPORT_SYMBOL(i2o_query_scalar);
+EXPORT_SYMBOL(i2o_set_scalar);
+EXPORT_SYMBOL(i2o_query_table);
+EXPORT_SYMBOL(i2o_clear_table);
+EXPORT_SYMBOL(i2o_row_add_table);
+EXPORT_SYMBOL(i2o_issue_params);
+
+EXPORT_SYMBOL(i2o_event_register);
+EXPORT_SYMBOL(i2o_event_ack);
+
+EXPORT_SYMBOL(i2o_report_status);
+EXPORT_SYMBOL(i2o_dump_message);
+
+EXPORT_SYMBOL(i2o_get_class_name);
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Red Hat Software");
+MODULE_DESCRIPTION("I2O Core");
+
+
+int init_module(void)
+{
+	printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n");
+	if (i2o_install_handler(&i2o_core_handler) < 0)
+	{
+		printk(KERN_ERR 
+			"i2o_core: Unable to install core handler.\nI2O stack not loaded!");
+		return 0;
+	}
+
+	core_context = i2o_core_handler.context;
+
+	/*
+	 * Attach core to I2O PCI transport (and others as they are developed)
+	 */
+#ifdef CONFIG_I2O_PCI_MODULE
+	if(i2o_pci_core_attach(&i2o_core_functions) < 0)
+		printk(KERN_INFO "i2o: No PCI I2O controllers found\n");
+#endif
+
+	/*
+	 * Initialize event handling thread
+	 */	
+	init_MUTEX_LOCKED(&evt_sem);
+	evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND);
+	if(evt_pid < 0)
+	{
+		printk(KERN_ERR "I2O: Could not create event handler kernel thread\n");
+		i2o_remove_handler(&i2o_core_handler);
+		return 0;
+	}
+	else
+		printk(KERN_INFO "I2O: Event thread created as pid %d\n", evt_pid);
+
+	if(i2o_num_controllers)
+		i2o_sys_init();
+
+	register_reboot_notifier(&i2o_reboot_notifier);
+
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	int stat;
+
+	unregister_reboot_notifier(&i2o_reboot_notifier);
+
+	if(i2o_num_controllers)
+		i2o_sys_shutdown();
+
+	/*
+	 * If this is shutdown time, the thread has already been killed
+	 */
+	if(evt_running) {
+		printk("Terminating i2o threads...");
+		stat = kill_proc(evt_pid, SIGTERM, 1);
+		if(!stat) {
+			printk("waiting...");
+			wait_for_completion(&evt_dead);
+		}
+		printk("done.\n");
+	}
+
+#ifdef CONFIG_I2O_PCI_MODULE
+	i2o_pci_core_detach();
+#endif
+
+	i2o_remove_handler(&i2o_core_handler);
+
+	unregister_reboot_notifier(&i2o_reboot_notifier);
+}
+
+#else
+
+extern int i2o_block_init(void);
+extern int i2o_config_init(void);
+extern int i2o_lan_init(void);
+extern int i2o_pci_init(void);
+extern int i2o_proc_init(void);
+extern int i2o_scsi_init(void);
+
+int __init i2o_init(void)
+{
+	printk(KERN_INFO "Loading I2O Core - (c) Copyright 1999 Red Hat Software\n");
+	
+	if (i2o_install_handler(&i2o_core_handler) < 0)
+	{
+		printk(KERN_ERR 
+			"i2o_core: Unable to install core handler.\nI2O stack not loaded!");
+		return 0;
+	}
+
+	core_context = i2o_core_handler.context;
+
+	/*
+	 * Initialize event handling thread
+	 * We may not find any controllers, but still want this as 
+	 * down the road we may have hot pluggable controllers that
+	 * need to be dealt with.
+	 */	
+	init_MUTEX_LOCKED(&evt_sem);
+	if((evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND)) < 0)
+	{
+		printk(KERN_ERR "I2O: Could not create event handler kernel thread\n");
+		i2o_remove_handler(&i2o_core_handler);
+		return 0;
+	}
+
+
+#ifdef CONFIG_I2O_PCI
+	i2o_pci_init();
+#endif
+
+	if(i2o_num_controllers)
+		i2o_sys_init();
+
+	register_reboot_notifier(&i2o_reboot_notifier);
+
+	i2o_config_init();
+#ifdef CONFIG_I2O_BLOCK
+	i2o_block_init();
+#endif
+#ifdef CONFIG_I2O_LAN
+	i2o_lan_init();
+#endif
+#ifdef CONFIG_I2O_PROC
+	i2o_proc_init();
+#endif
+	return 0;
+}
+
+#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/i2o_lan.c linux/drivers/message/i2o/i2o_lan.c
--- v2.4.12/linux/drivers/message/i2o/i2o_lan.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/i2o_lan.c	Mon Oct 15 13:41:10 2001
@@ -0,0 +1,1577 @@
+/*
+ *	drivers/message/i2o/i2o_lan.c
+ *
+ * 	I2O LAN CLASS OSM 		May 26th 2000
+ *
+ *	(C) Copyright 1999, 2000 	University of Helsinki,
+ *		      			Department of Computer Science
+ *
+ * 	This code is still under development / test.
+ *
+ *	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.
+ *
+ *	Authors: 	Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *	Fixes:		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *	 		Taneli Vähäkangas <Taneli.Vahakangas@cs.Helsinki.FI>
+ *			Deepak Saxena <deepak@plexity.net>
+ *
+ *	Tested:		in FDDI environment (using SysKonnect's DDM)
+ *			in Gigabit Eth environment (using SysKonnect's DDM)
+ *			in Fast Ethernet environment (using Intel 82558 DDM)
+ *
+ *	TODO:		tests for other LAN classes (Token Ring, Fibre Channel)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/pci.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/trdevice.h>
+#include <linux/fcdevice.h>
+
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/tqueue.h>
+#include <asm/io.h>
+
+#include <linux/errno.h>
+
+#include <linux/i2o.h>
+#include "i2o_lan.h"
+
+//#define DRIVERDEBUG
+#ifdef DRIVERDEBUG
+#define dprintk(s, args...) printk(s, ## args)
+#else
+#define dprintk(s, args...)
+#endif
+
+/* The following module parameters are used as default values
+ * for per interface values located in the net_device private area.
+ * Private values are changed via /proc filesystem.
+ */
+static u32 max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT;
+static u32 bucket_thresh   = I2O_LAN_BUCKET_THRESH;
+static u32 rx_copybreak    = I2O_LAN_RX_COPYBREAK;
+static u8  tx_batch_mode   = I2O_LAN_TX_BATCH_MODE;
+static u32 i2o_event_mask  = I2O_LAN_EVENT_MASK;
+
+#define MAX_LAN_CARDS 16
+static struct net_device *i2o_landevs[MAX_LAN_CARDS+1];
+static int unit = -1; 	  /* device unit number */
+
+static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m);
+static void i2o_lan_send_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m);
+static int i2o_lan_receive_post(struct net_device *dev);
+static void i2o_lan_receive_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m);
+static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg);
+
+static int i2o_lan_reset(struct net_device *dev);
+static void i2o_lan_handle_event(struct net_device *dev, u32 *msg);
+
+/* Structures to register handlers for the incoming replies. */
+
+static struct i2o_handler i2o_lan_send_handler = {
+	i2o_lan_send_post_reply, 	// For send replies
+	NULL,
+	NULL,
+	NULL,
+	"I2O LAN OSM send",
+	-1,
+	I2O_CLASS_LAN
+};
+static int lan_send_context;
+
+static struct i2o_handler i2o_lan_receive_handler = {
+	i2o_lan_receive_post_reply,	// For receive replies
+	NULL,
+	NULL,
+	NULL,
+	"I2O LAN OSM receive",
+	-1,
+	I2O_CLASS_LAN
+};
+static int lan_receive_context;
+
+static struct i2o_handler i2o_lan_handler = {
+	i2o_lan_reply,			// For other replies
+	NULL,
+	NULL,
+	NULL,
+	"I2O LAN OSM",
+	-1,
+	I2O_CLASS_LAN
+};
+static int lan_context;
+
+DECLARE_TASK_QUEUE(i2o_post_buckets_task);
+struct tq_struct run_i2o_post_buckets_task = {
+	routine: (void (*)(void *)) run_task_queue,
+	data: (void *) 0
+};
+
+/* Functions to handle message failures and transaction errors:
+==============================================================*/
+
+/*
+ * i2o_lan_handle_failure(): Fail bit has been set since IOP's message
+ * layer cannot deliver the request to the target, or the target cannot
+ * process the request.
+ */
+static void i2o_lan_handle_failure(struct net_device *dev, u32 *msg)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+
+	u32 *preserved_msg = (u32*)(iop->mem_offset + msg[7]);
+	u32 *sgl_elem = &preserved_msg[4];
+	struct sk_buff *skb = NULL;
+	u8 le_flag;
+
+	i2o_report_status(KERN_INFO, dev->name, msg);
+
+	/* If PacketSend failed, free sk_buffs reserved by upper layers */
+
+	if (msg[1] >> 24 == LAN_PACKET_SEND) {
+		do {
+			skb = (struct sk_buff *)(sgl_elem[1]);
+			dev_kfree_skb_irq(skb);
+
+			atomic_dec(&priv->tx_out);
+
+			le_flag = *sgl_elem >> 31;
+			sgl_elem +=3;
+		} while (le_flag == 0); /* Last element flag not set */
+
+		if (netif_queue_stopped(dev))
+			netif_wake_queue(dev);
+	}
+
+	/* If ReceivePost failed, free sk_buffs we have reserved */
+
+	if (msg[1] >> 24 == LAN_RECEIVE_POST) {
+		do {
+			skb = (struct sk_buff *)(sgl_elem[1]);
+			dev_kfree_skb_irq(skb);
+
+			atomic_dec(&priv->buckets_out);
+
+			le_flag = *sgl_elem >> 31;
+			sgl_elem +=3;
+		} while (le_flag == 0); /* Last element flag not set */
+	}
+
+	/* Release the preserved msg frame by resubmitting it as a NOP */
+
+	preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+	preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
+	preserved_msg[2] = 0;
+	i2o_post_message(iop, msg[7]);
+}
+/*
+ * i2o_lan_handle_transaction_error(): IOP or DDM has rejected the request
+ * for general cause (format error, bad function code, insufficient resources,
+ * etc.). We get one transaction_error for each failed transaction.
+ */
+static void i2o_lan_handle_transaction_error(struct net_device *dev, u32 *msg)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct sk_buff *skb;
+
+	i2o_report_status(KERN_INFO, dev->name, msg);
+
+	/* If PacketSend was rejected, free sk_buff reserved by upper layers */
+
+	if (msg[1] >> 24 == LAN_PACKET_SEND) {
+		skb = (struct sk_buff *)(msg[3]); // TransactionContext
+		dev_kfree_skb_irq(skb);
+		atomic_dec(&priv->tx_out);
+
+		if (netif_queue_stopped(dev))
+			netif_wake_queue(dev);
+ 	}
+
+	/* If ReceivePost was rejected, free sk_buff we have reserved */
+
+	if (msg[1] >> 24 == LAN_RECEIVE_POST) {
+		skb = (struct sk_buff *)(msg[3]);
+		dev_kfree_skb_irq(skb);
+		atomic_dec(&priv->buckets_out);
+	}
+}
+
+/*
+ * i2o_lan_handle_status(): Common parts of handling a not succeeded request
+ * (status != SUCCESS).
+ */
+static int i2o_lan_handle_status(struct net_device *dev, u32 *msg)
+{
+	/* Fail bit set? */
+
+	if (msg[0] & MSG_FAIL) {
+		i2o_lan_handle_failure(dev, msg);
+		return -1;
+	}
+
+	/* Message rejected for general cause? */
+
+	if ((msg[4]>>24) == I2O_REPLY_STATUS_TRANSACTION_ERROR) {
+		i2o_lan_handle_transaction_error(dev, msg);
+		return -1;
+	}
+
+	/* Else have to handle it in the callback function */
+
+	return 0;
+}
+
+/* Callback functions called from the interrupt routine:
+=======================================================*/
+
+/*
+ * i2o_lan_send_post_reply(): Callback function to handle PostSend replies.
+ */
+static void i2o_lan_send_post_reply(struct i2o_handler *h,
+			struct i2o_controller *iop, struct i2o_message *m)
+{
+	u32 *msg = (u32 *)m;
+	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
+	struct net_device *dev = i2o_landevs[unit];
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	u8 trl_count  = msg[3] & 0x000000FF;
+
+	if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) {
+		if (i2o_lan_handle_status(dev, msg))
+			return;
+	}
+
+#ifdef DRIVERDEBUG
+	i2o_report_status(KERN_INFO, dev->name, msg);
+#endif
+
+	/* DDM has handled transmit request(s), free sk_buffs.
+	 * We get similar single transaction reply also in error cases 
+	 * (except if msg failure or transaction error).
+	 */
+	while (trl_count) {
+		dev_kfree_skb_irq((struct sk_buff *)msg[4 + trl_count]);
+		dprintk(KERN_INFO "%s: tx skb freed (trl_count=%d).\n",
+			dev->name, trl_count);
+		atomic_dec(&priv->tx_out);
+		trl_count--;
+	}
+
+	/* If priv->tx_out had reached tx_max_out, the queue was stopped */
+
+	if (netif_queue_stopped(dev))
+ 		netif_wake_queue(dev);
+}
+
+/*
+ * i2o_lan_receive_post_reply(): Callback function to process incoming packets.
+ */
+static void i2o_lan_receive_post_reply(struct i2o_handler *h,
+			struct i2o_controller *iop, struct i2o_message *m)
+{
+	u32 *msg = (u32 *)m;
+	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
+	struct net_device *dev = i2o_landevs[unit];
+
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_bucket_descriptor *bucket = (struct i2o_bucket_descriptor *)&msg[6];
+	struct i2o_packet_info *packet;
+	u8 trl_count = msg[3] & 0x000000FF;
+	struct sk_buff *skb, *old_skb;
+	unsigned long flags = 0;
+
+	if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) {
+		if (i2o_lan_handle_status(dev, msg))
+			return;
+
+		i2o_lan_release_buckets(dev, msg);
+		return;
+	}
+
+#ifdef DRIVERDEBUG
+	i2o_report_status(KERN_INFO, dev->name, msg);
+#endif
+
+	/* Else we are receiving incoming post. */
+
+	while (trl_count--) {
+		skb = (struct sk_buff *)bucket->context;
+		packet = (struct i2o_packet_info *)bucket->packet_info;
+		atomic_dec(&priv->buckets_out);
+
+		/* Sanity checks: Any weird characteristics in bucket? */
+
+		if (packet->flags & 0x0f || ! packet->flags & 0x40) {
+			if (packet->flags & 0x01)
+				printk(KERN_WARNING "%s: packet with errors, error code=0x%02x.\n",
+					dev->name, packet->status & 0xff);
+
+			/* The following shouldn't happen, unless parameters in
+			 * LAN_OPERATION group are changed during the run time.
+			 */
+			 if (packet->flags & 0x0c)
+				printk(KERN_DEBUG "%s: multi-bucket packets not supported!\n", 
+					dev->name);
+					
+			if (! packet->flags & 0x40)
+				printk(KERN_DEBUG "%s: multiple packets in a bucket not supported!\n", 
+					dev->name);
+
+			dev_kfree_skb_irq(skb);
+
+			bucket++;
+			continue;
+		}
+
+		/* Copy short packet to a new skb */
+		
+		if (packet->len < priv->rx_copybreak) {
+			old_skb = skb;
+			skb = (struct sk_buff *)dev_alloc_skb(packet->len+2);
+			if (skb == NULL) {
+				printk(KERN_ERR "%s: Can't allocate skb.\n", dev->name);
+				return;
+			}
+			skb_reserve(skb, 2);
+			memcpy(skb_put(skb, packet->len), old_skb->data, packet->len);
+
+			spin_lock_irqsave(&priv->fbl_lock, flags);
+			if (priv->i2o_fbl_tail < I2O_LAN_MAX_BUCKETS_OUT)
+				priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb;
+			else
+				dev_kfree_skb_irq(old_skb);
+
+			spin_unlock_irqrestore(&priv->fbl_lock, flags);
+		} else
+			skb_put(skb, packet->len);
+
+		/* Deliver to upper layers */
+
+		skb->dev = dev;
+		skb->protocol = priv->type_trans(skb, dev);
+		netif_rx(skb);
+
+		dev->last_rx = jiffies;
+
+		dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered "
+			"to upper level.\n", dev->name, packet->len);
+
+		bucket++; // to next Packet Descriptor Block
+	}
+
+#ifdef DRIVERDEBUG
+	if (msg[5] == 0)
+		printk(KERN_INFO "%s: DDM out of buckets (priv->count = %d)!\n",
+		       dev->name, atomic_read(&priv->buckets_out));
+#endif
+
+	/* If DDM has already consumed bucket_thresh buckets, post new ones */
+
+	if (atomic_read(&priv->buckets_out) <= priv->max_buckets_out - priv->bucket_thresh) {
+		run_i2o_post_buckets_task.data = (void *)dev;
+		queue_task(&run_i2o_post_buckets_task, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+
+	return;
+}
+
+/*
+ * i2o_lan_reply(): Callback function to handle other incoming messages
+ * except SendPost and ReceivePost.
+ */
+static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
+			  struct i2o_message *m)
+{
+	u32 *msg = (u32 *)m;
+	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
+	struct net_device *dev = i2o_landevs[unit];
+
+	if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) {
+		if (i2o_lan_handle_status(dev, msg))
+			return;
+
+		/* In other error cases just report and continue */
+
+		i2o_report_status(KERN_INFO, dev->name, msg);
+	}
+
+#ifdef DRIVERDEBUG
+	i2o_report_status(KERN_INFO, dev->name, msg);
+#endif
+	switch (msg[1] >> 24) {
+		case LAN_RESET:
+		case LAN_SUSPEND:
+			/* default reply without payload */
+		break;
+
+		case I2O_CMD_UTIL_EVT_REGISTER: 
+		case I2O_CMD_UTIL_EVT_ACK:
+			i2o_lan_handle_event(dev, msg);
+		break;
+
+		case I2O_CMD_UTIL_PARAMS_SET:
+			/* default reply, results in ReplyPayload (not examined) */
+			switch (msg[3] >> 16) {
+			    case 1: dprintk(KERN_INFO "%s: Reply to set MAC filter mask.\n",
+					dev->name);
+			    break;
+			    case 2: dprintk(KERN_INFO "%s: Reply to set MAC table.\n", 
+					dev->name);
+			    break;
+			    default: printk(KERN_WARNING "%s: Bad group 0x%04X\n",
+			 		dev->name,msg[3] >> 16);
+			}
+		break;
+
+		default:
+			printk(KERN_ERR "%s: No handler for the reply.\n",
+		       		dev->name);
+			i2o_report_status(KERN_INFO, dev->name, msg);
+	}
+}
+
+/* Functions used by the above callback functions:
+=================================================*/
+/*
+ * i2o_lan_release_buckets(): Free unused buckets (sk_buffs).
+ */
+static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	u8 trl_elem_size = (u8)(msg[3]>>8 & 0x000000FF);
+	u8 trl_count = (u8)(msg[3] & 0x000000FF);
+	u32 *pskb = &msg[6];
+
+	while (trl_count--) {
+		dprintk(KERN_DEBUG "%s: Releasing unused rx skb %p (trl_count=%d).\n",
+			dev->name, (struct sk_buff*)(*pskb),trl_count+1);
+		dev_kfree_skb_irq((struct sk_buff *)(*pskb));
+		pskb += 1 + trl_elem_size;
+		atomic_dec(&priv->buckets_out);
+	}
+}
+
+/*
+ * i2o_lan_event_reply(): Handle events.
+ */
+static void i2o_lan_handle_event(struct net_device *dev, u32 *msg)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	u32 max_evt_data_size =iop->status_block->inbound_frame_size-5;
+	struct i2o_reply {
+		u32 header[4];
+		u32 evt_indicator;
+		u32 data[max_evt_data_size];
+	} *evt = (struct i2o_reply *)msg;
+	int evt_data_len = ((msg[0]>>16) - 5) * 4; /* real size*/
+
+	printk(KERN_INFO "%s: I2O event - ", dev->name);
+
+	if (msg[1]>>24 == I2O_CMD_UTIL_EVT_ACK) {
+		printk("Event acknowledgement reply.\n");
+		return;
+	}
+
+	/* Else evt->function == I2O_CMD_UTIL_EVT_REGISTER) */
+
+	switch (evt->evt_indicator) {
+	case I2O_EVT_IND_STATE_CHANGE:  {
+		struct state_data {
+			u16 status;
+			u8 state;
+			u8 data;
+		} *evt_data = (struct state_data *)(evt->data[0]);
+
+		printk("State chance 0x%08x.\n", evt->data[0]);
+
+		/* If the DDM is in error state, recovery may be
+		 * possible if status = Transmit or Receive Control
+		 * Unit Inoperable.
+		 */
+		if (evt_data->state==0x05 && evt_data->status==0x0003)
+			i2o_lan_reset(dev);
+		break;
+	}
+
+	case I2O_EVT_IND_FIELD_MODIFIED: {
+		u16 *work16 = (u16 *)evt->data;
+		printk("Group 0x%04x, field %d changed.\n", work16[0], work16[1]);
+		break;
+	}
+
+	case I2O_EVT_IND_VENDOR_EVT: {
+		int i;
+		printk("Vendor event:\n");
+		for (i = 0; i < evt_data_len / 4; i++)
+			printk("   0x%08x\n", evt->data[i]);
+		break;
+	}
+
+	case I2O_EVT_IND_DEVICE_RESET:
+		/* Spec 2.0 p. 6-121:
+		 * The event of _DEVICE_RESET should also be responded
+		 */
+		printk("Device reset.\n");
+		if (i2o_event_ack(iop, msg) < 0)
+			printk("%s: Event Acknowledge timeout.\n", dev->name);
+		break;
+
+#if 0
+	case I2O_EVT_IND_EVT_MASK_MODIFIED:
+		printk("Event mask modified, 0x%08x.\n", evt->data[0]);
+		break;
+
+	case I2O_EVT_IND_GENERAL_WARNING:
+		printk("General warning 0x%04x.\n", evt->data[0]);
+		break;
+
+	case I2O_EVT_IND_CONFIGURATION_FLAG:
+		printk("Configuration requested.\n");
+		break;
+
+	case I2O_EVT_IND_CAPABILITY_CHANGE:
+		printk("Capability change 0x%04x.\n", evt->data[0]);
+		break;
+
+	case I2O_EVT_IND_DEVICE_STATE:
+		printk("Device state changed 0x%08x.\n", evt->data[0]);
+		break;
+#endif
+	case I2O_LAN_EVT_LINK_DOWN:
+		netif_carrier_off(dev); 
+		printk("Link to the physical device is lost.\n");
+		break;
+
+	case I2O_LAN_EVT_LINK_UP:
+		netif_carrier_on(dev); 
+		printk("Link to the physical device is (re)established.\n");
+		break;
+
+	case I2O_LAN_EVT_MEDIA_CHANGE:
+		printk("Media change.\n");
+		break;
+	default:
+		printk("0x%08x. No handler.\n", evt->evt_indicator);
+	}
+}
+
+/*
+ * i2o_lan_receive_post(): Post buckets to receive packets.
+ */
+static int i2o_lan_receive_post(struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	struct sk_buff *skb;
+	u32 m, *msg;
+	u32 bucket_len = (dev->mtu + dev->hard_header_len);
+	u32 total = priv->max_buckets_out - atomic_read(&priv->buckets_out);
+	u32 bucket_count;
+	u32 *sgl_elem;
+	unsigned long flags;
+
+	/* Send (total/bucket_count) separate I2O requests */
+
+	while (total) {
+		m = I2O_POST_READ32(iop);
+		if (m == 0xFFFFFFFF)
+			return -ETIMEDOUT;
+		msg = (u32 *)(iop->mem_offset + m);
+
+		bucket_count = (total >= priv->sgl_max) ? priv->sgl_max : total;
+		total -= bucket_count;
+		atomic_add(bucket_count, &priv->buckets_out);
+
+		dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN DDM.\n",
+			dev->name, bucket_count, bucket_len);
+
+		/* Fill in the header */
+
+		__raw_writel(I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4, msg);
+		__raw_writel(LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1);
+		__raw_writel(priv->unit << 16 | lan_receive_context, msg+2);
+		__raw_writel(bucket_count, msg+3);
+		sgl_elem = &msg[4];
+
+		/* Fill in the payload - contains bucket_count SGL elements */
+
+		while (bucket_count--) {
+			spin_lock_irqsave(&priv->fbl_lock, flags);
+			if (priv->i2o_fbl_tail >= 0)
+				skb = priv->i2o_fbl[priv->i2o_fbl_tail--];
+			else {
+				skb = dev_alloc_skb(bucket_len + 2);
+				if (skb == NULL) {
+					spin_unlock_irqrestore(&priv->fbl_lock, flags);
+					return -ENOMEM;
+				}
+				skb_reserve(skb, 2);
+			}
+			spin_unlock_irqrestore(&priv->fbl_lock, flags);
+
+			__raw_writel(0x51000000 | bucket_len, sgl_elem);
+			__raw_writel((u32)skb,		      sgl_elem+1);
+			__raw_writel(virt_to_bus(skb->data),  sgl_elem+2);
+			sgl_elem += 3;
+		}
+
+		/* set LE flag and post  */
+		__raw_writel(__raw_readl(sgl_elem-3) | 0x80000000, (sgl_elem-3));
+		i2o_post_message(iop, m);
+	}
+
+	return 0;
+}
+
+/* Functions called from the network stack, and functions called by them:
+========================================================================*/
+
+/*
+ * i2o_lan_reset(): Reset the LAN adapter into the operational state and
+ * 	restore it to full operation.
+ */
+static int i2o_lan_reset(struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	u32 msg[5];
+
+	dprintk(KERN_INFO "%s: LAN RESET MESSAGE.\n", dev->name);
+	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+	msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid;
+	msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
+	msg[3] = 0; 				 // TransactionContext
+	msg[4] = 0;				 // Keep posted buckets
+
+	if (i2o_post_this(iop, msg, sizeof(msg)) < 0)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+/*
+ * i2o_lan_suspend(): Put LAN adapter into a safe, non-active state.
+ * 	IOP replies to any LAN class message with status error_no_data_transfer
+ *	/ suspended.
+ */
+static int i2o_lan_suspend(struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	u32 msg[5];
+
+	dprintk(KERN_INFO "%s: LAN SUSPEND MESSAGE.\n", dev->name);
+	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+	msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid;
+	msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
+	msg[3] = 0; 				 // TransactionContext
+	msg[4] = 1 << 16; 			 // return posted buckets
+
+	if (i2o_post_this(iop, msg, sizeof(msg)) < 0)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+/*
+ * i2o_set_ddm_parameters:
+ * These settings are done to ensure proper initial values for DDM.
+ * They can be changed via proc file system or vai configuration utility.
+ */
+static void i2o_set_ddm_parameters(struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	u32 val;
+
+	/*
+	 * When PacketOrphanlimit is set to the maximum packet length,
+	 * the packets will never be split into two separate buckets
+	 */
+	val = dev->mtu + dev->hard_header_len;
+	if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0004, 2, &val, sizeof(val)) < 0)
+		printk(KERN_WARNING "%s: Unable to set PacketOrphanLimit.\n",
+		       dev->name);
+	else
+		dprintk(KERN_INFO "%s: PacketOrphanLimit set to %d.\n",
+			dev->name, val);
+
+	/* When RxMaxPacketsBucket = 1, DDM puts only one packet into bucket */
+
+	val = 1;
+	if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0008, 4, &val, sizeof(val)) <0)
+		printk(KERN_WARNING "%s: Unable to set RxMaxPacketsBucket.\n",
+		       dev->name);
+	else
+		dprintk(KERN_INFO "%s: RxMaxPacketsBucket set to %d.\n", 
+			dev->name, val);
+	return;
+}
+
+/* Functions called from the network stack:
+==========================================*/
+
+/*
+ * i2o_lan_open(): Open the device to send/receive packets via
+ * the network device.
+ */
+static int i2o_lan_open(struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	u32 mc_addr_group[64];
+
+	MOD_INC_USE_COUNT;
+
+	if (i2o_claim_device(i2o_dev, &i2o_lan_handler)) {
+		printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name);
+		MOD_DEC_USE_COUNT;
+		return -EAGAIN;
+	}
+	dprintk(KERN_INFO "%s: I2O LAN device (tid=%d) claimed by LAN OSM.\n",
+		dev->name, i2o_dev->lct_data.tid);
+
+	if (i2o_event_register(iop, i2o_dev->lct_data.tid,
+			       priv->unit << 16 | lan_context, 0, priv->i2o_event_mask) < 0)
+		printk(KERN_WARNING "%s: Unable to set the event mask.\n", dev->name);
+
+	i2o_lan_reset(dev);
+
+	/* Get the max number of multicast addresses */
+
+	if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0001, -1,
+			     &mc_addr_group, sizeof(mc_addr_group)) < 0 ) {
+		printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name);
+		MOD_DEC_USE_COUNT;
+		return -EAGAIN;
+	}
+	priv->max_size_mc_table = mc_addr_group[8];
+
+	/* Malloc space for free bucket list to resuse reveive post buckets */
+
+	priv->i2o_fbl = kmalloc(priv->max_buckets_out * sizeof(struct sk_buff *),
+				GFP_KERNEL);
+	if (priv->i2o_fbl == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+	priv->i2o_fbl_tail = -1;
+	priv->send_active = 0;
+
+	i2o_set_ddm_parameters(dev);
+	i2o_lan_receive_post(dev);
+
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+/*
+ * i2o_lan_close(): End the transfering.
+ */
+static int i2o_lan_close(struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	int ret = 0;
+
+	netif_stop_queue(dev);
+	i2o_lan_suspend(dev);
+
+	if (i2o_event_register(iop, i2o_dev->lct_data.tid,
+			       priv->unit << 16 | lan_context, 0, 0) < 0)
+		printk(KERN_WARNING "%s: Unable to clear the event mask.\n",
+		       dev->name);
+
+	while (priv->i2o_fbl_tail >= 0)
+		dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]);
+
+	kfree(priv->i2o_fbl);
+
+	if (i2o_release_device(i2o_dev, &i2o_lan_handler)) {
+		printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device "
+		       "(tid=%d).\n", dev->name, i2o_dev->lct_data.tid);
+		ret = -EBUSY;
+	}
+
+	MOD_DEC_USE_COUNT;
+
+	return ret;
+}
+
+/*
+ * i2o_lan_tx_timeout(): Tx timeout handler.
+ */
+static void i2o_lan_tx_timeout(struct net_device *dev)
+{
+ 	if (!netif_queue_stopped(dev))
+		netif_start_queue(dev);
+}
+
+/*
+ * i2o_lan_batch_send(): Send packets in batch. 
+ * Both i2o_lan_sdu_send and i2o_lan_packet_send use this.
+ */
+static void i2o_lan_batch_send(struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_controller *iop = priv->i2o_dev->controller;
+
+	spin_lock_irq(&priv->tx_lock);
+	if (priv->tx_count != 0) {
+		dev->trans_start = jiffies;
+		i2o_post_message(iop, priv->m);
+		dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count);
+		priv->tx_count = 0;
+	}
+	priv->send_active = 0;
+	spin_unlock_irq(&priv->tx_lock);
+	MOD_DEC_USE_COUNT;
+}
+
+#ifdef CONFIG_NET_FC
+/*
+ * i2o_lan_sdu_send(): Send a packet, MAC header added by the DDM.
+ * Must be supported by Fibre Channel, optional for Ethernet/802.3,
+ * Token Ring, FDDI
+ */
+static int i2o_lan_sdu_send(struct sk_buff *skb, struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	int tickssofar = jiffies - dev->trans_start;
+	u32 m, *msg;
+	u32 *sgl_elem;
+
+	spin_lock_irq(&priv->tx_lock);
+
+	priv->tx_count++;
+	atomic_inc(&priv->tx_out);
+
+	/* 
+	 * If tx_batch_mode = 0x00 forced to immediate mode
+	 * If tx_batch_mode = 0x01 forced to batch mode
+	 * If tx_batch_mode = 0x10 switch automatically, current mode immediate
+	 * If tx_batch_mode = 0x11 switch automatically, current mode batch
+	 *	If gap between two packets is > 0 ticks, switch to immediate
+	 */
+	if (priv->tx_batch_mode >> 1) // switch automatically
+		priv->tx_batch_mode = tickssofar ? 0x02 : 0x03;
+
+	if (priv->tx_count == 1) {
+		m = I2O_POST_READ32(iop);
+		if (m == 0xFFFFFFFF) {
+			spin_unlock_irq(&priv->tx_lock);
+			return 1;
+		}
+		msg = (u32 *)(iop->mem_offset + m);
+		priv->m = m;
+
+		__raw_writel(NINE_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg);
+		__raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1);
+		__raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext
+		__raw_writel(1 << 30 | 1 << 3, msg+3); 		 	  // TransmitControlWord
+
+		__raw_writel(0xD7000000 | skb->len, msg+4);  	     // MAC hdr included
+		__raw_writel((u32)skb, msg+5);  		     // TransactionContext
+		__raw_writel(virt_to_bus(skb->data), msg+6);
+		__raw_writel((u32)skb->mac.raw, msg+7);
+		__raw_writel((u32)skb->mac.raw+4, msg+8);
+
+		if ((priv->tx_batch_mode & 0x01) && !priv->send_active) {
+			priv->send_active = 1;
+			MOD_INC_USE_COUNT;
+			if (schedule_task(&priv->i2o_batch_send_task) == 0)
+				MOD_DEC_USE_COUNT;
+		}
+	} else {  /* Add new SGL element to the previous message frame */
+
+		msg = (u32 *)(iop->mem_offset + priv->m);
+		sgl_elem = &msg[priv->tx_count * 5 + 1];
+
+		__raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 5) | 1<<12 | SGL_OFFSET_4, msg);
+		__raw_writel(__raw_readl(sgl_elem-5) & 0x7FFFFFFF, sgl_elem-5); /* clear LE flag */
+		__raw_writel(0xD5000000 | skb->len, sgl_elem);
+		__raw_writel((u32)skb, sgl_elem+1);
+		__raw_writel(virt_to_bus(skb->data), sgl_elem+2);
+		__raw_writel((u32)(skb->mac.raw), sgl_elem+3);
+		__raw_writel((u32)(skb->mac.raw)+1, sgl_elem+4);
+	}
+
+	/* If tx not in batch mode or frame is full, send immediatelly */
+
+	if (!(priv->tx_batch_mode & 0x01) || priv->tx_count == priv->sgl_max) {
+		dev->trans_start = jiffies;
+		i2o_post_message(iop, priv->m);
+		dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count);
+		priv->tx_count = 0;
+	}
+
+	/* If DDMs TxMaxPktOut reached, stop queueing layer to send more */
+
+	if (atomic_read(&priv->tx_out) >= priv->tx_max_out)
+		netif_stop_queue(dev);
+
+	spin_unlock_irq(&priv->tx_lock);
+	return 0;
+}
+#endif /* CONFIG_NET_FC */
+
+/*
+ * i2o_lan_packet_send(): Send a packet as is, including the MAC header.
+ *
+ * Must be supported by Ethernet/802.3, Token Ring, FDDI, optional for
+ * Fibre Channel
+ */
+static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	int tickssofar = jiffies - dev->trans_start;
+	u32 m, *msg;
+	u32 *sgl_elem;
+
+	spin_lock_irq(&priv->tx_lock);
+
+	priv->tx_count++;
+	atomic_inc(&priv->tx_out);
+
+	/* 
+	 * If tx_batch_mode = 0x00 forced to immediate mode
+	 * If tx_batch_mode = 0x01 forced to batch mode
+	 * If tx_batch_mode = 0x10 switch automatically, current mode immediate
+	 * If tx_batch_mode = 0x11 switch automatically, current mode batch
+	 *	If gap between two packets is > 0 ticks, switch to immediate
+	 */
+	if (priv->tx_batch_mode >> 1) // switch automatically
+		priv->tx_batch_mode = tickssofar ? 0x02 : 0x03;
+
+	if (priv->tx_count == 1) {
+		m = I2O_POST_READ32(iop);
+		if (m == 0xFFFFFFFF) {
+			spin_unlock_irq(&priv->tx_lock);
+			return 1;
+		}
+		msg = (u32 *)(iop->mem_offset + m);
+		priv->m = m;
+
+		__raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg);
+		__raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1);
+		__raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext
+		__raw_writel(1 << 30 | 1 << 3, msg+3); 		 	  // TransmitControlWord
+			// bit 30: reply as soon as transmission attempt is complete
+			// bit 3: Suppress CRC generation
+		__raw_writel(0xD5000000 | skb->len, msg+4);  	     // MAC hdr included
+		__raw_writel((u32)skb, msg+5);  		     // TransactionContext
+		__raw_writel(virt_to_bus(skb->data), msg+6);
+
+		if ((priv->tx_batch_mode & 0x01) && !priv->send_active) {
+			priv->send_active = 1;
+			MOD_INC_USE_COUNT;
+			if (schedule_task(&priv->i2o_batch_send_task) == 0)
+				MOD_DEC_USE_COUNT;
+		}
+	} else {  /* Add new SGL element to the previous message frame */
+
+		msg = (u32 *)(iop->mem_offset + priv->m);
+		sgl_elem = &msg[priv->tx_count * 3 + 1];
+
+		__raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 3) | 1<<12 | SGL_OFFSET_4, msg);
+		__raw_writel(__raw_readl(sgl_elem-3) & 0x7FFFFFFF, sgl_elem-3); /* clear LE flag */
+		__raw_writel(0xD5000000 | skb->len, sgl_elem);
+		__raw_writel((u32)skb, sgl_elem+1);
+		__raw_writel(virt_to_bus(skb->data), sgl_elem+2);
+	}
+
+	/* If tx is in immediate mode or frame is full, send now */
+
+	if (!(priv->tx_batch_mode & 0x01) || priv->tx_count == priv->sgl_max) {
+		dev->trans_start = jiffies;
+		i2o_post_message(iop, priv->m);
+		dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count);
+		priv->tx_count = 0;
+	}
+
+	/* If DDMs TxMaxPktOut reached, stop queueing layer to send more */
+
+	if (atomic_read(&priv->tx_out) >= priv->tx_max_out)
+		netif_stop_queue(dev);
+
+	spin_unlock_irq(&priv->tx_lock);
+	return 0;
+}
+
+/*
+ * i2o_lan_get_stats(): Fill in the statistics.
+ */
+static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	u64 val64[16];
+	u64 supported_group[4] = { 0, 0, 0, 0 };
+
+	if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0100, -1, val64,
+			     sizeof(val64)) < 0)
+		printk(KERN_INFO "%s: Unable to query LAN_HISTORICAL_STATS.\n", dev->name);
+	else {
+		dprintk(KERN_DEBUG "%s: LAN_HISTORICAL_STATS queried.\n", dev->name);
+		priv->stats.tx_packets = val64[0];
+		priv->stats.tx_bytes   = val64[1];
+		priv->stats.rx_packets = val64[2];
+		priv->stats.rx_bytes   = val64[3];
+		priv->stats.tx_errors  = val64[4];
+		priv->stats.rx_errors  = val64[5];
+		priv->stats.rx_dropped = val64[6];
+	}
+
+	if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0180, -1,
+			     &supported_group, sizeof(supported_group)) < 0)
+		printk(KERN_INFO "%s: Unable to query LAN_SUPPORTED_OPTIONAL_HISTORICAL_STATS.\n", dev->name);
+
+	if (supported_group[2]) {
+		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0183, -1,
+				     val64, sizeof(val64)) < 0)
+			printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n", dev->name);
+		else {
+			dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n", dev->name);
+			priv->stats.multicast	     = val64[4];
+			priv->stats.rx_length_errors = val64[10];
+			priv->stats.rx_crc_errors    = val64[0];
+		}
+	}
+
+	if (i2o_dev->lct_data.sub_class == I2O_LAN_ETHERNET) {
+		u64 supported_stats = 0;
+		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0200, -1,
+				     val64, sizeof(val64)) < 0)
+			printk(KERN_INFO "%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n", dev->name);
+		else {
+			dprintk(KERN_DEBUG "%s: LAN_802_3_HISTORICAL_STATS queried.\n", dev->name);
+	 		priv->stats.transmit_collision = val64[1] + val64[2];
+			priv->stats.rx_frame_errors    = val64[0];
+			priv->stats.tx_carrier_errors  = val64[6];
+		}
+
+		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0280, -1,
+				     &supported_stats, sizeof(supported_stats)) < 0)
+			printk(KERN_INFO "%s: Unable to query LAN_SUPPORTED_802_3_HISTORICAL_STATS.\n", dev->name);
+
+		if (supported_stats != 0) {
+			if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0281, -1,
+					     val64, sizeof(val64)) < 0)
+				printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n", dev->name);
+			else {
+				dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n", dev->name);
+				if (supported_stats & 0x1)
+					priv->stats.rx_over_errors = val64[0];
+				if (supported_stats & 0x4)
+					priv->stats.tx_heartbeat_errors = val64[2];
+			}
+		}
+	}
+
+#ifdef CONFIG_TR
+	if (i2o_dev->lct_data.sub_class == I2O_LAN_TR) {
+		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0300, -1,
+				     val64, sizeof(val64)) < 0)
+			printk(KERN_INFO "%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n", dev->name);
+		else {
+			struct tr_statistics *stats =
+				(struct tr_statistics *)&priv->stats;
+			dprintk(KERN_DEBUG "%s: LAN_802_5_HISTORICAL_STATS queried.\n", dev->name);
+
+			stats->line_errors		= val64[0];
+			stats->internal_errors		= val64[7];
+			stats->burst_errors		= val64[4];
+			stats->A_C_errors		= val64[2];
+			stats->abort_delimiters		= val64[3];
+			stats->lost_frames		= val64[1];
+			/* stats->recv_congest_count	= ?;  FIXME ??*/
+			stats->frame_copied_errors	= val64[5];
+			stats->frequency_errors		= val64[6];
+			stats->token_errors		= val64[9];
+		}
+		/* Token Ring optional stats not yet defined */
+	}
+#endif
+
+#ifdef CONFIG_FDDI
+	if (i2o_dev->lct_data.sub_class == I2O_LAN_FDDI) {
+		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0400, -1,
+				     val64, sizeof(val64)) < 0)
+			printk(KERN_INFO "%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n", dev->name);
+		else {
+			dprintk(KERN_DEBUG "%s: LAN_FDDI_HISTORICAL_STATS queried.\n", dev->name);
+			priv->stats.smt_cf_state = val64[0];
+			memcpy(priv->stats.mac_upstream_nbr, &val64[1], FDDI_K_ALEN);
+			memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN);
+			priv->stats.mac_error_cts = val64[3];
+			priv->stats.mac_lost_cts  = val64[4];
+			priv->stats.mac_rmt_state = val64[5];
+			memcpy(priv->stats.port_lct_fail_cts, &val64[6], 8);
+			memcpy(priv->stats.port_lem_reject_cts, &val64[7], 8);
+			memcpy(priv->stats.port_lem_cts, &val64[8], 8);
+			memcpy(priv->stats.port_pcm_state, &val64[9], 8);
+		}
+		/* FDDI optional stats not yet defined */
+	}
+#endif
+
+#ifdef CONFIG_NET_FC
+	/* Fibre Channel Statistics not yet defined in 1.53 nor 2.0 */
+#endif
+
+	return (struct net_device_stats *)&priv->stats;
+}
+
+/* 
+ * i2o_lan_set_mc_filter(): Post a request to set multicast filter.
+ */
+int i2o_lan_set_mc_filter(struct net_device *dev, u32 filter_mask)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	u32 msg[10]; 
+
+	msg[0] = TEN_WORD_MSG_SIZE | SGL_OFFSET_5;
+	msg[1] = I2O_CMD_UTIL_PARAMS_SET << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid;
+	msg[2] = priv->unit << 16 | lan_context;
+	msg[3] = 0x0001 << 16 | 3 ;	// TransactionContext: group&field
+	msg[4] = 0;
+	msg[5] = 0xCC000000 | 16; 			// Immediate data SGL
+	msg[6] = 1;					// OperationCount
+	msg[7] = 0x0001<<16 | I2O_PARAMS_FIELD_SET;	// Group, Operation
+	msg[8] = 3 << 16 | 1; 				// FieldIndex, FieldCount 
+	msg[9] = filter_mask;				// Value
+
+	return i2o_post_this(iop, msg, sizeof(msg));
+}
+
+/* 
+ * i2o_lan_set_mc_table(): Post a request to set LAN_MULTICAST_MAC_ADDRESS table.
+ */
+int i2o_lan_set_mc_table(struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	struct dev_mc_list *mc;
+	u32 msg[10 + 2 * dev->mc_count]; 
+	u8 *work8 = (u8 *)(msg + 10);
+
+	msg[0] = I2O_MESSAGE_SIZE(10 + 2 * dev->mc_count) | SGL_OFFSET_5;
+	msg[1] = I2O_CMD_UTIL_PARAMS_SET << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid;
+	msg[2] = priv->unit << 16 | lan_context;	// InitiatorContext
+	msg[3] = 0x0002 << 16 | (u16)-1;		// TransactionContext
+	msg[4] = 0;					// OperationFlags
+	msg[5] = 0xCC000000 | (16 + 8 * dev->mc_count);	// Immediate data SGL
+	msg[6] = 2;					// OperationCount
+	msg[7] = 0x0002 << 16 | I2O_PARAMS_TABLE_CLEAR;	// Group, Operation
+	msg[8] = 0x0002 << 16 | I2O_PARAMS_ROW_ADD;     // Group, Operation
+	msg[9] = dev->mc_count << 16 | (u16)-1; 	// RowCount, FieldCount
+
+        for (mc = dev->mc_list; mc ; mc = mc->next, work8 += 8) {
+		  memset(work8, 0, 8);
+                  memcpy(work8, mc->dmi_addr, mc->dmi_addrlen); // Values
+	}
+
+	return i2o_post_this(iop, msg, sizeof(msg));
+}
+
+/*
+ * i2o_lan_set_multicast_list(): Enable a network device to receive packets
+ *      not send to the protocol address.
+ */
+static void i2o_lan_set_multicast_list(struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	u32 filter_mask;
+
+	if (dev->flags & IFF_PROMISC) {
+		filter_mask = 0x00000002;
+		dprintk(KERN_INFO "%s: Enabling promiscuous mode...\n", dev->name);
+	} else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > priv->max_size_mc_table) {
+		filter_mask = 0x00000004;
+		dprintk(KERN_INFO "%s: Enabling all multicast mode...\n", dev->name);
+	} else if (dev->mc_count) {
+		filter_mask = 0x00000000;
+		dprintk(KERN_INFO "%s: Enabling multicast mode...\n", dev->name);
+		if (i2o_lan_set_mc_table(dev) < 0)
+			printk(KERN_WARNING "%s: Unable to send MAC table.\n", dev->name);
+	} else {
+		filter_mask = 0x00000300; // Broadcast, Multicast disabled
+		dprintk(KERN_INFO "%s: Enabling unicast mode...\n", dev->name);
+	}
+
+	/* Finally copy new FilterMask to DDM */
+
+	if (i2o_lan_set_mc_filter(dev, filter_mask) < 0)
+		printk(KERN_WARNING "%s: Unable to send MAC FilterMask.\n", dev->name);
+}
+
+/*
+ * i2o_lan_change_mtu(): Change maximum transfer unit size.
+ */
+static int i2o_lan_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	u32 max_pkt_size;
+
+	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid,
+		 	     0x0000, 6, &max_pkt_size, 4) < 0)
+		return -EFAULT;
+
+	if (new_mtu < 68 || new_mtu > 9000 || new_mtu > max_pkt_size)
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+
+	i2o_lan_suspend(dev);   	// to SUSPENDED state, return buckets
+
+	while (priv->i2o_fbl_tail >= 0) // free buffered buckets
+		dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]);
+
+	i2o_lan_reset(dev);		// to OPERATIONAL state
+	i2o_set_ddm_parameters(dev); 	// reset some parameters
+	i2o_lan_receive_post(dev); 	// post new buckets (new size)
+
+	return 0;
+}
+
+/* Functions to initialize I2O LAN OSM:
+======================================*/
+
+/*
+ * i2o_lan_register_device(): Register LAN class device to kernel.
+ */
+struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
+{
+	struct net_device *dev = NULL;
+	struct i2o_lan_local *priv = NULL;
+	u8 hw_addr[8];
+	u32 tx_max_out = 0;
+	unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
+	void (*unregister_dev)(struct net_device *dev);
+
+	switch (i2o_dev->lct_data.sub_class) {
+	case I2O_LAN_ETHERNET:
+		dev = init_etherdev(NULL, sizeof(struct i2o_lan_local));
+		if (dev == NULL)
+			return NULL;
+		type_trans = eth_type_trans;
+		unregister_dev = unregister_netdev;
+		break;
+
+#ifdef CONFIG_ANYLAN
+	case I2O_LAN_100VG:
+		printk(KERN_ERR "i2o_lan: 100base VG not yet supported.\n");
+		return NULL;
+		break;
+#endif
+
+#ifdef CONFIG_TR
+	case I2O_LAN_TR:
+		dev = init_trdev(NULL, sizeof(struct i2o_lan_local));
+		if (dev==NULL)
+			return NULL;
+		type_trans = tr_type_trans;
+		unregister_dev = unregister_trdev;
+		break;
+#endif
+
+#ifdef CONFIG_FDDI
+	case I2O_LAN_FDDI:
+	{
+		int size = sizeof(struct net_device) + sizeof(struct i2o_lan_local);
+
+		dev = (struct net_device *) kmalloc(size, GFP_KERNEL);
+		if (dev == NULL)
+			return NULL;
+		memset((char *)dev, 0, size);
+	    	dev->priv = (void *)(dev + 1);
+
+		if (dev_alloc_name(dev, "fddi%d") < 0) {
+			printk(KERN_WARNING "i2o_lan: Too many FDDI devices.\n");
+			kfree(dev);
+			return NULL;
+		}
+		type_trans = fddi_type_trans;
+		unregister_dev = (void *)unregister_netdevice;
+
+		fddi_setup(dev);
+		register_netdev(dev);
+	}
+	break;
+#endif
+
+#ifdef CONFIG_NET_FC
+	case I2O_LAN_FIBRE_CHANNEL:
+		dev = init_fcdev(NULL, sizeof(struct i2o_lan_local));
+		if (dev == NULL)
+			return NULL;
+		type_trans = NULL;
+/* FIXME: Move fc_type_trans() from drivers/net/fc/iph5526.c to net/802/fc.c
+ * and export it in include/linux/fcdevice.h
+ *		type_trans = fc_type_trans;
+ */
+		unregister_dev = (void *)unregister_fcdev;
+		break;
+#endif
+
+	case I2O_LAN_UNKNOWN:
+	default:
+		printk(KERN_ERR "i2o_lan: LAN type 0x%04x not supported.\n",
+		       i2o_dev->lct_data.sub_class);
+		return NULL;
+	}
+
+	priv = (struct i2o_lan_local *)dev->priv;
+	priv->i2o_dev = i2o_dev;
+	priv->type_trans = type_trans;
+	priv->sgl_max = (i2o_dev->controller->status_block->inbound_frame_size - 4) / 3;
+	atomic_set(&priv->buckets_out, 0);
+
+	/* Set default values for user configurable parameters */
+	/* Private values are changed via /proc file system */
+
+	priv->max_buckets_out = max_buckets_out;
+	priv->bucket_thresh   = bucket_thresh;
+	priv->rx_copybreak    = rx_copybreak;
+	priv->tx_batch_mode   = tx_batch_mode & 0x03;
+	priv->i2o_event_mask  = i2o_event_mask;
+
+	priv->tx_lock	      = SPIN_LOCK_UNLOCKED;
+	priv->fbl_lock	      = SPIN_LOCK_UNLOCKED;
+
+	unit++;
+	i2o_landevs[unit] = dev;
+	priv->unit = unit;
+
+	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid,
+			     0x0001, 0, &hw_addr, sizeof(hw_addr)) < 0) {
+		printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name);
+		unit--;
+		unregister_dev(dev);
+		kfree(dev);
+		return NULL;
+	}
+	dprintk(KERN_DEBUG "%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ 		dev->name, hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3],
+		hw_addr[4], hw_addr[5]);
+
+	dev->addr_len = 6;
+	memcpy(dev->dev_addr, hw_addr, 6);
+
+	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid,
+			     0x0007, 2, &tx_max_out, sizeof(tx_max_out)) < 0) {
+		printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name);
+		unit--;
+		unregister_dev(dev);
+		kfree(dev);
+		return NULL;
+	}
+	dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max_out);
+	priv->tx_max_out = tx_max_out;
+	atomic_set(&priv->tx_out, 0);
+	priv->tx_count = 0;
+
+	INIT_LIST_HEAD(&priv->i2o_batch_send_task.list);
+	priv->i2o_batch_send_task.sync    = 0;
+	priv->i2o_batch_send_task.routine = (void *)i2o_lan_batch_send;
+	priv->i2o_batch_send_task.data    = (void *)dev;
+
+	dev->open		= i2o_lan_open;
+	dev->stop		= i2o_lan_close;
+	dev->get_stats		= i2o_lan_get_stats;
+	dev->set_multicast_list = i2o_lan_set_multicast_list;
+	dev->tx_timeout		= i2o_lan_tx_timeout;
+	dev->watchdog_timeo	= I2O_LAN_TX_TIMEOUT;
+
+#ifdef CONFIG_NET_FC
+	if (i2o_dev->lct_data.sub_class == I2O_LAN_FIBRE_CHANNEL)
+		dev->hard_start_xmit = i2o_lan_sdu_send;
+	else
+#endif
+		dev->hard_start_xmit = i2o_lan_packet_send;
+
+	if (i2o_dev->lct_data.sub_class == I2O_LAN_ETHERNET)
+		dev->change_mtu	= i2o_lan_change_mtu;
+
+	return dev;
+}
+
+#ifdef MODULE
+#define i2o_lan_init	init_module
+#endif
+
+int __init i2o_lan_init(void)
+{
+	struct net_device *dev;
+	int i;
+
+	printk(KERN_INFO "I2O LAN OSM (C) 1999 University of Helsinki.\n");
+
+	/* Module params are used as global defaults for private values */
+
+	if (max_buckets_out > I2O_LAN_MAX_BUCKETS_OUT)
+		max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT;
+	if (bucket_thresh > max_buckets_out)
+		bucket_thresh = max_buckets_out;
+
+	/* Install handlers for incoming replies */
+
+	if (i2o_install_handler(&i2o_lan_send_handler) < 0) {
+ 		printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n");
+		return -EINVAL;
+	}
+	lan_send_context = i2o_lan_send_handler.context;
+
+	if (i2o_install_handler(&i2o_lan_receive_handler) < 0) {
+ 		printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n");
+		return -EINVAL;
+	}
+	lan_receive_context = i2o_lan_receive_handler.context;
+
+	if (i2o_install_handler(&i2o_lan_handler) < 0) {
+ 		printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n");
+		return -EINVAL;
+	}
+	lan_context = i2o_lan_handler.context;
+
+	for(i=0; i <= MAX_LAN_CARDS; i++)
+		i2o_landevs[i] = NULL;
+
+	for (i=0; i < MAX_I2O_CONTROLLERS; i++) {
+		struct i2o_controller *iop = i2o_find_controller(i);
+		struct i2o_device *i2o_dev;
+
+		if (iop==NULL)
+			continue;
+
+		for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next) {
+
+			if (i2o_dev->lct_data.class_id != I2O_CLASS_LAN)
+				continue;
+
+			/* Make sure device not already claimed by an ISM */
+			if (i2o_dev->lct_data.user_tid != 0xFFF)
+				continue;
+
+			if (unit == MAX_LAN_CARDS) {
+				i2o_unlock_controller(iop);
+				printk(KERN_WARNING "i2o_lan: Too many I2O LAN devices.\n");
+				return -EINVAL;
+			}
+
+			dev = i2o_lan_register_device(i2o_dev);
+ 			if (dev == NULL) {
+				printk(KERN_ERR "i2o_lan: Unable to register I2O LAN device 0x%04x.\n",
+				       i2o_dev->lct_data.sub_class);
+				continue;
+			}
+
+			printk(KERN_INFO "%s: I2O LAN device registered, "
+				"subclass = 0x%04x, unit = %d, tid = %d.\n",
+				dev->name, i2o_dev->lct_data.sub_class,
+				((struct i2o_lan_local *)dev->priv)->unit,
+				i2o_dev->lct_data.tid);
+		}
+
+		i2o_unlock_controller(iop);
+	}
+
+	dprintk(KERN_INFO "%d I2O LAN devices found and registered.\n", unit+1);
+
+	return 0;
+}
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+	int i;
+
+	for (i = 0; i <= unit; i++) {
+		struct net_device *dev = i2o_landevs[i];
+		struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+		struct i2o_device *i2o_dev = priv->i2o_dev;
+
+		switch (i2o_dev->lct_data.sub_class) {
+		case I2O_LAN_ETHERNET:
+			unregister_netdev(dev);
+			break;
+#ifdef CONFIG_FDDI
+		case I2O_LAN_FDDI:
+			unregister_netdevice(dev);
+			break;
+#endif
+#ifdef CONFIG_TR
+		case I2O_LAN_TR:
+			unregister_trdev(dev);
+			break;
+#endif
+#ifdef CONFIG_NET_FC
+		case I2O_LAN_FIBRE_CHANNEL:
+			unregister_fcdev(dev);
+			break;
+#endif
+		default:
+			printk(KERN_WARNING "%s: Spurious I2O LAN subclass 0x%08x.\n",
+			       dev->name, i2o_dev->lct_data.sub_class);
+		}
+
+		dprintk(KERN_INFO "%s: I2O LAN device unregistered.\n",
+			dev->name);
+		kfree(dev);
+	}
+
+	i2o_remove_handler(&i2o_lan_handler);
+	i2o_remove_handler(&i2o_lan_send_handler);
+	i2o_remove_handler(&i2o_lan_receive_handler);
+}
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("University of Helsinki, Department of Computer Science");
+MODULE_DESCRIPTION("I2O Lan OSM");
+
+MODULE_PARM(max_buckets_out, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i");
+MODULE_PARM_DESC(max_buckets_out, "Total number of buckets to post (1-)");
+MODULE_PARM(bucket_thresh, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i");
+MODULE_PARM_DESC(bucket_thresh, "Bucket post threshold (1-)");
+MODULE_PARM(rx_copybreak, "1-" "i");
+MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy only small frames (1-)");
+MODULE_PARM(tx_batch_mode, "0-2" "i");
+MODULE_PARM_DESC(tx_batch_mode, "0=Send immediatelly, 1=Send in batches, 2=Switch automatically");
+
+#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/i2o_lan.h linux/drivers/message/i2o/i2o_lan.h
--- v2.4.12/linux/drivers/message/i2o/i2o_lan.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/i2o_lan.h	Mon Dec 11 13:20:00 2000
@@ -0,0 +1,159 @@
+/*
+ *   	i2o_lan.h			I2O LAN Class definitions
+ *
+ *      I2O LAN CLASS OSM       	May 26th 2000
+ *
+ *      (C) Copyright 1999, 2000	University of Helsinki,
+ *					Department of Computer Science
+ *
+ *      This code is still under development / test.
+ *
+ *	Author:		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *			Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *			Taneli Vähäkangas <Taneli.Vahakangas@cs.Helsinki.FI>
+ */
+
+#ifndef _I2O_LAN_H
+#define _I2O_LAN_H
+
+/* Default values for tunable parameters first */
+
+#define I2O_LAN_MAX_BUCKETS_OUT 96
+#define I2O_LAN_BUCKET_THRESH	18	/* 9 buckets in one message */
+#define I2O_LAN_RX_COPYBREAK	200
+#define I2O_LAN_TX_TIMEOUT 	(1*HZ)
+#define I2O_LAN_TX_BATCH_MODE	2	/* 2=automatic, 1=on, 0=off */
+#define I2O_LAN_EVENT_MASK	0	/* 0=None, 0xFFC00002=All */
+
+/* LAN types */
+#define I2O_LAN_ETHERNET	0x0030
+#define I2O_LAN_100VG		0x0040
+#define I2O_LAN_TR		0x0050
+#define I2O_LAN_FDDI		0x0060
+#define I2O_LAN_FIBRE_CHANNEL	0x0070
+#define I2O_LAN_UNKNOWN		0x00000000
+
+/* Connector types */
+
+/* Ethernet */
+#define I2O_LAN_AUI		(I2O_LAN_ETHERNET << 4) + 0x00000001
+#define I2O_LAN_10BASE5		(I2O_LAN_ETHERNET << 4) + 0x00000002
+#define I2O_LAN_FIORL		(I2O_LAN_ETHERNET << 4) + 0x00000003
+#define I2O_LAN_10BASE2		(I2O_LAN_ETHERNET << 4) + 0x00000004
+#define I2O_LAN_10BROAD36	(I2O_LAN_ETHERNET << 4) + 0x00000005
+#define I2O_LAN_10BASE_T	(I2O_LAN_ETHERNET << 4) + 0x00000006
+#define I2O_LAN_10BASE_FP	(I2O_LAN_ETHERNET << 4) + 0x00000007
+#define I2O_LAN_10BASE_FB	(I2O_LAN_ETHERNET << 4) + 0x00000008
+#define I2O_LAN_10BASE_FL	(I2O_LAN_ETHERNET << 4) + 0x00000009
+#define I2O_LAN_100BASE_TX	(I2O_LAN_ETHERNET << 4) + 0x0000000A
+#define I2O_LAN_100BASE_FX	(I2O_LAN_ETHERNET << 4) + 0x0000000B
+#define I2O_LAN_100BASE_T4	(I2O_LAN_ETHERNET << 4) + 0x0000000C
+#define I2O_LAN_1000BASE_SX	(I2O_LAN_ETHERNET << 4) + 0x0000000D
+#define I2O_LAN_1000BASE_LX	(I2O_LAN_ETHERNET << 4) + 0x0000000E
+#define I2O_LAN_1000BASE_CX	(I2O_LAN_ETHERNET << 4) + 0x0000000F
+#define I2O_LAN_1000BASE_T	(I2O_LAN_ETHERNET << 4) + 0x00000010
+
+/* AnyLAN */
+#define I2O_LAN_100VG_ETHERNET	(I2O_LAN_100VG << 4) + 0x00000001
+#define I2O_LAN_100VG_TR	(I2O_LAN_100VG << 4) + 0x00000002
+
+/* Token Ring */
+#define I2O_LAN_4MBIT		(I2O_LAN_TR << 4) + 0x00000001
+#define I2O_LAN_16MBIT		(I2O_LAN_TR << 4) + 0x00000002
+
+/* FDDI */
+#define I2O_LAN_125MBAUD	(I2O_LAN_FDDI << 4) + 0x00000001
+
+/* Fibre Channel */
+#define I2O_LAN_POINT_POINT	(I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000001
+#define I2O_LAN_ARB_LOOP	(I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000002
+#define I2O_LAN_PUBLIC_LOOP	(I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000003
+#define I2O_LAN_FABRIC		(I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000004
+
+#define I2O_LAN_EMULATION	0x00000F00
+#define I2O_LAN_OTHER		0x00000F01
+#define I2O_LAN_DEFAULT		0xFFFFFFFF
+
+/* LAN class functions */
+
+#define LAN_PACKET_SEND		0x3B
+#define LAN_SDU_SEND		0x3D
+#define LAN_RECEIVE_POST	0x3E
+#define LAN_RESET		0x35
+#define LAN_SUSPEND		0x37
+
+/* LAN DetailedStatusCode defines */
+#define I2O_LAN_DSC_SUCCESS			0x00
+#define I2O_LAN_DSC_DEVICE_FAILURE		0x01
+#define I2O_LAN_DSC_DESTINATION_NOT_FOUND	0x02
+#define	I2O_LAN_DSC_TRANSMIT_ERROR		0x03
+#define I2O_LAN_DSC_TRANSMIT_ABORTED		0x04
+#define I2O_LAN_DSC_RECEIVE_ERROR		0x05
+#define I2O_LAN_DSC_RECEIVE_ABORTED		0x06
+#define I2O_LAN_DSC_DMA_ERROR			0x07
+#define I2O_LAN_DSC_BAD_PACKET_DETECTED		0x08
+#define I2O_LAN_DSC_OUT_OF_MEMORY		0x09
+#define I2O_LAN_DSC_BUCKET_OVERRUN		0x0A
+#define I2O_LAN_DSC_IOP_INTERNAL_ERROR		0x0B
+#define I2O_LAN_DSC_CANCELED			0x0C
+#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT	0x0D
+#define I2O_LAN_DSC_DEST_ADDRESS_DETECTED	0x0E
+#define I2O_LAN_DSC_DEST_ADDRESS_OMITTED	0x0F
+#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED	0x10
+#define I2O_LAN_DSC_SUSPENDED			0x11
+
+struct i2o_packet_info {
+	u32 offset : 24;
+	u32 flags  : 8;
+	u32 len    : 24;
+	u32 status : 8;
+};
+
+struct i2o_bucket_descriptor {
+	u32 context; 			/* FIXME: 64bit support */
+	struct i2o_packet_info packet_info[1];
+};
+
+/* Event Indicator Mask Flags for LAN OSM */
+
+#define I2O_LAN_EVT_LINK_DOWN		0x01
+#define I2O_LAN_EVT_LINK_UP		0x02
+#define I2O_LAN_EVT_MEDIA_CHANGE 	0x04
+
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+
+struct i2o_lan_local {
+	u8 unit;
+	struct i2o_device *i2o_dev;
+
+	struct fddi_statistics stats;   /* see also struct net_device_stats */
+	unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
+	atomic_t buckets_out;  		/* nbr of unused buckets on DDM */
+	atomic_t tx_out;		/* outstanding TXes */
+	u8 tx_count;  			/* packets in one TX message frame */
+	u16 tx_max_out;	   		/* DDM's Tx queue len */
+	u8 sgl_max;			/* max SGLs in one message frame */
+	u32 m;				/* IOP address of the batch msg frame */
+
+	struct tq_struct i2o_batch_send_task;
+	int send_active;
+	struct sk_buff **i2o_fbl;	/* Free bucket list (to reuse skbs) */
+	int i2o_fbl_tail;
+	spinlock_t fbl_lock;
+
+	spinlock_t tx_lock;
+
+	u32 max_size_mc_table;		/* max number of multicast addresses */
+
+	/* LAN OSM configurable parameters are here: */
+
+	u16 max_buckets_out;		/* max nbr of buckets to send to DDM */
+	u16 bucket_thresh;		/* send more when this many used */
+	u16 rx_copybreak;
+
+	u8  tx_batch_mode;		/* Set when using batch mode sends */
+	u32 i2o_event_mask;		/* To turn on interesting event flags */
+};
+
+#endif /* _I2O_LAN_H */
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/i2o_pci.c linux/drivers/message/i2o/i2o_pci.c
--- v2.4.12/linux/drivers/message/i2o/i2o_pci.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/i2o_pci.c	Fri Oct 19 08:32:28 2001
@@ -0,0 +1,377 @@
+/*
+ *	Find I2O capable controllers on the PCI bus, and register/install
+ *	them with the I2O layer
+ *
+ *	(C) Copyright 1999   Red Hat Software
+ *	
+ *	Written by Alan Cox, Building Number Three Ltd
+ * 	Modified by Deepak Saxena <deepak@plexity.net>
+ * 	Modified by Boji T Kannanthanam <boji.t.kannanthanam@intel.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.
+ *
+ *	TODO:
+ *		Support polled I2O PCI controllers. 
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/i2o.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif // CONFIG_MTRR
+
+#ifdef MODULE
+/*
+ * Core function table
+ * See <include/linux/i2o.h> for an explanation
+ */
+static struct i2o_core_func_table *core;
+
+/* Core attach function */
+extern int i2o_pci_core_attach(struct i2o_core_func_table *);
+extern void i2o_pci_core_detach(void);
+#endif /* MODULE */
+
+/*
+ *	Free bus specific resources
+ */
+static void i2o_pci_dispose(struct i2o_controller *c)
+{
+	I2O_IRQ_WRITE32(c,0xFFFFFFFF);
+	if(c->bus.pci.irq > 0)
+		free_irq(c->bus.pci.irq, c);
+	iounmap(((u8 *)c->post_port)-0x40);
+
+#ifdef CONFIG_MTRR
+	if(c->bus.pci.mtrr_reg0 > 0)
+		mtrr_del(c->bus.pci.mtrr_reg0, 0, 0);
+	if(c->bus.pci.mtrr_reg1 > 0)
+		mtrr_del(c->bus.pci.mtrr_reg1, 0, 0);
+#endif
+}
+
+/*
+ *	No real bus specific handling yet (note that later we will
+ *	need to 'steal' PCI devices on i960 mainboards)
+ */
+ 
+static int i2o_pci_bind(struct i2o_controller *c, struct i2o_device *dev)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int i2o_pci_unbind(struct i2o_controller *c, struct i2o_device *dev)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * Bus specific enable/disable functions
+ */
+static void i2o_pci_enable(struct i2o_controller *c)
+{
+	I2O_IRQ_WRITE32(c, 0);
+	c->enabled = 1;
+}
+
+static void i2o_pci_disable(struct i2o_controller *c)
+{
+	I2O_IRQ_WRITE32(c, 0xFFFFFFFF);
+	c->enabled = 0;
+}
+
+/*
+ *	Bus specific interrupt handler
+ */
+ 
+static void i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r)
+{
+	struct i2o_controller *c = dev_id;
+#ifdef MODULE
+	core->run_queue(c);
+#else
+	i2o_run_queue(c);
+#endif /* MODULE */
+}	
+
+/*
+ *	Install a PCI (or in theory AGP) i2o controller
+ *
+ * TODO: Add support for polled controllers
+ */
+int __init i2o_pci_install(struct pci_dev *dev)
+{
+	struct i2o_controller *c=kmalloc(sizeof(struct i2o_controller),
+						GFP_KERNEL);
+	u8 *mem;
+	u32 memptr = 0;
+	u32 size;
+	
+	int i;
+
+	if(c==NULL)
+	{
+		printk(KERN_ERR "i2o: Insufficient memory to add controller.\n");
+		return -ENOMEM;
+	}
+	memset(c, 0, sizeof(*c));
+
+	for(i=0; i<6; i++)
+	{
+		/* Skip I/O spaces */
+		if(!(pci_resource_flags(dev, i) & IORESOURCE_IO))
+		{
+			memptr = pci_resource_start(dev, i);
+			break;
+		}
+	}
+	
+	if(i==6)
+	{
+		printk(KERN_ERR "i2o: I2O controller has no memory regions defined.\n");
+		kfree(c);
+		return -EINVAL;
+	}
+	
+	size = dev->resource[i].end-dev->resource[i].start+1;	
+	/* Map the I2O controller */
+	
+	printk(KERN_INFO "i2o: PCI I2O controller at 0x%08X size=%d\n", memptr, size);
+	mem = ioremap(memptr, size);
+	if(mem==NULL)
+	{
+		printk(KERN_ERR "i2o: Unable to map controller.\n");
+		kfree(c);
+		return -EINVAL;
+	}
+
+	c->bus.pci.irq = -1;
+	c->bus.pci.queue_buggy = 0;
+	c->bus.pci.dpt = 0;
+	c->bus.pci.short_req = 0;
+	c->pdev = dev;
+
+	c->irq_mask = (volatile u32 *)(mem+0x34);
+	c->post_port = (volatile u32 *)(mem+0x40);
+	c->reply_port = (volatile u32 *)(mem+0x44);
+
+	c->mem_phys = memptr;
+	c->mem_offset = (u32)mem;
+	c->destructor = i2o_pci_dispose;
+	
+	c->bind = i2o_pci_bind;
+	c->unbind = i2o_pci_unbind;
+	c->bus_enable = i2o_pci_enable;
+	c->bus_disable = i2o_pci_disable;
+	
+	c->type = I2O_TYPE_PCI;
+
+	/*
+	 *	Cards that fall apart if you hit them with large I/O
+	 *	loads...
+	 */
+	 
+	if(dev->vendor == PCI_VENDOR_ID_NCR && dev->device == 0x0630)
+	{
+		c->bus.pci.short_req=1;
+		printk(KERN_INFO "I2O: Symbios FC920 workarounds activated.\n");
+	}
+	if(dev->subsystem_vendor == PCI_VENDOR_ID_PROMISE)
+	{
+		c->bus.pci.queue_buggy=1;
+		printk(KERN_INFO "I2O: Promise workarounds activated.\n");
+	}
+
+	/*
+	 *	Cards that go bananas if you quiesce them before you reset
+	 *	them
+	 */
+	 
+	if(dev->vendor == PCI_VENDOR_ID_DPT)
+		c->bus.pci.dpt=1;
+	
+	/* 
+	 * Enable Write Combining MTRR for IOP's memory region
+	 */
+#ifdef CONFIG_MTRR
+	c->bus.pci.mtrr_reg0 =
+		mtrr_add(c->mem_phys, size, MTRR_TYPE_WRCOMB, 1);
+/*
+* If it is an INTEL i960 I/O processor then set the first 64K to Uncacheable
+* since the region contains the Messaging unit which shouldn't be cached.
+*/
+	c->bus.pci.mtrr_reg1 = -1;
+	if(dev->vendor == PCI_VENDOR_ID_INTEL || dev->vendor == PCI_VENDOR_ID_DPT)
+	{
+		printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); 
+		c->bus.pci.mtrr_reg1 =	mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1);
+		if(c->bus.pci.mtrr_reg1< 0)
+			printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n");
+	}
+
+#endif
+
+	I2O_IRQ_WRITE32(c,0xFFFFFFFF);
+
+#ifdef MODULE
+	i = core->install(c);
+#else
+	i = i2o_install_controller(c);
+#endif /* MODULE */
+	
+	if(i<0)
+	{
+		printk(KERN_ERR "i2o: Unable to install controller.\n");
+		kfree(c);
+		iounmap(mem);
+		return i;
+	}
+
+	c->bus.pci.irq = dev->irq;
+	if(c->bus.pci.irq)
+	{
+		i=request_irq(dev->irq, i2o_pci_interrupt, SA_SHIRQ,
+			c->name, c);
+		if(i<0)
+		{
+			printk(KERN_ERR "%s: unable to allocate interrupt %d.\n",
+				c->name, dev->irq);
+			c->bus.pci.irq = -1;
+#ifdef MODULE
+			core->delete(c);
+#else
+			i2o_delete_controller(c);
+#endif /* MODULE */	
+			iounmap(mem);
+			return -EBUSY;
+		}
+	}
+
+	printk(KERN_INFO "%s: Installed at IRQ%d\n", c->name, dev->irq);
+	I2O_IRQ_WRITE32(c,0x0);
+	c->enabled = 1;
+	return 0;	
+}
+
+int __init i2o_pci_scan(void)
+{
+	struct pci_dev *dev;
+	int count=0;
+	
+	printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
+
+	pci_for_each_dev(dev)	
+	{
+		if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O)
+			continue;
+		if((dev->class&0xFF)>1)
+		{
+			printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n");
+			continue;
+		}
+		if (pci_enable_device(dev))
+			continue;
+		printk(KERN_INFO "i2o: I2O controller on bus %d at %d.\n",
+			dev->bus->number, dev->devfn);
+		pci_set_master(dev);
+		if(i2o_pci_install(dev)==0)
+			count++;
+	}
+	if(count)
+		printk(KERN_INFO "i2o: %d I2O controller%s found and installed.\n", count,
+			count==1?"":"s");
+	return count?count:-ENODEV;
+}
+
+#ifdef I2O_HOTPLUG_SUPPORT
+/*
+ * Activate a newly found PCI I2O controller
+ * Not used now, but will be needed in future for
+ * hot plug PCI support
+ */
+static void i2o_pci_activate(i2o_controller * c)
+{
+	int i=0;
+	struct i2o_controller *c;
+	
+	if(c->type == I2O_TYPE_PCI)
+	{
+		I2O_IRQ_WRITE32(c,0);
+#ifdef MODULE
+		if(core->activate(c))
+#else
+		if(i2o_activate_controller(c))
+#endif /* MODULE */
+		{
+			printk("%s: Failed to initialize.\n", c->name);
+#ifdef MODULE
+			core->unlock(c);
+			core->delete(c);
+#else
+			i2o_unlock_controller(c);
+			i2o_delete_controller(c);
+#endif
+			continue;
+		}
+	}
+}
+#endif // I2O_HOTPLUG_SUPPORT
+
+#ifdef MODULE
+
+int i2o_pci_core_attach(struct i2o_core_func_table *table)
+{
+	MOD_INC_USE_COUNT;
+
+	core = table;
+
+	return i2o_pci_scan();
+}
+
+void i2o_pci_core_detach(void)
+{
+	core = NULL;
+
+	MOD_DEC_USE_COUNT;
+}
+
+int init_module(void)
+{
+	printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
+	
+	core = NULL;
+
+ 	return 0;
+ 
+}
+
+void cleanup_module(void)
+{
+}
+
+EXPORT_SYMBOL(i2o_pci_core_attach);
+EXPORT_SYMBOL(i2o_pci_core_detach);
+
+MODULE_AUTHOR("Red Hat Software");
+MODULE_DESCRIPTION("I2O PCI Interface");
+
+#else
+void __init i2o_pci_init(void)
+{
+	printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
+	i2o_pci_scan();
+}
+#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/i2o_proc.c linux/drivers/message/i2o/i2o_proc.c
--- v2.4.12/linux/drivers/message/i2o/i2o_proc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/i2o_proc.c	Sun Aug 12 11:16:18 2001
@@ -0,0 +1,3379 @@
+/*
+ *   procfs handler for Linux I2O subsystem
+ *
+ *   (c) Copyright 1999 Deepak Saxena
+ *   
+ *   Originally written by Deepak Saxena(deepak@plexity.net)
+ *
+ *   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 is an initial test release. The code is based on the design
+ *   of the ide procfs system (drivers/block/ide-proc.c). Some code
+ *   taken from i2o-core module by Alan Cox.
+ *
+ *   DISCLAIMER: This code is still under development/test and may cause
+ *   your system to behave unpredictably.  Use at your own discretion.
+ *
+ *   LAN entries by Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI),
+ *		    Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI)
+ *   University of Helsinki, Department of Computer Science
+ */
+
+/*
+ * set tabstop=3
+ */
+
+/*
+ * TODO List
+ *
+ * - Add support for any version 2.0 spec changes once 2.0 IRTOS is
+ *   is available to test with
+ * - Clean up code to use official structure definitions 
+ */
+
+// FIXME!
+#define FMT_U64_HEX "0x%08x%08x"
+#define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64))
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/i2o.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+#include "i2o_lan.h"
+
+/*
+ * Structure used to define /proc entries
+ */
+typedef struct _i2o_proc_entry_t
+{
+	char *name;			/* entry name */
+	mode_t mode;			/* mode */
+	read_proc_t *read_proc;		/* read func */
+	write_proc_t *write_proc;	/* write func */
+} i2o_proc_entry;
+
+// #define DRIVERDEBUG
+
+static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_status(char *, char **, off_t, int, int *, void *);
+
+static int i2o_proc_read_hw(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_ddm_table(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_driver_store(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_drivers_stored(char *, char **, off_t, int, int *, void *);
+
+static int i2o_proc_read_groups(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_phys_device(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_claimed(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_users(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_priv_msgs(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_authorized_users(char *, char **, off_t, int, int *, void *);
+
+static int i2o_proc_read_dev_name(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_dev_identity(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_ddm_identity(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_uinfo(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_sgl_limits(char *, char **, off_t, int, int *, void *);
+
+static int i2o_proc_read_sensors(char *, char **, off_t, int, int *, void *);
+
+static int print_serial_number(char *, int, u8 *, int);
+
+static int i2o_proc_create_entries(void *, i2o_proc_entry *,
+				   struct proc_dir_entry *);
+static void i2o_proc_remove_entries(i2o_proc_entry *, struct proc_dir_entry *);
+static int i2o_proc_add_controller(struct i2o_controller *, 
+				   struct proc_dir_entry * );
+static void i2o_proc_remove_controller(struct i2o_controller *, 
+				       struct proc_dir_entry * );
+static void i2o_proc_add_device(struct i2o_device *, struct proc_dir_entry *);
+static void i2o_proc_remove_device(struct i2o_device *);
+static int create_i2o_procfs(void);
+static int destroy_i2o_procfs(void);
+static void i2o_proc_new_dev(struct i2o_controller *, struct i2o_device *);
+static void i2o_proc_dev_del(struct i2o_controller *, struct i2o_device *);
+
+static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *,
+				      void *);
+static int i2o_proc_read_lan_mac_addr(char *, char **, off_t, int, int *,
+				      void *);
+static int i2o_proc_read_lan_mcast_addr(char *, char **, off_t, int, int *,
+					void *);
+static int i2o_proc_read_lan_batch_control(char *, char **, off_t, int, int *,
+					   void *);
+static int i2o_proc_read_lan_operation(char *, char **, off_t, int, int *,
+				       void *);
+static int i2o_proc_read_lan_media_operation(char *, char **, off_t, int,
+					     int *, void *);
+static int i2o_proc_read_lan_alt_addr(char *, char **, off_t, int, int *,
+				      void *);
+static int i2o_proc_read_lan_tx_info(char *, char **, off_t, int, int *,
+				     void *);
+static int i2o_proc_read_lan_rx_info(char *, char **, off_t, int, int *,
+				     void *);
+static int i2o_proc_read_lan_hist_stats(char *, char **, off_t, int, int *,
+					void *);
+static int i2o_proc_read_lan_eth_stats(char *, char **, off_t, int,
+				       int *, void *);
+static int i2o_proc_read_lan_tr_stats(char *, char **, off_t, int, int *,
+				      void *);
+static int i2o_proc_read_lan_fddi_stats(char *, char **, off_t, int, int *,
+					void *);
+
+static struct proc_dir_entry *i2o_proc_dir_root;
+
+/*
+ * I2O OSM descriptor
+ */
+static struct i2o_handler i2o_proc_handler =
+{
+	NULL,
+	i2o_proc_new_dev,
+	i2o_proc_dev_del,
+	NULL,
+	"I2O procfs Layer",
+	0,
+	0xffffffff	// All classes
+};
+
+/*
+ * IOP specific entries...write field just in case someone 
+ * ever wants one.
+ */
+static i2o_proc_entry generic_iop_entries[] = 
+{
+	{"hrt", S_IFREG|S_IRUGO, i2o_proc_read_hrt, NULL},
+	{"lct", S_IFREG|S_IRUGO, i2o_proc_read_lct, NULL},
+	{"status", S_IFREG|S_IRUGO, i2o_proc_read_status, NULL},
+	{"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL},
+	{"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, NULL},
+	{"driver_store", S_IFREG|S_IRUGO, i2o_proc_read_driver_store, NULL},
+	{"drivers_stored", S_IFREG|S_IRUGO, i2o_proc_read_drivers_stored, NULL},
+	{NULL, 0, NULL, NULL}
+};
+
+/*
+ * Device specific entries
+ */
+static i2o_proc_entry generic_dev_entries[] = 
+{
+	{"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL},
+	{"phys_dev", S_IFREG|S_IRUGO, i2o_proc_read_phys_device, NULL},
+	{"claimed", S_IFREG|S_IRUGO, i2o_proc_read_claimed, NULL},
+	{"users", S_IFREG|S_IRUGO, i2o_proc_read_users, NULL},
+	{"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, NULL},
+	{"authorized_users", S_IFREG|S_IRUGO, i2o_proc_read_authorized_users, NULL},
+	{"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev_identity, NULL},
+	{"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm_identity, NULL},
+	{"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL},
+	{"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL},
+	{"sensors", S_IFREG|S_IRUGO, i2o_proc_read_sensors, NULL},
+	{NULL, 0, NULL, NULL}
+};
+
+/*
+ *  Storage unit specific entries (SCSI Periph, BS) with device names
+ */
+static i2o_proc_entry rbs_dev_entries[] = 
+{
+	{"dev_name", S_IFREG|S_IRUGO, i2o_proc_read_dev_name, NULL},
+	{NULL, 0, NULL, NULL}
+};
+
+#define SCSI_TABLE_SIZE	13
+static char *scsi_devices[] = 
+{
+	"Direct-Access Read/Write",
+	"Sequential-Access Storage",
+	"Printer",
+	"Processor",
+	"WORM Device",
+	"CD-ROM Device",
+	"Scanner Device",
+	"Optical Memory Device",
+	"Medium Changer Device",
+	"Communications Device",
+	"Graphics Art Pre-Press Device",
+	"Graphics Art Pre-Press Device",
+	"Array Controller Device"
+};
+
+/* private */
+
+/*
+ * Generic LAN specific entries
+ * 
+ * Should groups with r/w entries have their own subdirectory?
+ *
+ */
+static i2o_proc_entry lan_entries[] = 
+{
+	{"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL},
+	{"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL},
+	{"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR,
+	 i2o_proc_read_lan_mcast_addr, NULL},
+	{"lan_batch_ctrl", S_IFREG|S_IRUGO|S_IWUSR,
+	 i2o_proc_read_lan_batch_control, NULL},
+	{"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL},
+	{"lan_media_operation", S_IFREG|S_IRUGO,
+	 i2o_proc_read_lan_media_operation, NULL},
+	{"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL},
+	{"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL},
+	{"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL},
+
+	{"lan_hist_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL},
+	{NULL, 0, NULL, NULL}
+};
+
+/*
+ * Port specific LAN entries
+ * 
+ */
+static i2o_proc_entry lan_eth_entries[] = 
+{
+	{"lan_eth_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL},
+	{NULL, 0, NULL, NULL}
+};
+
+static i2o_proc_entry lan_tr_entries[] = 
+{
+	{"lan_tr_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_tr_stats, NULL},
+	{NULL, 0, NULL, NULL}
+};
+
+static i2o_proc_entry lan_fddi_entries[] = 
+{
+	{"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL},
+	{NULL, 0, NULL, NULL}
+};
+
+
+static char *chtostr(u8 *chars, int n)
+{
+	char tmp[256];
+	tmp[0] = 0;
+        return strncat(tmp, (char *)chars, n);
+}
+
+static int i2o_report_query_status(char *buf, int block_status, char *group)
+{
+	switch (block_status)
+	{
+	case -ETIMEDOUT:
+		return sprintf(buf, "Timeout reading group %s.\n",group);
+	case -ENOMEM:
+		return sprintf(buf, "No free memory to read the table.\n");
+	case -I2O_PARAMS_STATUS_INVALID_GROUP_ID:
+		return sprintf(buf, "Group %s not supported.\n", group);
+	default:
+		return sprintf(buf, "Error reading group %s. BlockStatus 0x%02X\n",
+			       group, -block_status);
+	}
+}
+
+static char* bus_strings[] = 
+{ 
+	"Local Bus", 
+	"ISA", 
+	"EISA", 
+	"MCA", 
+	"PCI",
+	"PCMCIA", 
+	"NUBUS", 
+	"CARDBUS"
+};
+
+static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED;
+
+int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len, 
+		      int *eof, void *data)
+{
+	struct i2o_controller *c = (struct i2o_controller *)data;
+	i2o_hrt *hrt = (i2o_hrt *)c->hrt;
+	u32 bus;
+	int count;
+	int i;
+
+	spin_lock(&i2o_proc_lock);
+
+	len = 0;
+
+	if(hrt->hrt_version)
+	{
+		len += sprintf(buf+len, 
+			       "HRT table for controller is too new a version.\n");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	count = hrt->num_entries;
+
+	if((count * hrt->entry_len + 8) > 2048) {
+		printk(KERN_WARNING "i2o_proc: HRT does not fit into buffer\n");
+		len += sprintf(buf+len,
+			       "HRT table too big to fit in buffer.\n");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+	
+	len += sprintf(buf+len, "HRT has %d entries of %d bytes each.\n",
+		       count, hrt->entry_len << 2);
+
+	for(i = 0; i < count; i++)
+	{
+		len += sprintf(buf+len, "Entry %d:\n", i);
+		len += sprintf(buf+len, "   Adapter ID: %0#10x\n", 
+					hrt->hrt_entry[i].adapter_id);
+		len += sprintf(buf+len, "   Controlling tid: %0#6x\n",
+					hrt->hrt_entry[i].parent_tid);
+
+		if(hrt->hrt_entry[i].bus_type != 0x80)
+		{
+			bus = hrt->hrt_entry[i].bus_type;
+			len += sprintf(buf+len, "   %s Information\n", bus_strings[bus]);
+
+			switch(bus)
+			{
+				case I2O_BUS_LOCAL:
+					len += sprintf(buf+len, "     IOBase: %0#6x,",
+								hrt->hrt_entry[i].bus.local_bus.LbBaseIOPort);
+					len += sprintf(buf+len, " MemoryBase: %0#10x\n",
+								hrt->hrt_entry[i].bus.local_bus.LbBaseMemoryAddress);
+					break;
+
+				case I2O_BUS_ISA:
+					len += sprintf(buf+len, "     IOBase: %0#6x,",
+								hrt->hrt_entry[i].bus.isa_bus.IsaBaseIOPort);
+					len += sprintf(buf+len, " MemoryBase: %0#10x,",
+								hrt->hrt_entry[i].bus.isa_bus.IsaBaseMemoryAddress);
+					len += sprintf(buf+len, " CSN: %0#4x,",
+								hrt->hrt_entry[i].bus.isa_bus.CSN);
+					break;
+
+				case I2O_BUS_EISA:
+					len += sprintf(buf+len, "     IOBase: %0#6x,",
+								hrt->hrt_entry[i].bus.eisa_bus.EisaBaseIOPort);
+					len += sprintf(buf+len, " MemoryBase: %0#10x,",
+								hrt->hrt_entry[i].bus.eisa_bus.EisaBaseMemoryAddress);
+					len += sprintf(buf+len, " Slot: %0#4x,",
+								hrt->hrt_entry[i].bus.eisa_bus.EisaSlotNumber);
+					break;
+			 
+				case I2O_BUS_MCA:
+					len += sprintf(buf+len, "     IOBase: %0#6x,",
+								hrt->hrt_entry[i].bus.mca_bus.McaBaseIOPort);
+					len += sprintf(buf+len, " MemoryBase: %0#10x,",
+								hrt->hrt_entry[i].bus.mca_bus.McaBaseMemoryAddress);
+					len += sprintf(buf+len, " Slot: %0#4x,",
+								hrt->hrt_entry[i].bus.mca_bus.McaSlotNumber);
+					break;
+
+				case I2O_BUS_PCI:
+					len += sprintf(buf+len, "     Bus: %0#4x",
+								hrt->hrt_entry[i].bus.pci_bus.PciBusNumber);
+					len += sprintf(buf+len, " Dev: %0#4x",
+								hrt->hrt_entry[i].bus.pci_bus.PciDeviceNumber);
+					len += sprintf(buf+len, " Func: %0#4x",
+								hrt->hrt_entry[i].bus.pci_bus.PciFunctionNumber);
+					len += sprintf(buf+len, " Vendor: %0#6x",
+								hrt->hrt_entry[i].bus.pci_bus.PciVendorID);
+					len += sprintf(buf+len, " Device: %0#6x\n",
+								hrt->hrt_entry[i].bus.pci_bus.PciDeviceID);
+					break;
+
+				default:
+					len += sprintf(buf+len, "      Unsupported Bus Type\n");
+			}
+		}
+		else
+			len += sprintf(buf+len, "   Unknown Bus Type\n");
+	}
+
+	spin_unlock(&i2o_proc_lock);
+	
+	return len;
+}
+
+int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
+	int *eof, void *data)
+{
+	struct i2o_controller *c = (struct i2o_controller*)data;
+	i2o_lct *lct = (i2o_lct *)c->lct;
+	int entries;
+	int i;
+
+#define BUS_TABLE_SIZE 3
+	static char *bus_ports[] =
+	{
+		"Generic Bus",
+		"SCSI Bus",
+		"Fibre Channel Bus"
+	};
+
+	spin_lock(&i2o_proc_lock);
+	len = 0;
+
+	entries = (lct->table_size - 3)/9;
+
+	len += sprintf(buf, "LCT contains %d %s\n", entries,
+						entries == 1 ? "entry" : "entries");
+	if(lct->boot_tid)	
+		len += sprintf(buf+len, "Boot Device @ ID %d\n", lct->boot_tid);
+
+	len += 
+		sprintf(buf+len, "Current Change Indicator: %#10x\n", lct->change_ind);
+
+	for(i = 0; i < entries; i++)
+	{
+		len += sprintf(buf+len, "Entry %d\n", i);
+		len += sprintf(buf+len, "  Class, SubClass  : %s", i2o_get_class_name(lct->lct_entry[i].class_id));
+	
+		/*
+		 *	Classes which we'll print subclass info for
+		 */
+		switch(lct->lct_entry[i].class_id & 0xFFF)
+		{
+			case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+				switch(lct->lct_entry[i].sub_class)
+				{
+					case 0x00:
+						len += sprintf(buf+len, ", Direct-Access Read/Write");
+						break;
+
+					case 0x04:
+						len += sprintf(buf+len, ", WORM Drive");
+						break;
+	
+					case 0x05:
+						len += sprintf(buf+len, ", CD-ROM Drive");
+						break;
+
+					case 0x07:
+						len += sprintf(buf+len, ", Optical Memory Device");
+						break;
+
+					default:
+						len += sprintf(buf+len, ", Unknown (0x%02x)",
+							       lct->lct_entry[i].sub_class);
+						break;
+				}
+				break;
+
+			case I2O_CLASS_LAN:
+				switch(lct->lct_entry[i].sub_class & 0xFF)
+				{
+					case 0x30:
+						len += sprintf(buf+len, ", Ethernet");
+						break;
+
+					case 0x40:
+						len += sprintf(buf+len, ", 100base VG");
+						break;
+
+					case 0x50:
+						len += sprintf(buf+len, ", IEEE 802.5/Token-Ring");
+						break;
+
+					case 0x60:
+						len += sprintf(buf+len, ", ANSI X3T9.5 FDDI");
+						break;
+		
+					case 0x70:
+						len += sprintf(buf+len, ", Fibre Channel");
+						break;
+
+					default:
+						len += sprintf(buf+len, ", Unknown Sub-Class (0x%02x)",
+							       lct->lct_entry[i].sub_class & 0xFF);
+						break;
+				}
+				break;
+
+			case I2O_CLASS_SCSI_PERIPHERAL:
+				if(lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE)
+					len += sprintf(buf+len, ", %s", 
+								scsi_devices[lct->lct_entry[i].sub_class]);
+				else
+					len += sprintf(buf+len, ", Unknown Device Type");
+				break;
+
+			case I2O_CLASS_BUS_ADAPTER_PORT:
+				if(lct->lct_entry[i].sub_class < BUS_TABLE_SIZE)
+					len += sprintf(buf+len, ", %s", 
+								bus_ports[lct->lct_entry[i].sub_class]);
+				else
+					len += sprintf(buf+len, ", Unknown Bus Type");
+				break;
+		}
+		len += sprintf(buf+len, "\n");
+		
+		len += sprintf(buf+len, "  Local TID        : 0x%03x\n", lct->lct_entry[i].tid);
+		len += sprintf(buf+len, "  User TID         : 0x%03x\n", lct->lct_entry[i].user_tid);
+		len += sprintf(buf+len, "  Parent TID       : 0x%03x\n", 
+					lct->lct_entry[i].parent_tid);
+		len += sprintf(buf+len, "  Identity Tag     : 0x%x%x%x%x%x%x%x%x\n",
+					lct->lct_entry[i].identity_tag[0],
+					lct->lct_entry[i].identity_tag[1],
+					lct->lct_entry[i].identity_tag[2],
+					lct->lct_entry[i].identity_tag[3],
+					lct->lct_entry[i].identity_tag[4],
+					lct->lct_entry[i].identity_tag[5],
+					lct->lct_entry[i].identity_tag[6],
+					lct->lct_entry[i].identity_tag[7]);
+		len += sprintf(buf+len, "  Change Indicator : %0#10x\n", 
+				lct->lct_entry[i].change_ind);
+		len += sprintf(buf+len, "  Event Capab Mask : %0#10x\n", 
+				lct->lct_entry[i].device_flags);
+	}
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+int i2o_proc_read_status(char *buf, char **start, off_t offset, int len, 
+			 int *eof, void *data)
+{
+	struct i2o_controller *c = (struct i2o_controller*)data;
+	char prodstr[25];
+	int version;
+	
+	spin_lock(&i2o_proc_lock);
+	len = 0;
+
+	i2o_status_get(c); // reread the status block
+
+	len += sprintf(buf+len,"Organization ID        : %0#6x\n", 
+				c->status_block->org_id);
+
+	version = c->status_block->i2o_version;
+	
+/* FIXME for Spec 2.0
+	if (version == 0x02) {
+		len += sprintf(buf+len,"Lowest I2O version supported: ");
+		switch(workspace[2]) {
+			case 0x00:
+				len += sprintf(buf+len,"1.0\n");
+				break;
+			case 0x01:
+				len += sprintf(buf+len,"1.5\n");
+				break;
+			case 0x02:
+				len += sprintf(buf+len,"2.0\n");
+				break;
+		}
+
+		len += sprintf(buf+len, "Highest I2O version supported: ");
+		switch(workspace[3]) {
+			case 0x00:
+				len += sprintf(buf+len,"1.0\n");
+				break;
+			case 0x01:
+				len += sprintf(buf+len,"1.5\n");
+				break;
+			case 0x02:
+				len += sprintf(buf+len,"2.0\n");
+				break;
+		}
+	}
+*/
+	len += sprintf(buf+len,"IOP ID                 : %0#5x\n", 
+				c->status_block->iop_id);
+	len += sprintf(buf+len,"Host Unit ID           : %0#6x\n",
+				c->status_block->host_unit_id);
+	len += sprintf(buf+len,"Segment Number         : %0#5x\n",
+				c->status_block->segment_number);
+
+	len += sprintf(buf+len, "I2O version            : ");
+	switch (version) {
+		case 0x00:
+			len += sprintf(buf+len,"1.0\n");
+			break;
+		case 0x01:
+			len += sprintf(buf+len,"1.5\n");
+			break;
+		case 0x02:
+			len += sprintf(buf+len,"2.0\n");
+			break;
+		default:
+			len += sprintf(buf+len,"Unknown version\n");
+	}
+
+	len += sprintf(buf+len, "IOP State              : ");
+	switch (c->status_block->iop_state) {
+		case 0x01:
+			len += sprintf(buf+len,"INIT\n");
+			break;
+
+		case 0x02:
+			len += sprintf(buf+len,"RESET\n");
+			break;
+
+		case 0x04:
+			len += sprintf(buf+len,"HOLD\n");
+			break;
+
+		case 0x05:
+			len += sprintf(buf+len,"READY\n");
+			break;
+
+		case 0x08:
+			len += sprintf(buf+len,"OPERATIONAL\n");
+			break;
+
+		case 0x10:
+			len += sprintf(buf+len,"FAILED\n");
+			break;
+
+		case 0x11:
+			len += sprintf(buf+len,"FAULTED\n");
+			break;
+
+		default:
+			len += sprintf(buf+len,"Unknown\n");
+			break;
+	}
+
+	len += sprintf(buf+len,"Messenger Type         : ");
+	switch (c->status_block->msg_type) { 
+		case 0x00:
+			len += sprintf(buf+len,"Memory mapped\n");
+			break;
+		case 0x01:
+			len += sprintf(buf+len,"Memory mapped only\n");
+			break;
+		case 0x02:
+			len += sprintf(buf+len,"Remote only\n");
+			break;
+		case 0x03:
+			len += sprintf(buf+len,"Memory mapped and remote\n");
+			break;
+		default:
+			len += sprintf(buf+len,"Unknown\n");
+	}
+
+	len += sprintf(buf+len,"Inbound Frame Size     : %d bytes\n", 
+				c->status_block->inbound_frame_size<<2);
+	len += sprintf(buf+len,"Max Inbound Frames     : %d\n", 
+				c->status_block->max_inbound_frames);
+	len += sprintf(buf+len,"Current Inbound Frames : %d\n", 
+				c->status_block->cur_inbound_frames);
+	len += sprintf(buf+len,"Max Outbound Frames    : %d\n", 
+				c->status_block->max_outbound_frames);
+
+	/* Spec doesn't say if NULL terminated or not... */
+	memcpy(prodstr, c->status_block->product_id, 24);
+	prodstr[24] = '\0';
+	len += sprintf(buf+len,"Product ID             : %s\n", prodstr);
+	len += sprintf(buf+len,"Expected LCT Size      : %d bytes\n", 
+				c->status_block->expected_lct_size);
+
+	len += sprintf(buf+len,"IOP Capabilities\n");
+	len += sprintf(buf+len,"    Context Field Size Support : ");
+	switch (c->status_block->iop_capabilities & 0x0000003) {
+		case 0:
+			len += sprintf(buf+len,"Supports only 32-bit context fields\n");
+			break;
+		case 1:
+			len += sprintf(buf+len,"Supports only 64-bit context fields\n");
+			break;
+		case 2:
+			len += sprintf(buf+len,"Supports 32-bit and 64-bit context fields, "
+						"but not concurrently\n");
+			break;
+		case 3:
+			len += sprintf(buf+len,"Supports 32-bit and 64-bit context fields "
+						"concurrently\n");
+			break;
+		default:
+			len += sprintf(buf+len,"0x%08x\n",c->status_block->iop_capabilities);
+	}
+	len += sprintf(buf+len,"    Current Context Field Size : ");
+	switch (c->status_block->iop_capabilities & 0x0000000C) {
+		case 0:
+			len += sprintf(buf+len,"not configured\n");
+			break;
+		case 4:
+			len += sprintf(buf+len,"Supports only 32-bit context fields\n");
+			break;
+		case 8:
+			len += sprintf(buf+len,"Supports only 64-bit context fields\n");
+			break;
+		case 12:
+			len += sprintf(buf+len,"Supports both 32-bit or 64-bit context fields "
+						"concurrently\n");
+			break;
+		default:
+			len += sprintf(buf+len,"\n");
+	}
+	len += sprintf(buf+len,"    Inbound Peer Support       : %s\n",
+			(c->status_block->iop_capabilities & 0x00000010) ? "Supported" : "Not supported");
+	len += sprintf(buf+len,"    Outbound Peer Support      : %s\n",
+			(c->status_block->iop_capabilities & 0x00000020) ? "Supported" : "Not supported");
+	len += sprintf(buf+len,"    Peer to Peer Support       : %s\n",
+			(c->status_block->iop_capabilities & 0x00000040) ? "Supported" : "Not supported");
+
+	len += sprintf(buf+len, "Desired private memory size   : %d kB\n", 
+				c->status_block->desired_mem_size>>10);
+	len += sprintf(buf+len, "Allocated private memory size : %d kB\n", 
+				c->status_block->current_mem_size>>10);
+	len += sprintf(buf+len, "Private memory base address   : %0#10x\n", 
+				c->status_block->current_mem_base);
+	len += sprintf(buf+len, "Desired private I/O size      : %d kB\n", 
+				c->status_block->desired_io_size>>10);
+	len += sprintf(buf+len, "Allocated private I/O size    : %d kB\n", 
+				c->status_block->current_io_size>>10);
+	len += sprintf(buf+len, "Private I/O base address      : %0#10x\n", 
+				c->status_block->current_io_base);
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, 
+		     int *eof, void *data)
+{
+	struct i2o_controller *c = (struct i2o_controller*)data;
+	static u32 work32[5];
+	static u8 *work8 = (u8*)work32;
+	static u16 *work16 = (u16*)work32;
+	int token;
+	u32 hwcap;
+
+	static char *cpu_table[] =
+	{
+		"Intel 80960 series",
+		"AMD2900 series",
+		"Motorola 68000 series",
+		"ARM series",
+		"MIPS series",
+		"Sparc series",
+		"PowerPC series",
+		"Intel x86 series"
+	};
+
+	spin_lock(&i2o_proc_lock);
+
+	len = 0;
+
+	token = i2o_query_scalar(c, ADAPTER_TID, 0x0000, -1, &work32, sizeof(work32));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0000 IOP Hardware");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf+len, "I2O Vendor ID    : %0#6x\n", work16[0]);
+	len += sprintf(buf+len, "Product ID       : %0#6x\n", work16[1]);
+	len += sprintf(buf+len, "CPU              : ");
+	if(work8[16] > 8)
+		len += sprintf(buf+len, "Unknown\n");
+	else
+		len += sprintf(buf+len, "%s\n", cpu_table[work8[16]]);
+	/* Anyone using ProcessorVersion? */
+	
+	len += sprintf(buf+len, "RAM              : %dkB\n", work32[1]>>10);
+	len += sprintf(buf+len, "Non-Volatile Mem : %dkB\n", work32[2]>>10);
+
+	hwcap = work32[3];
+	len += sprintf(buf+len, "Capabilities : 0x%08x\n", hwcap);
+	len += sprintf(buf+len, "   [%s] Self booting\n",
+			(hwcap&0x00000001) ? "+" : "-");
+	len += sprintf(buf+len, "   [%s] Upgradable IRTOS\n",
+			(hwcap&0x00000002) ? "+" : "-");
+	len += sprintf(buf+len, "   [%s] Supports downloading DDMs\n",
+			(hwcap&0x00000004) ? "+" : "-");
+	len += sprintf(buf+len, "   [%s] Supports installing DDMs\n",
+			(hwcap&0x00000008) ? "+" : "-");
+	len += sprintf(buf+len, "   [%s] Battery-backed RAM\n",
+			(hwcap&0x00000010) ? "+" : "-");
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+
+/* Executive group 0003h - Executing DDM List (table) */
+int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len, 
+			    int *eof, void *data)
+{
+	struct i2o_controller *c = (struct i2o_controller*)data;
+	int token;
+	int i;
+
+	typedef struct _i2o_exec_execute_ddm_table {
+		u16 ddm_tid;
+		u8  module_type;
+		u8  reserved;
+		u16 i2o_vendor_id;
+		u16 module_id;
+		u8  module_name_version[28];
+		u32 data_size;
+		u32 code_size;
+	} i2o_exec_execute_ddm_table;
+
+	struct
+	{
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8  block_status;
+		u8  error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		i2o_exec_execute_ddm_table ddm_table[MAX_I2O_MODULES];
+	} result;
+
+	i2o_exec_execute_ddm_table ddm_table;
+
+	spin_lock(&i2o_proc_lock);
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				c, ADAPTER_TID, 
+				0x0003, -1,
+				NULL, 0,
+				&result, sizeof(result));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0003 Executing DDM List");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf+len, "Tid   Module_type     Vendor Mod_id  Module_name             Vrs  Data_size Code_size\n");
+	ddm_table=result.ddm_table[0];
+
+	for(i=0; i < result.row_count; ddm_table=result.ddm_table[++i])
+	{
+		len += sprintf(buf+len, "0x%03x ", ddm_table.ddm_tid & 0xFFF);
+
+		switch(ddm_table.module_type)
+		{
+		case 0x01:
+			len += sprintf(buf+len, "Downloaded DDM  ");
+			break;			
+		case 0x22:
+			len += sprintf(buf+len, "Embedded DDM    ");
+			break;
+		default:
+			len += sprintf(buf+len, "                ");
+		}
+
+		len += sprintf(buf+len, "%-#7x", ddm_table.i2o_vendor_id);
+		len += sprintf(buf+len, "%-#8x", ddm_table.module_id);
+		len += sprintf(buf+len, "%-29s", chtostr(ddm_table.module_name_version, 28));
+		len += sprintf(buf+len, "%9d  ", ddm_table.data_size);
+		len += sprintf(buf+len, "%8d", ddm_table.code_size);
+
+		len += sprintf(buf+len, "\n");
+	}
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+
+/* Executive group 0004h - Driver Store (scalar) */
+int i2o_proc_read_driver_store(char *buf, char **start, off_t offset, int len, 
+		     int *eof, void *data)
+{
+	struct i2o_controller *c = (struct i2o_controller*)data;
+	u32 work32[8];
+	int token;
+
+	spin_lock(&i2o_proc_lock);
+
+	len = 0;
+
+	token = i2o_query_scalar(c, ADAPTER_TID, 0x0004, -1, &work32, sizeof(work32));
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0004 Driver Store");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf+len, "Module limit  : %d\n"
+				"Module count  : %d\n"
+				"Current space : %d kB\n"
+				"Free space    : %d kB\n", 
+			work32[0], work32[1], work32[2]>>10, work32[3]>>10);
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+
+/* Executive group 0005h - Driver Store Table (table) */
+int i2o_proc_read_drivers_stored(char *buf, char **start, off_t offset,
+				 int len, int *eof, void *data)
+{
+	typedef struct _i2o_driver_store {
+		u16 stored_ddm_index;
+		u8  module_type;
+		u8  reserved;
+		u16 i2o_vendor_id;
+		u16 module_id;
+		u8  module_name_version[28];
+		u8  date[8];
+		u32 module_size;
+		u32 mpb_size;
+		u32 module_flags;
+	} i2o_driver_store_table;
+
+	struct i2o_controller *c = (struct i2o_controller*)data;
+	int token;
+	int i;
+
+	typedef struct
+	{
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8  block_status;
+		u8  error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		i2o_driver_store_table dst[MAX_I2O_MODULES];
+	} i2o_driver_result_table;
+	
+	i2o_driver_result_table *result;
+	i2o_driver_store_table *dst;
+
+	spin_lock(&i2o_proc_lock);
+
+	len = 0;
+	
+	result = kmalloc(sizeof(i2o_driver_result_table), GFP_KERNEL);
+	if(result == NULL)
+		return -ENOMEM;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				c, ADAPTER_TID, 0x0005, -1, NULL, 0, 
+				result, sizeof(*result));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0005 DRIVER STORE TABLE");
+		spin_unlock(&i2o_proc_lock);
+		kfree(result);
+		return len;
+	}
+
+	len += sprintf(buf+len, "#  Module_type     Vendor Mod_id  Module_name             Vrs"  
+				"Date     Mod_size Par_size Flags\n");
+	for(i=0, dst=&result->dst[0]; i < result->row_count; dst=&result->dst[++i])
+	{
+		len += sprintf(buf+len, "%-3d", dst->stored_ddm_index);
+		switch(dst->module_type)
+		{
+		case 0x01:
+			len += sprintf(buf+len, "Downloaded DDM  ");
+			break;			
+		case 0x22:
+			len += sprintf(buf+len, "Embedded DDM    ");
+			break;
+		default:
+			len += sprintf(buf+len, "                ");
+		}
+
+#if 0
+		if(c->i2oversion == 0x02)
+			len += sprintf(buf+len, "%-d", dst->module_state);
+#endif
+
+		len += sprintf(buf+len, "%-#7x", dst->i2o_vendor_id);
+		len += sprintf(buf+len, "%-#8x", dst->module_id);
+		len += sprintf(buf+len, "%-29s", chtostr(dst->module_name_version,28));
+		len += sprintf(buf+len, "%-9s", chtostr(dst->date,8));
+		len += sprintf(buf+len, "%8d ", dst->module_size);
+		len += sprintf(buf+len, "%8d ", dst->mpb_size);
+		len += sprintf(buf+len, "0x%04x", dst->module_flags);
+#if 0
+		if(c->i2oversion == 0x02)
+			len += sprintf(buf+len, "%d",
+				       dst->notification_level);
+#endif
+		len += sprintf(buf+len, "\n");
+	}
+
+	spin_unlock(&i2o_proc_lock);
+	kfree(result);
+	return len;
+}
+
+
+/* Generic group F000h - Params Descriptor (table) */
+int i2o_proc_read_groups(char *buf, char **start, off_t offset, int len, 
+			 int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+	int i;
+	u8 properties;
+
+	typedef struct _i2o_group_info
+	{
+		u16 group_number;
+		u16 field_count;
+		u16 row_count;
+		u8  properties;
+		u8  reserved;
+	} i2o_group_info;
+
+	struct
+	{
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8  block_status;
+		u8  error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		i2o_group_info group[256];
+	} result;
+
+	spin_lock(&i2o_proc_lock);
+
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				d->controller, d->lct_data.tid, 0xF000, -1, NULL, 0,
+				&result, sizeof(result));
+
+	if (token < 0) {
+		len = i2o_report_query_status(buf+len, token, "0xF000 Params Descriptor");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf+len, "#  Group   FieldCount RowCount Type   Add Del Clear\n");
+
+	for (i=0; i < result.row_count; i++)
+	{
+		len += sprintf(buf+len, "%-3d", i);
+		len += sprintf(buf+len, "0x%04X ", result.group[i].group_number);
+		len += sprintf(buf+len, "%10d ", result.group[i].field_count);
+		len += sprintf(buf+len, "%8d ",  result.group[i].row_count);
+
+		properties = result.group[i].properties;
+		if (properties & 0x1)	len += sprintf(buf+len, "Table  ");
+				else	len += sprintf(buf+len, "Scalar ");
+		if (properties & 0x2)	len += sprintf(buf+len, " + ");
+				else	len += sprintf(buf+len, " - ");
+		if (properties & 0x4)	len += sprintf(buf+len, "  + ");
+				else	len += sprintf(buf+len, "  - ");
+		if (properties & 0x8)	len += sprintf(buf+len, "  + ");
+				else	len += sprintf(buf+len, "  - ");
+
+		len += sprintf(buf+len, "\n");
+	}
+
+	if (result.more_flag)
+		len += sprintf(buf+len, "There is more...\n");
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+
+/* Generic group F001h - Physical Device Table (table) */
+int i2o_proc_read_phys_device(char *buf, char **start, off_t offset, int len,
+			      int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+	int i;
+
+	struct
+	{
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8  block_status;
+		u8  error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		u32 adapter_id[64];
+	} result;
+
+	spin_lock(&i2o_proc_lock);
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				d->controller, d->lct_data.tid,
+				0xF001, -1, NULL, 0,
+				&result, sizeof(result));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0xF001 Physical Device Table");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	if (result.row_count)
+		len += sprintf(buf+len, "#  AdapterId\n");
+
+	for (i=0; i < result.row_count; i++)
+	{
+		len += sprintf(buf+len, "%-2d", i);
+		len += sprintf(buf+len, "%#7x\n", result.adapter_id[i]);
+	}
+
+	if (result.more_flag)
+		len += sprintf(buf+len, "There is more...\n");
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* Generic group F002h - Claimed Table (table) */
+int i2o_proc_read_claimed(char *buf, char **start, off_t offset, int len,
+			  int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+	int i;
+
+	struct {
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8  block_status;
+		u8  error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		u16 claimed_tid[64];
+	} result;
+
+	spin_lock(&i2o_proc_lock);
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				d->controller, d->lct_data.tid,
+				0xF002, -1, NULL, 0,
+				&result, sizeof(result));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0xF002 Claimed Table");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	if (result.row_count)
+		len += sprintf(buf+len, "#  ClaimedTid\n");
+
+	for (i=0; i < result.row_count; i++)
+	{
+		len += sprintf(buf+len, "%-2d", i);
+		len += sprintf(buf+len, "%#7x\n", result.claimed_tid[i]);
+	}
+
+	if (result.more_flag)
+		len += sprintf(buf+len, "There is more...\n");
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* Generic group F003h - User Table (table) */
+int i2o_proc_read_users(char *buf, char **start, off_t offset, int len,
+			int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+	int i;
+
+	typedef struct _i2o_user_table
+	{
+		u16 instance;
+		u16 user_tid;
+		u8 claim_type;
+		u8  reserved1;
+		u16  reserved2;
+	} i2o_user_table;
+
+	struct
+	{
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8  block_status;
+		u8  error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		i2o_user_table user[64];
+	} result;
+
+	spin_lock(&i2o_proc_lock);
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				d->controller, d->lct_data.tid,
+				0xF003, -1, NULL, 0,
+				&result, sizeof(result));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0xF003 User Table");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf+len, "#  Instance UserTid ClaimType\n");
+
+	for(i=0; i < result.row_count; i++)
+	{
+		len += sprintf(buf+len, "%-3d", i);
+		len += sprintf(buf+len, "%#8x ", result.user[i].instance);
+		len += sprintf(buf+len, "%#7x ", result.user[i].user_tid);
+		len += sprintf(buf+len, "%#9x\n", result.user[i].claim_type);
+	}
+
+	if (result.more_flag)
+		len += sprintf(buf+len, "There is more...\n");
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* Generic group F005h - Private message extensions (table) (optional) */
+int i2o_proc_read_priv_msgs(char *buf, char **start, off_t offset, int len, 
+			    int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+	int i;
+
+	typedef struct _i2o_private
+	{
+		u16 ext_instance;
+		u16 organization_id;
+		u16 x_function_code;
+	} i2o_private;
+
+	struct
+	{
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8  block_status;
+		u8  error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		i2o_private extension[64];
+	} result;
+
+	spin_lock(&i2o_proc_lock);
+
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				d->controller, d->lct_data.tid,
+				0xF000, -1,
+				NULL, 0,
+				&result, sizeof(result));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0xF005 Private Message Extensions (optional)");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+	
+	len += sprintf(buf+len, "Instance#  OrgId  FunctionCode\n");
+
+	for(i=0; i < result.row_count; i++)
+	{
+		len += sprintf(buf+len, "%0#9x ", result.extension[i].ext_instance);
+		len += sprintf(buf+len, "%0#6x ", result.extension[i].organization_id);
+		len += sprintf(buf+len, "%0#6x",  result.extension[i].x_function_code);
+
+		len += sprintf(buf+len, "\n");
+	}
+
+	if(result.more_flag)
+		len += sprintf(buf+len, "There is more...\n");
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+
+/* Generic group F006h - Authorized User Table (table) */
+int i2o_proc_read_authorized_users(char *buf, char **start, off_t offset, int len,
+				   int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+	int i;
+
+	struct
+	{
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8  block_status;
+		u8  error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		u32 alternate_tid[64];
+	} result;
+
+	spin_lock(&i2o_proc_lock);
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				d->controller, d->lct_data.tid,
+				0xF006, -1,
+				NULL, 0,
+				&result, sizeof(result));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0xF006 Autohorized User Table");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	if (result.row_count)
+		len += sprintf(buf+len, "#  AlternateTid\n");
+
+	for(i=0; i < result.row_count; i++)
+	{
+		len += sprintf(buf+len, "%-2d", i);
+		len += sprintf(buf+len, "%#7x ", result.alternate_tid[i]);
+	}
+
+	if (result.more_flag)
+		len += sprintf(buf+len, "There is more...\n");
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+
+/* Generic group F100h - Device Identity (scalar) */
+int i2o_proc_read_dev_identity(char *buf, char **start, off_t offset, int len, 
+			       int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u32 work32[128];		// allow for "stuff" + up to 256 byte (max) serial number
+					// == (allow) 512d bytes (max)
+	static u16 *work16 = (u16*)work32;
+	int token;
+
+	spin_lock(&i2o_proc_lock);
+	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				0xF100,	-1,
+				&work32, sizeof(work32));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token ,"0xF100 Device Identity");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+	
+	len += sprintf(buf,     "Device Class  : %s\n", i2o_get_class_name(work16[0]));
+	len += sprintf(buf+len, "Owner TID     : %0#5x\n", work16[2]);
+	len += sprintf(buf+len, "Parent TID    : %0#5x\n", work16[3]);
+	len += sprintf(buf+len, "Vendor info   : %s\n", chtostr((u8 *)(work32+2), 16));
+	len += sprintf(buf+len, "Product info  : %s\n", chtostr((u8 *)(work32+6), 16));
+	len += sprintf(buf+len, "Description   : %s\n", chtostr((u8 *)(work32+10), 16));
+	len += sprintf(buf+len, "Product rev.  : %s\n", chtostr((u8 *)(work32+14), 8));
+
+	len += sprintf(buf+len, "Serial number : ");
+	len = print_serial_number(buf, len,
+			(u8*)(work32+16),
+						/* allow for SNLen plus
+						 * possible trailing '\0'
+						 */
+			sizeof(work32)-(16*sizeof(u32))-2
+				);
+	len +=  sprintf(buf+len, "\n");
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+
+int i2o_proc_read_dev_name(char *buf, char **start, off_t offset, int len,
+	int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+
+	if ( d->dev_name[0] == '\0' )
+		return 0;
+
+	len = sprintf(buf, "%s\n", d->dev_name);
+
+	return len;
+}
+
+
+/* Generic group F101h - DDM Identity (scalar) */
+int i2o_proc_read_ddm_identity(char *buf, char **start, off_t offset, int len, 
+			      int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+
+	struct
+	{
+		u16 ddm_tid;
+		u8 module_name[24];
+		u8 module_rev[8];
+		u8 sn_format;
+		u8 serial_number[12];
+		u8 pad[256]; // allow up to 256 byte (max) serial number
+	} result;	
+
+	spin_lock(&i2o_proc_lock);
+	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid, 
+				0xF101,	-1,
+				&result, sizeof(result));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0xF101 DDM Identity");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf,     "Registering DDM TID : 0x%03x\n", result.ddm_tid);
+	len += sprintf(buf+len, "Module name         : %s\n", chtostr(result.module_name, 24));
+	len += sprintf(buf+len, "Module revision     : %s\n", chtostr(result.module_rev, 8));
+
+	len += sprintf(buf+len, "Serial number       : ");
+	len = print_serial_number(buf, len, result.serial_number, sizeof(result)-36);
+				/* allow for SNLen plus possible trailing '\0' */
+
+	len += sprintf(buf+len, "\n");
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+/* Generic group F102h - User Information (scalar) */
+int i2o_proc_read_uinfo(char *buf, char **start, off_t offset, int len, 
+			int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+
+ 	struct
+	{
+		u8 device_name[64];
+		u8 service_name[64];
+		u8 physical_location[64];
+		u8 instance_number[4];
+	} result;
+
+	spin_lock(&i2o_proc_lock);
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				0xF102,	-1,
+				&result, sizeof(result));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0xF102 User Information");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf,     "Device name     : %s\n", chtostr(result.device_name, 64));
+	len += sprintf(buf+len, "Service name    : %s\n", chtostr(result.service_name, 64));
+	len += sprintf(buf+len, "Physical name   : %s\n", chtostr(result.physical_location, 64));
+	len += sprintf(buf+len, "Instance number : %s\n", chtostr(result.instance_number, 4));
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* Generic group F103h - SGL Operating Limits (scalar) */
+int i2o_proc_read_sgl_limits(char *buf, char **start, off_t offset, int len, 
+			     int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u32 work32[12];
+	static u16 *work16 = (u16 *)work32;
+	static u8 *work8 = (u8 *)work32;
+	int token;
+
+	spin_lock(&i2o_proc_lock);
+	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid, 
+				 0xF103, -1,
+				 &work32, sizeof(work32));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0xF103 SGL Operating Limits");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf,     "SGL chain size        : %d\n", work32[0]);
+	len += sprintf(buf+len, "Max SGL chain size    : %d\n", work32[1]);
+	len += sprintf(buf+len, "SGL chain size target : %d\n", work32[2]);
+	len += sprintf(buf+len, "SGL frag count        : %d\n", work16[6]);
+	len += sprintf(buf+len, "Max SGL frag count    : %d\n", work16[7]);
+	len += sprintf(buf+len, "SGL frag count target : %d\n", work16[8]);
+
+	if (d->i2oversion == 0x02)
+	{
+		len += sprintf(buf+len, "SGL data alignment    : %d\n", work16[8]);
+		len += sprintf(buf+len, "SGL addr limit        : %d\n", work8[20]);
+		len += sprintf(buf+len, "SGL addr sizes supported : ");
+		if (work8[21] & 0x01)
+			len += sprintf(buf+len, "32 bit ");
+		if (work8[21] & 0x02)
+			len += sprintf(buf+len, "64 bit ");
+		if (work8[21] & 0x04)
+			len += sprintf(buf+len, "96 bit ");
+		if (work8[21] & 0x08)
+			len += sprintf(buf+len, "128 bit ");
+		len += sprintf(buf+len, "\n");
+	}
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+/* Generic group F200h - Sensors (scalar) */
+int i2o_proc_read_sensors(char *buf, char **start, off_t offset, int len,
+			  int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+
+	struct
+	{
+		u16 sensor_instance;
+		u8  component;
+		u16 component_instance;
+		u8  sensor_class;
+		u8  sensor_type;
+		u8  scaling_exponent;
+		u32 actual_reading;
+		u32 minimum_reading;
+		u32 low2lowcat_treshold;
+		u32 lowcat2low_treshold;
+		u32 lowwarn2low_treshold;
+		u32 low2lowwarn_treshold;
+		u32 norm2lowwarn_treshold;
+		u32 lowwarn2norm_treshold;
+		u32 nominal_reading;
+		u32 hiwarn2norm_treshold;
+		u32 norm2hiwarn_treshold;
+		u32 high2hiwarn_treshold;
+		u32 hiwarn2high_treshold;
+		u32 hicat2high_treshold;
+		u32 hi2hicat_treshold;
+		u32 maximum_reading;
+		u8  sensor_state;
+		u16 event_enable;
+	} result;
+	
+	spin_lock(&i2o_proc_lock);	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0xF200, -1,
+				 &result, sizeof(result));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0xF200 Sensors (optional)");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+	
+	len += sprintf(buf+len, "Sensor instance       : %d\n", result.sensor_instance);
+
+	len += sprintf(buf+len, "Component             : %d = ", result.component);
+	switch (result.component)
+	{
+	case 0:	len += sprintf(buf+len, "Other");		
+		break;
+	case 1: len += sprintf(buf+len, "Planar logic Board");
+		break;
+	case 2: len += sprintf(buf+len, "CPU");
+		break;
+	case 3: len += sprintf(buf+len, "Chassis");
+		break;
+	case 4: len += sprintf(buf+len, "Power Supply");
+		break;
+	case 5: len += sprintf(buf+len, "Storage");
+		break;
+	case 6: len += sprintf(buf+len, "External");
+		break;
+	}		
+	len += sprintf(buf+len,"\n");
+
+	len += sprintf(buf+len, "Component instance    : %d\n", result.component_instance);
+	len += sprintf(buf+len, "Sensor class          : %s\n",
+				result.sensor_class ? "Analog" : "Digital");
+	
+	len += sprintf(buf+len, "Sensor type           : %d = ",result.sensor_type);
+	switch (result.sensor_type)
+	{
+	case 0:	len += sprintf(buf+len, "Other\n");
+		break;
+	case 1: len += sprintf(buf+len, "Thermal\n");
+		break;
+	case 2: len += sprintf(buf+len, "DC voltage (DC volts)\n");
+		break;
+	case 3: len += sprintf(buf+len, "AC voltage (AC volts)\n");
+		break;
+	case 4: len += sprintf(buf+len, "DC current (DC amps)\n");
+		break;
+	case 5: len += sprintf(buf+len, "AC current (AC volts)\n");
+		break;
+	case 6: len += sprintf(buf+len, "Door open\n");
+		break;
+	case 7: len += sprintf(buf+len, "Fan operational\n");
+		break;
+ 	}			
+
+	len += sprintf(buf+len, "Scaling exponent      : %d\n", result.scaling_exponent);
+	len += sprintf(buf+len, "Actual reading        : %d\n", result.actual_reading);
+	len += sprintf(buf+len, "Minimum reading       : %d\n", result.minimum_reading);
+	len += sprintf(buf+len, "Low2LowCat treshold   : %d\n", result.low2lowcat_treshold);
+	len += sprintf(buf+len, "LowCat2Low treshold   : %d\n", result.lowcat2low_treshold);
+	len += sprintf(buf+len, "LowWarn2Low treshold  : %d\n", result.lowwarn2low_treshold);
+	len += sprintf(buf+len, "Low2LowWarn treshold  : %d\n", result.low2lowwarn_treshold);
+	len += sprintf(buf+len, "Norm2LowWarn treshold : %d\n", result.norm2lowwarn_treshold);
+	len += sprintf(buf+len, "LowWarn2Norm treshold : %d\n", result.lowwarn2norm_treshold);
+	len += sprintf(buf+len, "Nominal reading       : %d\n", result.nominal_reading);
+	len += sprintf(buf+len, "HiWarn2Norm treshold  : %d\n", result.hiwarn2norm_treshold);
+	len += sprintf(buf+len, "Norm2HiWarn treshold  : %d\n", result.norm2hiwarn_treshold);
+	len += sprintf(buf+len, "High2HiWarn treshold  : %d\n", result.high2hiwarn_treshold);
+	len += sprintf(buf+len, "HiWarn2High treshold  : %d\n", result.hiwarn2high_treshold);
+	len += sprintf(buf+len, "HiCat2High treshold   : %d\n", result.hicat2high_treshold);
+	len += sprintf(buf+len, "High2HiCat treshold   : %d\n", result.hi2hicat_treshold);
+	len += sprintf(buf+len, "Maximum reading       : %d\n", result.maximum_reading);
+
+	len += sprintf(buf+len, "Sensor state          : %d = ", result.sensor_state);
+	switch (result.sensor_state)
+	{
+	case 0:	 len += sprintf(buf+len, "Normal\n");
+		 break;
+	case 1:  len += sprintf(buf+len, "Abnormal\n");
+		 break;
+	case 2:  len += sprintf(buf+len, "Unknown\n");
+		 break;
+	case 3:  len += sprintf(buf+len, "Low Catastrophic (LoCat)\n");
+		 break;
+	case 4:  len += sprintf(buf+len, "Low (Low)\n");
+		 break;
+	case 5:  len += sprintf(buf+len, "Low Warning (LoWarn)\n");
+		 break;
+	case 6:  len += sprintf(buf+len, "High Warning (HiWarn)\n");
+		 break;
+	case 7:  len += sprintf(buf+len, "High (High)\n");
+		 break;
+	case 8:  len += sprintf(buf+len, "High Catastrophic (HiCat)\n");
+		 break;
+	}			
+
+	len += sprintf(buf+len, "Event_enable : 0x%02X\n", result.event_enable);
+	len += sprintf(buf+len, "    [%s] Operational state change. \n",
+			(result.event_enable & 0x01) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] Low catastrophic. \n",
+			(result.event_enable & 0x02) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] Low reading. \n",
+			(result.event_enable & 0x04) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] Low warning. \n",
+			(result.event_enable & 0x08) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] Change back to normal from out of range state. \n",
+			(result.event_enable & 0x10) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] High warning. \n",
+			(result.event_enable & 0x20) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] High reading. \n",
+			(result.event_enable & 0x40) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] High catastrophic. \n",
+			(result.event_enable & 0x80) ? "+" : "-" );
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+
+static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len)
+{
+	int i;
+
+	/* 19990419 -sralston
+	 *	The I2O v1.5 (and v2.0 so far) "official specification"
+	 *	got serial numbers WRONG!
+	 *	Apparently, and despite what Section 3.4.4 says and
+	 *	Figure 3-35 shows (pg 3-39 in the pdf doc),
+	 *	the convention / consensus seems to be:
+	 *	  + First byte is SNFormat
+	 *	  + Second byte is SNLen (but only if SNFormat==7 (?))
+	 *	  + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format
+	 */
+	switch(serialno[0])
+	{
+		case I2O_SNFORMAT_BINARY:		/* Binary */
+			pos += sprintf(buff+pos, "0x");
+			for(i = 0; i < serialno[1]; i++)
+			{
+				pos += sprintf(buff+pos, "%02X", serialno[2+i]);
+			}
+			break;
+	
+		case I2O_SNFORMAT_ASCII:		/* ASCII */
+			if ( serialno[1] < ' ' )	/* printable or SNLen? */
+			{
+				/* sanity */
+				max_len = (max_len < serialno[1]) ? max_len : serialno[1];
+				serialno[1+max_len] = '\0';
+
+				/* just print it */
+				pos += sprintf(buff+pos, "%s", &serialno[2]);
+			}
+			else
+			{
+				/* print chars for specified length */
+				for(i = 0; i < serialno[1]; i++)
+				{
+					pos += sprintf(buff+pos, "%c", serialno[2+i]);
+				}
+			}
+			break;
+
+		case I2O_SNFORMAT_UNICODE:		/* UNICODE */
+			pos += sprintf(buff+pos, "UNICODE Format.  Can't Display\n");
+			break;
+
+		case I2O_SNFORMAT_LAN48_MAC:		/* LAN-48 MAC Address */
+			pos += sprintf(buff+pos, 
+						"LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X",
+						serialno[2], serialno[3],
+						serialno[4], serialno[5],
+						serialno[6], serialno[7]);
+			break;
+
+		case I2O_SNFORMAT_WAN:			/* WAN MAC Address */
+			/* FIXME: Figure out what a WAN access address looks like?? */
+			pos += sprintf(buff+pos, "WAN Access Address");
+			break;
+
+/* plus new in v2.0 */
+		case I2O_SNFORMAT_LAN64_MAC:		/* LAN-64 MAC Address */
+			/* FIXME: Figure out what a LAN-64 address really looks like?? */
+			pos += sprintf(buff+pos, 
+						"LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X",
+						serialno[8], serialno[9],
+						serialno[2], serialno[3],
+						serialno[4], serialno[5],
+						serialno[6], serialno[7]);
+			break;
+
+
+		case I2O_SNFORMAT_DDM:			/* I2O DDM */
+			pos += sprintf(buff+pos, 
+						"DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh",
+						*(u16*)&serialno[2],
+						*(u16*)&serialno[4],
+						*(u16*)&serialno[6]);
+			break;
+
+		case I2O_SNFORMAT_IEEE_REG64:		/* IEEE Registered (64-bit) */
+		case I2O_SNFORMAT_IEEE_REG128:		/* IEEE Registered (128-bit) */
+			/* FIXME: Figure if this is even close?? */
+			pos += sprintf(buff+pos, 
+						"IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n",
+						*(u32*)&serialno[2],
+						*(u32*)&serialno[6],
+						*(u32*)&serialno[10],
+						*(u32*)&serialno[14]);
+			break;
+
+
+		case I2O_SNFORMAT_UNKNOWN:		/* Unknown 0    */
+		case I2O_SNFORMAT_UNKNOWN2:		/* Unknown 0xff */
+		default:
+			pos += sprintf(buff+pos, "Unknown data format (0x%02x)",
+				       serialno[0]);
+			break;
+	}
+
+	return pos;
+}
+
+const char * i2o_get_connector_type(int conn)
+{
+	int idx = 16;
+	static char *i2o_connector_type[] = {
+		"OTHER",
+		"UNKNOWN",
+		"AUI",
+		"UTP",
+		"BNC",
+		"RJ45",
+		"STP DB9",
+		"FIBER MIC",
+		"APPLE AUI",
+		"MII",
+		"DB9",
+		"HSSDC",
+		"DUPLEX SC FIBER",
+		"DUPLEX ST FIBER",
+		"TNC/BNC",
+		"HW DEFAULT"
+	};
+
+	switch(conn)
+	{
+	case 0x00000000:
+		idx = 0;
+		break;
+	case 0x00000001:
+		idx = 1;
+		break;
+	case 0x00000002:
+		idx = 2;
+		break;
+	case 0x00000003:
+		idx = 3;
+		break;
+	case 0x00000004:
+		idx = 4;
+		break;
+	case 0x00000005:
+		idx = 5;
+		break;
+	case 0x00000006:
+		idx = 6;
+		break;
+	case 0x00000007:
+		idx = 7;
+		break;
+	case 0x00000008:
+		idx = 8;
+		break;
+	case 0x00000009:
+		idx = 9;
+		break;
+	case 0x0000000A:
+		idx = 10;
+		break;
+	case 0x0000000B:
+		idx = 11;
+		break;
+	case 0x0000000C:
+		idx = 12;
+		break;
+	case 0x0000000D:
+		idx = 13;
+		break;
+	case 0x0000000E:
+		idx = 14;
+		break;
+	case 0xFFFFFFFF:
+		idx = 15;
+		break;
+	}
+
+	return i2o_connector_type[idx];
+}
+
+
+const char * i2o_get_connection_type(int conn)
+{
+	int idx = 0;
+	static char *i2o_connection_type[] = {
+		"Unknown",
+		"AUI",
+		"10BASE5",
+		"FIORL",
+		"10BASE2",
+		"10BROAD36",
+		"10BASE-T",
+		"10BASE-FP",
+		"10BASE-FB",
+		"10BASE-FL",
+		"100BASE-TX",
+		"100BASE-FX",
+		"100BASE-T4",
+		"1000BASE-SX",
+		"1000BASE-LX",
+		"1000BASE-CX",
+		"1000BASE-T",
+		"100VG-ETHERNET",
+		"100VG-TOKEN RING",
+		"4MBIT TOKEN RING",
+		"16 Mb Token Ring",
+		"125 MBAUD FDDI",
+		"Point-to-point",
+		"Arbitrated loop",
+		"Public loop",
+		"Fabric",
+		"Emulation",
+		"Other",
+		"HW default"
+	};
+
+	switch(conn)
+	{
+	case I2O_LAN_UNKNOWN:
+		idx = 0;
+		break;
+	case I2O_LAN_AUI:
+		idx = 1;
+		break;
+	case I2O_LAN_10BASE5:
+		idx = 2;
+		break;
+	case I2O_LAN_FIORL:
+		idx = 3;
+		break;
+	case I2O_LAN_10BASE2:
+		idx = 4;
+		break;
+	case I2O_LAN_10BROAD36:
+		idx = 5;
+		break;
+	case I2O_LAN_10BASE_T:
+		idx = 6;
+		break;
+	case I2O_LAN_10BASE_FP:
+		idx = 7;
+		break;
+	case I2O_LAN_10BASE_FB:
+		idx = 8;
+		break;
+	case I2O_LAN_10BASE_FL:
+		idx = 9;
+		break;
+	case I2O_LAN_100BASE_TX:
+		idx = 10;
+		break;
+	case I2O_LAN_100BASE_FX:
+		idx = 11;
+		break;
+	case I2O_LAN_100BASE_T4:
+		idx = 12;
+		break;
+	case I2O_LAN_1000BASE_SX:
+		idx = 13;
+		break;
+	case I2O_LAN_1000BASE_LX:
+		idx = 14;
+		break;
+	case I2O_LAN_1000BASE_CX:
+		idx = 15;
+		break;
+	case I2O_LAN_1000BASE_T:
+		idx = 16;
+		break;
+	case I2O_LAN_100VG_ETHERNET:
+		idx = 17;
+		break;
+	case I2O_LAN_100VG_TR:
+		idx = 18;
+		break;
+	case I2O_LAN_4MBIT:
+		idx = 19;
+		break;
+	case I2O_LAN_16MBIT:
+		idx = 20;
+		break;
+	case I2O_LAN_125MBAUD:
+		idx = 21;
+		break;
+	case I2O_LAN_POINT_POINT:
+		idx = 22;
+		break;
+	case I2O_LAN_ARB_LOOP:
+		idx = 23;
+		break;
+	case I2O_LAN_PUBLIC_LOOP:
+		idx = 24;
+		break;
+	case I2O_LAN_FABRIC:
+		idx = 25;
+		break;
+	case I2O_LAN_EMULATION:
+		idx = 26;
+		break;
+	case I2O_LAN_OTHER:
+		idx = 27;
+		break;
+	case I2O_LAN_DEFAULT:
+		idx = 28;
+		break;
+	}
+
+	return i2o_connection_type[idx];
+}
+
+
+/* LAN group 0000h - Device info (scalar) */
+int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len, 
+			       int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u32 work32[56];
+	static u8 *work8 = (u8*)work32;
+	static u16 *work16 = (u16*)work32;
+	static u64 *work64 = (u64*)work32;
+	int token;
+
+	spin_lock(&i2o_proc_lock);
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0000, -1, &work32, 56*4);
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token, "0x0000 LAN Device Info");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf, "LAN Type            : ");
+	switch (work16[0])
+	{
+	case 0x0030:
+		len += sprintf(buf+len, "Ethernet, ");
+		break;
+	case 0x0040:
+		len += sprintf(buf+len, "100Base VG, ");
+		break;
+	case 0x0050:
+		len += sprintf(buf+len, "Token Ring, ");
+		break;
+	case 0x0060:
+		len += sprintf(buf+len, "FDDI, ");
+		break;
+	case 0x0070:
+		len += sprintf(buf+len, "Fibre Channel, ");
+		break;
+	default:
+		len += sprintf(buf+len, "Unknown type (0x%04x), ", work16[0]);
+		break;
+	}
+
+	if (work16[1]&0x00000001)
+		len += sprintf(buf+len, "emulated LAN, ");
+	else
+		len += sprintf(buf+len, "physical LAN port, ");
+
+	if (work16[1]&0x00000002)
+		len += sprintf(buf+len, "full duplex\n");
+	else
+		len += sprintf(buf+len, "simplex\n");
+
+	len += sprintf(buf+len, "Address format      : ");
+	switch(work8[4]) {
+	case 0x00:
+		len += sprintf(buf+len, "IEEE 48bit\n");
+		break;
+	case 0x01:
+		len += sprintf(buf+len, "FC IEEE\n");
+		break;
+	default:
+		len += sprintf(buf+len, "Unknown (0x%02x)\n", work8[4]);
+		break;
+	}
+
+	len += sprintf(buf+len, "State               : ");
+	switch(work8[5])
+	{
+	case 0x00:
+		len += sprintf(buf+len, "Unknown\n");
+		break;
+	case 0x01:
+		len += sprintf(buf+len, "Unclaimed\n");
+		break;
+	case 0x02:
+		len += sprintf(buf+len, "Operational\n");
+		break;
+	case 0x03:
+		len += sprintf(buf+len, "Suspended\n");
+		break;
+	case 0x04:
+		len += sprintf(buf+len, "Resetting\n");
+		break;
+	case 0x05:
+		len += sprintf(buf+len, "ERROR: ");
+		if(work16[3]&0x0001)
+			len += sprintf(buf+len, "TxCU inoperative ");
+		if(work16[3]&0x0002)
+			len += sprintf(buf+len, "RxCU inoperative ");
+		if(work16[3]&0x0004)
+			len += sprintf(buf+len, "Local mem alloc ");
+		len += sprintf(buf+len, "\n");
+		break;
+	case 0x06:
+		len += sprintf(buf+len, "Operational no Rx\n");
+		break;
+	case 0x07:
+		len += sprintf(buf+len, "Suspended no Rx\n");
+		break;
+	default:
+		len += sprintf(buf+len, "Unspecified\n");
+		break;
+	}
+
+	len += sprintf(buf+len, "Min packet size     : %d\n", work32[2]);
+	len += sprintf(buf+len, "Max packet size     : %d\n", work32[3]);
+	len += sprintf(buf+len, "HW address          : "
+		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		       work8[16],work8[17],work8[18],work8[19],
+		       work8[20],work8[21],work8[22],work8[23]);
+
+	len += sprintf(buf+len, "Max Tx wire speed   : %d bps\n", (int)work64[3]);
+	len += sprintf(buf+len, "Max Rx wire speed   : %d bps\n", (int)work64[4]);
+
+	len += sprintf(buf+len, "Min SDU packet size : 0x%08x\n", work32[10]);
+	len += sprintf(buf+len, "Max SDU packet size : 0x%08x\n", work32[11]);
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* LAN group 0001h - MAC address table (scalar) */
+int i2o_proc_read_lan_mac_addr(char *buf, char **start, off_t offset, int len, 
+			       int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u32 work32[48];
+	static u8 *work8 = (u8*)work32;
+	int token;
+
+	spin_lock(&i2o_proc_lock);	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0001, -1, &work32, 48*4);
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0001 LAN MAC Address");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf,     "Active address          : "
+		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		       work8[0],work8[1],work8[2],work8[3],
+		       work8[4],work8[5],work8[6],work8[7]);
+	len += sprintf(buf+len, "Current address         : "
+		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		       work8[8],work8[9],work8[10],work8[11],
+		       work8[12],work8[13],work8[14],work8[15]);
+	len += sprintf(buf+len, "Functional address mask : "
+		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		       work8[16],work8[17],work8[18],work8[19],
+		       work8[20],work8[21],work8[22],work8[23]);
+
+	len += sprintf(buf+len,"HW/DDM capabilities : 0x%08x\n", work32[7]);
+	len += sprintf(buf+len,"    [%s] Unicast packets supported\n",
+		       (work32[7]&0x00000001)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Promiscuous mode supported\n",
+		       (work32[7]&0x00000002)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Promiscuous multicast mode supported\n",
+		       (work32[7]&0x00000004)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Broadcast reception disabling supported\n",
+		       (work32[7]&0x00000100)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Multicast reception disabling supported\n",
+		       (work32[7]&0x00000200)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Functional address disabling supported\n",
+		       (work32[7]&0x00000400)?"+":"-");
+	len += sprintf(buf+len,"    [%s] MAC reporting supported\n",
+		       (work32[7]&0x00000800)?"+":"-");
+
+	len += sprintf(buf+len,"Filter mask : 0x%08x\n", work32[6]);
+	len += sprintf(buf+len,"    [%s] Unicast packets disable\n",
+		(work32[6]&0x00000001)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Promiscuous mode enable\n",
+		(work32[6]&0x00000002)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Promiscuous multicast mode enable\n",
+		(work32[6]&0x00000004)?"+":"-");	
+	len += sprintf(buf+len,"    [%s] Broadcast packets disable\n",
+		(work32[6]&0x00000100)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Multicast packets disable\n",
+		(work32[6]&0x00000200)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Functional address disable\n",
+		       (work32[6]&0x00000400)?"+":"-");
+		       
+	if (work32[7]&0x00000800) {
+		len += sprintf(buf+len, "    MAC reporting mode : ");
+		if (work32[6]&0x00000800)
+			len += sprintf(buf+len, "Pass only priority MAC packets to user\n");
+		else if (work32[6]&0x00001000)
+			len += sprintf(buf+len, "Pass all MAC packets to user\n");
+		else if (work32[6]&0x00001800)
+			len += sprintf(buf+len, "Pass all MAC packets (promiscuous) to user\n");
+		else
+			len += sprintf(buf+len, "Do not pass MAC packets to user\n");
+	}
+	len += sprintf(buf+len, "Number of multicast addresses : %d\n", work32[8]);
+	len += sprintf(buf+len, "Perfect filtering for max %d multicast addresses\n",
+		       work32[9]);
+	len += sprintf(buf+len, "Imperfect filtering for max %d multicast addresses\n",
+		       work32[10]);
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+/* LAN group 0002h - Multicast MAC address table (table) */
+int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset,
+				 int len, int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+	int i;
+	u8 mc_addr[8];
+
+	struct
+	{
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8  block_status;
+		u8  error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		u8  mc_addr[256][8];
+	} result;	
+
+	spin_lock(&i2o_proc_lock);	
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				d->controller, d->lct_data.tid, 0x0002, -1, 
+				NULL, 0, &result, sizeof(result));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x002 LAN Multicast MAC Address");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	for (i = 0; i < result.row_count; i++)
+	{
+		memcpy(mc_addr, result.mc_addr[i], 8);
+
+		len += sprintf(buf+len, "MC MAC address[%d]: "
+			       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+			       i, mc_addr[0], mc_addr[1], mc_addr[2],
+			       mc_addr[3], mc_addr[4], mc_addr[5],
+			       mc_addr[6], mc_addr[7]);
+	}
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* LAN group 0003h - Batch Control (scalar) */
+int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset,
+				    int len, int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u32 work32[9];
+	int token;
+
+	spin_lock(&i2o_proc_lock);	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0003, -1, &work32, 9*4);
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0003 LAN Batch Control");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf, "Batch mode ");
+	if (work32[0]&0x00000001)
+		len += sprintf(buf+len, "disabled");
+	else
+		len += sprintf(buf+len, "enabled");
+	if (work32[0]&0x00000002)
+		len += sprintf(buf+len, " (current setting)");
+	if (work32[0]&0x00000004)
+		len += sprintf(buf+len, ", forced");
+	else
+		len += sprintf(buf+len, ", toggle");
+	len += sprintf(buf+len, "\n");
+
+	len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]);
+	len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]);
+	len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]);
+	len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]);
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* LAN group 0004h - LAN Operation (scalar) */
+int i2o_proc_read_lan_operation(char *buf, char **start, off_t offset, int len,
+				int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u32 work32[5];
+	int token;
+
+	spin_lock(&i2o_proc_lock);	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0004, -1, &work32, 20);
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0004 LAN Operation");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf, "Packet prepadding (32b words) : %d\n", work32[0]);
+	len += sprintf(buf+len, "Transmission error reporting  : %s\n",
+		       (work32[1]&1)?"on":"off");
+	len += sprintf(buf+len, "Bad packet handling           : %s\n",
+				(work32[1]&0x2)?"by host":"by DDM");
+	len += sprintf(buf+len, "Packet orphan limit           : %d\n", work32[2]);
+
+	len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[3]);
+	len += sprintf(buf+len, "    [%s] HW CRC suppression\n",
+			(work32[3]&0x00000004) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW IPv4 checksum\n",
+			(work32[3]&0x00000100) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW TCP checksum\n",
+			(work32[3]&0x00000200) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW UDP checksum\n",
+			(work32[3]&0x00000400) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW RSVP checksum\n",
+			(work32[3]&0x00000800) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW ICMP checksum\n",
+			(work32[3]&0x00001000) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] Loopback suppression enable\n",
+			(work32[3]&0x00002000) ? "+" : "-");
+
+	len += sprintf(buf+len, "Rx modes : 0x%08x\n", work32[4]);
+	len += sprintf(buf+len, "    [%s] FCS in payload\n",
+			(work32[4]&0x00000004) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW IPv4 checksum validation\n",
+			(work32[4]&0x00000100) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW TCP checksum validation\n",
+			(work32[4]&0x00000200) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW UDP checksum validation\n",
+			(work32[4]&0x00000400) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW RSVP checksum validation\n",
+			(work32[4]&0x00000800) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW ICMP checksum validation\n",
+			(work32[4]&0x00001000) ? "+" : "-");
+ 
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* LAN group 0005h - Media operation (scalar) */
+int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset,
+				      int len, int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+
+	struct
+	{
+		u32 connector_type;
+		u32 connection_type;
+		u64 current_tx_wire_speed;
+		u64 current_rx_wire_speed;
+		u8  duplex_mode;
+		u8  link_status;
+		u8  reserved;
+		u8  duplex_mode_target;
+		u32 connector_type_target;
+		u32 connection_type_target;
+	} result;	
+
+	spin_lock(&i2o_proc_lock);	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0005, -1, &result, sizeof(result));
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token, "0x0005 LAN Media Operation");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf, "Connector type         : %s\n",
+		       i2o_get_connector_type(result.connector_type));
+	len += sprintf(buf+len, "Connection type        : %s\n",
+		       i2o_get_connection_type(result.connection_type));
+
+	len += sprintf(buf+len, "Current Tx wire speed  : %d bps\n", (int)result.current_tx_wire_speed);
+	len += sprintf(buf+len, "Current Rx wire speed  : %d bps\n", (int)result.current_rx_wire_speed);
+	len += sprintf(buf+len, "Duplex mode            : %s duplex\n",
+			(result.duplex_mode)?"Full":"Half");
+			
+	len += sprintf(buf+len, "Link status            : ");
+	switch (result.link_status)
+	{
+	case 0x00:
+		len += sprintf(buf+len, "Unknown\n");
+		break;
+	case 0x01:
+		len += sprintf(buf+len, "Normal\n");
+		break;
+	case 0x02:
+		len += sprintf(buf+len, "Failure\n");
+		break;
+	case 0x03:
+		len += sprintf(buf+len, "Reset\n");
+		break;
+	default:
+		len += sprintf(buf+len, "Unspecified\n");
+	}
+	
+	len += sprintf(buf+len, "Duplex mode target     : ");
+	switch (result.duplex_mode_target){
+		case 0:
+			len += sprintf(buf+len, "Half duplex\n");
+			break;
+		case 1:
+			len += sprintf(buf+len, "Full duplex\n");
+			break;
+		default:
+			len += sprintf(buf+len, "\n");
+	}
+
+	len += sprintf(buf+len, "Connector type target  : %s\n",
+		       i2o_get_connector_type(result.connector_type_target));
+	len += sprintf(buf+len, "Connection type target : %s\n",
+		       i2o_get_connection_type(result.connection_type_target));
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* LAN group 0006h - Alternate address (table) (optional) */
+int i2o_proc_read_lan_alt_addr(char *buf, char **start, off_t offset, int len,
+			       int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+	int i;
+	u8 alt_addr[8];
+	struct
+	{
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8  block_status;
+		u8  error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		u8  alt_addr[256][8];
+	} result;	
+
+	spin_lock(&i2o_proc_lock);	
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				d->controller, d->lct_data.tid,
+				0x0006, -1, NULL, 0, &result, sizeof(result));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token, "0x0006 LAN Alternate Address (optional)");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	for (i=0; i < result.row_count; i++)
+	{
+		memcpy(alt_addr,result.alt_addr[i],8);
+		len += sprintf(buf+len, "Alternate address[%d]: "
+			       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+			       i, alt_addr[0], alt_addr[1], alt_addr[2],
+			       alt_addr[3], alt_addr[4], alt_addr[5],
+			       alt_addr[6], alt_addr[7]);
+	}
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+
+/* LAN group 0007h - Transmit info (scalar) */
+int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len, 
+			      int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u32 work32[8];
+	int token;
+
+	spin_lock(&i2o_proc_lock);	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0007, -1, &work32, 8*4);
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0007 LAN Transmit Info");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf,     "Tx Max SG elements per packet : %d\n", work32[0]);
+	len += sprintf(buf+len, "Tx Max SG elements per chain  : %d\n", work32[1]);
+	len += sprintf(buf+len, "Tx Max outstanding packets    : %d\n", work32[2]);
+	len += sprintf(buf+len, "Tx Max packets per request    : %d\n", work32[3]);
+
+	len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[4]);
+	len += sprintf(buf+len, "    [%s] No DA in SGL\n",
+				(work32[4]&0x00000002) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] CRC suppression\n",
+				(work32[4]&0x00000004) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] MAC insertion\n",
+				(work32[4]&0x00000010) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] RIF insertion\n",
+				(work32[4]&0x00000020) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] IPv4 checksum generation\n",
+				(work32[4]&0x00000100) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] TCP checksum generation\n",
+				(work32[4]&0x00000200) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] UDP checksum generation\n",
+				(work32[4]&0x00000400) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] RSVP checksum generation\n",
+				(work32[4]&0x00000800) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] ICMP checksum generation\n",
+				(work32[4]&0x00001000) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] Loopback enabled\n",
+				(work32[4]&0x00010000) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] Loopback suppression enabled\n",
+				(work32[4]&0x00020000) ? "+" : "-");
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* LAN group 0008h - Receive info (scalar) */
+int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len, 
+			      int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u32 work32[8];
+	int token;
+
+	spin_lock(&i2o_proc_lock);	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0008, -1, &work32, 8*4);
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0008 LAN Receive Info");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf     ,"Rx Max size of chain element : %d\n", work32[0]);
+	len += sprintf(buf+len, "Rx Max Buckets               : %d\n", work32[1]);
+	len += sprintf(buf+len, "Rx Max Buckets in Reply      : %d\n", work32[3]);
+	len += sprintf(buf+len, "Rx Max Packets in Bucket     : %d\n", work32[4]);
+	len += sprintf(buf+len, "Rx Max Buckets in Post       : %d\n", work32[5]);
+
+	len += sprintf(buf+len, "Rx Modes : 0x%08x\n", work32[2]);
+	len += sprintf(buf+len, "    [%s] FCS reception\n",
+				(work32[2]&0x00000004) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] IPv4 checksum validation \n",
+				(work32[2]&0x00000100) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] TCP checksum validation \n",
+				(work32[2]&0x00000200) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] UDP checksum validation \n",
+				(work32[2]&0x00000400) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] RSVP checksum validation \n",
+				(work32[2]&0x00000800) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] ICMP checksum validation \n",
+				(work32[2]&0x00001000) ? "+" : "-");
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+static int i2o_report_opt_field(char *buf, char *field_name,
+				int field_nbr, int supp_fields, u64 *value)
+{
+	if (supp_fields & (1 << field_nbr))
+		return sprintf(buf, "%-24s : " FMT_U64_HEX "\n", field_name, U64_VAL(value));
+	else	
+		return sprintf(buf, "%-24s : Not supported\n", field_name);	
+}
+
+/* LAN group 0100h - LAN Historical statistics (scalar) */
+/* LAN group 0180h - Supported Optional Historical Statistics (scalar) */
+/* LAN group 0182h - Optional Non Media Specific Transmit Historical Statistics (scalar) */
+/* LAN group 0183h - Optional Non Media Specific Receive Historical Statistics (scalar) */
+
+int i2o_proc_read_lan_hist_stats(char *buf, char **start, off_t offset, int len,
+				 int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+
+	struct
+	{
+		u64 tx_packets;
+		u64 tx_bytes;
+		u64 rx_packets;
+		u64 rx_bytes;
+		u64 tx_errors;
+		u64 rx_errors;
+		u64 rx_dropped;
+		u64 adapter_resets;
+		u64 adapter_suspends;
+	} stats;			// 0x0100
+
+	static u64 supp_groups[4];	// 0x0180
+
+	struct
+	{
+		u64 tx_retries;
+		u64 tx_directed_bytes;
+		u64 tx_directed_packets;
+		u64 tx_multicast_bytes;
+		u64 tx_multicast_packets;
+		u64 tx_broadcast_bytes;
+		u64 tx_broadcast_packets;
+		u64 tx_group_addr_packets;
+		u64 tx_short_packets;
+	} tx_stats;			// 0x0182
+
+	struct
+	{
+		u64 rx_crc_errors;
+		u64 rx_directed_bytes;
+		u64 rx_directed_packets;
+		u64 rx_multicast_bytes;
+		u64 rx_multicast_packets;
+		u64 rx_broadcast_bytes;
+		u64 rx_broadcast_packets;
+		u64 rx_group_addr_packets;
+		u64 rx_short_packets;
+		u64 rx_long_packets;
+		u64 rx_runt_packets;
+	} rx_stats;			// 0x0183
+
+	struct
+	{
+		u64 ipv4_generate;
+		u64 ipv4_validate_success;
+		u64 ipv4_validate_errors;
+		u64 tcp_generate;
+		u64 tcp_validate_success;
+		u64 tcp_validate_errors;
+		u64 udp_generate;
+		u64 udp_validate_success;
+		u64 udp_validate_errors;
+		u64 rsvp_generate;
+		u64 rsvp_validate_success;
+		u64 rsvp_validate_errors;		
+		u64 icmp_generate;
+		u64 icmp_validate_success;
+		u64 icmp_validate_errors;
+	} chksum_stats;			// 0x0184
+
+	spin_lock(&i2o_proc_lock);	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0100, -1, &stats, sizeof(stats));
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x100 LAN Statistics");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf+len, "Tx packets       : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.tx_packets));
+	len += sprintf(buf+len, "Tx bytes         : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.tx_bytes));
+	len += sprintf(buf+len, "Rx packets       : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.rx_packets));
+	len += sprintf(buf+len, "Rx bytes         : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.rx_bytes));
+	len += sprintf(buf+len, "Tx errors        : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.tx_errors));
+	len += sprintf(buf+len, "Rx errors        : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.rx_errors));
+	len += sprintf(buf+len, "Rx dropped       : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.rx_dropped));
+	len += sprintf(buf+len, "Adapter resets   : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.adapter_resets));
+	len += sprintf(buf+len, "Adapter suspends : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.adapter_suspends));
+
+	/* Optional statistics follows */
+	/* Get 0x0180 to see which optional groups/fields are supported */
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0180, -1, &supp_groups, sizeof(supp_groups));
+	
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token, "0x180 LAN Supported Optional Statistics");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	if (supp_groups[1]) /* 0x0182 */
+	{
+		token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 	0x0182, -1, &tx_stats, sizeof(tx_stats));
+
+		if (token < 0) {
+			len += i2o_report_query_status(buf+len, token,"0x182 LAN Optional Tx Historical Statistics");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+		}
+
+		len += sprintf(buf+len, "==== Optional TX statistics (group 0182h)\n");
+
+		len += i2o_report_opt_field(buf+len, "Tx RetryCount",
+					0, supp_groups[1], &tx_stats.tx_retries);
+		len += i2o_report_opt_field(buf+len, "Tx DirectedBytes",
+					1, supp_groups[1], &tx_stats.tx_directed_bytes);
+		len += i2o_report_opt_field(buf+len, "Tx DirectedPackets",
+					2, supp_groups[1], &tx_stats.tx_directed_packets);
+		len += i2o_report_opt_field(buf+len, "Tx MulticastBytes",
+					3, supp_groups[1], &tx_stats.tx_multicast_bytes);
+		len += i2o_report_opt_field(buf+len, "Tx MulticastPackets",
+					4, supp_groups[1], &tx_stats.tx_multicast_packets);
+		len += i2o_report_opt_field(buf+len, "Tx BroadcastBytes",
+					5, supp_groups[1], &tx_stats.tx_broadcast_bytes);
+		len += i2o_report_opt_field(buf+len, "Tx BroadcastPackets",
+					6, supp_groups[1], &tx_stats.tx_broadcast_packets);
+		len += i2o_report_opt_field(buf+len, "Tx TotalGroupAddrPackets",
+					7, supp_groups[1], &tx_stats.tx_group_addr_packets);
+		len += i2o_report_opt_field(buf+len, "Tx TotalPacketsTooShort",
+					8, supp_groups[1], &tx_stats.tx_short_packets);
+	}
+
+	if (supp_groups[2]) /* 0x0183 */
+	{
+		token = i2o_query_scalar(d->controller, d->lct_data.tid,
+					 0x0183, -1, &rx_stats, sizeof(rx_stats));
+		if (token < 0) {
+			len += i2o_report_query_status(buf+len, token,"0x183 LAN Optional Rx Historical Stats");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+		}
+
+		len += sprintf(buf+len, "==== Optional RX statistics (group 0183h)\n");
+
+		len += i2o_report_opt_field(buf+len, "Rx CRCErrorCount",
+					0, supp_groups[2], &rx_stats.rx_crc_errors);
+		len += i2o_report_opt_field(buf+len, "Rx DirectedBytes",
+					1, supp_groups[2], &rx_stats.rx_directed_bytes);
+		len += i2o_report_opt_field(buf+len, "Rx DirectedPackets",
+					2, supp_groups[2], &rx_stats.rx_directed_packets);
+		len += i2o_report_opt_field(buf+len, "Rx MulticastBytes",
+					3, supp_groups[2], &rx_stats.rx_multicast_bytes);
+		len += i2o_report_opt_field(buf+len, "Rx MulticastPackets",
+					4, supp_groups[2], &rx_stats.rx_multicast_packets);
+		len += i2o_report_opt_field(buf+len, "Rx BroadcastBytes",
+					5, supp_groups[2], &rx_stats.rx_broadcast_bytes);
+		len += i2o_report_opt_field(buf+len, "Rx BroadcastPackets",
+					6, supp_groups[2], &rx_stats.rx_broadcast_packets);
+		len += i2o_report_opt_field(buf+len, "Rx TotalGroupAddrPackets",
+					7, supp_groups[2], &rx_stats.rx_group_addr_packets);
+		len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooShort",
+					8, supp_groups[2], &rx_stats.rx_short_packets);
+		len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooLong",
+					9, supp_groups[2], &rx_stats.rx_long_packets);
+		len += i2o_report_opt_field(buf+len, "Rx TotalPacketsRunt",
+					10, supp_groups[2], &rx_stats.rx_runt_packets);
+	}
+	
+	if (supp_groups[3]) /* 0x0184 */
+	{
+		token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 	0x0184, -1, &chksum_stats, sizeof(chksum_stats));
+
+		if (token < 0) {
+			len += i2o_report_query_status(buf+len, token,"0x184 LAN Optional Chksum Historical Stats");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+		}
+
+		len += sprintf(buf+len, "==== Optional CHKSUM statistics (group 0x0184)\n");
+
+		len += i2o_report_opt_field(buf+len, "IPv4 Generate",
+					0, supp_groups[3], &chksum_stats.ipv4_generate);
+		len += i2o_report_opt_field(buf+len, "IPv4 ValidateSuccess",
+					1, supp_groups[3], &chksum_stats.ipv4_validate_success);
+		len += i2o_report_opt_field(buf+len, "IPv4 ValidateError",
+					2, supp_groups[3], &chksum_stats.ipv4_validate_errors);
+		len += i2o_report_opt_field(buf+len, "TCP  Generate",
+					3, supp_groups[3], &chksum_stats.tcp_generate);
+		len += i2o_report_opt_field(buf+len, "TCP  ValidateSuccess",
+					4, supp_groups[3], &chksum_stats.tcp_validate_success);
+		len += i2o_report_opt_field(buf+len, "TCP  ValidateError",
+					5, supp_groups[3], &chksum_stats.tcp_validate_errors);
+		len += i2o_report_opt_field(buf+len, "UDP  Generate",
+					6, supp_groups[3], &chksum_stats.udp_generate);
+		len += i2o_report_opt_field(buf+len, "UDP  ValidateSuccess",
+					7, supp_groups[3], &chksum_stats.udp_validate_success);
+		len += i2o_report_opt_field(buf+len, "UDP  ValidateError",
+					8, supp_groups[3], &chksum_stats.udp_validate_errors);
+		len += i2o_report_opt_field(buf+len, "RSVP Generate",
+					9, supp_groups[3], &chksum_stats.rsvp_generate);
+		len += i2o_report_opt_field(buf+len, "RSVP ValidateSuccess",
+					10, supp_groups[3], &chksum_stats.rsvp_validate_success);
+		len += i2o_report_opt_field(buf+len, "RSVP ValidateError",
+					11, supp_groups[3], &chksum_stats.rsvp_validate_errors);
+		len += i2o_report_opt_field(buf+len, "ICMP Generate",
+					12, supp_groups[3], &chksum_stats.icmp_generate);
+		len += i2o_report_opt_field(buf+len, "ICMP ValidateSuccess",
+					13, supp_groups[3], &chksum_stats.icmp_validate_success);
+		len += i2o_report_opt_field(buf+len, "ICMP ValidateError",
+					14, supp_groups[3], &chksum_stats.icmp_validate_errors);
+	}
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* LAN group 0200h - Required Ethernet Statistics (scalar) */
+/* LAN group 0280h - Optional Ethernet Statistics Supported (scalar) */
+/* LAN group 0281h - Optional Ethernet Historical Statistics (scalar) */
+int i2o_proc_read_lan_eth_stats(char *buf, char **start, off_t offset,
+				int len, int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	int token;
+
+	struct
+	{
+		u64 rx_align_errors;
+		u64 tx_one_collisions;
+		u64 tx_multiple_collisions;
+		u64 tx_deferred;
+		u64 tx_late_collisions;
+		u64 tx_max_collisions;
+		u64 tx_carrier_lost;
+		u64 tx_excessive_deferrals;
+	} stats;	
+
+	static u64 supp_fields;
+	struct
+	{
+		u64 rx_overrun;
+		u64 tx_underrun;
+		u64 tx_heartbeat_failure;	
+	} hist_stats;
+
+	spin_lock(&i2o_proc_lock);	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0200, -1, &stats, sizeof(stats));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0200 LAN Ethernet Statistics");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf+len, "Rx alignment errors    : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.rx_align_errors));
+	len += sprintf(buf+len, "Tx one collisions      : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.tx_one_collisions));
+	len += sprintf(buf+len, "Tx multicollisions     : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.tx_multiple_collisions));
+	len += sprintf(buf+len, "Tx deferred            : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.tx_deferred));
+	len += sprintf(buf+len, "Tx late collisions     : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.tx_late_collisions));
+	len += sprintf(buf+len, "Tx max collisions      : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.tx_max_collisions));
+	len += sprintf(buf+len, "Tx carrier lost        : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.tx_carrier_lost));
+	len += sprintf(buf+len, "Tx excessive deferrals : " FMT_U64_HEX "\n",
+		       U64_VAL(&stats.tx_excessive_deferrals));
+
+	/* Optional Ethernet statistics follows  */
+	/* Get 0x0280 to see which optional fields are supported */
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0280, -1, &supp_fields, sizeof(supp_fields));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0280 LAN Supported Optional Ethernet Statistics");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	if (supp_fields) /* 0x0281 */
+	{
+		token = i2o_query_scalar(d->controller, d->lct_data.tid,
+					 0x0281, -1, &stats, sizeof(stats));
+
+		if (token < 0) {
+			len += i2o_report_query_status(buf+len, token,"0x0281 LAN Optional Ethernet Statistics");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+		}
+
+		len += sprintf(buf+len, "==== Optional ETHERNET statistics (group 0x0281)\n");
+
+		len += i2o_report_opt_field(buf+len, "Rx Overrun",
+					0, supp_fields, &hist_stats.rx_overrun);
+		len += i2o_report_opt_field(buf+len, "Tx Underrun",
+					1, supp_fields, &hist_stats.tx_underrun);
+		len += i2o_report_opt_field(buf+len, "Tx HeartbeatFailure",
+					2, supp_fields, &hist_stats.tx_heartbeat_failure);
+	}
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* LAN group 0300h - Required Token Ring Statistics (scalar) */
+/* LAN group 0380h, 0381h - Optional Statistics not yet defined (TODO) */
+int i2o_proc_read_lan_tr_stats(char *buf, char **start, off_t offset,
+			       int len, int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u64 work64[13];
+	int token;
+
+	static char *ring_status[] =
+	{
+		"",
+		"",
+		"",
+		"",
+		"",
+		"Ring Recovery",
+		"Single Station",
+		"Counter Overflow",
+		"Remove Received",
+		"",
+		"Auto-Removal Error 1",
+		"Lobe Wire Fault",
+		"Transmit Beacon",
+		"Soft Error",
+		"Hard Error",
+		"Signal Loss"
+	};
+
+	spin_lock(&i2o_proc_lock);	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0300, -1, &work64, sizeof(work64));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0300 Token Ring Statistics");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf,     "LineErrors          : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[0]));
+	len += sprintf(buf+len, "LostFrames          : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[1]));
+	len += sprintf(buf+len, "ACError             : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[2]));
+	len += sprintf(buf+len, "TxAbortDelimiter    : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[3]));
+	len += sprintf(buf+len, "BursErrors          : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[4]));
+	len += sprintf(buf+len, "FrameCopiedErrors   : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[5]));
+	len += sprintf(buf+len, "FrequencyErrors     : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[6]));
+	len += sprintf(buf+len, "InternalErrors      : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[7]));
+	len += sprintf(buf+len, "LastRingStatus      : %s\n", ring_status[work64[8]]);
+	len += sprintf(buf+len, "TokenError          : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[9]));
+	len += sprintf(buf+len, "UpstreamNodeAddress : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[10]));
+	len += sprintf(buf+len, "LastRingID          : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[11]));
+	len += sprintf(buf+len, "LastBeaconType      : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[12]));
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* LAN group 0400h - Required FDDI Statistics (scalar) */
+/* LAN group 0480h, 0481h - Optional Statistics, not yet defined (TODO) */
+int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset,
+				 int len, int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u64 work64[11];
+	int token;
+
+	static char *conf_state[] =
+	{
+		"Isolated",
+		"Local a",
+		"Local b",
+		"Local ab",
+		"Local s",
+		"Wrap a",
+		"Wrap b",
+		"Wrap ab",
+		"Wrap s",
+		"C-Wrap a",
+		"C-Wrap b",
+		"C-Wrap s",
+		"Through",
+	};
+
+	static char *ring_state[] =
+	{
+		"Isolated",
+		"Non-op",
+		"Rind-op",
+		"Detect",
+		"Non-op-Dup",
+		"Ring-op-Dup",
+		"Directed",
+		"Trace"
+	};
+
+	static char *link_state[] =
+	{
+		"Off",
+		"Break",
+		"Trace",
+		"Connect",
+		"Next",
+		"Signal",
+		"Join",
+		"Verify",
+		"Active",
+		"Maintenance"
+	};
+
+	spin_lock(&i2o_proc_lock);
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
+				 0x0400, -1, &work64, sizeof(work64));
+
+	if (token < 0) {
+		len += i2o_report_query_status(buf+len, token,"0x0400 FDDI Required Statistics");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf+len, "ConfigurationState : %s\n", conf_state[work64[0]]);
+	len += sprintf(buf+len, "UpstreamNode       : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[1]));
+	len += sprintf(buf+len, "DownStreamNode     : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[2]));
+	len += sprintf(buf+len, "FrameErrors        : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[3]));
+	len += sprintf(buf+len, "FramesLost         : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[4]));
+	len += sprintf(buf+len, "RingMgmtState      : %s\n", ring_state[work64[5]]);
+	len += sprintf(buf+len, "LCTFailures        : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[6]));
+	len += sprintf(buf+len, "LEMRejects         : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[7]));
+	len += sprintf(buf+len, "LEMCount           : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[8]));
+	len += sprintf(buf+len, "LConnectionState   : %s\n",
+		       link_state[work64[9]]);
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+static int i2o_proc_create_entries(void *data, i2o_proc_entry *pentry,
+				   struct proc_dir_entry *parent)
+{
+	struct proc_dir_entry *ent;
+	
+	while(pentry->name != NULL)
+	{
+		ent = create_proc_entry(pentry->name, pentry->mode, parent);
+		if(!ent) return -1;
+
+		ent->data = data;
+		ent->read_proc = pentry->read_proc;
+		ent->write_proc = pentry->write_proc;
+		ent->nlink = 1;
+
+		pentry++;
+	}
+
+	return 0;
+}
+
+static void i2o_proc_remove_entries(i2o_proc_entry *pentry, 
+				    struct proc_dir_entry *parent)
+{
+	while(pentry->name != NULL)
+	{
+		remove_proc_entry(pentry->name, parent);
+		pentry++;
+	}
+}
+
+static int i2o_proc_add_controller(struct i2o_controller *pctrl, 
+				   struct proc_dir_entry *root )
+{
+	struct proc_dir_entry *dir, *dir1;
+	struct i2o_device *dev;
+	char buff[10];
+
+	sprintf(buff, "iop%d", pctrl->unit);
+
+	dir = proc_mkdir(buff, root);
+	if(!dir)
+		return -1;
+
+	pctrl->proc_entry = dir;
+
+	i2o_proc_create_entries(pctrl, generic_iop_entries, dir);
+	
+	for(dev = pctrl->devices; dev; dev = dev->next)
+	{
+		sprintf(buff, "%0#5x", dev->lct_data.tid);
+
+		dir1 = proc_mkdir(buff, dir);
+		dev->proc_entry = dir1;
+
+		if(!dir1)
+			printk(KERN_INFO "i2o_proc: Could not allocate proc dir\n");
+
+		i2o_proc_add_device(dev, dir1);
+	}
+
+	return 0;
+}
+
+void i2o_proc_new_dev(struct i2o_controller *c, struct i2o_device *d)
+{
+	char buff[10];
+
+#ifdef DRIVERDEBUG
+	printk(KERN_INFO "Adding new device to /proc/i2o/iop%d\n", c->unit);
+#endif
+	sprintf(buff, "%0#5x", d->lct_data.tid);
+
+	d->proc_entry = proc_mkdir(buff, c->proc_entry);
+
+	if(!d->proc_entry)
+	{
+		printk(KERN_WARNING "i2o: Could not allocate procdir!\n");
+		return;
+	}
+
+	i2o_proc_add_device(d, d->proc_entry);
+}
+
+void i2o_proc_add_device(struct i2o_device *dev, struct proc_dir_entry *dir)
+{	
+	i2o_proc_create_entries(dev, generic_dev_entries, dir);
+
+	/* Inform core that we want updates about this device's status */
+	i2o_device_notify_on(dev, &i2o_proc_handler);
+	switch(dev->lct_data.class_id)
+	{
+		case I2O_CLASS_SCSI_PERIPHERAL:
+		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+			i2o_proc_create_entries(dev, rbs_dev_entries, dir);
+			break;
+		case I2O_CLASS_LAN:
+			i2o_proc_create_entries(dev, lan_entries, dir);
+			switch(dev->lct_data.sub_class)
+			{
+				case I2O_LAN_ETHERNET:
+					i2o_proc_create_entries(dev, lan_eth_entries, dir);
+					break;
+				case I2O_LAN_FDDI:
+					i2o_proc_create_entries(dev, lan_fddi_entries, dir);
+					break;
+				case I2O_LAN_TR:
+					i2o_proc_create_entries(dev, lan_tr_entries, dir);
+					break;
+				default:
+					break;
+			}
+			break;
+		default:
+			break;
+	}
+}
+
+static void i2o_proc_remove_controller(struct i2o_controller *pctrl, 
+				       struct proc_dir_entry *parent)
+{
+	char buff[10];
+	struct i2o_device *dev;
+
+	/* Remove unused device entries */
+	for(dev=pctrl->devices; dev; dev=dev->next)
+		i2o_proc_remove_device(dev);
+
+	if(!atomic_read(&pctrl->proc_entry->count))
+	{
+		sprintf(buff, "iop%d", pctrl->unit);
+
+		i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry);
+
+		remove_proc_entry(buff, parent);
+		pctrl->proc_entry = NULL;
+	}
+}
+
+void i2o_proc_remove_device(struct i2o_device *dev)
+{
+	struct proc_dir_entry *de=dev->proc_entry;
+	char dev_id[10];
+
+	sprintf(dev_id, "%0#5x", dev->lct_data.tid);
+
+	i2o_device_notify_off(dev, &i2o_proc_handler);
+	/* Would it be safe to remove _files_ even if they are in use? */
+	if((de) && (!atomic_read(&de->count)))
+	{
+		i2o_proc_remove_entries(generic_dev_entries, de);
+		switch(dev->lct_data.class_id)
+		{
+			case I2O_CLASS_SCSI_PERIPHERAL:
+			case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+				i2o_proc_remove_entries(rbs_dev_entries, de);
+				break;
+			case I2O_CLASS_LAN:
+			{
+				i2o_proc_remove_entries(lan_entries, de);
+				switch(dev->lct_data.sub_class)
+				{
+				case I2O_LAN_ETHERNET:
+					i2o_proc_remove_entries(lan_eth_entries, de);
+					break;
+				case I2O_LAN_FDDI:
+					i2o_proc_remove_entries(lan_fddi_entries, de);
+					break;
+				case I2O_LAN_TR:
+					i2o_proc_remove_entries(lan_tr_entries, de);
+					break;
+				}
+			}
+			remove_proc_entry(dev_id, dev->controller->proc_entry);
+		}
+	}
+}
+	
+void i2o_proc_dev_del(struct i2o_controller *c, struct i2o_device *d)
+{
+#ifdef DRIVERDEBUG
+	printk(KERN_INFO, "Deleting device %d from iop%d\n", 
+		d->lct_data.tid, c->unit);
+#endif
+
+	i2o_proc_remove_device(d);
+}
+
+static int create_i2o_procfs(void)
+{
+	struct i2o_controller *pctrl = NULL;
+	int i;
+
+	i2o_proc_dir_root = proc_mkdir("i2o", 0);
+	if(!i2o_proc_dir_root)
+		return -1;
+
+	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
+	{
+		pctrl = i2o_find_controller(i);
+		if(pctrl)
+		{
+			i2o_proc_add_controller(pctrl, i2o_proc_dir_root);
+			i2o_unlock_controller(pctrl);
+		}
+	};
+
+	return 0;
+}
+
+static int __exit destroy_i2o_procfs(void)
+{
+	struct i2o_controller *pctrl = NULL;
+	int i;
+
+	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
+	{
+		pctrl = i2o_find_controller(i);
+		if(pctrl)
+		{
+			i2o_proc_remove_controller(pctrl, i2o_proc_dir_root);
+			i2o_unlock_controller(pctrl);
+		}
+	}
+
+	if(!atomic_read(&i2o_proc_dir_root->count))
+		remove_proc_entry("i2o", 0);
+	else
+		return -1;
+
+	return 0;
+}
+
+int __init i2o_proc_init(void)
+{
+	if (i2o_install_handler(&i2o_proc_handler) < 0)
+	{
+		printk(KERN_ERR "i2o_proc: Unable to install PROC handler.\n");
+		return 0;
+	}
+
+	if(create_i2o_procfs())
+		return -EBUSY;
+
+	return 0;
+}
+
+MODULE_AUTHOR("Deepak Saxena");
+MODULE_DESCRIPTION("I2O procfs Handler");
+
+static void __exit i2o_proc_exit(void)
+{
+	destroy_i2o_procfs();
+	i2o_remove_handler(&i2o_proc_handler);
+}
+
+#ifdef MODULE
+module_init(i2o_proc_init);
+#endif
+module_exit(i2o_proc_exit);
+
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/i2o_scsi.c linux/drivers/message/i2o/i2o_scsi.c
--- v2.4.12/linux/drivers/message/i2o/i2o_scsi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/i2o_scsi.c	Fri Oct 19 08:32:28 2001
@@ -0,0 +1,912 @@
+/* 
+ *  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, 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.
+ *
+ *  Complications for I2O scsi
+ *
+ *	o	Each (bus,lun) is a logical device in I2O. We keep a map
+ *		table. We spoof failed selection for unmapped units
+ *	o	Request sense buffers can come back for free. 
+ *	o	Scatter gather is a bit dynamic. We have to investigate at
+ *		setup time.
+ *	o	Some of our resources are dynamically shared. The i2o core
+ *		needs a message reservation protocol to avoid swap v net
+ *		deadlocking. We need to back off queue requests.
+ *	
+ *	In general the firmware wants to help. Where its help isn't performance
+ *	useful we just ignore the aid. Its not worth the code in truth.
+ *
+ *	Fixes:
+ *		Steve Ralston	:	Scatter gather now works
+ *
+ *	To Do
+ *		64bit cleanups
+ *		Fix the resource management problems.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <linux/blk.h>
+#include <linux/version.h>
+#include <linux/i2o.h>
+#include "../../scsi/scsi.h"
+#include "../../scsi/hosts.h"
+#include "../../scsi/sd.h"
+#include "i2o_scsi.h"
+
+#define VERSION_STRING        "Version 0.0.1"
+
+#define dprintk(x)
+
+#define MAXHOSTS 32
+
+struct i2o_scsi_host
+{
+	struct i2o_controller *controller;
+	s16 task[16][8];		/* Allow 16 devices for now */
+	unsigned long tagclock[16][8];	/* Tag clock for queueing */
+	s16 bus_task;		/* The adapter TID */
+};
+
+static int scsi_context;
+static int lun_done;
+static int i2o_scsi_hosts;
+
+static u32 *retry[32];
+static struct i2o_controller *retry_ctrl[32];
+static struct timer_list retry_timer;
+static int retry_ct = 0;
+
+static atomic_t queue_depth;
+
+/*
+ *	SG Chain buffer support...
+ */
+
+#define SG_MAX_FRAGS		64
+
+/*
+ *	FIXME: we should allocate one of these per bus we find as we
+ *	locate them not in a lump at boot.
+ */
+ 
+typedef struct _chain_buf
+{
+	u32 sg_flags_cnt[SG_MAX_FRAGS];
+	u32 sg_buf[SG_MAX_FRAGS];
+} chain_buf;
+
+#define SG_CHAIN_BUF_SZ sizeof(chain_buf)
+
+#define SG_MAX_BUFS		(i2o_num_controllers * I2O_SCSI_CAN_QUEUE)
+#define SG_CHAIN_POOL_SZ	(SG_MAX_BUFS * SG_CHAIN_BUF_SZ)
+
+static int max_sg_len = 0;
+static chain_buf *sg_chain_pool = NULL;
+static int sg_chain_tag = 0;
+static int sg_max_frags = SG_MAX_FRAGS;
+
+/*
+ *	Retry congested frames. This actually needs pushing down into
+ *	i2o core. We should only bother the OSM with this when we can't
+ *	queue and retry the frame. Or perhaps we should call the OSM
+ *	and its default handler should be this in the core, and this
+ *	call a 2nd "I give up" handler in the OSM ?
+ */
+ 
+static void i2o_retry_run(unsigned long f)
+{
+	int i;
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+
+	for(i=0;i<retry_ct;i++)
+		i2o_post_message(retry_ctrl[i], virt_to_bus(retry[i]));
+	retry_ct=0;
+	
+	restore_flags(flags);
+}
+
+static void flush_pending(void)
+{
+	int i;
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+
+	for(i=0;i<retry_ct;i++)
+	{
+		retry[i][0]&=~0xFFFFFF;
+		retry[i][0]|=I2O_CMD_UTIL_NOP<<24;
+		i2o_post_message(retry_ctrl[i],virt_to_bus(retry[i]));
+	}
+	retry_ct=0;
+	
+	restore_flags(flags);
+}
+
+static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
+{
+	Scsi_Cmnd *current_command;
+	u32 *m = (u32 *)msg;
+	u8 as,ds,st;
+	
+	if(m[0] & (1<<13))
+	{
+		printk("IOP fail.\n");
+		printk("From %d To %d Cmd %d.\n",
+			(m[1]>>12)&0xFFF,
+			m[1]&0xFFF,
+			m[1]>>24);
+		printk("Failure Code %d.\n", m[4]>>24);
+		if(m[4]&(1<<16))
+			printk("Format error.\n");
+		if(m[4]&(1<<17))
+			printk("Path error.\n");
+		if(m[4]&(1<<18))
+			printk("Path State.\n");
+		if(m[4]&(1<<18))
+			printk("Congestion.\n");
+		
+		m=(u32 *)bus_to_virt(m[7]);
+		printk("Failing message is %p.\n", m);
+		
+		if((m[4]&(1<<18)) && retry_ct < 32)
+		{
+			retry_ctrl[retry_ct]=c;
+			retry[retry_ct]=m;
+			if(!retry_ct++)
+			{
+				retry_timer.expires=jiffies+1;
+				add_timer(&retry_timer);
+			}
+		}
+		else
+		{
+			/* Create a scsi error for this */
+			current_command = (Scsi_Cmnd *)m[3];
+			printk("Aborted %ld\n", current_command->serial_number);
+
+			spin_lock_irq(&io_request_lock);			
+			current_command->result = DID_ERROR << 16;
+			current_command->scsi_done(current_command);
+			spin_unlock_irq(&io_request_lock);			
+			
+			/* Now flush the message by making it a NOP */
+			m[0]&=0x00FFFFFF;
+			m[0]|=(I2O_CMD_UTIL_NOP)<<24;
+			i2o_post_message(c,virt_to_bus(m));
+		}
+		return;
+	}
+			
+	
+	/*
+	 *	Low byte is device status, next is adapter status,
+	 *	(then one byte reserved), then request status.
+	 */
+	ds=(u8)m[4]; 
+	as=(u8)(m[4]>>8);
+	st=(u8)(m[4]>>24);
+	
+	dprintk(("i2o got a scsi reply %08X: ", m[0]));
+	dprintk(("m[2]=%08X: ", m[2]));
+	dprintk(("m[4]=%08X\n", m[4]));
+
+	if(m[2]&0x80000000)
+	{
+		if(m[2]&0x40000000)
+		{
+			dprintk(("Event.\n"));
+			lun_done=1;
+			return;
+		}
+		printk(KERN_ERR "i2o_scsi: bus reset reply.\n");
+		return;
+	}
+	
+	current_command = (Scsi_Cmnd *)m[3];
+	
+	/*
+	 *	Is this a control request coming back - eg an abort ?
+	 */
+	 
+	if(current_command==NULL)
+	{
+		if(st)
+			dprintk(("SCSI abort: %08X", m[4]));
+		dprintk(("SCSI abort completed.\n"));
+		return;
+	}
+	
+	dprintk(("Completed %ld\n", current_command->serial_number));
+	
+	atomic_dec(&queue_depth);
+	
+	if(st == 0x06)
+	{
+		if(m[5] < current_command->underflow)
+		{
+			int i;
+			printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X\n",
+				m[5], current_command->underflow);
+			printk("Cmd: ");
+			for(i=0;i<15;i++)
+				printk("%02X ", current_command->cmnd[i]);
+			printk(".\n");
+		}
+		else st=0;
+	}
+	
+	if(st)
+	{
+		/* An error has occurred */
+
+		dprintk((KERN_DEBUG "SCSI error %08X", m[4]));
+			
+		if (as == 0x0E) 
+			/* SCSI Reset */
+			current_command->result = DID_RESET << 16;
+		else if (as == 0x0F)
+			current_command->result = DID_PARITY << 16;
+		else
+			current_command->result = DID_ERROR << 16;
+	}
+	else
+		/*
+		 *	It worked maybe ?
+		 */		
+		current_command->result = DID_OK << 16 | ds;
+	spin_lock(&io_request_lock);
+	current_command->scsi_done(current_command);
+	spin_unlock(&io_request_lock);
+	return;
+}
+
+struct i2o_handler i2o_scsi_handler=
+{
+	i2o_scsi_reply,
+	NULL,
+	NULL,
+	NULL,
+	"I2O SCSI OSM",
+	0,
+	I2O_CLASS_SCSI_PERIPHERAL
+};
+
+static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun)
+{
+	u8 reply[8];
+	
+	if(i2o_query_scalar(c, d->lct_data.tid, 0, 3, reply, 4)<0)
+		return -1;
+		
+	*target=reply[0];
+	
+	if(i2o_query_scalar(c, d->lct_data.tid, 0, 4, reply, 8)<0)
+		return -1;
+
+	*lun=reply[1];
+
+	dprintk(("SCSI (%d,%d)\n", *target, *lun));
+	return 0;
+}
+
+void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
+{
+	struct i2o_device *unit;
+	struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata;
+	int lun;
+	int target;
+	
+	h->controller=c;
+	h->bus_task=d->lct_data.tid;
+	
+	for(target=0;target<16;target++)
+		for(lun=0;lun<8;lun++)
+			h->task[target][lun] = -1;
+			
+	for(unit=c->devices;unit!=NULL;unit=unit->next)
+	{
+		dprintk(("Class %03X, parent %d, want %d.\n",
+			unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid));
+			
+		/* Only look at scsi and fc devices */
+		if (    (unit->lct_data.class_id != I2O_CLASS_SCSI_PERIPHERAL)
+		     && (unit->lct_data.class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL)
+		   )
+			continue;
+
+		/* On our bus ? */
+		dprintk(("Found a disk (%d).\n", unit->lct_data.tid));
+		if ((unit->lct_data.parent_tid == d->lct_data.tid)
+		     || (unit->lct_data.parent_tid == d->lct_data.parent_tid)
+		   )
+		{
+			u16 limit;
+			dprintk(("Its ours.\n"));
+			if(i2o_find_lun(c, unit, &target, &lun)==-1)
+			{
+				printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data.tid);
+				continue;
+			}
+			dprintk(("Found disk %d %d.\n", target, lun));
+			h->task[target][lun]=unit->lct_data.tid;
+			h->tagclock[target][lun]=jiffies;
+
+			/* Get the max fragments/request */
+			i2o_query_scalar(c, d->lct_data.tid, 0xF103, 3, &limit, 2);
+			
+			/* sanity */
+			if ( limit == 0 )
+			{
+				printk(KERN_WARNING "i2o_scsi: Ignoring unreasonable SG limit of 0 from IOP!\n");
+				limit = 1;
+			}
+			
+			shpnt->sg_tablesize = limit;
+
+			dprintk(("i2o_scsi: set scatter-gather to %d.\n", 
+				shpnt->sg_tablesize));
+		}
+	}		
+}
+
+int i2o_scsi_detect(Scsi_Host_Template * tpnt)
+{
+	unsigned long flags;
+	struct Scsi_Host *shpnt = NULL;
+	int i;
+	int count;
+
+	printk("i2o_scsi.c: %s\n", VERSION_STRING);
+
+	if(i2o_install_handler(&i2o_scsi_handler)<0)
+	{
+		printk(KERN_ERR "i2o_scsi: Unable to install OSM handler.\n");
+		return 0;
+	}
+	scsi_context = i2o_scsi_handler.context;
+	
+	if((sg_chain_pool = kmalloc(SG_CHAIN_POOL_SZ, GFP_KERNEL)) == NULL)
+	{
+		printk("i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ);
+		printk("i2o_scsi: SG chaining DISABLED!\n");
+		sg_max_frags = 11;
+	}
+	else
+	{
+		printk("  chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool);
+		printk("  (%d byte buffers X %d can_queue X %d i2o controllers)\n",
+				SG_CHAIN_BUF_SZ, I2O_SCSI_CAN_QUEUE, i2o_num_controllers);
+		sg_max_frags = SG_MAX_FRAGS;    // 64
+	}
+	
+	init_timer(&retry_timer);
+	retry_timer.data = 0UL;
+	retry_timer.function = i2o_retry_run;
+	
+//	printk("SCSI OSM at %d.\n", scsi_context);
+
+	for (count = 0, i = 0; i < MAX_I2O_CONTROLLERS; i++)
+	{
+		struct i2o_controller *c=i2o_find_controller(i);
+		struct i2o_device *d;
+		/*
+		 *	This controller doesn't exist.
+		 */
+		
+		if(c==NULL)
+			continue;
+			
+		/*
+		 *	Fixme - we need some altered device locking. This
+		 *	is racing with device addition in theory. Easy to fix.
+		 */
+		
+		for(d=c->devices;d!=NULL;d=d->next)
+		{
+			/*
+			 *	bus_adapter, SCSI (obsolete), or FibreChannel busses only
+			 */
+			if(    (d->lct_data.class_id!=I2O_CLASS_BUS_ADAPTER_PORT)	// bus_adapter
+//			    && (d->lct_data.class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT)	// FC_PORT
+			  )
+				continue;
+		
+			shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host));
+			if(shpnt==NULL)
+				continue;
+			save_flags(flags);
+			cli();
+			shpnt->unique_id = (u32)d;
+			shpnt->io_port = 0;
+			shpnt->n_io_port = 0;
+			shpnt->irq = 0;
+			shpnt->this_id = /* Good question */15;
+			restore_flags(flags);
+			i2o_scsi_init(c, d, shpnt);
+			count++;
+		}
+	}
+	i2o_scsi_hosts = count;
+	
+	if(count==0)
+	{
+		if(sg_chain_pool!=NULL)
+		{
+			kfree(sg_chain_pool);
+			sg_chain_pool = NULL;
+		}
+		flush_pending();
+		del_timer(&retry_timer);
+		i2o_remove_handler(&i2o_scsi_handler);
+	}
+	
+	return count;
+}
+
+int i2o_scsi_release(struct Scsi_Host *host)
+{
+	if(--i2o_scsi_hosts==0)
+	{
+		if(sg_chain_pool!=NULL)
+		{
+			kfree(sg_chain_pool);
+			sg_chain_pool = NULL;
+		}
+		flush_pending();
+		del_timer(&retry_timer);
+		i2o_remove_handler(&i2o_scsi_handler);
+	}
+	return 0;
+}
+
+
+const char *i2o_scsi_info(struct Scsi_Host *SChost)
+{
+	struct i2o_scsi_host *hostdata;
+
+	hostdata = (struct i2o_scsi_host *)SChost->hostdata;
+
+	return(&hostdata->controller->name[0]);
+}
+
+
+/*
+ * From the wd93 driver:
+ * Returns true if there will be a DATA_OUT phase with this command, 
+ * false otherwise.
+ * (Thanks to Joerg Dorchain for the research and suggestion.)
+ *
+ */
+static int is_dir_out(Scsi_Cmnd *cmd)
+{
+	switch (cmd->cmnd[0]) 
+	{
+     		case WRITE_6:           case WRITE_10:          case WRITE_12:
+      		case WRITE_LONG:        case WRITE_SAME:        case WRITE_BUFFER:
+      		case WRITE_VERIFY:      case WRITE_VERIFY_12:      
+      		case COMPARE:           case COPY:              case COPY_VERIFY:
+      		case SEARCH_EQUAL:      case SEARCH_HIGH:       case SEARCH_LOW:
+      		case SEARCH_EQUAL_12:   case SEARCH_HIGH_12:    case SEARCH_LOW_12:      
+      		case FORMAT_UNIT:       case REASSIGN_BLOCKS:   case RESERVE:
+      		case MODE_SELECT:       case MODE_SELECT_10:    case LOG_SELECT:
+      		case SEND_DIAGNOSTIC:   case CHANGE_DEFINITION: case UPDATE_BLOCK:
+      		case SET_WINDOW:        case MEDIUM_SCAN:       case SEND_VOLUME_TAG:
+      		case 0xea:
+        		return 1;
+		default:
+        		return 0;
+	}
+}
+
+int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+	int i;
+	int tid;
+	struct i2o_controller *c;
+	Scsi_Cmnd *current_command;
+	struct Scsi_Host *host;
+	struct i2o_scsi_host *hostdata;
+	u32 *msg, *mptr;
+	u32 m;
+	u32 *lenptr;
+	int direction;
+	int scsidir;
+	u32 len;
+	u32 reqlen;
+	u32 tag;
+	
+	static int max_qd = 1;
+	
+	/*
+	 *	Do the incoming paperwork
+	 */
+	 
+	host = SCpnt->host;
+	hostdata = (struct i2o_scsi_host *)host->hostdata;
+	SCpnt->scsi_done = done;
+	
+	if(SCpnt->target > 15)
+	{
+		printk(KERN_ERR "i2o_scsi: Wild target %d.\n", SCpnt->target);
+		return -1;
+	}
+	
+	tid = hostdata->task[SCpnt->target][SCpnt->lun];
+	
+	dprintk(("qcmd: Tid = %d\n", tid));
+	
+	current_command = SCpnt;		/* set current command                */
+	current_command->scsi_done = done;	/* set ptr to done function           */
+
+	/* We don't have such a device. Pretend we did the command 
+	   and that selection timed out */
+	
+	if(tid == -1)
+	{
+		SCpnt->result = DID_NO_CONNECT << 16;
+		done(SCpnt);
+		return 0;
+	}
+	
+	dprintk(("Real scsi messages.\n"));
+
+	c = hostdata->controller;
+	
+	/*
+	 *	Obtain an I2O message. Right now we _have_ to obtain one
+	 *	until the scsi layer stuff is cleaned up.
+	 */	
+	 
+	do
+	{
+		mb();
+		m = I2O_POST_READ32(c);
+	}
+	while(m==0xFFFFFFFF);
+	msg = (u32 *)(c->mem_offset + m);
+	
+	/*
+	 *	Put together a scsi execscb message
+	 */
+	
+	len = SCpnt->request_bufflen;
+	direction = 0x00000000;			// SGL IN  (osm<--iop)
+	
+	/*
+	 *	The scsi layer should be handling this stuff
+	 */
+	
+	scsidir = 0x00000000;			// DATA NO XFER
+	if(len)
+	{
+		if(is_dir_out(SCpnt))
+		{
+			direction=0x04000000;	// SGL OUT  (osm-->iop)
+			scsidir  =0x80000000;	// DATA OUT (iop-->dev)
+		}
+		else
+		{
+			scsidir  =0x40000000;	// DATA IN  (iop<--dev)
+		}
+	}
+	
+	__raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]);
+	__raw_writel(scsi_context, &msg[2]);	/* So the I2O layer passes to us */
+	/* Sorry 64bit folks. FIXME */
+	__raw_writel((u32)SCpnt, &msg[3]);	/* We want the SCSI control block back */
+
+	/* LSI_920_PCI_QUIRK
+	 *
+	 *	Intermittant observations of msg frame word data corruption
+	 *	observed on msg[4] after:
+	 *	  WRITE, READ-MODIFY-WRITE
+	 *	operations.  19990606 -sralston
+	 *
+	 *	(Hence we build this word via tag. Its good practice anyway
+	 *	 we don't want fetches over PCI needlessly)
+	 */
+
+	tag=0;
+	
+	/*
+	 *	Attach tags to the devices
+	 */	
+	if(SCpnt->device->tagged_supported)
+	{
+		/*
+		 *	Some drives are too stupid to handle fairness issues
+		 *	with tagged queueing. We throw in the odd ordered
+		 *	tag to stop them starving themselves.
+		 */
+		if((jiffies - hostdata->tagclock[SCpnt->target][SCpnt->lun]) > (5*HZ))
+		{
+			tag=0x01800000;		/* ORDERED! */
+			hostdata->tagclock[SCpnt->target][SCpnt->lun]=jiffies;
+		}
+		else
+		{
+			/* Hmmm...  I always see value of 0 here,
+			 *  of which {HEAD_OF, ORDERED, SIMPLE} are NOT!  -sralston
+			 */
+			if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
+				tag=0x01000000;
+			else if(SCpnt->tag == ORDERED_QUEUE_TAG)
+				tag=0x01800000;
+		}
+	}
+
+	/* Direction, disconnect ok, tag, CDBLen */
+	__raw_writel(scsidir|0x20000000|SCpnt->cmd_len|tag, &msg[4]);
+
+	mptr=msg+5;
+
+	/* 
+	 *	Write SCSI command into the message - always 16 byte block 
+	 */
+	 
+	memcpy_toio(mptr, SCpnt->cmnd, 16);
+	mptr+=4;
+	lenptr=mptr++;		/* Remember me - fill in when we know */
+	
+	reqlen = 12;		// SINGLE SGE
+	
+	/*
+	 *	Now fill in the SGList and command 
+	 *
+	 *	FIXME: we need to set the sglist limits according to the 
+	 *	message size of the I2O controller. We might only have room
+	 *	for 6 or so worst case
+	 */
+	
+	if(SCpnt->use_sg)
+	{
+		struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer;
+		int chain = 0;
+		
+		len = 0;
+
+		if((sg_max_frags > 11) && (SCpnt->use_sg > 11))
+		{
+			chain = 1;
+			/*
+			 *	Need to chain!
+			 */
+			__raw_writel(direction|0xB0000000|(SCpnt->use_sg*2*4), mptr++);
+			__raw_writel(virt_to_bus(sg_chain_pool + sg_chain_tag), mptr);
+			mptr = (u32*)(sg_chain_pool + sg_chain_tag);
+			if (SCpnt->use_sg > max_sg_len)
+			{
+				max_sg_len = SCpnt->use_sg;
+				printk("i2o_scsi: Chain SG! SCpnt=%p, SG_FragCnt=%d, SG_idx=%d\n",
+					SCpnt, SCpnt->use_sg, sg_chain_tag);
+			}
+			if ( ++sg_chain_tag == SG_MAX_BUFS )
+				sg_chain_tag = 0;
+			for(i = 0 ; i < SCpnt->use_sg; i++)
+			{
+				*mptr++=direction|0x10000000|sg->length;
+				len+=sg->length;
+				*mptr++=virt_to_bus(sg->address);
+				sg++;
+			}
+			mptr[-2]=direction|0xD0000000|(sg-1)->length;
+		}
+		else
+		{		
+			for(i = 0 ; i < SCpnt->use_sg; i++)
+			{
+				__raw_writel(direction|0x10000000|sg->length, mptr++);
+				len+=sg->length;
+				__raw_writel(virt_to_bus(sg->address), mptr++);
+				sg++;
+			}
+
+			/* Make this an end of list. Again evade the 920 bug and
+			   unwanted PCI read traffic */
+		
+			__raw_writel(direction|0xD0000000|(sg-1)->length, &mptr[-2]);
+		}
+		
+		if(!chain)
+			reqlen = mptr - msg;
+		
+		__raw_writel(len, lenptr);
+		
+		if(len != SCpnt->underflow)
+			printk("Cmd len %08X Cmd underflow %08X\n",
+				len, SCpnt->underflow);
+	}
+	else
+	{
+		dprintk(("non sg for %p, %d\n", SCpnt->request_buffer,
+				SCpnt->request_bufflen));
+		__raw_writel(len = SCpnt->request_bufflen, lenptr);
+		if(len == 0)
+		{
+			reqlen = 9;
+		}
+		else
+		{
+			__raw_writel(0xD0000000|direction|SCpnt->request_bufflen, mptr++);
+			__raw_writel(virt_to_bus(SCpnt->request_buffer), mptr++);
+		}
+	}
+	
+	/*
+	 *	Stick the headers on 
+	 */
+
+	__raw_writel(reqlen<<16 | SGL_OFFSET_10, msg);
+	
+	/* Queue the message */
+	i2o_post_message(c,m);
+	
+	atomic_inc(&queue_depth);
+	
+	if(atomic_read(&queue_depth)> max_qd)
+	{
+		max_qd=atomic_read(&queue_depth);
+		printk("Queue depth now %d.\n", max_qd);
+	}
+	
+	mb();
+	dprintk(("Issued %ld\n", current_command->serial_number));
+	
+	return 0;
+}
+
+static void internal_done(Scsi_Cmnd * SCpnt)
+{
+	SCpnt->SCp.Status++;
+}
+
+int i2o_scsi_command(Scsi_Cmnd * SCpnt)
+{
+	i2o_scsi_queuecommand(SCpnt, internal_done);
+	SCpnt->SCp.Status = 0;
+	while (!SCpnt->SCp.Status)
+		barrier();
+	return SCpnt->result;
+}
+
+int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
+{
+	struct i2o_controller *c;
+	struct Scsi_Host *host;
+	struct i2o_scsi_host *hostdata;
+	u32 *msg;
+	u32 m;
+	int tid;
+	
+	printk("i2o_scsi: Aborting command block.\n");
+	
+	host = SCpnt->host;
+	hostdata = (struct i2o_scsi_host *)host->hostdata;
+	tid = hostdata->task[SCpnt->target][SCpnt->lun];
+	if(tid==-1)
+	{
+		printk(KERN_ERR "impossible command to abort.\n");
+		return SCSI_ABORT_NOT_RUNNING;
+	}
+	c = hostdata->controller;
+	
+	/*
+	 *	Obtain an I2O message. Right now we _have_ to obtain one
+	 *	until the scsi layer stuff is cleaned up.
+	 */	
+	 
+	do
+	{
+		mb();
+		m = I2O_POST_READ32(c);
+	}
+	while(m==0xFFFFFFFF);
+	msg = (u32 *)(c->mem_offset + m);
+	
+	__raw_writel(FIVE_WORD_MSG_SIZE, &msg[0]);
+	__raw_writel(I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid, &msg[1]);
+	__raw_writel(scsi_context, &msg[2]);
+	__raw_writel(0, &msg[3]);	/* Not needed for an abort */
+	__raw_writel((u32)SCpnt, &msg[4]);	
+	wmb();
+	i2o_post_message(c,m);
+	wmb();
+	return SCSI_ABORT_PENDING;
+}
+
+int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+{
+	int tid;
+	struct i2o_controller *c;
+	struct Scsi_Host *host;
+	struct i2o_scsi_host *hostdata;
+	u32 m;
+	u32 *msg;
+
+	/*
+	 *	Find the TID for the bus
+	 */
+
+	printk("i2o_scsi: Attempting to reset the bus.\n");
+	
+	host = SCpnt->host;
+	hostdata = (struct i2o_scsi_host *)host->hostdata;
+	tid = hostdata->bus_task;
+	c = hostdata->controller;
+
+	/*
+	 *	Now send a SCSI reset request. Any remaining commands
+	 *	will be aborted by the IOP. We need to catch the reply
+	 *	possibly ?
+	 */
+	 
+	m = I2O_POST_READ32(c);
+	
+	/*
+	 *	No free messages, try again next time - no big deal
+	 */
+	 
+	if(m == 0xFFFFFFFF)
+		return SCSI_RESET_PUNT;
+	
+	msg = (u32 *)(c->mem_offset + m);
+	__raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]);
+	__raw_writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, &msg[1]);
+	__raw_writel(scsi_context|0x80000000, &msg[2]);
+	/* We use the top bit to split controller and unit transactions */
+	/* Now store unit,tid so we can tie the completion back to a specific device */
+	__raw_writel(c->unit << 16 | tid, &msg[3]);
+	wmb();
+	i2o_post_message(c,m);
+	return SCSI_RESET_PENDING;
+}
+
+/*
+ *	This is anyones guess quite frankly.
+ */
+ 
+int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip)
+{
+	int size;
+
+	size = disk->capacity;
+	ip[0] = 64;		/* heads                        */
+	ip[1] = 32;		/* sectors                      */
+	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */
+		ip[0] = 255;	/* heads                        */
+		ip[1] = 63;	/* sectors                      */
+		ip[2] = size / (255 * 63);	/* cylinders                    */
+	}
+	return 0;
+}
+
+MODULE_AUTHOR("Red Hat Software");
+
+static Scsi_Host_Template driver_template = I2OSCSI;
+
+#include "../../scsi/scsi_module.c"
diff -u --recursive --new-file v2.4.12/linux/drivers/message/i2o/i2o_scsi.h linux/drivers/message/i2o/i2o_scsi.h
--- v2.4.12/linux/drivers/message/i2o/i2o_scsi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/i2o_scsi.h	Mon Dec 11 13:20:04 2000
@@ -0,0 +1,47 @@
+#ifndef _I2O_SCSI_H
+#define _I2O_SCSI_H
+
+#if !defined(LINUX_VERSION_CODE)
+#include <linux/version.h>
+#endif
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+
+#define I2O_SCSI_ID 15
+#define I2O_SCSI_CAN_QUEUE 4
+#define I2O_SCSI_CMD_PER_LUN 6
+
+extern int i2o_scsi_detect(Scsi_Host_Template *);
+extern const char *i2o_scsi_info(struct Scsi_Host *);
+extern int i2o_scsi_command(Scsi_Cmnd *);
+extern int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int i2o_scsi_abort(Scsi_Cmnd *);
+extern int i2o_scsi_reset(Scsi_Cmnd *, unsigned int);
+extern int i2o_scsi_bios_param(Disk *, kdev_t, int *);
+extern void i2o_scsi_setup(char *str, int *ints);
+extern int i2o_scsi_release(struct Scsi_Host *host);
+
+#define I2OSCSI {                                          \
+		  next: NULL,				    \
+                  proc_name:         "i2o_scsi",   \
+                  name:              "I2O SCSI Layer", 	    \
+                  detect:            i2o_scsi_detect,       \
+                  release:	     i2o_scsi_release,	    \
+                  info:              i2o_scsi_info,         \
+                  command:           i2o_scsi_command,      \
+                  queuecommand:      i2o_scsi_queuecommand, \
+                  abort:             i2o_scsi_abort,        \
+                  reset:             i2o_scsi_reset,        \
+                  bios_param:        i2o_scsi_bios_param,   \
+                  can_queue:         I2O_SCSI_CAN_QUEUE,    \
+                  this_id:           I2O_SCSI_ID,           \
+                  sg_tablesize:      8,                     \
+                  cmd_per_lun:       I2O_SCSI_CMD_PER_LUN,  \
+                  unchecked_isa_dma: 0,                     \
+                  use_clustering:    ENABLE_CLUSTERING     \
+                  }
+
+#endif
diff -u --recursive --new-file v2.4.12/linux/drivers/mtd/Config.in linux/drivers/mtd/Config.in
--- v2.4.12/linux/drivers/mtd/Config.in	Tue Oct  9 17:06:51 2001
+++ linux/drivers/mtd/Config.in	Thu Oct 11 09:14:32 2001
@@ -13,10 +13,10 @@
    fi
    dep_tristate '  MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
    dep_tristate '  RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
-if [ "$CONFIG_ARM" = "y" ]; then
-   dep_tristate '  Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS
-   dep_tristate '  ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS
-fi
+   if [ "$CONFIG_ARM" = "y" ]; then
+      dep_tristate '  Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS
+      dep_tristate '  ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS
+   fi
 
 comment 'User Modules And Translation Layers'
    dep_tristate '  Direct char device access to MTD devices' CONFIG_MTD_CHAR $CONFIG_MTD
diff -u --recursive --new-file v2.4.12/linux/drivers/mtd/ftl.c linux/drivers/mtd/ftl.c
--- v2.4.12/linux/drivers/mtd/ftl.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/mtd/ftl.c	Mon Oct 15 13:27:52 2001
@@ -1174,7 +1174,7 @@
 	put_user(ftl_hd[minor].start_sect, (u_long *)&geo->start);
 	break;
     case BLKGETSIZE:
-	ret = put_user(ftl_hd[minor].nr_sects, (long *)arg);
+	ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg);
 	break;
     case BLKGETSIZE64:
 	ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg);
diff -u --recursive --new-file v2.4.12/linux/drivers/mtd/mtdblock.c linux/drivers/mtd/mtdblock.c
--- v2.4.12/linux/drivers/mtd/mtdblock.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/mtd/mtdblock.c	Mon Oct 15 13:27:52 2001
@@ -539,7 +539,7 @@
 
 	switch (cmd) {
 	case BLKGETSIZE:   /* Return device size */
-		return put_user((mtdblk->mtd->size >> 9), (long *) arg);
+		return put_user((mtdblk->mtd->size >> 9), (unsigned long *) arg);
 	case BLKGETSIZE64:
 		return put_user((u64)mtdblk->mtd->size, (u64 *)arg);
 		
diff -u --recursive --new-file v2.4.12/linux/drivers/mtd/mtdblock_ro.c linux/drivers/mtd/mtdblock_ro.c
--- v2.4.12/linux/drivers/mtd/mtdblock_ro.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/mtd/mtdblock_ro.c	Mon Oct 15 13:27:52 2001
@@ -213,7 +213,7 @@
 
 	switch (cmd) {
 	case BLKGETSIZE:   /* Return device size */
-		return put_user((mtd->size >> 9), (long *) arg);
+		return put_user((mtd->size >> 9), (unsigned long *) arg);
 	case BLKGETSIZE64:
 		return put_user((u64)mtd->size, (u64 *)arg);
 		
diff -u --recursive --new-file v2.4.12/linux/drivers/mtd/nftlcore.c linux/drivers/mtd/nftlcore.c
--- v2.4.12/linux/drivers/mtd/nftlcore.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/mtd/nftlcore.c	Mon Oct 15 13:27:52 2001
@@ -804,7 +804,7 @@
 	}
 	case BLKGETSIZE:   /* Return device size */
 		return put_user(part_table[MINOR(inode->i_rdev)].nr_sects,
-                                (long *) arg);
+                                (unsigned long *) arg);
 	case BLKGETSIZE64:
 		return put_user((u64)part_table[MINOR(inode->i_rdev)].nr_sects << 9,
                                 (u64 *)arg);
diff -u --recursive --new-file v2.4.12/linux/drivers/net/8139cp.c linux/drivers/net/8139cp.c
--- v2.4.12/linux/drivers/net/8139cp.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/8139cp.c	Fri Oct 19 08:32:28 2001
@@ -0,0 +1,1325 @@
+/* 8139cp.c: A Linux PCI Ethernet driver for the RealTek 8139C+ chips. */
+/*
+	Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+
+	Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c]
+	Copyright 2001 Manfred Spraul				    [natsemi.c]
+	Copyright 1999-2001 by Donald Becker.			    [natsemi.c]
+       	Written 1997-2001 by Donald Becker.			    [8139too.c]
+	Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>. [acenic.c]
+
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
+
+	See the file COPYING in this distribution for more information.
+
+	TODO:
+	* dev->tx_timeout
+	* Constants (module parms?) for Rx work limit
+	* support 64-bit PCI DMA
+	* ETHTOOL_[GS]SET, ETHTOOL_GREGS, ETHTOOL_[GS]WOL,
+	  ETHTOOL_[GS]MSGLVL, ETHTOOL_NWAY_RST
+	* Complete reset on PciErr
+	* LinkChg and LenChg interrupts
+	* Consider Rx interrupt mitigation using TimerIntr
+	* Implement 8139C+ statistics dump
+	* Support forcing media type with a module parameter,
+	  like dl2k.c/sundance.c
+	* Rx checksumming
+	* Tx checksumming
+	* Jumbo frames / dev->change_mtu
+	* Tx abort stops Tx DMA?
+	* Investigate IntrStatus bit 10 purpose and use
+	* Investigate using skb->priority with h/w VLAN priority
+	* Investigate using High Priority Tx Queue with skb->priority
+	* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
+	* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
+
+ */
+
+#define DRV_NAME		"8139cp"
+#define DRV_VERSION		"0.0.5"
+#define DRV_RELDATE		"Oct 19, 2001"
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO DRV_NAME " 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
+
+MODULE_AUTHOR("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_DESCRIPTION("RealTek RTL-8139C+ series 10/100 PCI Ethernet driver");
+MODULE_LICENSE("GPL");
+
+static int debug = -1;
+MODULE_PARM (debug, "i");
+MODULE_PARM_DESC (debug, "8139cp bitmapped message enable number");
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+   The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
+static int multicast_filter_limit = 32;
+MODULE_PARM (multicast_filter_limit, "i");
+MODULE_PARM_DESC (multicast_filter_limit, "8139cp maximum number of filtered multicast addresses");
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
+#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
+        || defined(__sparc_) || defined(__ia64__) \
+        || defined(__sh__) || defined(__mips__)
+static int rx_copybreak = 1518;
+#else
+static int rx_copybreak = 100;
+#endif
+MODULE_PARM (rx_copybreak, "i");
+MODULE_PARM_DESC (rx_copybreak, "8139cp Breakpoint at which Rx packets are copied");
+
+#define PFX			DRV_NAME ": "
+
+#define CP_DEF_MSG_ENABLE	(NETIF_MSG_DRV		| \
+				 NETIF_MSG_PROBE 	| \
+				 NETIF_MSG_LINK)
+#define CP_REGS_SIZE		(0xff + 1)
+#define CP_RX_RING_SIZE		64
+#define CP_TX_RING_SIZE		64
+#define CP_RING_BYTES		\
+		((sizeof(struct cp_desc) * CP_RX_RING_SIZE) +	\
+		(sizeof(struct cp_desc) * CP_TX_RING_SIZE))
+#define NEXT_TX(N)		(((N) + 1) & (CP_TX_RING_SIZE - 1))
+#define NEXT_RX(N)		(((N) + 1) & (CP_RX_RING_SIZE - 1))
+#define TX_BUFFS_AVAIL(CP)					\
+	(((CP)->tx_tail <= (CP)->tx_head) ?			\
+	  (CP)->tx_tail + (CP_TX_RING_SIZE - 1) - (CP)->tx_head :	\
+	  (CP)->tx_tail - (CP)->tx_head - 1)
+#define CP_CHIP_VERSION		0x76
+
+#define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer.*/
+#define RX_OFFSET		2
+
+/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
+#define RX_FIFO_THRESH		5	/* Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST		4	/* Maximum PCI burst, '4' is 256 */
+#define TX_DMA_BURST		6	/* Maximum PCI burst, '6' is 1024 */
+#define TX_EARLY_THRESH		256	/* Early Tx threshold, in bytes */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (6*HZ)
+
+
+enum {
+	/* NIC register offsets */
+	MAC0		= 0x00,	/* Ethernet hardware address. */
+	MAR0		= 0x08,	/* Multicast filter. */
+	TxRingAddr	= 0x20, /* 64-bit start addr of Tx ring */
+	HiTxRingAddr	= 0x28, /* 64-bit start addr of high priority Tx ring */
+	Cmd		= 0x37, /* Command register */
+	IntrMask	= 0x3C, /* Interrupt mask */
+	IntrStatus	= 0x3E, /* Interrupt status */
+	TxConfig	= 0x40, /* Tx configuration */
+	ChipVersion	= 0x43, /* 8-bit chip version, inside TxConfig */
+	RxConfig	= 0x44, /* Rx configuration */
+	Cfg9346		= 0x50, /* EEPROM select/control; Cfg reg [un]lock */
+	Config1		= 0x52, /* Config1 */
+	Config3		= 0x59, /* Config3 */
+	Config4		= 0x5A, /* Config4 */
+	MultiIntr	= 0x5C, /* Multiple interrupt select */
+	Config5		= 0xD8,	/* Config5 */
+	TxPoll		= 0xD9,	/* Tell chip to check Tx descriptors for work */
+	CpCmd		= 0xE0, /* C+ Command register (C+ mode only) */
+	RxRingAddr	= 0xE4, /* 64-bit start addr of Rx ring */
+	TxThresh	= 0xEC, /* Early Tx threshold */
+	OldRxBufAddr	= 0x30, /* DMA address of Rx ring buffer (C mode) */
+	OldTSD0		= 0x10, /* DMA address of first Tx desc (C mode) */
+
+	/* Tx and Rx status descriptors */
+	DescOwn		= (1 << 31), /* Descriptor is owned by NIC */
+	RingEnd		= (1 << 30), /* End of descriptor ring */
+	FirstFrag	= (1 << 29), /* First segment of a packet */
+	LastFrag	= (1 << 28), /* Final segment of a packet */
+	TxError		= (1 << 23), /* Tx error summary */
+	RxError		= (1 << 20), /* Rx error summary */
+	IPCS		= (1 << 18), /* Calculate IP checksum */
+	UDPCS		= (1 << 17), /* Calculate UDP/IP checksum */
+	TCPCS		= (1 << 16), /* Calculate TCP/IP checksum */
+	IPFail		= (1 << 15), /* IP checksum failed */
+	UDPFail		= (1 << 14), /* UDP/IP checksum failed */
+	TCPFail		= (1 << 13), /* TCP/IP checksum failed */
+	NormalTxPoll	= (1 << 6),  /* One or more normal Tx packets to send */
+	PID1		= (1 << 17), /* 2 protocol id bits:  0==non-IP, */
+	PID0		= (1 << 16), /* 1==UDP/IP, 2==TCP/IP, 3==IP */
+	TxFIFOUnder	= (1 << 25), /* Tx FIFO underrun */
+	TxOWC		= (1 << 22), /* Tx Out-of-window collision */
+	TxLinkFail	= (1 << 21), /* Link failed during Tx of packet */
+	TxMaxCol	= (1 << 20), /* Tx aborted due to excessive collisions */
+	TxColCntShift	= 16,	     /* Shift, to get 4-bit Tx collision cnt */
+	TxColCntMask	= 0x01 | 0x02 | 0x04 | 0x08, /* 4-bit collision count */
+	RxErrFrame	= (1 << 27), /* Rx frame alignment error */
+	RxMcast		= (1 << 26), /* Rx multicast packet rcv'd */
+	RxErrCRC	= (1 << 18), /* Rx CRC error */
+	RxErrRunt	= (1 << 19), /* Rx error, packet < 64 bytes */
+	RxErrLong	= (1 << 21), /* Rx error, packet > 4096 bytes */
+	RxErrFIFO	= (1 << 22), /* Rx error, FIFO overflowed, pkt bad */
+
+	/* RxConfig register */
+	RxCfgFIFOShift	= 13,	     /* Shift, to get Rx FIFO thresh value */
+	RxCfgDMAShift	= 8,	     /* Shift, to get Rx Max DMA value */
+	AcceptErr	= 0x20,	     /* Accept packets with CRC errors */
+	AcceptRunt	= 0x10,	     /* Accept runt (<64 bytes) packets */
+	AcceptBroadcast	= 0x08,	     /* Accept broadcast packets */
+	AcceptMulticast	= 0x04,	     /* Accept multicast packets */
+	AcceptMyPhys	= 0x02,	     /* Accept pkts with our MAC as dest */
+	AcceptAllPhys	= 0x01,	     /* Accept all pkts w/ physical dest */
+
+	/* IntrMask / IntrStatus registers */
+	PciErr		= (1 << 15), /* System error on the PCI bus */
+	TimerIntr	= (1 << 14), /* Asserted when TCTR reaches TimerInt value */
+	LenChg		= (1 << 13), /* Cable length change */
+	SWInt		= (1 << 8),  /* Software-requested interrupt */
+	TxEmpty		= (1 << 7),  /* No Tx descriptors available */
+	RxFIFOOvr	= (1 << 6),  /* Rx FIFO Overflow */
+	LinkChg		= (1 << 5),  /* Packet underrun, or link change */
+	RxEmpty		= (1 << 4),  /* No Rx descriptors available */
+	TxErr		= (1 << 3),  /* Tx error */
+	TxOK		= (1 << 2),  /* Tx packet sent */
+	RxErr		= (1 << 1),  /* Rx error */
+	RxOK		= (1 << 0),  /* Rx packet received */
+	IntrResvd	= (1 << 10), /* reserved, according to RealTek engineers,
+					but hardware likes to raise it */
+
+	IntrAll		= PciErr | TimerIntr | LenChg | SWInt | TxEmpty |
+			  RxFIFOOvr | LinkChg | RxEmpty | TxErr | TxOK |
+			  RxErr | RxOK | IntrResvd,
+
+	/* C mode command register */
+	CmdReset	= (1 << 4),  /* Enable to reset; self-clearing */
+	RxOn		= (1 << 3),  /* Rx mode enable */
+	TxOn		= (1 << 2),  /* Tx mode enable */
+
+	/* C+ mode command register */
+	RxChkSum	= (1 << 5),  /* Rx checksum offload enable */
+	PCIMulRW	= (1 << 3),  /* Enable PCI read/write multiple */
+	CpRxOn		= (1 << 1),  /* Rx mode enable */
+	CpTxOn		= (1 << 0),  /* Tx mode enable */
+
+	/* Cfg9436 EEPROM control register */
+	Cfg9346_Lock	= 0x00,	     /* Lock ConfigX/MII register access */
+	Cfg9346_Unlock	= 0xC0,	     /* Unlock ConfigX/MII register access */
+
+	/* TxConfig register */
+	IFG		= (1 << 25) | (1 << 24), /* standard IEEE interframe gap */
+	TxDMAShift	= 8,	     /* DMA burst value (0-7) is shift this many bits */
+
+	/* Early Tx Threshold register */
+	TxThreshMask	= 0x3f,	     /* Mask bits 5-0 */
+	TxThreshMax	= 2048,	     /* Max early Tx threshold */
+
+	/* Config1 register */
+	DriverLoaded	= (1 << 5),  /* Software marker, driver is loaded */
+	PMEnable	= (1 << 0),  /* Enable various PM features of chip */
+
+	/* Config3 register */
+	PARMEnable	= (1 << 6),  /* Enable auto-loading of PHY parms */
+
+	/* Config5 register */
+	PMEStatus	= (1 << 0),  /* PME status can be reset by PCI RST# */
+};
+
+static const unsigned int cp_intr_mask =
+	PciErr | LinkChg |
+	RxOK | RxErr | RxEmpty | RxFIFOOvr |
+	TxOK | TxErr | TxEmpty;
+
+static const unsigned int cp_rx_config =
+	  (RX_FIFO_THRESH << RxCfgFIFOShift) |
+	  (RX_DMA_BURST << RxCfgDMAShift);
+
+struct cp_desc {
+	u32		opts1;
+	u32		opts2;
+	u32		addr_lo;
+	u32		addr_hi;
+};
+
+struct ring_info {
+	struct sk_buff		*skb;
+	dma_addr_t		mapping;
+	unsigned		frag;
+};
+
+struct cp_extra_stats {
+	unsigned long		rx_frags;
+};
+
+struct cp_private {
+	unsigned		tx_head;
+	unsigned		tx_tail;
+	unsigned		rx_tail;
+
+	void			*regs;
+	struct net_device	*dev;
+	spinlock_t		lock;
+
+	struct cp_desc		*rx_ring;
+	struct cp_desc		*tx_ring;
+	struct ring_info	tx_skb[CP_TX_RING_SIZE];
+	struct ring_info	rx_skb[CP_RX_RING_SIZE];
+	unsigned		rx_buf_sz;
+	dma_addr_t		ring_dma;
+
+	u32			msg_enable;
+
+	struct net_device_stats net_stats;
+	struct cp_extra_stats	cp_stats;
+
+	struct pci_dev		*pdev;
+	u32			rx_config;
+
+	struct sk_buff		*frag_skb;
+	unsigned		dropping_frag : 1;
+};
+
+#define cpr8(reg)	readb(cp->regs + (reg))
+#define cpr16(reg)	readw(cp->regs + (reg))
+#define cpr32(reg)	readl(cp->regs + (reg))
+#define cpw8(reg,val)	writeb((val), cp->regs + (reg))
+#define cpw16(reg,val)	writew((val), cp->regs + (reg))
+#define cpw32(reg,val)	writel((val), cp->regs + (reg))
+#define cpw8_f(reg,val) do {			\
+	writeb((val), cp->regs + (reg));	\
+	readb(cp->regs + (reg));		\
+	} while (0)
+#define cpw16_f(reg,val) do {			\
+	writew((val), cp->regs + (reg));	\
+	readw(cp->regs + (reg));		\
+	} while (0)
+#define cpw32_f(reg,val) do {			\
+	writel((val), cp->regs + (reg));	\
+	readl(cp->regs + (reg));		\
+	} while (0)
+
+
+static void __cp_set_rx_mode (struct net_device *dev);
+static void cp_tx (struct cp_private *cp);
+static void cp_clean_rings (struct cp_private *cp);
+
+
+static struct pci_device_id cp_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, cp_pci_tbl);
+
+static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb)
+{
+	skb->protocol = eth_type_trans (skb, cp->dev);
+
+	cp->net_stats.rx_packets++;
+	cp->net_stats.rx_bytes += skb->len;
+	cp->dev->last_rx = jiffies;
+	netif_rx (skb);
+}
+
+static inline void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
+				   u32 status, u32 len)
+{
+	if (netif_msg_rx_err (cp))
+		printk (KERN_DEBUG
+			"%s: rx err, slot %d status 0x%x len %d\n",
+			cp->dev->name, rx_tail, status, len);
+	cp->net_stats.rx_errors++;
+	if (status & RxErrFrame)
+		cp->net_stats.rx_frame_errors++;
+	if (status & RxErrCRC)
+		cp->net_stats.rx_crc_errors++;
+	if (status & RxErrRunt)
+		cp->net_stats.rx_length_errors++;
+	if (status & RxErrLong)
+		cp->net_stats.rx_length_errors++;
+	if (status & RxErrFIFO)
+		cp->net_stats.rx_fifo_errors++;
+}
+
+static void cp_rx_frag (struct cp_private *cp, unsigned rx_tail,
+			struct sk_buff *skb, u32 status, u32 len)
+{
+	struct sk_buff *copy_skb, *frag_skb = cp->frag_skb;
+	unsigned orig_len = frag_skb ? frag_skb->len : 0;
+	unsigned target_len = orig_len + len;
+	unsigned first_frag = status & FirstFrag;
+	unsigned last_frag = status & LastFrag;
+
+	if (netif_msg_rx_status (cp))
+		printk (KERN_DEBUG "%s: rx %s%sfrag, slot %d status 0x%x len %d\n",
+			cp->dev->name,
+			cp->dropping_frag ? "dropping " : "",
+			first_frag ? "first " :
+			last_frag ? "last " : "",
+			rx_tail, status, len);
+
+	cp->cp_stats.rx_frags++;
+
+	if (!frag_skb && !first_frag)
+		cp->dropping_frag = 1;
+	if (cp->dropping_frag)
+		goto drop_frag;
+
+	copy_skb = dev_alloc_skb (target_len + RX_OFFSET);
+	if (!copy_skb) {
+		printk(KERN_WARNING "%s: rx slot %d alloc failed\n",
+		       cp->dev->name, rx_tail);
+
+		cp->dropping_frag = 1;
+drop_frag:
+		if (frag_skb) {
+			dev_kfree_skb_irq(frag_skb);
+			cp->frag_skb = NULL;
+		}
+		if (last_frag) {
+			cp->net_stats.rx_dropped++;
+			cp->dropping_frag = 0;
+		}
+		return;
+	}
+
+	copy_skb->dev = cp->dev;
+	skb_reserve(copy_skb, RX_OFFSET);
+	skb_put(copy_skb, target_len);
+	if (frag_skb) {
+		memcpy(copy_skb->data, frag_skb->data, orig_len);
+		dev_kfree_skb_irq(frag_skb);
+	}
+	pci_dma_sync_single(cp->pdev, cp->rx_skb[rx_tail].mapping,
+			    len, PCI_DMA_FROMDEVICE);
+	memcpy(copy_skb->data + orig_len, skb->data, len);
+
+	copy_skb->ip_summed = CHECKSUM_NONE;
+
+	if (last_frag) {
+		if (status & (RxError | RxErrFIFO)) {
+			cp_rx_err_acct(cp, rx_tail, status, len);
+			dev_kfree_skb_irq(copy_skb);
+		} else
+			cp_rx_skb(cp, copy_skb);
+		cp->frag_skb = NULL;
+	} else {
+		cp->frag_skb = copy_skb;
+	}
+}
+
+static void cp_rx (struct cp_private *cp)
+{
+	unsigned rx_tail = cp->rx_tail;
+	unsigned rx_work = 100;
+
+	while (rx_work--) {
+		u32 status, len;
+		dma_addr_t mapping;
+		struct sk_buff *skb, *copy_skb;
+		unsigned copying_skb, buflen;
+
+		skb = cp->rx_skb[rx_tail].skb;
+		if (!skb)
+			BUG();
+		rmb();
+		status = le32_to_cpu(cp->rx_ring[rx_tail].opts1);
+		if (status & DescOwn)
+			break;
+
+		len = (status & 0x1fff) - 4;
+		mapping = cp->rx_skb[rx_tail].mapping;
+
+		if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag)) {
+			cp_rx_frag(cp, rx_tail, skb, status, len);
+			goto rx_next;
+		}
+
+		if (status & (RxError | RxErrFIFO)) {
+			cp_rx_err_acct(cp, rx_tail, status, len);
+			goto rx_next;
+		}
+
+		copying_skb = (len <= rx_copybreak);
+
+		if (netif_msg_rx_status(cp))
+			printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d copying? %d\n",
+			       cp->dev->name, rx_tail, status, len,
+			       copying_skb);
+
+		buflen = copying_skb ? len : cp->rx_buf_sz;
+		copy_skb = dev_alloc_skb (buflen + RX_OFFSET);
+		if (!copy_skb) {
+			cp->net_stats.rx_dropped++;
+			goto rx_next;
+		}
+
+		skb_reserve(copy_skb, RX_OFFSET);
+		copy_skb->dev = cp->dev;
+
+		if (!copying_skb) {
+			pci_unmap_single(cp->pdev, mapping,
+					 buflen, PCI_DMA_FROMDEVICE);
+			skb->ip_summed = CHECKSUM_NONE;
+			skb_trim(skb, len);
+
+			mapping =
+			cp->rx_skb[rx_tail].mapping =
+				pci_map_single(cp->pdev, copy_skb->data,
+					       buflen, PCI_DMA_FROMDEVICE);
+			cp->rx_skb[rx_tail].skb = copy_skb;
+			skb_put(copy_skb, buflen);
+		} else {
+			skb_put(copy_skb, len);
+			pci_dma_sync_single(cp->pdev, mapping, len, PCI_DMA_FROMDEVICE);
+			memcpy(copy_skb->data, skb->data, len);
+
+			/* We'll reuse the original ring buffer. */
+			skb = copy_skb;
+		}
+
+		cp_rx_skb(cp, skb);
+
+rx_next:
+		if (rx_tail == (CP_RX_RING_SIZE - 1))
+			cp->rx_ring[rx_tail].opts1 =
+				cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz);
+		else
+			cp->rx_ring[rx_tail].opts1 =
+				cpu_to_le32(DescOwn | cp->rx_buf_sz);
+		cp->rx_ring[rx_tail].opts2 = 0;
+		cp->rx_ring[rx_tail].addr_lo = cpu_to_le32(mapping);
+		rx_tail = NEXT_RX(rx_tail);
+	}
+
+	if (!rx_work)
+		printk(KERN_WARNING "%s: rx work limit reached\n", cp->dev->name);
+
+	cp->rx_tail = rx_tail;
+}
+
+static void cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_instance;
+	struct cp_private *cp = dev->priv;
+	u16 status;
+
+	status = cpr16(IntrStatus);
+	if (!status || (status == 0xFFFF))
+		return;
+
+	if (netif_msg_intr(cp))
+		printk(KERN_DEBUG "%s: intr, status %04x cmd %02x cpcmd %04x\n",
+		        dev->name, status, cpr8(Cmd), cpr16(CpCmd));
+
+	spin_lock(&cp->lock);
+
+	if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
+		cp_rx(cp);
+	if (status & (TxOK | TxErr | TxEmpty | SWInt))
+		cp_tx(cp);
+
+	cpw16_f(IntrStatus, status);
+
+	if (status & PciErr) {
+		u16 pci_status;
+
+		pci_read_config_word(cp->pdev, PCI_STATUS, &pci_status);
+		pci_write_config_word(cp->pdev, PCI_STATUS, pci_status);
+		printk(KERN_ERR "%s: PCI bus error, status=%04x, PCI status=%04x\n",
+		       dev->name, status, pci_status);
+	}
+
+	spin_unlock(&cp->lock);
+}
+
+static void cp_tx (struct cp_private *cp)
+{
+	unsigned tx_head = cp->tx_head;
+	unsigned tx_tail = cp->tx_tail;
+
+	while (tx_tail != tx_head) {
+		struct sk_buff *skb;
+		u32 status;
+
+		rmb();
+		status = le32_to_cpu(cp->tx_ring[tx_tail].opts1);
+		if (status & DescOwn)
+			break;
+
+		skb = cp->tx_skb[tx_tail].skb;
+		if (!skb)
+			BUG();
+
+		pci_unmap_single(cp->pdev, cp->tx_skb[tx_tail].mapping,
+					skb->len, PCI_DMA_TODEVICE);
+
+		if (status & LastFrag) {
+			if (status & (TxError | TxFIFOUnder)) {
+				if (netif_msg_tx_err(cp))
+					printk(KERN_DEBUG "%s: tx err, status 0x%x\n",
+					       cp->dev->name, status);
+				cp->net_stats.tx_errors++;
+				if (status & TxOWC)
+					cp->net_stats.tx_window_errors++;
+				if (status & TxMaxCol)
+					cp->net_stats.tx_aborted_errors++;
+				if (status & TxLinkFail)
+					cp->net_stats.tx_carrier_errors++;
+				if (status & TxFIFOUnder)
+					cp->net_stats.tx_fifo_errors++;
+			} else {
+				cp->net_stats.collisions +=
+					((status >> TxColCntShift) & TxColCntMask);
+				cp->net_stats.tx_packets++;
+				cp->net_stats.tx_bytes += skb->len;
+				if (netif_msg_tx_done(cp))
+					printk(KERN_DEBUG "%s: tx done, slot %d\n", cp->dev->name, tx_tail);
+			}
+			dev_kfree_skb_irq(skb);
+		}
+
+		cp->tx_skb[tx_tail].skb = NULL;
+
+		tx_tail = NEXT_TX(tx_tail);
+	}
+
+	cp->tx_tail = tx_tail;
+
+	if (netif_queue_stopped(cp->dev) && (TX_BUFFS_AVAIL(cp) > 1))
+		netif_wake_queue(cp->dev);
+}
+
+static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+	struct cp_private *cp = dev->priv;
+	unsigned entry;
+	u32 eor;
+
+	spin_lock_irq(&cp->lock);
+
+	if (TX_BUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) {
+		netif_stop_queue(dev);
+		spin_unlock_irq(&cp->lock);
+		return 1;
+	}
+
+	entry = cp->tx_head;
+	eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
+	if (skb_shinfo(skb)->nr_frags == 0) {
+		struct cp_desc *txd = &cp->tx_ring[entry];
+		u32 mapping, len;
+
+		len = skb->len;
+		mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+		eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
+#ifdef CP_TX_CHECKSUM
+		txd->opts1 = cpu_to_le32(eor | len | DescOwn | FirstFrag |
+			LastFrag | IPCS | UDPCS | TCPCS);
+#else
+		txd->opts1 = cpu_to_le32(eor | len | DescOwn | FirstFrag |
+			LastFrag);
+#endif
+		txd->opts2 = 0;
+		txd->addr_lo = cpu_to_le32(mapping);
+
+		cp->tx_skb[entry].skb = skb;
+		cp->tx_skb[entry].mapping = mapping;
+		cp->tx_skb[entry].frag = 0;
+		wmb();
+		entry = NEXT_TX(entry);
+	} else {
+		struct cp_desc *txd;
+		u32 first_len, first_mapping;
+		int frag, first_entry = entry;
+
+		/* We must give this initial chunk to the device last.
+		 * Otherwise we could race with the device.
+		 */
+		first_len = skb->len - skb->data_len;
+		first_mapping = pci_map_single(cp->pdev, skb->data,
+					       first_len, PCI_DMA_TODEVICE);
+		cp->tx_skb[entry].skb = skb;
+		cp->tx_skb[entry].mapping = first_mapping;
+		cp->tx_skb[entry].frag = 1;
+		entry = NEXT_TX(entry);
+
+		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+			skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+			u32 len, mapping;
+			u32 ctrl;
+
+			len = this_frag->size;
+			mapping = pci_map_single(cp->pdev,
+						 ((void *) page_address(this_frag->page) +
+						  this_frag->page_offset),
+						 len, PCI_DMA_TODEVICE);
+			eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
+#ifdef CP_TX_CHECKSUM
+			ctrl = eor | len | DescOwn | IPCS | UDPCS | TCPCS;
+#else
+			ctrl = eor | len | DescOwn;
+#endif
+			if (frag == skb_shinfo(skb)->nr_frags - 1)
+				ctrl |= LastFrag;
+
+			txd = &cp->tx_ring[entry];
+			txd->opts1 = cpu_to_le32(ctrl);
+			txd->opts2 = 0;
+			txd->addr_lo = cpu_to_le32(mapping);
+
+			cp->tx_skb[entry].skb = skb;
+			cp->tx_skb[entry].mapping = mapping;
+			cp->tx_skb[entry].frag = frag + 2;
+			wmb();
+			entry = NEXT_TX(entry);
+		}
+		txd = &cp->tx_ring[first_entry];
+#ifdef CP_TX_CHECKSUM
+		txd->opts1 = cpu_to_le32(first_len | FirstFrag | DescOwn | IPCS | UDPCS | TCPCS);
+#else
+		txd->opts1 = cpu_to_le32(first_len | FirstFrag | DescOwn);
+#endif
+		txd->opts2 = 0;
+		txd->addr_lo = cpu_to_le32(first_mapping);
+		wmb();
+	}
+	cp->tx_head = entry;
+	if (netif_msg_tx_queued(cp))
+		printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n",
+		       dev->name, entry, skb->len);
+	if (TX_BUFFS_AVAIL(cp) < 0)
+		BUG();
+	if (TX_BUFFS_AVAIL(cp) == 0)
+		netif_stop_queue(dev);
+
+	spin_unlock_irq(&cp->lock);
+
+	cpw8(TxPoll, NormalTxPoll);
+	dev->trans_start = jiffies;
+
+	return 0;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   This routine is not state sensitive and need not be SMP locked. */
+
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc (int length, unsigned char *data)
+{
+	int crc = -1;
+
+	while (--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+			crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
+			     ethernet_polynomial : 0);
+	}
+
+	return crc;
+}
+
+static void __cp_set_rx_mode (struct net_device *dev)
+{
+	struct cp_private *cp = dev->priv;
+	u32 mc_filter[2];	/* Multicast hash filter */
+	int i, rx_mode;
+	u32 tmp;
+
+	/* Note: do not reorder, GCC is clever about common statements. */
+	if (dev->flags & IFF_PROMISC) {
+		/* Unconditionally log net taps. */
+		printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+			dev->name);
+		rx_mode =
+		    AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+		    AcceptAllPhys;
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+	} else if ((dev->mc_count > multicast_filter_limit)
+		   || (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter perfectly -- accept all multicasts. */
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+	} else {
+		struct dev_mc_list *mclist;
+		rx_mode = AcceptBroadcast | AcceptMyPhys;
+		mc_filter[1] = mc_filter[0] = 0;
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+		     i++, mclist = mclist->next) {
+			int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+			mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
+			rx_mode |= AcceptMulticast;
+		}
+	}
+
+	/* We can safely update without stopping the chip. */
+	tmp = cp_rx_config | rx_mode;
+	if (cp->rx_config != tmp) {
+		cpw32_f (RxConfig, tmp);
+		cp->rx_config = tmp;
+	}
+	cpw32_f (MAR0 + 0, mc_filter[0]);
+	cpw32_f (MAR0 + 4, mc_filter[1]);
+}
+
+static void cp_set_rx_mode (struct net_device *dev)
+{
+	unsigned long flags;
+	struct cp_private *cp = dev->priv;
+
+	spin_lock_irqsave (&cp->lock, flags);
+	__cp_set_rx_mode(dev);
+	spin_unlock_irqrestore (&cp->lock, flags);
+}
+
+static void __cp_get_stats(struct cp_private *cp)
+{
+	/* XXX implement */
+}
+
+static struct net_device_stats *cp_get_stats(struct net_device *dev)
+{
+	struct cp_private *cp = dev->priv;
+
+	/* The chip only need report frame silently dropped. */
+	spin_lock_irq(&cp->lock);
+ 	if (netif_running(dev) && netif_device_present(dev))
+ 		__cp_get_stats(cp);
+	spin_unlock_irq(&cp->lock);
+
+	return &cp->net_stats;
+}
+
+static void cp_stop_hw (struct cp_private *cp)
+{
+	cpw16(IntrMask, 0);
+	cpr16(IntrMask);
+	cpw8(Cmd, 0);
+	cpw16(CpCmd, 0);
+	cpr16(CpCmd);
+	cpw16(IntrStatus, ~(cpr16(IntrStatus)));
+	synchronize_irq();
+	udelay(10);
+
+	cp->rx_tail = 0;
+	cp->tx_head = cp->tx_tail = 0;
+}
+
+static void cp_reset_hw (struct cp_private *cp)
+{
+	unsigned work = 1000;
+
+	cpw8(Cmd, CmdReset);
+
+	while (work--) {
+		if (!(cpr8(Cmd) & CmdReset))
+			return;
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(10);
+	}
+
+	printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name);
+}
+
+static void cp_init_hw (struct cp_private *cp)
+{
+	struct net_device *dev = cp->dev;
+
+	cp_reset_hw(cp);
+
+	cpw8_f (Cfg9346, Cfg9346_Unlock);
+
+	/* Restore our idea of the MAC address. */
+	cpw32_f (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
+	cpw32_f (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+
+	cpw8(Cmd, RxOn | TxOn);
+	cpw16(CpCmd, PCIMulRW | CpRxOn | CpTxOn);
+	cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */
+
+	__cp_set_rx_mode(dev);
+	cpw32_f (TxConfig, IFG | (TX_DMA_BURST << TxDMAShift));
+
+	cpw8(Config1, cpr8(Config1) | DriverLoaded | PMEnable);
+	cpw8(Config3, PARMEnable); /* disables magic packet and WOL */
+	cpw8(Config5, cpr8(Config5) & PMEStatus); /* disables more WOL stuff */
+
+	cpw32_f(HiTxRingAddr, 0);
+	cpw32_f(HiTxRingAddr + 4, 0);
+	cpw32_f(OldRxBufAddr, 0);
+	cpw32_f(OldTSD0, 0);
+	cpw32_f(OldTSD0 + 4, 0);
+	cpw32_f(OldTSD0 + 8, 0);
+	cpw32_f(OldTSD0 + 12, 0);
+
+	cpw32_f(RxRingAddr, cp->ring_dma);
+	cpw32_f(RxRingAddr + 4, 0);
+	cpw32_f(TxRingAddr, cp->ring_dma + (sizeof(struct cp_desc) * CP_RX_RING_SIZE));
+	cpw32_f(TxRingAddr + 4, 0);
+
+	cpw16(MultiIntr, 0);
+
+	cpw16(IntrMask, cp_intr_mask);
+
+	cpw8_f (Cfg9346, Cfg9346_Lock);
+}
+
+static int cp_refill_rx (struct cp_private *cp)
+{
+	unsigned i;
+
+	for (i = 0; i < CP_RX_RING_SIZE; i++) {
+		struct sk_buff *skb;
+
+		skb = dev_alloc_skb(cp->rx_buf_sz + RX_OFFSET);
+		if (!skb)
+			goto err_out;
+
+		skb->dev = cp->dev;
+		skb_reserve(skb, RX_OFFSET);
+		skb_put(skb, cp->rx_buf_sz);
+
+		cp->rx_skb[i].mapping = pci_map_single(cp->pdev,
+			skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+		cp->rx_skb[i].skb = skb;
+		cp->rx_skb[i].frag = 0;
+
+		if (i == (CP_RX_RING_SIZE - 1))
+			cp->rx_ring[i].opts1 =
+				cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz);
+		else
+			cp->rx_ring[i].opts1 =
+				cpu_to_le32(DescOwn | cp->rx_buf_sz);
+		cp->rx_ring[i].opts2 = 0;
+		cp->rx_ring[i].addr_lo = cpu_to_le32(cp->rx_skb[i].mapping);
+		cp->rx_ring[i].addr_hi = 0;
+	}
+
+	return 0;
+
+err_out:
+	cp_clean_rings(cp);
+	return -ENOMEM;
+}
+
+static int cp_init_rings (struct cp_private *cp)
+{
+	memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
+	cp->tx_ring[CP_TX_RING_SIZE - 1].opts1 = cpu_to_le32(RingEnd);
+
+	cp->rx_tail = 0;
+	cp->tx_head = cp->tx_tail = 0;
+
+	return cp_refill_rx (cp);
+}
+
+static int cp_alloc_rings (struct cp_private *cp)
+{
+	cp->rx_ring = pci_alloc_consistent(cp->pdev, CP_RING_BYTES, &cp->ring_dma);
+	if (!cp->rx_ring)
+		return -ENOMEM;
+	cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE];
+	return cp_init_rings(cp);
+}
+
+static void cp_clean_rings (struct cp_private *cp)
+{
+	unsigned i;
+
+	memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
+	memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
+
+	for (i = 0; i < CP_RX_RING_SIZE; i++) {
+		if (cp->rx_skb[i].skb) {
+			pci_unmap_single(cp->pdev, cp->rx_skb[i].mapping,
+					 cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(cp->rx_skb[i].skb);
+		}
+	}
+
+	for (i = 0; i < CP_TX_RING_SIZE; i++) {
+		if (cp->tx_skb[i].skb) {
+			struct sk_buff *skb = cp->tx_skb[i].skb;
+			pci_unmap_single(cp->pdev, cp->tx_skb[i].mapping,
+					 skb->len, PCI_DMA_TODEVICE);
+			dev_kfree_skb(skb);
+			cp->net_stats.tx_dropped++;
+		}
+	}
+
+	memset(&cp->rx_skb, 0, sizeof(struct ring_info) * CP_RX_RING_SIZE);
+	memset(&cp->tx_skb, 0, sizeof(struct ring_info) * CP_TX_RING_SIZE);
+}
+
+static void cp_free_rings (struct cp_private *cp)
+{
+	cp_clean_rings(cp);
+	pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma);
+	cp->rx_ring = NULL;
+	cp->tx_ring = NULL;
+}
+
+static int cp_open (struct net_device *dev)
+{
+	struct cp_private *cp = dev->priv;
+	int rc;
+
+	if (netif_msg_ifup(cp))
+		printk(KERN_DEBUG "%s: enabling interface\n", dev->name);
+
+	cp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+
+	rc = cp_alloc_rings(cp);
+	if (rc)
+		return rc;
+
+	cp_init_hw(cp);
+
+	rc = request_irq(dev->irq, cp_interrupt, SA_SHIRQ, dev->name, dev);
+	if (rc)
+		goto err_out_hw;
+
+	netif_start_queue(dev);
+
+	return 0;
+
+err_out_hw:
+	cp_stop_hw(cp);
+	cp_free_rings(cp);
+	return rc;
+}
+
+static int cp_close (struct net_device *dev)
+{
+	struct cp_private *cp = dev->priv;
+
+	if (netif_msg_ifdown(cp))
+		printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
+
+	netif_stop_queue(dev);
+	cp_stop_hw(cp);
+	free_irq(dev->irq, dev);
+	cp_free_rings(cp);
+	return 0;
+}
+
+static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO:
+		{
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+			strcpy (info.driver, DRV_NAME);
+			strcpy (info.version, DRV_VERSION);
+			strcpy (info.bus_info, cp->pdev->slot_name);
+			if (copy_to_user (useraddr, &info, sizeof (info)))
+				return -EFAULT;
+			return 0;
+		}
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+
+static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct cp_private *cp = dev->priv;
+	int rc = 0;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return cp_ethtool_ioctl(cp, (void *) rq->ifr_data);
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	return rc;
+}
+
+
+
+/* Serial EEPROM section. */
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
+#define EE_CS			0x08	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */
+#define EE_WRITE_0		0x00
+#define EE_WRITE_1		0x02
+#define EE_DATA_READ	0x01	/* EEPROM chip data out. */
+#define EE_ENB			(0x80 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
+ */
+
+#define eeprom_delay()	readl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5)
+#define EE_READ_CMD		(6)
+#define EE_ERASE_CMD	(7)
+
+static int __devinit read_eeprom (void *ioaddr, int location, int addr_len)
+{
+	int i;
+	unsigned retval = 0;
+	void *ee_addr = ioaddr + Cfg9346;
+	int read_cmd = location | (EE_READ_CMD << addr_len);
+
+	writeb (EE_ENB & ~EE_CS, ee_addr);
+	writeb (EE_ENB, ee_addr);
+	eeprom_delay ();
+
+	/* Shift the read command bits out. */
+	for (i = 4 + addr_len; i >= 0; i--) {
+		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		writeb (EE_ENB | dataval, ee_addr);
+		eeprom_delay ();
+		writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay ();
+	}
+	writeb (EE_ENB, ee_addr);
+	eeprom_delay ();
+
+	for (i = 16; i > 0; i--) {
+		writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay ();
+		retval =
+		    (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 :
+				     0);
+		writeb (EE_ENB, ee_addr);
+		eeprom_delay ();
+	}
+
+	/* Terminate the EEPROM access. */
+	writeb (~EE_CS, ee_addr);
+	eeprom_delay ();
+
+	return retval;
+}
+
+static int __devinit cp_init_one (struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	struct net_device *dev;
+	struct cp_private *cp;
+	int rc;
+	void *regs;
+	long pciaddr;
+	unsigned addr_len, i;
+	u8 pci_rev, cache_size;
+	u16 pci_command;
+
+#ifndef MODULE
+	static int version_printed;
+	if (version_printed++ == 0)
+		printk("%s", version);
+#endif
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
+
+	if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
+	    pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev < 0x20) {
+		printk(KERN_ERR PFX "pci dev %s (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
+		       pdev->slot_name, pdev->vendor, pdev->device, pci_rev);
+		printk(KERN_ERR PFX "Try the \"8139too\" driver instead.\n");
+		return -ENODEV;
+	}
+
+	dev = alloc_etherdev(sizeof(struct cp_private));
+	if (!dev)
+		return -ENOMEM;
+	SET_MODULE_OWNER(dev);
+	cp = dev->priv;
+	cp->pdev = pdev;
+	cp->dev = dev;
+	cp->msg_enable = (debug < 0 ? CP_DEF_MSG_ENABLE : debug);
+	spin_lock_init (&cp->lock);
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		goto err_out_free;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out_disable;
+
+	if (pdev->irq < 2) {
+		rc = -EIO;
+		printk(KERN_ERR PFX "invalid irq (%d) for pci dev %s\n",
+		       pdev->irq, pdev->slot_name);
+		goto err_out_res;
+	}
+	pciaddr = pci_resource_start(pdev, 1);
+	if (!pciaddr) {
+		rc = -EIO;
+		printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n",
+		       pdev->slot_name);
+		goto err_out_res;
+	}
+	if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
+		rc = -EIO;
+		printk(KERN_ERR PFX "MMIO resource (%lx) too small on pci dev %s\n",
+		       pci_resource_len(pdev, 1), pdev->slot_name);
+		goto err_out_res;
+	}
+
+	regs = ioremap_nocache(pciaddr, CP_REGS_SIZE);
+	if (!regs) {
+		rc = -EIO;
+		printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n",
+		       pci_resource_len(pdev, 1), pciaddr, pdev->slot_name);
+		goto err_out_res;
+	}
+	dev->base_addr = (unsigned long) regs;
+	cp->regs = regs;
+
+	cp_stop_hw(cp);
+
+	/* read MAC address from EEPROM */
+	addr_len = read_eeprom (regs, 0, 8) == 0x8129 ? 8 : 6;
+	for (i = 0; i < 3; i++)
+		((u16 *) (dev->dev_addr))[i] =
+		    le16_to_cpu (read_eeprom (regs, i + 7, addr_len));
+
+	dev->open = cp_open;
+	dev->stop = cp_close;
+	dev->set_multicast_list = cp_set_rx_mode;
+	dev->hard_start_xmit = cp_start_xmit;
+	dev->get_stats = cp_get_stats;
+	dev->do_ioctl = cp_ioctl;
+#if 0
+	dev->tx_timeout = cp_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+#ifdef CP_TX_CHECKSUM
+	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+#endif
+
+	dev->irq = pdev->irq;
+
+	rc = register_netdev(dev);
+	if (rc)
+		goto err_out_iomap;
+
+	printk (KERN_INFO "%s: %s at 0x%lx, "
+		"%02x:%02x:%02x:%02x:%02x:%02x, "
+		"IRQ %d\n",
+		dev->name,
+		"RTL-8139C+",
+		dev->base_addr,
+		dev->dev_addr[0], dev->dev_addr[1],
+		dev->dev_addr[2], dev->dev_addr[3],
+		dev->dev_addr[4], dev->dev_addr[5],
+		dev->irq);
+
+	pci_set_drvdata(pdev, dev);
+
+	/*
+	 * Looks like this is necessary to deal with on all architectures,
+	 * even this %$#%$# N440BX Intel based thing doesn't get it right.
+	 * Ie. having two NICs in the machine, one will have the cache
+	 * line set at boot time, the other will not.
+	 */
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_size);
+	cache_size <<= 2;
+	if (cache_size != SMP_CACHE_BYTES) {
+		printk(KERN_INFO "%s: PCI cache line size set incorrectly "
+		       "(%i bytes) by BIOS/FW, ", dev->name, cache_size);
+		if (cache_size > SMP_CACHE_BYTES)
+			printk("expecting %i\n", SMP_CACHE_BYTES);
+		else {
+			printk("correcting to %i\n", SMP_CACHE_BYTES);
+			pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+					      SMP_CACHE_BYTES >> 2);
+		}
+	}
+
+	/* enable busmastering and memory-write-invalidate */
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	if (!(pci_command & PCI_COMMAND_INVALIDATE)) {
+		pci_command |= PCI_COMMAND_INVALIDATE;
+		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+	}
+	pci_set_master(pdev);
+
+	return 0;
+
+err_out_iomap:
+	iounmap(regs);
+err_out_res:
+	pci_release_regions(pdev);
+err_out_disable:
+	pci_disable_device(pdev);
+err_out_free:
+	kfree(dev);
+	return rc;
+}
+
+static void __devexit cp_remove_one (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct cp_private *cp = dev->priv;
+
+	if (!dev)
+		BUG();
+	unregister_netdev(dev);
+	iounmap(cp->regs);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	kfree(dev);
+}
+
+static struct pci_driver cp_driver = {
+	name:		DRV_NAME,
+	id_table:	cp_pci_tbl,
+	probe:		cp_init_one,
+	remove:		cp_remove_one,
+};
+
+static int __init cp_init (void)
+{
+#ifdef MODULE
+	printk("%s", version);
+#endif
+	return pci_module_init (&cp_driver);
+}
+
+static void __exit cp_exit (void)
+{
+	pci_unregister_driver (&cp_driver);
+}
+
+module_init(cp_init);
+module_exit(cp_exit);
diff -u --recursive --new-file v2.4.12/linux/drivers/net/8139too.c linux/drivers/net/8139too.c
--- v2.4.12/linux/drivers/net/8139too.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/net/8139too.c	Fri Oct 19 08:32:28 2001
@@ -72,7 +72,7 @@
 		features of the 8139 chips
 
 		Jean-Jacques Michel - bug fix
-		
+
 		Tobias Ringström - Rx interrupt status checking suggestion
 
 		Andrew Morton - Clear blocked signals, avoid
@@ -139,7 +139,7 @@
 */
 
 #define DRV_NAME	"8139too"
-#define DRV_VERSION	"0.9.19"
+#define DRV_VERSION	"0.9.20"
 
 
 #include <linux/config.h>
@@ -258,6 +258,7 @@
 	DELTA8139,
 	ADDTRON8139,
 	DFE538TX,
+	DFE690TXD,
 	RTL8129,
 } board_t;
 
@@ -274,6 +275,7 @@
 	{ "Delta Electronics 8139 10/100BaseTX", RTL8139_CAPS },
 	{ "Addtron Technolgy 8139 10/100BaseTX", RTL8139_CAPS },
 	{ "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS },
+	{ "D-Link DFE-690TXD (RealTek RTL8139)", RTL8139_CAPS },
 	{ "RealTek RTL8129", RTL8129_CAPS },
 };
 
@@ -286,6 +288,7 @@
 	{0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 },
 	{0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 },
 	{0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE538TX },
+	{0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE690TXD },
 
 #ifdef CONFIG_8139TOO_8129
 	{0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
@@ -942,6 +945,7 @@
 	int i, addr_len, option;
 	void *ioaddr;
 	static int board_idx = -1;
+	u8 pci_rev;
 
 	DPRINTK ("ENTER\n");
 
@@ -961,6 +965,15 @@
 	}
 #endif
 
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
+
+	if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
+	    pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
+		printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
+		       pdev->slot_name, pdev->vendor, pdev->device, pci_rev);
+		printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
+	}
+
 	i = rtl8139_init_board (pdev, &dev);
 	if (i < 0) {
 		DPRINTK ("EXIT, returning %d\n", i);
@@ -1372,7 +1385,7 @@
 	struct rtl8139_private *tp = dev->priv;
 
 	DPRINTK("ENTER\n");
-	
+
 	if (tp->phys[0] >= 0) {
 		u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
 		if (mii_reg5 == 0xffff)
@@ -1421,7 +1434,7 @@
 	RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift));
 
 	tp->cur_rx = 0;
-	
+
 	rtl_check_media (dev);
 
 	if (tp->chipset >= CH_8139B) {
@@ -1879,7 +1892,7 @@
 {
 	u8 tmp8;
 	int tmp_work;
-    
+
 	DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n",
 	         dev->name, rx_status);
 	if (rx_status & RxTooLong) {
@@ -1967,7 +1980,7 @@
 		struct sk_buff *skb;
 
 		rmb();
-		
+
 		/* read size+status of next frame from DMA ring buffer */
 		rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
 		rx_size = rx_status >> 16;
@@ -2376,7 +2389,7 @@
 		}
 
 	/* TODO: ETHTOOL_SSET */
-		
+
 	case ETHTOOL_GDRVINFO:
 		{
 			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
diff -u --recursive --new-file v2.4.12/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.4.12/linux/drivers/net/Config.in	Sun Sep 23 11:40:58 2001
+++ linux/drivers/net/Config.in	Fri Oct 19 08:32:28 2001
@@ -176,6 +176,7 @@
       dep_tristate '    PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI
       dep_tristate '    Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
+      dep_tristate '    RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_8139CP $CONFIG_PCI $CONFIG_EXPERIMENTAL
       dep_tristate '    RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO $CONFIG_PCI
       dep_mbool '      Use PIO instead of MMIO' CONFIG_8139TOO_PIO $CONFIG_8139TOO
       dep_mbool '      Support for automatic channel equalization (EXPERIMENTAL)' CONFIG_8139TOO_TUNE_TWISTER $CONFIG_8139TOO $CONFIG_EXPERIMENTAL
@@ -191,7 +192,7 @@
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
 	 dep_bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET $CONFIG_ISA
       fi
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_MIPS" = "y" ]; then
 	 bool '    Philips SAA9730 Ethernet support (EXPERIMENTAL)' CONFIG_LAN_SAA9730
       fi
    fi
diff -u --recursive --new-file v2.4.12/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.4.12/linux/drivers/net/Makefile	Sun Sep 23 11:40:58 2001
+++ linux/drivers/net/Makefile	Fri Oct 19 08:32:28 2001
@@ -164,6 +164,7 @@
 obj-$(CONFIG_3C515) += 3c515.o
 obj-$(CONFIG_EEXPRESS) += eexpress.o
 obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
+obj-$(CONFIG_8139CP) += 8139cp.o
 obj-$(CONFIG_8139TOO) += 8139too.o
 obj-$(CONFIG_WAVELAN) += wavelan.o
 obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o
diff -u --recursive --new-file v2.4.12/linux/drivers/net/a2065.c linux/drivers/net/a2065.c
--- v2.4.12/linux/drivers/net/a2065.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/a2065.c	Tue Oct 16 21:56:29 2001
@@ -837,3 +837,4 @@
 
 module_init(a2065_probe);
 module_exit(a2065_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.4.12/linux/drivers/net/acenic.c	Thu Oct 11 08:02:26 2001
+++ linux/drivers/net/acenic.c	Fri Oct 12 15:35:53 2001
@@ -165,10 +165,6 @@
 #define SMP_CACHE_BYTES	L1_CACHE_BYTES
 #endif
 
-#if (BITS_PER_LONG == 64) || defined(CONFIG_HIGHMEM)
-#define ACE_64BIT_PTR	1
-#endif
-
 #ifndef SET_MODULE_OWNER
 #define SET_MODULE_OWNER(dev)		{do{} while(0);}
 #define ACE_MOD_INC_USE_COUNT		MOD_INC_USE_COUNT
@@ -203,9 +199,15 @@
 	*dma_handle = virt_to_bus(virt_ptr);
 	return virt_ptr;
 }
+
 #define pci_free_consistent(cookie, size, ptr, dma_ptr)	kfree(ptr)
-#define pci_map_single(cookie, address, size, dir)	virt_to_bus(address)
-#define pci_unmap_single(cookie, address, size, dir)
+#define pci_map_page(cookie, page, off, size, dir)	\
+	virt_to_bus(page_address(page)+(off))
+#define pci_unmap_page(cookie, address, size, dir)
+#define pci_set_dma_mask(dev, mask)		\
+	(((u64)(mask) & 0xffffffff00000000) == 0 ? 0 : -EIO)
+#define pci_dma_supported(dev, mask)		\
+	(((u64)(mask) & 0xffffffff00000000) == 0 ? 1 : 0)
 #endif
 
 #if (LINUX_VERSION_CODE < 0x02032b)
@@ -263,10 +265,6 @@
 #define ace_if_down(dev)			{do{} while(0);}
 #endif
 
-#ifndef pci_set_dma_mask
-#define pci_set_dma_mask(dev, mask)		dev->dma_mask = mask;
-#endif
-
 #if (LINUX_VERSION_CODE >= 0x02031b)
 #define NEW_NETINIT
 #define ACE_PROBE_ARG				void
@@ -598,7 +596,7 @@
 		dev->irq = pdev->irq;
 		dev->open = &ace_open;
 		dev->hard_start_xmit = &ace_start_xmit;
-		dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA;
+		dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 		if (1) {
 			static void ace_watchdog(struct net_device *dev);
 			dev->tx_timeout = &ace_watchdog;
@@ -740,6 +738,8 @@
 			kfree(dev);
 			continue;
 		}
+		if (ap->pci_using_dac)
+			dev->features |= NETIF_F_HIGHDMA;
 
 		boards_found++;
 	}
@@ -816,9 +816,9 @@
 				dma_addr_t mapping;
 
 				mapping = ap->skb->rx_std_skbuff[i].mapping;
-				pci_unmap_single(ap->pdev, mapping,
-						 ACE_STD_BUFSIZE - (2 + 16),
-						 PCI_DMA_FROMDEVICE);
+				pci_unmap_page(ap->pdev, mapping,
+					       ACE_STD_BUFSIZE - (2 + 16),
+					       PCI_DMA_FROMDEVICE);
 
 				ap->rx_std_ring[i].size = 0;
 				ap->skb->rx_std_skbuff[i].skb = NULL;
@@ -833,9 +833,9 @@
 					dma_addr_t mapping;
 
 					mapping = ap->skb->rx_mini_skbuff[i].mapping;
-					pci_unmap_single(ap->pdev, mapping,
-							 ACE_MINI_BUFSIZE - (2 + 16),
-							 PCI_DMA_FROMDEVICE);
+					pci_unmap_page(ap->pdev, mapping,
+						       ACE_MINI_BUFSIZE - (2 + 16),
+						       PCI_DMA_FROMDEVICE);
 
 					ap->rx_mini_ring[i].size = 0;
 					ap->skb->rx_mini_skbuff[i].skb = NULL;
@@ -849,9 +849,9 @@
 				dma_addr_t mapping;
 
 				mapping = ap->skb->rx_jumbo_skbuff[i].mapping;
-				pci_unmap_single(ap->pdev, mapping,
-						 ACE_JUMBO_BUFSIZE - (2 + 16),
-						 PCI_DMA_FROMDEVICE);
+				pci_unmap_page(ap->pdev, mapping,
+					       ACE_JUMBO_BUFSIZE - (2 + 16),
+					       PCI_DMA_FROMDEVICE);
 
 				ap->rx_jumbo_ring[i].size = 0;
 				ap->skb->rx_jumbo_skbuff[i].skb = NULL;
@@ -1210,12 +1210,6 @@
 		ap->pci_latency);
 
 	/*
-	 * Make sure to enable the 64 bit DMA mask if we're in a 64bit slot
-	 */
-	if (!(pci_state & PCI_32BIT))
-		pci_set_dma_mask(ap->pdev, (dma_addr_t)~0ULL);
-
-	/*
 	 * Set the max DMA transfer size. Seems that for most systems
 	 * the performance is better when no MAX parameter is
 	 * set. However for systems enabling PCI write and invalidate,
@@ -1309,12 +1303,24 @@
 #endif
 		
 	/*
+	 * Configure DMA attributes.
+	 */
+	if (!pci_set_dma_mask(ap->pdev, (u64) 0xffffffffffffffff)) {
+		ap->pci_using_dac = 1;
+	} else if (!pci_set_dma_mask(ap->pdev, (u64) 0xffffffff)) {
+		ap->pci_using_dac = 0;
+	} else {
+		ecode = -ENODEV;
+		goto init_error;
+	}
+
+	/*
 	 * Initialize the generic info block and the command+event rings
 	 * and the control blocks for the transmit and receive rings
 	 * as they need to be setup once and for all.
 	 */
 	if (!(info = pci_alloc_consistent(ap->pdev, sizeof(struct ace_info),
-				    &ap->info_dma))) {
+					  &ap->info_dma))) {
 		ecode = -EAGAIN;
 		goto init_error;
 	}
@@ -1355,12 +1361,8 @@
 	ace_load_firmware(dev);
 	ap->fw_running = 0;
 
-	tmp_ptr = (unsigned long) ap->info_dma;
-#ifdef ACE_64BIT_PTR
+	tmp_ptr = (u64) ap->info_dma;
 	writel(tmp_ptr >> 32, &regs->InfoPtrHi);
-#else
-	writel(0, &regs->InfoPtrHi);
-#endif
 	writel(tmp_ptr & 0xffffffff, &regs->InfoPtrLo);
 
 	memset(ap->evt_ring, 0, EVT_RING_ENTRIES * sizeof(struct event));
@@ -1796,9 +1798,12 @@
 		 * Make sure IP header starts on a fresh cache line.
 		 */
 		skb_reserve(skb, 2 + 16);
-		mapping = pci_map_single(ap->pdev, skb->data,
-					 ACE_STD_BUFSIZE - (2 + 16),
-					 PCI_DMA_FROMDEVICE);
+		mapping = pci_map_page(ap->pdev,
+				       virt_to_page(skb->data),
+				       ((unsigned long) skb->data &
+					~PAGE_MASK),
+				       ACE_STD_BUFSIZE - (2 + 16),
+				       PCI_DMA_FROMDEVICE);
 		ap->skb->rx_std_skbuff[idx].skb = skb;
 		ap->skb->rx_std_skbuff[idx].mapping = mapping;
 
@@ -1860,9 +1865,12 @@
 		 * Make sure the IP header ends up on a fresh cache line
 		 */
 		skb_reserve(skb, 2 + 16);
-		mapping = pci_map_single(ap->pdev, skb->data,
-					 ACE_MINI_BUFSIZE - (2 + 16),
-					 PCI_DMA_FROMDEVICE);
+		mapping = pci_map_page(ap->pdev,
+				       virt_to_page(skb->data),
+				       ((unsigned long) skb->data &
+					~PAGE_MASK),
+				       ACE_MINI_BUFSIZE - (2 + 16),
+				       PCI_DMA_FROMDEVICE);
 		ap->skb->rx_mini_skbuff[idx].skb = skb;
 		ap->skb->rx_mini_skbuff[idx].mapping = mapping;
 
@@ -1919,9 +1927,12 @@
 		 * Make sure the IP header ends up on a fresh cache line
 		 */
 		skb_reserve(skb, 2 + 16);
-		mapping = pci_map_single(ap->pdev, skb->data,
-					 ACE_JUMBO_BUFSIZE - (2 + 16),
-					 PCI_DMA_FROMDEVICE);
+		mapping = pci_map_page(ap->pdev,
+				       virt_to_page(skb->data),
+				       ((unsigned long) skb->data &
+					~PAGE_MASK),
+				       ACE_JUMBO_BUFSIZE - (2 + 16),
+				       PCI_DMA_FROMDEVICE);
 		ap->skb->rx_jumbo_skbuff[idx].skb = skb;
 		ap->skb->rx_jumbo_skbuff[idx].mapping = mapping;
 
@@ -2129,8 +2140,8 @@
 
 		skb = rip->skb;
 		rip->skb = NULL;
-		pci_unmap_single(ap->pdev, rip->mapping, mapsize,
-				 PCI_DMA_FROMDEVICE);
+		pci_unmap_page(ap->pdev, rip->mapping, mapsize,
+			       PCI_DMA_FROMDEVICE);
 		skb_put(skb, retdesc->size);
 
 		/*
@@ -2198,8 +2209,8 @@
 		mapping = info->mapping;
 
 		if (mapping) {
-			pci_unmap_single(ap->pdev, mapping, info->maplen,
-					 PCI_DMA_TODEVICE);
+			pci_unmap_page(ap->pdev, mapping, info->maplen,
+				       PCI_DMA_TODEVICE);
 			info->mapping = 0;
 		}
 
@@ -2488,11 +2499,10 @@
 
 		if (mapping) {
 			memset(ap->tx_ring+i, 0, sizeof(struct tx_desc));
-			pci_unmap_single(ap->pdev, mapping, info->maplen,
-					 PCI_DMA_TODEVICE);
+			pci_unmap_page(ap->pdev, mapping, info->maplen,
+				       PCI_DMA_TODEVICE);
 			info->mapping = 0;
 		}
-
 		if (skb) {
 			dev_kfree_skb(skb);
 			info->skb = NULL;
@@ -2512,75 +2522,35 @@
 	return 0;
 }
 
-
-/*
- * Following below should be (in more clean form!) in arch/ARCH/kernel/pci_*.
- * For now, let it stay here.
- */
-#if defined(CONFIG_HIGHMEM) && MAX_SKB_FRAGS
-
-#if defined(CONFIG_X86)
-#define DMAADDR_OFFSET	0
-typedef unsigned long long dmaaddr_high_t;
-#elif defined(CONFIG_PPC)
-#define DMAADDR_OFFSET PCI_DRAM_OFFSET
-typedef unsigned long dmaaddr_high_t;
-#endif
-
-
-static inline dmaaddr_high_t
-pci_map_single_high(struct pci_dev *hwdev, struct page *page,
-		    int offset, size_t size, int dir)
-{
-	dmaaddr_high_t phys;
-
-	phys = (page-mem_map) *	(dmaaddr_high_t) PAGE_SIZE + offset;
-
-	return (phys + DMAADDR_OFFSET);
-}
-
-#else
-
-typedef unsigned long dmaaddr_high_t;
-
-static inline dmaaddr_high_t
-pci_map_single_high(struct pci_dev *hwdev, struct page *page,
-		    int offset, size_t size, int dir)
-{
-	return pci_map_single(hwdev, page_address(page) + offset, size, dir);
-}
-
-#endif
-
-
-static inline dmaaddr_high_t
+static inline dma_addr_t
 ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb,
 	       struct sk_buff *tail, u32 idx)
 {
 	unsigned long addr;
 	struct tx_ring_info *info;
 
-	addr = pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+	addr = pci_map_page(ap->pdev,
+			    virt_to_page(skb->data),
+			    ((unsigned long) skb->data &
+			     ~PAGE_MASK),
+			    skb->len, PCI_DMA_TODEVICE);
 
 	info = ap->skb->tx_skbuff + idx;
 	info->skb = tail;
 	info->mapping = addr;
 	info->maplen = skb->len;
-
 	return addr;
 }
 
 
 static inline void
-ace_load_tx_bd(struct tx_desc *desc, dmaaddr_high_t addr, u32 flagsize)
+ace_load_tx_bd(struct tx_desc *desc, u64 addr, u32 flagsize)
 {
 #if !USE_TX_COAL_NOW
 	flagsize &= ~BD_FLG_COAL_NOW;
 #endif
 
-#ifdef ACE_64BIT_PTR
 	desc->addr.addrhi = addr >> 32;
-#endif
 	desc->addr.addrlo = addr;
 	desc->flagsize = flagsize;
 }
@@ -2642,16 +2612,16 @@
 		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
 			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 			struct tx_ring_info *info;
-			dmaaddr_high_t phys;
+			dma_addr_t phys;
 
 			len += frag->size;
 			info = ap->skb->tx_skbuff + idx;
 			desc = ap->tx_ring + idx;
 
-			phys = pci_map_single_high(ap->pdev, frag->page,
-						   frag->page_offset,
-						   frag->size,
-						   PCI_DMA_TODEVICE);
+			phys = pci_map_page(ap->pdev, frag->page,
+					    frag->page_offset,
+					    frag->size,
+					    PCI_DMA_TODEVICE);
 
 			flagsize = (frag->size << 16);
 			if (skb->ip_summed == CHECKSUM_HW)
@@ -2673,7 +2643,6 @@
 			}
 			info->mapping = phys;
 			info->maplen = frag->size;
-
 			ace_load_tx_bd(desc, phys, flagsize);
 		}
 	}
@@ -2995,7 +2964,7 @@
 
 	while (size > 0) {
 		tsize = min_t(u32, ((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
-				min_t(u32, size, ACE_WINDOW_SIZE));
+			    min_t(u32, size, ACE_WINDOW_SIZE));
 		tdest = (unsigned long)&regs->Window +
 			(dest & (ACE_WINDOW_SIZE - 1));
 		writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);
@@ -3026,7 +2995,7 @@
 
 	while (size > 0) {
 		tsize = min_t(u32, ((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
-			    min_t(u32, size, ACE_WINDOW_SIZE));
+				min_t(u32, size, ACE_WINDOW_SIZE));
 		tdest = (unsigned long)&regs->Window +
 			(dest & (ACE_WINDOW_SIZE - 1));
 		writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);
diff -u --recursive --new-file v2.4.12/linux/drivers/net/acenic.h linux/drivers/net/acenic.h
--- v2.4.12/linux/drivers/net/acenic.h	Thu Oct 11 08:02:26 2001
+++ linux/drivers/net/acenic.h	Fri Oct 12 15:35:53 2001
@@ -582,7 +582,6 @@
 	aceaddr	stats2_ptr;
 };
 
-
 struct ring_info {
 	struct sk_buff		*skb;
 	dma_addr_t		mapping;
@@ -684,6 +683,7 @@
 	u32			last_tx, last_std_rx, last_mini_rx;
 #endif
 	struct net_device_stats stats;
+	int			pci_using_dac;
 };
 
 
@@ -705,31 +705,11 @@
 
 static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr)
 {
-	unsigned long baddr = (unsigned long) addr;
-#ifdef ACE_64BIT_PTR
+	u64 baddr = (u64) addr;
 	aa->addrlo = baddr & 0xffffffff;
 	aa->addrhi = baddr >> 32;
-#else
-	/* Don't bother setting zero every time */
-	aa->addrlo = baddr;
-#endif
 	mb();
 }
-
-
-#if 0
-static inline void *get_aceaddr(aceaddr *aa)
-{
-	unsigned long addr;
-	mb();
-#ifdef ACE_64BIT_PTR
-	addr = (u64)aa->addrhi << 32 | aa->addrlo;
-#else
-	addr = aa->addrlo;
-#endif
-	return (void *)addr;
-}
-#endif
 
 
 static inline void ace_set_txprd(struct ace_regs *regs,
diff -u --recursive --new-file v2.4.12/linux/drivers/net/atari_bionet.c linux/drivers/net/atari_bionet.c
--- v2.4.12/linux/drivers/net/atari_bionet.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/atari_bionet.c	Tue Oct 16 21:56:29 2001
@@ -128,6 +128,7 @@
 unsigned int bionet_debug = NET_DEBUG;
 MODULE_PARM(bionet_debug, "i");
 MODULE_PARM_DESC(bionet_debug, "bionet debug level (0-2)");
+MODULE_LICENSE("GPL");
 
 static unsigned int bionet_min_poll_time = 2;
 
diff -u --recursive --new-file v2.4.12/linux/drivers/net/atari_pamsnet.c linux/drivers/net/atari_pamsnet.c
--- v2.4.12/linux/drivers/net/atari_pamsnet.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/atari_pamsnet.c	Tue Oct 16 21:56:29 2001
@@ -124,6 +124,7 @@
 unsigned int pamsnet_debug = NET_DEBUG;
 MODULE_PARM(pamsnet_debug, "i");
 MODULE_PARM_DESC(pamsnet_debug, "pamsnet debug enable (0-1)");
+MODULE_LICENSE("GPL");
 
 static unsigned int pamsnet_min_poll_time = 2;
 
diff -u --recursive --new-file v2.4.12/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c
--- v2.4.12/linux/drivers/net/atarilance.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/atarilance.c	Tue Oct 16 21:56:29 2001
@@ -84,6 +84,7 @@
 #endif
 MODULE_PARM(lance_debug, "i");
 MODULE_PARM_DESC(lance_debug, "atarilance debug level (0-3)");
+MODULE_LICENSE("GPL");
 
 /* Print debug messages on probing? */
 #undef LANCE_DEBUG_PROBE
diff -u --recursive --new-file v2.4.12/linux/drivers/net/bagetlance.c linux/drivers/net/bagetlance.c
--- v2.4.12/linux/drivers/net/bagetlance.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/bagetlance.c	Tue Oct 16 21:56:29 2001
@@ -60,6 +60,7 @@
 #endif
 MODULE_PARM(lance_debug, "i");
 MODULE_PARM_DESC(lance_debug, "Lance debug level (0-3)");
+MODULE_LICENSE("GPL");
 
 /* Print debug messages on probing? */
 #undef LANCE_DEBUG_PROBE
diff -u --recursive --new-file v2.4.12/linux/drivers/net/bmac.c linux/drivers/net/bmac.c
--- v2.4.12/linux/drivers/net/bmac.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/net/bmac.c	Tue Oct 16 21:56:29 2001
@@ -1658,6 +1658,7 @@
 
 MODULE_AUTHOR("Randy Gobbel/Paul Mackerras");
 MODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");
+MODULE_LICENSE("GPL");
 
 
 static void __exit bmac_cleanup (void)
diff -u --recursive --new-file v2.4.12/linux/drivers/net/fealnx.c linux/drivers/net/fealnx.c
--- v2.4.12/linux/drivers/net/fealnx.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/net/fealnx.c	Tue Oct 16 21:56:29 2001
@@ -109,6 +109,7 @@
 
 MODULE_AUTHOR("Myson or whoever");
 MODULE_DESCRIPTION("Myson MTD-8xx 100/10M Ethernet PCI Adapter Driver");
+MODULE_LICENSE("GPL");
 MODULE_PARM(max_interrupt_work, "i");
 //MODULE_PARM(min_pci_latency, "i");
 MODULE_PARM(debug, "i");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c
--- v2.4.12/linux/drivers/net/fmv18x.c	Wed Jul 25 17:10:21 2001
+++ linux/drivers/net/fmv18x.c	Tue Oct 16 21:56:29 2001
@@ -632,6 +632,7 @@
 MODULE_PARM_DESC(io, "FMV-18X I/O address");
 MODULE_PARM_DESC(irq, "FMV-18X IRQ number");
 MODULE_PARM_DESC(net_debug, "FMV-18X debug level (0-1,5-6)");
+MODULE_LICENSE("GPL");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.12/linux/drivers/net/gmac.c linux/drivers/net/gmac.c
--- v2.4.12/linux/drivers/net/gmac.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/net/gmac.c	Tue Oct 16 21:56:29 2001
@@ -1676,6 +1676,7 @@
 
 MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt");
 MODULE_DESCRIPTION("PowerMac GMAC driver.");
+MODULE_LICENSE("GPL");
 
 static void __exit gmac_cleanup_module(void)
 {
diff -u --recursive --new-file v2.4.12/linux/drivers/net/gt96100eth.c linux/drivers/net/gt96100eth.c
--- v2.4.12/linux/drivers/net/gt96100eth.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/net/gt96100eth.c	Tue Oct 16 21:56:29 2001
@@ -1250,3 +1250,4 @@
 }
 
 module_init(gt96100_probe);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c
--- v2.4.12/linux/drivers/net/hamradio/scc.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/net/hamradio/scc.c	Fri Oct 12 14:22:49 2001
@@ -1,5 +1,3 @@
-#define RCS_ID "$Id: scc.c,v 1.75 1998/11/04 15:15:01 jreuter Exp jreuter $"
-
 #define VERSION "3.0"
 
 /*
@@ -18,7 +16,7 @@
 
    ********************************************************************
 
-	Copyright (c) 1993, 2000 Joerg Reuter DL1BKE
+	Copyright (c) 1993, 2001 Joerg Reuter DL1BKE
 
 	portions (c) 1993 Guido ten Dolle PE1NNZ
 
@@ -106,6 +104,10 @@
    2000-02-13	Fixed for new network driver interface changes, still
    		does TX timeouts itself since it uses its own queue
    		scheme.
+   2001-10-05   Set skb to NULL on Rx_OVR in scc_spint() (tnx everybody
+		who insisted that the skb gets in fact re-used by the
+		following code otherwise. I think we have another Z8530
+		bug here...)
 
    Thanks to all who contributed to this driver with ideas and bug
    reports!
@@ -583,6 +585,7 @@
 		if (skb != NULL) 
 			dev_kfree_skb_irq(skb);
 		scc->rx_buff = skb = NULL;
+		skb = NULL;			/* avoid skb being reused */
 	}
 
 	if(status & END_FR && skb != NULL)	/* end of frame */
diff -u --recursive --new-file v2.4.12/linux/drivers/net/hplance.c linux/drivers/net/hplance.c
--- v2.4.12/linux/drivers/net/hplance.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/hplance.c	Tue Oct 16 21:56:29 2001
@@ -226,6 +226,7 @@
 }
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
 int init_module(void)
 {
         root_lance_dev = NULL;
diff -u --recursive --new-file v2.4.12/linux/drivers/net/hydra.c linux/drivers/net/hydra.c
--- v2.4.12/linux/drivers/net/hydra.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/hydra.c	Tue Oct 16 21:56:29 2001
@@ -254,3 +254,4 @@
 
 module_init(hydra_probe);
 module_exit(hydra_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/ibmlana.c linux/drivers/net/ibmlana.c
--- v2.4.12/linux/drivers/net/ibmlana.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/ibmlana.c	Tue Oct 16 21:56:29 2001
@@ -1199,6 +1199,7 @@
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(irq, "IBM LAN/A IRQ number");
 MODULE_PARM_DESC(io, "IBM LAN/A I/O base address");
+MODULE_LICENSE("GPL");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.12/linux/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c
--- v2.4.12/linux/drivers/net/ioc3-eth.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/net/ioc3-eth.c	Tue Oct 16 21:56:29 2001
@@ -1817,6 +1817,7 @@
 
 MODULE_AUTHOR("Ralf Baechle <ralf@oss.sgi.com>");
 MODULE_DESCRIPTION("SGI IOC3 Ethernet driver");
+MODULE_LICENSE("GPL");
 
 module_init(ioc3_init_module);
 module_exit(ioc3_cleanup_module);
diff -u --recursive --new-file v2.4.12/linux/drivers/net/isa-skeleton.c linux/drivers/net/isa-skeleton.c
--- v2.4.12/linux/drivers/net/isa-skeleton.c	Wed Jul 25 17:10:21 2001
+++ linux/drivers/net/isa-skeleton.c	Tue Oct 16 21:56:29 2001
@@ -636,6 +636,7 @@
 static int irq;
 static int dma;
 static int mem;
+MODULE_LICENSE("GPL");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.12/linux/drivers/net/lasi_82596.c linux/drivers/net/lasi_82596.c
--- v2.4.12/linux/drivers/net/lasi_82596.c	Mon Aug 27 12:41:42 2001
+++ linux/drivers/net/lasi_82596.c	Tue Oct 16 21:56:29 2001
@@ -180,6 +180,7 @@
 
 MODULE_AUTHOR("Richard Hirst");
 MODULE_DESCRIPTION("i82596 driver");
+MODULE_LICENSE("GPL");
 MODULE_PARM(i596_debug, "i");
 MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
 
diff -u --recursive --new-file v2.4.12/linux/drivers/net/mac89x0.c linux/drivers/net/mac89x0.c
--- v2.4.12/linux/drivers/net/mac89x0.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/mac89x0.c	Tue Oct 16 21:56:29 2001
@@ -627,6 +627,7 @@
 
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)");
+MODULE_LICENSE("GPL");
 
 EXPORT_NO_SYMBOLS;
 
diff -u --recursive --new-file v2.4.12/linux/drivers/net/mace.c linux/drivers/net/mace.c
--- v2.4.12/linux/drivers/net/mace.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/mace.c	Tue Oct 16 21:56:29 2001
@@ -913,6 +913,7 @@
 
 MODULE_AUTHOR("Paul Mackerras");
 MODULE_DESCRIPTION("PowerMac MACE driver.");
+MODULE_LICENSE("GPL");
 
 static void __exit mace_cleanup (void)
 {
diff -u --recursive --new-file v2.4.12/linux/drivers/net/macsonic.c linux/drivers/net/macsonic.c
--- v2.4.12/linux/drivers/net/macsonic.c	Thu Oct 11 08:02:26 2001
+++ linux/drivers/net/macsonic.c	Tue Oct 16 21:56:29 2001
@@ -584,6 +584,7 @@
 
 MODULE_PARM(sonic_debug, "i");
 MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)");
+MODULE_LICENSE("GPL");
 
 EXPORT_NO_SYMBOLS;
 
diff -u --recursive --new-file v2.4.12/linux/drivers/net/mvme147.c linux/drivers/net/mvme147.c
--- v2.4.12/linux/drivers/net/mvme147.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/mvme147.c	Tue Oct 16 21:56:29 2001
@@ -188,6 +188,8 @@
 }
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	root_lance_dev = NULL;
diff -u --recursive --new-file v2.4.12/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c
--- v2.4.12/linux/drivers/net/myri_sbus.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/myri_sbus.c	Fri Oct 19 08:32:28 2001
@@ -1153,3 +1153,4 @@
 
 module_init(myri_sbus_probe);
 module_exit(myri_sbus_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/ne2.c linux/drivers/net/ne2.c
--- v2.4.12/linux/drivers/net/ne2.c	Sun Aug 12 13:27:59 2001
+++ linux/drivers/net/ne2.c	Tue Oct 16 21:56:29 2001
@@ -744,6 +744,7 @@
 static int io[MAX_NE_CARDS];
 static int irq[MAX_NE_CARDS];
 static int bad[MAX_NE_CARDS];	/* 0xbad = bad sig or no reset ack */
+MODULE_LICENSE("GPL");
 
 #ifdef MODULE_PARM
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/oaknet.c linux/drivers/net/oaknet.c
--- v2.4.12/linux/drivers/net/oaknet.c	Sat Mar  3 10:55:47 2001
+++ linux/drivers/net/oaknet.c	Tue Oct 16 21:56:29 2001
@@ -696,3 +696,4 @@
 
 module_init(oaknet_init_module);
 module_exit(oaknet_cleanup_module);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/pci-skeleton.c linux/drivers/net/pci-skeleton.c
--- v2.4.12/linux/drivers/net/pci-skeleton.c	Sun Aug 12 13:27:59 2001
+++ linux/drivers/net/pci-skeleton.c	Tue Oct 16 21:56:29 2001
@@ -484,6 +484,7 @@
 
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
 MODULE_DESCRIPTION ("Skeleton for a PCI Fast Ethernet driver");
+MODULE_LICENSE("GPL");
 MODULE_PARM (multicast_filter_limit, "i");
 MODULE_PARM (max_interrupt_work, "i");
 MODULE_PARM (debug, "i");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c
--- v2.4.12/linux/drivers/net/pcmcia/netwave_cs.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/pcmcia/netwave_cs.c	Fri Oct 12 14:21:18 2001
@@ -269,8 +269,15 @@
    because they generally can't be allocated dynamically.
 */
 
-#define SIOCGIPSNAP	SIOCDEVPRIVATE		/* Site Survey Snapshot */
-/*#define SIOCGIPQTHR	SIOCDEVPRIVATE + 1*/
+/* Wireless Extension Backward compatibility - Jean II
+ * If the new wireless device private ioctl range is not defined,
+ * default to standard device private ioctl range */
+#ifndef SIOCIWFIRSTPRIV
+#define SIOCIWFIRSTPRIV	SIOCDEVPRIVATE
+#endif /* SIOCIWFIRSTPRIV */
+
+#define SIOCGIPSNAP	SIOCIWFIRSTPRIV		/* Site Survey Snapshot */
+/*#define SIOCGIPQTHR	SIOCIWFIRSTPRIV + 1*/
 
 #define MAX_ESA 10
 
diff -u --recursive --new-file v2.4.12/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c
--- v2.4.12/linux/drivers/net/pcmcia/ray_cs.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/pcmcia/ray_cs.c	Fri Oct 12 14:21:18 2001
@@ -1451,9 +1451,12 @@
 #endif	/* WIRELESS_SPY */
 
       /* ------------------ PRIVATE IOCTL ------------------ */
-#define SIOCSIPFRAMING	SIOCDEVPRIVATE		/* Set framing mode */
-#define SIOCGIPFRAMING	SIOCDEVPRIVATE + 1	/* Get framing mode */
-#define SIOCGIPCOUNTRY	SIOCDEVPRIVATE + 3	/* Get country code */
+#ifndef SIOCIWFIRSTPRIV
+#define SIOCIWFIRSTPRIV	SIOCDEVPRIVATE
+#endif /* SIOCIWFIRSTPRIV */
+#define SIOCSIPFRAMING	SIOCIWFIRSTPRIV		/* Set framing mode */
+#define SIOCGIPFRAMING	SIOCIWFIRSTPRIV + 1	/* Get framing mode */
+#define SIOCGIPCOUNTRY	SIOCIWFIRSTPRIV + 3	/* Get country code */
     case SIOCSIPFRAMING:
       if(!capable(CAP_NET_ADMIN))	/* For private IOCTLs, we need to check permissions */
 	{
diff -u --recursive --new-file v2.4.12/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c
--- v2.4.12/linux/drivers/net/pcmcia/wavelan_cs.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/pcmcia/wavelan_cs.c	Fri Oct 12 14:21:18 2001
@@ -2269,6 +2269,12 @@
 	  range.max_qual.qual = MMR_SGNL_QUAL;
 	  range.max_qual.level = MMR_SIGNAL_LVL;
 	  range.max_qual.noise = MMR_SILENCE_LVL;
+#if WIRELESS_EXT > 11
+	  range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
+	  /* Need to get better values for those two */
+	  range.avg_qual.level = 30;
+	  range.avg_qual.noise = 8;
+#endif /* WIRELESS_EXT > 11 */
 
 #if WIRELESS_EXT > 7
 	  range.num_bitrates = 1;
diff -u --recursive --new-file v2.4.12/linux/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h
--- v2.4.12/linux/drivers/net/pcmcia/wavelan_cs.h	Wed Apr 18 14:40:05 2001
+++ linux/drivers/net/pcmcia/wavelan_cs.h	Fri Oct 12 14:21:18 2001
@@ -465,13 +465,20 @@
 
 /* ------------------------ PRIVATE IOCTL ------------------------ */
 
-#define SIOCSIPQTHR	SIOCDEVPRIVATE		/* Set quality threshold */
-#define SIOCGIPQTHR	SIOCDEVPRIVATE + 1	/* Get quality threshold */
-#define SIOCSIPROAM     SIOCDEVPRIVATE + 2      /* Set roaming state */
-#define SIOCGIPROAM     SIOCDEVPRIVATE + 3      /* Get roaming state */
+/* Wireless Extension Backward compatibility - Jean II
+ * If the new wireless device private ioctl range is not defined,
+ * default to standard device private ioctl range */
+#ifndef SIOCIWFIRSTPRIV
+#define SIOCIWFIRSTPRIV	SIOCDEVPRIVATE
+#endif /* SIOCIWFIRSTPRIV */
 
-#define SIOCSIPHISTO	SIOCDEVPRIVATE + 6	/* Set histogram ranges */
-#define SIOCGIPHISTO	SIOCDEVPRIVATE + 7	/* Get histogram values */
+#define SIOCSIPQTHR	SIOCIWFIRSTPRIV		/* Set quality threshold */
+#define SIOCGIPQTHR	SIOCIWFIRSTPRIV + 1	/* Get quality threshold */
+#define SIOCSIPROAM     SIOCIWFIRSTPRIV + 2	/* Set roaming state */
+#define SIOCGIPROAM     SIOCIWFIRSTPRIV + 3	/* Get roaming state */
+
+#define SIOCSIPHISTO	SIOCIWFIRSTPRIV + 6	/* Set histogram ranges */
+#define SIOCGIPHISTO	SIOCIWFIRSTPRIV + 7	/* Get histogram values */
 
 /*************************** WaveLAN Roaming  **************************/
 #ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
diff -u --recursive --new-file v2.4.12/linux/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c
--- v2.4.12/linux/drivers/net/pcmcia/xircom_tulip_cb.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/pcmcia/xircom_tulip_cb.c	Tue Oct 16 21:56:29 2001
@@ -9,11 +9,25 @@
 	Scyld Computing Corporation
 	410 Severn Ave., Suite 210
 	Annapolis MD 21403
+
+	-----------------------------------------------------------
+
+	Linux kernel-specific changes:
+
+	LK1.0 (Ion Badulescu)
+	- Major cleanup
+	- Use 2.4 PCI API
+	- Support ethtool
+	- Rewrite perfect filter/hash code
+	- Use interrupts for media changes
+
+	LK1.1 (Ion Badulescu)
+	- Disallow negotiation of unsupported full-duplex modes
 */
 
 #define DRV_NAME	"xircom_tulip_cb"
-#define DRV_VERSION	"0.91+LK"
-#define DRV_RELDATE	"July 19, 2001"
+#define DRV_VERSION	"0.91+LK1.1"
+#define DRV_RELDATE	"October 11, 2001"
 
 #define CARDBUS 1
 
@@ -94,7 +108,6 @@
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
 KERN_INFO DRV_NAME ".c derived from tulip.c:v0.91 4/14/99 becker@scyld.com\n"
-KERN_INFO " modified by danilo@cs.uni-magdeburg.de for XIRCOM CBE, fixed by Doug Ledford\n"
 KERN_INFO " unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE "\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
@@ -238,7 +251,7 @@
 	int valid_intrs;			/* CSR7 interrupt enable settings */
 	int flags;
 } xircom_tbl[] = {
-  { "Xircom Cardbus Adapter (DEC 21143 compatible mode)",
+  { "Xircom Cardbus Adapter",
 	LinkChange | NormalIntr | AbnormalIntr | BusErrorIntr |
 	RxDied | RxNoBuf | RxIntr | TxFIFOUnderflow | TxNoBuf | TxDied | TxIntr,
 	HAS_MII | HAS_ACPI, },
@@ -425,12 +438,22 @@
 
 /*
  * locate the MII interfaces and initialize them.
+ * we disable full-duplex modes here,
+ * because we don't know how to handle them.
  */
 static void find_mii_transceivers(struct net_device *dev)
 {
 	struct xircom_private *tp = dev->priv;
 	int phy, phy_idx;
 
+	if (media_cap[tp->default_port] & MediaIsMII) {
+		u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
+		tp->to_advertise = media2advert[tp->default_port - 9];
+	} else
+		tp->to_advertise =
+			/*ADVERTISE_100BASE4 | ADVERTISE_100FULL |*/ ADVERTISE_100HALF |
+			/*ADVERTISE_10FULL |*/ ADVERTISE_10HALF | ADVERTISE_CSMA;
+
 	/* Find the connected MII xcvrs.
 	   Doing this in open() would allow detecting external xcvrs later,
 	   but takes much time. */
@@ -447,17 +470,6 @@
 			printk(KERN_INFO "%s:  MII transceiver #%d "
 				   "config %4.4x status %4.4x advertising %4.4x.\n",
 				   dev->name, phy, mii_reg0, mii_status, mii_advert);
-			/* Fixup for DLink with miswired PHY. */
-			if (mii_advert != reg4) {
-				printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d,"
-					   " previously advertising %4.4x.\n",
-					   dev->name, reg4, phy, mii_advert);
-				mdio_write(dev, phy, MII_ADVERTISE, reg4);
-			}
-			/* Enable autonegotiation: some boards default to off. */
-			mdio_write(dev, phy, MII_BMCR, mii_reg0 | BMCR_ANENABLE |
-					   (tp->full_duplex ? BMCR_FULLDPLX : 0) |
-					   (media_cap[tp->default_port]&MediaIs100 ? BMCR_SPEED100 : 0));
 		}
 	}
 	tp->mii_cnt = phy_idx;
@@ -529,7 +541,7 @@
 		printk(version);
 #endif
 
-	printk(KERN_INFO "xircom_init_one(%s)\n", pdev->slot_name);
+	//printk(KERN_INFO "xircom_init_one(%s)\n", pdev->slot_name);
 
 	board_idx++;
 
@@ -1696,7 +1708,6 @@
 }
 
 
-/* XXX: resume isn't able to power up the MII/PHY! */
 static int xircom_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pdev->driver_data;
diff -u --recursive --new-file v2.4.12/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
--- v2.4.12/linux/drivers/net/pcnet32.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/pcnet32.c	Fri Oct 19 08:32:28 2001
@@ -53,7 +53,13 @@
 static struct pci_device_id pcnet32_pci_tbl[] __devinitdata = {
     { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
     { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+/* this id is never reached as the match above occurs first.
+ * However it clearly has significance, so let's not remove it
+ * until we know what that significance is.  -jgarzik
+ */
+#if 0
     { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000, 0, 0, 0 },
+#endif
     { 0, }
 };
 
diff -u --recursive --new-file v2.4.12/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c
--- v2.4.12/linux/drivers/net/ppp_generic.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/ppp_generic.c	Thu Oct 11 09:18:31 2001
@@ -2481,3 +2481,4 @@
 EXPORT_SYMBOL(ppp_unregister_compressor);
 EXPORT_SYMBOL(all_ppp_units); /* for debugging */
 EXPORT_SYMBOL(all_channels); /* for debugging */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/ppp_synctty.c linux/drivers/net/ppp_synctty.c
--- v2.4.12/linux/drivers/net/ppp_synctty.c	Wed Jul 25 17:10:21 2001
+++ linux/drivers/net/ppp_synctty.c	Thu Oct 11 11:17:22 2001
@@ -44,13 +44,6 @@
 #include <linux/init.h>
 #include <asm/uaccess.h>
 
-#ifndef spin_trylock_bh
-#define spin_trylock_bh(lock)	({ int __r; local_bh_disable();	\
-				   __r = spin_trylock(lock);	\
-				   if (!__r) local_bh_enable();	\
-				   __r; })
-#endif
-
 #define PPP_VERSION	"2.4.1"
 
 /* Structure for storing local state. */
@@ -708,3 +701,4 @@
 
 module_init(ppp_sync_init);
 module_exit(ppp_sync_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/saa9730.c linux/drivers/net/saa9730.c
--- v2.4.12/linux/drivers/net/saa9730.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/saa9730.c	Tue Oct 16 21:56:29 2001
@@ -1080,3 +1080,4 @@
 }
 
 module_init(saa9730_probe);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c
--- v2.4.12/linux/drivers/net/seeq8005.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/seeq8005.c	Tue Oct 16 21:56:29 2001
@@ -711,6 +711,7 @@
 static struct net_device dev_seeq = { init: seeq8005_probe };
 static int io = 0x320;
 static int irq = 10;
+MODULE_LICENSE("GPL");
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
 MODULE_PARM_DESC(io, "SEEQ 8005 I/O base address");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c
--- v2.4.12/linux/drivers/net/sk98lin/skge.c	Thu Oct 11 08:02:26 2001
+++ linux/drivers/net/sk98lin/skge.c	Fri Oct 12 15:35:53 2001
@@ -443,6 +443,11 @@
 		if (pci_enable_device(pdev))
 			continue;
 
+		/* Configure DMA attributes. */
+		if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) &&
+		    pci_set_dma_mask(pdev, (u64) 0xffffffff))
+				continue;
+
 		if ((dev = init_etherdev(dev, sizeof(DEV_NET))) == 0) {
 			printk(KERN_ERR "Unable to allocate etherdev "
 			       "structure!\n");
@@ -1770,10 +1775,12 @@
 #endif
 
 	/* set up descriptor and CONTROL dword */
-	PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev,
-					   pMessage->data,
-					   pMessage->len,
-					   PCI_DMA_TODEVICE);
+	PhysAddr = (SK_U64) pci_map_page(&pAC->PciDev,
+					 virt_to_page(pMessage->data),
+					 ((unsigned long) pMessage->data &
+					  ~PAGE_MASK),
+					 pMessage->len,
+					 PCI_DMA_TODEVICE);
 	pTxd->VDataLow = (SK_U32)  (PhysAddr & 0xffffffff);
 	pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
 	pTxd->pMBuf = pMessage;
@@ -1865,9 +1872,9 @@
 		/* release the DMA mapping */
 		PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32;
 		PhysAddr |= (SK_U64) pTxd->VDataLow;
-		pci_unmap_single(&pAC->PciDev, PhysAddr,
-				 pTxd->pMBuf->len,
-				 PCI_DMA_TODEVICE);
+		pci_unmap_page(&pAC->PciDev, PhysAddr,
+			       pTxd->pMBuf->len,
+			       PCI_DMA_TODEVICE);
 
 		/* free message */
 		DEV_KFREE_SKB_ANY(pTxd->pMBuf);
@@ -1946,10 +1953,12 @@
 	pRxPort->pRxdRingTail = pRxd->pNextRxd;
 	pRxPort->RxdRingFree--;
 	Length = pAC->RxBufSize;
-	PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev,
-					   pMsgBlock->data,
-					   pAC->RxBufSize - 2,
-					   PCI_DMA_FROMDEVICE);
+	PhysAddr = (SK_U64) pci_map_page(&pAC->PciDev,
+					 virt_to_page(pMsgBlock->data),
+					 ((unsigned long) pMsgBlock->data &
+					  ~PAGE_MASK),
+					 pAC->RxBufSize - 2,
+					 PCI_DMA_FROMDEVICE);
 	pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
 	pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
 	pRxd->pMBuf = pMsgBlock;
@@ -2093,9 +2102,9 @@
 			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
 			PhysAddr |= (SK_U64) pRxd->VDataLow;
 			pci_dma_sync_single(&pAC->PciDev,
-						(dma_addr_t) PhysAddr,
-						FrameLength,
-						PCI_DMA_FROMDEVICE);
+					    (dma_addr_t) PhysAddr,
+					    FrameLength,
+					    PCI_DMA_FROMDEVICE);
 			ReQueueRxBuffer(pAC, pRxPort, pMsg,
 				pRxd->VDataHigh, pRxd->VDataLow);
 
@@ -2117,9 +2126,9 @@
 			skb_reserve(pNewMsg, 2);
 			skb_put(pNewMsg, FrameLength);
 			pci_dma_sync_single(&pAC->PciDev,
-						(dma_addr_t) PhysAddr,
-						FrameLength,
-						PCI_DMA_FROMDEVICE);
+					    (dma_addr_t) PhysAddr,
+					    FrameLength,
+					    PCI_DMA_FROMDEVICE);
 			eth_copy_and_sum(pNewMsg, pMsg->data,
 				FrameLength, 0);
 			ReQueueRxBuffer(pAC, pRxPort, pMsg,
@@ -2137,10 +2146,10 @@
 			PhysAddr |= (SK_U64) pRxd->VDataLow;
 
 			/* release the DMA mapping */
-			pci_unmap_single(&pAC->PciDev,
-					 PhysAddr,
-					 pAC->RxBufSize - 2,
-					 PCI_DMA_FROMDEVICE);
+			pci_unmap_page(&pAC->PciDev,
+				       PhysAddr,
+				       pAC->RxBufSize - 2,
+				       PCI_DMA_FROMDEVICE);
 
 			/* set length in message */
 			skb_put(pMsg, FrameLength);
@@ -2262,10 +2271,10 @@
 	/* release the DMA mapping */
 	PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
 	PhysAddr |= (SK_U64) pRxd->VDataLow;
-	pci_unmap_single(&pAC->PciDev,
-			 PhysAddr,
-			 pAC->RxBufSize - 2,
-			 PCI_DMA_FROMDEVICE);
+	pci_unmap_page(&pAC->PciDev,
+		       PhysAddr,
+		       pAC->RxBufSize - 2,
+		       PCI_DMA_FROMDEVICE);
 	DEV_KFREE_SKB_IRQ(pRxd->pMBuf);
 	pRxd->pMBuf = NULL;
 	pRxPort->RxdRingFree++;
@@ -2342,10 +2351,10 @@
 		if (pRxd->pMBuf != NULL) {
 			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
 			PhysAddr |= (SK_U64) pRxd->VDataLow;
-			pci_unmap_single(&pAC->PciDev,
-					 PhysAddr,
-					 pAC->RxBufSize - 2,
-					 PCI_DMA_FROMDEVICE);
+			pci_unmap_page(&pAC->PciDev,
+				       PhysAddr,
+				       pAC->RxBufSize - 2,
+				       PCI_DMA_FROMDEVICE);
 			DEV_KFREE_SKB(pRxd->pMBuf);
 			pRxd->pMBuf = NULL;
 		}
diff -u --recursive --new-file v2.4.12/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v2.4.12/linux/drivers/net/sk_g16.c	Wed Jul 25 17:10:22 2001
+++ linux/drivers/net/sk_g16.c	Tue Oct 16 21:56:29 2001
@@ -616,6 +616,7 @@
 
 MODULE_AUTHOR("Patrick J.D. Weichmann");
 MODULE_DESCRIPTION("Schneider & Koch G16 Ethernet Device Driver");
+MODULE_LICENSE("GPL");
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(io, "0 to probe common ports (unsafe), or the I/O base of the board");
 
diff -u --recursive --new-file v2.4.12/linux/drivers/net/sk_mca.c linux/drivers/net/sk_mca.c
--- v2.4.12/linux/drivers/net/sk_mca.c	Wed Jul 25 17:10:22 2001
+++ linux/drivers/net/sk_mca.c	Tue Oct 16 21:56:29 2001
@@ -1229,6 +1229,7 @@
  * ------------------------------------------------------------------------ */
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
 
 #define DEVMAX 5
 
diff -u --recursive --new-file v2.4.12/linux/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c
--- v2.4.12/linux/drivers/net/smc-mca.c	Mon Aug 27 12:41:43 2001
+++ linux/drivers/net/smc-mca.c	Tue Oct 16 21:56:29 2001
@@ -437,6 +437,7 @@
 static struct net_device dev_ultra[MAX_ULTRAMCA_CARDS];
 static int io[MAX_ULTRAMCA_CARDS];
 static int irq[MAX_ULTRAMCA_CARDS];
+MODULE_LICENSE("GPL");
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c
--- v2.4.12/linux/drivers/net/smc9194.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/net/smc9194.c	Tue Oct 16 21:56:29 2001
@@ -1558,6 +1558,7 @@
 static int io;
 static int irq;
 static int ifport;
+MODULE_LICENSE("GPL");
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/stnic.c linux/drivers/net/stnic.c
--- v2.4.12/linux/drivers/net/stnic.c	Wed Jul 25 17:10:22 2001
+++ linux/drivers/net/stnic.c	Tue Oct 16 21:56:29 2001
@@ -316,3 +316,4 @@
 
 module_init(stnic_probe);
 /* No cleanup routine. */
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/sun3lance.c linux/drivers/net/sun3lance.c
--- v2.4.12/linux/drivers/net/sun3lance.c	Wed Jul 25 17:10:22 2001
+++ linux/drivers/net/sun3lance.c	Tue Oct 16 21:56:29 2001
@@ -71,6 +71,7 @@
 #endif
 MODULE_PARM(lance_debug, "i");
 MODULE_PARM_DESC(lance_debug, "SUN3 Lance debug level (0-3)");
+MODULE_LICENSE("GPL");
 
 #define	DPRINTK(n,a) \
 	do {  \
diff -u --recursive --new-file v2.4.12/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c
--- v2.4.12/linux/drivers/net/sunbmac.c	Thu Apr 26 22:17:25 2001
+++ linux/drivers/net/sunbmac.c	Fri Oct 19 08:32:28 2001
@@ -1301,3 +1301,4 @@
 
 module_init(bigmac_probe);
 module_exit(bigmac_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/sundance.c linux/drivers/net/sundance.c
--- v2.4.12/linux/drivers/net/sundance.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/sundance.c	Fri Oct 19 08:32:28 2001
@@ -25,10 +25,9 @@
 
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
-
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
+static int max_interrupt_work = 30;
 static int mtu;
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
    Typical is a 64 element hash table based on the Ethernet CRC.  */
@@ -40,15 +39,20 @@
    need a copy-align. */
 static int rx_copybreak;
 
-/* Used to pass the media type, etc.
-   Both 'options[]' and 'full_duplex[]' should exist for driver
-   interoperability.
-   The media type is usually passed in 'options[]'.
+/* media[] specifies the media type the NIC operates at.
+		 autosense	Autosensing active media.
+		 10mbps_hd 	10Mbps half duplex.
+		 10mbps_fd 	10Mbps full duplex.
+		 100mbps_hd 	100Mbps half duplex.
+		 100mbps_fd 	100Mbps full duplex.
+		 0		Autosensing active media.
+		 1	 	10Mbps half duplex.
+		 2	 	10Mbps full duplex.
+		 3	 	100Mbps half duplex.
+		 4	 	100Mbps full duplex.
 */
-#define MAX_UNITS 8		/* More are supported, limit only on options */
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
+#define MAX_UNITS 8	
+static char *media[MAX_UNITS];
 /* Operational parameters that are set at compile time. */
 
 /* Keep the ring sizes a power of two for compile efficiency.
@@ -65,7 +69,7 @@
 
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (2*HZ)
+#define TX_TIMEOUT  (4*HZ)
 
 #define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
 
@@ -98,7 +102,7 @@
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
-
+#include <linux/delay.h>
 #include <linux/spinlock.h>
 
 /* These identify the driver base version and may not be removed. */
@@ -114,15 +118,11 @@
 MODULE_PARM(mtu, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s");
 MODULE_PARM_DESC(max_interrupt_work, "Sundance Alta maximum events handled per interrupt");
 MODULE_PARM_DESC(mtu, "Sundance Alta MTU (all boards)");
 MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)");
 MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(options, "Sundance Alta: Bits 0-3: media type, bit 17: full duplex");
-MODULE_PARM_DESC(full_duplex, "Sundance Alta full duplex setting(s) (1)");
-
 /*
 				Theory of Operation
 
@@ -214,9 +214,12 @@
 #endif
 
 static struct pci_device_id sundance_pci_tbl[] __devinitdata = {
-	{ 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-	{ 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
-	{ 0, }
+	{0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0},
+	{0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1},
+	{0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2},
+	{0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{0,}
 };
 MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
 
@@ -231,11 +234,19 @@
         int drv_flags;                          /* Driver use, intended as capability flags. */
 };
 static struct pci_id_info pci_id_tbl[] = {
-	{"OEM Sundance Technology ST201", {0x10021186, 0xffffffff, },
+	{"D-Link DFE-550TX FAST Ethernet Adapter", {0x10021186, 0xffffffff,},
 	 PCI_IOTYPE, 128, CanHaveMII},
-	{"Sundance Technology Alta", {0x020113F0, 0xffffffff, },
+	{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter",
+	 {0x10031186, 0xffffffff,},
 	 PCI_IOTYPE, 128, CanHaveMII},
-	{0,},						/* 0 terminated list. */
+	{"D-Link DFE-580TX 4 port Server Adapter", {0x10121186, 0xffffffff,},
+	 PCI_IOTYPE, 128, CanHaveMII},
+	{"D-Link DL10050-based FAST Ethernet Adapter",
+	 {0x10021186, 0xffffffff,},
+	 PCI_IOTYPE, 128, CanHaveMII},
+	{"Sundance Technology Alta", {0x020113F0, 0xffffffff,},
+	 PCI_IOTYPE, 128, CanHaveMII},
+	{0,},			/* 0 terminated list. */
 };
 
 /* This driver was written to use PCI memory space, however x86-oriented
@@ -384,9 +395,10 @@
 	unsigned int tx_full:1;				/* The Tx queue is full. */
 	/* These values are keep track of the transceiver/media in use. */
 	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
-	unsigned int duplex_lock:1;
 	unsigned int medialock:1;			/* Do not sense media. */
 	unsigned int default_port:4;		/* Last dev->if_port value. */
+	unsigned int an_enable:1;
+	unsigned int speed;
 	/* Multicast and receive mode. */
 	spinlock_t mcastlock;				/* SMP lock multicast updates. */
 	u16 mcast_filter[4];
@@ -428,8 +440,9 @@
 	static int card_idx;
 	int chip_idx = ent->driver_data;
 	int irq;
-	int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+	int i;
 	long ioaddr;
+	u16 mii_reg0;
 	void *ring_space;
 	dma_addr_t ring_dma;
 
@@ -489,23 +502,6 @@
 	np->rx_ring = (struct netdev_desc *)ring_space;
 	np->rx_ring_dma = ring_dma;
 
-	if (dev->mem_start)
-		option = dev->mem_start;
-
-	/* The lower four bits are the media type. */
-	if (option > 0) {
-		if (option & 0x200)
-			np->full_duplex = 1;
-		np->default_port = option & 15;
-		if (np->default_port)
-			np->medialock = 1;
-	}
-	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
-		np->full_duplex = 1;
-
-	if (np->full_duplex)
-		np->duplex_lock = 1;
-
 	/* The chip-specific entries in the device structure. */
 	dev->open = &netdev_open;
 	dev->hard_start_xmit = &start_tx;
@@ -548,6 +544,56 @@
 			printk(KERN_INFO "%s: No MII transceiver found!, ASIC status %x\n",
 				   dev->name, readl(ioaddr + ASICCtrl));
 	}
+	/* Parse override configuration */
+	np->an_enable = 1;
+	if (card_idx < MAX_UNITS) {
+		if (media[card_idx] != NULL) {
+			np->an_enable = 0;
+			if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
+			    strcmp (media[card_idx], "4") == 0) {
+				np->speed = 100;
+				np->full_duplex = 1;
+			} else if (strcmp (media[card_idx], "100mbps_hd") == 0
+				   || strcmp (media[card_idx], "3") == 0) {
+				np->speed = 100;
+				np->full_duplex = 0;
+			} else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
+				   strcmp (media[card_idx], "2") == 0) {
+				np->speed = 10;
+				np->full_duplex = 1;
+			} else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
+				   strcmp (media[card_idx], "1") == 0) {
+				np->speed = 10;
+				np->full_duplex = 0;
+			} else {
+				np->an_enable = 1;
+			}
+		}
+	}
+
+	/* Fibre PHY? */
+	if (readl (ioaddr + ASICCtrl) & 0x80) {
+		/* Default 100Mbps Full */
+		if (np->an_enable) {
+			np->speed = 100;
+			np->full_duplex = 1;
+			np->an_enable = 0;
+		}
+	}
+	/* Reset PHY */
+	mdio_write (dev, np->phys[0], 0, 0x8000);
+	mdelay (300);
+	mdio_write (dev, np->phys[0], 0, 0x1200);
+	/* Force media type */
+	if (!np->an_enable) {
+		mii_reg0 = 0;
+		mii_reg0 |= (np->speed == 100) ? 0x2000 : 0;
+		mii_reg0 |= (np->full_duplex) ? 0x0100 : 0;
+		mdio_write (dev, np->phys[0], 0, mii_reg0);
+		printk (KERN_INFO "Override speed=%d, %s duplex\n",
+			np->speed, np->full_duplex ? "Full" : "Half");
+
+	}
 
 	/* Perhaps move the reset here? */
 	/* Reset the chip to erase previous misconfiguration. */
@@ -714,7 +760,6 @@
 	if (dev->if_port == 0)
 		dev->if_port = np->default_port;
 
-	np->full_duplex = np->duplex_lock;
 	np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED;
 
 	set_rx_mode(dev);
@@ -755,9 +800,15 @@
 	int mii_reg5 = mdio_read(dev, np->phys[0], 5);
 	int negotiated = mii_reg5 & np->advertising;
 	int duplex;
-
-	if (np->duplex_lock  ||  mii_reg5 == 0xffff)
+	
+	/* Force media */
+	if (!np->an_enable || mii_reg5 == 0xffff) {
+		if (np->full_duplex)
+			writew (readw (ioaddr + MACCtrl0) | EnbFullDuplex,
+				ioaddr + MACCtrl0);
 		return;
+	}
+	/* Autonegotiation */
 	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
 	if (np->full_duplex != duplex) {
 		np->full_duplex = duplex;
@@ -1003,10 +1054,10 @@
 		/* Abnormal error summary/uncommon events handlers. */
 		if (intr_status & (IntrDrvRqst | IntrPCIErr | LinkChange | StatsMax))
 			netdev_error(dev, intr_status);
-
 		if (--boguscnt < 0) {
 			get_stats(dev);
-			printk(KERN_WARNING "%s: Too much work at interrupt, "
+			if (debug > 1) 
+				printk(KERN_WARNING "%s: Too much work at interrupt, "
 				   "status=0x%4.4x / 0x%4.4x.\n",
 				   dev->name, intr_status, readw(ioaddr + IntrClear));
 			/* Re-enable us in 3.2msec. */
@@ -1132,21 +1183,46 @@
 {
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = dev->priv;
+	u16 mii_reg0, mii_reg4, mii_reg5;
+	int speed;
 
 	if (intr_status & IntrDrvRqst) {
 		/* Stop the down counter and turn interrupts back on. */
-		printk("%s: Turning interrupts back on.\n", dev->name);
+		if (debug > 1)
+			printk("%s: Turning interrupts back on.\n", dev->name);
 		writew(0, ioaddr + IntrEnable);
 		writew(0, ioaddr + DownCounter);
 		writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst |
 			   IntrTxDone | StatsMax | LinkChange, ioaddr + IntrEnable);
+		/* Ack buggy InRequest */
+		writew (IntrDrvRqst, ioaddr + IntrStatus);
 	}
 	if (intr_status & LinkChange) {
-		printk(KERN_ERR "%s: Link changed: Autonegotiation advertising"
-			   " %4.4x  partner %4.4x.\n", dev->name,
-			   mdio_read(dev, np->phys[0], 4),
-			   mdio_read(dev, np->phys[0], 5));
-		check_duplex(dev);
+		if (np->an_enable) {
+			mii_reg4 = mdio_read (dev, np->phys[0], 4);
+			mii_reg5= mdio_read (dev, np->phys[0], 5);
+			mii_reg4 &= mii_reg5;
+			printk (KERN_INFO "%s: Link changed: ", dev->name);
+			if (mii_reg4 & 0x0100)
+				printk ("100Mbps, full duplex\n");
+			else if (mii_reg4 & 0x0080)
+				printk ("100Mbps, half duplex\n");
+			else if (mii_reg4 & 0x0040)
+				printk ("10Mbps, full duplex\n");
+			else if (mii_reg4 & 0x0020)
+				printk ("10Mbps, half duplex\n");
+			else
+				printk ("\n");
+
+		} else {
+			mii_reg0 = mdio_read (dev, np->phys[0], 0);
+			speed = (mii_reg0 & 0x2000) ? 100 : 10;
+			printk (KERN_INFO "%s: Link changed: %dMbps ,",
+				dev->name, speed);
+			printk ("%s duplex.\n", (mii_reg0 & 0x0100) ?
+				"full" : "half");
+		}
+		check_duplex (dev);
 	}
 	if (intr_status & StatsMax) {
 		get_stats(dev);
diff -u --recursive --new-file v2.4.12/linux/drivers/net/sungem.c linux/drivers/net/sungem.c
--- v2.4.12/linux/drivers/net/sungem.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/sungem.c	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: sungem.c,v 1.20 2001/09/19 00:04:32 davem Exp $
+/* $Id: sungem.c,v 1.30 2001/10/17 06:55:10 davem Exp $
  * sungem.c: Sun GEM ethernet driver.
  *
  * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
@@ -36,15 +36,17 @@
 #include <asm/pbm.h>
 #endif
 
-#ifdef __powerpc__
+#ifdef CONFIG_ALL_PPC
 #include <asm/pci-bridge.h>
 #include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
 #endif
 
 #include "sungem.h"
 
 static char version[] __devinitdata =
-        "sungem.c:v0.75 21/Mar/01 David S. Miller (davem@redhat.com)\n";
+        "sungem.c:v0.95 16/Oct/01 David S. Miller (davem@redhat.com)\n";
 
 MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
 MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver");
@@ -69,6 +71,9 @@
 	/* These models only differ from the original GEM in
 	 * that their tx/rx fifos are of a different size and
 	 * they only support 10/100 speeds. -DaveM
+	 * 
+	 * Apple's GMAC does support gigabit on machines with
+	 * the BCM5400 or 5401 PHYs. -BenH
 	 */
 	{ PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_GEM,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
@@ -79,14 +84,14 @@
 
 MODULE_DEVICE_TABLE(pci, gem_pci_tbl);
 
-static u16 phy_read(struct gem *gp, int reg)
+static u16 __phy_read(struct gem *gp, int reg, int phy_addr)
 {
 	u32 cmd;
 	int limit = 10000;
 
 	cmd  = (1 << 30);
 	cmd |= (2 << 28);
-	cmd |= (gp->mii_phy_addr << 23) & MIF_FRAME_PHYAD;
+	cmd |= (phy_addr << 23) & MIF_FRAME_PHYAD;
 	cmd |= (reg << 18) & MIF_FRAME_REGAD;
 	cmd |= (MIF_FRAME_TAMSB);
 	writel(cmd, gp->regs + MIF_FRAME);
@@ -105,14 +110,19 @@
 	return cmd & MIF_FRAME_DATA;
 }
 
-static void phy_write(struct gem *gp, int reg, u16 val)
+static inline u16 phy_read(struct gem *gp, int reg)
+{
+	return __phy_read(gp, reg, gp->mii_phy_addr);
+}
+
+static void __phy_write(struct gem *gp, int reg, u16 val, int phy_addr)
 {
 	u32 cmd;
 	int limit = 10000;
 
 	cmd  = (1 << 30);
 	cmd |= (1 << 28);
-	cmd |= (gp->mii_phy_addr << 23) & MIF_FRAME_PHYAD;
+	cmd |= (phy_addr << 23) & MIF_FRAME_PHYAD;
 	cmd |= (reg << 18) & MIF_FRAME_REGAD;
 	cmd |= (MIF_FRAME_TAMSB);
 	cmd |= (val & MIF_FRAME_DATA);
@@ -127,6 +137,11 @@
 	}
 }
 
+static inline void phy_write(struct gem *gp, int reg, u16 val)
+{
+	__phy_write(gp, reg, val, gp->mii_phy_addr);
+}
+
 static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits)
 {
 }
@@ -418,7 +433,8 @@
 	while (entry != limit) {
 		struct sk_buff *skb;
 		struct gem_txd *txd;
-		u32 dma_addr, dma_len;
+		dma_addr_t dma_addr;
+		u32 dma_len;
 		int frag;
 
 		skb = gp->tx_skbs[entry];
@@ -444,10 +460,10 @@
 		for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
 			txd = &gp->init_block->txd[entry];
 
-			dma_addr = (u32) le64_to_cpu(txd->buffer);
+			dma_addr = le64_to_cpu(txd->buffer);
 			dma_len = le64_to_cpu(txd->control_word) & TXDCTRL_BUFSZ;
 
-			pci_unmap_single(gp->pdev, dma_addr, dma_len, PCI_DMA_TODEVICE);
+			pci_unmap_page(gp->pdev, dma_addr, dma_len, PCI_DMA_TODEVICE);
 			entry = NEXT_TX(entry);
 		}
 
@@ -498,7 +514,7 @@
 		struct gem_rxd *rxd = &gp->init_block->rxd[entry];
 		struct sk_buff *skb;
 		u64 status = cpu_to_le64(rxd->status_word);
-		u32 dma_addr;
+		dma_addr_t dma_addr;
 		int len;
 
 		if ((status & RXDCTRL_OWN) != 0)
@@ -520,7 +536,7 @@
 			goto next;
 		}
 
-		dma_addr = (u32) cpu_to_le64(rxd->buffer);
+		dma_addr = cpu_to_le64(rxd->buffer);
 		if (len > RX_COPY_THRESHOLD) {
 			struct sk_buff *new_skb;
 
@@ -529,15 +545,18 @@
 				drops++;
 				goto drop_it;
 			}
-			pci_unmap_single(gp->pdev, dma_addr,
-					 RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE);
+			pci_unmap_page(gp->pdev, dma_addr,
+				       RX_BUF_ALLOC_SIZE(gp),
+				       PCI_DMA_FROMDEVICE);
 			gp->rx_skbs[entry] = new_skb;
 			new_skb->dev = gp->dev;
 			skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET));
-			rxd->buffer = cpu_to_le64(pci_map_single(gp->pdev,
-								 new_skb->data,
-								 RX_BUF_ALLOC_SIZE(gp),
-								 PCI_DMA_FROMDEVICE));
+			rxd->buffer = cpu_to_le64(pci_map_page(gp->pdev,
+							       virt_to_page(new_skb->data),
+							       ((unsigned long) new_skb->data &
+								~PAGE_MASK),
+							       RX_BUF_ALLOC_SIZE(gp),
+							       PCI_DMA_FROMDEVICE));
 			skb_reserve(new_skb, RX_OFFSET);
 
 			/* Trim the original skb for the netif. */
@@ -661,37 +680,45 @@
 
 	if (skb_shinfo(skb)->nr_frags == 0) {
 		struct gem_txd *txd = &gp->init_block->txd[entry];
-		u32 mapping, len;
+		dma_addr_t mapping;
+		u32 len;
 
 		len = skb->len;
-		mapping = pci_map_single(gp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+		mapping = pci_map_page(gp->pdev,
+				       virt_to_page(skb->data),
+				       ((unsigned long) skb->data &
+					~PAGE_MASK),
+				       len, PCI_DMA_TODEVICE);
 		ctrl |= TXDCTRL_SOF | TXDCTRL_EOF | len;
 		txd->buffer = cpu_to_le64(mapping);
 		txd->control_word = cpu_to_le64(ctrl);
 		entry = NEXT_TX(entry);
 	} else {
 		struct gem_txd *txd;
-		u32 first_len, first_mapping;
+		u32 first_len;
+		dma_addr_t first_mapping;
 		int frag, first_entry = entry;
 
 		/* We must give this initial chunk to the device last.
 		 * Otherwise we could race with the device.
 		 */
 		first_len = skb->len - skb->data_len;
-		first_mapping = pci_map_single(gp->pdev, skb->data,
-					       first_len, PCI_DMA_TODEVICE);
+		first_mapping = pci_map_page(gp->pdev, virt_to_page(skb->data),
+					     ((unsigned long) skb->data & ~PAGE_MASK),
+					     first_len, PCI_DMA_TODEVICE);
 		entry = NEXT_TX(entry);
 
 		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
 			skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
-			u32 len, mapping;
+			u32 len;
+			dma_addr_t mapping;
 			u64 this_ctrl;
 
 			len = this_frag->size;
-			mapping = pci_map_single(gp->pdev,
-						 ((void *) page_address(this_frag->page) +
-						  this_frag->page_offset),
-						 len, PCI_DMA_TODEVICE);
+			mapping = pci_map_page(gp->pdev,
+					       this_frag->page,
+					       this_frag->page_offset,
+					       len, PCI_DMA_TODEVICE);
 			this_ctrl = ctrl;
 			if (frag == skb_shinfo(skb)->nr_frags - 1)
 				this_ctrl |= TXDCTRL_EOF;
@@ -750,6 +777,10 @@
 	int limit;
 	u32 val;
 
+	/* Make sure we won't get any more interrupts */
+	writel(0xffffffff, gp->regs + GREG_IMASK);
+
+	/* Reset the chip */
 	writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, regs + GREG_SWRST);
 
 	limit = STOP_TRIES;
@@ -765,24 +796,73 @@
 		printk(KERN_ERR "gem: SW reset is ghetto.\n");
 }
 
+static void gem_start_dma(struct gem *gp)
+{
+	unsigned long val;
+	
+	/* We are ready to rock, turn everything on. */
+	val = readl(gp->regs + TXDMA_CFG);
+	writel(val | TXDMA_CFG_ENABLE, gp->regs + TXDMA_CFG);
+	val = readl(gp->regs + RXDMA_CFG);
+	writel(val | RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG);
+	val = readl(gp->regs + MAC_TXCFG);
+	writel(val | MAC_TXCFG_ENAB, gp->regs + MAC_TXCFG);
+	val = readl(gp->regs + MAC_RXCFG);
+	writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
+
+	writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK);
+
+	writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
+
+}
+
+/* Link modes of the BCM5400 PHY */
+static int phy_BCM5400_link_table[8][3] = {
+	{ 0, 0, 0 },	/* No link */
+	{ 0, 0, 0 },	/* 10BT Half Duplex */
+	{ 1, 0, 0 },	/* 10BT Full Duplex */
+	{ 0, 1, 0 },	/* 100BT Half Duplex */
+	{ 0, 1, 0 },	/* 100BT Half Duplex */
+	{ 1, 1, 0 },	/* 100BT Full Duplex*/
+	{ 1, 0, 1 },	/* 1000BT */
+	{ 1, 0, 1 },	/* 1000BT */
+};
+
 /* A link-up condition has occurred, initialize and enable the
  * rest of the chip.
  */
 static void gem_set_link_modes(struct gem *gp)
 {
 	u32 val;
-	int full_duplex, speed;
+	int full_duplex, speed, pause;
 
 	full_duplex = 0;
 	speed = 10;
+	pause = 0;
+
 	if (gp->phy_type == phy_mii_mdio0 ||
 	    gp->phy_type == phy_mii_mdio1) {
 		if (gp->lstate == aneg_wait) {
-			val = phy_read(gp, PHY_LPA);
-			if (val & (PHY_LPA_10FULL | PHY_LPA_100FULL))
-				full_duplex = 1;
-			if (val & (PHY_LPA_100FULL | PHY_LPA_100HALF))
-				speed = 100;
+			if (gp->phy_mod == phymod_bcm5400 ||
+			    gp->phy_mod == phymod_bcm5401 ||
+			    gp->phy_mod == phymod_bcm5411) {
+				int link_mode;	
+		    		val = phy_read(gp, PHY_BCM5400_AUXSTATUS);
+		    		link_mode = (val & PHY_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
+		    			PHY_BCM5400_AUXSTATUS_LINKMODE_SHIFT;
+		    		full_duplex = phy_BCM5400_link_table[link_mode][0];
+		    		speed = phy_BCM5400_link_table[link_mode][2] ? 1000
+		    			: (phy_BCM5400_link_table[link_mode][1] ? 100 : 10);
+					val = phy_read(gp, PHY_LPA);
+					if (val & PHY_LPA_PAUSE)
+						pause = 1;	
+			} else {
+				val = phy_read(gp, PHY_LPA);
+				if (val & (PHY_LPA_10FULL | PHY_LPA_100FULL))
+					full_duplex = 1;
+				if (val & (PHY_LPA_100FULL | PHY_LPA_100HALF))
+					speed = 100;
+			}
 		} else {
 			val = phy_read(gp, PHY_CTRL);
 			if (val & PHY_CTRL_FDPLX)
@@ -842,33 +922,24 @@
 
 	if (gp->phy_type == phy_serialink ||
 	    gp->phy_type == phy_serdes) {
-		u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
+ 		u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
 
-		val = readl(gp->regs + MAC_MCCFG);
 		if (pcs_lpa & (PCS_MIIADV_SP | PCS_MIIADV_AP))
-			val |= (MAC_MCCFG_SPE | MAC_MCCFG_RPE);
-		else
-			val &= ~(MAC_MCCFG_SPE | MAC_MCCFG_RPE);
-		writel(val, gp->regs + MAC_MCCFG);
+			pause = 1;
+	}
 
-		if (!full_duplex)
-			writel(512, gp->regs + MAC_STIME);
-		else
-			writel(64, gp->regs + MAC_STIME);
-	} else {
-		/* Set slot-time of 64. */
+	if (!full_duplex)
+		writel(512, gp->regs + MAC_STIME);
+	else
 		writel(64, gp->regs + MAC_STIME);
-	}
+	val = readl(gp->regs + MAC_MCCFG);
+	if (pause)
+		val |= (MAC_MCCFG_SPE | MAC_MCCFG_RPE);
+	else
+		val &= ~(MAC_MCCFG_SPE | MAC_MCCFG_RPE);
+	writel(val, gp->regs + MAC_MCCFG);
 
-	/* We are ready to rock, turn everything on. */
-	val = readl(gp->regs + TXDMA_CFG);
-	writel(val | TXDMA_CFG_ENABLE, gp->regs + TXDMA_CFG);
-	val = readl(gp->regs + RXDMA_CFG);
-	writel(val | RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG);
-	val = readl(gp->regs + MAC_TXCFG);
-	writel(val | MAC_TXCFG_ENAB, gp->regs + MAC_TXCFG);
-	val = readl(gp->regs + MAC_RXCFG);
-	writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
+	gem_start_dma(gp);
 }
 
 static int gem_mdio_link_not_up(struct gem *gp)
@@ -948,19 +1019,18 @@
 	struct gem_init_block *gb = gp->init_block;
 	struct sk_buff *skb;
 	int i;
-	u32 dma_addr;
+	dma_addr_t dma_addr;
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct gem_rxd *rxd;
 
 		rxd = &gb->rxd[i];
 		if (gp->rx_skbs[i] != NULL) {
-
 			skb = gp->rx_skbs[i];
-			dma_addr = (u32) le64_to_cpu(rxd->buffer);
-			pci_unmap_single(gp->pdev, dma_addr,
-					 RX_BUF_ALLOC_SIZE(gp),
-					 PCI_DMA_FROMDEVICE);
+			dma_addr = le64_to_cpu(rxd->buffer);
+			pci_unmap_page(gp->pdev, dma_addr,
+				       RX_BUF_ALLOC_SIZE(gp),
+				       PCI_DMA_FROMDEVICE);
 			dev_kfree_skb_any(skb);
 			gp->rx_skbs[i] = NULL;
 		}
@@ -978,10 +1048,10 @@
 
 			for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
 				txd = &gb->txd[i];
-				dma_addr = (u32) le64_to_cpu(txd->buffer);
-				pci_unmap_single(gp->pdev, dma_addr,
-						 le64_to_cpu(txd->control_word) &
-						 TXDCTRL_BUFSZ, PCI_DMA_TODEVICE);
+				dma_addr = le64_to_cpu(txd->buffer);
+				pci_unmap_page(gp->pdev, dma_addr,
+					       le64_to_cpu(txd->control_word) &
+					       TXDCTRL_BUFSZ, PCI_DMA_TODEVICE);
 
 				if (frag != skb_shinfo(skb)->nr_frags)
 					i++;
@@ -996,7 +1066,7 @@
 	struct gem_init_block *gb = gp->init_block;
 	struct net_device *dev = gp->dev;
 	int i, gfp_flags = GFP_KERNEL;
-	u32 dma_addr;
+	dma_addr_t dma_addr;
 
 	if (from_irq)
 		gfp_flags = GFP_ATOMIC;
@@ -1019,9 +1089,12 @@
 		gp->rx_skbs[i] = skb;
 		skb->dev = dev;
 		skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET));
-		dma_addr = pci_map_single(gp->pdev, skb->data,
-					  RX_BUF_ALLOC_SIZE(gp),
-					  PCI_DMA_FROMDEVICE);
+		dma_addr = pci_map_page(gp->pdev,
+					virt_to_page(skb->data),
+					((unsigned long) skb->data &
+					 ~PAGE_MASK),
+					RX_BUF_ALLOC_SIZE(gp),
+					PCI_DMA_FROMDEVICE);
 		rxd->buffer = cpu_to_le64(dma_addr);
 		rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp));
 		skb_reserve(skb, RX_OFFSET);
@@ -1035,8 +1108,150 @@
 	}
 }
 
+static int
+gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
+{
+	u16 val;
+	int limit = 10000;
+	
+	val = __phy_read(gp, PHY_CTRL, phy_addr);
+	val &= ~PHY_CTRL_ISO;
+	val |= PHY_CTRL_RST;
+	__phy_write(gp, PHY_CTRL, val, phy_addr);
+
+	udelay(100);
+
+	while (limit--) {
+		val = __phy_read(gp, PHY_CTRL, phy_addr);
+		if ((val & PHY_CTRL_RST) == 0)
+			break;
+		udelay(10);
+	}
+	if ((val & PHY_CTRL_ISO) && limit > 0)
+		__phy_write(gp, PHY_CTRL, val & ~PHY_CTRL_ISO, phy_addr);
+	
+	return (limit <= 0);
+}
+
+static void
+gem_init_bcm5400_phy(struct gem *gp)
+{
+	u16 data;
+
+	/* Configure for gigabit full duplex */
+	data = phy_read(gp, PHY_BCM5400_AUXCONTROL);
+	data |= PHY_BCM5400_AUXCONTROL_PWR10BASET;
+	phy_write(gp, PHY_BCM5400_AUXCONTROL, data);
+	
+	data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
+	data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+	
+	mdelay(10);
+
+	/* Reset and configure cascaded 10/100 PHY */
+	gem_reset_one_mii_phy(gp, 0x1f);
+	
+	data = __phy_read(gp, PHY_BCM5201_MULTIPHY, 0x1f);
+	data |= PHY_BCM5201_MULTIPHY_SERIALMODE;
+	__phy_write(gp, PHY_BCM5201_MULTIPHY, data, 0x1f);
+
+	data = phy_read(gp, PHY_BCM5400_AUXCONTROL);
+	data &= ~PHY_BCM5400_AUXCONTROL_PWR10BASET;
+	phy_write(gp, PHY_BCM5400_AUXCONTROL, data);
+}
+
+static void
+gem_init_bcm5401_phy(struct gem *gp)
+{
+	u16 data;
+	int rev;
+
+	rev = phy_read(gp, PHY_ID1) & 0x000f;
+	if (rev == 0 || rev == 3) {
+		/* Some revisions of 5401 appear to need this
+		 * initialisation sequence to disable, according
+		 * to OF, "tap power management"
+		 * 
+		 * WARNING ! OF and Darwin don't agree on the
+		 * register addresses. OF seem to interpret the
+		 * register numbers below as decimal
+		 */
+		phy_write(gp, 0x18, 0x0c20);
+		phy_write(gp, 0x17, 0x0012);
+		phy_write(gp, 0x15, 0x1804);
+		phy_write(gp, 0x17, 0x0013);
+		phy_write(gp, 0x15, 0x1204);
+		phy_write(gp, 0x17, 0x8006);
+		phy_write(gp, 0x15, 0x0132);
+		phy_write(gp, 0x17, 0x8006);
+		phy_write(gp, 0x15, 0x0232);
+		phy_write(gp, 0x17, 0x201f);
+		phy_write(gp, 0x15, 0x0a20);
+	}
+	
+	/* Configure for gigabit full duplex */
+	data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
+	data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+
+	mdelay(1);
+
+	/* Reset and configure cascaded 10/100 PHY */
+	gem_reset_one_mii_phy(gp, 0x1f);
+	
+	data = __phy_read(gp, PHY_BCM5201_MULTIPHY, 0x1f);
+	data |= PHY_BCM5201_MULTIPHY_SERIALMODE;
+	__phy_write(gp, PHY_BCM5201_MULTIPHY, data, 0x1f);
+}
+
+static void
+gem_init_bcm5411_phy(struct gem *gp)
+{
+	u16 data;
+
+	/* Here's some more Apple black magic to setup
+	 * some voltage stuffs.
+	 */
+	phy_write(gp, 0x1c, 0x8c23);
+	phy_write(gp, 0x1c, 0x8ca3);
+	phy_write(gp, 0x1c, 0x8c23);
+
+	/* Here, Apple seems to want to reset it, do
+	 * it as well
+	 */
+	phy_write(gp, PHY_CTRL, PHY_CTRL_RST);
+
+	/* Start autoneg */
+	phy_write(gp, PHY_CTRL,
+		  (PHY_CTRL_ANENAB | PHY_CTRL_FDPLX |
+		   PHY_CTRL_ANRES | PHY_CTRL_SPD2));
+
+	data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
+	data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+}
+
 static void gem_init_phy(struct gem *gp)
 {
+#ifdef CONFIG_ALL_PPC
+	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
+		int i;
+
+		pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0);
+		for (i = 0; i < 32; i++) {
+			gp->mii_phy_addr = i;
+			if (phy_read(gp, PHY_CTRL) != 0xffff)
+				break;
+		}
+		if (i == 32) {
+			printk(KERN_WARNING "%s: GMAC PHY not responding !\n",
+			       gp->dev->name);
+			return;
+		}
+	}
+#endif /* CONFIG_ALL_PPC */
+
 	if (gp->pdev->vendor == PCI_VENDOR_ID_SUN &&
 	    gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) {
 		u32 val;
@@ -1056,27 +1271,59 @@
 
 	if (gp->phy_type == phy_mii_mdio0 ||
 	    gp->phy_type == phy_mii_mdio1) {
-		u16 val = phy_read(gp, PHY_CTRL);
-		int limit = 10000;
-
+		u32 phy_id;
+		u16 val;
+	
 		/* Take PHY out of isloate mode and reset it. */
-		val &= ~PHY_CTRL_ISO;
-		val |= PHY_CTRL_RST;
-		phy_write(gp, PHY_CTRL, val);
+		gem_reset_one_mii_phy(gp, gp->mii_phy_addr);
 
-		while (limit--) {
-			val = phy_read(gp, PHY_CTRL);
-			if ((val & PHY_CTRL_RST) == 0)
+		phy_id = (phy_read(gp, PHY_ID0) << 16 | phy_read(gp, PHY_ID1))
+			 	& 0xfffffff0;
+		printk(KERN_INFO "%s: MII PHY ID: %x ", gp->dev->name, phy_id);
+		switch(phy_id) {
+			case 0x406210:
+				gp->phy_mod = phymod_bcm5201;
+				printk("BCM 5201\n");
 				break;
-			udelay(10);
-		}
+			case 0x4061e0:
+				printk("BCM 5221\n");
+				gp->phy_mod = phymod_bcm5221;
+				break;
+			case 0x206040:
+				printk("BCM 5400\n");
+				gp->phy_mod = phymod_bcm5400;
+				gem_init_bcm5400_phy(gp);
+				break;
+			case 0x206050:
+				printk("BCM 5401\n");
+				gp->phy_mod = phymod_bcm5401;
+				gem_init_bcm5401_phy(gp);
+				break;
+			case 0x206070:
+				printk("BCM 5411\n");
+				gp->phy_mod = phymod_bcm5411;
+				gem_init_bcm5411_phy(gp);
+				break;
+			default:
+				printk("Generic\n");
+				gp->phy_mod = phymod_generic;
+		};
 
 		/* Init advertisement and enable autonegotiation. */
+		val = phy_read(gp, PHY_CTRL);
+		val &= ~PHY_CTRL_ANENAB;
+		phy_write(gp, PHY_CTRL, val);
+		udelay(10);
+		
 		phy_write(gp, PHY_ADV,
+			  phy_read(gp, PHY_ADV) |
 			  (PHY_ADV_10HALF | PHY_ADV_10FULL |
 			   PHY_ADV_100HALF | PHY_ADV_100FULL));
 
-		val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB);
+		val = phy_read(gp, PHY_CTRL);
+		val |= PHY_CTRL_ANENAB;
+		phy_write(gp, PHY_CTRL, val);
+		val |= PHY_CTRL_ANRES;
 		phy_write(gp, PHY_CTRL, val);
 	} else {
 		u32 val;
@@ -1137,13 +1384,15 @@
 
 static void gem_init_dma(struct gem *gp)
 {
+	u64 desc_dma = (u64) gp->gblock_dvma;
 	u32 val;
 
 	val = (TXDMA_CFG_BASE | (0x7ff << 10) | TXDMA_CFG_PMODE);
 	writel(val, gp->regs + TXDMA_CFG);
 
-	writel(0, gp->regs + TXDMA_DBHI);
-	writel(gp->gblock_dvma, gp->regs + TXDMA_DBLOW);
+	writel(desc_dma >> 32, gp->regs + TXDMA_DBHI);
+	writel(desc_dma & 0xffffffff, gp->regs + TXDMA_DBLOW);
+	desc_dma += (TX_RING_SIZE * sizeof(struct gem_txd));
 
 	writel(0, gp->regs + TXDMA_KICK);
 
@@ -1151,10 +1400,8 @@
 	       ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_512);
 	writel(val, gp->regs + RXDMA_CFG);
 
-	writel(0, gp->regs + RXDMA_DBHI);
-	writel((gp->gblock_dvma +
-		(TX_RING_SIZE * sizeof(struct gem_txd))),
-	       gp->regs + RXDMA_DBLOW);
+	writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
+	writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW);
 
 	writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
 
@@ -1314,20 +1561,186 @@
 	writel(0, gp->regs + MAC_MCMASK);
 }
 
+static void
+gem_init_pause_thresholds(struct gem* gp)
+{
+	/* Calculate pause thresholds.  Setting the OFF threshold to the
+	 * full RX fifo size effectively disables PAUSE generation which
+	 * is what we do for 10/100 only GEMs which have FIFOs too small
+	 * to make real gains from PAUSE.
+	 */
+	if (gp->rx_fifo_sz <= (2 * 1024)) {
+		gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz;
+	} else {
+		int off = (gp->rx_fifo_sz - (5 * 1024));
+		int on = off - 1024;
+
+		gp->rx_pause_off = off;
+		gp->rx_pause_on = on;
+	}
+
+	{
+		u32 cfg = readl(gp->regs + GREG_BIFCFG);
+
+		/* XXX Why do I do this? -DaveM XXX */
+		cfg |= GREG_BIFCFG_B64DIS;
+		writel(cfg, gp->regs + GREG_BIFCFG);
+
+		cfg  = GREG_CFG_IBURST;
+		cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
+		cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
+		writel(cfg, gp->regs + GREG_CFG);
+	}
+}
+
+static int gem_check_invariants(struct gem *gp)
+{
+	struct pci_dev *pdev = gp->pdev;
+	u32 mif_cfg;
+
+	/* On Apple's sungem, we can't realy on registers as the chip
+	 * was been powered down by the firmware. We do the PHY lookup
+	 * when the interface is opened and we configure the driver
+	 * with known values.
+	 */
+	if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
+		gp->phy_type = phy_mii_mdio0;
+		mif_cfg = readl(gp->regs + MIF_CFG);
+		mif_cfg &= ~MIF_CFG_PSELECT;
+		writel(mif_cfg, gp->regs + MIF_CFG);
+		writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE);
+		writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG);
+		gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
+		gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
+		gem_init_pause_thresholds(gp);
+		return 0;
+	}
+
+	mif_cfg = readl(gp->regs + MIF_CFG);
+
+	if (pdev->vendor == PCI_VENDOR_ID_SUN &&
+	    pdev->device == PCI_DEVICE_ID_SUN_RIO_GEM) {
+		/* One of the MII PHYs _must_ be present
+		 * as this chip has no gigabit PHY.
+		 */
+		if ((mif_cfg & (MIF_CFG_MDI0 | MIF_CFG_MDI1)) == 0) {
+			printk(KERN_ERR PFX "RIO GEM lacks MII phy, mif_cfg[%08x]\n",
+			       mif_cfg);
+			return -1;
+		}
+	}
+
+	/* Determine initial PHY interface type guess.  MDIO1 is the
+	 * external PHY and thus takes precedence over MDIO0.
+	 */
+	
+	if (mif_cfg & MIF_CFG_MDI1) {
+		gp->phy_type = phy_mii_mdio1;
+		mif_cfg |= MIF_CFG_PSELECT;
+		writel(mif_cfg, gp->regs + MIF_CFG);
+	} else if (mif_cfg & MIF_CFG_MDI0) {
+		gp->phy_type = phy_mii_mdio0;
+		mif_cfg &= ~MIF_CFG_PSELECT;
+		writel(mif_cfg, gp->regs + MIF_CFG);
+	} else {
+		gp->phy_type = phy_serialink;
+	}
+	if (gp->phy_type == phy_mii_mdio1 ||
+	    gp->phy_type == phy_mii_mdio0) {
+		int i;
+
+		for (i = 0; i < 32; i++) {
+			gp->mii_phy_addr = i;
+			if (phy_read(gp, PHY_CTRL) != 0xffff)
+				break;
+		}
+		if (i == 32) {
+			if (pdev->device != PCI_DEVICE_ID_SUN_GEM) {
+				printk(KERN_ERR PFX "RIO MII phy will not respond.\n");
+				return -1;
+			}
+			gp->phy_type = phy_serdes;
+		}
+	}
+
+	/* Fetch the FIFO configurations now too. */
+	gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
+	gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
+
+	if (pdev->vendor == PCI_VENDOR_ID_SUN) {
+		if (pdev->device == PCI_DEVICE_ID_SUN_GEM) {
+			if (gp->tx_fifo_sz != (9 * 1024) ||
+			    gp->rx_fifo_sz != (20 * 1024)) {
+				printk(KERN_ERR PFX "GEM has bogus fifo sizes tx(%d) rx(%d)\n",
+				       gp->tx_fifo_sz, gp->rx_fifo_sz);
+				return -1;
+			}
+		} else {
+			if (gp->tx_fifo_sz != (2 * 1024) ||
+			    gp->rx_fifo_sz != (2 * 1024)) {
+				printk(KERN_ERR PFX "RIO GEM has bogus fifo sizes tx(%d) rx(%d)\n",
+				       gp->tx_fifo_sz, gp->rx_fifo_sz);
+				return -1;
+			}
+		}
+	}
+
+	gem_init_pause_thresholds(gp);
+
+	return 0;
+}
+
 static void gem_init_hw(struct gem *gp)
 {
+	/* On Apple's gmac, I initialize the PHY only after
+	 * setting up the chip. It appears the gigabit PHYs
+	 * don't quite like beeing talked to on the GII when
+	 * the chip is not running, I suspect it might not
+	 * be clocked at that point. --BenH
+	 */
+	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
+		gem_check_invariants(gp);
+		gp->hw_running = 1;
+	}
 	gem_init_phy(gp);
 	gem_init_dma(gp);
 	gem_init_mac(gp);
 
-	writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK);
-
 	gp->timer_ticks = 0;
 	gp->lstate = aneg_wait;
 	gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
 	add_timer(&gp->link_timer);
 }
 
+#ifdef CONFIG_ALL_PPC
+/* Enable the chip's clock and make sure it's config space is
+ * setup properly. There appear to be no need to restore the
+ * base addresses.
+ */
+static void
+gem_apple_powerup(struct gem* gp)
+{
+	u16 cmd;
+
+	pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1);
+
+	udelay(100);
+
+	pci_read_config_word(gp->pdev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+    	pci_write_config_word(gp->pdev, PCI_COMMAND, cmd);
+    	pci_write_config_byte(gp->pdev, PCI_LATENCY_TIMER, 6);
+    	pci_write_config_byte(gp->pdev, PCI_CACHE_LINE_SIZE, 8);
+}
+
+/* Turn off the chip's clock */
+static void
+gem_apple_powerdown(struct gem* gp)
+{
+	pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);
+}
+#endif /* CONFIG_ALL_PPC */
+
 static int gem_open(struct net_device *dev)
 {
 	struct gem *gp = dev->priv;
@@ -1335,12 +1748,31 @@
 
 	del_timer(&gp->link_timer);
 
+#ifdef CONFIG_ALL_PPC
+	/* First, we need to bring up the chip */
+	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+		gem_apple_powerup(gp);
+#endif /* CONFIG_ALL_PPC */
+
+	/* Reset the chip */
+	gem_stop(gp, regs);
+
+	/* We can now request the interrupt as we know it's masked
+	 * on the controller
+	 */
 	if (request_irq(gp->pdev->irq, gem_interrupt,
-			SA_SHIRQ, dev->name, (void *)dev))
+			SA_SHIRQ, dev->name, (void *)dev)) {
+#ifdef CONFIG_ALL_PPC
+		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+			gem_apple_powerdown(gp);
+#endif /* CONFIG_ALL_PPC */
 		return -EAGAIN;
+	}
 
-	gem_stop(gp, regs);
+	/* Allocate & setup ring buffers */
 	gem_init_rings(gp, 0);
+
+	/* Init & setup chip hardware */
 	gem_init_hw(gp);
 
 	return 0;
@@ -1353,6 +1785,11 @@
 	del_timer(&gp->link_timer);
 	gem_stop(gp, gp->regs);
 	gem_clean_rings(gp);
+	gp->hw_running = 0;
+#ifdef CONFIG_ALL_PPC
+	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+		gem_apple_powerdown(gp);
+#endif /* CONFIG_ALL_PPC */
 	free_irq(gp->pdev->irq, (void *)dev);
 	return 0;
 }
@@ -1362,22 +1799,23 @@
 	struct gem *gp = dev->priv;
 	struct net_device_stats *stats = &gp->net_stats;
 
-	stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR);
-	writel(0, gp->regs + MAC_FCSERR);
-
-	stats->rx_frame_errors += readl(gp->regs + MAC_AERR);
-	writel(0, gp->regs + MAC_AERR);
-
-	stats->rx_length_errors += readl(gp->regs + MAC_LERR);
-	writel(0, gp->regs + MAC_LERR);
-
-	stats->tx_aborted_errors += readl(gp->regs + MAC_ECOLL);
-	stats->collisions +=
-		(readl(gp->regs + MAC_ECOLL) +
-		 readl(gp->regs + MAC_LCOLL));
-	writel(0, gp->regs + MAC_ECOLL);
-	writel(0, gp->regs + MAC_LCOLL);
-
+	if (gp->hw_running) {
+		stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR);
+		writel(0, gp->regs + MAC_FCSERR);
+
+		stats->rx_frame_errors += readl(gp->regs + MAC_AERR);
+		writel(0, gp->regs + MAC_AERR);
+
+		stats->rx_length_errors += readl(gp->regs + MAC_LERR);
+		writel(0, gp->regs + MAC_LERR);
+
+		stats->tx_aborted_errors += readl(gp->regs + MAC_ECOLL);
+		stats->collisions +=
+			(readl(gp->regs + MAC_ECOLL) +
+			 readl(gp->regs + MAC_LCOLL));
+		writel(0, gp->regs + MAC_ECOLL);
+		writel(0, gp->regs + MAC_LCOLL);
+	}
 	return &gp->net_stats;
 }
 
@@ -1385,6 +1823,9 @@
 {
 	struct gem *gp = dev->priv;
 
+	if (!gp->hw_running)
+		return;
+		
 	netif_stop_queue(dev);
 
 	if ((gp->dev->flags & IFF_ALLMULTI) ||
@@ -1475,115 +1916,14 @@
 	return -EINVAL;
 }
 
-static int __devinit gem_check_invariants(struct gem *gp)
-{
-	struct pci_dev *pdev = gp->pdev;
-	u32 mif_cfg = readl(gp->regs + MIF_CFG);
-
-	if (pdev->vendor == PCI_VENDOR_ID_SUN &&
-	    pdev->device == PCI_DEVICE_ID_SUN_RIO_GEM) {
-		/* One of the MII PHYs _must_ be present
-		 * as this chip has no gigabit PHY.
-		 */
-		if ((mif_cfg & (MIF_CFG_MDI0 | MIF_CFG_MDI1)) == 0) {
-			printk(KERN_ERR PFX "RIO GEM lacks MII phy, mif_cfg[%08x]\n",
-			       mif_cfg);
-			return -1;
-		}
-	}
-
-	/* Determine initial PHY interface type guess.  MDIO1 is the
-	 * external PHY and thus takes precedence over MDIO0.
-	 */
-	if (mif_cfg & MIF_CFG_MDI1) {
-		gp->phy_type = phy_mii_mdio1;
-		mif_cfg |= MIF_CFG_PSELECT;
-		writel(mif_cfg, gp->regs + MIF_CFG);
-	} else if (mif_cfg & MIF_CFG_MDI0) {
-		gp->phy_type = phy_mii_mdio0;
-		mif_cfg &= ~MIF_CFG_PSELECT;
-		writel(mif_cfg, gp->regs + MIF_CFG);
-	} else {
-		gp->phy_type = phy_serialink;
-	}
-	if (gp->phy_type == phy_mii_mdio1 ||
-	    gp->phy_type == phy_mii_mdio0) {
-		int i;
-
-		for (i = 0; i < 32; i++) {
-			gp->mii_phy_addr = i;
-			if (phy_read(gp, PHY_CTRL) != 0xffff)
-				break;
-		}
-		if (i == 32) {
-			if (pdev->device != PCI_DEVICE_ID_SUN_GEM) {
-				printk(KERN_ERR PFX "RIO MII phy will not respond.\n");
-				return -1;
-			}
-			gp->phy_type = phy_serdes;
-		}
-	}
-
-	/* Fetch the FIFO configurations now too. */
-	gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
-	gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
-
-	if (pdev->vendor == PCI_VENDOR_ID_SUN) {
-		if (pdev->device == PCI_DEVICE_ID_SUN_GEM) {
-			if (gp->tx_fifo_sz != (9 * 1024) ||
-			    gp->rx_fifo_sz != (20 * 1024)) {
-				printk(KERN_ERR PFX "GEM has bogus fifo sizes tx(%d) rx(%d)\n",
-				       gp->tx_fifo_sz, gp->rx_fifo_sz);
-				return -1;
-			}
-		} else {
-			if (gp->tx_fifo_sz != (2 * 1024) ||
-			    gp->rx_fifo_sz != (2 * 1024)) {
-				printk(KERN_ERR PFX "RIO GEM has bogus fifo sizes tx(%d) rx(%d)\n",
-				       gp->tx_fifo_sz, gp->rx_fifo_sz);
-				return -1;
-			}
-		}
-	}
-
-	/* Calculate pause thresholds.  Setting the OFF threshold to the
-	 * full RX fifo size effectively disables PAUSE generation which
-	 * is what we do for 10/100 only GEMs which have FIFOs too small
-	 * to make real gains from PAUSE.
-	 */
-	if (gp->rx_fifo_sz <= (2 * 1024)) {
-		gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz;
-	} else {
-		int off = (gp->rx_fifo_sz - (5 * 1024));
-		int on = off - 1024;
-
-		gp->rx_pause_off = off;
-		gp->rx_pause_on = on;
-	}
-
-	{
-		u32 cfg = readl(gp->regs + GREG_BIFCFG);
-
-		cfg |= GREG_BIFCFG_B64DIS;
-		writel(cfg, gp->regs + GREG_BIFCFG);
-
-		cfg  = GREG_CFG_IBURST;
-		cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
-		cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
-		writel(cfg, gp->regs + GREG_CFG);
-	}
-
-	return 0;
-}
-
 static int __devinit gem_get_device_address(struct gem *gp)
 {
-#if defined(__sparc__) || defined(__powerpc__)
+#if defined(__sparc__) || defined(CONFIG_ALL_PPC)
 	struct net_device *dev = gp->dev;
-	struct pci_dev *pdev = gp->pdev;
 #endif
 
 #ifdef __sparc__
+	struct pci_dev *pdev = gp->pdev;
 	struct pcidev_cookie *pcp = pdev->sysdata;
 	int node = -1;
 
@@ -1598,12 +1938,10 @@
 	if (node == -1)
 		memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
 #endif
-#ifdef __powerpc__
-	struct device_node *gem_node;
+#ifdef CONFIG_ALL_PPC
 	unsigned char *addr;
 
-	gem_node = pci_device_to_OF_node(pdev);
-	addr = get_property(gem_node, "local-mac-address", NULL);
+	addr = get_property(gp->of_node, "local-mac-address", NULL);
 	if (addr == NULL) {
 		printk("\n");
 		printk(KERN_ERR "%s: can't get mac-address\n", dev->name);
@@ -1621,11 +1959,17 @@
 	unsigned long gemreg_base, gemreg_len;
 	struct net_device *dev;
 	struct gem *gp;
-	int i, err;
+	int i, err, pci_using_dac;
 
 	if (gem_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
 
+	/* Apple gmac note: during probe, the chip is powered up by
+	 * the arch code to allow the code below to work (and to let
+	 * the chip be probed on the config space. It won't stay powered
+	 * up until the interface is brought up however, so we can't rely
+	 * on register configuration done at this point.
+	 */
 	err = pci_enable_device(pdev);
 	if (err) {
 		printk(KERN_ERR PFX "Cannot enable MMIO operation, "
@@ -1634,6 +1978,29 @@
 	}
 	pci_set_master(pdev);
 
+	/* Configure DMA attributes. */
+
+	/* All of the GEM documentation states that 64-bit DMA addressing
+	 * is fully supported and should work just fine.  However the
+	 * front end for RIO based GEMs is different and only supports
+	 * 32-bit addressing.
+	 *
+	 * For now we assume the various PPC GEMs are 32-bit only as well.
+	 */
+	if (pdev->vendor == PCI_VENDOR_ID_SUN &&
+	    pdev->device == PCI_DEVICE_ID_SUN_GEM &&
+	    !pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) {
+		pci_using_dac = 1;
+	} else {
+		err = pci_set_dma_mask(pdev, (u64) 0xffffffff);
+		if (err) {
+			printk(KERN_ERR PFX "No usable DMA configuration, "
+			       "aborting.\n");
+			return err;
+		}
+		pci_using_dac = 0;
+	}
+
 	gemreg_base = pci_resource_start(pdev, 0);
 	gemreg_len = pci_resource_len(pdev, 0);
 
@@ -1671,8 +2038,13 @@
 		goto err_out_free_mmio_res;
 	}
 
-	if (gem_check_invariants(gp))
-		goto err_out_iounmap;
+	/* On Apple's, we might not access the hardware at that point */
+	if (pdev->vendor != PCI_VENDOR_ID_APPLE) {
+		gem_stop(gp, gp->regs);
+		if (gem_check_invariants(gp))
+			goto err_out_iounmap;
+		gp->hw_running = 1;
+	}
 
 	/* It is guarenteed that the returned buffer will be at least
 	 * PAGE_SIZE aligned.
@@ -1691,6 +2063,9 @@
 	printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
 	       dev->name);
 
+#ifdef CONFIG_ALL_PPC
+	gp->of_node = pci_device_to_OF_node(pdev);
+#endif	
 	if (gem_get_device_address(gp))
 		goto err_out_iounmap;
 
@@ -1717,6 +2092,8 @@
 
 	/* GEM can do it all... */
 	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+	if (pci_using_dac)
+		dev->features |= NETIF_F_HIGHDMA;
 
 	return 0;
 
@@ -1750,6 +2127,9 @@
 		iounmap((void *) gp->regs);
 		release_mem_region(pci_resource_start(pdev, 0),
 				   pci_resource_len(pdev, 0));
+#ifdef CONFIG_ALL_PPC
+		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);
+#endif		
 		kfree(dev);
 
 		pci_set_drvdata(pdev, NULL);
diff -u --recursive --new-file v2.4.12/linux/drivers/net/sungem.h linux/drivers/net/sungem.h
--- v2.4.12/linux/drivers/net/sungem.h	Thu Apr 12 12:11:39 2001
+++ linux/drivers/net/sungem.h	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: sungem.h,v 1.7 2001/04/04 14:49:40 davem Exp $
+/* $Id: sungem.h,v 1.8 2001/10/17 05:55:39 davem Exp $
  * sungem.h: Definitions for Sun GEM ethernet driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -756,9 +756,12 @@
 /* MII phy registers */
 #define PHY_CTRL	0x00
 #define PHY_STAT	0x01
+#define PHY_ID0		0x02
+#define PHY_ID1		0x03
 #define PHY_ADV		0x04
 #define PHY_LPA		0x05
 
+#define PHY_CTRL_SPD2	0x0040		/* Gigabit enable? (bcm5411)	*/
 #define PHY_CTRL_FDPLX	0x0100		/* Full duplex			*/
 #define PHY_CTRL_ISO	0x0400		/* Isloate MII from PHY		*/
 #define PHY_CTRL_ANRES	0x0200		/* Auto-negotiation restart	*/
@@ -778,8 +781,37 @@
 #define PHY_LPA_10FULL	0x0040
 #define PHY_LPA_100HALF	0x0080
 #define PHY_LPA_100FULL	0x0100
+#define PHY_LPA_PAUSE	0x0400
 #define PHY_LPA_FAULT	0x2000
 
+/* More PHY registers (specific to Broadcom models) */
+
+/* MII BCM5201 MULTIPHY interrupt register */
+#define PHY_BCM5201_INTERRUPT			0x1A
+#define PHY_BCM5201_INTERRUPT_INTENABLE		0x4000
+
+#define PHY_BCM5201_AUXMODE2			0x1B
+#define PHY_BCM5201_AUXMODE2_LOWPOWER		0x0008
+
+#define PHY_BCM5201_MULTIPHY                    0x1E
+
+/* MII BCM5201 MULTIPHY register bits */
+#define PHY_BCM5201_MULTIPHY_SERIALMODE         0x0002
+#define PHY_BCM5201_MULTIPHY_SUPERISOLATE       0x0008
+
+/* MII BCM5400 1000-BASET Control register */
+#define PHY_BCM5400_GB_CONTROL			0x09
+#define PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP	0x0200
+
+/* MII BCM5400 AUXCONTROL register */
+#define PHY_BCM5400_AUXCONTROL                  0x18
+#define PHY_BCM5400_AUXCONTROL_PWR10BASET       0x0004
+
+/* MII BCM5400 AUXSTATUS register */
+#define PHY_BCM5400_AUXSTATUS                   0x19
+#define PHY_BCM5400_AUXSTATUS_LINKMODE_MASK     0x0700
+#define PHY_BCM5400_AUXSTATUS_LINKMODE_SHIFT    8  
+
 /* When it can, GEM internally caches 4 aligned TX descriptors
  * at a time, so that it can use full cacheline DMA reads.
  *
@@ -916,9 +948,19 @@
 	phy_serdes,
 };
 
+enum gem_phy_model {
+	phymod_generic,
+	phymod_bcm5201,
+	phymod_bcm5221,
+	phymod_bcm5400,
+	phymod_bcm5401,
+	phymod_bcm5411,
+};
+
 enum link_state {
 	aneg_wait,
 	force_wait,
+	aneg_up,
 };
 
 struct gem {
@@ -927,6 +969,11 @@
 	int rx_new, rx_old;
 	int tx_new, tx_old;
 
+	/* Set when chip is actually in operational state
+	 * (ie. not power managed)
+	 */
+	int hw_running;
+
 	struct gem_init_block *init_block;
 
 	struct sk_buff *rx_skbs[RX_RING_SIZE];
@@ -935,6 +982,7 @@
 	struct net_device_stats net_stats;
 
 	enum gem_phy_type	phy_type;
+	enum gem_phy_model	phy_mod;
 	int			tx_fifo_sz;
 	int			rx_fifo_sz;
 	int			rx_pause_off;
@@ -952,6 +1000,9 @@
 	dma_addr_t gblock_dvma;
 	struct pci_dev *pdev;
 	struct net_device *dev;
+#ifdef CONFIG_ALL_PPC
+	struct device_node	*of_node;
+#endif
 };
 
 #define ALIGNED_RX_SKB_ADDR(addr) \
diff -u --recursive --new-file v2.4.12/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.4.12/linux/drivers/net/sunhme.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/sunhme.c	Fri Oct 12 15:35:53 2001
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.122 2001/08/13 14:40:07 davem Exp $
+/* $Id: sunhme.c,v 1.123 2001/10/02 02:22:30 davem Exp $
  * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
diff -u --recursive --new-file v2.4.12/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.4.12/linux/drivers/net/sunlance.c	Thu Apr 26 22:17:26 2001
+++ linux/drivers/net/sunlance.c	Fri Oct 19 08:32:28 2001
@@ -1603,3 +1603,4 @@
 
 module_init(sparc_lance_probe);
 module_exit(sparc_lance_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.4.12/linux/drivers/net/sunqe.c	Thu Apr 26 22:17:26 2001
+++ linux/drivers/net/sunqe.c	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: sunqe.c,v 1.51 2001/04/19 22:32:42 davem Exp $
+/* $Id: sunqe.c,v 1.52 2001/10/18 08:18:08 davem Exp $
  * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
  *          Once again I am out to prove that every ethernet
  *          controller out there can be most efficiently programmed
@@ -1041,3 +1041,4 @@
 
 module_init(qec_probe);
 module_exit(qec_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c
--- v2.4.12/linux/drivers/net/tulip/interrupt.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/tulip/interrupt.c	Tue Oct 16 21:56:29 2001
@@ -301,7 +301,7 @@
 	long ioaddr = dev->base_addr;
 	int csr5;
 	int entry;
-	int csr8;
+	int missed;
 	int rx = 0;
 	int tx = 0;
 	int oi = 0;
@@ -434,6 +434,7 @@
 				}
 			}
 			if (csr5 & RxDied) {		/* Missed a Rx frame. */
+                                tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
 #ifdef CONFIG_NET_HW_FLOWCONTROL
 				if (tp->fc_bit && !test_bit(tp->fc_bit, &netdev_fc_xoff)) {
 					tp->stats.rx_errors++;
@@ -547,8 +548,9 @@
 		}
 	}
 
-	csr8 = inl(ioaddr + CSR8);
-	tp->stats.rx_dropped += (csr8 & 0x1ffff) + ((csr8 >> 17) & 0xfff);
+	if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) {
+		tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
+	}
 
 	if (tulip_debug > 4)
 		printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
diff -u --recursive --new-file v2.4.12/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c
--- v2.4.12/linux/drivers/net/tulip/tulip_core.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/tulip/tulip_core.c	Tue Oct 16 21:56:29 2001
@@ -15,8 +15,8 @@
 */
 
 #define DRV_NAME	"tulip"
-#define DRV_VERSION	"0.9.15-pre7"
-#define DRV_RELDATE	"Oct 2, 2001"
+#define DRV_VERSION	"0.9.15-pre8"
+#define DRV_RELDATE	"Oct 11, 2001"
 
 #include <linux/config.h>
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.12/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.4.12/linux/drivers/net/via-rhine.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/via-rhine.c	Mon Oct 15 13:32:32 2001
@@ -764,6 +764,7 @@
 			    RX_RING_SIZE * sizeof(struct rx_desc) +
 			    TX_RING_SIZE * sizeof(struct tx_desc),
 			    np->rx_ring, np->rx_ring_dma);
+	np->tx_ring = NULL;
 
 	if (np->tx_bufs)
 		pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE,
@@ -1595,11 +1596,6 @@
 #ifndef USE_IO
 	iounmap((char *)(dev->base_addr));
 #endif
-
-	pci_free_consistent(pdev, 
-			    RX_RING_SIZE * sizeof(struct rx_desc) +
-			    TX_RING_SIZE * sizeof(struct tx_desc),
-			    np->rx_ring, np->rx_ring_dma);
 
 	kfree(dev);
 
diff -u --recursive --new-file v2.4.12/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.4.12/linux/drivers/net/wavelan.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/wavelan.c	Fri Oct 12 14:21:18 2001
@@ -2059,6 +2059,10 @@
 			range.max_qual.qual = MMR_SGNL_QUAL;
 			range.max_qual.level = MMR_SIGNAL_LVL;
 			range.max_qual.noise = MMR_SILENCE_LVL;
+			range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
+			/* Need to get better values for those two */
+			range.avg_qual.level = 30;
+			range.avg_qual.noise = 8;
 
 			range.num_bitrates = 1;
 			range.bitrate[0] = 2000000;	/* 2 Mb/s */
diff -u --recursive --new-file v2.4.12/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h
--- v2.4.12/linux/drivers/net/wavelan.p.h	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/wavelan.p.h	Fri Oct 12 14:21:18 2001
@@ -447,13 +447,13 @@
 
 /* ------------------------ PRIVATE IOCTL ------------------------ */
 
-#define SIOCSIPQTHR	SIOCDEVPRIVATE		/* Set quality threshold */
-#define SIOCGIPQTHR	SIOCDEVPRIVATE + 1	/* Get quality threshold */
-#define SIOCSIPLTHR	SIOCDEVPRIVATE + 2	/* Set level threshold */
-#define SIOCGIPLTHR	SIOCDEVPRIVATE + 3	/* Get level threshold */
+#define SIOCSIPQTHR	SIOCIWFIRSTPRIV		/* Set quality threshold */
+#define SIOCGIPQTHR	SIOCIWFIRSTPRIV + 1	/* Get quality threshold */
+#define SIOCSIPLTHR	SIOCIWFIRSTPRIV + 2	/* Set level threshold */
+#define SIOCGIPLTHR	SIOCIWFIRSTPRIV + 3	/* Get level threshold */
 
-#define SIOCSIPHISTO	SIOCDEVPRIVATE + 6	/* Set histogram ranges */
-#define SIOCGIPHISTO	SIOCDEVPRIVATE + 7	/* Get histogram values */
+#define SIOCSIPHISTO	SIOCIWFIRSTPRIV + 6	/* Set histogram ranges */
+#define SIOCGIPHISTO	SIOCIWFIRSTPRIV + 7	/* Get histogram values */
 
 /****************************** TYPES ******************************/
 
diff -u --recursive --new-file v2.4.12/linux/drivers/net/wireless/airo.c linux/drivers/net/wireless/airo.c
--- v2.4.12/linux/drivers/net/wireless/airo.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/wireless/airo.c	Fri Oct 19 08:32:28 2001
@@ -14,7 +14,7 @@
     Aironet.  Major code contributions were received from Javier Achirica
     and Jean Tourrilhes <jt@hpl.hp.com>.  Code was also integrated from
     the Cisco Aironet driver for Linux.
-    
+
 ======================================================================*/
 
 #include <linux/config.h>
@@ -53,7 +53,7 @@
 	{ 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, },
-	{ 0, } 
+	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, card_ids);
 
@@ -213,7 +213,7 @@
 
 static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */
 static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read
-		    the bap, needed on some older cards and buses. */   
+		    the bap, needed on some older cards and buses. */
 static int adhoc;
 
 static int proc_uid /* = 0 */;
@@ -341,6 +341,9 @@
 
 /* The RIDs */
 #define RID_CAPABILITIES 0xFF00
+#define RID_APINFO     0xFF01
+#define RID_RADIOINFO  0xFF02
+#define RID_UNKNOWN3   0xFF03
 #define RID_RSSI       0xFF04
 #define RID_CONFIG     0xFF10
 #define RID_SSID       0xFF11
@@ -350,13 +353,25 @@
 #define RID_WEP_TEMP   0xFF15
 #define RID_WEP_PERM   0xFF16
 #define RID_MODULATION 0xFF17
+#define RID_OPTIONS    0xFF18
 #define RID_ACTUALCONFIG 0xFF20 /*readonly*/
+#define RID_FACTORYCONFIG 0xFF21
+#define RID_UNKNOWN22  0xFF22
 #define RID_LEAPUSERNAME 0xFF23
 #define RID_LEAPPASSWORD 0xFF24
 #define RID_STATUS     0xFF50
+#define RID_UNKNOWN52  0xFF52
+#define RID_UNKNOWN54  0xFF54
+#define RID_UNKNOWN55  0xFF55
+#define RID_UNKNOWN56  0xFF56
+#define RID_STATS16    0xFF60
+#define RID_STATS16DELTA 0xFF61
+#define RID_STATS16DELTACLEAR 0xFF62
 #define RID_STATS      0xFF68
 #define RID_STATSDELTA 0xFF69
 #define RID_STATSDELTACLEAR 0xFF6A
+#define RID_UNKNOWN70  0xFF70
+#define RID_UNKNOWN71  0xFF71
 #define RID_BSSLISTFIRST 0xFF72
 #define RID_BSSLISTNEXT  0xFF73
 
@@ -563,7 +578,7 @@
 	u16 spacer;
 	u32 vals[100];
 } StatsRid;
-	
+
 
 typedef struct {
 	u16 len;
@@ -604,7 +619,7 @@
 #define RADIO_FH 1 /* Frequency hopping radio type */
 #define RADIO_DS 2 /* Direct sequence radio type */
 #define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */
-  u16 radioType; 
+  u16 radioType;
   u8 bssid[6]; /* Mac address of the BSS */
   u8 zero;
   u8 ssidLen;
@@ -653,14 +668,23 @@
 
 #ifdef CISCO_EXT
 #define AIROMAGIC	0xa55a
-#define AIROIOCTL	SIOCDEVPRIVATE
+/* Warning : SIOCDEVPRIVATE may disapear during 2.5.X - Jean II */
+#ifdef SIOCIWFIRSTPRIV
+#ifdef SIOCDEVPRIVATE
+#define AIROOLDIOCTL	SIOCDEVPRIVATE
+#define AIROOLDIDIFC 	AIROOLDIOCTL + 1
+#endif /* SIOCDEVPRIVATE */
+#else /* SIOCIWFIRSTPRIV */
+#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
+#endif /* SIOCIWFIRSTPRIV */
+#define AIROIOCTL	SIOCIWFIRSTPRIV
 #define AIROIDIFC 	AIROIOCTL + 1
 
 /* Ioctl constants to be used in airo_ioctl.command */
 
 #define	AIROGCAP  		0	// Capability rid
-#define AIROGCFG		1       // USED A LOT 
-#define AIROGSLIST		2	// System ID list 
+#define AIROGCFG		1       // USED A LOT
+#define AIROGSLIST		2	// System ID list
 #define AIROGVLIST		3       // List of specified AP's
 #define AIROGDRVNAM		4	//  NOTUSED
 #define AIROGEHTENC		5	// NOTUSED
@@ -728,11 +752,12 @@
 static u16 setup_card(struct airo_info*, u8 *mac, ConfigRid *);
 static void enable_interrupts(struct airo_info*);
 static void disable_interrupts(struct airo_info*);
+static u16 lock_issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
 static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
 static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
-static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen, 
+static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
 			int whichbap);
-static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen, 
+static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
 			 int whichbap);
 static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen,
 		     int whichbap);
@@ -740,7 +765,7 @@
 static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len);
 static int PC4500_writerid(struct airo_info*, u16 rid, const void
 			   *pBuf, int len);
-static int do_writerid( struct airo_info*, u16 rid, const void *rid_data, 
+static int do_writerid( struct airo_info*, u16 rid, const void *rid_data,
 			int len );
 static u16 transmit_allocate(struct airo_info*, int lenPayload);
 static int transmit_802_3_packet(struct airo_info*, u16 TxFid, char
@@ -768,20 +793,18 @@
 	int                           fids[MAX_FIDS];
 	int registered;
 	ConfigRid config;
-	u16 authtype; // Used with auto_wep 
+	u16 authtype; // Used with auto_wep
 	char keyindex; // Used with auto wep
 	char defindex; // Used with auto wep
 	struct timer_list timer;
 	struct proc_dir_entry *proc_entry;
 	struct airo_info *next;
-        spinlock_t bap0_lock;
-        spinlock_t bap1_lock;
         spinlock_t aux_lock;
-        spinlock_t cmd_lock;
+        spinlock_t main_lock;
         int flags;
 #define FLAG_PROMISC   IFF_PROMISC
 #define FLAG_RADIO_OFF 0x02
-	int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen, 
+	int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
 			int whichbap);
 	int (*header_parse)(struct sk_buff*, unsigned char *);
 	unsigned short *flash;
@@ -797,7 +820,7 @@
 #endif /* WIRELESS_EXT */
 };
 
-static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, 
+static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
 			   int whichbap) {
 	return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
 }
@@ -816,12 +839,12 @@
 	if (first == 1) {
 			memset(&cmd, 0, sizeof(cmd));
 			cmd.cmd=CMD_LISTBSS;
-			issuecommand(ai, &cmd, &rsp);
+			lock_issuecommand(ai, &cmd, &rsp);
 			/* Let the command take effect */
 			set_current_state (TASK_INTERRUPTIBLE);
 			schedule_timeout (3*HZ);
 		}
-	rc = PC4500_readrid(ai, 
+	rc = PC4500_readrid(ai,
 		            first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
 			    list, sizeof(*list));
 
@@ -837,9 +860,9 @@
 }
 
 static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp) {
-	int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, 
+	int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
 				wkr, sizeof(*wkr));
-	
+
 	wkr->len = le16_to_cpu(wkr->len);
 	wkr->kindex = le16_to_cpu(wkr->kindex);
 	wkr->klen = le16_to_cpu(wkr->klen);
@@ -855,7 +878,7 @@
 	wkr.kindex = cpu_to_le16(wkr.kindex);
 	wkr.klen = cpu_to_le16(wkr.klen);
 	rc = do_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr));
-	if (rc!=SUCCESS) printk(KERN_ERR "airo:  WEP_TEMP set %x\n", rc); 
+	if (rc!=SUCCESS) printk(KERN_ERR "airo:  WEP_TEMP set %x\n", rc);
 	if (perm) {
 		rc = do_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr));
 		if (rc!=SUCCESS) {
@@ -890,7 +913,7 @@
 static int readConfigRid(struct airo_info*ai, ConfigRid *cfgr) {
 	int rc = PC4500_readrid(ai, RID_ACTUALCONFIG, cfgr, sizeof(*cfgr));
 	u16 *s;
-	
+
 	for(s = &cfgr->len; s <= &cfgr->rtsThres; s++) *s = le16_to_cpu(*s);
 
 	for(s = &cfgr->shortRetryLimit; s <= &cfgr->radioType; s++)
@@ -898,16 +921,16 @@
 
 	for(s = &cfgr->txPower; s <= &cfgr->radioSpecific; s++)
 		*s = le16_to_cpu(*s);
-	
+
 	for(s = &cfgr->arlThreshold; s <= &cfgr->autoWake; s++)
 		*s = le16_to_cpu(*s);
-	
+
 	return rc;
 }
 static int writeConfigRid(struct airo_info*ai, ConfigRid *pcfgr) {
 	u16 *s;
 	ConfigRid cfgr = *pcfgr;
-	
+
 	for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
 
 	for(s = &cfgr.shortRetryLimit; s <= &cfgr.radioType; s++)
@@ -915,10 +938,10 @@
 
 	for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++)
 		*s = cpu_to_le16(*s);
-	
+
 	for(s = &cfgr.arlThreshold; s <= &cfgr.autoWake; s++)
 		*s = cpu_to_le16(*s);
-	
+
 	return do_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr));
 }
 static int readStatusRid(struct airo_info*ai, StatusRid *statr) {
@@ -947,7 +970,7 @@
 static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr) {
 	int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr));
 	u16 *s;
-	
+
 	capr->len = le16_to_cpu(capr->len);
 	capr->prodNum = le16_to_cpu(capr->prodNum);
 	capr->radioType = le16_to_cpu(capr->radioType);
@@ -976,21 +999,19 @@
 
 static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
 	s16 len;
-	s16 retval = 0;
 	u16 status;
 	u32 flags;
-	s8 *buffer;
 	int i,j;
 	struct airo_info *priv = (struct airo_info*)dev->priv;
 	u32 *fids = priv->fids;
-	
+
 	if ( skb == NULL ) {
 		printk( KERN_ERR "airo:  skb == NULL!!!\n" );
 		return 0;
 	}
-	
+
 	/* Find a vacant FID */
-	spin_lock_irqsave(&priv->bap1_lock, flags);
+	spin_lock_irqsave(&priv->main_lock, flags);
 	for( j = 0, i = -1; j < MAX_FIDS; j++ ) {
 		if ( !( fids[j] & 0xffff0000 ) ) {
 			if ( i == -1 ) i = j;
@@ -999,31 +1020,51 @@
 	}
 	if ( j == MAX_FIDS ) netif_stop_queue(dev);
 	if ( i == -1 ) {
-		retval = -EBUSY;
+		priv->stats.tx_fifo_errors++;
 		goto tx_done;
 	}
-	
+
 	len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* check min length*/
-	buffer = skb->data;
-	status = transmit_802_3_packet( priv, 
-					fids[i],
-					skb->data, len );
-	
+	status = transmit_802_3_packet( priv, fids[i], skb->data, len );
+
 	if ( status == SUCCESS ) {
                 /* Mark fid as used & save length for later */
-		fids[i] |= (len << 16); 
+		fids[i] |= (len << 16);
 		dev->trans_start = jiffies;
 	} else {
-		priv->stats.tx_errors++;
+		priv->stats.tx_window_errors++;
 	}
  tx_done:
-	spin_unlock_irqrestore(&priv->bap1_lock, flags);
+	spin_unlock_irqrestore(&priv->main_lock, flags);
 	dev_kfree_skb(skb);
 	return 0;
 }
 
-static struct net_device_stats *airo_get_stats(struct net_device *dev) {
-	return &(((struct airo_info*)dev->priv)->stats);
+struct net_device_stats *airo_get_stats(struct net_device *dev)
+{
+	struct airo_info *local = (struct airo_info*) dev->priv;
+	StatsRid stats_rid;
+	u32 *vals = stats_rid.vals;
+
+	/* Get stats out of the card */
+	readStatsRid(local, &stats_rid, RID_STATS);
+
+	local->stats.rx_packets = vals[43] + vals[44] + vals[45];
+	local->stats.tx_packets = vals[39] + vals[40] + vals[41];
+	local->stats.rx_bytes = vals[92];
+	local->stats.tx_bytes = vals[91];
+	local->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
+	local->stats.tx_errors = vals[42] + local->stats.tx_fifo_errors;
+	local->stats.multicast = vals[43];
+	local->stats.collisions = vals[89];
+
+	/* detailed rx_errors: */
+	local->stats.rx_length_errors = vals[3];
+	local->stats.rx_crc_errors = vals[4];
+	local->stats.rx_frame_errors = vals[2];
+	local->stats.rx_fifo_errors = vals[0];
+
+	return (&local->stats);
 }
 
 static int enable_MAC( struct airo_info *ai, Resp *rsp );
@@ -1033,7 +1074,7 @@
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	Cmd cmd;
 	Resp rsp;
-	  
+
 	/* For some reason this command takes a lot of time (~20 ms) and it's
 	 * run in an interrupt handler, so we'd better be sure we needed it
 	 * before executing it.
@@ -1042,7 +1083,7 @@
 		memset(&cmd, 0, sizeof(cmd));
 		cmd.cmd=CMD_SETMODE;
 		cmd.parm0=(dev->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
-		issuecommand(ai, &cmd, &rsp);
+		lock_issuecommand(ai, &cmd, &rsp);
 		ai->flags^=IFF_PROMISC;
 	}
 
@@ -1073,7 +1114,7 @@
 }
 
 
-static int airo_close(struct net_device *dev) { 
+static int airo_close(struct net_device *dev) {
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 
 	netif_stop_queue(dev);
@@ -1083,7 +1124,7 @@
 
 static void del_airo_dev( struct net_device *dev );
 
-void stop_airo_card( struct net_device *dev, int freeres ) 
+void stop_airo_card( struct net_device *dev, int freeres )
 {
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	if (ai->flash)
@@ -1106,32 +1147,35 @@
 	kfree( dev );
 }
 
-static int add_airo_dev( struct net_device *dev ); 
+static int add_airo_dev( struct net_device *dev );
 
 struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
 {
 	struct net_device *dev;
 	struct airo_info *ai;
 	int i, rc;
-	
+
 	/* Create the network device object. */
         dev = alloc_etherdev(sizeof(*ai));
         if (!dev) {
 		printk(KERN_ERR "airo:  Couldn't alloc_etherdev\n");
 		return NULL;
         }
+	if (dev_alloc_name(dev, dev->name) < 0) {
+		printk(KERN_ERR "airo:  Couldn't get name!\n");
+		goto err_out_free;
+	}
+
 	ai = dev->priv;
-	ai->registered = 1;
+	ai->registered = 0;
         ai->dev = dev;
-	ai->bap0_lock = SPIN_LOCK_UNLOCKED;
-	ai->bap1_lock = SPIN_LOCK_UNLOCKED;
 	ai->aux_lock = SPIN_LOCK_UNLOCKED;
-	ai->cmd_lock = SPIN_LOCK_UNLOCKED;
+	ai->main_lock = SPIN_LOCK_UNLOCKED;
 	ai->header_parse = dev->hard_header_parse;
 	rc = add_airo_dev( dev );
 	if (rc)
 		goto err_out_free;
-	
+
 	/* The Airo-specific entries in the device structure. */
 	dev->hard_start_xmit = &airo_start_xmit;
 	dev->get_stats = &airo_get_stats;
@@ -1146,16 +1190,11 @@
 	dev->stop = &airo_close;
 	dev->irq = irq;
 	dev->base_addr = port;
-	
-	rc = register_netdev(dev);
-	if (rc)
-		goto err_out_unlink;
-	
-	rc = request_irq( dev->irq, airo_interrupt, 
-			  SA_SHIRQ | SA_INTERRUPT, dev->name, dev );
+
+	rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev );
 	if (rc) {
 		printk(KERN_ERR "airo: register interrupt %d failed, rc %d\n", irq, rc );
-		goto err_out_unregister;
+		goto err_out_unlink;
 	}
 	if (!is_pcmcia) {
 		if (!request_region( dev->base_addr, 64, dev->name )) {
@@ -1163,13 +1202,18 @@
 			goto err_out_irq;
 		}
 	}
-	
+
 	if ( setup_card( ai, dev->dev_addr, &ai->config) != SUCCESS ) {
 		printk( KERN_ERR "airo: MAC could not be enabled\n" );
 		rc = -EIO;
 		goto err_out_res;
 	}
 
+	rc = register_netdev(dev);
+	if (rc)
+		goto err_out_res;
+
+	ai->registered = 1;
 	printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
 		dev->name,
 		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
@@ -1189,8 +1233,6 @@
 	        release_region( dev->base_addr, 64 );
 err_out_irq:
 	free_irq(dev->irq, dev);
-err_out_unregister:
-	unregister_netdev(dev);
 err_out_unlink:
 	del_airo_dev(dev);
 err_out_free:
@@ -1204,7 +1246,7 @@
 		udelay (10);
 		if (++delay % 20)
 			OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
-	}  
+	}
 	return delay < 10000;
 }
 
@@ -1253,29 +1295,33 @@
 	u16 status;
 	u16 fid;
 	struct airo_info *apriv = (struct airo_info *)dev->priv;
-	u16 savedInterrupts;
-	
+	u16 savedInterrupts = 0;
+
 	if (!netif_device_present(dev))
 		return;
-	
-	status = IN4500( apriv, EVSTAT );
-	if ( !status || status == 0xffff ) return;
-	
-	if ( status & EV_AWAKE ) {
-		OUT4500( apriv, EVACK, EV_AWAKE );
-		OUT4500( apriv, EVACK, EV_AWAKE );
-	}
-	
-	savedInterrupts = IN4500( apriv, EVINTEN );
-	OUT4500( apriv, EVINTEN, 0 );
-	
-	if ( status & EV_LINK ) {
-		/* The link status has changed, if you want to put a
-		   monitor hook in, do it here.  (Remember that
-		   interrupts are still disabled!)
-		*/
-		u16 newStatus = IN4500(apriv, LINKSTAT);
-		/* Here is what newStatus means: */
+
+	for (;;) {
+		status = IN4500( apriv, EVSTAT );
+		if ( !status || status == 0xffff ) break;
+
+		if ( status & EV_AWAKE ) {
+			OUT4500( apriv, EVACK, EV_AWAKE );
+			OUT4500( apriv, EVACK, EV_AWAKE );
+		}
+
+		if (!savedInterrupts) {
+			savedInterrupts = IN4500( apriv, EVINTEN );
+			OUT4500( apriv, EVINTEN, 0 );
+		}
+
+		if ( status & EV_LINK ) {
+			/* The link status has changed, if you want to put a
+			   monitor hook in, do it here.  (Remember that
+			   interrupts are still disabled!)
+			*/
+			u16 newStatus = IN4500(apriv, LINKSTAT);
+			OUT4500( apriv, EVACK, EV_LINK);
+			/* Here is what newStatus means: */
 #define NOBEACON 0x8000 /* Loss of sync - missed beacons */
 #define MAXRETRIES 0x8001 /* Loss of sync - max retries */
 #define MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/
@@ -1304,155 +1350,137 @@
 			  leaving BSS */
 #define RC_NOAUTH 9 /* Station requesting (Re)Association is not
 		       Authenticated with the responding station */
-		if (newStatus != ASSOCIATED) {
-			if (auto_wep && !timer_pending(&apriv->timer)) {
-				apriv->timer.expires = RUN_AT(HZ*3);
-	      			add_timer(&apriv->timer);
-			}
-		}
-	}
-	
-	/* Check to see if there is something to receive */
-	if ( status & EV_RX  ) {
-		struct sk_buff *skb = NULL;
-		long flags;
-		u16 fc, len, hdrlen = 0;
-		struct {
-			u16 status, len;
-			u8 rssi[2];
-		} hdr;
-
-		fid = IN4500( apriv, RXFID );
-
-		/* Get the packet length */
-	        spin_lock_irqsave(&apriv->bap0_lock, flags);
-		if (dev->type == ARPHRD_IEEE80211) {
-			bap_setup (apriv, fid, 4, BAP0);
-			bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
-			/* Bad CRC. Ignore packet */
-			if (le16_to_cpu(hdr.status) == 2) {
-				apriv->stats.rx_crc_errors++;
-				apriv->stats.rx_errors++;
-				hdr.len = 0;
+			if (newStatus != ASSOCIATED) {
+				if (auto_wep && !timer_pending(&apriv->timer)) {
+					apriv->timer.expires = RUN_AT(HZ*3);
+		      			add_timer(&apriv->timer);
+				}
 			}
-		} else {
-			bap_setup (apriv, fid, 6, BAP0);
-			bap_read (apriv, (u16*)&hdr.len, 4, BAP0);
 		}
-		len = le16_to_cpu(hdr.len);
 
-		if (len > 2312) {
-			apriv->stats.rx_length_errors++;
-			apriv->stats.rx_errors++;
-			printk( KERN_ERR 
-				"airo: Bad size %d\n", len );
-			len = 0;
-		}
-		if (len) {
+		/* Check to see if there is something to receive */
+		if ( status & EV_RX  ) {
+			struct sk_buff *skb = NULL;
+			u16 fc, len, hdrlen = 0;
+			struct {
+				u16 status, len;
+				u8 rssi[2];
+			} hdr;
+
+			fid = IN4500( apriv, RXFID );
+
+			/* Get the packet length */
 			if (dev->type == ARPHRD_IEEE80211) {
-				bap_setup (apriv, fid, 0x14, BAP0);
-				bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
-				if ((le16_to_cpu(fc) & 0x300) == 0x300)
-					hdrlen = 30;
-				else
-					hdrlen = 24;
-			} else
-				hdrlen = 12;
+				bap_setup (apriv, fid, 4, BAP0);
+				bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
+				/* Bad CRC. Ignore packet */
+				if (le16_to_cpu(hdr.status) & 2)
+					hdr.len = 0;
+			} else {
+				bap_setup (apriv, fid, 6, BAP0);
+				bap_read (apriv, (u16*)&hdr.len, 4, BAP0);
+			}
+			len = le16_to_cpu(hdr.len);
 
-			skb = dev_alloc_skb( len + hdrlen + 2 );
-			if ( !skb ) {
-				apriv->stats.rx_dropped++;
+			if (len > 2312) {
+				printk( KERN_ERR "airo: Bad size %d\n", len );
 				len = 0;
 			}
-		}
-		if (len) {
-			u16 *buffer;
-			buffer = (u16*)skb_put (skb, len + hdrlen);
-			if (dev->type == ARPHRD_IEEE80211) {
-				u16 gap, tmpbuf[4];
-				buffer[0] = fc;
-				bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
-				if (hdrlen == 24)
-					bap_read (apriv, tmpbuf, 6, BAP0);
-
-				bap_read (apriv, &gap, sizeof(gap), BAP0);
-				gap = le16_to_cpu(gap);
-				if (gap && gap <= 8)
-					bap_read (apriv, tmpbuf, gap, BAP0);
+			if (len) {
+				if (dev->type == ARPHRD_IEEE80211) {
+					bap_setup (apriv, fid, 0x14, BAP0);
+					bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
+					if ((le16_to_cpu(fc) & 0x300) == 0x300)
+						hdrlen = 30;
+					else
+						hdrlen = 24;
+				} else
+					hdrlen = 12;
 
-				bap_read (apriv, buffer + hdrlen/2, len, BAP0);
-			} else {
-		                bap_setup (apriv, fid, 0x38, BAP0);
-				bap_read (apriv, buffer,len + hdrlen,BAP0);
+				skb = dev_alloc_skb( len + hdrlen + 2 );
+				if ( !skb ) {
+					apriv->stats.rx_dropped++;
+					len = 0;
+				}
 			}
+			if (len) {
+				u16 *buffer;
+				buffer = (u16*)skb_put (skb, len + hdrlen);
+				if (dev->type == ARPHRD_IEEE80211) {
+					u16 gap, tmpbuf[4];
+					buffer[0] = fc;
+					bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
+					if (hdrlen == 24)
+						bap_read (apriv, tmpbuf, 6, BAP0);
+
+					bap_read (apriv, &gap, sizeof(gap), BAP0);
+					gap = le16_to_cpu(gap);
+					if (gap && gap <= 8)
+						bap_read (apriv, tmpbuf, gap, BAP0);
+
+					bap_read (apriv, buffer + hdrlen/2, len, BAP0);
+				} else {
+			                bap_setup (apriv, fid, 0x38, BAP0);
+					bap_read (apriv, buffer,len + hdrlen,BAP0);
+				}
+				OUT4500( apriv, EVACK, EV_RX);
 #ifdef WIRELESS_SPY
-			if (apriv->spy_number > 0) {
-				int i;
-				char *sa;
-
-				sa = (char*)buffer + ((dev->type == ARPHRD_IEEE80211) ? 10 : 6);
-
-				for (i=0; i<apriv->spy_number; i++)
-					if (!memcmp(sa,apriv->spy_address[i],6))
-					{
-						apriv->spy_stat[i].qual = hdr.rssi[0];
-						if (apriv->rssi)
-							apriv->spy_stat[i].level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
-						else
-							apriv->spy_stat[i].level = (hdr.rssi[1] + 321) / 2;
-						apriv->spy_stat[i].noise = 0;
-						apriv->spy_stat[i].updated = 3;
-						break;
-					}
-			}
+				if (apriv->spy_number > 0) {
+					int i;
+					char *sa;
+
+					sa = (char*)buffer + ((dev->type == ARPHRD_IEEE80211) ? 10 : 6);
+
+					for (i=0; i<apriv->spy_number; i++)
+						if (!memcmp(sa,apriv->spy_address[i],6))
+						{
+							apriv->spy_stat[i].qual = hdr.rssi[0];
+							if (apriv->rssi)
+								apriv->spy_stat[i].level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
+							else
+								apriv->spy_stat[i].level = (hdr.rssi[1] + 321) / 2;
+							apriv->spy_stat[i].noise = 0;
+							apriv->spy_stat[i].updated = 3;
+							break;
+						}
+				}
 #endif /* WIRELESS_SPY  */
-			apriv->stats.rx_packets++;
-			apriv->stats.rx_bytes += len + hdrlen;
-			dev->last_rx = jiffies;
-			skb->dev = dev;
-			skb->ip_summed = CHECKSUM_NONE;
-			if (dev->type == ARPHRD_IEEE80211) {
-				skb->mac.raw = skb->data;
-				skb_pull (skb, hdrlen);
-				skb->pkt_type = PACKET_OTHERHOST;
-				skb->protocol = htons(ETH_P_802_2);
-			} else
-				skb->protocol = eth_type_trans( skb, dev );
+				dev->last_rx = jiffies;
+				skb->dev = dev;
+				skb->ip_summed = CHECKSUM_NONE;
+				if (dev->type == ARPHRD_IEEE80211) {
+					skb->mac.raw = skb->data;
+					skb_pull (skb, hdrlen);
+					skb->pkt_type = PACKET_OTHERHOST;
+					skb->protocol = htons(ETH_P_802_2);
+				} else
+					skb->protocol = eth_type_trans(skb,dev);
 
-			netif_rx( skb );
+				netif_rx( skb );
+			} else
+				OUT4500( apriv, EVACK, EV_RX);
 		}
-		spin_unlock_irqrestore(&apriv->bap0_lock, flags);
-	}
 
-	/* Check to see if a packet has been transmitted */
-	if (  status & ( EV_TX|EV_TXEXC ) ) {
-		int i;
-		int len = 0;
-		int full = 1;
-		int index = -1;
-		
-		fid = IN4500(apriv, TXCOMPLFID);
-		
-		for( i = 0; i < MAX_FIDS; i++ ) {
-			if (!(apriv->fids[i] & 0xffff0000)) full = 0;
-			if ( ( apriv->fids[i] & 0xffff ) == fid ) {
-				len = apriv->fids[i] >> 16;
-				index = i;
-				/* Set up to be used again */
-				apriv->fids[i] &= 0xffff; 
+		/* Check to see if a packet has been transmitted */
+		if (  status & ( EV_TX|EV_TXEXC ) ) {
+			int i;
+			int len = 0;
+			int index = -1;
+
+			fid = IN4500(apriv, TXCOMPLFID);
+
+			for( i = 0; i < MAX_FIDS; i++ ) {
+				if ( ( apriv->fids[i] & 0xffff ) == fid ) {
+					len = apriv->fids[i] >> 16;
+					index = i;
+					/* Set up to be used again */
+					apriv->fids[i] &= 0xffff;
+				}
 			}
-		}
-		if (full) netif_wake_queue(dev);
-		if (index==-1) {
-			printk( KERN_ERR
-				"airo: Unallocated FID was used to xmit\n" );
-		}
-		if ( status & EV_TX ) {
-			apriv->stats.tx_packets++;
-			if(index!=-1)
-				apriv->stats.tx_bytes += len;
-		} else {
-			if (bap_setup(apriv, fid, 0x0004, BAP1) == SUCCESS) {
+			if (index != -1) netif_wake_queue(dev);
+			if ((status & EV_TXEXC) &&
+				(bap_setup(apriv, fid, 4, BAP1) == SUCCESS)) {
+
 				u16 status;
 				bap_read(apriv, &status, 2, BAP1);
 				if (le16_to_cpu(status) & 2)
@@ -1462,18 +1490,24 @@
 				if (le16_to_cpu(status) & 0x10)
 					apriv->stats.tx_carrier_errors++;
 			}
-			apriv->stats.tx_errors++;
+			OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
+			if (index==-1) {
+				printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" );
+			}
 		}
+		if ( status & ~STATUS_INTS )
+			OUT4500( apriv, EVACK, status & ~STATUS_INTS);
+
+		if ( status & ~STATUS_INTS & ~IGNORE_INTS )
+			printk( KERN_WARNING "airo: Got weird status %x\n",
+				status & ~STATUS_INTS & ~IGNORE_INTS );
 	}
-	if ( status & ~STATUS_INTS & ~IGNORE_INTS ) 
-		printk( KERN_WARNING 
-			"airo: Got weird status %x\n", 
-			status & ~STATUS_INTS & ~IGNORE_INTS );
-	OUT4500( apriv, EVACK, status & STATUS_INTS );
-	OUT4500( apriv, EVINTEN, savedInterrupts );
-	
+
+	if (savedInterrupts)
+		OUT4500( apriv, EVINTEN, savedInterrupts );
+
 	/* done.. */
-	return;     
+	return;
 }
 
 /*
@@ -1496,7 +1530,7 @@
 
 static u16 IN4500( struct airo_info *ai, u16 reg ) {
 	unsigned short rc;
-	
+
 	if ( !do8bitIO )
 		rc = inw( ai->dev->base_addr + reg );
 	else {
@@ -1512,7 +1546,7 @@
         if (ai->flags&FLAG_RADIO_OFF) return SUCCESS;
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.cmd = MAC_ENABLE;
-	return issuecommand(ai, &cmd, rsp);
+	return lock_issuecommand(ai, &cmd, rsp);
 }
 
 static void disable_MAC( struct airo_info *ai ) {
@@ -1521,7 +1555,7 @@
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.cmd = MAC_DISABLE; // disable in case already enabled
-	issuecommand(ai, &cmd, &rsp);
+	lock_issuecommand(ai, &cmd, &rsp);
 }
 
 static void enable_interrupts( struct airo_info *ai ) {
@@ -1538,10 +1572,10 @@
 	OUT4500( ai, EVINTEN, 0 );
 }
 
-static u16 setup_card(struct airo_info *ai, u8 *mac, 
+static u16 setup_card(struct airo_info *ai, u8 *mac,
 		      ConfigRid *config)
 {
-	Cmd cmd; 
+	Cmd cmd;
 	Resp rsp;
 	ConfigRid cfg;
 	int status;
@@ -1560,18 +1594,18 @@
 	/* The NOP is the first step in getting the card going */
 	cmd.cmd = NOP;
 	cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
-	if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
+	if ( lock_issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
 		return ERROR;
 	}
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.cmd = MAC_DISABLE; // disable in case already enabled
-	if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
+	if ( lock_issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
 		return ERROR;
 	}
-	
+
 	// Let's figure out if we need to use the AUX port
 	cmd.cmd = CMD_ENABLEAUX;
-	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
+	if (lock_issuecommand(ai, &cmd, &rsp) != SUCCESS) {
 		printk(KERN_ERR "airo: Error checking for AUX port\n");
 		return ERROR;
 	}
@@ -1586,7 +1620,7 @@
 		cfg = *config;
 	} else {
 		tdsRssiRid rssi_rid;
-	
+
 		// general configuration (read/modify/write)
 		status = readConfigRid(ai, &cfg);
 		if ( status != SUCCESS ) return ERROR;
@@ -1606,23 +1640,23 @@
 			if ((status == SUCCESS) && (cap_rid.softCap & 8))
 				cfg.rmode |= RXMODE_NORMALIZED_RSSI;
 			else
-				printk(KERN_WARNING "airo: unknown received signal level\n");
+				printk(KERN_WARNING "airo: unknown received signal level scale\n");
 		}
 		cfg.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
-    
+
 		/* Save off the MAC */
 		for( i = 0; i < 6; i++ ) {
 			mac[i] = cfg.macAddr[i];
 		}
 
-		/* Check to see if there are any insmod configured 
+		/* Check to see if there are any insmod configured
 		   rates to add */
 		if ( rates ) {
 			int i = 0;
 			if ( rates[0] ) memset(cfg.rates,0,sizeof(cfg.rates));
 			for( i = 0; i < 8 && rates[i]; i++ ) {
 				cfg.rates[i] = rates[i];
-			}    
+			}
 		}
 		if ( basic_rate > 0 ) {
 			int i;
@@ -1637,27 +1671,27 @@
 		cfg.authType = ai->authtype;
 		*config = cfg;
 	}
-	
+
 	/* Setup the SSIDs if present */
 	if ( ssids[0] ) {
 		int i = 0;
 		for( i = 0; i < 3 && ssids[i]; i++ ) {
 			mySsid.ssids[i].len = strlen(ssids[i]);
-			if ( mySsid.ssids[i].len > 32 ) 
+			if ( mySsid.ssids[i].len > 32 )
 				mySsid.ssids[i].len = 32;
 			memcpy(mySsid.ssids[i].ssid, ssids[i],
 			       mySsid.ssids[i].len);
 			mySsid.ssids[i].len = mySsid.ssids[i].len;
 		}
 	}
-	
+
 	status = writeConfigRid(ai, &cfg);
 	if ( status != SUCCESS ) return ERROR;
-	
+
 	/* Set up the SSID list */
 	status = writeSsidRid(ai, &mySsid);
 	if ( status != SUCCESS ) return ERROR;
-	
+
 	/* Grab the initial wep key, we gotta save it for auto_wep */
 	rc = readWepKeyRid(ai, &wkr, 1);
 	if (rc == SUCCESS) do {
@@ -1667,7 +1701,7 @@
 		}
 		rc = readWepKeyRid(ai, &wkr, 0);
 	} while(lastindex != wkr.kindex);
-	
+
 	if (auto_wep && !timer_pending(&ai->timer)) {
 		ai->timer.expires = RUN_AT(HZ*3);
 		add_timer(&ai->timer);
@@ -1675,49 +1709,49 @@
 	return SUCCESS;
 }
 
+static u16 lock_issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
+	int rc;
+	long flags;
+
+	spin_lock_irqsave(&ai->main_lock, flags);
+	rc = issuecommand(ai, pCmd, pRsp);
+	spin_unlock_irqrestore(&ai->main_lock, flags);
+	return rc;
+}
+
 static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
         // Im really paranoid about letting it run forever!
-	int max_tries = 600000;  
-        int rc = SUCCESS;
-	long flags;
+	int max_tries = 600000;
 
-	spin_lock_irqsave(&ai->cmd_lock, flags);
 	OUT4500(ai, PARAM0, pCmd->parm0);
 	OUT4500(ai, PARAM1, pCmd->parm1);
 	OUT4500(ai, PARAM2, pCmd->parm2);
 	OUT4500(ai, COMMAND, pCmd->cmd);
 	while ( max_tries-- &&
 		(IN4500(ai, EVSTAT) & EV_CMD) == 0) {
-		if ( IN4500(ai, COMMAND) == pCmd->cmd) { 
+		if ( IN4500(ai, COMMAND) == pCmd->cmd) {
 			// PC4500 didn't notice command, try again
 			OUT4500(ai, COMMAND, pCmd->cmd);
 		}
-		if (!(max_tries & 255) && !in_interrupt()) {
-			set_current_state(TASK_RUNNING);
-			schedule();
-		}
 	}
 	if ( max_tries == -1 ) {
-		printk( KERN_ERR 
+		printk( KERN_ERR
 			"airo: Max tries exceeded when issueing command\n" );
-                rc = ERROR;
-                goto done;
+                return ERROR;
 	}
 	// command completed
 	pRsp->status = IN4500(ai, STATUS);
 	pRsp->rsp0 = IN4500(ai, RESP0);
 	pRsp->rsp1 = IN4500(ai, RESP1);
 	pRsp->rsp2 = IN4500(ai, RESP2);
-	
+
 	// clear stuck command busy if necessary
 	if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
 		OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
 	}
 	// acknowledge processing the status/response
 	OUT4500(ai, EVACK, EV_CMD);
- done:
-	spin_unlock_irqrestore(&ai->cmd_lock, flags);
-	return rc;
+	return SUCCESS;
 }
 
 /* Sets up the bap to start exchange data.  whichbap should
@@ -1727,7 +1761,7 @@
 {
 	int timeout = 50;
 	int max_tries = 3;
-	
+
 	OUT4500(ai, SELECT0+whichbap, rid);
 	OUT4500(ai, OFFSET0+whichbap, offset);
 	while (1) {
@@ -1735,19 +1769,19 @@
 		if (status & BAP_BUSY) {
                         /* This isn't really a timeout, but its kinda
 			   close */
-			if (timeout--) { 
+			if (timeout--) {
 				continue;
 			}
 		} else if ( status & BAP_ERR ) {
 			/* invalid rid or offset */
-			printk( KERN_ERR "airo: BAP error %x %d\n", 
+			printk( KERN_ERR "airo: BAP error %x %d\n",
 				status, whichbap );
 			return ERROR;
 		} else if (status & BAP_DONE) { // success
 			return SUCCESS;
 		}
 		if ( !(max_tries--) ) {
-			printk( KERN_ERR 
+			printk( KERN_ERR
 				"airo: BAP setup error too many retries\n" );
 			return ERROR;
 		}
@@ -1776,7 +1810,7 @@
 
 /* requires call to bap_setup() first */
 static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
-			int bytelen, int whichbap) 
+			int bytelen, int whichbap)
 {
 	u16 len;
 	u16 page;
@@ -1795,11 +1829,11 @@
 	for (i=0; i<words;) {
 		int count;
 		count = (len>>1) < (words-i) ? (len>>1) : (words-i);
-		if ( !do8bitIO ) 
-			insw( ai->dev->base_addr+DATA0+whichbap, 
+		if ( !do8bitIO )
+			insw( ai->dev->base_addr+DATA0+whichbap,
 			      pu16Dst+i,count );
 		else
-			insb( ai->dev->base_addr+DATA0+whichbap, 
+			insb( ai->dev->base_addr+DATA0+whichbap,
 			      pu16Dst+i, count << 1 );
 		i += count;
 		if (i<words) {
@@ -1812,11 +1846,11 @@
 
 
 /* requires call to bap_setup() first */
-static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst, 
+static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst,
 			 int bytelen, int whichbap)
 {
 	bytelen = (bytelen + 1) & (~1); // round up to even value
-	if ( !do8bitIO ) 
+	if ( !do8bitIO )
 		insw( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1 );
 	else
 		insb( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen );
@@ -1824,12 +1858,12 @@
 }
 
 /* requires call to bap_setup() first */
-static int bap_write(struct airo_info *ai, const u16 *pu16Src, 
+static int bap_write(struct airo_info *ai, const u16 *pu16Src,
 		     int bytelen, int whichbap)
 {
 	bytelen = (bytelen + 1) & (~1); // round up to even value
-	if ( !do8bitIO ) 
-		outsw( ai->dev->base_addr+DATA0+whichbap, 
+	if ( !do8bitIO )
+		outsw( ai->dev->base_addr+DATA0+whichbap,
 		       pu16Src, bytelen>>1 );
 	else
 		outsb( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen );
@@ -1861,7 +1895,7 @@
         long flags;
         int rc = SUCCESS;
 
-	spin_lock_irqsave(&ai->bap1_lock, flags);
+	spin_lock_irqsave(&ai->main_lock, flags);
 	if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS) {
                 rc = status;
                 goto done;
@@ -1873,10 +1907,10 @@
 	// read the rid length field
 	bap_read(ai, pBuf, 2, BAP1);
 	// length for remaining part of rid
-	len = min_t(unsigned int, len, le16_to_cpu(*(u16*)pBuf)) - 2;
-	
+	len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2;
+
 	if ( len <= 2 ) {
-		printk( KERN_ERR 
+		printk( KERN_ERR
 			"airo: Rid %x has a length of %d which is too short\n",
 			(int)rid,
 			(int)len );
@@ -1884,26 +1918,22 @@
                 goto done;
 	}
 	// read remainder of the rid
-	if (bap_setup(ai, rid, 2, BAP1) != SUCCESS) {
-                rc = ERROR;
-                goto done;
-        }
 	rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
  done:
-	spin_unlock_irqrestore(&ai->bap1_lock, flags);
+	spin_unlock_irqrestore(&ai->main_lock, flags);
 	return rc;
 }
 
 /*  Note, that we are using BAP1 which is also used by transmit, so
  *  make sure this isnt called when a transmit is happening */
-static int PC4500_writerid(struct airo_info *ai, u16 rid, 
+static int PC4500_writerid(struct airo_info *ai, u16 rid,
 			   const void *pBuf, int len)
 {
 	u16 status;
         long flags;
 	int rc = SUCCESS;
 
-	spin_lock_irqsave(&ai->bap1_lock, flags);
+	spin_lock_irqsave(&ai->main_lock, flags);
 	// --- first access so that we can write the rid data
 	if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
                 rc = status;
@@ -1918,7 +1948,7 @@
 	// ---now commit the rid data
 	rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
  done:
-	spin_unlock_irqrestore(&ai->bap1_lock, flags);
+	spin_unlock_irqrestore(&ai->main_lock, flags);
         return rc;
 }
 
@@ -1934,7 +1964,7 @@
 
 	cmd.cmd = CMD_ALLOCATETX;
 	cmd.parm0 = lenPayload;
-	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return 0;
+	if (lock_issuecommand(ai, &cmd, &rsp) != SUCCESS) return 0;
 	if ( (rsp.status & 0xFF00) != 0) return 0;
 	/* wait for the allocate event/indication
 	 * It makes me kind of nervous that this can just sit here and spin,
@@ -1943,7 +1973,7 @@
 	// get the allocated fid and acknowledge
 	txFid = IN4500(ai, TXALLOCFID);
 	OUT4500(ai, EVACK, EV_ALLOC);
-  
+
 	/*  The CARD is pretty cool since it converts the ethernet packet
 	 *  into 802.11.  Also note that we don't release the FID since we
 	 *  will be using the same one over and over again. */
@@ -1951,13 +1981,13 @@
 	 *  releasing the fid. */
 	txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
 		| TXCTL_ETHERNET | TXCTL_NORELEASE);
-	spin_lock_irqsave(&ai->bap1_lock, flags);
+	spin_lock_irqsave(&ai->main_lock, flags);
 	if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS) {
-		spin_unlock_irqrestore(&ai->bap1_lock, flags);
+		spin_unlock_irqrestore(&ai->main_lock, flags);
 		return ERROR;
 	}
 	bap_write(ai, &txControl, sizeof(txControl), BAP1);
-	spin_unlock_irqrestore(&ai->bap1_lock, flags);
+	spin_unlock_irqrestore(&ai->main_lock, flags);
 
 	return txFid;
 }
@@ -1965,18 +1995,18 @@
 /* In general BAP1 is dedicated to transmiting packets.  However,
    since we need a BAP when accessing RIDs, we also use BAP1 for that.
    Make sure the BAP1 spinlock is held when this is called. */
-static int transmit_802_3_packet(struct airo_info *ai, u16 txFid, 
+static int transmit_802_3_packet(struct airo_info *ai, u16 txFid,
 				 char *pPacket, int len)
 {
 	u16 payloadLen;
 	Cmd cmd;
 	Resp rsp;
-	
+
 	if (len < 12) {
 		printk( KERN_WARNING "Short packet %d\n", len );
 		return ERROR;
 	}
-	
+
 	// packet is destination[6], source[6], payload[len-12]
 	// write the payload length and dst/src/payload
 	if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
@@ -2106,7 +2136,7 @@
         entry->gid = proc_gid;
 	entry->data = dev;
 	SETPROC_OPS(entry, proc_statsdelta_ops);
-	
+
 	/* Setup the Stats */
 	entry = create_proc_entry("Stats",
 				  S_IFREG | (S_IRUGO&proc_perm),
@@ -2115,7 +2145,7 @@
         entry->gid = proc_gid;
 	entry->data = dev;
 	SETPROC_OPS(entry, proc_stats_ops);
-	
+
 	/* Setup the Status */
 	entry = create_proc_entry("Status",
 				  S_IFREG | (S_IRUGO&proc_perm),
@@ -2124,7 +2154,7 @@
         entry->gid = proc_gid;
 	entry->data = dev;
 	SETPROC_OPS(entry, proc_status_ops);
-	
+
 	/* Setup the Config */
 	entry = create_proc_entry("Config",
 				  S_IFREG | proc_perm,
@@ -2208,9 +2238,9 @@
 	int i;
 	int pos;
 	struct proc_data *priv = (struct proc_data*)file->private_data;
-	
+
 	if( !priv->rbuffer ) return -EINVAL;
-	
+
 	pos = *offset;
 	for( i = 0; i+pos < priv->readlen && i < len; i++ ) {
 		if (put_user( priv->rbuffer[i+pos], buffer+i ))
@@ -2227,18 +2257,18 @@
 static ssize_t proc_write( struct file *file,
 			   const char *buffer,
 			   size_t len,
-			   loff_t *offset ) 
+			   loff_t *offset )
 {
 	int i;
 	int pos;
 	struct proc_data *priv = (struct proc_data*)file->private_data;
-	
+
 	if ( !priv->wbuffer ) {
 		return -EINVAL;
 	}
-	
+
 	pos = *offset;
-	
+
 	for( i = 0; i + pos <  priv->maxwritelen &&
 		     i < len; i++ ) {
 		if (get_user( priv->wbuffer[i+pos], buffer + i ))
@@ -2257,11 +2287,11 @@
 	CapabilityRid cap_rid;
 	StatusRid status_rid;
 	int i;
-	
+
 	MOD_INC_USE_COUNT;
-	
+
 	dp = inode->u.generic_ip;
-	
+
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2270,10 +2300,10 @@
 		kfree (file->private_data);
 		return -ENOMEM;
 	}
-	
+
 	readStatusRid(apriv, &status_rid);
 	readCapabilityRid(apriv, &cap_rid);
-	
+
         i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n",
                     status_rid.mode & 1 ? "CFG ": "",
                     status_rid.mode & 2 ? "ACT ": "",
@@ -2319,7 +2349,7 @@
 }
 
 static int proc_stats_rid_open(struct inode*, struct file*, u16);
-static int proc_statsdelta_open( struct inode *inode, 
+static int proc_statsdelta_open( struct inode *inode,
 				 struct file *file ) {
 	if (file->f_mode&FMODE_WRITE) {
 		return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR);
@@ -2331,7 +2361,7 @@
 	return proc_stats_rid_open(inode, file, RID_STATS);
 }
 
-static int proc_stats_rid_open( struct inode *inode, 
+static int proc_stats_rid_open( struct inode *inode,
 				struct file *file,
 				u16 rid ) {
 	struct proc_data *data;
@@ -2342,10 +2372,10 @@
 	int i, j;
 	int *vals = stats.vals;
 	MOD_INC_USE_COUNT;
-	
-	
+
+
 	dp = inode->u.generic_ip;
-	
+
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2354,11 +2384,11 @@
 		kfree (file->private_data);
 		return -ENOMEM;
 	}
-	
+
 	readStatsRid(apriv, &stats, rid);
-	
+
         j = 0;
-	for(i=0; (int)statsLabels[i]!=-1 && 
+	for(i=0; (int)statsLabels[i]!=-1 &&
 		    i*4<stats.len; i++){
 		if (!statsLabels[i]) continue;
 		if (j+strlen(statsLabels[i])+16>4096) {
@@ -2411,10 +2441,10 @@
 	Resp rsp;
 	char *line;
 	int need_reset = 0;
-	
+
 	if ( !data->writelen ) return;
 	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-	
+
 	disable_MAC(ai);
 	readConfigRid(ai, &config);
 
@@ -2442,7 +2472,7 @@
 				need_reset = 1;
 			}
 		}
-		
+
 /*** Radio status */
 		else if (!strncmp(line,"Radio: ", 7)) {
 			line += 7;
@@ -2455,15 +2485,15 @@
 /*** NodeName processing */
 		else if ( !strncmp( line, "NodeName: ", 10 ) ) {
 			int j;
-			
+
 			line += 10;
 			memset( config.nodeName, 0, 16 );
 /* Do the name, assume a space between the mode and node name */
 			for( j = 0; j < 16 && line[j] != '\n'; j++ ) {
 				config.nodeName[j] = line[j];
 			}
-		} 
-		
+		}
+
 /*** PowerMode processing */
 		else if ( !strncmp( line, "PowerMode: ", 11 ) ) {
 			line += 11;
@@ -2473,11 +2503,11 @@
 				config.powerSaveMode = POWERSAVE_PSP;
 			} else {
 				config.powerSaveMode = POWERSAVE_CAM;
-			}	
+			}
 		} else if ( !strncmp( line, "DataRates: ", 11 ) ) {
-			int v, i = 0, k = 0; /* i is index into line, 
+			int v, i = 0, k = 0; /* i is index into line,
 						k is index to rates */
-			
+
 			line += 11;
 			while((v = get_dec_u16(line, &i, 3))!=-1) {
 				config.rates[k++] = (u8)v;
@@ -2488,7 +2518,7 @@
 			int v, i = 0;
 			line += 9;
 			v = get_dec_u16(line, &i, i+3);
-			if ( v != -1 ) 
+			if ( v != -1 )
 				config.channelSet = (u16)v;
 		} else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
 			int v, i = 0;
@@ -2510,50 +2540,50 @@
 			}
 		} else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) {
 			int v, i = 0;
-			
+
 			line += 16;
 			v = get_dec_u16(line, &i, 3);
 			v = (v<0) ? 0 : ((v>255) ? 255 : v);
 			config.longRetryLimit = (u16)v;
 		} else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
 			int v, i = 0;
-			
+
 			line += 17;
 			v = get_dec_u16(line, &i, 3);
 			v = (v<0) ? 0 : ((v>255) ? 255 : v);
 			config.shortRetryLimit = (u16)v;
 		} else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
 			int v, i = 0;
-			
+
 			line += 14;
 			v = get_dec_u16(line, &i, 4);
 			v = (v<0) ? 0 : ((v>2312) ? 2312 : v);
 			config.rtsThres = (u16)v;
 		} else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
 			int v, i = 0;
-			
+
 			line += 16;
 			v = get_dec_u16(line, &i, 5);
 			v = (v<0) ? 0 : v;
 			config.txLifetime = (u16)v;
 		} else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
 			int v, i = 0;
-			
+
 			line += 16;
 			v = get_dec_u16(line, &i, 5);
 			v = (v<0) ? 0 : v;
 			config.rxLifetime = (u16)v;
 		} else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
-			config.txDiversity = 
+			config.txDiversity =
 				(line[13]=='l') ? 1 :
 				((line[13]=='r')? 2: 3);
 		} else if ( !strncmp( line, "RXDiversity: ", 13 ) ) {
-			config.rxDiversity = 
+			config.rxDiversity =
 				(line[13]=='l') ? 1 :
 				((line[13]=='r')? 2: 3);
 		} else if ( !strncmp( line, "FragThreshold: ", 15 ) ) {
 			int v, i = 0;
-			
+
 			line += 15;
 			v = get_dec_u16(line, &i, 4);
 			v = (v<256) ? 256 : ((v>2312) ? 2312 : v);
@@ -2605,11 +2635,11 @@
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	ConfigRid config;
 	int i;
-	
+
 	MOD_INC_USE_COUNT;
-	
+
 	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-	
+
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2626,10 +2656,10 @@
 	memset( data->wbuffer, 0, 2048 );
 	data->maxwritelen = 2048;
 	data->on_close = proc_config_on_close;
-	
+
 	readConfigRid(ai, &config);
-	
-	i = sprintf( data->rbuffer, 
+
+	i = sprintf( data->rbuffer,
 		     "Mode: %s\n"
 		     "Radio: %s\n"
 		     "NodeName: %-16s\n"
@@ -2637,9 +2667,9 @@
 		     "DataRates: %d %d %d %d %d %d %d %d\n"
 		     "Channel: %d\n"
 		     "XmitPower: %d\n",
-		     config.opmode == 0 ? "adhoc" : 
+		     config.opmode == 0 ? "adhoc" :
 		     config.opmode == 1 ? "ESS" :
-		     config.opmode == 2 ? "AP" : 
+		     config.opmode == 2 ? "AP" :
 		     config.opmode == 3 ? "AP RPTR" : "Error",
 		     ai->flags&FLAG_RADIO_OFF ? "off" : "on",
 		     config.nodeName,
@@ -2700,11 +2730,11 @@
 	SsidRid SSID_rid;
 	int i;
 	int offset = 0;
-	
+
 	if ( !data->writelen ) return;
-	
+
 	memset( &SSID_rid, 0, sizeof( SSID_rid ) );
-	
+
 	for( i = 0; i < 3; i++ ) {
 		int j;
 		for( j = 0; j+offset < data->writelen && j < 32 &&
@@ -2714,7 +2744,7 @@
 		if ( j == 0 ) break;
 		SSID_rid.ssids[i].len = j;
 		offset += j;
-		while( data->wbuffer[offset] != '\n' && 
+		while( data->wbuffer[offset] != '\n' &&
 		       offset < data->writelen ) offset++;
 		offset++;
 	}
@@ -2735,12 +2765,12 @@
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	APListRid APList_rid;
 	int i;
-	
+
 	if ( !data->writelen ) return;
-	
+
 	memset( &APList_rid, 0, sizeof(APList_rid) );
 	APList_rid.len = sizeof(APList_rid);
-	
+
 	for( i = 0; i < 4 && data->writelen >= (i+1)*6*3; i++ ) {
 		int j;
 		for( j = 0; j < 6*3 && data->wbuffer[j+i*6*3]; j++ ) {
@@ -2764,7 +2794,7 @@
 			int len ) {
 	int rc;
 	Resp rsp;
-	
+
 	disable_MAC(ai);
 	rc = PC4500_writerid(ai, rid, rid_data, len);
 	enable_MAC(ai, &rsp);
@@ -2816,7 +2846,7 @@
 		memcpy( wkr.mac, macaddr, 6 );
 		printk(KERN_INFO "Setting key %d\n", index);
 	}
-	
+
 	writeWepKeyRid(ai, &wkr, perm);
 	return 0;
 }
@@ -2832,11 +2862,11 @@
 	int j = 0;
 
 	memset(key, 0, sizeof(key));
-	
+
 	dp = (struct proc_dir_entry *) inode->u.generic_ip;
 	data = (struct proc_data *)file->private_data;
 	if ( !data->writelen ) return;
-	
+
 	if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' &&
 	    (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
 		index = data->wbuffer[0] - '0';
@@ -2873,11 +2903,11 @@
 	u16 lastindex;
 	int j=0;
 	int rc;
-	
+
 	MOD_INC_USE_COUNT;
-	
+
 	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-	
+
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2897,7 +2927,7 @@
 	}
 	memset( data->wbuffer, 0, 80 );
 	data->on_close = proc_wepkey_on_close;
-	
+
 	ptr = data->rbuffer;
 	strcpy(ptr, "No wep keys\n");
 	rc = readWepKeyRid(ai, &wkr, 1);
@@ -2927,9 +2957,9 @@
 	SsidRid SSID_rid;
 
 	MOD_INC_USE_COUNT;
-	
+
 	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-	
+
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2947,16 +2977,16 @@
 	}
 	memset( data->wbuffer, 0, 33*3 );
 	data->on_close = proc_SSID_on_close;
-	
+
 	readSsidRid(ai, &SSID_rid);
 	ptr = data->rbuffer;
 	for( i = 0; i < 3; i++ ) {
 		int j;
 		if ( !SSID_rid.ssids[i].len ) break;
-		for( j = 0; j < 32 && 
-			     j < SSID_rid.ssids[i].len && 
+		for( j = 0; j < 32 &&
+			     j < SSID_rid.ssids[i].len &&
 			     SSID_rid.ssids[i].ssid[j]; j++ ) {
-			*ptr++ = SSID_rid.ssids[i].ssid[j]; 
+			*ptr++ = SSID_rid.ssids[i].ssid[j];
 		}
 		*ptr++ = '\n';
 	}
@@ -2975,9 +3005,9 @@
 	APListRid APList_rid;
 
 	MOD_INC_USE_COUNT;
-	
+
 	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-	
+
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2995,7 +3025,7 @@
 	}
 	memset( data->wbuffer, 0, data->maxwritelen );
 	data->on_close = proc_APList_on_close;
-	
+
 	readAPListRid(ai, &APList_rid);
 	ptr = data->rbuffer;
 	for( i = 0; i < 4; i++ ) {
@@ -3027,11 +3057,11 @@
 	int rc;
 	/* If doLoseSync is not 1, we won't do a Lose Sync */
 	int doLoseSync = -1;
-        
+
 	MOD_INC_USE_COUNT;
-	
+
 	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-	
+
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -3044,15 +3074,15 @@
 	data->maxwritelen = 0;
 	data->wbuffer = 0;
 	data->on_close = 0;
-	
+
 	if (file->f_mode & FMODE_WRITE) {
 		if (!(file->f_mode & FMODE_READ)) {
 			Cmd cmd;
 			Resp rsp;
-                        
+
 			memset(&cmd, 0, sizeof(cmd));
 			cmd.cmd=CMD_LISTBSS;
-			issuecommand(ai, &cmd, &rsp);
+			lock_issuecommand(ai, &cmd, &rsp);
 			data->readlen = 0;
 			return 0;
 		}
@@ -3087,7 +3117,7 @@
 	return 0;
 }
 
-static int proc_close( struct inode *inode, struct file *file ) 
+static int proc_close( struct inode *inode, struct file *file )
 {
 	struct proc_data *data = (struct proc_data *)file->private_data;
 	if ( data->on_close != NULL ) data->on_close( inode, file );
@@ -3112,7 +3142,7 @@
 	struct net_device *dev = (struct net_device*)data;
 	struct airo_info *apriv = (struct airo_info *)dev->priv;
 	u16 linkstat = IN4500(apriv, LINKSTAT);
-	
+
 	if (linkstat != 0x400 ) {
 /* We don't have a link so try changing the authtype */
 		ConfigRid config = apriv->config;
@@ -3158,13 +3188,13 @@
 	if ( auto_wep ) {
 		struct airo_info *apriv=dev->priv;
 		struct timer_list *timer = &apriv->timer;
-			
+
 		timer->function = timer_func;
 		timer->data = (u_long)dev;
 		init_timer(timer);
 		apriv->authtype = AUTH_SHAREDKEY;
 	}
-		
+
 	node->dev = dev;
 	node->next = airo_devices;
 	airo_devices = node;
@@ -3177,14 +3207,14 @@
 	while( *p && ( (*p)->dev != dev ) )
 		p = &(*p)->next;
 	if ( *p && (*p)->dev == dev )
-		*p = (*p)->next; 
+		*p = (*p)->next;
 }
 
 #ifdef CONFIG_PCI
-static int __devinit airo_pci_probe(struct pci_dev *pdev, 
+static int __devinit airo_pci_probe(struct pci_dev *pdev,
 				    const struct pci_device_id *pent)
 {
-	pdev->driver_data = init_airo_card(pdev->irq, 
+	pdev->driver_data = init_airo_card(pdev->irq,
 					   pdev->resource[2].start, 0);
 	if (!pdev->driver_data) {
 		return -ENODEV;
@@ -3201,21 +3231,21 @@
 static int __init airo_init_module( void )
 {
 	int i, rc = 0, have_isa_dev = 0;
-	
+
 	airo_entry = create_proc_entry("aironet",
 				       S_IFDIR | airo_perm,
 				       proc_root_driver);
         airo_entry->uid = proc_uid;
         airo_entry->gid = proc_gid;
-	
+
 	for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
-		printk( KERN_INFO 
+		printk( KERN_INFO
 			"airo:  Trying to configure ISA adapter at irq=%d io=0x%x\n",
 			irq[i], io[i] );
 		if (init_airo_card( irq[i], io[i], 0 ))
 			have_isa_dev = 1;
 	}
-	
+
 #ifdef CONFIG_PCI
 	printk( KERN_INFO "airo:  Probing for PCI adapters\n" );
 	rc = pci_module_init(&airo_driver);
@@ -3274,7 +3304,11 @@
 	StatusRid status_rid;		/* Card status info */
 
 #ifdef CISCO_EXT
-	if (cmd != SIOCGIWPRIV && cmd != AIROIOCTL && cmd != AIROIDIFC)
+	if (cmd != SIOCGIWPRIV && cmd != AIROIOCTL && cmd != AIROIDIFC
+#ifdef AIROOLDIOCTL
+		&& cmd != AIROOLDIOCTL && cmd != AIROOLDIDIFC
+#endif
+		)
 #endif /* CISCO_EXT */
 	{
 		/* If the command read some stuff, we better get it out of
@@ -3851,7 +3885,7 @@
 
 			/* Hum... Should put the right values there */
 			range.max_qual.qual = 10;
-			range.max_qual.level = 0;
+			range.max_qual.level = 0x100 - 120;	/* -120 dBm */
 			range.max_qual.noise = 0;
 			range.sensitivity = 65535;
 
@@ -3908,7 +3942,7 @@
 			range.txpower_capa = IW_TXPOW_MWATT;
 #endif /* WIRELESS_EXT > 9 */
 #if WIRELESS_EXT > 10
-			range.we_version_source = 11;
+			range.we_version_source = 12;
 			range.we_version_compiled = WIRELESS_EXT;
 			range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
 			range.retry_flags = IW_RETRY_LIMIT;
@@ -3918,6 +3952,17 @@
 			range.min_r_time = 1024;
 			range.max_r_time = 65535 * 1024;
 #endif /* WIRELESS_EXT > 10 */
+#if WIRELESS_EXT > 11
+			/* Experimental measurements - boundary 11/5.5 Mb/s */
+			/* Note : with or without the (local->rssi), results
+			 * are somewhat different. - Jean II */
+			range.avg_qual.qual = 6;
+			if (local->rssi)
+				range.avg_qual.level = 186;	/* -70 dBm */
+			else
+				range.avg_qual.level = 176;	/* -80 dBm */
+			range.avg_qual.noise = 0;
+#endif /* WIRELESS_EXT > 11 */
 
 			if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
 				rc = -EFAULT;
@@ -3943,7 +3988,7 @@
 	}
 	break;
 
-	case SIOCSIWPOWER: 
+	case SIOCSIWPOWER:
 		if (wrq->u.power.disabled) {
 			if ((config.rmode & 0xFF) >= RXMODE_RFMON) {
 				rc = -EINVAL;
@@ -4022,7 +4067,7 @@
 				if (BSSList.index == 0xffff) break;
 			}
 			if (!i) {
-				for (i = 0; 
+				for (i = 0;
 				     i < min(IW_MAX_AP, 4) &&
 					     (status_rid.bssid[i][0]
 					      & status_rid.bssid[i][1]
@@ -4037,7 +4082,7 @@
 					      | status_rid.bssid[i][4]
 					      | status_rid.bssid[i][5]);
 				     i++) {
-					memcpy(s[i].sa_data, 
+					memcpy(s[i].sa_data,
 					       status_rid.bssid[i], 6);
 					s[i].sa_family = ARPHRD_ETHER;
 				}
@@ -4050,7 +4095,7 @@
 					rc = -EFAULT;
 			}
 			wrq->u.data.length = i;
-			if (copy_to_user(wrq->u.data.pointer, &s, 
+			if (copy_to_user(wrq->u.data.pointer, &s,
 					 sizeof(struct sockaddr)*i))
 				rc = -EFAULT;
 		}
@@ -4134,6 +4179,9 @@
 
 #ifdef CISCO_EXT
 	case AIROIDIFC:
+#ifdef AIROOLDIDIFC
+	case AIROOLDIDIFC:
+#endif
 	{
 		int val = AIROMAGIC;
 		aironet_ioctl com;
@@ -4143,9 +4191,12 @@
 			rc = -EFAULT;
 	}
 	break;
-  
+
 	case AIROIOCTL:
-		/* Get the command struct and hand it off for evaluation by 
+#ifdef AIROOLDIOCTL
+	case AIROOLDIOCTL:
+#endif
+		/* Get the command struct and hand it off for evaluation by
 		 * the proper subfunction
 		 */
 	{
@@ -4209,8 +4260,6 @@
  * TODO :
  *	o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs)
  *	o Find the noise level
- *	o Convert values to dBm
- *	o Fill out discard.misc with something interesting
  *
  * Jean
  */
@@ -4219,7 +4268,7 @@
 	struct airo_info *local = (struct airo_info*) dev->priv;
 	StatusRid status_rid;
 	StatsRid stats_rid;
-	int *vals = stats_rid.vals;
+	u32 *vals = stats_rid.vals;
 
 	/* Get stats out of the card */
 	readStatusRid(local, &status_rid);
@@ -4241,21 +4290,28 @@
 	 * specific problems */
 	local->wstats.discard.nwid = vals[56] + vals[57] + vals[58];/* SSID Mismatch */
 	local->wstats.discard.code = vals[6];/* RxWepErr */
-	local->wstats.discard.misc = vals[1] + vals[2] + vals[3] + vals[4] + vals[30] + vals[32];
+#if WIRELESS_EXT > 11
+	local->wstats.discard.fragment = vals[30];
+	local->wstats.discard.retries = vals[10];
+	local->wstats.discard.misc = vals[1] + vals[32];
+	local->wstats.miss.beacon = vals[34];
+#else /* WIRELESS_EXT > 11 */
+	local->wstats.discard.misc = vals[1] + vals[30] + vals[32];
+#endif /* WIRELESS_EXT > 11 */
 	return (&local->wstats);
 }
 #endif /* WIRELESS_EXT */
 
 #ifdef CISCO_EXT
 /*
- * This just translates from driver IOCTL codes to the command codes to 
- * feed to the radio's host interface. Things can be added/deleted 
- * as needed.  This represents the READ side of control I/O to 
+ * This just translates from driver IOCTL codes to the command codes to
+ * feed to the radio's host interface. Things can be added/deleted
+ * as needed.  This represents the READ side of control I/O to
  * the card
  */
 static int readrids(struct net_device *dev, aironet_ioctl *comp) {
 	unsigned short ridcode;
-	unsigned char iobuf[2048]; 
+	unsigned char iobuf[2048];
 
 	switch(comp->command)
 	{
@@ -4279,18 +4335,18 @@
 	case AIROGSTATSD32: ridcode = RID_STATSDELTA;   break;
 	case AIROGSTATSC32: ridcode = RID_STATS;        break;
 	default:
-		return -EINVAL;  
+		return -EINVAL;
 		break;
 	}
 
 	PC4500_readrid((struct airo_info *)dev->priv,ridcode,iobuf,sizeof(iobuf));
 	/* get the count of bytes in the rid  docs say 1st 2 bytes is it.
-	 * then return it to the user 
+	 * then return it to the user
 	 * 9/22/2000 Honor user given length
 	 */
 
 	if (copy_to_user(comp->data, iobuf,
-			 min_t(unsigned int, comp->len, sizeof(iobuf))))
+			 min((int)comp->len, (int)sizeof(iobuf))))
 		return -EFAULT;
 	return 0;
 }
@@ -4303,7 +4359,7 @@
 	int  ridcode;
 	Resp      rsp;
 	static int (* writer)(struct airo_info *, u16 rid, const void *, int);
-	unsigned char iobuf[2048]; 
+	unsigned char iobuf[2048];
 
 	/* Only super-user can write RIDs */
 	if (!capable(CAP_NET_ADMIN))
@@ -4324,7 +4380,7 @@
 	case AIROPWEPKEY:   ridcode = RID_WEP_TEMP; writer = PC4500_writerid;
 		break;
 
-		/* this is not really a rid but a command given to the card 
+		/* this is not really a rid but a command given to the card
 		 * same with MAC off
 		 */
 	case AIROPMACON:
@@ -4332,7 +4388,7 @@
 			return -EIO;
 		return 0;
 
-		/* 
+		/*
 		 * Evidently this code in the airo driver does not get a symbol
 		 * as disable_MAC. it's probably so short the compiler does not gen one.
 		 */
@@ -4350,7 +4406,7 @@
 		PC4500_readrid(dev->priv,ridcode,iobuf,sizeof(iobuf));
 
 		if (copy_to_user(comp->data, iobuf,
-				 min_t(unsigned int, comp->len, sizeof(iobuf))))
+				 min((int)comp->len, (int)sizeof(iobuf))))
 			return -EFAULT;
 		return 0;
 
@@ -4372,7 +4428,7 @@
  *****************************************************************************
  */
 
-/* 
+/*
  * Flash command switch table
  */
 
@@ -4435,10 +4491,10 @@
 
 #define FLASH_COMMAND  0x7e7e
 
-/* 
+/*
  * STEP 1)
- * Disable MAC and do soft reset on 
- * card. 
+ * Disable MAC and do soft reset on
+ * card.
  */
 
 int cmdreset(struct airo_info *ai) {
@@ -4448,7 +4504,7 @@
 		printk(KERN_INFO "Waitbusy hang before RESET\n");
 		return -EBUSY;
 	}
-    
+
 	OUT4500(ai,COMMAND,CMD_SOFTRESET);
 
 	set_current_state (TASK_UNINTERRUPTIBLE);
@@ -4462,7 +4518,7 @@
 }
 
 /* STEP 2)
- * Put the card in legendary flash 
+ * Put the card in legendary flash
  * mode
  */
 
@@ -4473,7 +4529,7 @@
 	OUT4500(ai, COMMAND,0x10);
 	set_current_state (TASK_UNINTERRUPTIBLE);
 	schedule_timeout (HZ/2); /* 500ms delay */
-  
+
 	if(!waitbusy(ai)) {
 		printk(KERN_INFO "Waitbusy hang after setflash mode\n");
 		return -EIO;
@@ -4481,8 +4537,8 @@
 	return 0;
 }
 
-/* Put character to SWS0 wait for dwelltime 
- * x 50us for  echo . 
+/* Put character to SWS0 wait for dwelltime
+ * x 50us for  echo .
  */
 
 int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
@@ -4493,7 +4549,7 @@
 
 	if(dwelltime == 0 )
 		dwelltime = 200;
-  
+
 	waittime=dwelltime;
 
 	/* Wait for busy bit d15 to go false indicating buffer empty */
@@ -4531,7 +4587,7 @@
 
 	do {
 		rchar = IN4500(ai,SWS1);
-    
+
 		if(dwelltime && !(0x8000 & rchar)){
 			dwelltime -= 10;
 			mdelay(10);
@@ -4551,9 +4607,9 @@
 	return -EIO;
 }
 
-/* 
- * Transfer 32k of firmware data from user buffer to our buffer and 
- * send to the card 
+/*
+ * Transfer 32k of firmware data from user buffer to our buffer and
+ * send to the card
  */
 
 int flashputbuf(struct airo_info *ai){
@@ -4566,7 +4622,7 @@
 	for(nwords=0;nwords != FLASHSIZE / 2;nwords++){
 		OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff);
 	}
-  
+
 	OUT4500(ai,SWS0,0x8000);
 
 	return 0;
@@ -4628,7 +4684,7 @@
     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-    POSSIBILITY OF SUCH DAMAGE.    
+    POSSIBILITY OF SUCH DAMAGE.
 */
 
 module_init(airo_init_module);
diff -u --recursive --new-file v2.4.12/linux/drivers/net/wireless/airport.c linux/drivers/net/wireless/airport.c
--- v2.4.12/linux/drivers/net/wireless/airport.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/net/wireless/airport.c	Wed Oct 17 14:37:01 2001
@@ -43,6 +43,7 @@
 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
 MODULE_LICENSE("Dual MPL/GPL");
+EXPORT_NO_SYMBOLS;
 
 typedef struct dldwd_card {
 	struct device_node* node;
diff -u --recursive --new-file v2.4.12/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- v2.4.12/linux/drivers/net/yellowfin.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/yellowfin.c	Fri Oct 19 08:32:28 2001
@@ -38,10 +38,13 @@
 	* Fix three endian-ness bugs
 	* Support dual function SYM53C885E ethernet chip
 	
+	LK1.1.5 (val@nmt.edu):
+	* Fix forced full-duplex bug I introduced
+	
 */
 
 #define DRV_NAME	"yellowfin"
-#define DRV_VERSION	"1.05+LK1.1.3"
+#define DRV_VERSION	"1.05+LK1.1.5"
 #define DRV_RELDATE	"May 10, 2001"
 
 #define PFX DRV_NAME ": "
@@ -256,7 +259,7 @@
 };
 enum capability_flags {
 	HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16,
-	HasMACAddrBug=32,			/* Only on early revs.  */
+	HasMACAddrBug=32, DontUseEeprom=64, /* Only on early revs.  */
 };
 /* The PCI I/O space extent. */
 #define YELLOWFIN_SIZE 0x100
@@ -282,7 +285,7 @@
 	 PCI_IOTYPE, YELLOWFIN_SIZE,
 	 FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug},
 	{"Symbios SYM83C885", { 0x07011000, 0xffffffff},
-	 PCI_IOTYPE, YELLOWFIN_SIZE, HasMII | IsGigabit | FullTxStatus },
+	 PCI_IOTYPE, YELLOWFIN_SIZE, HasMII | DontUseEeprom },
 	{0,},
 };
 
@@ -453,7 +456,7 @@
 #endif
 	irq = pdev->irq;
 
-	if (drv_flags & IsGigabit)
+	if (drv_flags & DontUseEeprom)
 		for (i = 0; i < 6; i++)
 			dev->dev_addr[i] = inb(ioaddr + StnAddr + i);
 	else {
diff -u --recursive --new-file v2.4.12/linux/drivers/nubus/nubus_syms.c linux/drivers/nubus/nubus_syms.c
--- v2.4.12/linux/drivers/nubus/nubus_syms.c	Sat Sep  4 13:08:32 1999
+++ linux/drivers/nubus/nubus_syms.c	Thu Oct 11 09:18:31 2001
@@ -12,6 +12,8 @@
 EXPORT_SYMBOL(nubus_proc_detach_device);
 #endif
 
+MODULE_LICENSE("GPL");
+
 EXPORT_SYMBOL(nubus_find_device);
 EXPORT_SYMBOL(nubus_find_type);
 EXPORT_SYMBOL(nubus_find_slot);
diff -u --recursive --new-file v2.4.12/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c
--- v2.4.12/linux/drivers/parport/ieee1284_ops.c	Thu Oct 11 08:02:26 2001
+++ linux/drivers/parport/ieee1284_ops.c	Thu Oct 11 07:53:24 2001
@@ -362,7 +362,7 @@
 	} else {
 		DPRINTK (KERN_DEBUG "%s: ECP direction: failed to reverse\n",
 			 port->name);
-		port->ieee1284.phase = IEEE1284_PH_DIR_UNKNOWN;
+		port->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
 	}
 
 	return retval;
@@ -394,7 +394,7 @@
 		DPRINTK (KERN_DEBUG
 			 "%s: ECP direction: failed to switch forward\n",
 			 port->name);
-		port->ieee1284.phase = IEEE1284_PH_DIR_UNKNOWN;
+		port->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
 	}
 
 
diff -u --recursive --new-file v2.4.12/linux/drivers/parport/parport_amiga.c linux/drivers/parport/parport_amiga.c
--- v2.4.12/linux/drivers/parport/parport_amiga.c	Tue May 22 19:54:04 2001
+++ linux/drivers/parport/parport_amiga.c	Thu Oct 11 09:18:31 2001
@@ -298,6 +298,7 @@
 MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
 MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
 MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port");
+MODULE_LICENSE("GPL");
 
 module_init(parport_amiga_init)
 module_exit(parport_amiga_exit)
diff -u --recursive --new-file v2.4.12/linux/drivers/parport/parport_atari.c linux/drivers/parport/parport_atari.c
--- v2.4.12/linux/drivers/parport/parport_atari.c	Mon Nov 27 17:11:26 2000
+++ linux/drivers/parport/parport_atari.c	Thu Oct 11 09:18:31 2001
@@ -249,6 +249,7 @@
 MODULE_AUTHOR("Andreas Schwab");
 MODULE_DESCRIPTION("Parport Driver for Atari builtin Port");
 MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port");
+MODULE_LICENSE("GPL");
 
 int
 init_module(void)
diff -u --recursive --new-file v2.4.12/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.4.12/linux/drivers/parport/parport_pc.c	Thu Oct 11 08:02:26 2001
+++ linux/drivers/parport/parport_pc.c	Thu Oct 11 09:18:31 2001
@@ -2884,6 +2884,8 @@
 
 MODULE_AUTHOR("Phil Blundell, Tim Waugh, others");
 MODULE_DESCRIPTION("PC-style parallel port driver");
+MODULE_LICENSE("GPL");
+
 MODULE_PARM_DESC(io, "Base I/O address (SPP regs)");
 MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
 MODULE_PARM_DESC(io_hi, "Base I/O address (ECR)");
diff -u --recursive --new-file v2.4.12/linux/drivers/pci/gen-devlist.c linux/drivers/pci/gen-devlist.c
--- v2.4.12/linux/drivers/pci/gen-devlist.c	Mon Oct 16 12:56:50 2000
+++ linux/drivers/pci/gen-devlist.c	Thu Oct 11 09:18:31 2001
@@ -68,6 +68,7 @@
 							bra[-1] = 0;
 						if (vendor_len + strlen(c) + 1 > MAX_NAME_SIZE) {
 							fprintf(stderr, "Line %d: Device name too long\n", lino);
+							fprintf(stderr, "%s\n", c);
 							return 1;
 						}
 					}
diff -u --recursive --new-file v2.4.12/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.4.12/linux/drivers/pci/pci.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/pci/pci.c	Fri Oct 12 15:35:53 2001
@@ -834,17 +834,27 @@
 }
 
 int
-pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask)
+pci_set_dma_mask(struct pci_dev *dev, u64 mask)
 {
-    if(! pci_dma_supported(dev, mask))
-        return -EIO;
+	if (!pci_dma_supported(dev, mask))
+		return -EIO;
 
-    dev->dma_mask = mask;
+	dev->dma_mask = mask;
 
-    return 0;
+	return 0;
 }
     
+int
+pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+	if (!pci_dac_dma_supported(dev, mask))
+		return -EIO;
+
+	dev->dma_mask = mask;
 
+	return 0;
+}
+    
 /*
  * Translate the low bits of the PCI base
  * to the resource type
@@ -1678,7 +1688,8 @@
 	if (!page)
 		return 0;
 	page->vaddr = pci_alloc_consistent (pool->dev,
-				pool->allocation, &page->dma);
+					    pool->allocation,
+					    &page->dma);
 	if (page->vaddr) {
 		memset (page->bitmap, 0xff, mapsize);	// bit set == free
 		if (pool->flags & SLAB_POISON)
@@ -1864,14 +1875,14 @@
 	if ((page = pool_find_page (pool, dma)) == 0) {
 		printk (KERN_ERR "pci_pool_free %s/%s, %p/%x (bad dma)\n",
 			pool->dev ? pool->dev->slot_name : NULL,
-			pool->name, vaddr, dma);
+			pool->name, vaddr, (int) (dma & 0xffffffff));
 		return;
 	}
 #ifdef	CONFIG_PCIPOOL_DEBUG
 	if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
 		printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%x\n",
 			pool->dev ? pool->dev->slot_name : NULL,
-			pool->name, vaddr, dma);
+			pool->name, vaddr, (int) (dma & 0xffffffff));
 		return;
 	}
 #endif
@@ -1956,6 +1967,7 @@
 EXPORT_SYMBOL(pci_find_subsys);
 EXPORT_SYMBOL(pci_set_master);
 EXPORT_SYMBOL(pci_set_dma_mask);
+EXPORT_SYMBOL(pci_dac_set_dma_mask);
 EXPORT_SYMBOL(pci_assign_resource);
 EXPORT_SYMBOL(pci_register_driver);
 EXPORT_SYMBOL(pci_unregister_driver);
diff -u --recursive --new-file v2.4.12/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids
--- v2.4.12/linux/drivers/pci/pci.ids	Tue Oct  9 17:06:52 2001
+++ linux/drivers/pci/pci.ids	Fri Oct 19 08:32:28 2001
@@ -106,9 +106,16 @@
 	0012  53c895a
 	0020  53c1010 Ultra3 SCSI Adapter
 	0021  53c1010 66MHz  Ultra3 SCSI Adapter
+	0030  53c1030
+	0040  53c1035
 	008f  53c875J
 		1092 8000  FirePort 40 SCSI Controller
 		1092 8760  FirePort 40 Dual SCSI Host Adapter
+	0621  FC909
+	0622  FC929
+	0623  FC929 LAN
+	0624  FC919
+	0625  FC919 LAN
 	0701  83C885
 	0702  Yellowfin G-NIC gigabit ethernet
 		1318 0000  PEI100X
@@ -2085,6 +2092,7 @@
 110a  Siemens Nixdorf AG
 	0002  Pirahna 2-port
 	0005  Tulip controller, power management, switch extender
+	2102  DSCC4 WAN adapter
 	4942  FPGA I-Bus Tracer for MBD
 	6120  SZB6120
 110b  Chromatic Research Inc.
@@ -2310,7 +2318,7 @@
 		1148 5841  FDDI SK-5841 (SK-NET FDDI-FP64)
 		1148 5843  FDDI SK-5843 (SK-NET FDDI-LP64)
 		1148 5844  FDDI SK-5844 (SK-NET FDDI-LP64 DAS)
-	4200  Token ring adaptor
+	4200  Token Ring adapter
 	4300  Gigabit Ethernet
 		1148 9821  SK-9821 (1000Base-T single link)
 		1148 9822  SK-9822 (1000Base-T dual link)
@@ -3107,34 +3115,104 @@
 	0396  SDRAM controller
 	0397  BIOS scratchpad
 127a  Rockwell International
-	1002  HCF 56k V90 FaxModem
-		127a 1002  HCF 56k V90 Modem
-	1003  HCF 56k V90 FaxModem
-		127a 1003  PCI56RX Modem
-		13df 1003  PCI56RX Modem
-	1004  HCF 56k V90 FaxModem
-	1005  HCF 56k V90 FaxModem
-		122d 4008  MDP3858SP-A SVD Modem
-		127a 1005  PCI56RVP Modem 
-		13df 1005  PCI56RVP Modem 
-		1436 1005  WS-5614PS3G
-	1025  HCF 56k PCI Modem
-		127a 1025  HCF 56k PCI Modem
+	1002  HCF 56k Data/Fax Modem
+		122d 4002  HPG / MDP3858-U # Aztech
+		122d 4005  MDP3858-E # Aztech
+		122d 4007  MDP3858-A/-NZ # Aztech
+		122d 4012  MDP3858-SA # Aztech
+		122d 4017  MDP3858-W # Aztech
+		122d 4018  MDP3858-W # Aztech
+	1003  HCF 56k Data/Fax Modem
+		0e11 b0bc  229-DF Zephyr # Compaq
+		0e11 b114  229-DF Cheetah # Compaq
+		1033 802b  229-DF # NEC
+		13df 1003  PCI56RX Modem # E-Tech Inc
+		13e0 0117  IBM # GVC
+		13e0 0147  IBM # GVC
+		13e0 0197  IBM # GVC
+		13e0 01c7  IBM # GVC
+		13e0 01f7  IBM # GVC
+		1436 1003  IBM # CIS
+		1436 1103  IBM # CIS
+		1436 1602  Compaq 229-DF Ducati
+	1004  HCF 56k Data/Fax/Voice Modem
+		10cf 1059  Fujitsu 229-DFRT
+	1005  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+		1033 8029  229-DFSV # NEC
+		1033 8054  Modem # NEC
+		10cf 103c  Fujitsu
+		10cf 1055  Fujitsu 229-DFSV
+		10cf 1056  Fujitsu 229-DFSV
+		122d 4003  MDP3858SP-U # Aztech
+		122d 4006  Packard Bell MDP3858V-E # Aztech
+		122d 4008  MDP3858SP-A/SP-NZ # Aztech
+		122d 4009  MDP3858SP-E # Aztech
+		122d 4010  MDP3858V-U # Aztech
+		122d 4011  MDP3858SP-SA # Aztech
+		122d 4013  MDP3858V-A/V-NZ # Aztech
+		122d 4015  MDP3858SP-W # Aztech
+		122d 4016  MDP3858V-W # Aztech
+		122d 4019  MDP3858V-SA # Aztech
+		13df 1005  PCI56RVP Modem  # E-Tech Inc
+		13e0 0187  IBM # GVC
+		13e0 01a7  IBM # GVC
+		13e0 01b7  IBM # GVC
+		13e0 01d7  IBM # GVC
+		1436 1005  IBM # CIS
+		1436 1105  IBM # CIS
+	1023  HCF 56k Data/Fax Modem
+		122d 4020  Packard Bell MDP3858-WE # Aztech
+		122d 4023  MDP3858-UE # Aztech
+		13e0 0247  IBM # GVC
+		13e0 0297  IBM # GVC
+		13e0 02c7  IBM # GVC
+		1436 1203  IBM # CIS
+		1436 1303  IBM # CIS
+	1024  HCF 56k Data/Fax/Voice Modem
+	1025  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+		10cf 106a  Fujitsu 235-DFSV
+		122d 4021  Packard Bell MDP3858V-WE # Aztech
+		122d 4022  MDP3858SP-WE # Aztech
+		122d 4024  MDP3858V-UE # Aztech
+		122d 4025  MDP3858SP-UE # Aztech
 	1026  HCF 56k PCI Speakerphone Modem
-		127a 1026  HCF 56k PCI Speakerphone Modem
 	1035  HCF 56k PCI Speakerphone Modem
-		127a 1035  HCF 56k PCI Speakerphone Modem
-	1085  Volcano HCF 56k PCI Modem
-		127a 1085  Volcano HCF 56k PCI Modem
-	2005  HCF 56k V90 FaxModem
-		127a 2005  Conexant SoftK56 Speakerphone Modem
-	2015  Conexant SoftK56 Speakerphone Modem
-		127a 2015  Conexant SoftK56 Speakerphone Modem
-		14c8 2115  Conexant SoftK56 Speakerphone Modem
+	1085  HCF 56k Volcano PCI Modem
+	2005  HCF 56k Data/Fax Modem
+		104d 8044  229-DFSV # Sony
+		104d 8045  229-DFSV # Sony
+		104d 8055  PBE/Aztech 235W-DFSV # Sony
+		104d 8056  235-DFSV # Sony
+		104d 805a  Modem # Sony
+		104d 805f  Modem # Sony
+		104d 8074  Modem # Sony
+	2013  HSF 56k Data/Fax Modem
+		1179 0001  Modem # Toshiba
+		1179 ff00  Modem # Toshiba
+	2014  HSF 56k Data/Fax/Voice Modem
+		10cf 1057  Fujitsu Citicorp III
+		122d 4050  MSP3880-U # Aztech
+		122d 4055  MSP3880-W # Aztech
+	2015  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+		10cf 1063  Fujitsu
+		10cf 1064  Fujitsu
+		1468 2015  Fujitsu
+	2016  HSF 56k Data/Fax/Voice/Spkp Modem
+		122d 4051  MSP3880V-W # Aztech
+		122d 4052  MSP3880SP-W # Aztech
+		122d 4054  MSP3880V-U # Aztech
+		122d 4056  MSP3880SP-U # Aztech
+		122d 4057  MSP3880SP-A # Aztech
+	4311  Riptide HSF 56k PCI Modem
+		127a 4311  Ring Modular? Riptide HSF RT HP Dom
+		13e0 0210  HP-GVC
 	4320  Riptide PCI Audio Controller
 		1235 4320  Riptide PCI Audio Controller
 	4321  Riptide HCF 56k PCI Modem
-		1235 4321  Riptide HCF 56k PCI Modem
+		1235 4321  Hewlett Packard DF
+		1235 4324  Hewlett Packard DF
+		13e0 0210  Hewlett Packard DF
+		144d 2321  Riptide # Samsung
 	4322  Riptide PCI Game Controller
 		1235 4322  Riptide PCI Game Controller
 	8234  RapidFire 616X ATM155 Adapter
@@ -3884,6 +3962,7 @@
 148b  INNOMEDIALOGIC Inc.
 148c  C.P. Technology Co. Ltd
 148d  DIGICOM Systems, Inc.
+	1003  HCF 56k Data/Fax Modem
 148e  OSI Plus Corporation
 148f  Plant Equipment, Inc.
 1490  Stone Microsystems PTY Ltd.
@@ -4009,6 +4088,7 @@
 		14e4 0007  NetXtreme BCM5701 1000BaseSX
 		14e4 0008  NetXtreme BCM5701 1000BaseTX
 		14e4 8008  NetXtreme BCM5701 1000BaseTX
+	5820  BCM5820 Crypto Accelerator
 14e5  Pixelfusion Ltd
 14e6  SHINING Technology Inc
 14e7  3CX
@@ -4021,30 +4101,123 @@
 14ee  MASPRO KENKOH Corp
 14ef  CARRY Computer ENG. CO Ltd
 14f0  CANON RESEACH CENTRE FRANCE
-14f1  CONEXANT
-	1033  56K Winmodem
-		13e0 02b0  56K Winmodem
-	1035  PCI Modem Enumerator
-	2003  SoftK56 Winmodem
-		14f1 2003  SoftK56 Winmodem
-	2004  SoftK56 RemoteTAM Winmodem
-		14f1 2004  SoftK56 RemoteTAM Winmodem
-	2005  SoftK56 Speakerphone Winmodem
-		14f1 2005  SoftK56 Speakerphone Winmodem
-	2006  SoftK56 Speakerphone Winmodem
-		14f1 2006  SoftK56 Speakerphone Winmodem
-	2013  HSP MicroModem 56K
-		14f1 2013  SoftK56 Winmodem
-	2014  SoftK56 RemoteTAM Winmodem
-		144f 101c  SoftK56 RemoteTAM Winmodem
-		144f 2014  SoftK56 RemoteTAM Winmodem
-	2015  SoftK56 Speakerphone Winmodem
-		14c8 2115  SoftK56 Speakerphone Winmodem
-		14f1 2015  SoftK56 Speakerphone Winmodem
-	2016  SoftK56 Speakerphone Winmodem
-		14f1 2016  SoftK56 Speakerphone Winmodem
-	2443  SoftK56 Speakerphone Winmodem
-		14f1 2443  SoftK56 Speakerphone Winmodem
+14f1  Conexant
+	1033  HCF 56k Data/Fax Modem
+		1033 8077  NEC
+		122d 4027  Dell Zeus - MDP3880-W(B) Data Fax Modem # Aztech
+		122d 4030  Dell Mercury - MDP3880-U(B) Data Fax Modem # Aztech
+		122d 4034  Dell Thor - MDP3880-W(U) Data Fax Modem # Aztech
+		13e0 020d  Dell Copper
+		13e0 020e  Dell Silver
+		13e0 0261  IBM # GVC
+		13e0 0290  Compaq Goldwing
+		13e0 02a0  IBM # GVC
+		13e0 02b0  IBM # GVC
+		13e0 02c0  Compaq Scooter
+		13e0 02d0  IBM # GVC
+		144f 1500  IBM P85-DF # Askey
+		144f 1501  IBM P85-DF # Askey
+		144f 150a  IBM P85-DF # Askey
+		144f 150b  IBM P85-DF Low Profile # Askey
+		144f 1510  IBM P85-DF Low Profile # Askey
+	1034  HCF 56k Data/Fax/Voice Modem
+	1035  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+		10cf 1098  Fujitsu P85-DFSV
+	1036  HCF 56k Data/Fax/Voice/Spkp Modem
+		122d 4029  MDP3880SP-W # Aztech
+		122d 4031  MDP3880SP-U # Aztech
+		13e0 0209  Dell Titanium
+		13e0 020a  Dell Graphite
+		13e0 0260  Gateway Red Owl
+		13e0 0270  Gateway White Horse
+	1052  HCF 56k Data/Fax Modem (Worldwide)
+	1053  HCF 56k Data/Fax Modem (Worldwide)
+	1054  HCF 56k Data/Fax/Voice Modem (Worldwide)
+	1055  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (Worldwide)
+	1056  HCF 56k Data/Fax/Voice/Spkp Modem (Worldwide)
+	1057  HCF 56k Data/Fax/Voice/Spkp Modem (Worldwide)
+	1059  HCF 56k Data/Fax/Voice Modem (Worldwide)
+	1063  HCF 56k Data/Fax Modem
+	1064  HCF 56k Data/Fax/Voice Modem
+	1065  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+	1066  HCF 56k Data/Fax/Voice/Spkp Modem
+		122d 4033  Dell Athena - MDP3900V-U # Aztech
+	1433  HCF 56k Data/Fax Modem
+	1434  HCF 56k Data/Fax/Voice Modem
+	1435  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+	1436  HCF 56k Data/Fax Modem
+	1453  HCF 56k Data/Fax Modem
+		13e0 0240  IBM # GVC
+		13e0 0250  IBM # GVC
+		144f 1502  IBM P95-DF # Askey
+		144f 1503  IBM P95-DF # Askey
+	1454  HCF 56k Data/Fax/Voice Modem
+	1455  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+	1456  HCF 56k Data/Fax/Voice/Spkp Modem
+		122d 4035  Dell Europa - MDP3900V-W # Aztech
+		122d 4302  MP3930V-W(C) MiniPCI # Aztech
+	1803  HCF 56k Modem
+		0e11 0023 623-LAN Grizzly # Compaq
+		0e11 0043 623-LAN Yogi # Compaq
+	1815  HCF 56k Modem
+		0e11 0022  Grizzly # Compaq
+		0e11 0042  Yogi # Compaq
+	2003  HSF 56k Data/Fax Modem
+	2004  HSF 56k Data/Fax/Voice Modem
+	2005  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+	2006  HSF 56k Data/Fax/Voice/Spkp Modem
+	2013  HSF 56k Data/Fax Modem
+		0e11 b195  Bear # Compaq
+		0e11 b196  Seminole 1 # Compaq
+		0e11 b1be  Seminole 2 # Compaq
+		1025 8013  Acer
+		1033 809d  NEC
+		1033 80bc  NEC
+		155d 6793  HP
+		155d 8850  E Machines
+	2014  HSF 56k Data/Fax/Voice Modem
+	2015  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+	2016  HSF 56k Data/Fax/Voice/Spkp Modem
+	2043  HSF 56k Data/Fax Modem (Worldwide SmartDAA)
+	2044  HSF 56k Data/Fax/Voice Modem (Worldwide SmartDAA)
+	2045  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (Worldwide SmartDAA)
+	2046  HSF 56k Data/Fax/Voice/Spkp Modem (Worldwide SmartDAA)
+	2063  HSF 56k Data/Fax Modem (SmartDAA)
+	2064  HSF 56k Data/Fax/Voice Modem (SmartDAA)
+	2065  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (SmartDAA)
+	2066  HSF 56k Data/Fax/Voice/Spkp Modem (SmartDAA)
+	2093  HSF 56k Modem
+		155d 2f07  Legend
+	2143  HSF 56k Data/Fax/Cell Modem (Mobile Worldwide SmartDAA)
+	2144  HSF 56k Data/Fax/Voice/Cell Modem (Mobile Worldwide SmartDAA)
+	2145  HSF 56k Data/Fax/Voice/Spkp (w/HS)/Cell Modem (Mob WW SmartDAA)
+	2146  HSF 56k Data/Fax/Voice/Spkp/Cell Modem (Mobile Worldwide SmartDAA)
+	2163  HSF 56k Data/Fax/Cell Modem (Mobile SmartDAA)
+	2164  HSF 56k Data/Fax/Voice/Cell Modem (Mobile SmartDAA)
+	2165  HSF 56k Data/Fax/Voice/Spkp (w/Handset)/Cell Modem (Mobile SmartDAA)
+	2166  HSF 56k Data/Fax/Voice/Spkp/Cell Modem (Mobile SmartDAA)
+	2343  HSF 56k Data/Fax CardBus Modem (Mobile Worldwide SmartDAA)
+	2344  HSF 56k Data/Fax/Voice CardBus Modem (Mobile Worldwide SmartDAA)
+	2345  HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob WW SmartDAA)
+	2346  HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mobile Worldwide SmartDAA)
+	2363  HSF 56k Data/Fax CardBus Modem (Mobile SmartDAA)
+	2364  HSF 56k Data/Fax/Voice CardBus Modem (Mobile SmartDAA)
+	2365  HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob SmartDAA)
+	2366  HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mobile SmartDAA)
+	2443  HSF 56k Data/Fax Modem (Mobile Worldwide SmartDAA)
+		104d 8075  Modem # Sony
+		104d 8083  Modem # Sony
+		104d 8097  Modem # Sony
+	2444  HSF 56k Data/Fax/Voice Modem (Mobile Worldwide SmartDAA)
+	2445  HSF 56k Data/Fax/Voice/Spkp (w/HS) Modem (Mobile WW SmartDAA)
+	2446  HSF 56k Data/Fax/Voice/Spkp Modem (Mobile Worldwide SmartDAA)
+	2463  HSF 56k Data/Fax Modem (Mobile SmartDAA)
+	2464  HSF 56k Data/Fax/Voice Modem (Mobile SmartDAA)
+	2465  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (Mobile SmartDAA)
+	2466  HSF 56k Data/Fax/Voice/Spkp Modem (Mobile SmartDAA)
+	2f00  HSF 56k HSFi Modem
+		13e0 8d84  IBM HSFi V.90
+		13e0 8d85  Compaq Stinger
 14f2  MOBILITY Electronics
 14f3  BROADLOGIC
 14f4  TOKYO Electronic Industry CO Ltd
@@ -4659,7 +4832,7 @@
 		0e11 b0c6  Embedded NC3120 with Wake on LAN
 		0e11 b0c7  Embedded NC3121
 		0e11 b0d7  NC3121 with Wake on LAN
-		0e11 b0dd  NC3131
+		0e11 b0dd  NC3131 (82558B)
 		0e11 b0de  NC3132
 		0e11 b0e1  NC3133
 		0e11 b144  NC3123 (82559)
@@ -4727,6 +4900,8 @@
 	1a21  82840 840 (Carmel) Chipset Host Bridge (Hub A)
 	1a23  82840 840 (Carmel) Chipset AGP Bridge
 	1a24  82840 840 (Carmel) Chipset PCI Bridge (Hub B)
+	1a30  82845 845 (Brookdale) Chipset Host Bridge
+	1a31  82845 845 (Brookdale) Chipset AGP Bridge
 	2410  82801AA ISA Bridge (LPC)
 	2411  82801AA IDE
 	2412  82801AA USB
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/Makefile linux/drivers/pcmcia/Makefile
--- v2.4.12/linux/drivers/pcmcia/Makefile	Mon Mar 26 15:36:30 2001
+++ linux/drivers/pcmcia/Makefile	Thu Oct 11 09:43:29 2001
@@ -53,10 +53,33 @@
   endif
 endif
 
+obj-$(CONFIG_PCMCIA_SA1100)	+= sa1100_cs.o
+
+sa1100_cs-objs-y				:= sa1100_generic.o
+sa1100_cs-objs-$(CONFIG_SA1100_ASSABET)		+= sa1100_assabet.o
+sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET)	+= sa1100_neponset.o
+sa1100_cs-objs-$(CONFIG_SA1100_H3600)		+= sa1100_h3600.o
+sa1100_cs-objs-$(CONFIG_SA1100_CERF)		+= sa1100_cerf.o
+sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT)	+= sa1100_graphicsclient.o
+sa1100_cs-objs-$(CONFIG_SA1100_XP860)		+= sa1100_xp860.o
+sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN)	+= sa1100_pangolin.o
+sa1100_cs-objs-$(CONFIG_SA1100_YOPY)		+= sa1100_yopy.o
+sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD)	+= sa1100_freebird.o
+sa1100_cs-objs-$(CONFIG_SA1100_PFS168)		+= sa1100_pfs168.o
+sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720)	+= sa1100_jornada720.o
+sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET)	+= sa1100_flexanet.o
+sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD)		+= sa1100_simpad.o
+sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER)	+= sa1100_graphicsmaster.o
+sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o
+sa1100_cs-objs-$(CONFIG_SA1100_STORK)		+= sa1100_stork.o
+
 include $(TOPDIR)/Rules.make
 
 pcmcia_core.o:  $(pcmcia_core-objs)
 	$(LD) $(LD_RFLAG) -r -o $@ $(pcmcia_core-objs)
+
+sa1100_cs.o: $(sa1100_cs-objs-y)
+	$(LD) -r -o $@ $(sa1100_cs-objs-y)
 
 yenta_socket.o: $(yenta_socket-objs)
 	$(LD) $(LD_RFLAG) -r -o $@ $(yenta_socket-objs)
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- v2.4.12/linux/drivers/pcmcia/cs.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/pcmcia/cs.c	Thu Oct 11 09:43:29 2001
@@ -789,6 +789,10 @@
 	      *base, align);
 	align = 0;
     }
+    if ((s->cap.features & SS_CAP_STATIC_MAP) && s->cap.io_offset) {
+	*base = s->cap.io_offset | (*base & 0x0fff);
+	return 0;
+    }
     /* Check for an already-allocated window that must conflict with
        what was asked for.  It is a hack because it does not catch all
        potential conflicts, just the most obvious ones. */
@@ -833,7 +837,8 @@
 			     ioaddr_t num)
 {
     int i;
-    release_region(base, num);
+    if(!(s->cap.features & SS_CAP_STATIC_MAP))
+	release_region(base, num);
     for (i = 0; i < MAX_IO_WIN; i++) {
 	if ((s->io[i].BasePort <= base) &&
 	    (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
@@ -1623,7 +1628,8 @@
     s->state &= ~SOCKET_WIN_REQ(win->index);
 
     /* Release system memory */
-    release_mem_region(win->base, win->size);
+    if(!(s->cap.features & SS_CAP_STATIC_MAP))
+	release_mem_region(win->base, win->size);
     win->handle->state &= ~CLIENT_WIN_REQ(win->index);
 
     win->magic = 0;
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100.h linux/drivers/pcmcia/sa1100.h
--- v2.4.12/linux/drivers/pcmcia/sa1100.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100.h	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,202 @@
+/*======================================================================
+
+    Device driver for the PCMCIA control functionality of StrongARM
+    SA-1100 microprocessors.
+
+    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 John G. Dorsey
+    <john+@cs.cmu.edu>.  Portions created by John G. Dorsey are
+    Copyright (C) 1999 John G. Dorsey.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU 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.
+    
+======================================================================*/
+
+#if !defined(_PCMCIA_SA1100_H)
+# define _PCMCIA_SA1100_H
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+#include <asm/arch/pcmcia.h>
+
+
+/* MECR: Expansion Memory Configuration Register
+ * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24)
+ *
+ * MECR layout is:  
+ *
+ *   FAST1 BSM1<4:0> BSA1<4:0> BSIO1<4:0> FAST0 BSM0<4:0> BSA0<4:0> BSIO0<4:0>
+ *
+ * (This layout is actually true only for the SA-1110; the FASTn bits are
+ * reserved on the SA-1100.)
+ */
+
+#define MECR_SOCKET_0_SHIFT (0)
+#define MECR_SOCKET_1_SHIFT (16)
+
+#define MECR_BS_MASK        (0x1f)
+#define MECR_FAST_MODE_MASK (0x01)
+
+#define MECR_BSIO_SHIFT (0)
+#define MECR_BSA_SHIFT  (5)
+#define MECR_BSM_SHIFT  (10)
+#define MECR_FAST_SHIFT (15)
+
+#define MECR_SET(mecr, sock, shift, mask, bs) \
+((mecr)=((mecr)&~(((mask)<<(shift))<<\
+                  ((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT)))|\
+        (((bs)<<(shift))<<((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT)))
+
+#define MECR_GET(mecr, sock, shift, mask) \
+((((mecr)>>(((sock)==0)?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT))>>\
+ (shift))&(mask))
+
+#define MECR_BSIO_SET(mecr, sock, bs) \
+MECR_SET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK, (bs))
+
+#define MECR_BSIO_GET(mecr, sock) \
+MECR_GET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK)
+
+#define MECR_BSA_SET(mecr, sock, bs) \
+MECR_SET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK, (bs))
+
+#define MECR_BSA_GET(mecr, sock) \
+MECR_GET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK)
+
+#define MECR_BSM_SET(mecr, sock, bs) \
+MECR_SET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK, (bs))
+
+#define MECR_BSM_GET(mecr, sock) \
+MECR_GET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK)
+
+#define MECR_FAST_SET(mecr, sock, fast) \
+MECR_SET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK, (fast))
+
+#define MECR_FAST_GET(mecr, sock) \
+MECR_GET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK)
+
+
+/* This function implements the BS value calculation for setting the MECR
+ * using integer arithmetic:
+ */
+static inline unsigned int sa1100_pcmcia_mecr_bs(unsigned int pcmcia_cycle_ns,
+						 unsigned int cpu_clock_khz){
+  unsigned int t = ((pcmcia_cycle_ns * cpu_clock_khz) / 6) - 1000000;
+  return (t / 1000000) + (((t % 1000000) == 0) ? 0 : 1);
+}
+
+/* This function returns the (approxmiate) command assertion period, in
+ * nanoseconds, for a given CPU clock frequency and MECR BS value:
+ */
+static inline unsigned int sa1100_pcmcia_cmd_time(unsigned int cpu_clock_khz,
+						  unsigned int pcmcia_mecr_bs){
+  return (((10000000 * 2) / cpu_clock_khz) * (3 * (pcmcia_mecr_bs + 1))) / 10;
+}
+
+
+/* SA-1100 PCMCIA Memory and I/O timing
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * The SA-1110 Developer's Manual, section 10.2.5, says the following:
+ *
+ *  "To calculate the recommended BS_xx value for each address space:
+ *   divide the command width time (the greater of twIOWR and twIORD,
+ *   or the greater of twWE and twOE) by processor cycle time; divide
+ *   by 2; divide again by 3 (number of BCLK's per command assertion);
+ *   round up to the next whole number; and subtract 1."
+ *
+ * The PC Card Standard, Release 7, section 4.13.4, says that twIORD
+ * has a minimum value of 165ns. Section 4.13.5 says that twIOWR has
+ * a minimum value of 165ns, as well. Section 4.7.2 (describing
+ * common and attribute memory write timing) says that twWE has a
+ * minimum value of 150ns for a 250ns cycle time (for 5V operation;
+ * see section 4.7.4), or 300ns for a 600ns cycle time (for 3.3V
+ * operation, also section 4.7.4). Section 4.7.3 says that taOE
+ * has a maximum value of 150ns for a 300ns cycle time (for 5V
+ * operation), or 300ns for a 600ns cycle time (for 3.3V operation).
+ *
+ * When configuring memory maps, Card Services appears to adopt the policy
+ * that a memory access time of "0" means "use the default." The default
+ * PCMCIA I/O command width time is 165ns. The default PCMCIA 5V attribute
+ * and memory command width time is 150ns; the PCMCIA 3.3V attribute and
+ * memory command width time is 300ns.
+ */
+#define SA1100_PCMCIA_IO_ACCESS      (165)
+#define SA1100_PCMCIA_5V_MEM_ACCESS  (150)
+#define SA1100_PCMCIA_3V_MEM_ACCESS  (300)
+
+
+/* The socket driver actually works nicely in interrupt-driven form,
+ * so the (relatively infrequent) polling is "just to be sure."
+ */
+#define SA1100_PCMCIA_POLL_PERIOD    (2*HZ)
+
+
+/* This structure encapsulates per-socket state which we might need to
+ * use when responding to a Card Services query of some kind.
+ */
+struct sa1100_pcmcia_socket {
+  socket_state_t        cs_state;
+  struct pcmcia_state   k_state;
+  unsigned int          irq;
+  void                  (*handler)(void *, unsigned int);
+  void                  *handler_info;
+  pccard_io_map         io_map[MAX_IO_WIN];
+  pccard_mem_map        mem_map[MAX_WIN];
+  ioaddr_t              virt_io, phys_attr, phys_mem;
+  unsigned short        speed_io, speed_attr, speed_mem;
+};
+
+
+/* I/O pins replacing memory pins
+ * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75)
+ *
+ * These signals change meaning when going from memory-only to 
+ * memory-or-I/O interface:
+ */
+#define iostschg bvd1
+#define iospkr   bvd2
+
+
+/*
+ * Declaration for all implementation specific low_level operations.
+ */
+extern struct pcmcia_low_level assabet_pcmcia_ops;
+extern struct pcmcia_low_level neponset_pcmcia_ops;
+extern struct pcmcia_low_level h3600_pcmcia_ops;
+extern struct pcmcia_low_level cerf_pcmcia_ops;
+extern struct pcmcia_low_level gcplus_pcmcia_ops;
+extern struct pcmcia_low_level xp860_pcmcia_ops;
+extern struct pcmcia_low_level yopy_pcmcia_ops;
+extern struct pcmcia_low_level pangolin_pcmcia_ops;
+extern struct pcmcia_low_level freebird_pcmcia_ops;
+extern struct pcmcia_low_level pfs168_pcmcia_ops;
+extern struct pcmcia_low_level jornada720_pcmcia_ops;
+extern struct pcmcia_low_level flexanet_pcmcia_ops;
+extern struct pcmcia_low_level simpad_pcmcia_ops;
+extern struct pcmcia_low_level graphicsmaster_pcmcia_ops;
+extern struct pcmcia_low_level adsbitsy_pcmcia_ops;
+extern struct pcmcia_low_level stork_pcmcia_ops;
+
+#endif  /* !defined(_PCMCIA_SA1100_H) */
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_adsbitsy.c linux/drivers/pcmcia/sa1100_adsbitsy.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_adsbitsy.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_adsbitsy.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,216 @@
+/*
+ * drivers/pcmcia/sa1100_adsbitsy.c
+ *
+ * PCMCIA implementation routines for ADS Bitsy
+ *
+ * 9/18/01 Woojung
+ *         Fixed wrong PCMCIA voltage setting
+ *
+ * 7/5/01 Woojung Huh <whuh@applieddata.net>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/delay.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+static int adsbitsy_pcmcia_init(struct pcmcia_init *init)
+{
+  int return_val=0;
+
+  /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
+  PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+
+  /* Disable Power 3.3V/5V for PCMCIA/CF */
+  PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
+
+  INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
+			 (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
+    		 (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
+    		 (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
+    		 (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
+    		 (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
+
+  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
+			  "GC Master PCMCIA (0) CD", NULL);
+  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
+			  "GC Master CF (1) CD", NULL);
+  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
+			  "GC Master PCMCIA (0) BVD1", NULL);
+  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
+			  "GC Master CF (1) BVD1", NULL);
+
+  MECR = 0x09430943;
+
+  return (return_val<0) ? -1 : 2;
+}
+
+static int adsbitsy_pcmcia_shutdown(void)
+{
+
+  free_irq(S0_CD_VALID, NULL);
+  free_irq(S1_CD_VALID, NULL);
+  free_irq(S0_BVD1_STSCHG, NULL);
+  free_irq(S1_BVD1_STSCHG, NULL);
+
+  INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
+			   (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
+      		   (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
+      		   (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
+
+  return 0;
+}
+
+static int adsbitsy_pcmcia_socket_state(struct pcmcia_state_array *state_array)
+{
+  unsigned long status;
+  int return_val=1;
+
+  if(state_array->size<2) return -1;
+
+  memset(state_array->state, 0,
+	 (state_array->size)*sizeof(struct pcmcia_state));
+
+  status=PCSR;
+
+  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
+
+  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
+
+  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
+
+  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
+
+  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
+
+  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
+
+  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
+
+  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
+
+  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
+
+  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
+
+  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
+
+  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
+
+  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
+
+  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
+
+  return return_val;
+}
+
+static int adsbitsy_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+
+  switch(info->sock){
+  case 0:
+    info->irq=S0_READY_NINT;
+    break;
+
+  case 1:
+    info->irq=S1_READY_NINT;
+    break;
+
+  default:
+    return -1;
+  }
+
+  return 0;
+}
+
+static int adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *configure)
+{
+  unsigned long pccr=PCCR, gpio=PA_DWR;
+
+  switch(configure->sock){
+  case 0:
+
+    switch(configure->vcc){
+    case 0:
+      pccr = (pccr & ~PCCR_S0_FLT);
+      gpio |= GPIO_GPIO0 | GPIO_GPIO1;
+      break;
+
+    case 33:
+      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
+      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
+	  gpio &= ~GPIO_GPIO0;
+      break;
+
+    case 50:
+      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
+      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
+	  gpio |= GPIO_GPIO0;
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	     configure->vcc);
+      return -1;
+    }
+
+    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
+
+    break;
+
+  case 1:
+    switch(configure->vcc){
+    case 0:
+      pccr = (pccr & ~PCCR_S1_FLT);
+      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
+      break;
+
+    case 33:
+      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
+      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
+	  gpio |= GPIO_GPIO2;
+      break;
+
+    case 50:
+      pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
+      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
+	  gpio |= GPIO_GPIO3;
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	     configure->vcc);
+      return -1;
+    }
+
+    if(configure->vpp!=configure->vcc && configure->vpp!=0){
+      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
+	     configure->vpp);
+      return -1;
+    }
+
+    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
+
+    break;
+
+  default:
+    return -1;
+  }
+
+  PCCR = pccr;
+  PA_DWR = gpio;
+
+  return 0;
+}
+
+struct pcmcia_low_level adsbitsy_pcmcia_ops = {
+  adsbitsy_pcmcia_init,
+  adsbitsy_pcmcia_shutdown,
+  adsbitsy_pcmcia_socket_state,
+  adsbitsy_pcmcia_get_irq_info,
+  adsbitsy_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_assabet.c linux/drivers/pcmcia/sa1100_assabet.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_assabet.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_assabet.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,149 @@
+/*
+ * drivers/pcmcia/sa1100_assabet.c
+ *
+ * PCMCIA implementation routines for Assabet
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+
+static int assabet_pcmcia_init(struct pcmcia_init *init){
+  int irq, res;
+
+  /* Enable CF bus: */
+  BCR_clear(BCR_CF_BUS_OFF);
+
+  /* All those are inputs */
+  GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ);
+
+  /* Set transition detect */
+  set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES );
+  set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
+
+  /* Register interrupts */
+  irq = IRQ_GPIO_CF_CD;
+  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL );
+  if( res < 0 ) goto irq_err;
+  irq = IRQ_GPIO_CF_BVD2;
+  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL );
+  if( res < 0 ) goto irq_err;
+  irq = IRQ_GPIO_CF_BVD1;
+  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
+  if( res < 0 ) goto irq_err;
+
+  /* There's only one slot, but it's "Slot 1": */
+  return 2;
+
+irq_err:
+  printk( KERN_ERR "%s: Request for IRQ %u failed\n", __FUNCTION__, irq );
+  return -1;
+}
+
+static int assabet_pcmcia_shutdown(void)
+{
+  /* disable IRQs */
+  free_irq( IRQ_GPIO_CF_CD, NULL );
+  free_irq( IRQ_GPIO_CF_BVD2, NULL );
+  free_irq( IRQ_GPIO_CF_BVD1, NULL );
+  
+  /* Disable CF bus: */
+  BCR_set(BCR_CF_BUS_OFF);
+
+  return 0;
+}
+
+static int assabet_pcmcia_socket_state(struct pcmcia_state_array
+				       *state_array){
+  unsigned long levels;
+
+  if(state_array->size<2) return -1;
+
+  memset(state_array->state, 0, 
+	 (state_array->size)*sizeof(struct pcmcia_state));
+
+  levels=GPLR;
+
+  state_array->state[1].detect=((levels & GPIO_CF_CD)==0)?1:0;
+
+  state_array->state[1].ready=(levels & GPIO_CF_IRQ)?1:0;
+
+  state_array->state[1].bvd1=(levels & GPIO_CF_BVD1)?1:0;
+
+  state_array->state[1].bvd2=(levels & GPIO_CF_BVD2)?1:0;
+
+  state_array->state[1].wrprot=0; /* Not available on Assabet. */
+
+  state_array->state[1].vs_3v=1;  /* Can only apply 3.3V on Assabet. */
+
+  state_array->state[1].vs_Xv=0;
+
+  return 1;
+}
+
+static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+
+  if(info->sock>1) return -1;
+
+  if(info->sock==1)
+    info->irq=IRQ_GPIO_CF_IRQ;
+
+  return 0;
+}
+
+static int assabet_pcmcia_configure_socket(const struct pcmcia_configure
+					   *configure)
+{
+  unsigned long value, flags;
+
+  if(configure->sock>1) return -1;
+
+  if(configure->sock==0) return 0;
+
+  save_flags_cli(flags);
+
+  value = BCR_value;
+
+  switch(configure->vcc){
+  case 0:
+    value &= ~BCR_CF_PWR;
+    break;
+
+  case 50:
+    printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
+	   __FUNCTION__);
+
+  case 33:  /* Can only apply 3.3V to the CF slot. */
+    value |= BCR_CF_PWR;
+    break;
+
+  default:
+    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	   configure->vcc);
+    restore_flags(flags);
+    return -1;
+  }
+
+  value = (configure->reset) ? (value | BCR_CF_RST) : (value & ~BCR_CF_RST);
+
+  /* Silently ignore Vpp, output enable, speaker enable. */
+
+  BCR = BCR_value = value;
+
+  restore_flags(flags);
+
+  return 0;
+}
+
+struct pcmcia_low_level assabet_pcmcia_ops = { 
+  assabet_pcmcia_init,
+  assabet_pcmcia_shutdown,
+  assabet_pcmcia_socket_state,
+  assabet_pcmcia_get_irq_info,
+  assabet_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_cerf.c linux/drivers/pcmcia/sa1100_cerf.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_cerf.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_cerf.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,150 @@
+/*
+ * drivers/pcmcia/sa1100_cerf.c
+ *
+ * PCMCIA implementation routines for CerfBoard
+ * Based off the Assabet.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+
+static int cerf_pcmcia_init(struct pcmcia_init *init){
+  int irq, res;
+
+  /* Enable CF bus: */
+//  BCR_clear(BCR_CF_BUS_OFF);
+
+  /* All those are inputs */
+  GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ);
+
+  /* Set transition detect */
+  set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES );
+  set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
+
+  /* Register interrupts */
+  irq = IRQ_GPIO_CF_CD;
+  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL );
+  if( res < 0 ) goto irq_err;
+  irq = IRQ_GPIO_CF_BVD2;
+  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL );
+  if( res < 0 ) goto irq_err;
+  irq = IRQ_GPIO_CF_BVD1;
+  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
+  if( res < 0 ) goto irq_err;
+
+  /* There's only one slot, but it's "Slot 1": */
+  return 2;
+
+irq_err:
+  printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq );
+  return -1;
+}
+
+static int cerf_pcmcia_shutdown(void)
+{
+  /* disable IRQs */
+  free_irq( IRQ_GPIO_CF_CD, NULL );
+  free_irq( IRQ_GPIO_CF_BVD2, NULL );
+  free_irq( IRQ_GPIO_CF_BVD1, NULL );
+  
+  /* Disable CF bus: */
+//  BCR_set(BCR_CF_BUS_OFF);
+
+  return 0;
+}
+
+static int cerf_pcmcia_socket_state(struct pcmcia_state_array
+				       *state_array){
+  unsigned long levels;
+
+  if(state_array->size<2) return -1;
+
+  memset(state_array->state, 0, 
+	 (state_array->size)*sizeof(struct pcmcia_state));
+
+  levels=GPLR;
+
+  state_array->state[1].detect=((levels & GPIO_CF_CD)==0)?1:0;
+
+  state_array->state[1].ready=(levels & GPIO_CF_IRQ)?1:0;
+
+  state_array->state[1].bvd1=(levels & GPIO_CF_BVD1)?1:0;
+
+  state_array->state[1].bvd2=(levels & GPIO_CF_BVD2)?1:0;
+
+  state_array->state[1].wrprot=0; /* Not available on Assabet. */
+
+  state_array->state[1].vs_3v=1;  /* Can only apply 3.3V on Assabet. */
+
+  state_array->state[1].vs_Xv=0;
+
+  return 1;
+}
+
+static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+
+  if(info->sock>1) return -1;
+
+  if(info->sock==1)
+    info->irq=IRQ_GPIO_CF_IRQ;
+
+  return 0;
+}
+
+static int cerf_pcmcia_configure_socket(const struct pcmcia_configure
+					   *configure)
+{
+  unsigned long value, flags;
+
+  if(configure->sock>1) return -1;
+
+  if(configure->sock==0) return 0;
+
+  save_flags_cli(flags);
+
+//  value = BCR_value;
+
+  switch(configure->vcc){
+  case 0:
+//    value &= ~BCR_CF_PWR;
+    break;
+
+  case 50:
+    printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
+	   __FUNCTION__);
+
+  case 33:  /* Can only apply 3.3V to the CF slot. */
+//    value |= BCR_CF_PWR;
+    break;
+
+  default:
+    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	   configure->vcc);
+    restore_flags(flags);
+    return -1;
+  }
+
+//  value = (configure->reset) ? (value | BCR_CF_RST) : (value & ~BCR_CF_RST);
+
+  /* Silently ignore Vpp, output enable, speaker enable. */
+
+//  BCR = BCR_value = value;
+
+  restore_flags(flags);
+
+  return 0;
+}
+
+struct pcmcia_low_level cerf_pcmcia_ops = { 
+  cerf_pcmcia_init,
+  cerf_pcmcia_shutdown,
+  cerf_pcmcia_socket_state,
+  cerf_pcmcia_get_irq_info,
+  cerf_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_flexanet.c linux/drivers/pcmcia/sa1100_flexanet.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_flexanet.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_flexanet.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,84 @@
+/*
+ * drivers/pcmcia/sa1100_flexanet.c
+ *
+ * PCMCIA implementation routines for Flexanet.
+ * by Jordi Colomer, 09/05/2001
+ *
+ * Yet to be defined.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+
+/*
+ * Socket initialization.
+ *
+ * Called by sa1100_pcmcia_driver_init on startup.
+ * Must return the number of slots.
+ *
+ */
+static int flexanet_pcmcia_init(struct pcmcia_init *init){
+
+  return 0;
+}
+
+
+/*
+ * Socket shutdown
+ *
+ */
+static int flexanet_pcmcia_shutdown(void)
+{
+  return 0;
+}
+
+
+/*
+ * Get the state of the sockets.
+ *
+ *  Sockets in Flexanet are 3.3V only, without BVD2.
+ *
+ */
+static int flexanet_pcmcia_socket_state(struct pcmcia_state_array
+				       *state_array){
+  return -1;
+}
+
+
+/*
+ * Return the IRQ information for a given socket number (the IRQ number)
+ *
+ */
+static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+
+  return -1;
+}
+
+
+/*
+ *
+ */
+static int flexanet_pcmcia_configure_socket(const struct pcmcia_configure
+					   *configure)
+{
+  return -1;
+}
+
+
+/*
+ * The set of socket operations
+ *
+ */
+struct pcmcia_low_level flexanet_pcmcia_ops = {
+  flexanet_pcmcia_init,
+  flexanet_pcmcia_shutdown,
+  flexanet_pcmcia_socket_state,
+  flexanet_pcmcia_get_irq_info,
+  flexanet_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_freebird.c linux/drivers/pcmcia/sa1100_freebird.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_freebird.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_freebird.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,160 @@
+/*
+ * drivers/pcmcia/sa1100_freebird.c
+ *
+ * Created by Eric Peng <ericpeng@coventive.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+
+static int freebird_pcmcia_init(struct pcmcia_init *init){
+  int irq, res;
+
+  /* Enable Linkup CF card */
+  LINKUP_PRC = 0xc0;
+  mdelay(100);
+  LINKUP_PRC = 0xc1;
+  mdelay(100);
+  LINKUP_PRC = 0xd1;
+  mdelay(100);
+  LINKUP_PRC = 0xd1;
+  mdelay(100);
+  LINKUP_PRC = 0xc0;
+
+  /* All those are inputs */
+  ////GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ);
+  GPDR &= ~(GPIO_FREEBIRD_CF_CD | GPIO_FREEBIRD_CF_IRQ | GPIO_FREEBIRD_CF_BVD);
+
+  /* Set transition detect */
+  //set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES );
+  //set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
+  set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD,GPIO_BOTH_EDGES);
+  set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_IRQ, GPIO_FALLING_EDGE);
+
+  /* Register interrupts */
+  irq = IRQ_GPIO_FREEBIRD_CF_CD;
+  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL );
+  if( res < 0 ) goto irq_err;
+  irq = IRQ_GPIO_FREEBIRD_CF_BVD;
+  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
+  if( res < 0 ) goto irq_err;
+
+  /* There's only one slot, but it's "Slot 1": */
+  return 2;
+
+irq_err:
+  printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq );
+  return -1;
+}
+
+static int freebird_pcmcia_shutdown(void)
+{
+  /* disable IRQs */
+  free_irq( IRQ_GPIO_FREEBIRD_CF_CD, NULL );
+  free_irq( IRQ_GPIO_FREEBIRD_CF_BVD, NULL );
+
+  /* Disable CF card */
+  LINKUP_PRC = 0x40;  /* SSP=1   SOE=0 */
+  mdelay(100);
+
+  return 0;
+}
+
+static int freebird_pcmcia_socket_state(struct pcmcia_state_array
+				       *state_array){
+  unsigned long levels;
+
+  if(state_array->size<2) return -1;
+
+  memset(state_array->state, 0,
+	 (state_array->size)*sizeof(struct pcmcia_state));
+
+  levels = LINKUP_PRS;
+//printk("LINKUP_PRS=%x \n",levels);
+
+  state_array->state[0].detect=
+    ((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0;
+
+  state_array->state[0].ready=(levels & LINKUP_RDY)?1:0;
+
+  state_array->state[0].bvd1=(levels & LINKUP_BVD1)?1:0;
+
+  state_array->state[0].bvd2=(levels & LINKUP_BVD2)?1:0;
+
+  state_array->state[0].wrprot=0; /* Not available on Assabet. */
+
+  state_array->state[0].vs_3v=1;  /* Can only apply 3.3V on Assabet. */
+
+  state_array->state[0].vs_Xv=0;
+
+  return 1;
+}
+
+static int freebird_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+
+  if(info->sock>1) return -1;
+
+  if(info->sock==0)
+    info->irq=IRQ_GPIO_FREEBIRD_CF_IRQ;
+
+  return 0;
+}
+
+static int freebird_pcmcia_configure_socket(const struct pcmcia_configure
+					   *configure)
+{
+  unsigned long value, flags;
+
+  if(configure->sock>1) return -1;
+
+  if(configure->sock==1) return 0;
+
+  save_flags_cli(flags);
+
+  value = 0xc0;   /* SSP=1  SOE=1  CFE=1 */
+
+  switch(configure->vcc){
+  case 0:
+
+    break;
+
+  case 50:
+    printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
+	   __FUNCTION__);
+
+  case 33:  /* Can only apply 3.3V to the CF slot. */
+    value |= LINKUP_S1;
+    break;
+
+  default:
+    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	   configure->vcc);
+    restore_flags(flags);
+    return -1;
+  }
+
+  if (configure->reset)
+  value = (configure->reset) ? (value | LINKUP_RESET) : (value & ~LINKUP_RESET);
+
+  /* Silently ignore Vpp, output enable, speaker enable. */
+
+  LINKUP_PRC = value;
+//printk("LINKUP_PRC=%x\n",value);
+  restore_flags(flags);
+
+  return 0;
+}
+
+struct pcmcia_low_level freebird_pcmcia_ops = {
+  freebird_pcmcia_init,
+  freebird_pcmcia_shutdown,
+  freebird_pcmcia_socket_state,
+  freebird_pcmcia_get_irq_info,
+  freebird_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_generic.c linux/drivers/pcmcia/sa1100_generic.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_generic.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_generic.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,1168 @@
+/*======================================================================
+
+    Device driver for the PCMCIA control functionality of StrongARM
+    SA-1100 microprocessors.
+
+    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 John G. Dorsey
+    <john+@cs.cmu.edu>.  Portions created by John G. Dorsey are
+    Copyright (C) 1999 John G. Dorsey.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU 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.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/tqueue.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/notifier.h>
+#include <linux/proc_fs.h>
+#include <linux/version.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/bus_ops.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "sa1100.h"
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug;
+#endif
+
+MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller");
+
+/* This structure maintains housekeeping state for each socket, such
+ * as the last known values of the card detect pins, or the Card Services
+ * callback value associated with the socket:
+ */
+static struct sa1100_pcmcia_socket 
+sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK];
+
+static int sa1100_pcmcia_socket_count;
+
+
+/* Returned by the low-level PCMCIA interface: */
+static struct pcmcia_low_level *pcmcia_low_level;
+
+/* Event poll timer structure */
+static struct timer_list poll_timer;
+
+
+/* Prototypes for routines which are used internally: */
+
+static int  sa1100_pcmcia_driver_init(void);
+static void sa1100_pcmcia_driver_shutdown(void);
+static void sa1100_pcmcia_task_handler(void *data);
+static void sa1100_pcmcia_poll_event(unsigned long data);
+static void sa1100_pcmcia_interrupt(int irq, void *dev,
+				    struct pt_regs *regs);
+static struct tq_struct sa1100_pcmcia_task;
+
+#ifdef CONFIG_PROC_FS
+static int  sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
+				      int count, int *eof, void *data);
+#endif
+
+
+/* Prototypes for operations which are exported to the
+ * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core:
+ */
+
+static int sa1100_pcmcia_init(unsigned int sock);
+static int sa1100_pcmcia_suspend(unsigned int sock);
+static int sa1100_pcmcia_register_callback(unsigned int sock,
+					   void (*handler)(void *, 
+							   unsigned int),
+					   void *info);
+static int sa1100_pcmcia_inquire_socket(unsigned int sock, 
+					socket_cap_t *cap);
+static int sa1100_pcmcia_get_status(unsigned int sock, u_int *value);
+static int sa1100_pcmcia_get_socket(unsigned int sock, 
+				    socket_state_t *state);
+static int sa1100_pcmcia_set_socket(unsigned int sock,
+				    socket_state_t *state);
+static int sa1100_pcmcia_get_io_map(unsigned int sock,
+				    struct pccard_io_map *io);
+static int sa1100_pcmcia_set_io_map(unsigned int sock,
+				    struct pccard_io_map *io);
+static int sa1100_pcmcia_get_mem_map(unsigned int sock,
+				     struct pccard_mem_map *mem);
+static int sa1100_pcmcia_set_mem_map(unsigned int sock,
+				     struct pccard_mem_map *mem);
+#ifdef CONFIG_PROC_FS
+static void sa1100_pcmcia_proc_setup(unsigned int sock,
+				     struct proc_dir_entry *base);
+#endif
+
+static struct pccard_operations sa1100_pcmcia_operations = {
+  sa1100_pcmcia_init,
+  sa1100_pcmcia_suspend,
+  sa1100_pcmcia_register_callback,
+  sa1100_pcmcia_inquire_socket,
+  sa1100_pcmcia_get_status,
+  sa1100_pcmcia_get_socket,
+  sa1100_pcmcia_set_socket,
+  sa1100_pcmcia_get_io_map,
+  sa1100_pcmcia_set_io_map,
+  sa1100_pcmcia_get_mem_map,
+  sa1100_pcmcia_set_mem_map,
+#ifdef CONFIG_PROC_FS
+  sa1100_pcmcia_proc_setup
+#endif
+};
+
+#ifdef CONFIG_CPU_FREQ
+/* forward declaration */
+static struct notifier_block sa1100_pcmcia_notifier_block;
+#endif
+
+
+/* sa1100_pcmcia_driver_init()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * This routine performs a basic sanity check to ensure that this
+ * kernel has been built with the appropriate board-specific low-level
+ * PCMCIA support, performs low-level PCMCIA initialization, registers
+ * this socket driver with Card Services, and then spawns the daemon
+ * thread which is the real workhorse of the socket driver.
+ *
+ * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
+ * on the low-level kernel interface.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int __init sa1100_pcmcia_driver_init(void){
+  servinfo_t info;
+  struct pcmcia_init pcmcia_init;
+  struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
+  struct pcmcia_state_array state_array;
+  unsigned int i, clock;
+  unsigned long mecr;
+
+  printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE);
+
+  CardServices(GetCardServicesInfo, &info);
+
+  if(info.Revision!=CS_RELEASE_CODE){
+    printk(KERN_ERR "Card Services release codes do not match\n");
+    return -1;
+  }
+
+  if(machine_is_assabet()){
+#ifdef CONFIG_SA1100_ASSABET
+    if(machine_has_neponset()){
+#ifdef CONFIG_ASSABET_NEPONSET
+      pcmcia_low_level=&neponset_pcmcia_ops;
+#else
+      printk(KERN_ERR "Card Services disabled: missing Neponset support\n");
+      return -1;
+#endif
+    }else{
+      pcmcia_low_level=&assabet_pcmcia_ops;
+    }
+#endif
+  } else if (machine_is_freebird()) {
+#ifdef CONFIG_SA1100_FREEBIRD
+    pcmcia_low_level = &freebird_pcmcia_ops;
+#endif
+  } else if (machine_is_h3600()) {
+#ifdef CONFIG_SA1100_H3600
+    pcmcia_low_level = &h3600_pcmcia_ops;
+#endif    
+  } else if (machine_is_cerf()) {
+#ifdef CONFIG_SA1100_CERF
+    pcmcia_low_level = &cerf_pcmcia_ops;
+#endif
+  } else if (machine_is_graphicsclient()) {
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+    pcmcia_low_level = &gcplus_pcmcia_ops;
+#endif
+  } else if (machine_is_xp860()) {
+#ifdef CONFIG_SA1100_XP860
+    pcmcia_low_level = &xp860_pcmcia_ops;
+#endif
+  } else if (machine_is_yopy()) {
+#ifdef CONFIG_SA1100_YOPY
+    pcmcia_low_level = &yopy_pcmcia_ops;
+#endif
+  } else if (machine_is_pangolin()) {
+#ifdef CONFIG_SA1100_PANGOLIN
+    pcmcia_low_level = &pangolin_pcmcia_ops;
+#endif
+  } else if (machine_is_jornada720()) {
+#ifdef CONFIG_SA1100_JORNADA720
+    pcmcia_low_level = &jornada720_pcmcia_ops;
+#endif
+  } else if(machine_is_pfs168()){
+#ifdef CONFIG_SA1100_PFS168
+    pcmcia_low_level=&pfs168_pcmcia_ops;
+#endif
+  } else if(machine_is_flexanet()){
+#ifdef CONFIG_SA1100_FLEXANET
+    pcmcia_low_level=&flexanet_pcmcia_ops;
+#endif
+ } else if(machine_is_simpad()){
+#ifdef CONFIG_SA1100_SIMPAD
+    pcmcia_low_level=&simpad_pcmcia_ops;
+#endif
+  } else if(machine_is_graphicsmaster()) {
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+    pcmcia_low_level=&graphicsmaster_pcmcia_ops;
+#endif
+  } else if(machine_is_adsbitsy()) {
+#ifdef CONFIG_SA1100_ADSBITSY
+    pcmcia_low_level=&adsbitsy_pcmcia_ops;
+#endif
+  } else if(machine_is_stork()) {
+#ifdef CONFIG_SA1100_STORK
+    pcmcia_low_level=&stork_pcmcia_ops;
+#endif
+  }
+
+  if (!pcmcia_low_level) {
+    printk(KERN_ERR "This hardware is not supported by the SA1100 Card Service driver\n");
+    return -ENODEV;
+  }
+
+  pcmcia_init.handler=sa1100_pcmcia_interrupt;
+
+  if((sa1100_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){
+    printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n");
+    return -EIO;
+  }
+
+  state_array.size=sa1100_pcmcia_socket_count;
+  state_array.state=state;
+
+  if(pcmcia_low_level->socket_state(&state_array)<0){
+    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
+    return -EIO;
+  }
+
+  /* We initialize the MECR to default values here, because we are
+   * not guaranteed to see a SetIOMap operation at runtime.
+   */
+  mecr=0;
+
+  clock = get_cclk_frequency() * 100;
+
+  for(i=0; i<sa1100_pcmcia_socket_count; ++i){
+    sa1100_pcmcia_socket[i].k_state=state[i];
+
+    /* This is an interim fix. Apparently, SetSocket is no longer
+     * called to initialize each socket (prior to the first detect
+     * event). For now, we'll just manually set up the mask.
+     */
+    sa1100_pcmcia_socket[i].cs_state.csc_mask=SS_DETECT;
+
+    sa1100_pcmcia_socket[i].virt_io=(i==0)?PCMCIA_IO_0_BASE:PCMCIA_IO_1_BASE;
+    sa1100_pcmcia_socket[i].phys_attr=_PCMCIAAttr(i);
+    sa1100_pcmcia_socket[i].phys_mem=_PCMCIAMem(i);
+
+    MECR_FAST_SET(mecr, i, 0);
+    MECR_BSIO_SET(mecr, i,
+		  sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_IO_ACCESS, clock));
+    MECR_BSA_SET(mecr, i,
+		 sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock));
+    MECR_BSM_SET(mecr, i,
+		 sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock));
+
+    sa1100_pcmcia_socket[i].speed_io=SA1100_PCMCIA_IO_ACCESS;
+    sa1100_pcmcia_socket[i].speed_attr=SA1100_PCMCIA_5V_MEM_ACCESS;
+    sa1100_pcmcia_socket[i].speed_mem=SA1100_PCMCIA_5V_MEM_ACCESS;
+  }
+
+  MECR=mecr;
+
+#ifdef CONFIG_CPU_FREQ
+  if(cpufreq_register_notifier(&sa1100_pcmcia_notifier_block) < 0){
+    printk(KERN_ERR "Unable to register CPU frequency change notifier\n");
+    return -ENXIO;
+  }
+#endif
+
+  /* Only advertise as many sockets as we can detect: */
+  if(register_ss_entry(sa1100_pcmcia_socket_count, 
+		       &sa1100_pcmcia_operations)<0){
+    printk(KERN_ERR "Unable to register socket service routine\n");
+    return -ENXIO;
+  }
+
+  /* Start the event poll timer.  It will reschedule by itself afterwards. */
+  sa1100_pcmcia_poll_event(0);
+
+  DEBUG(1, "sa1100: initialization complete\n");
+
+  return 0;
+
+}  /* sa1100_pcmcia_driver_init() */
+
+module_init(sa1100_pcmcia_driver_init);
+
+
+/* sa1100_pcmcia_driver_shutdown()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Invokes the low-level kernel service to free IRQs associated with this
+ * socket controller and reset GPIO edge detection.
+ */
+static void __exit sa1100_pcmcia_driver_shutdown(void){
+
+  del_timer_sync(&poll_timer);
+  unregister_ss_entry(&sa1100_pcmcia_operations);
+#ifdef CONFIG_CPU_FREQ
+  cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block);
+#endif
+  pcmcia_low_level->shutdown();
+  flush_scheduled_tasks();
+
+  DEBUG(1, "sa1100: shutdown complete\n");
+}
+
+module_exit(sa1100_pcmcia_driver_shutdown);
+
+
+/* sa1100_pcmcia_init()
+ * ^^^^^^^^^^^^^^^^^^^^
+ * We perform all of the interesting initialization tasks in 
+ * sa1100_pcmcia_driver_init().
+ *
+ * Returns: 0
+ */
+static int sa1100_pcmcia_init(unsigned int sock){
+  
+  DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock);
+
+  return 0;
+}
+
+
+/* sa1100_pcmcia_suspend()
+ * ^^^^^^^^^^^^^^^^^^^^^^^
+ * We don't currently perform any actions on a suspend.
+ *
+ * Returns: 0
+ */
+static int sa1100_pcmcia_suspend(unsigned int sock){
+
+  DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock);
+
+  return 0;
+}
+
+
+/* sa1100_pcmcia_events()
+ * ^^^^^^^^^^^^^^^^^^^^^^
+ * Helper routine to generate a Card Services event mask based on
+ * state information obtained from the kernel low-level PCMCIA layer
+ * in a recent (and previous) sampling. Updates `prev_state'.
+ *
+ * Returns: an event mask for the given socket state.
+ */
+static inline unsigned sa1100_pcmcia_events(struct pcmcia_state *state,
+					    struct pcmcia_state *prev_state,
+					    unsigned int mask,
+					    unsigned int flags){
+  unsigned int events=0;
+
+  if(state->detect!=prev_state->detect){
+
+    DEBUG(2, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
+
+    events|=mask&SS_DETECT;
+  }
+
+  if(state->ready!=prev_state->ready){
+
+    DEBUG(2, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
+
+    events|=mask&((flags&SS_IOCARD)?0:SS_READY);
+  }
+
+  if(state->bvd1!=prev_state->bvd1){
+
+    DEBUG(2, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
+
+    events|=mask&(flags&SS_IOCARD)?SS_STSCHG:SS_BATDEAD;
+  }
+
+  if(state->bvd2!=prev_state->bvd2){
+
+    DEBUG(2, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
+
+    events|=mask&(flags&SS_IOCARD)?0:SS_BATWARN;
+  }
+
+  DEBUG(2, "events: %s%s%s%s%s%s\n",
+	(events==0)?"<NONE>":"",
+	(events&SS_DETECT)?"DETECT ":"",
+	(events&SS_READY)?"READY ":"",
+	(events&SS_BATDEAD)?"BATDEAD ":"",
+	(events&SS_BATWARN)?"BATWARN ":"",
+	(events&SS_STSCHG)?"STSCHG ":"");
+
+  *prev_state=*state;
+
+  return events;
+
+}  /* sa1100_pcmcia_events() */
+
+
+/* sa1100_pcmcia_task_handler()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Processes serviceable socket events using the "eventd" thread context.
+ *
+ * Event processing (specifically, the invocation of the Card Services event
+ * callback) occurs in this thread rather than in the actual interrupt
+ * handler due to the use of scheduling operations in the PCMCIA core.
+ */
+static void sa1100_pcmcia_task_handler(void *data) {
+  struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
+  struct pcmcia_state_array state_array;
+  int i, events, all_events, irq_status;
+
+  DEBUG(2, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
+
+  state_array.size=sa1100_pcmcia_socket_count;
+  state_array.state=state;
+
+  do {
+
+    DEBUG(3, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__);
+
+    if((irq_status=pcmcia_low_level->socket_state(&state_array))<0)
+      printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n");
+
+    all_events=0;
+
+    if(irq_status>0){
+
+      for(i=0; i<state_array.size; ++i, all_events|=events)
+	if((events=
+	    sa1100_pcmcia_events(&state[i],
+				 &sa1100_pcmcia_socket[i].k_state,
+				 sa1100_pcmcia_socket[i].cs_state.csc_mask,
+				 sa1100_pcmcia_socket[i].cs_state.flags)))
+	  if(sa1100_pcmcia_socket[i].handler!=NULL)
+	    sa1100_pcmcia_socket[i].handler(sa1100_pcmcia_socket[i].handler_info,
+					    events);
+    }
+
+  } while(all_events);
+}  /* sa1100_pcmcia_task_handler() */
+
+static struct tq_struct sa1100_pcmcia_task = {
+	routine: sa1100_pcmcia_task_handler
+};
+
+
+/* sa1100_pcmcia_poll_event()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Let's poll for events in addition to IRQs since IRQ only is unreliable...
+ */
+static void sa1100_pcmcia_poll_event(unsigned long dummy)
+{
+  DEBUG(3, "%s(): polling for events\n", __FUNCTION__);
+  poll_timer.function = sa1100_pcmcia_poll_event;
+  poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD;
+  add_timer(&poll_timer);
+  schedule_task(&sa1100_pcmcia_task);
+}
+
+
+/* sa1100_pcmcia_interrupt()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Service routine for socket driver interrupts (requested by the
+ * low-level PCMCIA init() operation via sa1100_pcmcia_thread()).
+ * The actual interrupt-servicing work is performed by
+ * sa1100_pcmcia_thread(), largely because the Card Services event-
+ * handling code performs scheduling operations which cannot be
+ * executed from within an interrupt context.
+ */
+static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs){
+  DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
+  schedule_task(&sa1100_pcmcia_task);
+}
+
+
+/* sa1100_pcmcia_register_callback()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the register_callback() operation for the in-kernel
+ * PCMCIA service (formerly SS_RegisterCallback in Card Services). If 
+ * the function pointer `handler' is not NULL, remember the callback 
+ * location in the state for `sock', and increment the usage counter 
+ * for the driver module. (The callback is invoked from the interrupt
+ * service routine, sa1100_pcmcia_interrupt(), to notify Card Services
+ * of interesting events.) Otherwise, clear the callback pointer in the
+ * socket state and decrement the module usage count.
+ *
+ * Returns: 0
+ */
+static int sa1100_pcmcia_register_callback(unsigned int sock,
+					   void (*handler)(void *,
+							   unsigned int),
+					   void *info){
+  if(handler==NULL){
+    sa1100_pcmcia_socket[sock].handler=NULL;
+    MOD_DEC_USE_COUNT;
+  } else {
+    MOD_INC_USE_COUNT;
+    sa1100_pcmcia_socket[sock].handler=handler;
+    sa1100_pcmcia_socket[sock].handler_info=info;
+  }
+
+  return 0;
+}
+
+
+/* sa1100_pcmcia_inquire_socket()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the inquire_socket() operation for the in-kernel PCMCIA
+ * service (formerly SS_InquireSocket in Card Services). Of note is
+ * the setting of the SS_CAP_PAGE_REGS bit in the `features' field of
+ * `cap' to "trick" Card Services into tolerating large "I/O memory" 
+ * addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory
+ * resource database check. (Mapped memory is set up within the socket
+ * driver itself.)
+ *
+ * In conjunction with the STATIC_MAP capability is a new field,
+ * `io_offset', recommended by David Hinds. Rather than go through
+ * the SetIOMap interface (which is not quite suited for communicating
+ * window locations up from the socket driver), we just pass up
+ * an offset which is applied to client-requested base I/O addresses
+ * in alloc_io_space().
+ *
+ * Returns: 0 on success, -1 if no pin has been configured for `sock'
+ */
+static int sa1100_pcmcia_inquire_socket(unsigned int sock,
+					socket_cap_t *cap){
+  struct pcmcia_irq_info irq_info;
+
+  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+
+  if(sock>=sa1100_pcmcia_socket_count){
+    printk(KERN_ERR "sa1100: socket %u not configured\n", sock);
+    return -1;
+  }
+
+  /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
+   *   force_low argument to validate_mem() in rsrc_mgr.c -- since in
+   *   general, the mapped * addresses of the PCMCIA memory regions
+   *   will not be within 0xffff, setting force_low would be
+   *   undesirable.
+   *
+   * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
+   *   resource database; we instead pass up physical address ranges
+   *   and allow other parts of Card Services to deal with remapping.
+   *
+   * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
+   *   not 32-bit CardBus devices.
+   */
+  cap->features=(SS_CAP_PAGE_REGS  | SS_CAP_STATIC_MAP | SS_CAP_PCCARD);
+
+  irq_info.sock=sock;
+  irq_info.irq=-1;
+
+  if(pcmcia_low_level->get_irq_info(&irq_info)<0){
+    printk(KERN_ERR "Error obtaining IRQ info from kernel for socket %u\n",
+	   sock);
+    return -1;
+  }
+
+  cap->irq_mask=0;
+  cap->map_size=PAGE_SIZE;
+  cap->pci_irq=irq_info.irq;
+  cap->io_offset=sa1100_pcmcia_socket[sock].virt_io;
+
+  return 0;
+
+}  /* sa1100_pcmcia_inquire_socket() */
+
+
+/* sa1100_pcmcia_get_status()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the get_status() operation for the in-kernel PCMCIA
+ * service (formerly SS_GetStatus in Card Services). Essentially just
+ * fills in bits in `status' according to internal driver state or
+ * the value of the voltage detect chipselect register.
+ *
+ * As a debugging note, during card startup, the PCMCIA core issues
+ * three set_socket() commands in a row the first with RESET deasserted,
+ * the second with RESET asserted, and the last with RESET deasserted
+ * again. Following the third set_socket(), a get_status() command will
+ * be issued. The kernel is looking for the SS_READY flag (see
+ * setup_socket(), reset_socket(), and unreset_socket() in cs.c).
+ *
+ * Returns: 0
+ */
+static int sa1100_pcmcia_get_status(unsigned int sock,
+				    unsigned int *status){
+  struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
+  struct pcmcia_state_array state_array;
+
+  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+
+  state_array.size=sa1100_pcmcia_socket_count;
+  state_array.state=state;
+
+  if((pcmcia_low_level->socket_state(&state_array))<0){
+    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
+    return -1;
+  }
+
+  sa1100_pcmcia_socket[sock].k_state=state[sock];
+
+  *status=state[sock].detect?SS_DETECT:0;
+
+  *status|=state[sock].ready?SS_READY:0;
+
+  /* The power status of individual sockets is not available
+   * explicitly from the hardware, so we just remember the state
+   * and regurgitate it upon request:
+   */
+  *status|=sa1100_pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0;
+
+  if(sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)
+    *status|=state[sock].bvd1?SS_STSCHG:0;
+  else {
+    if(state[sock].bvd1==0)
+      *status|=SS_BATDEAD;
+    else if(state[sock].bvd2==0)
+      *status|=SS_BATWARN;
+  }
+
+  *status|=state[sock].vs_3v?SS_3VCARD:0;
+
+  *status|=state[sock].vs_Xv?SS_XVCARD:0;
+
+  DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n",
+	(*status&SS_DETECT)?"DETECT ":"",
+	(*status&SS_READY)?"READY ":"", 
+	(*status&SS_BATDEAD)?"BATDEAD ":"",
+	(*status&SS_BATWARN)?"BATWARN ":"",
+	(*status&SS_POWERON)?"POWERON ":"",
+	(*status&SS_STSCHG)?"STSCHG ":"",
+	(*status&SS_3VCARD)?"3VCARD ":"",
+	(*status&SS_XVCARD)?"XVCARD ":"");
+
+  return 0;
+
+}  /* sa1100_pcmcia_get_status() */
+
+
+/* sa1100_pcmcia_get_socket()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the get_socket() operation for the in-kernel PCMCIA
+ * service (formerly SS_GetSocket in Card Services). Not a very 
+ * exciting routine.
+ *
+ * Returns: 0
+ */
+static int sa1100_pcmcia_get_socket(unsigned int sock,
+				    socket_state_t *state){
+
+  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+
+  /* This information was given to us in an earlier call to set_socket(),
+   * so we're just regurgitating it here:
+   */
+  *state=sa1100_pcmcia_socket[sock].cs_state;
+
+  return 0;
+}
+
+
+/* sa1100_pcmcia_set_socket()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the set_socket() operation for the in-kernel PCMCIA
+ * service (formerly SS_SetSocket in Card Services). We more or
+ * less punt all of this work and let the kernel handle the details
+ * of power configuration, reset, &c. We also record the value of
+ * `state' in order to regurgitate it to the PCMCIA core later.
+ *
+ * Returns: 0
+ */
+static int sa1100_pcmcia_set_socket(unsigned int sock,
+				    socket_state_t *state){
+  struct pcmcia_configure configure;
+
+  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+
+  DEBUG(3, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n"
+	"\tVcc %d  Vpp %d  irq %d\n",
+	(state->csc_mask==0)?"<NONE>":"",
+	(state->csc_mask&SS_DETECT)?"DETECT ":"",
+	(state->csc_mask&SS_READY)?"READY ":"",
+	(state->csc_mask&SS_BATDEAD)?"BATDEAD ":"",
+	(state->csc_mask&SS_BATWARN)?"BATWARN ":"",
+	(state->csc_mask&SS_STSCHG)?"STSCHG ":"",
+	(state->flags==0)?"<NONE>":"",
+	(state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"",
+	(state->flags&SS_IOCARD)?"IOCARD ":"",
+	(state->flags&SS_RESET)?"RESET ":"",
+	(state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
+	(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
+	state->Vcc, state->Vpp, state->io_irq);
+
+  configure.sock=sock;
+  configure.vcc=state->Vcc;
+  configure.vpp=state->Vpp;
+  configure.output=(state->flags&SS_OUTPUT_ENA)?1:0;
+  configure.speaker=(state->flags&SS_SPKR_ENA)?1:0;
+  configure.reset=(state->flags&SS_RESET)?1:0;
+
+  if(pcmcia_low_level->configure_socket(&configure)<0){
+    printk(KERN_ERR "Unable to configure socket %u\n", sock);
+    return -1;
+  }
+
+  sa1100_pcmcia_socket[sock].cs_state=*state;
+  
+  return 0;
+
+}  /* sa1100_pcmcia_set_socket() */
+
+
+/* sa1100_pcmcia_get_io_map()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the get_io_map() operation for the in-kernel PCMCIA
+ * service (formerly SS_GetIOMap in Card Services). Just returns an
+ * I/O map descriptor which was assigned earlier by a set_io_map().
+ *
+ * Returns: 0 on success, -1 if the map index was out of range
+ */
+static int sa1100_pcmcia_get_io_map(unsigned int sock,
+				    struct pccard_io_map *map){
+
+  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+
+  if(map->map>=MAX_IO_WIN){
+    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
+	   map->map);
+    return -1;
+  }
+
+  *map=sa1100_pcmcia_socket[sock].io_map[map->map];
+
+  return 0;
+}
+
+
+/* sa1100_pcmcia_set_io_map()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the set_io_map() operation for the in-kernel PCMCIA
+ * service (formerly SS_SetIOMap in Card Services). We configure
+ * the map speed as requested, but override the address ranges
+ * supplied by Card Services.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int sa1100_pcmcia_set_io_map(unsigned int sock,
+				    struct pccard_io_map *map){
+  unsigned int clock, speed;
+  unsigned long mecr, start;
+
+  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+
+  DEBUG(4, "\tmap %u  speed %u\n\tstart 0x%08lx  stop 0x%08lx\n"
+	"\tflags: %s%s%s%s%s%s%s%s\n",
+	map->map, map->speed, map->start, map->stop,
+	(map->flags==0)?"<NONE>":"",
+	(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
+	(map->flags&MAP_16BIT)?"16BIT ":"",
+	(map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
+	(map->flags&MAP_0WS)?"0WS ":"",
+	(map->flags&MAP_WRPROT)?"WRPROT ":"",
+	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"",
+	(map->flags&MAP_PREFETCH)?"PREFETCH ":"");
+
+  if(map->map>=MAX_IO_WIN){
+    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
+	   map->map);
+    return -1;
+  }
+
+  if(map->flags&MAP_ACTIVE){
+
+    speed=(map->speed>0)?map->speed:SA1100_PCMCIA_IO_ACCESS;
+
+    clock = get_cclk_frequency() * 100;
+
+    mecr=MECR;
+
+    MECR_BSIO_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
+
+    sa1100_pcmcia_socket[sock].speed_io=speed;
+
+    DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
+	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
+	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
+	  sock, MECR_BSIO_GET(mecr, sock));
+
+    MECR=mecr;
+
+  }
+
+  start=map->start;
+
+  if(map->stop==1)
+    map->stop=PAGE_SIZE-1;
+
+  map->start=sa1100_pcmcia_socket[sock].virt_io;
+  map->stop=map->start+(map->stop-start);
+
+  sa1100_pcmcia_socket[sock].io_map[map->map]=*map;
+
+  return 0;
+
+}  /* sa1100_pcmcia_set_io_map() */
+
+
+/* sa1100_pcmcia_get_mem_map()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the get_mem_map() operation for the in-kernel PCMCIA
+ * service (formerly SS_GetMemMap in Card Services). Just returns a
+ *  memory map descriptor which was assigned earlier by a
+ *  set_mem_map() request.
+ *
+ * Returns: 0 on success, -1 if the map index was out of range
+ */
+static int sa1100_pcmcia_get_mem_map(unsigned int sock,
+				     struct pccard_mem_map *map){
+
+  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+
+  if(map->map>=MAX_WIN){
+    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
+	   map->map);
+    return -1;
+  }
+
+  *map=sa1100_pcmcia_socket[sock].mem_map[map->map];
+
+  return 0;
+}
+
+
+/* sa1100_pcmcia_set_mem_map()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the set_mem_map() operation for the in-kernel PCMCIA
+ * service (formerly SS_SetMemMap in Card Services). We configure
+ * the map speed as requested, but override the address ranges
+ * supplied by Card Services.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int sa1100_pcmcia_set_mem_map(unsigned int sock,
+				     struct pccard_mem_map *map){
+  unsigned int clock, speed;
+  unsigned long mecr, start;
+
+  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+
+  DEBUG(4, "\tmap %u  speed %u\n\tsys_start  %#lx\n"
+	"\tsys_stop   %#lx\n\tcard_start %#x\n"
+	"\tflags: %s%s%s%s%s%s%s%s\n",
+	map->map, map->speed, map->sys_start, map->sys_stop,
+	map->card_start, (map->flags==0)?"<NONE>":"",
+	(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
+	(map->flags&MAP_16BIT)?"16BIT ":"",
+	(map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
+	(map->flags&MAP_0WS)?"0WS ":"",
+	(map->flags&MAP_WRPROT)?"WRPROT ":"",
+	(map->flags&MAP_ATTRIB)?"ATTRIB ":"",
+	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
+
+  if(map->map>=MAX_WIN){
+    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
+	   map->map);
+    return -1;
+  }
+
+  if(map->flags&MAP_ACTIVE){
+
+    /* When clients issue RequestMap, the access speed is not always
+     * properly configured:
+     */
+    if(map->speed > 0)
+      speed = map->speed;
+    else
+      switch(sa1100_pcmcia_socket[sock].cs_state.Vcc){
+      case 33:
+	speed = SA1100_PCMCIA_3V_MEM_ACCESS;
+	break;
+      default:
+	speed = SA1100_PCMCIA_5V_MEM_ACCESS;
+      }
+
+    clock = get_cclk_frequency() * 100;
+    
+    mecr=MECR;
+    
+    if(map->flags&MAP_ATTRIB){
+
+      MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
+      sa1100_pcmcia_socket[sock].speed_attr=speed;
+
+    } else {
+
+      MECR_BSM_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
+      sa1100_pcmcia_socket[sock].speed_mem=speed;
+
+    }
+    
+    DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
+	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
+	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
+	  sock, MECR_BSIO_GET(mecr, sock));
+    
+    MECR=mecr;
+
+  }
+
+  start=map->sys_start;
+
+  if(map->sys_stop==0)
+    map->sys_stop=PAGE_SIZE-1;
+
+  map->sys_start=(map->flags & MAP_ATTRIB)?\
+    sa1100_pcmcia_socket[sock].phys_attr:\
+    sa1100_pcmcia_socket[sock].phys_mem;
+
+  map->sys_stop=map->sys_start+(map->sys_stop-start);
+
+  sa1100_pcmcia_socket[sock].mem_map[map->map]=*map;
+
+  return 0;
+
+}  /* sa1100_pcmcia_set_mem_map() */
+
+
+#if defined(CONFIG_PROC_FS)
+
+/* sa1100_pcmcia_proc_setup()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the proc_setup() operation for the in-kernel PCMCIA
+ * service (formerly SS_ProcSetup in Card Services).
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static void sa1100_pcmcia_proc_setup(unsigned int sock,
+				     struct proc_dir_entry *base){
+  struct proc_dir_entry *entry;
+
+  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+
+  if((entry=create_proc_entry("status", 0, base))==NULL){
+    printk(KERN_ERR "Unable to install \"status\" procfs entry\n");
+    return;
+  }
+
+  entry->read_proc=sa1100_pcmcia_proc_status;
+  entry->data=(void *)sock;
+}
+
+
+/* sa1100_pcmcia_proc_status()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the /proc/bus/pccard/??/status file.
+ *
+ * Returns: the number of characters added to the buffer
+ */
+static int sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
+				     int count, int *eof, void *data){
+  char *p=buf;
+  unsigned int sock=(unsigned int)data;
+  unsigned int clock = get_cclk_frequency() * 100;
+  unsigned long mecr = MECR;
+
+  p+=sprintf(p, "k_flags  : %s%s%s%s%s%s%s\n", 
+	     sa1100_pcmcia_socket[sock].k_state.detect?"detect ":"",
+	     sa1100_pcmcia_socket[sock].k_state.ready?"ready ":"",
+	     sa1100_pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"",
+	     sa1100_pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"",
+	     sa1100_pcmcia_socket[sock].k_state.wrprot?"wrprot ":"",
+	     sa1100_pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"",
+	     sa1100_pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":"");
+
+  p+=sprintf(p, "status   : %s%s%s%s%s%s%s%s%s\n",
+	     sa1100_pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"",
+	     sa1100_pcmcia_socket[sock].k_state.ready?"SS_READY ":"",
+	     sa1100_pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"",
+	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
+	     "SS_IOCARD ":"",
+	     (sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD &&
+	      sa1100_pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"",
+	     ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
+	      (sa1100_pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"",
+	     ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
+	      (sa1100_pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"",
+	     sa1100_pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"",
+	     sa1100_pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":"");
+
+  p+=sprintf(p, "mask     : %s%s%s%s%s\n",
+	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\
+	     "SS_DETECT ":"",
+	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\
+	     "SS_READY ":"",
+	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\
+	     "SS_BATDEAD ":"",
+	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\
+	     "SS_BATWARN ":"",
+	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\
+	     "SS_STSCHG ":"");
+
+  p+=sprintf(p, "cs_flags : %s%s%s%s%s\n",
+	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\
+	     "SS_PWR_AUTO ":"",
+	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
+	     "SS_IOCARD ":"",
+	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_RESET?\
+	     "SS_RESET ":"",
+	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\
+	     "SS_SPKR_ENA ":"",
+	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\
+	     "SS_OUTPUT_ENA ":"");
+
+  p+=sprintf(p, "Vcc      : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vcc);
+
+  p+=sprintf(p, "Vpp      : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vpp);
+
+  p+=sprintf(p, "irq      : %d\n", sa1100_pcmcia_socket[sock].cs_state.io_irq);
+
+  p+=sprintf(p, "I/O      : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_io,
+	     sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, sock)));
+
+  p+=sprintf(p, "attribute: %u (%u)\n", sa1100_pcmcia_socket[sock].speed_attr,
+	     sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, sock)));
+
+  p+=sprintf(p, "common   : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_mem,
+	     sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, sock)));
+
+  return p-buf;
+}
+
+#endif  /* defined(CONFIG_PROC_FS) */
+
+
+#ifdef CONFIG_CPU_FREQ
+
+/* sa1100_pcmcia_update_mecr()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * When sa1100_pcmcia_notifier() decides that a MECR adjustment (due
+ * to a core clock frequency change) is needed, this routine establishes
+ * new BS_xx values consistent with the clock speed `clock'.
+ */
+static void sa1100_pcmcia_update_mecr(unsigned int clock){
+  unsigned int sock;
+  unsigned long mecr = MECR;
+
+  for(sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock){
+
+    MECR_BSIO_SET(mecr, sock,
+		  sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_io,
+					clock));
+    MECR_BSA_SET(mecr, sock,
+		 sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_attr,
+				       clock));
+    MECR_BSM_SET(mecr, sock,
+		 sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_mem,
+				       clock));
+  }
+
+  MECR = mecr;
+
+}
+
+/* sa1100_pcmcia_notifier()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^
+ * When changing the processor core clock frequency, it is necessary
+ * to adjust the MECR timings accordingly. We've recorded the timings
+ * requested by Card Services, so this is just a matter of finding
+ * out what our current speed is, and then recomputing the new MECR
+ * values.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int sa1100_pcmcia_notifier(struct notifier_block *nb,
+				  unsigned long val, void *data){
+  struct cpufreq_info *ci = data;
+
+  switch(val){
+  case CPUFREQ_MINMAX:
+
+    break;
+
+  case CPUFREQ_PRECHANGE:
+
+    if(ci->new_freq > ci->old_freq){
+      DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n",
+	    __FUNCTION__,
+	    ci->new_freq / 1000, (ci->new_freq / 100) % 10,
+	    ci->old_freq / 1000, (ci->old_freq / 100) % 10);
+      sa1100_pcmcia_update_mecr(ci->new_freq);
+    }
+
+    break;
+
+  case CPUFREQ_POSTCHANGE:
+
+    if(ci->new_freq < ci->old_freq){
+      DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n",
+	    __FUNCTION__,
+	    ci->new_freq / 1000, (ci->new_freq / 100) % 10,
+	    ci->old_freq / 1000, (ci->old_freq / 100) % 10);
+      sa1100_pcmcia_update_mecr(ci->new_freq);
+    }
+
+    break;
+
+  default:
+    printk(KERN_ERR "%s(): unknown CPU frequency event %lx\n", __FUNCTION__,
+	   val);
+    return -1;
+
+  }
+
+  return 0;
+
+}
+
+static struct notifier_block sa1100_pcmcia_notifier_block = {
+  notifier_call: sa1100_pcmcia_notifier
+};
+
+#endif
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_graphicsclient.c linux/drivers/pcmcia/sa1100_graphicsclient.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_graphicsclient.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_graphicsclient.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,154 @@
+/*
+ * drivers/pcmcia/sa1100_graphicsclient.c
+ *
+ * PCMCIA implementation routines for Graphics Client Plus
+ *
+ * 9/12/01   Woojung
+ *    Turn power OFF at startup
+ * 1/31/2001 Woojung Huh
+ *    Fix for GC Plus PCMCIA Reset Problem
+ * 2/27/2001 Woojung Huh [whuh@applieddata.net]
+ *    Fix
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+#define	S0_CD_IRQ		60				// Socket 0 Card Detect IRQ
+#define	S0_STS_IRQ		55				// Socket 0 PCMCIA IRQ
+
+static volatile unsigned long *PCMCIA_Status = 
+		((volatile unsigned long *) ADS_p2v(_ADS_CS_STATUS));
+
+static volatile unsigned long *PCMCIA_Power = 
+		((volatile unsigned long *) ADS_p2v(_ADS_CS_PR));
+
+static int gcplus_pcmcia_init(struct pcmcia_init *init)
+{
+  int irq, res;
+
+  // Reset PCMCIA
+  // Reset Timing for CPLD(U2) version 8001E or later
+  *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET;
+  udelay(12);			// 12 uSec
+
+  *PCMCIA_Power |= ADS_CS_PR_A_RESET;
+  mdelay(30);			// 30 mSec
+
+  // Turn off 5V
+  *PCMCIA_Power &= ~0x03;
+
+  /* Register interrupts */
+  irq = S0_CD_IRQ;
+  res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA 0 CD", NULL);
+  if (res < 0) {
+	  printk(KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq);
+	  return	-1;
+  }
+
+  return 1;			// 1 PCMCIA Slot
+}
+
+static int gcplus_pcmcia_shutdown(void)
+{
+  /* disable IRQs */
+  free_irq( S0_CD_IRQ, NULL);
+  
+  /* Shutdown PCMCIA power */
+  mdelay(2);						// 2msec
+  *PCMCIA_Power &= ~0x03;
+
+  return 0;
+}
+
+static int gcplus_pcmcia_socket_state(struct pcmcia_state_array
+				       *state_array){
+  unsigned long levels;
+
+  if(state_array->size<1) return -1;
+
+  memset(state_array->state, 0, 
+	 (state_array->size)*sizeof(struct pcmcia_state));
+
+  levels=*PCMCIA_Status;
+
+  state_array->state[0].detect=(levels & ADS_CS_ST_A_CD)?1:0;
+  state_array->state[0].ready=(levels & ADS_CS_ST_A_READY)?1:0;
+  state_array->state[0].bvd1= 0;
+  state_array->state[0].bvd2= 0;
+  state_array->state[0].wrprot=0;
+  state_array->state[0].vs_3v=0;
+  state_array->state[0].vs_Xv=0;
+
+  return 1;
+}
+
+static int gcplus_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+	if (info->sock > 1)
+		return -1;
+
+	if (info->sock == 0)
+		info->irq = S0_STS_IRQ;
+
+  	return 0;
+}
+
+static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure
+					   *configure)
+{
+  unsigned long flags;
+
+  if(configure->sock>1) return -1;
+
+  save_flags_cli(flags);
+
+  switch (configure->vcc) {
+  case 0:
+	  *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER);
+    break;
+
+  case 50:
+	  *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER);
+	  *PCMCIA_Power |= ADS_CS_PR_A_5V_POWER;
+	break;
+
+  case 33:
+	  *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER);
+	  *PCMCIA_Power |= ADS_CS_PR_A_3V_POWER;
+    break;
+
+  default:
+    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	   configure->vcc);
+    restore_flags(flags);
+    return -1;
+  }
+
+  /* Silently ignore Vpp, output enable, speaker enable. */
+
+  // Reset PCMCIA
+  *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET;
+  udelay(12);
+
+  *PCMCIA_Power |= ADS_CS_PR_A_RESET;
+  mdelay(30);
+
+  restore_flags(flags);
+
+  return 0;
+}
+
+struct pcmcia_low_level gcplus_pcmcia_ops = { 
+  gcplus_pcmcia_init,
+  gcplus_pcmcia_shutdown,
+  gcplus_pcmcia_socket_state,
+  gcplus_pcmcia_get_irq_info,
+  gcplus_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_graphicsmaster.c linux/drivers/pcmcia/sa1100_graphicsmaster.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_graphicsmaster.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_graphicsmaster.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,215 @@
+/*
+ * drivers/pcmcia/sa1100_graphicsmaster.c
+ *
+ * PCMCIA implementation routines for GraphicsMaster
+ *
+ * 9/18/01 Woojung
+ *         Fixed wrong PCMCIA voltage setting
+ * 7/5/01 Woojung Huh <whuh@applieddata.net>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/delay.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+static int graphicsmaster_pcmcia_init(struct pcmcia_init *init)
+{
+  int return_val=0;
+
+  /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
+  PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+
+  /* Disable Power 3.3V/5V for PCMCIA/CF */
+  PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
+
+  INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
+			 (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
+    		 (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
+    		 (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
+    		 (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
+    		 (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
+
+  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
+			  "GC Master PCMCIA (0) CD", NULL);
+  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
+			  "GC Master CF (1) CD", NULL);
+  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
+			  "GC Master PCMCIA (0) BVD1", NULL);
+  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
+			  "GC Master CF (1) BVD1", NULL);
+
+  MECR = 0x09430943;
+
+  return (return_val<0) ? -1 : 2;
+}
+
+static int graphicsmaster_pcmcia_shutdown(void)
+{
+
+  free_irq(S0_CD_VALID, NULL);
+  free_irq(S1_CD_VALID, NULL);
+  free_irq(S0_BVD1_STSCHG, NULL);
+  free_irq(S1_BVD1_STSCHG, NULL);
+
+  INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
+			   (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
+      		   (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
+      		   (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
+
+  return 0;
+}
+
+static int graphicsmaster_pcmcia_socket_state(struct pcmcia_state_array *state_array)
+{
+  unsigned long status;
+  int return_val=1;
+
+  if(state_array->size<2) return -1;
+
+  memset(state_array->state, 0,
+	 (state_array->size)*sizeof(struct pcmcia_state));
+
+  status=PCSR;
+
+  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
+
+  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
+
+  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
+
+  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
+
+  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
+
+  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
+
+  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
+
+  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
+
+  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
+
+  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
+
+  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
+
+  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
+
+  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
+
+  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
+
+  return return_val;
+}
+
+static int graphicsmaster_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+
+  switch(info->sock){
+  case 0:
+    info->irq=S0_READY_NINT;
+    break;
+
+  case 1:
+    info->irq=S1_READY_NINT;
+    break;
+
+  default:
+    return -1;
+  }
+
+  return 0;
+}
+
+static int graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *configure)
+{
+  unsigned long pccr=PCCR, gpio=PA_DWR;
+
+  switch(configure->sock){
+  case 0:
+
+    switch(configure->vcc){
+    case 0:
+      pccr = (pccr & ~PCCR_S0_FLT);
+      gpio |= GPIO_GPIO0 | GPIO_GPIO1;
+      break;
+
+    case 33:
+      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
+      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
+	  gpio &= ~GPIO_GPIO0;
+      break;
+
+    case 50:
+      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
+      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
+	  gpio |= GPIO_GPIO0;
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	     configure->vcc);
+      return -1;
+    }
+
+    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
+
+    break;
+
+  case 1:
+    switch(configure->vcc){
+    case 0:
+      pccr = (pccr & ~PCCR_S1_FLT);
+      gpio |= GPIO_GPIO2 | GPIO_GPIO3;
+      break;
+
+    case 33:
+      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
+      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
+	  gpio &= ~GPIO_GPIO2;
+      break;
+
+    case 50:
+      pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
+      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
+	  gpio |= GPIO_GPIO2;
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	     configure->vcc);
+      return -1;
+    }
+
+    if(configure->vpp!=configure->vcc && configure->vpp!=0){
+      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
+	     configure->vpp);
+      return -1;
+    }
+
+    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
+
+    break;
+
+  default:
+    return -1;
+  }
+
+  PCCR = pccr;
+  PA_DWR = gpio;
+
+  return 0;
+}
+
+struct pcmcia_low_level graphicsmaster_pcmcia_ops = {
+  graphicsmaster_pcmcia_init,
+  graphicsmaster_pcmcia_shutdown,
+  graphicsmaster_pcmcia_socket_state,
+  graphicsmaster_pcmcia_get_irq_info,
+  graphicsmaster_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_h3600.c linux/drivers/pcmcia/sa1100_h3600.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_h3600.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_h3600.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,147 @@
+/*
+ * drivers/pcmcia/sa1100_h3600.c
+ *
+ * PCMCIA implementation routines for H3600
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+
+static int h3600_pcmcia_init(struct pcmcia_init *init){
+  int irq, res;
+
+  /* Enable CF bus: */
+  set_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON);
+  clr_h3600_egpio(EGPIO_H3600_OPT_RESET);
+
+  /* All those are inputs */
+  GPDR &= ~(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1 | GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1);
+
+  /* Set transition detect */
+  set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES );
+  set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1, GPIO_FALLING_EDGE );
+
+  /* Register interrupts */
+  irq = IRQ_GPIO_H3600_PCMCIA_CD0;
+  res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD0", NULL );
+  if( res < 0 ) goto irq_err;
+  irq = IRQ_GPIO_H3600_PCMCIA_CD1;
+  res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD1", NULL );
+  if( res < 0 ) goto irq_err;
+
+  return 2;
+
+irq_err:
+  printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq );
+  return -1;
+}
+
+static int h3600_pcmcia_shutdown(void)
+{
+  /* disable IRQs */
+  free_irq( IRQ_GPIO_H3600_PCMCIA_CD0, NULL );
+  free_irq( IRQ_GPIO_H3600_PCMCIA_CD1, NULL );
+  
+  /* Disable CF bus: */
+  clr_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON|EGPIO_H3600_OPT_ON);
+  set_h3600_egpio(EGPIO_H3600_OPT_RESET);
+
+  return 0;
+}
+
+static int h3600_pcmcia_socket_state(struct pcmcia_state_array
+				       *state_array){
+  unsigned long levels;
+
+  if(state_array->size<2) return -1;
+
+  memset(state_array->state, 0, 
+	 (state_array->size)*sizeof(struct pcmcia_state));
+
+  levels=GPLR;
+
+  state_array->state[0].detect=((levels & GPIO_H3600_PCMCIA_CD0)==0)?1:0;
+  state_array->state[0].ready=(levels & GPIO_H3600_PCMCIA_IRQ0)?1:0;
+  state_array->state[0].bvd1= 0;
+  state_array->state[0].bvd2= 0;
+  state_array->state[0].wrprot=0; /* Not available on H3600. */
+  state_array->state[0].vs_3v=0;
+  state_array->state[0].vs_Xv=0;
+
+  state_array->state[1].detect=((levels & GPIO_H3600_PCMCIA_CD1)==0)?1:0;
+  state_array->state[1].ready=(levels & GPIO_H3600_PCMCIA_IRQ1)?1:0;
+  state_array->state[1].bvd1=0;
+  state_array->state[1].bvd2=0;
+  state_array->state[1].wrprot=0; /* Not available on H3600. */
+  state_array->state[1].vs_3v=0;
+  state_array->state[1].vs_Xv=0;
+
+  return 1;
+}
+
+static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+
+  switch (info->sock) {
+  case 0:
+    info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ0;
+    break;
+  case 1:
+    info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ1;
+    break;
+  default:
+    return -1;
+  }
+  return 0;
+}
+
+static int h3600_pcmcia_configure_socket(const struct pcmcia_configure
+					   *configure)
+{
+  unsigned long flags;
+
+  if(configure->sock>1) return -1;
+
+  save_flags_cli(flags);
+
+  switch (configure->vcc) {
+  case 0:
+    clr_h3600_egpio(EGPIO_H3600_OPT_ON);
+    break;
+
+  case 33:
+  case 50:
+    set_h3600_egpio(EGPIO_H3600_OPT_ON);
+    break;
+
+  default:
+    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	   configure->vcc);
+    restore_flags(flags);
+    return -1;
+  }
+
+  if (configure->reset)
+    set_h3600_egpio(EGPIO_H3600_CARD_RESET);
+  else
+    clr_h3600_egpio(EGPIO_H3600_CARD_RESET);
+
+  /* Silently ignore Vpp, output enable, speaker enable. */
+
+  restore_flags(flags);
+
+  return 0;
+}
+
+struct pcmcia_low_level h3600_pcmcia_ops = { 
+  h3600_pcmcia_init,
+  h3600_pcmcia_shutdown,
+  h3600_pcmcia_socket_state,
+  h3600_pcmcia_get_irq_info,
+  h3600_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_jornada720.c linux/drivers/pcmcia/sa1100_jornada720.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_jornada720.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_jornada720.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,215 @@
+/*
+ * drivers/pcmcia/sa1100_jornada720.c
+ *
+ * Jornada720 PCMCIA specific routines
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/delay.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+#define SOCKET0_POWER   GPIO_GPIO0
+#define SOCKET0_3V      GPIO_GPIO2
+#define SOCKET1_POWER   (GPIO_GPIO1 | GPIO_GPIO3)
+#define SOCKET1_3V   GPIO_GPIO3
+
+static int jornada720_pcmcia_init(struct pcmcia_init *init)
+{
+  int return_val=0;
+
+  GRER |= 0x00000002;
+  /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
+  PA_DDR = 0;
+  PA_DWR = 0;
+  PA_SDR = 0;
+  PA_SSR = 0;
+
+  PB_DDR = 0;
+  PB_DWR = 0x01;
+  PB_SDR = 0;
+  PB_SSR = 0;
+
+  PC_DDR = 0x88;
+  PC_DWR = 0x20;
+  PC_SDR = 0;
+  PC_SSR = 0;
+
+  INTPOL1 |=
+    (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
+    (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
+    (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
+    (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
+    (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
+    (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
+
+  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
+			  "Jornada720 PCMCIA (0) CD", NULL);
+  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
+			  "Jornada720 CF (1) CD", NULL);
+  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
+			  "Jornada720 PCMCIA (0) BVD1", NULL);
+  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
+			  "Jornada720 CF (1) BVD1", NULL);
+
+  return (return_val<0) ? -1 : 2;
+}
+
+static int jornada720_pcmcia_shutdown(void)
+{
+  free_irq(S0_CD_VALID, NULL);
+  free_irq(S1_CD_VALID, NULL);
+  free_irq(S0_BVD1_STSCHG, NULL);
+  free_irq(S1_BVD1_STSCHG, NULL);
+
+  INTPOL1 &=
+    ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
+      (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
+      (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
+      (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
+
+  return 0;
+}
+
+static int jornada720_pcmcia_socket_state(struct pcmcia_state_array
+					*state_array)
+{
+  unsigned long status;
+  int return_val=1;
+
+  if(state_array->size<2) return -1;
+
+  memset(state_array->state, 0,
+	 (state_array->size)*sizeof(struct pcmcia_state));
+  status=PCSR;
+  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
+  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
+  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
+  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
+  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
+  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
+  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
+  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
+  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
+  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
+  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
+  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
+  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
+  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
+  return return_val;
+}
+
+static int jornada720_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+  switch(info->sock){
+  case 0:
+    info->irq=S0_READY_NINT;
+    break;
+
+  case 1:
+    info->irq=S1_READY_NINT;
+    break;
+
+  default:
+    return -1;
+  }
+  return 0;
+}
+
+static int jornada720_pcmcia_configure_socket(const struct pcmcia_configure
+					    *configure)
+{
+  unsigned long pccr=PCCR, gpio=PA_DWR;
+
+printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
+	       configure->sock, configure->vcc, configure->vpp);
+  switch(configure->sock){
+  case 0:
+    switch(configure->vcc){
+    case 0:
+      pccr = (pccr & ~PCCR_S0_FLT);
+      gpio&=~(SOCKET0_POWER | SOCKET0_3V);
+      break;
+
+    case 33:
+      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
+      gpio |= SOCKET0_POWER | SOCKET0_3V;
+      break;
+
+    case 50:
+      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
+      gpio = (gpio & ~SOCKET0_3V) | SOCKET0_POWER;
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	     configure->vcc);
+      return -1;
+    }
+    switch(configure->vpp){
+    case 0:
+      break;
+    case 50:
+	printk(KERN_ERR "%s(): 5.0 Vpp %u\n", __FUNCTION__,
+	       configure->vpp);
+      break;
+    case 120:
+	printk(KERN_ERR "%s(): 12 Vpp %u\n", __FUNCTION__,
+	       configure->vpp);
+      break;
+    default:
+	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
+	       configure->vpp);
+	return -1;
+    }
+    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
+    break;
+
+  case 1:
+    switch(configure->vcc){
+    case 0:
+      pccr = (pccr & ~PCCR_S1_FLT);
+      gpio &= ~(SOCKET1_POWER);
+      break;
+
+    case 33:
+      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
+      gpio |= SOCKET1_POWER;
+      break;
+
+    case 50:
+      pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
+      gpio = (gpio & ~(SOCKET1_POWER)) | SOCKET1_POWER;
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	     configure->vcc);
+      return -1;
+    }
+    if(configure->vpp!=configure->vcc && configure->vpp!=0){
+      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
+	     configure->vpp);
+      return -1;
+    }
+    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
+    break;
+  default:
+    return -1;
+  }
+  PCCR = pccr;
+  PA_DWR = gpio;
+  return 0;
+}
+
+struct pcmcia_low_level jornada720_pcmcia_ops = {
+  jornada720_pcmcia_init,
+  jornada720_pcmcia_shutdown,
+  jornada720_pcmcia_socket_state,
+  jornada720_pcmcia_get_irq_info,
+  jornada720_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_neponset.c linux/drivers/pcmcia/sa1100_neponset.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_neponset.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_neponset.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,248 @@
+/*
+ * drivers/pcmcia/sa1100_neponset.c
+ *
+ * Neponset PCMCIA specific routines
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/delay.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+static int neponset_pcmcia_init(struct pcmcia_init *init){
+  int return_val=0;
+
+  /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
+  PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+  
+  /* MAX1600 to standby mode: */
+  PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+  NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
+
+  INTPOL1 |= 
+    (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
+    (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
+    (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
+    (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
+    (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
+    (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
+
+  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
+			  "Neponset PCMCIA (0) CD", NULL);
+  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
+			  "Neponset CF (1) CD", NULL);
+  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
+			  "Neponset PCMCIA (0) BVD1", NULL);
+  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
+			  "Neponset CF (1) BVD1", NULL);
+
+  return (return_val<0) ? -1 : 2;
+}
+
+static int neponset_pcmcia_shutdown(void){
+
+  free_irq(S0_CD_VALID, NULL);
+  free_irq(S1_CD_VALID, NULL);
+  free_irq(S0_BVD1_STSCHG, NULL);
+  free_irq(S1_BVD1_STSCHG, NULL);
+
+  INTPOL1 &= 
+    ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
+      (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
+      (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
+      (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
+
+  return 0;
+}
+
+static int neponset_pcmcia_socket_state(struct pcmcia_state_array
+					*state_array){
+  unsigned long status;
+  int return_val=1;
+
+  if(state_array->size<2) return -1;
+
+  memset(state_array->state, 0, 
+	 (state_array->size)*sizeof(struct pcmcia_state));
+
+  status=PCSR;
+
+  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
+
+  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
+
+  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
+
+  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
+
+  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
+
+  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
+
+  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
+
+  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
+
+  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
+
+  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
+
+  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
+
+  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
+
+  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
+
+  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
+
+  return return_val;
+}
+
+static int neponset_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+
+  switch(info->sock){
+  case 0:
+    info->irq=S0_READY_NINT;
+    break;
+
+  case 1:
+    info->irq=S1_READY_NINT;
+    break;
+
+  default:
+    return -1;
+  }
+
+  return 0;
+}
+
+static int neponset_pcmcia_configure_socket(const struct pcmcia_configure
+					    *configure){
+  unsigned long pccr=PCCR, ncr=NCR_0, gpio=PA_DWR;
+
+  /* Neponset uses the Maxim MAX1600, with the following connections:
+   *
+   *   MAX1600      Neponset
+   *
+   *    A0VCC        SA-1111 GPIO A<1>
+   *    A1VCC        SA-1111 GPIO A<0>
+   *    A0VPP        CPLD NCR A0VPP
+   *    A1VPP        CPLD NCR A1VPP
+   *    B0VCC        SA-1111 GPIO A<2>
+   *    B1VCC        SA-1111 GPIO A<3>
+   *    B0VPP        ground (slot B is CF)
+   *    B1VPP        ground (slot B is CF)
+   *
+   *     VX          VCC (5V)
+   *     VY          VCC3_3 (3.3V)
+   *     12INA       12V
+   *     12INB       ground (slot B is CF)
+   *
+   * The MAX1600 CODE pin is tied to ground, placing the device in 
+   * "Standard Intel code" mode. Refer to the Maxim data sheet for
+   * the corresponding truth table.
+   */
+
+  switch(configure->sock){
+  case 0:
+    
+    switch(configure->vcc){
+    case 0:
+      pccr=(pccr & ~PCCR_S0_FLT);
+      gpio&=~(GPIO_GPIO0 | GPIO_GPIO1);
+      break;
+
+    case 33:
+      pccr=(pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
+      gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1;
+      break;
+
+    case 50:
+      pccr=(pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
+      gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0;
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	     configure->vcc);
+      return -1;
+    }
+
+    switch(configure->vpp){
+    case 0:
+      ncr&=~(NCR_A0VPP | NCR_A1VPP);
+      break;
+
+    case 120:
+      ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP;
+      break;
+
+    default:
+      if(configure->vpp == configure->vcc)
+	ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP;
+      else {
+	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
+	       configure->vpp);
+	return -1;
+      }
+    }
+
+    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
+
+    break;
+
+  case 1:
+    switch(configure->vcc){
+    case 0:
+      pccr=(pccr & ~PCCR_S1_FLT);
+      gpio&=~(GPIO_GPIO2 | GPIO_GPIO3);
+      break;
+
+    case 33:
+      pccr=(pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
+      gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO2;
+      break;
+
+    case 50:
+      pccr=(pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
+      gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3;
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	     configure->vcc);
+      return -1;
+    }
+
+    if(configure->vpp!=configure->vcc && configure->vpp!=0){
+      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
+	     configure->vpp);
+      return -1;
+    }
+
+    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
+
+    break;
+
+  default:
+    return -1;
+  }
+
+  PCCR = pccr;
+  NCR_0 = ncr;
+  PA_DWR = gpio;
+
+  return 0;
+}
+
+struct pcmcia_low_level neponset_pcmcia_ops = { 
+  neponset_pcmcia_init,
+  neponset_pcmcia_shutdown,
+  neponset_pcmcia_socket_state,
+  neponset_pcmcia_get_irq_info,
+  neponset_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_pangolin.c linux/drivers/pcmcia/sa1100_pangolin.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_pangolin.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_pangolin.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,157 @@
+/*
+ * drivers/pcmcia/sa1100_pangolin.c
+ *
+ * PCMCIA implementation routines for Pangolin
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+static int pangolin_pcmcia_init(struct pcmcia_init *init){
+  int irq, res;
+
+  /* set GPIO_PCMCIA_CD & GPIO_PCMCIA_IRQ as inputs */
+  GPDR &= ~(GPIO_PCMCIA_CD|GPIO_PCMCIA_IRQ);
+#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
+  /* set GPIO pins GPIO_PCMCIA_BUS_ON & GPIO_PCMCIA_RESET as output */
+  GPDR |= (GPIO_PCMCIA_BUS_ON|GPIO_PCMCIA_RESET);
+  /* Enable PCMCIA bus: */
+  GPCR = GPIO_PCMCIA_BUS_ON;
+#else
+  /* set GPIO pin GPIO_PCMCIA_RESET as output */
+  GPDR |= GPIO_PCMCIA_RESET;
+#endif
+  /* Set transition detect */
+  set_GPIO_IRQ_edge( GPIO_PCMCIA_CD, GPIO_BOTH_EDGES );
+  set_GPIO_IRQ_edge( GPIO_PCMCIA_IRQ, GPIO_FALLING_EDGE );
+
+  /* Register interrupts */
+  irq = IRQ_PCMCIA_CD;
+  res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD", NULL );
+  if( res < 0 ) goto irq_err;
+
+  /* There's only one slot, but it's "Slot 1": */
+  return 2;
+
+irq_err:
+  printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq );
+  return -1;
+}
+
+static int pangolin_pcmcia_shutdown(void)
+{
+  /* disable IRQs */
+  free_irq( IRQ_PCMCIA_CD, NULL );
+#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
+    /* Disable PCMCIA bus: */
+    GPSR = GPIO_PCMCIA_BUS_ON;
+#endif
+  return 0;
+}
+
+static int pangolin_pcmcia_socket_state(struct pcmcia_state_array
+				       *state_array){
+  unsigned long levels;
+
+  if(state_array->size<2) return -1;
+
+  memset(state_array->state, 0, 
+	 (state_array->size)*sizeof(struct pcmcia_state));
+
+  levels=GPLR;
+#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
+  state_array->state[1].detect=((levels & GPIO_PCMCIA_CD)==0)?1:0;
+  state_array->state[1].ready=(levels & GPIO_PCMCIA_IRQ)?1:0;
+  state_array->state[1].bvd1=1; /* Not available on Pangolin. */
+  state_array->state[1].bvd2=1; /* Not available on Pangolin. */
+  state_array->state[1].wrprot=0; /* Not available on Pangolin. */
+  state_array->state[1].vs_3v=1;  /* Can only apply 3.3V on Pangolin. */
+  state_array->state[1].vs_Xv=0;
+#else
+  state_array->state[0].detect=((levels & GPIO_PCMCIA_CD)==0)?1:0;
+  state_array->state[0].ready=(levels & GPIO_PCMCIA_IRQ)?1:0;
+  state_array->state[0].bvd1=1; /* Not available on Pangolin. */
+  state_array->state[0].bvd2=1; /* Not available on Pangolin. */
+  state_array->state[0].wrprot=0; /* Not available on Pangolin. */
+  state_array->state[0].vs_3v=0;  /* voltage level is determined by jumper setting */
+  state_array->state[0].vs_Xv=0;
+#endif
+  return 1;
+}
+
+static int pangolin_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+
+  if(info->sock>1) return -1;
+#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
+  if(info->sock==1)
+	info->irq=IRQ_PCMCIA_IRQ;
+#else
+  if(info->sock==0)
+        info->irq=IRQ_PCMCIA_IRQ;
+#endif
+  return 0;
+}
+
+static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure
+					   *configure)
+{
+  unsigned long value, flags;
+
+  if(configure->sock>1) return -1;
+#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
+  if(configure->sock==0) return 0;
+#endif
+  save_flags_cli(flags);
+
+  /* Murphy: BUS_ON different from POWER ? */
+
+  switch(configure->vcc){
+  case 0:
+    break;
+#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
+  case 50:
+    printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
+	   __FUNCTION__);
+  case 33:  /* Can only apply 3.3V to the CF slot. */
+    break;
+#else
+  case 50:
+    printk(KERN_WARNING "%s(): CS asked for 5V, determinded by jumper setting...\n", __FUNCTION__);
+    break;
+  case 33:
+    printk(KERN_WARNING "%s(): CS asked for 3.3V, determined by jumper setting...\n", __FUNCTION__);
+    break;
+#endif
+  default:
+    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	   configure->vcc);
+    restore_flags(flags);
+    return -1;
+  }
+#ifdef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
+  /* reset & unreset request */
+  if(configure->sock==0) {
+	if(configure->reset) {
+		GPSR |= GPIO_PCMCIA_RESET;
+	} else {
+		GPCR |= GPIO_PCMCIA_RESET;
+	}
+  }
+#endif
+  /* Silently ignore Vpp, output enable, speaker enable. */
+  restore_flags(flags);
+  return 0;
+}
+
+struct pcmcia_low_level pangolin_pcmcia_ops = { 
+  pangolin_pcmcia_init,
+  pangolin_pcmcia_shutdown,
+  pangolin_pcmcia_socket_state,
+  pangolin_pcmcia_get_irq_info,
+  pangolin_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_pfs168.c linux/drivers/pcmcia/sa1100_pfs168.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_pfs168.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_pfs168.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,237 @@
+#warning	"REVISIT_PFS168: Need to verify and test GPIO power encodings."
+/*
+ * drivers/pcmcia/sa1100_pfs168.c
+ *
+ * PFS168 PCMCIA specific routines
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/delay.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+static int pfs168_pcmcia_init(struct pcmcia_init *init){
+  int return_val=0;
+
+  /* TPS2211 to standby mode: */
+  PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+
+  /* Set GPIO_A<3:0> to be outputs for PCMCIA (socket 0) power controller: */
+  PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+
+  INTPOL1 |=
+    (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
+    (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
+    (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
+    (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
+    (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
+    (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
+
+  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
+			  "PFS168 PCMCIA (0) CD", NULL);
+  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
+			  "PFS168 CF (1) CD", NULL);
+  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
+			  "PFS168 PCMCIA (0) BVD1", NULL);
+  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
+			  "PFS168 CF (1) BVD1", NULL);
+
+  return (return_val<0) ? -1 : 2;
+}
+
+static int pfs168_pcmcia_shutdown(void){
+
+  free_irq(S0_CD_VALID, NULL);
+  free_irq(S1_CD_VALID, NULL);
+  free_irq(S0_BVD1_STSCHG, NULL);
+  free_irq(S1_BVD1_STSCHG, NULL);
+
+  INTPOL1 &=
+    ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
+      (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
+      (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
+      (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
+
+  return 0;
+}
+
+static int pfs168_pcmcia_socket_state(struct pcmcia_state_array
+					*state_array){
+  unsigned long status;
+  int return_val=1;
+
+  if(state_array->size<2) return -1;
+
+  memset(state_array->state, 0,
+	 (state_array->size)*sizeof(struct pcmcia_state));
+
+  status=PCSR;
+
+  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
+
+  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
+
+  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
+
+  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
+
+  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
+
+  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
+
+  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
+
+  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
+
+  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
+
+  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
+
+  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
+
+  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
+
+  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
+
+  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
+
+  return return_val;
+}
+
+static int pfs168_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+
+  switch(info->sock){
+  case 0:
+    info->irq=S0_READY_NINT;
+    break;
+
+  case 1:
+    info->irq=S1_READY_NINT;
+    break;
+
+  default:
+    return -1;
+  }
+
+  return 0;
+}
+
+static int pfs168_pcmcia_configure_socket(const struct pcmcia_configure
+					    *configure){
+  unsigned long pccr=PCCR, gpio=PA_DWR;
+
+  /* PFS168 uses the Texas Instruments TPS2211 for PCMCIA (socket 0) voltage control only,
+   * with the following connections:
+   *
+   *   TPS2211      PFS168
+   *
+   *    -VCCD0      SA-1111 GPIO A<0>
+   *    -VCCD0      SA-1111 GPIO A<1>
+   *     VPPD0      SA-1111 GPIO A<2>
+   *     VPPD0      SA-1111 GPIO A<2>
+   *
+   */
+
+  switch(configure->sock){
+  case 0:
+
+    switch(configure->vcc){
+    case 0:
+      pccr = (pccr & ~PCCR_S0_FLT);
+      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
+      break;
+
+    case 33:
+      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
+      gpio = (gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0;
+      break;
+
+    case 50:
+      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
+      gpio = (gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1;
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	     configure->vcc);
+      return -1;
+    }
+
+    switch(configure->vpp){
+    case 0:
+      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
+      break;
+
+    case 120:
+      printk(KERN_ERR "%s(): PFS-168 does not support Vpp %uV\n", __FUNCTION__,
+	     configure->vpp/10);
+      return -1;
+      break;
+
+    default:
+      if(configure->vpp == configure->vcc)
+        gpio = (gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3;
+      else {
+	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
+	       configure->vpp);
+	return -1;
+      }
+    }
+
+    pccr = (configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
+
+    PA_DWR = gpio;
+
+    break;
+
+  case 1:
+    switch(configure->vcc){
+    case 0:
+      pccr = (pccr & ~PCCR_S1_FLT);
+      break;
+
+    case 33:
+      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
+      break;
+
+    case 50:
+      printk(KERN_ERR "%s(): PFS-168 CompactFlash socket does not support Vcc %uV\n", __FUNCTION__,
+	     configure->vcc/10);
+      return -1;
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	     configure->vcc);
+      return -1;
+    }
+
+    if(configure->vpp!=configure->vcc && configure->vpp!=0){
+      printk(KERN_ERR "%s(): CompactFlash socket does not support Vpp %uV\n", __FUNCTION__,
+	     configure->vpp/10);
+      return -1;
+    }
+
+    pccr = (configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
+
+    break;
+
+  default:
+    return -1;
+  }
+
+  PCCR = pccr;
+
+  return 0;
+}
+
+struct pcmcia_low_level pfs168_pcmcia_ops = {
+  pfs168_pcmcia_init,
+  pfs168_pcmcia_shutdown,
+  pfs168_pcmcia_socket_state,
+  pfs168_pcmcia_get_irq_info,
+  pfs168_pcmcia_configure_socket
+};
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_simpad.c linux/drivers/pcmcia/sa1100_simpad.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_simpad.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_simpad.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,136 @@
+/*
+ * drivers/pcmcia/sa1100_pangolin.c
+ *
+ * PCMCIA implementation routines for simpad
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+static int simpad_pcmcia_init(struct pcmcia_init *init){
+  int irq, res;
+
+  /* set GPIO_CF_CD & GPIO_CF_IRQ as inputs */
+  GPDR &= ~(GPIO_CF_CD|GPIO_CF_IRQ);
+  //init_simpad_cs3();
+  printk("\nCS3:%x\n",cs3_shadow);
+  PCMCIA_setbit(PCMCIA_RESET);
+  PCMCIA_clearbit(PCMCIA_BUFF_DIS);
+
+  /* Set transition detect */
+  set_GPIO_IRQ_edge( GPIO_CF_CD, GPIO_BOTH_EDGES );
+  set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
+
+  /* Register interrupts */
+  irq = IRQ_GPIO_CF_CD;
+  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL );
+  if( res < 0 ) goto irq_err;
+
+  /* There's only one slot, but it's "Slot 1": */
+  return 2;
+
+irq_err:
+  printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq );
+  return -1;
+}
+
+static int simpad_pcmcia_shutdown(void)
+{
+  /* disable IRQs */
+  free_irq( IRQ_GPIO_CF_CD, NULL );
+
+  /* Disable CF bus: */
+
+  PCMCIA_setbit(PCMCIA_BUFF_DIS);
+  PCMCIA_clearbit(PCMCIA_RESET);
+  return 0;
+}
+
+static int simpad_pcmcia_socket_state(struct pcmcia_state_array
+				       *state_array)
+{
+  unsigned long levels;
+
+  if(state_array->size<2) return -1;
+
+  memset(state_array->state, 0,
+	 (state_array->size)*sizeof(struct pcmcia_state));
+
+  levels=GPLR;
+
+  state_array->state[1].detect=((levels & GPIO_CF_CD)==0)?1:0;
+
+  state_array->state[1].ready=(levels & GPIO_CF_IRQ)?1:0;
+
+  state_array->state[1].bvd1=1; /* Not available on Simpad. */
+
+  state_array->state[1].bvd2=1; /* Not available on Simpad. */
+
+  state_array->state[1].wrprot=0; /* Not available on Simpad. */
+
+  state_array->state[1].vs_3v=1;  /* Can only apply 3.3V on Simpad. */
+
+  state_array->state[1].vs_Xv=0;
+
+  return 1;
+}
+
+static int simpad_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+
+  if(info->sock>1) return -1;
+
+  if(info->sock==1)
+    info->irq=IRQ_GPIO_CF_IRQ;
+
+  return 0;
+}
+
+static int simpad_pcmcia_configure_socket(const struct pcmcia_configure
+					   *configure)
+{
+  unsigned long value, flags;
+
+  if(configure->sock>1) return -1;
+
+  if(configure->sock==0) return 0;
+
+  save_flags_cli(flags);
+
+  /* Murphy: BUS_ON different from POWER ? */
+
+  switch(configure->vcc){
+  case 0:
+    PCMCIA_setbit(PCMCIA_BUFF_DIS);
+    break;
+
+  case 33:
+  case 50:
+    PCMCIA_setbit(PCMCIA_BUFF_DIS);
+    break;
+
+  default:
+    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	   configure->vcc);
+    restore_flags(flags);
+    return -1;
+  }
+
+  /* Silently ignore Vpp, output enable, speaker enable. */
+
+  restore_flags(flags);
+
+  return 0;
+}
+
+struct pcmcia_low_level simpad_pcmcia_ops = {
+  simpad_pcmcia_init,
+  simpad_pcmcia_shutdown,
+  simpad_pcmcia_socket_state,
+  simpad_pcmcia_get_irq_info,
+  simpad_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_stork.c linux/drivers/pcmcia/sa1100_stork.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_stork.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_stork.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,202 @@
+/* 
+ * drivers/pcmcia/sa1100_stork.c
+ *
+    Copyright 2001 (C) Ken Gordon
+
+    This is derived from pre-existing drivers/pcmcia/sa1100_?????.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
+    the Free Software Foundation; either version 2 of the License.
+
+    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.
+
+ * 
+ * PCMCIA implementation routines for stork
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+static int debug = 0;
+
+static struct pcmcia_init sa1100_stork_pcmcia_init;
+
+static int stork_pcmcia_init(struct pcmcia_init *init)
+{
+        int irq, res;
+        printk("in stork_pcmcia_init\n");
+
+        sa1100_stork_pcmcia_init = *init;
+
+        /* Enable CF bus: */
+        storkSetLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
+
+        /* All those are inputs */
+	GPDR &= ~(GPIO_STORK_PCMCIA_A_CARD_DETECT | GPIO_STORK_PCMCIA_B_CARD_DETECT | GPIO_STORK_PCMCIA_A_RDY| GPIO_STORK_PCMCIA_B_RDY);
+
+	/* Set transition detect */
+	set_GPIO_IRQ_edge( GPIO_STORK_PCMCIA_A_CARD_DETECT | GPIO_STORK_PCMCIA_B_CARD_DETECT, GPIO_BOTH_EDGES );
+        set_GPIO_IRQ_edge( GPIO_STORK_PCMCIA_A_RDY| GPIO_STORK_PCMCIA_B_RDY, GPIO_FALLING_EDGE );
+
+	/* Register interrupts */
+	irq = IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT;
+	res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD0", NULL );
+	if( res < 0 ) goto irq_err;
+	irq = IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT;
+	res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD1", NULL );
+	if( res < 0 ) goto irq_err;
+
+        return 2;
+
+ irq_err:
+        printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq );
+        return -1;
+}
+
+static int stork_pcmcia_shutdown(void)
+{
+        printk(__FUNCTION__ "\n");
+        /* disable IRQs */
+        free_irq( IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, NULL );
+        free_irq( IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, NULL );
+  
+        /* Disable CF bus: */
+        storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
+	storkClearLatchA(STORK_PCMCIA_A_POWER_ON);
+	storkClearLatchA(STORK_PCMCIA_B_POWER_ON);
+        return 0;
+}
+
+static int stork_pcmcia_socket_state(struct pcmcia_state_array *state_array)
+{
+        unsigned long levels;
+
+        if(state_array->size<2) return -1;
+
+        memset(state_array->state, 0, 
+               (state_array->size)*sizeof(struct pcmcia_state));
+
+        levels=GPLR;
+
+	if (debug > 1)
+		printk(__FUNCTION__ " GPLR=%x IRQ[1:0]=%x\n", GPLR, (GPLR & (GPIO_STORK_PCMCIA_A_RDY|GPIO_STORK_PCMCIA_B_RDY)));
+	state_array->state[0].detect=((levels & GPIO_STORK_PCMCIA_A_CARD_DETECT)==0)?1:0;
+	state_array->state[0].ready=(levels & GPIO_STORK_PCMCIA_A_RDY)?1:0;
+	state_array->state[0].bvd1= 1;
+	state_array->state[0].bvd2= 1;
+	state_array->state[0].wrprot=0;
+	state_array->state[0].vs_3v=1;
+	state_array->state[0].vs_Xv=0;
+
+	state_array->state[1].detect=((levels & GPIO_STORK_PCMCIA_B_CARD_DETECT)==0)?1:0;
+	state_array->state[1].ready=(levels & GPIO_STORK_PCMCIA_B_RDY)?1:0;
+	state_array->state[1].bvd1=1;
+	state_array->state[1].bvd2=1;
+	state_array->state[1].wrprot=0;
+	state_array->state[1].vs_3v=1;
+	state_array->state[1].vs_Xv=0;
+
+        return 1;
+}
+
+static int stork_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+
+        switch (info->sock) {
+        case 0:
+                info->irq=IRQ_GPIO_STORK_PCMCIA_A_RDY;
+                break;
+        case 1:
+                info->irq=IRQ_GPIO_STORK_PCMCIA_B_RDY;
+                break;
+        default:
+                return -1;
+        }
+        return 0;
+}
+
+static int stork_pcmcia_configure_socket(const struct pcmcia_configure *configure)
+{
+        int card = configure->sock;
+	unsigned long flags;
+
+        int DETECT, RDY, POWER, RESET;
+
+        if (card > 1) return -1;
+
+	printk(__FUNCTION__ ": socket=%d vcc=%d vpp=%d reset=%d\n", 
+                       card, configure->vcc, configure->vpp, configure->reset);
+
+	save_flags_cli(flags);
+
+        if (card == 0) {
+    	    DETECT = GPIO_STORK_PCMCIA_A_CARD_DETECT;
+    	    RDY = GPIO_STORK_PCMCIA_A_RDY;
+    	    POWER = STORK_PCMCIA_A_POWER_ON;
+    	    RESET = STORK_PCMCIA_A_RESET;
+        } else {
+    	    DETECT = GPIO_STORK_PCMCIA_B_CARD_DETECT;
+    	    RDY = GPIO_STORK_PCMCIA_B_RDY;
+    	    POWER = STORK_PCMCIA_B_POWER_ON;
+    	    RESET = STORK_PCMCIA_B_RESET;
+        }
+    
+/*
+        if (storkTestGPIO(DETECT)) {
+           printk("no card detected - but resetting anyway\r\n");
+        }
+*/
+	switch (configure->vcc) {
+	case 0:
+		storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
+                storkClearLatchA(POWER);
+		break;
+
+	case 50:
+	case 33:
+                storkSetLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
+                storkSetLatchA(POWER);
+		break;
+
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+		       configure->vcc);
+		restore_flags(flags);
+		return -1;
+	}
+
+	if (configure->reset)
+                storkSetLatchB(RESET);
+	else
+                storkClearLatchB(RESET);
+
+	restore_flags(flags);
+
+        /* silently ignore vpp and speaker enables. */
+
+        printk(__FUNCTION__ ": finished\n");
+
+        return 0;
+}
+
+struct pcmcia_low_level stork_pcmcia_ops = { 
+        stork_pcmcia_init,
+        stork_pcmcia_shutdown,
+        stork_pcmcia_socket_state,
+        stork_pcmcia_get_irq_info,
+        stork_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_xp860.c linux/drivers/pcmcia/sa1100_xp860.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_xp860.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_xp860.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,255 @@
+/*
+ * drivers/pcmcia/sa1100_xp860.c
+ *
+ * XP860 PCMCIA specific routines
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+#define NCR_A0VPP	(1<<16)
+#define NCR_A1VPP	(1<<17)
+
+static int xp860_pcmcia_init(struct pcmcia_init *init){
+  int return_val=0;
+
+  /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
+  PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+  
+  /* MAX1600 to standby mode: */
+  PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+  GPDR |= (NCR_A0VPP | NCR_A1VPP);
+  GPCR &= ~(NCR_A0VPP | NCR_A1VPP);
+
+  INTPOL1 |= 
+    (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
+    (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
+    (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
+    (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
+    (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
+    (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
+
+  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
+			  "XP860 PCMCIA (0) CD", NULL);
+  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
+			  "XP860 CF (1) CD", NULL);
+  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
+			  "XP860 PCMCIA (0) BVD1", NULL);
+  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
+			  "XP860 CF (1) BVD1", NULL);
+
+  return (return_val<0) ? -1 : 2;
+}
+
+static int xp860_pcmcia_shutdown(void){
+
+  free_irq(S0_CD_VALID, NULL);
+  free_irq(S1_CD_VALID, NULL);
+  free_irq(S0_BVD1_STSCHG, NULL);
+  free_irq(S1_BVD1_STSCHG, NULL);
+
+  INTPOL1 &= 
+    ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
+      (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
+      (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
+      (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
+
+  return 0;
+}
+
+static int xp860_pcmcia_socket_state(struct pcmcia_state_array
+					*state_array){
+  unsigned long status;
+  int return_val=1;
+
+  if(state_array->size<2) return -1;
+
+  memset(state_array->state, 0, 
+	 (state_array->size)*sizeof(struct pcmcia_state));
+
+  status=PCSR;
+
+  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
+
+  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
+
+  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
+
+  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
+
+  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
+
+  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
+
+  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
+
+  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
+
+  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
+
+  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
+
+  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
+
+  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
+
+  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
+
+  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
+
+  return return_val;
+}
+
+static int xp860_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+
+  switch(info->sock){
+  case 0:
+    info->irq=S0_READY_NINT;
+    break;
+
+  case 1:
+    info->irq=S1_READY_NINT;
+    break;
+
+  default:
+    return -1;
+  }
+
+  return 0;
+}
+
+static int xp860_pcmcia_configure_socket(const struct pcmcia_configure
+					    *configure){
+  unsigned long pccr=PCCR, ncr=GPLR, gpio=PA_DWR;
+
+
+  /* Neponset uses the Maxim MAX1600, with the following connections:
+   *
+   *   MAX1600      Neponset
+   *
+   *    A0VCC        SA-1111 GPIO A<1>
+   *    A1VCC        SA-1111 GPIO A<0>
+   *    A0VPP        CPLD NCR A0VPP
+   *    A1VPP        CPLD NCR A1VPP
+   *    B0VCC        SA-1111 GPIO A<2>
+   *    B1VCC        SA-1111 GPIO A<3>
+   *    B0VPP        ground (slot B is CF)
+   *    B1VPP        ground (slot B is CF)
+   *
+   *     VX          VCC (5V)
+   *     VY          VCC3_3 (3.3V)
+   *     12INA       12V
+   *     12INB       ground (slot B is CF)
+   *
+   * The MAX1600 CODE pin is tied to ground, placing the device in 
+   * "Standard Intel code" mode. Refer to the Maxim data sheet for
+   * the corresponding truth table.
+   */
+
+  switch(configure->sock){
+  case 0:
+    
+    switch(configure->vcc){
+    case 0:
+      gpio&=~(GPIO_GPIO0 | GPIO_GPIO1);
+      break;
+
+    case 33:
+      pccr=(pccr & ~PCCR_S0_PSE);
+      gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1;
+      break;
+
+    case 50:
+      pccr=(pccr | PCCR_S0_PSE);
+      gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0;
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	     configure->vcc);
+      return -1;
+    }
+
+    switch(configure->vpp){
+    case 0:
+      ncr&=~(NCR_A0VPP | NCR_A1VPP);
+      break;
+
+    case 120:
+      ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP;
+      break;
+
+    default:
+      if(configure->vpp == configure->vcc)
+	ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP;
+      else {
+	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
+	       configure->vpp);
+	return -1;
+      }
+    }
+
+    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
+    pccr=(configure->output)?(pccr | PCCR_S0_FLT):(pccr & ~PCCR_S0_FLT);
+
+    break;
+
+  case 1:
+    switch(configure->vcc){
+    case 0:
+      gpio&=~(GPIO_GPIO2 | GPIO_GPIO3);
+      break;
+
+    case 33:
+      pccr=(pccr & ~PCCR_S1_PSE);
+      gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO2;
+      break;
+
+    case 50:
+      pccr=(pccr | PCCR_S1_PSE);
+      gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3;
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+	     configure->vcc);
+      return -1;
+    }
+
+    if(configure->vpp!=configure->vcc && configure->vpp!=0){
+      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
+	     configure->vpp);
+      return -1;
+    }
+
+    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
+    pccr=(configure->output)?(pccr | PCCR_S1_FLT):(pccr & ~PCCR_S1_FLT);
+
+    break;
+
+  default:
+    return -1;
+  }
+
+  PCCR = pccr;
+  ncr &= NCR_A0VPP|NCR_A1VPP;
+  GPSR = ncr;
+  GPCR = (~ncr)&(NCR_A0VPP|NCR_A1VPP);
+  PA_DWR = gpio;
+
+  return 0;
+}
+
+struct pcmcia_low_level xp860_pcmcia_ops = { 
+  xp860_pcmcia_init,
+  xp860_pcmcia_shutdown,
+  xp860_pcmcia_socket_state,
+  xp860_pcmcia_get_irq_info,
+  xp860_pcmcia_configure_socket
+};
+
diff -u --recursive --new-file v2.4.12/linux/drivers/pcmcia/sa1100_yopy.c linux/drivers/pcmcia/sa1100_yopy.c
--- v2.4.12/linux/drivers/pcmcia/sa1100_yopy.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/sa1100_yopy.c	Thu Oct 11 09:43:29 2001
@@ -0,0 +1,139 @@
+/*
+ * drivers/pcmcia/sa1100_yopy.c
+ *
+ * PCMCIA implementation routines for Yopy
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pcmcia.h>
+
+
+static inline void pcmcia_power(int on) {
+	/* high for power up */
+	yopy_gpio_set(GPIO_CF_POWER, on);
+}
+
+static inline void pcmcia_reset(int reset)
+{
+	/* high for reset */
+	yopy_gpio_set(GPIO_CF_RESET, reset);
+}
+
+static int yopy_pcmcia_init(struct pcmcia_init *init)
+{
+	int irq, res;
+
+	pcmcia_power(0);
+	pcmcia_reset(1);
+
+	/* All those are inputs */
+	GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IREQ);
+	GAFR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IREQ);
+
+	/* Set transition detect */
+	set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1,
+			   GPIO_BOTH_EDGES );
+	set_GPIO_IRQ_edge( GPIO_CF_IREQ, GPIO_FALLING_EDGE );
+
+	/* Register interrupts */
+	irq = IRQ_CF_CD;
+	res = request_irq(irq, init->handler, SA_INTERRUPT, "CF_CD", NULL);
+	if (res < 0) goto irq_err;
+	irq = IRQ_CF_BVD2;
+	res = request_irq(irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL);
+	if (res < 0) goto irq_err;
+	irq = IRQ_CF_BVD1;
+	res = request_irq(irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL);
+	if (res < 0) goto irq_err;
+
+	return 1;
+irq_err:
+	printk(KERN_ERR "%s: Request for IRQ %d failed\n", __FUNCTION__, irq);
+	return -1;
+}
+
+static int yopy_pcmcia_shutdown(void)
+{
+	/* disable IRQs */
+	free_irq( IRQ_CF_CD, NULL );
+	free_irq( IRQ_CF_BVD2, NULL );
+	free_irq( IRQ_CF_BVD1, NULL );
+
+	/* Disable CF */
+	pcmcia_reset(1);
+	pcmcia_power(0);
+
+	return 0;
+}
+
+static int yopy_pcmcia_socket_state(struct pcmcia_state_array *state_array)
+{
+	unsigned long levels;
+
+	if (state_array->size != 1)
+		return -1;
+
+	memset(state_array->state, 0,
+	       state_array->size * sizeof(struct pcmcia_state));
+
+	levels = GPLR;
+
+	state_array->state[0].detect = (levels & GPIO_CF_CD)    ? 0 : 1;
+	state_array->state[0].ready  = (levels & GPIO_CF_READY) ? 1 : 0;
+	state_array->state[0].bvd1   = (levels & GPIO_CF_BVD1)  ? 1 : 0;
+	state_array->state[0].bvd2   = (levels & GPIO_CF_BVD2)  ? 1 : 0;
+	state_array->state[0].wrprot = 0; /* Not available on Yopy. */
+	state_array->state[0].vs_3v  = 0; /* FIXME Can only apply 3.3V on Yopy. */
+	state_array->state[0].vs_Xv  = 0;
+
+	return 1;
+}
+
+static int yopy_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+	if (info->sock != 0)
+		return -1;
+
+	info->irq = IRQ_CF_IREQ;
+
+	return 0;
+}
+
+static int yopy_pcmcia_configure_socket(const struct pcmcia_configure *configure)
+{
+	if (configure->sock != 0)
+		return -1;
+
+	switch (configure->vcc) {
+	case 0:	/* power off */;
+		pcmcia_power(0);
+		break;
+	case 50:
+		printk(KERN_WARNING __FUNCTION__"(): CS asked for 5V, applying 3.3V..\n");
+	case 33:
+		pcmcia_power(1);
+		break;
+	default:
+		printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n",
+		       configure->vcc);
+		return -1;
+	}
+
+	pcmcia_reset(configure->reset);
+
+	/* Silently ignore Vpp, output enable, speaker enable. */
+
+	return 0;
+}
+
+struct pcmcia_low_level yopy_pcmcia_ops = {
+	yopy_pcmcia_init,
+	yopy_pcmcia_shutdown,
+	yopy_pcmcia_socket_state,
+	yopy_pcmcia_get_irq_info,
+	yopy_pcmcia_configure_socket
+};
diff -u --recursive --new-file v2.4.12/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c
--- v2.4.12/linux/drivers/pnp/isapnp.c	Wed Jul 25 17:10:22 2001
+++ linux/drivers/pnp/isapnp.c	Thu Oct 11 09:43:29 2001
@@ -87,6 +87,7 @@
 MODULE_PARM_DESC(isapnp_reserve_io, "ISA Plug & Play - reserve I/O region(s) - port,size");
 MODULE_PARM(isapnp_reserve_mem, "1-16i");
 MODULE_PARM_DESC(isapnp_reserve_mem, "ISA Plug & Play - reserve memory region(s) - address,size");
+MODULE_LICENSE("GPL");
 
 #define _PIDXR		0x279
 #define _PNPWRP		0xa79
@@ -1673,8 +1674,8 @@
 	}
 	isapnp_for_each_dev(dev) {
 		if (dev->active) {
-			if (dev->irq_resource[0].start == irq ||
-			    dev->irq_resource[1].start == irq)
+			if ((dev->irq_resource[0].flags && dev->irq_resource[0].start == irq) ||
+			    (dev->irq_resource[1].flags && dev->irq_resource[1].start == irq))
 				return 1;
 		}
 	}
@@ -1763,7 +1764,8 @@
 	}
 	isapnp_for_each_dev(dev) {
 		if (dev->active) {
-			if (dev->dma_resource[0].start == dma || dev->dma_resource[1].start == dma)
+			if ((dev->dma_resource[0].flags && dev->dma_resource[0].start == dma) ||
+			    (dev->dma_resource[1].flags && dev->dma_resource[1].start == dma))
 				return 1;
 		}
 	}
@@ -1784,6 +1786,10 @@
 
 static int isapnp_valid_dma(struct isapnp_cfgtmp *cfg, int idx)
 {
+	/* DMA priority: this table is good for i386 */
+	static unsigned short xtab[16] = {
+		1, 3, 5, 6, 7, 0, 2, 4
+	};
 	int err, i;
 	unsigned long *value1, *value2;
 	struct isapnp_dma *dma;
@@ -1799,15 +1805,16 @@
       	value1 = &cfg->result.dma_resource[idx].start;
       	value2 = &cfg->result.dma_resource[idx].end;
 	if (cfg->result.dma_resource[idx].flags & IORESOURCE_AUTO) {
-		for (i = 0; i < 8 && !(dma->map & (1<<i)); i++);
+		for (i = 0; i < 8 && !(dma->map & (1<<xtab[i])); i++);
 		if (i >= 8)
 			return -ENOENT;
 		cfg->result.dma_resource[idx].flags &= ~IORESOURCE_AUTO;
-		if (!isapnp_check_dma(cfg, *value1 = *value2 = i, idx))
+		if (!isapnp_check_dma(cfg, *value1 = *value2 = xtab[i], idx))
 			return 0;
 	}
 	do {
-		for (i = *value1 + 1; i < 8 && !(dma->map & (1<<i)); i++);
+		for (i = 0; i < 8 && xtab[i] != *value1; i++);
+		for (i++; i < 8 && !(dma->map & (1<<xtab[i])); i++);
 		if (i >= 8) {
 			if (dma->res && dma->res->alt) {
 				if ((err = isapnp_alternative_switch(cfg, dma->res, dma->res->alt))<0)
@@ -1816,7 +1823,7 @@
 			}
 			return -ENOENT;
 		} else {
-			*value1 = *value2 = i;
+			*value1 = *value2 = xtab[i];
 		}
 	} while (isapnp_check_dma(cfg, *value1, idx));
 	return 0;
diff -u --recursive --new-file v2.4.12/linux/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
--- v2.4.12/linux/drivers/s390/block/dasd.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/s390/block/dasd.c	Mon Oct 15 13:30:13 2001
@@ -1092,9 +1092,11 @@
 		BUG ();
 		}
         if (device->lowmem_cqr==NULL) {
-                DASD_MESSAGE (KERN_WARNING, device, 
-                              "Low memory! Using emergency request %p",
-                              device->lowmem_ccws);
+                DASD_DRIVER_DEBUG_EVENT (2, dasd_alloc_request,
+                                         "(%04x) Low memory! Using emergency request %p.",
+                                         device->devinfo.devno,
+                                         device->lowmem_ccws);
+
                 device->lowmem_cqr=device->lowmem_ccws;
                 rv = device->lowmem_ccws;
 		memset (rv, 0, PAGE_SIZE);
@@ -1105,10 +1107,11 @@
 		rv->data = (void *) ((long) rv + PAGE_SIZE - datasize);
 		rv->cpaddr = (ccw1_t *) ((long) rv + sizeof (ccw_req_t));
         } else {
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "Refusing emergency mem for request "
-                              "NULL, already in use at %p.",
-                              device->lowmem_ccws);
+                DASD_DRIVER_DEBUG_EVENT (2, dasd_alloc_request,
+                                         "(%04x) Refusing emergency mem for request "
+                                         "NULL, already in use at %p.",
+                                         device->devinfo.devno,
+                                         device->lowmem_ccws);
 	}
 	return rv;
 }
@@ -1219,6 +1222,7 @@
                         CQR_STATUS_QUEUED);
 
        
+#ifdef DASD_PROFILE
         /* save profile information for non erp cqr */
         if (cqr->refers == NULL) {
                 unsigned int  counter = 0;
@@ -1235,6 +1239,7 @@
                 dasd_global_profile.dasd_io_nr_req[counter]++;
                 device->profile.dasd_io_nr_req[counter]++;
         }
+#endif 
 }
 
 /*
@@ -1671,9 +1676,12 @@
 		    chanq_max_size > 0 || (req->nr_sectors >= chanq_min_size)) {
 			ccw_req_t *cqr = NULL;
                         if (is_read_only(device->kdev) && req->cmd == WRITE) {
-                            DASD_MESSAGE (KERN_WARNING, device,
-                                          "rejecting write request %p\n",
-                                          req);
+
+                                DASD_DRIVER_DEBUG_EVENT (3, dasd_int_handler,
+                                                         "(%04x) Rejecting write request %p\n",
+                                                         device->devinfo.devno,
+                                                         req);
+
                                 dasd_end_request (req, 0);
                                 dasd_dequeue_request (queue,req);
                         } else {
@@ -1683,9 +1691,12 @@
                                 part[MINOR (req->rq_dev)].start_sect;
                             cqr = device->discipline->build_cp_from_req (device, req);
                             if (cqr == NULL) {
-				    DASD_MESSAGE (KERN_WARNING, device,
-                                                  "CCW creation failed on request %p\n",
-                                                  req);
+
+                                    DASD_DRIVER_DEBUG_EVENT (3, dasd_int_handler,
+                                                             "(%04x) CCW creation failed "
+                                                             "on request %p\n",
+                                                             device->devinfo.devno,
+                                                             req);
                                     /* revert relocation of request */
                                     req->sector -=
                                         device->major_info->gendisk.
@@ -2032,7 +2043,7 @@
 	}
 
 	erp->cpaddr->cmd_code = CCW_CMD_TIC;
-	erp->cpaddr->cda = (__u32) (void *) cqr->cpaddr;
+	erp->cpaddr->cda = (__u32) (addr_t) cqr->cpaddr;
 	erp->function = dasd_default_erp_action;
 	erp->refers = cqr;
 	erp->device = cqr->device;
@@ -2232,13 +2243,7 @@
 	}
 	for (i = (1 << DASD_PARTN_BITS) - 1; i >= 0; i--) {
                 int major = device->major_info->gendisk.major;
-		int minor = start + i;
-		kdev_t devi = MKDEV (major, minor);
-		struct super_block *sb = get_super (devi);
-		//sync_dev (devi);
-		if (sb)
-			invalidate_inodes (sb);
-		invalidate_buffers (devi);
+		invalidate_device(MKDEV (major, start+i), 1);
 	}
         dasd_destroy_partitions(device);
         dasd_setup_partitions(device);
@@ -2285,20 +2290,20 @@
 #endif
 	switch (no) {
         case DASDAPIVER: {
-                       int ver = DASD_API_VERSION;
-                       rc = copy_to_user ((int *) data, &ver, sizeof (int));
-                       if (rc)
-                               rc = -EFAULT;
-                       break;
+			int ver = DASD_API_VERSION;
+			rc = put_user(ver, (int *) data);
+			break;
         }
 	case BLKGETSIZE:{	/* Return device size */
-			long blocks = major_info->gendisk.sizes 
-                                      [MINOR (inp->i_rdev)] << 1;
-			rc =
-			    copy_to_user ((long *) data, &blocks,
-					  sizeof (long));
-			if (rc)
-				rc = -EFAULT;
+			unsigned long blocks = major_info->gendisk.sizes
+						[MINOR (inp->i_rdev)] << 1;
+			rc = put_user(blocks, (unsigned long *) data);
+			break;
+		}
+	case BLKGETSIZE64:{
+			u64 blocks = major_info->gendisk.sizes 
+                                      [MINOR (inp->i_rdev)];
+			rc = put_user(blocks << 10, (u64 *) data);
 			break;
 		}
 	case BLKRRPART:{
@@ -3253,10 +3258,6 @@
         int rc = 0;
         unsigned long flags;
 
-        printk (KERN_ERR PRINTK_HEADER
-                "called dasd_state_accept_to_init for device %02x\n",
-                device->devinfo.devno);
-
         if ( device->discipline->init_analysis ) {
                 device->init_cqr=device->discipline->init_analysis (device);
                 if ( device->init_cqr != NULL ) {
@@ -3297,8 +3298,10 @@
                                 rc = -EMEDIUMTYPE;
                         }
         if ( device->init_cqr ) {
+                /* This pointer is no longer needed, BUT dont't free the       */ 
+                /* memory, because this is done in bh for finished request!!!! */
                 atomic_dec(&dasd_init_pending);
-                device->init_cqr = NULL; /* This one is no longer needed */
+                device->init_cqr = NULL; 
         }
         device->level = DASD_STATE_READY;
         return rc;
@@ -3378,7 +3381,6 @@
 dasd_deactivate_queue (dasd_device_t *device)
 {
         int i;
-        int major = MAJOR(device->kdev);
         int minor = MINOR(device->kdev);
 
         for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
@@ -3764,7 +3766,14 @@
 		vfree (buffer);
 		return -EFAULT;
 	}
-	buffer[user_len] = 0;
+
+        /* replace LF with '\0' */
+        if (buffer[user_len -1] == '\n') {
+                buffer[user_len -1] = '\0';
+        } else {
+                buffer[user_len] = '\0';
+        }
+
 	printk (KERN_INFO PRINTK_HEADER "/proc/dasd/devices: '%s'\n", buffer);
 	if (strncmp (buffer, "set ", 4) && strncmp (buffer, "add ", 4)) {
 		printk (KERN_WARNING PRINTK_HEADER
@@ -3798,7 +3807,7 @@
             range.to   == -EINVAL   ) {
                 
                 printk (KERN_WARNING PRINTK_HEADER
-                        "/proc/dasd/devices: parse error in '%s'", 
+                        "/proc/dasd/devices: range parse error in '%s'\n", 
                         buffer);
         } else {
                 off = (long) temp - (long) buffer;
@@ -3814,7 +3823,8 @@
                                 dasd_disable_ranges (&range, NULL, 0, 1);
                         } else {
                                 printk (KERN_WARNING PRINTK_HEADER
-                                        "/proc/dasd/devices: parse error in '%s'", buffer);
+                                        "/proc/dasd/devices: parse error in '%s'\n",
+                                        buffer);
                         }
                 }
         }
diff -u --recursive --new-file v2.4.12/linux/drivers/s390/block/dasd_3990_erp.c linux/drivers/s390/block/dasd_3990_erp.c
--- v2.4.12/linux/drivers/s390/block/dasd_3990_erp.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/s390/block/dasd_3990_erp.c	Thu Oct 11 09:43:29 2001
@@ -761,7 +761,7 @@
  * DASD_3990_HANDLE_ENV_DATA
  *
  * DESCRIPTION
- *   Handles 24 byte 'Enviromental data present'.
+ *   Handles 24 byte 'Environmental data present'.
  *   Does a analysis of the sense data (message Format)
  *   and prints the error messages.
  *
diff -u --recursive --new-file v2.4.12/linux/drivers/s390/block/xpram.c linux/drivers/s390/block/xpram.c
--- v2.4.12/linux/drivers/s390/block/xpram.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/s390/block/xpram.c	Mon Oct 15 13:27:51 2001
@@ -171,7 +171,7 @@
 int xpram_devs, xpram_rahead;
 int xpram_blksize, xpram_hardsect;
 int xpram_mem_avail = 0;
-int xpram_sizes[XPRAM_MAX_DEVS];
+unsigned long xpram_sizes[XPRAM_MAX_DEVS];
 
 
 MODULE_PARM(devs,"i");
@@ -649,7 +649,7 @@
 		/* Return the device size, expressed in sectors */
 		return put_user( 1024* xpram_sizes[MINOR(inode->i_rdev)]
                            / XPRAM_SOFTSECT,
-			   (long *) arg);
+			   (unsigned long *) arg);
 
 	case BLKGETSIZE64:
 		return put_user( (u64)(1024* xpram_sizes[MINOR(inode->i_rdev)]
diff -u --recursive --new-file v2.4.12/linux/drivers/s390/char/Makefile linux/drivers/s390/char/Makefile
--- v2.4.12/linux/drivers/s390/char/Makefile	Sun Aug 12 13:28:00 2001
+++ linux/drivers/s390/char/Makefile	Thu Oct 11 09:43:29 2001
@@ -5,6 +5,7 @@
 O_TARGET := s390-char.o
 
 list-multi	:= tub3270.o tape390.o
+export-objs	:= hwc_rw.o
 
 tub3270-objs := tuball.o tubfs.o tubtty.o \
                      tubttyaid.o tubttybld.o tubttyscl.o \
diff -u --recursive --new-file v2.4.12/linux/drivers/s390/char/hwc_cpi.c linux/drivers/s390/char/hwc_cpi.c
--- v2.4.12/linux/drivers/s390/char/hwc_cpi.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/s390/char/hwc_cpi.c	Thu Oct 11 09:43:29 2001
@@ -9,7 +9,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/errno.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/version.h>
 #include <asm/semaphore.h>
 #include <asm/ebcdic.h>
diff -u --recursive --new-file v2.4.12/linux/drivers/s390/char/tape34xx.c linux/drivers/s390/char/tape34xx.c
--- v2.4.12/linux/drivers/s390/char/tape34xx.c	Sun Aug 12 13:28:00 2001
+++ linux/drivers/s390/char/tape34xx.c	Thu Oct 11 09:43:29 2001
@@ -1670,7 +1670,7 @@
 	tapestate_set (ti, TS_DONE);
 	ti->rc = 0;
 	ti->wanna_wakeup=1;
-	wake_up_interruptible (&ti->wq);
+	wake_up (&ti->wq);
 }
 
 void
@@ -2274,6 +2274,8 @@
 	ti->wanna_wakeup=1;
 	switch (tapestate_get(ti)) {
 	case TS_REW_RELEASE_INIT:
+	case TS_RFO_INIT:
+	case TS_RBA_INIT:
 	    tapestate_set(ti,TS_FAILED);
 	    wake_up (&ti->wq);
 	    break;
diff -u --recursive --new-file v2.4.12/linux/drivers/s390/char/tapechar.c linux/drivers/s390/char/tapechar.c
--- v2.4.12/linux/drivers/s390/char/tapechar.c	Sun Aug 12 13:28:00 2001
+++ linux/drivers/s390/char/tapechar.c	Thu Oct 11 09:43:29 2001
@@ -204,13 +204,9 @@
 	    return rc;
 	}
 	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-	wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+	wait_event (ti->wq,ti->wanna_wakeup);
 	ti->cqr = NULL;
 	ti->discipline->free_read_block (cqr, ti);
-	if (signal_pending (current)) {
-		tapestate_set (ti, TS_IDLE);
-		return -ERESTARTSYS;
-	}
 	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
 	if (tapestate_get (ti) == TS_FAILED) {
 		tapestate_set (ti, TS_IDLE);
diff -u --recursive --new-file v2.4.12/linux/drivers/s390/char/tuball.c linux/drivers/s390/char/tuball.c
--- v2.4.12/linux/drivers/s390/char/tuball.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/s390/char/tuball.c	Thu Oct 11 09:43:29 2001
@@ -93,8 +93,8 @@
 	NULL			/* next */
 };
 
-bcb_t tub3270_con_bcb;			/* Buffer that receives con writes */
-spinlock_t tub3270_con_bcblock;		/* Lock for the buffer */
+static bcb_t tub3270_con_bcb;		/* Buffer that receives con writes */
+static spinlock_t tub3270_con_bcblock;	/* Lock for the buffer */
 int tub3270_con_irq = -1;		/* set nonneg by _activate() */
 tub_t *tub3270_con_tubp;		/* set nonzero by _activate() */
 struct tty_driver tty3270_con_driver;	/* for /dev/console at 4, 64 */
diff -u --recursive --new-file v2.4.12/linux/drivers/s390/char/tubtty.c linux/drivers/s390/char/tubtty.c
--- v2.4.12/linux/drivers/s390/char/tubtty.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/s390/char/tubtty.c	Thu Oct 11 09:43:29 2001
@@ -992,8 +992,8 @@
 
 	if (tty)
 		len += sprintf(buf+len,
-				"    write_wait=%.8x read_wait=%.8x\n",
-				(int)&tty->write_wait, (int)&tty->read_wait);
+				"    write_wait=%p read_wait=%p\n",
+				&tty->write_wait, &tty->read_wait);
 
 	if (tty && ((mp = tty->termios)))
 		len += sprintf(buf+len,"    iflag=%.8x oflag=%.8x "
diff -u --recursive --new-file v2.4.12/linux/drivers/s390/net/ctcmain.c linux/drivers/s390/net/ctcmain.c
--- v2.4.12/linux/drivers/s390/net/ctcmain.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/s390/net/ctcmain.c	Thu Oct 11 09:43:29 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: ctcmain.c,v 1.49 2001/08/31 14:50:05 felfert Exp $
+ * $Id: ctcmain.c,v 1.51 2001/09/24 10:38:02 mschwide Exp $
  *
  * CTC / ESCON network driver
  *
@@ -35,7 +35,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.49 $
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.51 $
  *
  */
 
@@ -43,7 +43,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
@@ -96,6 +96,7 @@
 #ifdef MODULE
 MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
 MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
+MODULE_LICENSE("GPL");
 #ifndef CTC_CHANDEV
 MODULE_PARM(ctc, "s");
 MODULE_PARM_DESC(ctc,
@@ -296,6 +297,8 @@
 	net_device          *netdev;
 
 	ctc_profile         prof;
+
+	unsigned char       *trans_skb_data;
 } channel;
 
 #define CHANNEL_FLAGS_READ            0
@@ -382,7 +385,7 @@
  */
 static void print_banner(void) {
 	static int printed = 0;
-	char vbuf[] = "$Revision: 1.49 $";
+	char vbuf[] = "$Revision: 1.51 $";
 	char *version = vbuf;
 
 	if (printed)
@@ -951,6 +954,7 @@
 			return -ENOMEM;
 		}
 		ch->ccw[1].count = 0;
+		ch->trans_skb_data = ch->trans_skb->data;
 		ch->flags &= ~CHANNEL_FLAGS_BUFSIZE_CHANGED;
 	}
 	return 0;
@@ -1016,7 +1020,7 @@
 			spin_unlock(&ch->collect_lock);
 			return;
 		}
-		ch->trans_skb->tail = ch->trans_skb->data;
+		ch->trans_skb->tail = ch->trans_skb->data = ch->trans_skb_data;
 		ch->trans_skb->len = 0;
 		if (ch->prof.maxmulti < (ch->collect_len + 2))
 			ch->prof.maxmulti = ch->collect_len + 2;
@@ -1089,7 +1093,6 @@
 	int            len = ch->max_bufsize - ch->devstat->rescnt;
 	struct sk_buff *skb = ch->trans_skb;
 	__u16          block_len = *((__u16*)skb->data);
-	char           *saved_data = skb->data;
 	int            check_len;
 	int            rc;
 
@@ -1138,7 +1141,7 @@
 		ctc_unpack_skb(ch, skb);
 	}
  again:
-	skb->data = skb->tail = saved_data;
+	skb->data = skb->tail = ch->trans_skb_data;
 	skb->len = 0;
 	if (ctc_checkalloc_buffer(ch, 1))
 		return;
@@ -1548,9 +1551,9 @@
 	channel *ch = (channel *)arg;
 	net_device *dev = ch->netdev;
 
+	fsm_deltimer(&ch->timer);
 	printk(KERN_DEBUG "%s: %s channel restart\n", dev->name,
 	       (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX");
-
 	fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
 	oldstate = fsm_getstate(fi);
 	fsm_newstate(fi, CH_STATE_STARTWAIT);
@@ -1716,8 +1719,7 @@
 #ifdef DEBUG
 	printk(KERN_DEBUG "ccw[4].cda = %08x\n", ch->ccw[4].cda);
 #endif
-			rc = do_IO(ch->irq, &ch->ccw[3],
-				   (intparm_t)ch, 0xff, 0);
+			rc = do_IO(ch->irq, &ch->ccw[3], (intparm_t)ch, 0xff, 0);
 			if (event == CH_EVENT_TIMER)
 				s390irq_spin_unlock_irqrestore(ch->irq,
 							       saveflags);
@@ -2539,7 +2541,8 @@
 		if (rc != 0) {
 			fsm_deltimer(&ch->timer);
 			ccw_check_return_code(ch, rc);
-			skb_dequeue_tail(&ch->io_queue);
+			if (ccw_idx == 3)
+				skb_dequeue_tail(&ch->io_queue);
 			/**
 			 * Remove our header. It gets added
 			 * again on retransmit.
diff -u --recursive --new-file v2.4.12/linux/drivers/s390/net/iucv.c linux/drivers/s390/net/iucv.c
--- v2.4.12/linux/drivers/s390/net/iucv.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/s390/net/iucv.c	Thu Oct 11 09:43:29 2001
@@ -39,7 +39,7 @@
 #include <linux/version.h>
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/tqueue.h>
 #include <linux/interrupt.h>
@@ -53,10 +53,6 @@
 
 #undef DEBUG
 
-#ifndef min
-#define min(a,b) (((a)<(b))?(a):(b))
-#endif
-
 /* FLAGS:
  * All flags are defined in the field IPFLAGS1 of each function
  * and can be found in CP Programming Services.
@@ -1163,7 +1159,7 @@
 
 	parm = (iparml_db *)grab_param();
 
-	parm->ipbfadr1 = (__u32) buffer;
+	parm->ipbfadr1 = (__u32) (addr_t) buffer;
 	parm->ipbfln1f = (__u32) ((ulong) buflen);
 	parm->ipmsgid = msgid;
 	parm->ippathid = pathid;
@@ -1186,7 +1182,7 @@
 			if (residual_buffer)
 				*residual_buffer = parm->ipbfadr1;
 		} else {
-			moved = min (buflen, 8);
+			moved = min_t (unsigned long, buflen, 8);
 
 			memcpy ((char *) buffer,
 				(char *) &parm->ipbfadr1, moved);
@@ -1283,7 +1279,8 @@
 
 			while ((moved < 8) && (moved < buflen)) {
 				dyn_len =
-				    min ((buffer + i)->length, need_to_move);
+				    min_t (unsigned int,
+					 (buffer + i)->length, need_to_move);
 
 				memcpy ((char *)((ulong)((buffer + i)->address)),
 					((char *) &parm->ipbfadr1) + moved,
diff -u --recursive --new-file v2.4.12/linux/drivers/s390/net/netiucv.c linux/drivers/s390/net/netiucv.c
--- v2.4.12/linux/drivers/s390/net/netiucv.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/s390/net/netiucv.c	Thu Oct 11 09:43:29 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: netiucv.c,v 1.11 2001/07/16 17:00:02 felfert Exp $
+ * $Id: netiucv.c,v 1.12 2001/09/24 10:38:02 mschwide Exp $
  *
  * IUCV network driver
  *
@@ -28,7 +28,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV network driver $Revision: 1.11 $
+ * RELEASE-TAG: IUCV network driver $Revision: 1.12 $
  *
  */
 
@@ -36,7 +36,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
@@ -2002,7 +2002,7 @@
 static void
 netiucv_banner(void)
 {
-	char vbuf[] = "$Revision: 1.11 $";
+	char vbuf[] = "$Revision: 1.12 $";
 	char *version = vbuf;
 
 	if ((version = strchr(version, ':'))) {
@@ -2115,7 +2115,8 @@
 	return 0;
 }
 
-module_init(netiucv_init);
 #ifdef MODULE
+module_init(netiucv_init);
 module_exit(netiucv_exit);
+MODULE_LICENSE("GPL");
 #endif
diff -u --recursive --new-file v2.4.12/linux/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c
--- v2.4.12/linux/drivers/sbus/audio/amd7930.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/sbus/audio/amd7930.c	Wed Oct 17 14:16:39 2001
@@ -1,4 +1,4 @@
-/* $Id: amd7930.c,v 1.27 2001/05/21 01:25:22 davem Exp $
+/* $Id: amd7930.c,v 1.28 2001/10/13 01:47:29 davem Exp $
  * drivers/sbus/audio/amd7930.c
  *
  * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
@@ -1716,6 +1716,7 @@
 
 module_init(amd7930_init);
 module_exit(amd7930_exit);
+MODULE_LICENSE("GPL");
 
 /*************************************************************/
 /*                 Audio format conversion                   */
diff -u --recursive --new-file v2.4.12/linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c
--- v2.4.12/linux/drivers/sbus/char/aurora.c	Thu Oct 11 08:02:26 2001
+++ linux/drivers/sbus/char/aurora.c	Wed Oct 17 14:16:39 2001
@@ -1,4 +1,4 @@
-/*	$Id: aurora.c,v 1.16 2001/10/08 22:19:51 davem Exp $
+/*	$Id: aurora.c,v 1.17 2001/10/13 08:27:50 davem Exp $
  *	linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
  *
  *	Copyright (c) 1999 by Oliver Aldulea (oli at bv dot ro)
@@ -33,6 +33,14 @@
  *	read that file before reading this one.
  *
  *	Several parts of the code do not have comments yet.
+ * 
+ * n.b.  The board can support 115.2 bit rates, but only on a few
+ * ports. The total badwidth of one chip (ports 0-7 or 8-15) is equal
+ * to OSC_FREQ div 16. In case of my board, each chip can take 6
+ * channels of 115.2 kbaud.  This information is not well-tested.
+ * 
+ * Fixed to use tty_get_baud_rate().
+ *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
  */
 
 #include <linux/module.h>
@@ -100,16 +108,6 @@
 
 DECLARE_TASK_QUEUE(tq_aurora);
 
-/* Yes, the board can support 115.2 bit rates, but only on a few ports. The
- * total badwidth of one chip (ports 0-7 or 8-15) is equal to OSC_FREQ div
- * 16. In case of my board, each chip can take 6 channels of 115.2 kbaud.
- * This information is not well-tested.
- */
-static unsigned long baud_table[] =  {
-        0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-        9600, 19200, 38400, 57600, 115200, 0,
-};
-
 static inline int aurora_paranoia_check(struct Aurora_port const * port,
 				    kdev_t device, const char *routine)
 {
@@ -1030,28 +1028,14 @@
 	port->COR2 = 0;
 	port->MSVR = MSVR_RTS|MSVR_DTR;
 	
-	baud = C_BAUD(tty);
-	
-	if (baud & CBAUDEX) {
-		baud &= ~CBAUDEX;
-		if (baud < 1 || baud > 2) 
-			port->tty->termios->c_cflag &= ~CBAUDEX;
-		else
-			baud += 15;
-	}
-	if (baud == 15)  {
-		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-			baud ++;
-		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-			baud += 2;
-	}
+	baud = tty_get_baud_rate(tty);
 	
 	/* Select port on the board */
 	sbus_writeb(port_No(port) & 7,
 		    &bp->r[chip]->r[CD180_CAR]);
 	udelay(1);
 	
-	if (!baud_table[baud])  {
+	if (!baud)  {
 		/* Drop DTR & exit */
 		port->MSVR &= ~(bp->DTR|bp->RTS);
 		sbus_writeb(port->MSVR,
@@ -1067,10 +1051,10 @@
 	/* Now we must calculate some speed dependant things. */
 	
 	/* Set baud rate for port. */
-	tmp = (((bp->oscfreq + baud_table[baud]/2) / baud_table[baud] +
+	tmp = (((bp->oscfreq + baud/2) / baud +
 		CD180_TPC/2) / CD180_TPC);
 
-/*	tmp = (bp->oscfreq/7)/baud_table[baud];
+/*	tmp = (bp->oscfreq/7)/baud;
 	if((tmp%10)>4)tmp=tmp/10+1;else tmp=tmp/10;*/
 /*	printk("Prescaler period: %d\n",tmp);*/
 
@@ -1081,7 +1065,7 @@
 	sbus_writeb(tmp & 0xff, &bp->r[chip]->r[CD180_RBPRL]);
 	sbus_writeb(tmp & 0xff, &bp->r[chip]->r[CD180_TBPRL]);
 	
-	baud = (baud_table[baud] + 5) / 10;   /* Estimated CPS */
+	baud = (baud + 5) / 10;   /* Estimated CPS */
 	
 	/* Two timer ticks seems enough to wakeup something like SLIP driver */
 	tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;		
diff -u --recursive --new-file v2.4.12/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c
--- v2.4.12/linux/drivers/sbus/char/bpp.c	Thu Oct 11 08:02:26 2001
+++ linux/drivers/sbus/char/bpp.c	Thu Oct 11 09:43:29 2001
@@ -1073,4 +1073,3 @@
 
 module_init(bpp_init);
 module_exit(bpp_cleanup);
-MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/sbus/char/jsflash.c linux/drivers/sbus/char/jsflash.c
--- v2.4.12/linux/drivers/sbus/char/jsflash.c	Thu Oct 11 08:02:26 2001
+++ linux/drivers/sbus/char/jsflash.c	Mon Oct 15 13:27:42 2001
@@ -453,7 +453,7 @@
 
 	switch (cmd) {
 	case BLKGETSIZE:
-		return put_user(jsfd_bytesizes[dev] >> 9, (long *) arg);
+		return put_user(jsfd_bytesizes[dev] >> 9, (unsigned long *) arg);
 	case BLKGETSIZE64:
 		return put_user(jsfd_bytesizes[dev], (u64 *) arg);
 
diff -u --recursive --new-file v2.4.12/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- v2.4.12/linux/drivers/sbus/char/sab82532.c	Thu Oct 11 08:02:26 2001
+++ linux/drivers/sbus/char/sab82532.c	Wed Oct 17 14:16:39 2001
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.64 2001/10/08 22:19:51 davem Exp $
+/* $Id: sab82532.c,v 1.65 2001/10/13 08:27:50 davem Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -6,6 +6,10 @@
  * Rewrote buffer handling to use CIRC(Circular Buffer) macros.
  *   Maxim Krasnyanskiy <maxk@qualcomm.com>
  *
+ * Fixed to use tty_get_baud_rate, and to allow for arbitrary baud
+ * rates to be programmed into the UART.  Also eliminated a lot of
+ * duplicated code in the console setup.
+ *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
  */
 
 #include <linux/config.h>
@@ -147,45 +151,47 @@
  * The formula is:    Baud = BASE_BAUD / ((N + 1) * (1 << M)),
  *
  * with               0 <= N < 64 and 0 <= M < 16
- *
- * XXX:	Speeds with M = 0 might not work properly for XTAL frequencies
- *      above 10 MHz.
+ * 
+ * 12-Oct-2001 - Replaced table driven approach with code written by
+ * Theodore Ts'o <tytso@alum.mit.edu> which exactly replicates the
+ * table.  (Modulo bugs for the 307200 and 61440 baud rates, which
+ * were clearly incorrectly calculated in the original table.  This is
+ * why tables filled with magic constants are evil.)
  */
-struct ebrg_struct {
-	int	baud;
-	int	n;
-	int	m;
-};
 
-static struct ebrg_struct ebrg_table[] = {
-	{       0,	0,	 0 },
-	{      50,	35,	10 },
-	{      75,	47,	 9 },
-	{     110,	32,	 9 },
-	{     134,	53,	 8 },
-	{     150,	47,	 8 },
-	{     200,	35,	 8 },
-	{     300,	47,	 7 },
-	{     600,	47,	 6 },
-	{    1200,	47,	 5 },
-	{    1800,	31,	 5 },
-	{    2400,	47,	 4 },
-	{    4800,	47,	 3 },
-	{    9600,	47,	 2 },
-	{   19200,	47,	 1 },
-	{   38400,	23,	 1 },
-	{   57600,	15,	 1 },
-	{  115200,	 7,	 1 },
-	{  230400,	 3,	 1 },
-	{  460800,	 1,	 1 },
-	{   76800,	11,	 1 },
-	{  153600,	 5,	 1 },
-	{  307200,	 3,	 1 },
-	{  614400,	 3,	 0 },
-	{  921600,	 0,	 1 },
-};
+static void calc_ebrg(int baud, int *n_ret, int *m_ret)
+{
+	int	n, m;
 
-#define NR_EBRG_VALUES	(sizeof(ebrg_table)/sizeof(struct ebrg_struct))
+	if (baud == 0) {
+		*n_ret = 0;
+		*m_ret = 0;
+		return;
+	}
+     
+	/*
+	 * We scale numbers by 10 so that we get better accuracy
+	 * without having to use floating point.  Here we increment m
+	 * until n is within the valid range.
+	 */
+	n = (BASE_BAUD*10) / baud;
+	m = 0;
+	while (n >= 640) {
+		n = n / 2;
+		m++;
+	}
+	n = (n+5) / 10;
+	/*
+	 * We try very hard to avoid speeds with M == 0 since they may
+	 * not work correctly for XTAL frequences above 10 MHz.
+	 */
+	if ((m == 0) && ((n & 1) == 0)) {
+		n = n / 2;
+		m++;
+	}
+	*n_ret = n - 1;
+	*m_ret = m;
+}
 
 #define SAB82532_MAX_TEC_TIMEOUT 200000	/* 1 character time (at 50 baud) */
 #define SAB82532_MAX_CEC_TIMEOUT  50000	/* 2.5 TX CLKs (at 50 baud) */
@@ -939,7 +945,7 @@
 	unsigned int	ebrg;
 	tcflag_t	cflag;
 	unsigned char	dafo;
-	int		i, bits;
+	int		bits, n, m;
 
 	if (!info->tty || !info->tty->termios)
 		return;
@@ -982,18 +988,11 @@
 	}
 
 	/* Determine EBRG values based on baud rate */
-	i = cflag & CBAUD;
-	if (i & CBAUDEX) {
-		i &= ~(CBAUDEX);
-		if ((i < 1) || ((i + 15) >= NR_EBRG_VALUES))
-			info->tty->termios->c_cflag &= ~CBAUDEX;
-		else
-			i += 15;
-	}
-	ebrg = ebrg_table[i].n;
-	ebrg |= (ebrg_table[i].m << 6);
+	info->baud = tty_get_baud_rate(info->tty);
+	calc_ebrg(info->baud, &n, &m);
+	
+	ebrg = n | (m << 6);
 
-	info->baud = ebrg_table[i].baud;
 	if (info->baud) {
 		info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud;
 		info->tec_timeout = (10 * 1000000) / info->baud;
@@ -2205,7 +2204,7 @@
 
 static inline void __init show_serial_version(void)
 {
-	char *revision = "$Revision: 1.64 $";
+	char *revision = "$Revision: 1.65 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2558,12 +2557,11 @@
 static int
 sab82532_console_setup(struct console *con, char *options)
 {
+	static struct tty_struct c_tty;
+	static struct termios c_termios;
 	struct sab82532 *info;
-	unsigned int	ebrg;
 	tcflag_t	cflag;
-	unsigned char	dafo;
-	int		i, bits;
-	unsigned long	flags;
+	int		i;
 
 	info = sab82532_chain;
 	for (i = con->index; i; i--) {
@@ -2595,92 +2593,28 @@
 	sunserial_console_termios(con);
 	cflag = con->cflag;
 
-	/* Byte size and parity */
-	switch (cflag & CSIZE) {
-	      case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break;
-	      case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break;
-	      case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break;
-	      case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break;
-	      /* Never happens, but GCC is too dumb to figure it out */
-	      default:  dafo = SAB82532_DAFO_CHL5; bits = 7; break;
-	}
-
-	if (cflag & CSTOPB) {
-		dafo |= SAB82532_DAFO_STOP;
-		bits++;
-	}
-
-	if (cflag & PARENB) {
-		dafo |= SAB82532_DAFO_PARE;
-		bits++;
-	}
-
-	if (cflag & PARODD) {
-#ifdef CMSPAR
-		if (cflag & CMSPAR)
-			dafo |= SAB82532_DAFO_PAR_MARK;
-		else
-#endif
-			dafo |= SAB82532_DAFO_PAR_ODD;
-	} else {
-#ifdef CMSPAR
-		if (cflag & CMSPAR)
-			dafo |= SAB82532_DAFO_PAR_SPACE;
-		else
-#endif
-			dafo |= SAB82532_DAFO_PAR_EVEN;
+	/*
+	 * Fake up the tty and tty->termios structures so we can use
+	 * change_speed (and eliminate a lot of duplicate code).
+	 */
+	if (!info->tty) {
+		memset(&c_tty, 0, sizeof(c_tty));
+		info->tty = &c_tty;
 	}
-
-	/* Determine EBRG values based on baud rate */
-	i = cflag & CBAUD;
-	if (i & CBAUDEX) {
-		i &= ~(CBAUDEX);
-		if ((i < 1) || ((i + 15) >= NR_EBRG_VALUES))
-			cflag &= ~CBAUDEX;
-		else
-			i += 15;
+	if (!info->tty->termios) {
+		memset(&c_termios, 0, sizeof(c_termios));
+		info->tty->termios = &c_termios;
 	}
-	ebrg = ebrg_table[i].n;
-	ebrg |= (ebrg_table[i].m << 6);
-
-	info->baud = ebrg_table[i].baud;
-	if (info->baud)
-		info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud;
-	else
-		info->timeout = 0;
-	info->timeout += HZ / 50;		/* Add .02 seconds of slop */
-
-	/* CTS flow control flags */
-	if (cflag & CRTSCTS)
-		info->flags |= ASYNC_CTS_FLOW;
-	else
-		info->flags &= ~(ASYNC_CTS_FLOW);
-
-	if (cflag & CLOCAL)
-		info->flags &= ~(ASYNC_CHECK_CD);
-	else
-		info->flags |= ASYNC_CHECK_CD;
+	info->tty->termios->c_cflag = con->cflag;
 
-	save_flags(flags); cli();
-	sab82532_cec_wait(info);
-	sab82532_tec_wait(info);
-	writeb(dafo, &info->regs->w.dafo);
-	writeb(ebrg & 0xff, &info->regs->w.bgr);
-	writeb(readb(&info->regs->rw.ccr2) & ~(0xc0), &info->regs->rw.ccr2);
-	writeb(readb(&info->regs->rw.ccr2) | ((ebrg >> 2) & 0xc0), &info->regs->rw.ccr2);
-	if (info->flags & ASYNC_CTS_FLOW) {
-		writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_RTS), &info->regs->rw.mode);
-		writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode);
-		writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FCTS), &info->regs->rw.mode);
-	} else {
-		writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode);
-		writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FRTS), &info->regs->rw.mode);
-		writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FCTS, &info->regs->rw.mode);
-	}
-	writeb(~(info->pvr_dtr_bit), &info->regs->rw.pvr);
-	writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RAC, &info->regs->rw.mode);
-	restore_flags(flags);
+	change_speed(info);
 
+	/* Now take out the pointers to static structures if necessary */
+	if (info->tty->termios == &c_termios)
+		info->tty->termios = 0;
+	if (info->tty == &c_tty)
+		info->tty = 0;
+	
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.12/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- v2.4.12/linux/drivers/sbus/char/su.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/sbus/char/su.c	Wed Oct 17 14:16:39 2001
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.52 2001/06/29 21:54:32 davem Exp $
+/* $Id: su.c,v 1.53 2001/10/13 08:27:50 davem Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -6,6 +6,9 @@
  *
  * This is mainly a variation of drivers/char/serial.c,
  * credits go to authors mentioned therein.
+ *
+ * Fixed to use tty_get_baud_rate().
+ *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
  */
 
 /*
@@ -935,24 +938,18 @@
 static int
 su_get_baud_rate(struct su_struct *info)
 {
-	static int baud_table[] = {
-		0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
-		4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0
-	};
-	int i;
+	static struct tty_struct c_tty;
+	static struct termios c_termios;
 
 	if (info->tty)
 		return tty_get_baud_rate(info->tty);
 
-	i = info->cflag & CBAUD;
-	if (i & CBAUDEX) {
-		i &= ~(CBAUDEX);
-		if (i < 1 || i > 4)
-			info->cflag &= ~(CBAUDEX);
-		else
-			i += 15;
-	}
-	return baud_table[i];
+	memset(&c_tty, 0, sizeof(c_tty));
+	memset(&c_termios, 0, sizeof(c_termios));
+	c_tty.termios = &c_termios;
+	c_termios.c_cflag = info->cflag;
+
+	return tty_get_baud_rate(&c_tty);
 }
 
 /*
@@ -1168,7 +1165,7 @@
 	if (info->port_type != SU_PORT_MS)
 		return;
 
-	info->cflag &= ~(CBAUDEX | CBAUD);
+	info->cflag &= ~CBAUD;
 	switch (baud) {
 		case 1200:
 			info->cflag |= B1200;
@@ -2255,7 +2252,7 @@
  */
 static __inline__ void __init show_su_version(void)
 {
-	char *revision = "$Revision: 1.52 $";
+	char *revision = "$Revision: 1.53 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.4.12/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- v2.4.12/linux/drivers/sbus/char/zs.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/sbus/char/zs.c	Wed Oct 17 14:16:39 2001
@@ -1,9 +1,12 @@
-/* $Id: zs.c,v 1.66 2001/06/29 21:33:22 davem Exp $
+/* $Id: zs.c,v 1.67 2001/10/13 08:27:50 davem Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1996 Eddie C. Dost   (ecd@skynet.be)
  * Fixes by Pete A. Zaitcev <zaitcev@yahoo.com>.
+ *
+ * Fixed to use tty_get_baud_rate().
+ *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
  */
 
 #include <linux/errno.h>
@@ -241,12 +244,6 @@
 	return 0;
 }
 
-/* This is used to figure out the divisor speeds and the timeouts. */
-static int baud_table[] = {
-	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 76800, 0
-};
-
 /* Reading and writing Zilog8530 registers.  The delays are to make this
  * driver work on the Sun4 which needs a settling delay after each chip
  * register access, other machines handle this in hardware via auxiliary
@@ -944,8 +941,7 @@
 static void change_speed(struct sun_serial *info)
 {
 	unsigned cflag;
-	int	quot = 0;
-	int	i;
+	int	baud, quot = 0;
 	int	brg;
 
 	if (!info->tty || !info->tty->termios)
@@ -953,20 +949,12 @@
 	cflag = info->tty->termios->c_cflag;
 	if (!info->port)
 		return;
-	i = cflag & CBAUD;
-	if (cflag & CBAUDEX) {
-		i &= ~CBAUDEX;
-		if (i != 5)
-			info->tty->termios->c_cflag &= ~CBAUDEX;
-		else
-			i = 16;
-	}
-	if (i == 15) {
-		if ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_HI)
-			i += 1;
-		if ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_CUST)
-			quot = info->custom_divisor;
-	}
+	baud = tty_get_baud_rate(info->tty);
+	
+	if ((baud == 38400) && 
+	    ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_CUST))
+		quot = info->custom_divisor;
+
 	if (quot) {
 		info->zs_baud = info->baud_base / quot;
 		info->clk_divisor = 16;
@@ -978,8 +966,8 @@
 		info->curregs[13] = ((brg >> 8) & 255);
 		info->curregs[14] = BRSRC | BRENAB;
 		zs_rtsdtr(info, 1);
-	} else if (baud_table[i]) {
-		info->zs_baud = baud_table[i];
+	} else if (baud) {
+		info->zs_baud = baud;
 		info->clk_divisor = 16;
 
 		info->curregs[4] = X16CLK;
@@ -1945,7 +1933,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.66 $";
+	char *revision = "$Revision: 1.67 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2796,22 +2784,23 @@
 
 static int __init zs_console_setup(struct console *con, char *options)
 {
+	static struct tty_struct c_tty;
+	static struct termios c_termios;
 	struct sun_serial *info;
-	int i, brg, baud;
+	int brg, baud;
 
 	info = zs_soft + con->index;
 	info->is_cons = 1;
 
 	printk("Console: ttyS%d (Zilog8530)\n", info->line);
-
+	
 	sunserial_console_termios(con);
+	memset(&c_tty, 0, sizeof(c_tty));
+	memset(&c_termios, 0, sizeof(c_termios));
+	c_tty.termios = &c_termios;
+	c_termios.c_cflag = con->cflag;
+	baud = tty_get_baud_rate(&c_tty);
 
-	i = con->cflag & CBAUD;
-	if (con->cflag & CBAUDEX) {
-		i &= ~CBAUDEX;
-		con->cflag &= ~CBAUDEX;
-	}
-	baud = baud_table[i];
 	info->zs_baud = baud;
 
 	switch (con->cflag & CSIZE) {
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/53c700.c linux/drivers/scsi/53c700.c
--- v2.4.12/linux/drivers/scsi/53c700.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/53c700.c	Thu Oct 11 09:43:29 2001
@@ -51,6 +51,12 @@
 
 /* CHANGELOG
  *
+ * Version 2.6
+ *
+ * Following test of the 64 bit parisc kernel by Richard Hirst,
+ * several problems have now been corrected.  Also adds support for
+ * consistent memory allocation.
+ *
  * Version 2.5
  * 
  * More Compatibility changes for 710 (now actually works).  Enhanced
@@ -90,7 +96,7 @@
  * Initial modularisation from the D700.  See NCR_D700.c for the rest of
  * the changelog.
  * */
-#define NCR_700_VERSION "2.5"
+#define NCR_700_VERSION "2.6"
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -217,18 +223,39 @@
 NCR_700_detect(Scsi_Host_Template *tpnt,
 	       struct NCR_700_Host_Parameters *hostdata)
 {
-	dma_addr_t pScript, pSlots;
+	dma_addr_t pScript, pMemory, pSlots;
+	__u8 *memory;
 	__u32 *script;
 	struct Scsi_Host *host;
 	static int banner = 0;
 	int j;
 
-	/* This separation of pScript and script is not strictly
-	 * necessay, but may be useful in architectures which can
-	 * allocate consistent memory on which virt_to_bus will not
-	 * work */
-	script = kmalloc(sizeof(SCRIPT), GFP_KERNEL);
-	pScript = virt_to_bus(script);
+#ifdef CONFIG_53C700_USE_CONSISTENT
+	memory = pci_alloc_consistent(hostdata->pci_dev, TOTAL_MEM_SIZE,
+				      &pMemory);
+	hostdata->consistent = 1;
+	if(memory == NULL ) {
+		printk(KERN_WARNING "53c700: consistent memory allocation failed\n");
+#endif
+		memory = kmalloc(TOTAL_MEM_SIZE, GFP_KERNEL);
+		if(memory == NULL) {
+			printk(KERN_ERR "53c700: Failed to allocate memory for driver, detatching\n");
+			return NULL;
+		}
+		pMemory = pci_map_single(hostdata->pci_dev, memory,
+					 TOTAL_MEM_SIZE, PCI_DMA_BIDIRECTIONAL);
+#ifdef CONFIG_53C700_USE_CONSISTENT
+		hostdata->consistent = 0;
+	}
+#endif
+	script = (__u32 *)memory;
+	pScript = pMemory;
+	hostdata->msgin = memory + MSGIN_OFFSET;
+	hostdata->msgout = memory + MSGOUT_OFFSET;
+	hostdata->status = memory + STATUS_OFFSET;
+	hostdata->slots = (struct NCR_700_command_slot *)(memory + SLOTS_OFFSET);
+		
+	pSlots = pMemory + SLOTS_OFFSET;
 
 	/* Fill in the missing routines from the host template */
 	tpnt->queuecommand = NCR_700_queuecommand;
@@ -251,29 +278,6 @@
 
 	if((host = scsi_register(tpnt, 4)) == NULL)
 		return NULL;
-	if(script == NULL) {
-		printk(KERN_ERR "53c700: Failed to allocate script, detatching\n");
-		scsi_unregister(host);
-		return NULL;
-	}
-
-	/* This separation of slots and pSlots may facilitate later
-	 * migration to consistent memory on architectures which
-	 * support it */
-	hostdata->slots = kmalloc(sizeof(struct NCR_700_command_slot)
-				  * NCR_700_COMMAND_SLOTS_PER_HOST,
-				  GFP_KERNEL);
-	pSlots = virt_to_bus(hostdata->slots);
-
-	hostdata->msgin = kmalloc(MSG_ARRAY_SIZE, GFP_KERNEL);
-	hostdata->msgout = kmalloc(MSG_ARRAY_SIZE, GFP_KERNEL);
-	hostdata->status = kmalloc(MSG_ARRAY_SIZE, GFP_KERNEL);
-	if(hostdata->slots == NULL || hostdata->msgin == NULL
-	   || hostdata->msgout == NULL || hostdata->status==NULL) {
-		printk(KERN_ERR "53c700: Failed to allocate command slots or message buffers, detatching\n");
-		scsi_unregister(host);
-		return NULL;
-	}
 	memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot)
 	       * NCR_700_COMMAND_SLOTS_PER_HOST);
 	for(j = 0; j < NCR_700_COMMAND_SLOTS_PER_HOST; j++) {
@@ -295,19 +299,17 @@
 	for(j = 0; j < PATCHES; j++) {
 		script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]);
 	}
-	/* now patch up fixed addresses. 
-	 * NOTE: virt_to_bus may be wrong if consistent memory is used
-	 * for these in the future */
+	/* now patch up fixed addresses. */
 	script_patch_32(script, MessageLocation,
-			virt_to_bus(&hostdata->msgout[0]));
+			pScript + MSGOUT_OFFSET);
 	script_patch_32(script, StatusAddress,
-			virt_to_bus(&hostdata->status[0]));
+			pScript + STATUS_OFFSET);
 	script_patch_32(script, ReceiveMsgAddress,
-			virt_to_bus(&hostdata->msgin[0]));
+			pScript + MSGIN_OFFSET);
 
 	hostdata->script = script;
 	hostdata->pScript = pScript;
-	dma_cache_wback((unsigned long)script, sizeof(SCRIPT));
+	NCR_700_dma_cache_wback((unsigned long)script, sizeof(SCRIPT));
 	hostdata->state = NCR_700_HOST_FREE;
 	spin_lock_init(&hostdata->lock);
 	hostdata->cmd = NULL;
@@ -344,13 +346,18 @@
 	struct NCR_700_Host_Parameters *hostdata = 
 		(struct NCR_700_Host_Parameters *)host->hostdata[0];
 
-	/* NOTE: these may be NULL if we weren't fully initialised before
-	 * the scsi_unregister was called */
-	kfree(hostdata->script);
-	kfree(hostdata->slots);
-	kfree(hostdata->msgin);
-	kfree(hostdata->msgout);
-	kfree(hostdata->status);
+#ifdef CONFIG_53C700_USE_CONSISTENT
+	if(hostdata->consistent) {
+		pci_free_consistent(hostdata->pci_dev, TOTAL_MEM_SIZE,
+				    hostdata->script, hostdata->pScript);
+	} else {
+#endif
+		pci_unmap_single(hostdata->pci_dev, hostdata->pScript,
+				 TOTAL_MEM_SIZE, PCI_DMA_BIDIRECTIONAL);
+		kfree(hostdata->script);
+#ifdef CONFIG_53C700_USE_CONSISTENT
+	}
+#endif
 	return 1;
 }
 
@@ -620,7 +627,25 @@
 	}
 	return (offset & 0x0f) | (XFERP & 0x07)<<4;
 }
-	
+
+STATIC inline void
+NCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, Scsi_Cmnd *SCp,
+	      struct NCR_700_command_slot *slot)
+{
+	if(SCp->sc_data_direction != SCSI_DATA_NONE &&
+	   SCp->sc_data_direction != SCSI_DATA_UNKNOWN) {
+		int pci_direction = scsi_to_pci_dma_dir(SCp->sc_data_direction);
+		if(SCp->use_sg) {
+			pci_unmap_sg(hostdata->pci_dev, SCp->buffer,
+				     SCp->use_sg, pci_direction);
+		} else {
+			pci_unmap_single(hostdata->pci_dev,
+					 slot->dma_handle,
+					 SCp->request_bufflen,
+					 pci_direction);
+		}
+	}
+}
 
 STATIC inline void
 NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
@@ -632,31 +657,22 @@
 	if(SCp != NULL) {
 		struct NCR_700_command_slot *slot = 
 			(struct NCR_700_command_slot *)SCp->host_scribble;
-
+		
+		NCR_700_unmap(hostdata, SCp, slot);
+		pci_unmap_single(hostdata->pci_dev, slot->pCmd,
+				 sizeof(SCp->cmnd), PCI_DMA_TODEVICE);
 		if(SCp->cmnd[0] == REQUEST_SENSE && SCp->cmnd[6] == NCR_700_INTERNAL_SENSE_MAGIC) {
 #ifdef NCR_700_DEBUG
 			printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n",
 			       SCp, SCp->cmnd[7], result);
 			print_sense("53c700", SCp);
+
 #endif
+			SCp->use_sg = SCp->cmnd[8];
 			if(result == 0)
 				result = SCp->cmnd[7];
 		}
 
-		if(SCp->sc_data_direction != SCSI_DATA_NONE &&
-		   SCp->sc_data_direction != SCSI_DATA_UNKNOWN) {
-			int pci_direction = scsi_to_pci_dma_dir(SCp->sc_data_direction);
-			if(SCp->use_sg) {
-				pci_unmap_sg(hostdata->pci_dev, SCp->buffer,
-					     SCp->use_sg, pci_direction);
-			} else {
-				pci_unmap_single(hostdata->pci_dev,
-						 slot->dma_handle,
-						 SCp->request_bufflen,
-						 pci_direction);
-			}
-		}
-
 		free_slot(slot, hostdata);
 
 		SCp->host_scribble = NULL;
@@ -850,7 +866,7 @@
 			printk(KERN_WARNING "scsi%d Unexpected SDTR msg\n",
 			       host->host_no);
 			hostdata->msgout[0] = A_REJECT_MSG;
-			dma_cache_wback((unsigned long)hostdata->msgout, 1);
+			NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, 1);
 			script_patch_16(hostdata->script, MessageCount, 1);
 			/* SendMsgOut returns, so set up the return
 			 * address */
@@ -862,7 +878,7 @@
 		printk(KERN_INFO "scsi%d: (%d:%d), Unsolicited WDTR after CMD, Rejecting\n",
 		       host->host_no, pun, lun);
 		hostdata->msgout[0] = A_REJECT_MSG;
-		dma_cache_wback((unsigned long)hostdata->msgout, 1);
+		NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, 1);
 		script_patch_16(hostdata->script, MessageCount, 1);
 		resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
 
@@ -876,7 +892,7 @@
 		printk("\n");
 		/* just reject it */
 		hostdata->msgout[0] = A_REJECT_MSG;
-		dma_cache_wback((unsigned long)hostdata->msgout, 1);
+		NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, 1);
 		script_patch_16(hostdata->script, MessageCount, 1);
 		/* SendMsgOut returns, so set up the return
 		 * address */
@@ -954,7 +970,7 @@
 		printk("\n");
 		/* just reject it */
 		hostdata->msgout[0] = A_REJECT_MSG;
-		dma_cache_wback((unsigned long)hostdata->msgout, 1);
+		NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, 1);
 		script_patch_16(hostdata->script, MessageCount, 1);
 		/* SendMsgOut returns, so set up the return
 		 * address */
@@ -964,7 +980,7 @@
 	}
 	NCR_700_writel(temp, host, TEMP_REG);
 	/* set us up to receive another message */
-	dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
+	NCR_700_dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
 	return resume_offset;
 }
 
@@ -1002,10 +1018,15 @@
 				printk("  cmd %p has status %d, requesting sense\n",
 				       SCp, hostdata->status[0]);
 #endif
-				/* we can destroy the command here because the
-				 * contingent allegiance condition will cause a 
-				 * retry which will re-copy the command from the
-				 * saved data_cmnd */
+				/* we can destroy the command here
+				 * because the contingent allegiance
+				 * condition will cause a retry which
+				 * will re-copy the command from the
+				 * saved data_cmnd.  We also unmap any
+				 * data associated with the command
+				 * here */
+				NCR_700_unmap(hostdata, SCp, slot);
+
 				SCp->cmnd[0] = REQUEST_SENSE;
 				SCp->cmnd[1] = (SCp->lun & 0x7) << 5;
 				SCp->cmnd[2] = 0;
@@ -1013,21 +1034,29 @@
 				SCp->cmnd[4] = sizeof(SCp->sense_buffer);
 				SCp->cmnd[5] = 0;
 				SCp->cmd_len = 6;
-				/* Here's a quiet hack: the REQUEST_SENSE command is
-				 * six bytes, so store a flag indicating that this
-				 * was an internal sense request and the original
-				 * status at the end of the command */
+				/* Here's a quiet hack: the
+				 * REQUEST_SENSE command is six bytes,
+				 * so store a flag indicating that
+				 * this was an internal sense request
+				 * and the original status at the end
+				 * of the command */
 				SCp->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
 				SCp->cmnd[7] = hostdata->status[0];
+				SCp->cmnd[8] = SCp->use_sg;
+				SCp->use_sg = 0;
 				SCp->sc_data_direction = SCSI_DATA_READ;
-				dma_cache_wback((unsigned long)SCp->cmnd, SCp->cmd_len);
+				pci_dma_sync_single(hostdata->pci_dev,
+						    slot->pCmd,
+						    SCp->cmd_len,
+						    PCI_DMA_TODEVICE);
+				slot->dma_handle = pci_map_single(hostdata->pci_dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), PCI_DMA_FROMDEVICE);
 				slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
-				slot->SG[0].pAddr = bS_to_host(virt_to_bus(SCp->sense_buffer));
+				slot->SG[0].pAddr = bS_to_host(slot->dma_handle);
 				slot->SG[1].ins = bS_to_host(SCRIPT_RETURN);
 				slot->SG[1].pAddr = 0;
 				slot->resume_offset = hostdata->pScript;
-				dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG[0])*2);
-				dma_cache_inv((unsigned long)SCp->sense_buffer, sizeof(SCp->sense_buffer));
+				NCR_700_dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG[0])*2);
+				NCR_700_dma_cache_inv((unsigned long)SCp->sense_buffer, sizeof(SCp->sense_buffer));
 				
 				/* queue the command for reissue */
 				slot->state = NCR_700_SLOT_QUEUED;
@@ -1136,7 +1165,7 @@
 
 			/* re-patch for this command */
 			script_patch_32_abs(hostdata->script, CommandAddress, 
-					    virt_to_bus(slot->cmnd->cmnd));
+					    slot->pCmd);
 			script_patch_16(hostdata->script,
 					CommandCount, slot->cmnd->cmd_len);
 			script_patch_32_abs(hostdata->script, SGScriptStartAddress,
@@ -1149,13 +1178,13 @@
 			 * should therefore always clear ACK */
 			NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device),
 				       host, SXFER_REG);
-			dma_cache_inv((unsigned long)hostdata->msgin,
+			NCR_700_dma_cache_inv((unsigned long)hostdata->msgin,
 				      MSG_ARRAY_SIZE);
-			dma_cache_wback((unsigned long)hostdata->msgout,
+			NCR_700_dma_cache_wback((unsigned long)hostdata->msgout,
 					MSG_ARRAY_SIZE);
 			/* I'm just being paranoid here, the command should
 			 * already have been flushed from the cache */
-			dma_cache_wback((unsigned long)slot->cmnd->cmnd,
+			NCR_700_dma_cache_wback((unsigned long)slot->cmnd->cmnd,
 					slot->cmnd->cmd_len);
 
 
@@ -1219,7 +1248,8 @@
 		hostdata->reselection_id = reselection_id;
 		/* just in case we have a stale simple tag message, clear it */
 		hostdata->msgin[1] = 0;
-		dma_cache_wback_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
+		NCR_700_dma_cache_wback_inv((unsigned long)hostdata->msgin,
+					    MSG_ARRAY_SIZE);
 		if(hostdata->tag_negotiated & (1<<reselection_id)) {
 			resume_offset = hostdata->pScript + Ent_GetReselectionWithTag;
 		} else {
@@ -1334,7 +1364,7 @@
 	hostdata->cmd = NULL;
 	/* clear any stale simple tag message */
 	hostdata->msgin[1] = 0;
-	dma_cache_wback_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
+	NCR_700_dma_cache_wback_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
 
 	if(id == 0xff) {
 		/* Selected as target, Ignore */
@@ -1404,7 +1434,7 @@
 	 * set up so we cannot take a selection interrupt */
 
 	hostdata->msgout[0] = NCR_700_identify(SCp->cmnd[0] != REQUEST_SENSE,
-					    SCp->lun);
+					       SCp->lun);
 	/* for INQUIRY or REQUEST_SENSE commands, we cannot be sure
 	 * if the negotiated transfer parameters still hold, so
 	 * always renegotiate them */
@@ -1437,7 +1467,7 @@
 			Device_ID, 1<<SCp->target);
 
 	script_patch_32_abs(hostdata->script, CommandAddress, 
-			virt_to_bus(SCp->cmnd));
+			    slot->pCmd);
 	script_patch_16(hostdata->script, CommandCount, SCp->cmd_len);
 	/* finally plumb the beginning of the SG list into the script
 	 * */
@@ -1448,10 +1478,10 @@
 	if(slot->resume_offset == 0)
 		slot->resume_offset = hostdata->pScript;
 	/* now perform all the writebacks and invalidates */
-	dma_cache_wback((unsigned long)hostdata->msgout, count);
-	dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
-	dma_cache_wback((unsigned long)SCp->cmnd, SCp->cmd_len);
-	dma_cache_inv((unsigned long)hostdata->status, 1);
+	NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, count);
+	NCR_700_dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
+	NCR_700_dma_cache_wback((unsigned long)SCp->cmnd, SCp->cmd_len);
+	NCR_700_dma_cache_inv((unsigned long)hostdata->status, 1);
 
 	/* set the synchronous period/offset */
 	NCR_700_writeb(NCR_700_get_SXFER(SCp->device),
@@ -1519,7 +1549,7 @@
 
 		DEBUG(("scsi%d: istat %02x sstat0 %02x dstat %02x dsp %04x[%08x] dsps 0x%x\n",
 		       host->host_no, istat, sstat0, dstat,
-		       (dsp - (__u32)virt_to_bus(hostdata->script))/4,
+		       (dsp - (__u32)(hostdata->pScript))/4,
 		       dsp, dsps));
 
 		if(SCp != NULL) {
@@ -1632,7 +1662,7 @@
 					slot->SG[i].ins = bS_to_host(SCRIPT_NOP);
 					slot->SG[i].pAddr = 0;
 				}
-				dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG));
+				NCR_700_dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG));
 				/* and pretend we disconnected after
 				 * the command phase */
 				resume_offset = hostdata->pScript + Ent_MsgInDuringData;
@@ -1847,7 +1877,13 @@
 #endif
 		
 		if(old != NULL && old->tag == SCp->device->current_tag) {
-			printk(KERN_WARNING "scsi%d (%d:%d) Tag clock back to current, queueing\n", SCp->host->host_no, SCp->target, SCp->lun);
+			/* On some badly starving drives, this can be
+			 * a frequent occurance, so print the message
+			 * only once */
+			if(NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_TAG_STARVATION_WARNED)) {
+				printk(KERN_WARNING "scsi%d (%d:%d) Target is suffering from tag starvation.\n", SCp->host->host_no, SCp->target, SCp->lun);
+				NCR_700_set_flag(SCp->device, NCR_700_DEV_TAG_STARVATION_WARNED);
+			}
 			return 1;
 		}
 		slot->tag = SCp->device->current_tag++;
@@ -1900,6 +1936,18 @@
 		hostdata->ITL_Hash_back[hash] = slot;
 	slot->ITL_back = NULL;
 
+	/* sanity check: some of the commands generated by the mid-layer
+	 * have an eccentric idea of their sc_data_direction */
+	if(!SCp->use_sg && !SCp->request_bufflen 
+	   && SCp->sc_data_direction != SCSI_DATA_NONE) {
+#ifdef NCR_700_DEBUG
+		printk("53c700: Command");
+		print_command(SCp->cmnd);
+		printk("Has wrong data direction %d\n", SCp->sc_data_direction);
+#endif
+		SCp->sc_data_direction = SCSI_DATA_NONE;
+	}
+
 	switch (SCp->cmnd[0]) {
 	case REQUEST_SENSE:
 		/* clear the internal sense magic */
@@ -1965,12 +2013,14 @@
 		}
 		slot->SG[i].ins = bS_to_host(SCRIPT_RETURN);
 		slot->SG[i].pAddr = 0;
-		dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG));
+		NCR_700_dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG));
 		DEBUG((" SETTING %08lx to %x\n",
-		       virt_to_bus(&slot->SG[i].ins), 
+		       (&slot->pSG[i].ins), 
 		       slot->SG[i].ins));
 	}
 	slot->resume_offset = 0;
+	slot->pCmd = pci_map_single(hostdata->pci_dev, SCp->cmnd,
+				    sizeof(SCp->cmnd), PCI_DMA_TODEVICE);
 	NCR_700_start_command(SCp);
 	return 0;
 }
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/53c700.h linux/drivers/scsi/53c700.h
--- v2.4.12/linux/drivers/scsi/53c700.h	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/53c700.h	Thu Oct 11 09:43:29 2001
@@ -40,6 +40,24 @@
 #error "Config.in must define either CONFIG_53C700_IO_MAPPED or CONFIG_53C700_MEM_MAPPED to use this scsi core."
 #endif
 
+/* macros for consistent memory allocation */
+
+#ifdef CONFIG_53C700_USE_CONSISTENT
+#define NCR_700_dma_cache_wback(mem, size) \
+	if(!hostdata->consistent) \
+		dma_cache_wback(mem, size)
+#define NCR_700_dma_cache_inv(mem, size) \
+	if(!hostdata->consistent) \
+		dma_cache_inv(mem, size)
+#define NCR_700_dma_cache_wback_inv(mem, size) \
+	if(!hostdata->consistent) \
+		dma_cache_wback_inv(mem, size)
+#else
+#define NCR_700_dma_cache_wback(mem, size) dma_cache_wback(mem,size)
+#define NCR_700_dma_cache_inv(mem, size) dma_cache_inv(mem,size)
+#define NCR_700_dma_cache_wback_inv(mem, size) dma_cache_wback_inv(mem,size)
+#endif
+
 
 struct NCR_700_Host_Parameters;
 
@@ -86,6 +104,7 @@
 #define NCR_700_DEV_NEGOTIATED_SYNC	(1<<16)
 #define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION	(1<<17)
 #define NCR_700_DEV_BEGIN_TAG_QUEUEING	(1<<18)
+#define NCR_700_DEV_TAG_STARVATION_WARNED (1<<19)
 
 static inline void
 NCR_700_set_SXFER(Scsi_Device *SDp, __u8 sxfer)
@@ -174,6 +193,8 @@
 	__u16	tag;
 	__u32	resume_offset;
 	Scsi_Cmnd	*cmnd;
+	/* The pci_mapped address of the actual command in cmnd */
+	dma_addr_t	pCmd;
 	__u32		temp;
 	/* if this command is a pci_single mapping, holds the dma address
 	 * for later unmapping in the done routine */
@@ -191,19 +212,22 @@
 	int	clock;			/* board clock speed in MHz */
 	__u32	base;			/* the base for the port (copied to host) */
 	struct pci_dev	*pci_dev;
-	__u8	dmode_extra;	/* adjustable bus settings */
-	__u8	differential:1;	/* if we are differential */
+	__u32	dmode_extra;	/* adjustable bus settings */
+	__u32	differential:1;	/* if we are differential */
 #ifdef CONFIG_53C700_LE_ON_BE
 	/* This option is for HP only.  Set it if your chip is wired for
 	 * little endian on this platform (which is big endian) */
-	__u8	force_le_on_be:1;
+	__u32	force_le_on_be:1;
 #endif
-	__u8	chip710:1;	/* set if really a 710 not 700 */
-	__u8	burst_disable:1;	/* set to 1 to disable 710 bursting */
+	__u32	chip710:1;	/* set if really a 710 not 700 */
+	__u32	burst_disable:1;	/* set to 1 to disable 710 bursting */
 
 	/* NOTHING BELOW HERE NEEDS ALTERING */
-	__u8	fast:1;		/* if we can alter the SCSI bus clock
+	__u32	fast:1;		/* if we can alter the SCSI bus clock
                                    speed (so can negiotiate sync) */
+#ifdef CONFIG_53C700_USE_CONSISTENT
+	__u32	consistent:1;
+#endif
 
 	int	sync_clock;	/* The speed of the SYNC core */
 
@@ -216,15 +240,23 @@
 	spinlock_t lock;
 	enum NCR_700_Host_State state; /* protected by state lock */
 	Scsi_Cmnd *cmd;
-
+	/* Note: pScript contains the single consistent block of
+	 * memory.  All the msgin, msgout and status are allocated in
+	 * this memory too (at separate cache lines).  TOTAL_MEM_SIZE
+	 * represents the total size of this area */
+#define	MSG_ARRAY_SIZE	8
+#define	MSGOUT_OFFSET	(L1_CACHE_ALIGN(sizeof(SCRIPT)))
 	__u8	*msgout;
-#define	MSG_ARRAY_SIZE	16
-	__u8	tag_negotiated;
-	__u8	*status;
+#define MSGIN_OFFSET	(MSGOUT_OFFSET + L1_CACHE_ALIGN(MSG_ARRAY_SIZE))
 	__u8	*msgin;
+#define STATUS_OFFSET	(MSGIN_OFFSET + L1_CACHE_ALIGN(MSG_ARRAY_SIZE))
+	__u8	*status;
+#define SLOTS_OFFSET	(STATUS_OFFSET + L1_CACHE_ALIGN(MSG_ARRAY_SIZE))
 	struct NCR_700_command_slot	*slots;
+#define	TOTAL_MEM_SIZE	(SLOTS_OFFSET + L1_CACHE_ALIGN(sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST))
 	int	saved_slot_position;
 	int	command_slot_count; /* protected by state lock */
+	__u8	tag_negotiated;
 	__u8	rev;
 	__u8	reselection_id;
 	/* flags for the host */
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.4.12/linux/drivers/scsi/Config.in	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/Config.in	Thu Oct 11 09:43:29 2001
@@ -122,10 +122,11 @@
    fi
 fi
 if [ "$CONFIG_PARISC" = "y" ]; then
-   dep_tristate 'HP LASI SCSI support for 53c700' CONFIG_SCSI_LASI700 $CONFIG_SCSI
+   dep_tristate 'HP LASI SCSI support for 53c700/710' CONFIG_SCSI_LASI700 $CONFIG_SCSI
    if [ "$CONFIG_SCSI_LASI700" != "n" ]; then
       define_bool CONFIG_53C700_MEM_MAPPED y
       define_bool CONFIG_53C700_LE_ON_BE y
+      define_bool CONFIG_53C700_USE_CONSISTENT y
    fi
 fi
 dep_tristate 'NCR53c7,8xx SCSI support'  CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI $CONFIG_PCI
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/README.53c700 linux/drivers/scsi/README.53c700
--- v2.4.12/linux/drivers/scsi/README.53c700	Sun Sep 23 11:40:59 2001
+++ linux/drivers/scsi/README.53c700	Thu Oct 11 09:43:29 2001
@@ -1,17 +1,154 @@
-This driver supports the 53c700 and 53c700-66 chips only.  It is full
-featured and does sync (-66 only), disconnects and tag command
-queueing.
+General Description
+===================
+
+This driver supports the 53c700 and 53c700-66 chips.  It also supports
+the 53c710 but only in 53c700 emulation mode.  It is full featured and
+does sync (-66 and 710 only), disconnects and tag command queueing.
 
 Since the 53c700 must be interfaced to a bus, you need to wrapper the
 card detector around this driver.  For an example, see the
-NCR_D700.[ch] files.
+NCR_D700.[ch] or lasi700.[ch] files.
 
 The comments in the 53c700.[ch] files tell you which parts you need to
 fill in to get the driver working.
 
-The driver is currently I/O mapped only, but it should be easy enough
-to memory map (just make the port reads #defines with MEM_MAPPED for
-memory mapping or nothing for I/O mapping, specify an extra rule for
-53c700-mem.o with the -DMEM_MAPPED flag and make your driver use it,
-that way the make rules will generate the correct version).
+
+Compile Time Flags
+==================
+
+The driver may be either io mapped or memory mapped.  This is
+selectable by configuration flags:
+
+CONFIG_53C700_MEM_MAPPED
+
+define if the driver is memory mapped.
+
+CONFIG_53C700_IO_MAPPED
+
+define if the driver is to be io mapped.
+
+One or other of the above flags *must* be defined.
+
+Other flags are:
+
+CONFIG_53C700_LE_ON_BE
+
+define if the chipset must be supported in little endian mode on a big
+endian architecture (used for the 700 on parisc).
+
+CONFIG_53C700_USE_CONSISTENT
+
+allocate consistent memory (should only be used if your architecture
+has a mixture of consistent and inconsistent memory).  Fully
+consistent or fully inconsistent architectures should not define this.
+
+
+Using the Chip Core Driver
+==========================
+
+In order to plumb the 53c700 chip core driver into a working SCSI
+driver, you need to know three things about the way the chip is wired
+into your system (or expansion card).
+
+1. The clock speed of the SCSI core
+2. The interrupt line used
+3. The memory (or io space) location of the 53c700 registers.
+
+Optionally, you may also need to know other things, like how to read
+the SCSI Id from the card bios or whether the chip is wired for
+differential operation.
+
+Usually you can find items 2. and 3. from general spec. documents or
+even by examining the configuration of a working driver under another
+operating system.
+
+The clock speed is usually buried deep in the technical literature.
+It is required because it is used to set up both the synchronous and
+asynchronous dividers for the chip.  As a general rule of thumb,
+manufacturers set the clock speed at the lowest possible setting
+consistent with the best operation of the chip (although some choose
+to drive it off the CPU or bus clock rather than going to the expense
+of an extra clock chip).  The best operation clock speeds are:
+
+53c700 - 25MHz
+53c700-66 - 50MHz
+53c710 - 40Mhz
+
+Writing Your Glue Driver
+========================
+
+This will be a standard SCSI driver (I don't know of a good document
+describing this, just copy from some other driver) with at least a
+detect and release entry.
+
+In the detect routine, you need to allocate a struct
+NCR_700_Host_Parameters sized memory area and clear it (so that the
+default values for everything are 0).  Then you must fill in the
+parameters that matter to you (see below), plumb the NCR_700_intr
+routine into the interrupt line and call NCR_700_detect with the host
+template and the new parameters as arguments.  You should also call
+the relevant request_*_region function and place the register base
+address into the `base' pointer of the host parameters.
+
+In the release routine, you must free the NCR_700_Host_Parameters that
+you allocated, call the corresponding release_*_region and free the
+interrupt.
+
+Handling Interrupts
+-------------------
+
+In general, you should just plumb the card's interrupt line in with 
+
+request_irq(irq, NCR_700_intr, <irq flags>, <driver name>, host);
+
+where host is the return from the relevant NCR_700_detect() routine.
+
+You may also write your own interrupt handling routine which calls
+NCR_700_intr() directly.  However, you should only really do this if
+you have a card with more than one chip on it and you can read a
+register to tell which set of chips wants the interrupt.
+
+Settable NCR_700_Host_Parameters
+--------------------------------
+
+The following are a list of the user settable parameters:
+
+clock: (MANDATORY)
+
+Set to the clock speed of the chip in MHz.
+
+base: (MANDATORY)
+
+set to the base of the io or mem region for the register set. On 64
+bit architectures this is only 32 bits wide, so the registers must be
+mapped into the low 32 bits of memory.
+
+pci_dev: (OPTIONAL)
+
+set to the PCI board device.  Leave NULL for a non-pci board.  This is
+used for the pci_alloc_consistent() and pci_map_*() functions.
+
+dmode_extra: (OPTIONAL, 53c710 only)
+
+extra flags for the DMODE register.  These are used to control bus
+output pins on the 710.  The settings should be a combination of
+DMODE_FC1 and DMODE_FC2.  What these pins actually do is entirely up
+to the board designer.  Usually it is safe to ignore this setting.
+
+differential: (OPTIONAL)
+
+set to 1 if the chip drives a differential bus.
+
+force_le_on_be: (OPTIONAL, only if CONFIG_53C700_LE_ON_BE is set)
+
+set to 1 if the chip is operating in little endian mode on a big
+endian architecture.
+
+chip710: (OPTIONAL)
+
+set to 1 if the chip is a 53c710.
+
+burst_disable: (OPTIONAL, 53c710 only)
+
+disable 8 byte bursting for DMA transfers.
 
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v2.4.12/linux/drivers/scsi/aha152x.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/aha152x.c	Thu Oct 11 09:43:29 2001
@@ -390,13 +390,11 @@
 #endif /* !defined(AHA152X_DEBUG) */
 
 #ifdef __ISAPNP__
-
 static struct isapnp_device_id id_table[] __devinitdata = {
 	{ ISAPNP_DEVICE_SINGLE('A','D','P',0x1505, 'A','D','P',0x1505), },
 	{ ISAPNP_DEVICE_SINGLE_END, }
 };
 MODULE_DEVICE_TABLE(isapnp, id_table);
-
 #endif /* ISAPNP */
 #endif /* MODULE */
 
@@ -981,28 +979,6 @@
 			}
 		printk("ok\n");
 	}
-#ifdef __ISAPNP__
-	while (setup_count <= 2 &&
-	       (dev = isapnp_find_dev (NULL, ISAPNP_VENDOR('A','D','P'),
-				       ISAPNP_FUNCTION(0x1505), dev))) {
-		if (dev->prepare(dev) < 0)
-			continue;
-		if (dev->active)
-			continue;
-		if (!(dev->resource[0].flags & IORESOURCE_IO))
-			continue;
-		dev->resource[0].flags |= IORESOURCE_AUTO;
-		if (dev->activate(dev) < 0)
-			continue;
-		setup[setup_count].io_port = dev->resource[0].start;
-		setup[setup_count].irq = dev->irq_resource[0].start;
-		pnpdev[num_pnpdevs++] = dev;
-		printk (KERN_INFO
-			"aha152x: found ISAPnP AVA-1505A at address 0x%03X, IRQ %d\n",
-			setup[setup_count].io_port, setup[setup_count].irq);
-		setup_count++;
-	}
-#endif
 
 #if defined(SETUP0)
 	if (setup_count < 2) {
@@ -1132,6 +1108,41 @@
 			       setup[setup_count].ext_trans);
 	}
 #endif
+
+#ifdef __ISAPNP__
+	while ( setup_count<2 && (dev=isapnp_find_dev(NULL, ISAPNP_VENDOR('A','D','P'), ISAPNP_FUNCTION(0x1505), dev)) ) {
+		if (dev->prepare(dev) < 0)
+			continue;
+		if (dev->active)
+			continue;
+		if (!(dev->resource[0].flags & IORESOURCE_IO))
+			continue;
+		dev->resource[0].flags |= IORESOURCE_AUTO;
+		if (dev->activate(dev) < 0)
+			continue;
+		if ( setup_count==1 && dev->resource[0].start==setup[0].io_port) {
+			dev->deactivate(dev);
+			continue;
+		}
+		setup[setup_count].io_port     = dev->resource[0].start;
+		setup[setup_count].irq         = dev->irq_resource[0].start;
+		setup[setup_count].scsiid      = 7;
+		setup[setup_count].reconnect   = 1;
+		setup[setup_count].parity      = 1;
+		setup[setup_count].synchronous = 1;
+		setup[setup_count].delay       = DELAY_DEFAULT;
+		setup[setup_count].ext_trans   = 0;
+#if defined(AHA152X_DEBUG)
+		setup[setup_count].debug       = DEBUG_DEFAULT;
+#endif
+		pnpdev[num_pnpdevs++] = dev;
+		printk (KERN_INFO
+			"aha152x: found ISAPnP AVA-1505A at io=0x%03x, irq=%d\n",
+			setup[setup_count].io_port, setup[setup_count].irq);
+		setup_count++;
+	}
+#endif
+
 
 #if defined(AUTOCONF)
 	if (setup_count < 2) {
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v2.4.12/linux/drivers/scsi/aha1542.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/aha1542.c	Fri Oct 12 15:35:53 2001
@@ -67,12 +67,10 @@
 		       int nseg,
 		       int badseg)
 {
-	printk(KERN_CRIT "sgpnt[%d:%d] addr %p/0x%lx alt %p/0x%lx length %d\n",
+	printk(KERN_CRIT "sgpnt[%d:%d] addr %p/0x%lx length %d\n",
 	       badseg, nseg,
 	       sgpnt[badseg].address,
 	       SCSI_PA(sgpnt[badseg].address),
-	       sgpnt[badseg].alt_address,
-	       sgpnt[badseg].alt_address ? SCSI_PA(sgpnt[badseg].alt_address) : 0,
 	       sgpnt[badseg].length);
 
 	/*
@@ -716,7 +714,7 @@
 				unsigned char *ptr;
 				printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i);
 				for (i = 0; i < SCpnt->use_sg; i++) {
-					printk(KERN_CRIT "%d: %x %x %d\n", i, (unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address,
+					printk(KERN_CRIT "%d: %p %d\n", i, sgpnt[i].address,
 					       sgpnt[i].length);
 				};
 				printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr);
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c
--- v2.4.12/linux/drivers/scsi/aic7xxx_old.c	Thu Oct 11 08:02:26 2001
+++ linux/drivers/scsi/aic7xxx_old.c	Thu Oct 11 09:43:30 2001
@@ -220,11 +220,6 @@
  */
  
 #include <linux/module.h>
-
-#if defined(PCMCIA)
-#  undef MODULE
-#endif
-
 #include <stdarg.h>
 #include <asm/io.h>
 #include <asm/irq.h>
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/dpt_i2o.c linux/drivers/scsi/dpt_i2o.c
--- v2.4.12/linux/drivers/scsi/dpt_i2o.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/dpt_i2o.c	Thu Oct 11 09:43:30 2001
@@ -1838,7 +1838,7 @@
 #endif
 
 #if defined __alpha__ 
-static void adpt_sparc_info(sysInfo_S* si)
+static void adpt_alpha_info(sysInfo_S* si)
 {
 	// This is all the info we need for now
 	// We will add more info as our new
@@ -3324,4 +3324,4 @@
 static Scsi_Host_Template driver_template = DPT_I2O;
 #include "scsi_module.c"
 EXPORT_NO_SYMBOLS;
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/i60uscsi.h linux/drivers/scsi/i60uscsi.h
--- v2.4.12/linux/drivers/scsi/i60uscsi.h	Fri Mar  2 18:38:38 2001
+++ linux/drivers/scsi/i60uscsi.h	Thu Oct 11 09:43:30 2001
@@ -61,6 +61,7 @@
  **************************************************************************/
 
 #include <linux/config.h>
+#include <linux/types.h>
 
 #define ULONG   unsigned long
 #define PVOID   void *
@@ -72,11 +73,7 @@
 #define UBYTE   unsigned char
 #define UWORD   unsigned short
 #define UDWORD  unsigned long
-#ifdef ALPHA
-#define U32     unsigned int
-#else
-#define U32     unsigned long
-#endif
+#define U32     u32
 
 #ifndef NULL
 #define NULL     0		/* zero          */
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/i91uscsi.h linux/drivers/scsi/i91uscsi.h
--- v2.4.12/linux/drivers/scsi/i91uscsi.h	Fri Mar  2 18:38:38 2001
+++ linux/drivers/scsi/i91uscsi.h	Thu Oct 11 09:43:30 2001
@@ -54,6 +54,7 @@
  **************************************************************************/
 
 #include <linux/config.h>
+#include <linux/types.h>
 
 #define ULONG   unsigned long
 #define USHORT  unsigned short
@@ -64,11 +65,7 @@
 #define UBYTE   unsigned char
 #define UWORD   unsigned short
 #define UDWORD  unsigned long
-#ifdef ALPHA
-#define U32     unsigned int
-#else
-#define U32     unsigned long
-#endif
+#define U32     u32
 
 #ifndef NULL
 #define NULL     0		/* zero          */
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/ini9100u.h linux/drivers/scsi/ini9100u.h
--- v2.4.12/linux/drivers/scsi/ini9100u.h	Fri Apr 27 13:59:18 2001
+++ linux/drivers/scsi/ini9100u.h	Thu Oct 11 09:43:30 2001
@@ -74,6 +74,7 @@
 #ifndef	LINUX_VERSION_CODE
 #include <linux/version.h>
 #endif
+#include <linux/types.h>
 
 #include "sd.h"
 
@@ -121,17 +122,13 @@
 #define ULONG   unsigned long
 #define USHORT  unsigned short
 #define UCHAR   unsigned char
-#define BYTE    unsigned char
+#define BYTE    u8
 #define WORD    unsigned short
 #define DWORD   unsigned long
-#define UBYTE   unsigned char
+#define UBYTE   u8
 #define UWORD   unsigned short
 #define UDWORD  unsigned long
-#ifdef ALPHA
-#define U32   unsigned int
-#else
-#define U32   unsigned long
-#endif
+#define U32   u32
 
 #ifndef NULL
 #define NULL     0		/* zero          */
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/inia100.h linux/drivers/scsi/inia100.h
--- v2.4.12/linux/drivers/scsi/inia100.h	Fri Mar  2 18:38:38 2001
+++ linux/drivers/scsi/inia100.h	Thu Oct 11 09:43:30 2001
@@ -68,6 +68,8 @@
 #include <linux/version.h>
 #endif
 
+#include <linux/types.h>
+
 #include "sd.h"
 
 extern int inia100_detect(Scsi_Host_Template *);
@@ -122,11 +124,7 @@
 #define UBYTE   unsigned char
 #define UWORD   unsigned short
 #define UDWORD  unsigned long
-#ifdef ALPHA
-#define U32     unsigned int
-#else
-#define U32     unsigned long
-#endif
+#define U32     u32
 
 #ifndef NULL
 #define NULL     0		/* zero          */
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/osst.c linux/drivers/scsi/osst.c
--- v2.4.12/linux/drivers/scsi/osst.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/osst.c	Fri Oct 12 15:35:53 2001
@@ -4935,7 +4935,6 @@
 			tb->sg[0].address =
 			    (unsigned char *)__get_free_pages(priority, order);
 			if (tb->sg[0].address != NULL) {
-			    tb->sg[0].alt_address = NULL;
 			    tb->sg[0].length = b_size;
 			    break;
 			}
@@ -4971,7 +4970,6 @@
 				tb = NULL;
 				break;
 			    }
-			    tb->sg[segs].alt_address = NULL;
 			    tb->sg[segs].length = b_size;
 			    got += b_size;
 			    segs++;
@@ -5045,7 +5043,6 @@
 			normalize_buffer(STbuffer);
 			return FALSE;
 		}
-		STbuffer->sg[segs].alt_address = NULL;
 		STbuffer->sg[segs].length = b_size;
 		STbuffer->sg_segs += 1;
 		got += b_size;
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/pcmcia/nsp_cs.c linux/drivers/scsi/pcmcia/nsp_cs.c
--- v2.4.12/linux/drivers/scsi/pcmcia/nsp_cs.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/pcmcia/nsp_cs.c	Thu Oct 11 09:04:57 2001
@@ -23,7 +23,7 @@
 
 ***********************************************************************/
 
-/* $Id: nsp_cs.c,v 1.35 2001/07/05 16:58:24 elca Exp $ */
+/* $Id: nsp_cs.c,v 1.42 2001/09/10 10:30:58 elca Exp $ */
 
 #ifdef NSP_KERNEL_2_2
 #include <pcmcia/config.h>
@@ -66,15 +66,14 @@
 
 MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
 MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
-MODULE_LICENSE("GPL");
-
 MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
+MODULE_LICENSE("GPL");
 
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
 MODULE_PARM(pc_debug, "i");
 MODULE_PARM_DESC(pc_debug, "set debug level");
-static char *version = "$Id: nsp_cs.c,v 1.35 2001/07/05 16:58:24 elca Exp $";
+static char *version = "$Id: nsp_cs.c,v 1.42 2001/09/10 10:30:58 elca Exp $";
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 #else
 #define DEBUG(n, args...) /* */
@@ -93,18 +92,6 @@
 	struct bus_operations *bus;
 } scsi_info_t;
 
-static void nsp_cs_release(u_long arg);
-static int nsp_cs_event(event_t event, int priority,
-		     event_callback_args_t *args);
-static dev_link_t *nsp_cs_attach(void);
-static void nsp_cs_detach(dev_link_t *);
-static int nsp_detect(Scsi_Host_Template * );
-static int nsp_release(struct Scsi_Host *shpnt);
-static const char * nsp_info(struct Scsi_Host *shpnt);
-static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
-static int nsp_abort(Scsi_Cmnd *);
-static int nsp_reset(Scsi_Cmnd *, unsigned int);
-
 
 /*----------------------------------------------------------------*/
 
@@ -191,7 +178,7 @@
 		data->CurrentSC = NULL;
 		SCpnt->result   = DID_BAD_TARGET << 16;
 		done(SCpnt);
-		return FALSE;
+		return -1;
 	}
 
 	show_command(SCpnt);
@@ -229,12 +216,12 @@
 		data->CurrentSC = NULL;
 		SCpnt->result   = DID_NO_CONNECT << 16;
 		done(SCpnt);
-		return FALSE;
+		return -1;
 	}
 
 
 	//DEBUG(0, __FUNCTION__ "() out\n");
-	return TRUE;
+	return 0;
 }
 
 /*
@@ -1185,7 +1172,7 @@
 	return;
 }
 
-#ifdef DBG_SHOWCOMMAND
+#ifdef PCMCIA_DEBUG
 #include "nsp_debug.c"
 #endif	/* DBG_SHOWCOMMAND */
 
@@ -1205,13 +1192,13 @@
 	host->unique_id	  = data->BaseAddress;
 	host->n_io_port	  = data->NumAddress;
 	host->irq	  = data->IrqNumber;
-	host->dma_channel = -1;
+	host->dma_channel = 0xff;             /* not use dms */
 
 	sprintf(nspinfo,
 /* Buffer size is 100 bytes */
 /*  0         1         2         3         4         5         6         7         8         9         0*/
 /*  01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/
-   "NinjaSCSI-3/32Bi Driver version 2.7, I/O 0x%04lx-0x%04lx IRQ %2d",
+   "NinjaSCSI-3/32Bi Driver $Revision: 1.42 $, I/O 0x%04lx-0x%04lx IRQ %2d",
 		host->io_port, host->io_port + host->n_io_port,
 		host->irq);
 	sht->name	  = nspinfo;
@@ -1221,6 +1208,7 @@
 	return 1; /* detect done. */
 }
 
+/* nsp_cs requires own release handler because its uses dev_id (=data) */
 static int nsp_release(struct Scsi_Host *shpnt)
 {
 	nsp_hw_data *data = &nsp_data;
@@ -1228,7 +1216,7 @@
         if (shpnt->irq) {
                 free_irq(shpnt->irq, data);
 	}
-        if (shpnt->io_port) {
+        if (shpnt->io_port && shpnt->n_io_port) {
 		release_region(shpnt->io_port, shpnt->n_io_port);
 	}
 	return 0;
@@ -1249,7 +1237,9 @@
 {
 	DEBUG(0, __FUNCTION__ " SCpnt=0x%p why=%d\n", SCpnt, why);
 
-	return nsp_eh_bus_reset(SCpnt);
+	nsp_eh_bus_reset(SCpnt);
+
+	return SCSI_RESET_SUCCESS;
 }
 
 static int nsp_abort(Scsi_Cmnd *SCpnt)
@@ -1258,7 +1248,7 @@
 
 	nsp_eh_bus_reset(SCpnt);
 
-	return SUCCESS;
+	return SCSI_ABORT_SUCCESS;
 }
 
 /*static int nsp_eh_strategy(struct Scsi_Host *Shost)
@@ -1271,6 +1261,7 @@
 	DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt);
 
 	nsp_eh_bus_reset(SCpnt);
+
 	return SUCCESS;
 }
 
@@ -1309,9 +1300,8 @@
 	DEBUG(0, __FUNCTION__ "\n");
 
 	nsphw_init(data);
-	nsp_eh_bus_reset(SCpnt);
 
-	return SUCCESS;
+	return nsp_eh_bus_reset(SCpnt);
 }
 
 
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/pcmcia/nsp_cs.h linux/drivers/scsi/pcmcia/nsp_cs.h
--- v2.4.12/linux/drivers/scsi/pcmcia/nsp_cs.h	Sun Aug 12 13:28:00 2001
+++ linux/drivers/scsi/pcmcia/nsp_cs.h	Thu Oct 11 09:04:57 2001
@@ -6,22 +6,17 @@
     Ver 0.1 : Initial version.
 
     This software may be used and distributed according to the terms of
-    the GNU Public License.
+    the GNU General Public License.
 
 =========================================================*/
 
-/* $Id: nsp_cs.h,v 1.21 2001/07/04 14:45:31 elca Exp $ */
+/* $Id: nsp_cs.h,v 1.27 2001/09/10 10:31:13 elca Exp $ */
 
 #ifndef  __nsp_cs__
 #define  __nsp_cs__
 
 /* for debugging */
-/*
-#define DBG
-#define DBG_PRINT
-#define DBG_SHOWCOMMAND
-#define PCMCIA_DEBUG 9
-*/
+/*#define PCMCIA_DEBUG 9*/
 
 /*
 #define static
@@ -258,25 +253,36 @@
 } nsp_hw_data;
 
 
+static void nsp_cs_release(u_long arg);
+static int nsp_cs_event(event_t event, int priority, event_callback_args_t *args);
+static dev_link_t *nsp_cs_attach(void);
+static void nsp_cs_detach(dev_link_t *);
+
 static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt, nsp_hw_data *data);
 static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time);
 
+static int nsp_detect(Scsi_Host_Template * );
+static int nsp_release(struct Scsi_Host *shpnt);
+static const char * nsp_info(struct Scsi_Host *shpnt);
+static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+
+static int nsp_abort(Scsi_Cmnd *);
+static int nsp_reset(Scsi_Cmnd *, unsigned int);
+
 static int nsp_eh_abort(Scsi_Cmnd * SCpnt);
 static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt);
 static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt);
 static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt);
 
-static int nsp_fifo_count(Scsi_Cmnd *SCpnt);
+static int  nsp_fifo_count(Scsi_Cmnd *SCpnt);
 static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data);
-static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data);
+static int  nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data);
 
 #ifdef PCMCIA_DEBUG
-# ifdef DBG_SHOWCOMMAND
 static void show_command(Scsi_Cmnd *ptr);
 static void show_phase(Scsi_Cmnd *SCpnt);
 static void show_busphase(unsigned char stat);
 static void show_message(nsp_hw_data *data);
-# endif /* DBG_SHOWCOMMAND */
 #else
 # define show_command(ptr)   /* */
 # define show_phase(SCpnt)   /* */
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/pcmcia/nsp_debug.c linux/drivers/scsi/pcmcia/nsp_debug.c
--- v2.4.12/linux/drivers/scsi/pcmcia/nsp_debug.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/scsi/pcmcia/nsp_debug.c	Thu Oct 11 09:04:57 2001
@@ -6,7 +6,7 @@
     the GNU General Public License.
 =========================================================================*/
 
-/* $Id: nsp_debug.c,v 1.6 2001/07/04 14:43:53 elca Exp $ */
+/* $Id: nsp_debug.c,v 1.8 2001/09/07 04:32:28 elca Exp $ */
 
 /*
  * Show the command data of a command
@@ -85,7 +85,7 @@
 	}
 }
 
-void print_commandk (unsigned char *command)
+static void print_commandk (unsigned char *command)
 {
 	int i,s;
 	printk(KERN_DEBUG);
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/pcmcia/nsp_io.h linux/drivers/scsi/pcmcia/nsp_io.h
--- v2.4.12/linux/drivers/scsi/pcmcia/nsp_io.h	Sun Aug 12 13:28:00 2001
+++ linux/drivers/scsi/pcmcia/nsp_io.h	Thu Oct 11 09:04:57 2001
@@ -3,11 +3,11 @@
       By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
  
   This software may be used and distributed according to the terms of
-  the GNU Public License.
+  the GNU General Public License.
 
   */
 
-/* $Id: nsp_io.h,v 1.8 2001/01/30 05:16:02 elca Exp $ */
+/* $Id: nsp_io.h,v 1.9 2001/09/07 04:32:42 elca Exp $ */
 
 #ifndef __NSP_IO_H__
 #define __NSP_IO_H__
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/pcmcia/nsp_message.c linux/drivers/scsi/pcmcia/nsp_message.c
--- v2.4.12/linux/drivers/scsi/pcmcia/nsp_message.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/scsi/pcmcia/nsp_message.c	Thu Oct 11 09:04:57 2001
@@ -6,7 +6,7 @@
    the GNU General Public License.
  */
 
-/* $Id: nsp_message.c,v 1.6 2001/07/05 10:56:37 elca Exp $ */
+/* $Id: nsp_message.c,v 1.7 2001/09/07 04:33:01 elca Exp $ */
 
 static void nsp_message_in(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c
--- v2.4.12/linux/drivers/scsi/qlogicfc.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/qlogicfc.c	Fri Oct 12 15:35:53 2001
@@ -21,6 +21,9 @@
  *
  * Big endian support and dynamic DMA mapping added
  * by Jakub Jelinek <jakub@redhat.com>.
+ *
+ * Conversion to final pci64 DMA interfaces
+ * by David S. Miller <davem@redhat.com>.
  */
 
 /*
@@ -63,31 +66,10 @@
 #include "sd.h"
 #include "hosts.h"
 
-#if 1
-/* Once pci64_ DMA mapping interface is in, kill this. */
-typedef dma_addr_t dma64_addr_t;
-#define pci64_alloc_consistent(d,s,p) pci_alloc_consistent((d),(s),(p))
-#define pci64_free_consistent(d,s,c,a) pci_free_consistent((d),(s),(c),(a))
-#define pci64_map_single(d,c,s,dir) pci_map_single((d),(c),(s),(dir))
-#define pci64_map_sg(d,s,n,dir) pci_map_sg((d),(s),(n),(dir))
-#define pci64_unmap_single(d,a,s,dir) pci_unmap_single((d),(a),(s),(dir))
-#define pci64_unmap_sg(d,s,n,dir) pci_unmap_sg((d),(s),(n),(dir))
-#if BITS_PER_LONG > 32
 #define pci64_dma_hi32(a) ((u32) (0xffffffff & (((u64)(a))>>32)))
 #define pci64_dma_lo32(a) ((u32) (0xffffffff & (((u64)(a)))))
-#else
-#define pci64_dma_hi32(a) 0
-#define pci64_dma_lo32(a) (a)
-#endif	/* BITS_PER_LONG */
-#define pci64_dma_build(hi,lo) (lo)
-#define sg_dma64_address(s) sg_dma_address(s)
-#define sg_dma64_len(s) sg_dma_len(s)
-#if BITS_PER_LONG > 32
-#define PCI64_DMA_BITS 64
-#else
-#define PCI64_DMA_BITS	32
-#endif 	/* BITS_PER_LONG */
-#endif
+#define pci64_dma_build(hi,lo) \
+	((dma_addr_t)(((u64)(lo))|(((u64)(hi))<<32)))
 
 #include "qlogicfc.h"
 
@@ -243,13 +225,8 @@
 };
 
 /* entry header type commands */
-#if PCI64_DMA_BITS > 32
 #define ENTRY_COMMAND		0x19
 #define ENTRY_CONTINUATION	0x0a
-#else
-#define ENTRY_COMMAND		0x11
-#define ENTRY_CONTINUATION	0x02
-#endif
 
 #define ENTRY_STATUS		0x03
 #define ENTRY_MARKER		0x04
@@ -260,23 +237,12 @@
 #define EFLAG_BAD_HEADER	4
 #define EFLAG_BAD_PAYLOAD	8
 
-#if PCI64_DMA_BITS > 32
-
 struct dataseg {
 	u_int d_base;
 	u_int d_base_hi;
 	u_int d_count;
 };
 
-#else
-
-struct dataseg {
-	u_int d_base;
-	u_int d_count;
-};
-
-#endif
-
 struct Command_Entry {
 	struct Entry_header hdr;
 	u_int handle;
@@ -301,18 +267,10 @@
 #define CFLAG_READ		0x20
 #define CFLAG_WRITE		0x40
 
-#if PCI64_DMA_BITS > 32
-struct Continuation_Entry {
-	struct Entry_header hdr;
-	struct dataseg dataseg[DATASEGS_PER_CONT];
-};
-#else
 struct Continuation_Entry {
 	struct Entry_header hdr;
-        u32 rsvd;
 	struct dataseg dataseg[DATASEGS_PER_CONT];
 };
-#endif
 
 struct Marker_Entry {
 	struct Entry_header hdr;
@@ -741,7 +699,7 @@
 	struct isp2x00_hostdata *hostdata;
 	struct pci_dev *pdev;
 	unsigned short device_ids[2];
-	dma64_addr_t busaddr;
+	dma_addr_t busaddr;
 	int i;
 
 
@@ -753,7 +711,7 @@
 	tmpt->proc_name = "isp2x00";
 
 	if (pci_present() == 0) {
-		printk("qlogicfc : PCI not present\n");
+		printk(KERN_INFO "qlogicfc : PCI not present\n");
 		return 0;
 	}
 
@@ -763,6 +721,11 @@
 			if (pci_enable_device(pdev))
 				continue;
 
+			/* Try to configure DMA attributes. */
+			if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) &&
+			    pci_set_dma_mask(pdev, (u64) 0xffffffff))
+					continue;
+
 		        host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata));
 			if (!host) {
 			        printk("qlogicfc%d : could not register host.\n", hosts);
@@ -776,11 +739,11 @@
 
 			memset(hostdata, 0, sizeof(struct isp2x00_hostdata));
 			hostdata->pci_dev = pdev;
-			hostdata->res = pci64_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr);
+			hostdata->res = pci_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr);
 
 			if (!hostdata->res){
 			        printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hosts);
-				pci64_free_consistent(pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
+				pci_free_consistent(pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
 			        scsi_unregister(host);
 				continue;
 			}
@@ -813,7 +776,7 @@
 			hostdata->host_id = hosts;
 
 			if (isp2x00_init(host) || isp2x00_reset_hardware(host)) {
-				pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
+				pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
 			        scsi_unregister(host);
 				continue;
 			}
@@ -822,7 +785,7 @@
 			if (request_irq(host->irq, do_isp2x00_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) {
 			        printk("qlogicfc%d : interrupt %d already in use\n",
 				       hostdata->host_id, host->irq);
-				pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
+				pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
 				scsi_unregister(host);
 				continue;
 			}
@@ -831,7 +794,7 @@
 				       "in use\n",
 				       hostdata->host_id, host->io_port, host->io_port + 0xff);
 				free_irq(host->irq, host);
-				pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
+				pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
 				scsi_unregister(host);
 				continue;
 			}
@@ -990,7 +953,7 @@
 	u_int port_id;
 	struct sns_cb *req;
 	u_char *sns_response;
-	dma64_addr_t busaddr;
+	dma_addr_t busaddr;
 	struct isp2x00_hostdata *hostdata;
 
 	hostdata = (struct isp2x00_hostdata *) host->hostdata;
@@ -1007,7 +970,7 @@
 	}
 	printk("qlogicfc%d : Fabric found.\n", hostdata->host_id);
 
-	req = (struct sns_cb *)pci64_alloc_consistent(hostdata->pci_dev, sizeof(*req) + 608, &busaddr);
+	req = (struct sns_cb *)pci_alloc_consistent(hostdata->pci_dev, sizeof(*req) + 608, &busaddr);
 	
 	if (!req){
 		printk("qlogicfc%d : Could not allocate DMA resources for fabric initialization\n", hostdata->host_id);
@@ -1109,12 +1072,12 @@
 				done = 1;
 		} else {
 			printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]);
-			pci64_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr);
+			pci_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr);
 			return 0;
 		}
 	}
 
-	pci64_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr);
+	pci_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr);
 	return 1;
 }
 
@@ -1124,7 +1087,7 @@
 int isp2x00_release(struct Scsi_Host *host)
 {
 	struct isp2x00_hostdata *hostdata;
-	dma64_addr_t busaddr;
+	dma_addr_t busaddr;
 
 	ENTER("isp2x00_release");
 
@@ -1137,7 +1100,7 @@
 
 	busaddr = pci64_dma_build(le32_to_cpu(hostdata->control_block.res_queue_addr_high),
 				  le32_to_cpu(hostdata->control_block.res_queue_addr_lo));
-	pci64_free_consistent(hostdata->pci_dev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
+	pci_free_consistent(hostdata->pci_dev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
 
 	LEAVE("isp2x00_release");
 
@@ -1281,7 +1244,7 @@
 
 	if (Cmnd->use_sg) {
 		sg = (struct scatterlist *) Cmnd->request_buffer;
-		sg_count = pci64_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
 		cmd->segment_cnt = cpu_to_le16(sg_count);
 		ds = cmd->dataseg;
 		/* fill in first two sg entries: */
@@ -1290,11 +1253,9 @@
 			n = DATASEGS_PER_COMMAND;
 
 		for (i = 0; i < n; i++) {
-			ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma64_address(sg)));
-#if PCI64_DMA_BITS > 32
-			ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma64_address(sg)));
-#endif
-			ds[i].d_count = cpu_to_le32(sg_dma64_len(sg));
+			ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma_address(sg)));
+			ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma_address(sg)));
+			ds[i].d_count = cpu_to_le32(sg_dma_len(sg));
 			++sg;
 		}
 		sg_count -= DATASEGS_PER_COMMAND;
@@ -1316,31 +1277,30 @@
 			if (n > DATASEGS_PER_CONT)
 				n = DATASEGS_PER_CONT;
 			for (i = 0; i < n; ++i) {
-				ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma64_address(sg)));
-#if PCI64_DMA_BITS > 32
-				ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma64_address(sg)));
-#endif
-				ds[i].d_count = cpu_to_le32(sg_dma64_len(sg));
+				ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma_address(sg)));
+				ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma_address(sg)));
+				ds[i].d_count = cpu_to_le32(sg_dma_len(sg));
 				++sg;
 			}
 			sg_count -= n;
 		}
 	} else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE) {
-		dma64_addr_t busaddr = pci64_map_single(hostdata->pci_dev, Cmnd->request_buffer, Cmnd->request_bufflen,
-							scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		struct page *page = virt_to_page(Cmnd->request_buffer);
+		unsigned long offset = ((unsigned long)Cmnd->request_buffer &
+					~PAGE_MASK);
+		dma_addr_t busaddr = pci_map_page(hostdata->pci_dev,
+						  page, offset,
+						  Cmnd->request_bufflen,
+						  scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		Cmnd->SCp.dma_handle = busaddr;
 
-		*(dma64_addr_t *)&Cmnd->SCp = busaddr;
 		cmd->dataseg[0].d_base = cpu_to_le32(pci64_dma_lo32(busaddr));
-#if PCI64_DMA_BITS > 32
 		cmd->dataseg[0].d_base_hi = cpu_to_le32(pci64_dma_hi32(busaddr));
-#endif
 		cmd->dataseg[0].d_count = cpu_to_le32(Cmnd->request_bufflen);
 		cmd->segment_cnt = cpu_to_le16(1);
 	} else {
 		cmd->dataseg[0].d_base = 0;
-#if PCI64_DMA_BITS > 32
 		cmd->dataseg[0].d_base_hi = 0;
-#endif
 		cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */
 	}
 
@@ -1433,16 +1393,17 @@
 					Scsi_Cmnd *Cmnd = hostdata->handle_ptrs[i];
 
 					 if (Cmnd->use_sg)
-						 pci64_unmap_sg(hostdata->pci_dev,
-								(struct scatterlist *)Cmnd->buffer,
-								Cmnd->use_sg,
-								scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+						 pci_unmap_sg(hostdata->pci_dev,
+							      (struct scatterlist *)Cmnd->buffer,
+							      Cmnd->use_sg,
+							      scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
 					 else if (Cmnd->request_bufflen &&
-						  Cmnd->sc_data_direction != PCI_DMA_NONE)
-						 pci64_unmap_single(hostdata->pci_dev,
-								    *(dma64_addr_t *)&Cmnd->SCp,
-								    Cmnd->request_bufflen,
-								    scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+						  Cmnd->sc_data_direction != PCI_DMA_NONE) {
+						 pci_unmap_page(hostdata->pci_dev,
+								Cmnd->SCp.dma_handle,
+								Cmnd->request_bufflen,
+								scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+					 }
 
 					 hostdata->handle_ptrs[i]->result = DID_SOFT_ERROR << 16;
 
@@ -1539,16 +1500,16 @@
 			hostdata->queued--;
 			if (Cmnd != NULL) {
 				if (Cmnd->use_sg)
-					pci64_unmap_sg(hostdata->pci_dev,
-						       (struct scatterlist *)Cmnd->buffer,
-						       Cmnd->use_sg,
-						       scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+					pci_unmap_sg(hostdata->pci_dev,
+						     (struct scatterlist *)Cmnd->buffer,
+						     Cmnd->use_sg,
+						     scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
 				else if (Cmnd->request_bufflen &&
 					 Cmnd->sc_data_direction != PCI_DMA_NONE)
-					pci64_unmap_single(hostdata->pci_dev,
-							   *(dma64_addr_t *)&Cmnd->SCp,
-							   Cmnd->request_bufflen,
-							   scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+					pci_unmap_page(hostdata->pci_dev,
+						       Cmnd->SCp.dma_handle,
+						       Cmnd->request_bufflen,
+						       scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
 				Cmnd->result = 0x0;
 				(*Cmnd->scsi_done) (Cmnd);
 			} else
@@ -1594,13 +1555,14 @@
 				hostdata->queued--;
 
 				if (Cmnd->use_sg)
-					pci64_unmap_sg(hostdata->pci_dev,
-						       (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg,
-						       scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+					pci_unmap_sg(hostdata->pci_dev,
+						     (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg,
+						     scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
 				else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE)
-					pci64_unmap_single(hostdata->pci_dev, *(dma64_addr_t *)&Cmnd->SCp,
-							   Cmnd->request_bufflen,
-							   scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+					pci_unmap_page(hostdata->pci_dev,
+						       Cmnd->SCp.dma_handle,
+						       Cmnd->request_bufflen,
+						       scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
 
 				/* 
 				 * if any of the following are true we do not
@@ -1859,7 +1821,7 @@
 	u_short param[8];
 	struct isp2x00_hostdata *hostdata;
 	int loop_count;
-	dma64_addr_t busaddr;
+	dma_addr_t busaddr;
 
 	ENTER("isp2x00_reset_hardware");
 
@@ -1970,9 +1932,15 @@
 	hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[3]) & 0x00ff) << 8;
 	hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[3]) & 0xff00) >> 8;
 
-	/* FIXME: If the DMA transfer goes one way only, this should use PCI_DMA_TODEVICE and below as well. */
-	busaddr = pci64_map_single(hostdata->pci_dev, &hostdata->control_block, sizeof(hostdata->control_block),
-				   PCI_DMA_BIDIRECTIONAL);
+	/* FIXME: If the DMA transfer goes one way only, this should use
+	 *        PCI_DMA_TODEVICE and below as well.
+	 */
+	busaddr = pci_map_page(hostdata->pci_dev,
+			       virt_to_page(&hostdata->control_block),
+			       ((unsigned long) &hostdata->control_block &
+				~PAGE_MASK),
+			       sizeof(hostdata->control_block),
+			       PCI_DMA_BIDIRECTIONAL);
 
 	param[0] = MBOX_INIT_FIRMWARE;
 	param[2] = (u_short) (pci64_dma_lo32(busaddr) >> 16);
@@ -1984,21 +1952,24 @@
 	isp2x00_mbox_command(host, param);
 	if (param[0] != MBOX_COMMAND_COMPLETE) {
 		printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id,  param[0]);
-		pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block),
-				   PCI_DMA_BIDIRECTIONAL);
+		pci_unmap_page(hostdata->pci_dev, busaddr,
+			       sizeof(hostdata->control_block),
+			       PCI_DMA_BIDIRECTIONAL);
 		return 1;
 	}
 	param[0] = MBOX_GET_FIRMWARE_STATE;
 	isp2x00_mbox_command(host, param);
 	if (param[0] != MBOX_COMMAND_COMPLETE) {
 		printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id,  param[0]);
-		pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block),
-				   PCI_DMA_BIDIRECTIONAL);
+		pci_unmap_page(hostdata->pci_dev, busaddr,
+			       sizeof(hostdata->control_block),
+			       PCI_DMA_BIDIRECTIONAL);
 		return 1;
 	}
 
-	pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block),
-			   PCI_DMA_BIDIRECTIONAL);
+	pci_unmap_page(hostdata->pci_dev, busaddr,
+		       sizeof(hostdata->control_block),
+		       PCI_DMA_BIDIRECTIONAL);
 	LEAVE("isp2x00_reset_hardware");
 
 	return 0;
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/qlogicfc.h linux/drivers/scsi/qlogicfc.h
--- v2.4.12/linux/drivers/scsi/qlogicfc.h	Mon Jun 26 12:02:16 2000
+++ linux/drivers/scsi/qlogicfc.h	Sun Oct 21 10:36:54 2001
@@ -62,13 +62,8 @@
  * determined for each queue request anew.
  */
 
-#if BITS_PER_LONG > 32
 #define DATASEGS_PER_COMMAND 2
 #define DATASEGS_PER_CONT 5
-#else
-#define DATASEGS_PER_COMMAND 3
-#define DATASEGS_PER_CONT 7
-#endif
 
 #define QLOGICFC_REQ_QUEUE_LEN	127	/* must be power of two - 1 */
 #define QLOGICFC_MAX_SG(ql)	(DATASEGS_PER_COMMAND + (((ql) > 0) ? DATASEGS_PER_CONT*((ql) - 1) : 0))
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.4.12/linux/drivers/scsi/scsi.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/scsi.c	Mon Oct 15 19:30:33 2001
@@ -1837,6 +1837,8 @@
 
 	pcount = next_scsi_host;
 
+	MOD_INC_USE_COUNT;
+
 	/* The detect routine must carefully spinunlock/spinlock if 
 	   it enables interrupts, since all interrupt handlers do 
 	   spinlock as well.
@@ -1966,8 +1968,6 @@
 	       (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
 	       (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
 #endif
-
-	MOD_INC_USE_COUNT;
 
 	if (out_of_space) {
 		scsi_unregister_host(tpnt);	/* easiest way to clean up?? */
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.4.12/linux/drivers/scsi/scsi.h	Thu Oct 18 13:49:48 2001
+++ linux/drivers/scsi/scsi.h	Thu Oct 18 17:46:21 2001
@@ -633,6 +633,8 @@
 	struct scatterlist *buffer;	/* which buffer */
 	int buffers_residual;	/* how many buffers left */
 
+        dma_addr_t dma_handle;
+
 	volatile int Status;
 	volatile int Message;
 	volatile int have_data_in;
@@ -745,7 +747,8 @@
 	unsigned request_bufflen;	/* Actual request size */
 
 	struct timer_list eh_timeout;	/* Used to time out the command. */
-	void *request_buffer;	/* Actual requested buffer */
+	void *request_buffer;		/* Actual requested buffer */
+        void **bounce_buffers;		/* Array of bounce buffers when using scatter-gather */
 
 	/* These elements define the operation we ultimately want to perform */
 	unsigned char data_cmnd[MAX_COMMAND_SIZE];
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- v2.4.12/linux/drivers/scsi/scsi_debug.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/scsi_debug.c	Fri Oct 12 15:35:54 2001
@@ -154,10 +154,7 @@
 	if (SCpnt->use_sg) {
 		sgpnt = (struct scatterlist *) SCpnt->buffer;
 		for (i = 0; i < SCpnt->use_sg; i++) {
-			lpnt = (int *) sgpnt[i].alt_address;
-			printk(":%p %p %d\n", sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
-			if (lpnt)
-				printk(" (Alt %x) ", lpnt[15]);
+			printk(":%p %d\n", sgpnt[i].address, sgpnt[i].length);
 		};
 	} else {
 		printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer,
@@ -175,12 +172,6 @@
 	printk("\n");
 	if (flag == 0)
 		return;
-	lpnt = (unsigned int *) sgpnt[0].alt_address;
-	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
-		if ((i & 7) == 0)
-			printk("\n");
-		printk("%x ", *lpnt++);
-	};
 #if 0
 	printk("\n");
 	lpnt = (unsigned int *) sgpnt[0].address;
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
--- v2.4.12/linux/drivers/scsi/scsi_lib.c	Mon Aug 27 12:41:44 2001
+++ linux/drivers/scsi/scsi_lib.c	Fri Oct 12 15:35:54 2001
@@ -496,13 +496,16 @@
 	 */
 	if (SCpnt->use_sg) {
 		struct scatterlist *sgpnt;
+		void **bbpnt;
 		int i;
 
 		sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+		bbpnt = SCpnt->bounce_buffers;
 
-		for (i = 0; i < SCpnt->use_sg; i++) {
-			if (sgpnt[i].alt_address) {
-				scsi_free(sgpnt[i].address, sgpnt[i].length);
+		if (bbpnt) {
+			for (i = 0; i < SCpnt->use_sg; i++) {
+				if (bbpnt[i])
+					scsi_free(sgpnt[i].address, sgpnt[i].length);
 			}
 		}
 		scsi_free(SCpnt->request_buffer, SCpnt->sglist_len);
@@ -568,18 +571,22 @@
 	 */
 	if (SCpnt->use_sg) {
 		struct scatterlist *sgpnt;
+		void **bbpnt;
 		int i;
 
 		sgpnt = (struct scatterlist *) SCpnt->buffer;
+		bbpnt = SCpnt->bounce_buffers;
 
-		for (i = 0; i < SCpnt->use_sg; i++) {
-			if (sgpnt[i].alt_address) {
-				if (SCpnt->request.cmd == READ) {
-					memcpy(sgpnt[i].alt_address, 
-					       sgpnt[i].address,
-					       sgpnt[i].length);
+		if (bbpnt) {
+			for (i = 0; i < SCpnt->use_sg; i++) {
+				if (bbpnt[i]) {
+					if (SCpnt->request.cmd == READ) {
+						memcpy(bbpnt[i],
+						       sgpnt[i].address,
+						       sgpnt[i].length);
+					}
+					scsi_free(sgpnt[i].address, sgpnt[i].length);
 				}
-				scsi_free(sgpnt[i].address, sgpnt[i].length);
 			}
 		}
 		scsi_free(SCpnt->buffer, SCpnt->sglist_len);
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c
--- v2.4.12/linux/drivers/scsi/scsi_merge.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/scsi_merge.c	Fri Oct 12 15:35:54 2001
@@ -120,9 +120,11 @@
 {
 	int jj;
 	struct scatterlist *sgpnt;
+	void **bbpnt;
 	int consumed = 0;
 
 	sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+	bbpnt = SCpnt->bounce_buffers;
 
 	/*
 	 * Now print out a bunch of stats.  First, start with the request
@@ -136,15 +138,13 @@
 	 */
 	for(jj=0; jj < SCpnt->use_sg; jj++)
 	{
-		printk("[%d]\tlen:%d\taddr:%p\talt:%p\n",
+		printk("[%d]\tlen:%d\taddr:%p\tbounce:%p\n",
 		       jj,
 		       sgpnt[jj].length,
 		       sgpnt[jj].address,
-		       sgpnt[jj].alt_address);		       
-		if( sgpnt[jj].alt_address != NULL )
-		{
-			consumed = (sgpnt[jj].length >> 9);
-		}
+		       (bbpnt ? bbpnt[jj] : NULL));
+		if (bbpnt && bbpnt[jj])
+			consumed += sgpnt[jj].length;
 	}
 	printk("Total %d sectors consumed\n", consumed);
 	panic("DMA pool exhausted");
@@ -807,6 +807,7 @@
 	int		     sectors;
 	struct scatterlist * sgpnt;
 	int		     this_count;
+	void		   ** bbpnt;
 
 	/*
 	 * FIXME(eric) - don't inline this - it doesn't depend on the
@@ -861,10 +862,19 @@
 
 	/* 
 	 * Allocate the actual scatter-gather table itself.
-	 * scsi_malloc can only allocate in chunks of 512 bytes 
 	 */
-	SCpnt->sglist_len = (SCpnt->use_sg
-			     * sizeof(struct scatterlist) + 511) & ~511;
+	SCpnt->sglist_len = (SCpnt->use_sg * sizeof(struct scatterlist));
+
+	/* If we could potentially require ISA bounce buffers, allocate
+	 * space for this array here.
+	 */
+	if (dma_host)
+		SCpnt->sglist_len += (SCpnt->use_sg * sizeof(void *));
+
+	/* scsi_malloc can only allocate in chunks of 512 bytes so
+	 * round it up.
+	 */
+	SCpnt->sglist_len = (SCpnt->sglist_len + 511) & ~511;
 
 	sgpnt = (struct scatterlist *) scsi_malloc(SCpnt->sglist_len);
 
@@ -889,6 +899,14 @@
 	SCpnt->request_bufflen = 0;
 	bhprev = NULL;
 
+	if (dma_host)
+		bbpnt = (void **) ((char *)sgpnt +
+			 (SCpnt->use_sg * sizeof(struct scatterlist)));
+	else
+		bbpnt = NULL;
+
+	SCpnt->bounce_buffers = bbpnt;
+
 	for (count = 0, bh = SCpnt->request.bh;
 	     bh; bh = bh->b_reqnext) {
 		if (use_clustering && bhprev != NULL) {
@@ -956,7 +974,7 @@
 			if( scsi_dma_free_sectors - sectors <= 10  ) {
 				/*
 				 * If this would nearly drain the DMA
-				 * pool, mpty, then let's stop here.
+				 * pool empty, then let's stop here.
 				 * Don't make this request any larger.
 				 * This is kind of a safety valve that
 				 * we use - we could get screwed later
@@ -970,7 +988,7 @@
 				break;
 			}
 
-			sgpnt[i].alt_address = sgpnt[i].address;
+			bbpnt[i] = sgpnt[i].address;
 			sgpnt[i].address =
 			    (char *) scsi_malloc(sgpnt[i].length);
 			/*
@@ -987,7 +1005,7 @@
 				break;
 			}
 			if (SCpnt->request.cmd == WRITE) {
-				memcpy(sgpnt[i].address, sgpnt[i].alt_address,
+				memcpy(sgpnt[i].address, bbpnt[i],
 				       sgpnt[i].length);
 			}
 		}
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c
--- v2.4.12/linux/drivers/scsi/scsi_scan.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/scsi_scan.c	Thu Oct 11 09:43:30 2001
@@ -421,6 +421,10 @@
 					 max_scsi_luns : shpnt->max_lun);
 					sparse_lun = 0;
 					for (lun = 0, lun0_sl = SCSI_2; lun < max_dev_lun; ++lun) {
+						/* don't probe further for luns > 7 for targets <= SCSI_2 */
+						if ((lun0_sl < SCSI_3) && (lun > 7))
+							break;
+
 						if (!scan_scsis_single(channel, order_dev, lun, lun0_sl,
 							 	       &max_dev_lun, &sparse_lun, &SDpnt, shpnt,
 								       scsi_result)
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.4.12/linux/drivers/scsi/sd.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/sd.c	Mon Oct 15 19:30:33 2001
@@ -152,6 +152,9 @@
 	int diskinfo[4];
     
 	SDev = rscsi_disks[DEVICE_NR(dev)].device;
+	if (!SDev)
+		return -ENODEV;
+
 	/*
 	 * If we are in the middle of error recovery, don't let anyone
 	 * else try and use this device.  Also, if error recovery fails, it
@@ -228,7 +231,7 @@
 			return 0;
 		}
 		case BLKGETSIZE:   /* Return device size */
-			return put_user(sd[SD_PARTITION(inode->i_rdev)].nr_sects, (long *) arg);
+			return put_user(sd[SD_PARTITION(inode->i_rdev)].nr_sects, (unsigned long *) arg);
 		case BLKGETSIZE64:
 			return put_user((u64)sd[SD_PARTITION(inode->i_rdev)].nr_sects << 9, (u64 *)arg);
 
@@ -533,6 +536,8 @@
 
 	target = DEVICE_NR(inode->i_rdev);
 	SDev = rscsi_disks[target].device;
+	if (!SDev)
+		return -ENODEV;
 
 	SDev->access_count--;
 
@@ -786,7 +791,7 @@
 			SRpnt->sr_cmd_len = 0;
 			SRpnt->sr_sense_buffer[0] = 0;
 			SRpnt->sr_sense_buffer[2] = 0;
-			SRpnt->sr_data_direction = SCSI_DATA_READ;
+			SRpnt->sr_data_direction = SCSI_DATA_NONE;
 
 			scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer,
 				0/*512*/, SD_TIMEOUT, MAX_RETRIES);
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.4.12/linux/drivers/scsi/sr.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/sr.c	Fri Oct 12 15:35:54 2001
@@ -264,6 +264,7 @@
 	struct scatterlist *sg, *old_sg = NULL;
 	int i, fsize, bsize, sg_ent, sg_count;
 	char *front, *back;
+	void **bbpnt, **old_bbpnt = NULL;
 
 	back = front = NULL;
 	sg_ent = SCpnt->use_sg;
@@ -291,17 +292,25 @@
 	 * extend or allocate new scatter-gather table
 	 */
 	sg_count = SCpnt->use_sg;
-	if (sg_count)
+	if (sg_count) {
 		old_sg = (struct scatterlist *) SCpnt->request_buffer;
-	else {
+		old_bbpnt = SCpnt->bounce_buffers;
+	} else {
 		sg_count = 1;
 		sg_ent++;
 	}
 
-	i = ((sg_ent * sizeof(struct scatterlist)) + 511) & ~511;
+	/* Get space for scatterlist and bounce buffer array. */
+	i  = sg_ent * sizeof(struct scatterlist);
+	i += sg_ent * sizeof(void *);
+	i  = (i + 511) & ~511;
+
 	if ((sg = scsi_malloc(i)) == NULL)
 		goto no_mem;
 
+	bbpnt = (void **)
+		((char *)sg + (sg_ent * sizeof(struct scatterlist)));
+
 	/*
 	 * no more failing memory allocs possible, we can safely assign
 	 * SCpnt values now
@@ -312,13 +321,15 @@
 
 	i = 0;
 	if (fsize) {
-		sg[0].address = sg[0].alt_address = front;
+		sg[0].address = bbpnt[0] = front;
 		sg[0].length = fsize;
 		i++;
 	}
 	if (old_sg) {
 		memcpy(sg + i, old_sg, SCpnt->use_sg * sizeof(struct scatterlist));
-		scsi_free(old_sg, ((SCpnt->use_sg * sizeof(struct scatterlist)) + 511) & ~511);
+		memcpy(bbpnt + i, old_bbpnt, SCpnt->use_sg * sizeof(void *));
+		scsi_free(old_sg, (((SCpnt->use_sg * sizeof(struct scatterlist)) +
+				    (SCpnt->use_sg * sizeof(void *))) + 511) & ~511);
 	} else {
 		sg[i].address = SCpnt->request_buffer;
 		sg[i].length = SCpnt->request_bufflen;
@@ -326,11 +337,12 @@
 
 	SCpnt->request_bufflen += (fsize + bsize);
 	SCpnt->request_buffer = sg;
+	SCpnt->bounce_buffers = bbpnt;
 	SCpnt->use_sg += i;
 
 	if (bsize) {
 		sg[SCpnt->use_sg].address = back;
-		sg[SCpnt->use_sg].alt_address = back;
+		bbpnt[SCpnt->use_sg] = back;
 		sg[SCpnt->use_sg].length = bsize;
 		SCpnt->use_sg++;
 	}
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.4.12/linux/drivers/scsi/sr_ioctl.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/scsi/sr_ioctl.c	Mon Oct 15 13:27:42 2001
@@ -545,7 +545,7 @@
 
 	switch (cmd) {
 	case BLKGETSIZE:
-		return put_user(scsi_CDs[target].capacity, (long *) arg);
+		return put_user(scsi_CDs[target].capacity, (unsigned long *) arg);
 	case BLKGETSIZE64:
 		return put_user((u64)scsi_CDs[target].capacity << 9, (u64 *)arg);
 	case BLKROSET:
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.4.12/linux/drivers/scsi/st.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/st.c	Fri Oct 12 15:35:54 2001
@@ -3229,7 +3229,6 @@
 			tb->sg[0].address =
 			    (unsigned char *) __get_free_pages(priority, order);
 			if (tb->sg[0].address != NULL) {
-				tb->sg[0].alt_address = NULL;
 				tb->sg[0].length = b_size;
 				break;
 			}
@@ -3265,7 +3264,6 @@
 					tb = NULL;
 					break;
 				}
-				tb->sg[segs].alt_address = NULL;
 				tb->sg[segs].length = b_size;
 				got += b_size;
 				segs++;
@@ -3339,7 +3337,6 @@
 			normalize_buffer(STbuffer);
 			return FALSE;
 		}
-		STbuffer->sg[segs].alt_address = NULL;
 		STbuffer->sg[segs].length = b_size;
 		STbuffer->sg_segs += 1;
 		got += b_size;
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- v2.4.12/linux/drivers/scsi/sym53c8xx.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/sym53c8xx.c	Wed Oct 17 14:16:39 2001
@@ -987,8 +987,8 @@
 	if (vbp) {
 		dma_addr_t daddr;
 		vp = (m_addr_t) pci_alloc_consistent(mp->bush,
-						PAGE_SIZE<<MEMO_PAGE_ORDER,
-						&daddr);
+						     PAGE_SIZE<<MEMO_PAGE_ORDER,
+						     &daddr);
 		if (vp) {
 			int hc = VTOB_HASH_CODE(vp);
 			vbp->vaddr = vp;
@@ -1138,26 +1138,26 @@
 /* Linux version with pci bus iommu kernel interface */
 
 /* To keep track of the dma mapping (sg/single) that has been set */
-#define __data_mapped	SCp.phase
-#define __data_mapping	SCp.have_data_in
+#define __data_mapped(cmd)	(cmd)->SCp.phase
+#define __data_mapping(cmd)	(cmd)->SCp.dma_handle
 
 static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd)
 {
 	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 
-	switch(cmd->__data_mapped) {
+	switch(__data_mapped(cmd)) {
 	case 2:
 		pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
 		break;
 	case 1:
-		pci_unmap_single(pdev, cmd->__data_mapping,
-				 cmd->request_bufflen, dma_dir);
+		pci_unmap_page(pdev, __data_mapping(cmd),
+			       cmd->request_bufflen, dma_dir);
 		break;
 	}
-	cmd->__data_mapped = 0;
+	__data_mapped(cmd) = 0;
 }
 
-static u_long __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+static dma_addr_t __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd)
 {
 	dma_addr_t mapping;
 	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
@@ -1165,10 +1165,13 @@
 	if (cmd->request_bufflen == 0)
 		return 0;
 
-	mapping = pci_map_single(pdev, cmd->request_buffer,
-				 cmd->request_bufflen, dma_dir);
-	cmd->__data_mapped = 1;
-	cmd->__data_mapping = mapping;
+	mapping = pci_map_page(pdev,
+			       virt_to_page(cmd->request_buffer),
+			       ((unsigned long)cmd->request_buffer &
+				~PAGE_MASK),
+			       cmd->request_bufflen, dma_dir);
+	__data_mapped(cmd) = 1;
+	__data_mapping(cmd) = mapping;
 
 	return mapping;
 }
@@ -1182,8 +1185,8 @@
 		return 0;
 
 	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
-	cmd->__data_mapped = 2;
-	cmd->__data_mapping = use_sg;
+	__data_mapped(cmd) = 2;
+	__data_mapping(cmd) = use_sg;
 
 	return use_sg;
 }
@@ -1192,12 +1195,12 @@
 {
 	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 
-	switch(cmd->__data_mapped) {
+	switch(__data_mapped(cmd)) {
 	case 2:
 		pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
 		break;
 	case 1:
-		pci_dma_sync_single(pdev, cmd->__data_mapping,
+		pci_dma_sync_single(pdev, __data_mapping(cmd),
 				    cmd->request_bufflen, dma_dir);
 		break;
 	}
@@ -5029,12 +5032,12 @@
 	/*
 	**	64 bit (53C895A or 53C896) ?
 	*/
-	if (np->features & FE_DAC)
-#ifdef SCSI_NCR_USE_64BIT_DAC
-		np->rv_ccntl1	|= (XTIMOD | EXTIBMV);
-#else
-		np->rv_ccntl1	|= (DDAC);
-#endif
+	if (np->features & FE_DAC) {
+		if (np->features & FE_DAC_IN_USE)
+			np->rv_ccntl1	|= (XTIMOD | EXTIBMV);
+		else
+			np->rv_ccntl1	|= (DDAC);
+	}
 
 	/*
 	**	Phase mismatch handled by SCRIPTS (53C895A, 53C896 or C1010) ?
@@ -12068,15 +12071,9 @@
 **	code will get more complex later).
 */
 
-#ifdef SCSI_NCR_USE_64BIT_DAC
 #define SCATTER_ONE(data, badd, len)					\
 	(data)->addr = cpu_to_scr(badd);				\
 	(data)->size = cpu_to_scr((((badd) >> 8) & 0xff000000) + len);
-#else
-#define SCATTER_ONE(data, badd, len)		\
-	(data)->addr = cpu_to_scr(badd);	\
-	(data)->size = cpu_to_scr(len);
-#endif
 
 #define CROSS_16MB(p, n) (((((u_long) p) + n - 1) ^ ((u_long) p)) & ~0xffffff)
 
@@ -12088,7 +12085,7 @@
 	cp->data_len = cmd->request_bufflen;
 
 	if (cmd->request_bufflen) {
-		u_long baddr = map_scsi_single_data(np, cmd);
+		dma_addr_t baddr = map_scsi_single_data(np, cmd);
 
 		SCATTER_ONE(data, baddr, cmd->request_bufflen);
 		if (CROSS_16MB(baddr, cmd->request_bufflen)) {
@@ -12139,7 +12136,7 @@
 		data = &cp->phys.data[MAX_SCATTER - use_sg];
 
 		for (segn = 0; segn < use_sg; segn++) {
-			u_long baddr = scsi_sg_dma_address(&scatter[segn]);
+			dma_addr_t baddr = scsi_sg_dma_address(&scatter[segn]);
 			unsigned int len = scsi_sg_dma_len(&scatter[segn]);
 
 			SCATTER_ONE(&data[segn],
@@ -12178,7 +12175,7 @@
 		data = &cp->phys.data[MAX_SCATTER - use_sg];
 
 		for (segment = 0; segment < use_sg; segment++) {
-			u_long baddr = scsi_sg_dma_address(&scatter[segment]);
+			dma_addr_t baddr = scsi_sg_dma_address(&scatter[segment]);
 			unsigned int len = scsi_sg_dma_len(&scatter[segment]);
 
 			SCATTER_ONE(&data[segment],
@@ -13098,14 +13095,6 @@
 		(int) (PciDeviceFn(pdev) & 0xf8) >> 3,
 		(int) (PciDeviceFn(pdev) & 7));
 
-#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
-	if (pci_set_dma_mask(pdev, (dma_addr_t) (0xffffffffUL))) {
-		printk(KERN_WARNING NAME53C8XX
-		       "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
-		return -1;
-	}
-#endif
-
 	/*
 	**    Read info from the PCI config space.
 	**    pci_read_config_xxx() functions are assumed to be used for 
@@ -13173,6 +13162,28 @@
 		break;
 	}
 
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+	/* Configure DMA attributes.  For DAC capable boards, we can encode
+	** 32+8 bits for SCSI DMA data addresses with the extra bits used
+	** in the size field.  We use normal 32-bit PCI addresses for
+	** descriptors.
+	*/
+	if (chip && (chip->features & FE_DAC)) {
+		if (pci_set_dma_mask(pdev, (u64) 0xffffffffff))
+			chip->features &= ~FE_DAC_IN_USE;
+		else
+			chip->features |= FE_DAC_IN_USE;
+	}
+
+	if (chip && !(chip->features & FE_DAC_IN_USE)) {
+		if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) {
+			printk(KERN_WARNING NAME53C8XX
+			       "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
+			return -1;
+		}
+	}
+#endif
+
 	/*
 	**	Ignore Symbios chips controlled by SISL RAID controller.
 	**	This controller sets value 0x52414944 at RAM end - 16.
@@ -13609,8 +13620,8 @@
      cmd->SCp.ptr       = NULL;
      cmd->SCp.buffer    = NULL;
 #ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
-     cmd->__data_mapped = 0;
-     cmd->__data_mapping = 0;
+     __data_mapped(cmd) = 0;
+     __data_mapping(cmd) = 0;
 #endif
 
      NCR_LOCK_NCB(np, flags);
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h
--- v2.4.12/linux/drivers/scsi/sym53c8xx_comm.h	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/sym53c8xx_comm.h	Fri Oct 12 15:35:54 2001
@@ -2186,7 +2186,7 @@
 		(int) (PciDeviceFn(pdev) & 7));
 
 #ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
-	if (!pci_dma_supported(pdev, (dma_addr_t) (0xffffffffUL))) {
+	if (!pci_dma_supported(pdev, 0xffffffff)) {
 		printk(KERN_WARNING NAME53C8XX
 		       "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
 		return -1;
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/sym53c8xx_defs.h linux/drivers/scsi/sym53c8xx_defs.h
--- v2.4.12/linux/drivers/scsi/sym53c8xx_defs.h	Thu Oct 18 13:50:38 2001
+++ linux/drivers/scsi/sym53c8xx_defs.h	Thu Oct 18 17:47:00 2001
@@ -184,20 +184,6 @@
 #endif
 
 /*
- * Should we enable DAC cycles on Sparc64 platform?
- * Until further investigation we do not enable it
- * at the moment.
- * We may want to enable it for __ia64__ (untested)
- */
-#if defined(__ia64__)
-#    if !defined(SCSI_NCR_USE_64BIT_DAC)
-#        define SCSI_NCR_USE_64BIT_DAC
-#    endif
-#else
-#    undef SCSI_NCR_USE_64BIT_DAC
-#endif
-
-/*
  * Immediate arbitration
  */
 #if defined(CONFIG_SCSI_NCR53C8XX_IARB)
@@ -205,13 +191,6 @@
 #endif
 
 /*
- * Should we enable DAC cycles on sparc64 platforms?
- * Until further investigation we do not enable it
- * anywhere at the moment.
- */
-#undef SCSI_NCR_USE_64BIT_DAC
-
-/*
  * Sync transfer frequency at startup.
  * Allow from 5Mhz to 80Mhz default 20 Mhz.
  */
@@ -746,6 +725,7 @@
 #define FE_66MHZ 	(1<<23)   /* 66MHz PCI Support */
 #define FE_DAC	 	(1<<24)   /* Support DAC cycles (64 bit addressing) */
 #define FE_ISTAT1 	(1<<25)   /* Have ISTAT1, MBOX0, MBOX1 registers */
+#define FE_DAC_IN_USE	(1<<26)	  /* Platform does DAC cycles */
 
 #define FE_CACHE_SET	(FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
 #define FE_SCSI_SET	(FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80)
diff -u --recursive --new-file v2.4.12/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c
--- v2.4.12/linux/drivers/sgi/char/graphics.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/sgi/char/graphics.c	Thu Oct 11 09:43:30 2001
@@ -343,6 +343,8 @@
 }
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void) {
 	static int initiated = 0;
 
diff -u --recursive --new-file v2.4.12/linux/drivers/sound/btaudio.c linux/drivers/sound/btaudio.c
--- v2.4.12/linux/drivers/sound/btaudio.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/sound/btaudio.c	Wed Oct 17 14:19:20 2001
@@ -748,6 +748,24 @@
         case SNDCTL_DSP_SYNC:
 		/* NOP */
 		return 0;
+	case SNDCTL_DSP_GETISPACE:
+	{
+		audio_buf_info info;
+		if (!bta->recording)
+			return -EINVAL;
+		info.fragsize = bta->block_bytes>>bta->sampleshift;
+		info.fragstotal = bta->block_count;
+		info.bytes = bta->read_count;
+		info.fragments = info.bytes / info.fragsize;
+		if (debug)
+			printk(KERN_DEBUG "btaudio: SNDCTL_DSP_GETISPACE "
+			       "returns %d/%d/%d/%d\n",
+			       info.fragsize, info.fragstotal,
+			       info.bytes, info.fragments);
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
 #if 0 /* TODO */
         case SNDCTL_DSP_GETTRIGGER:
         case SNDCTL_DSP_SETTRIGGER:
diff -u --recursive --new-file v2.4.12/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- v2.4.12/linux/drivers/sound/cmpci.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/sound/cmpci.c	Thu Oct 11 09:43:30 2001
@@ -74,6 +74,7 @@
  *    18/05/2001 - .bss nitpicks, fix a bug in set_dac_channels where it
  *    		   was calling prog_dmabuf with s->lock held, call missing
  *    		   unlock_kernel in cm_midi_release
+ *    08/10/2001 - use set_current_state in some more places
  *
  *	Carlos Eduardo Gorges <carlos@techlinux.com.br>
  *	Fri May 25 2001 
@@ -1483,7 +1484,7 @@
 
 	if (s->dma_dac.mapped || !s->dma_dac.ready)
 		return 0;
-        current->state = TASK_INTERRUPTIBLE;
+        set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac.wait, &wait);
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
@@ -1495,7 +1496,7 @@
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
 		tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
@@ -1504,7 +1505,7 @@
 			printk(KERN_DEBUG "cmpci: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
diff -u --recursive --new-file v2.4.12/linux/drivers/sound/ite8172.c linux/drivers/sound/ite8172.c
--- v2.4.12/linux/drivers/sound/ite8172.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/sound/ite8172.c	Thu Oct 11 09:43:30 2001
@@ -58,7 +58,7 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/sound.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/soundcard.h>
 #include <linux/pci.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.4.12/linux/drivers/sound/maestro3.c linux/drivers/sound/maestro3.c
--- v2.4.12/linux/drivers/sound/maestro3.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/sound/maestro3.c	Thu Oct 11 09:43:30 2001
@@ -172,7 +172,7 @@
 #define SND_DEV_DSP16       5 
    
 #ifdef M_DEBUG
-static int debug=0;
+static int debug;
 #define DPMOD   1   /* per module load */
 #define DPSTR   2   /* per 'stream' */
 #define DPSYS   3   /* per syscall */
@@ -365,7 +365,7 @@
     return r;
 }
 
-static struct m3_card *devs = NULL;
+static struct m3_card *devs;
 
 /*
  * I'm not very good at laying out functions in a file :)
@@ -1289,7 +1289,7 @@
 
     if (s->dma_dac.mapped || !s->dma_dac.ready)
         return 0;
-    current->state = TASK_INTERRUPTIBLE;
+    set_current_state(TASK_INTERRUPTIBLE);
     add_wait_queue(&s->dma_dac.wait, &wait);
     for (;;) {
         spin_lock_irqsave(&s->lock, flags);
@@ -1301,7 +1301,7 @@
             break;
         if (nonblock) {
             remove_wait_queue(&s->dma_dac.wait, &wait);
-            current->state = TASK_RUNNING;
+            set_current_state(TASK_RUNNING);
             return -EBUSY;
         }
         tmo = (count * HZ) / s->ratedac;
@@ -1312,7 +1312,7 @@
             DPRINTK(DPCRAP,"dma timed out?? %ld\n",jiffies);
     }
     remove_wait_queue(&s->dma_dac.wait, &wait);
-    current->state = TASK_RUNNING;
+    set_current_state(TASK_RUNNING);
     if (signal_pending(current))
             return -ERESTARTSYS;
     return 0;
@@ -2251,7 +2251,7 @@
         if(busywait)  {
             mdelay(delay1);
         } else {
-            current->state = TASK_UNINTERRUPTIBLE;
+            set_current_state(TASK_UNINTERRUPTIBLE);
             schedule_timeout((delay1 * HZ) / 1000);
         }
 
@@ -2264,7 +2264,7 @@
         if(busywait) {
             mdelay(delay2);
         } else {
-            current->state = TASK_UNINTERRUPTIBLE;
+            set_current_state(TASK_UNINTERRUPTIBLE);
             schedule_timeout((delay2 * HZ) / 1000);
         }
         if(! try_read_vendor(card))
@@ -2958,8 +2958,8 @@
 
     card->in_suspend++;
     add_wait_queue(&card->suspend_queue, &wait);
-    current->state = TASK_UNINTERRUPTIBLE;
+    set_current_state(TASK_UNINTERRUPTIBLE);
     schedule();
     remove_wait_queue(&card->suspend_queue, &wait);
-    current->state = TASK_RUNNING;
+    set_current_state(TASK_RUNNING);
 }
diff -u --recursive --new-file v2.4.12/linux/drivers/sound/nec_vrc5477.c linux/drivers/sound/nec_vrc5477.c
--- v2.4.12/linux/drivers/sound/nec_vrc5477.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/sound/nec_vrc5477.c	Thu Oct 11 09:43:30 2001
@@ -67,7 +67,7 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/sound.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/soundcard.h>
 #include <linux/pci.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.4.12/linux/drivers/sound/opl3sa2.c linux/drivers/sound/opl3sa2.c
--- v2.4.12/linux/drivers/sound/opl3sa2.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/sound/opl3sa2.c	Thu Oct 11 09:43:30 2001
@@ -862,9 +862,9 @@
 
 	/* Our own config: */
 	hw_cfg->io_base = dev->resource[4].start;
-	hw_cfg->irq     = 0;
-	hw_cfg->dma     = -1;
-	hw_cfg->dma2    = -1;
+	hw_cfg->irq     = dev->irq_resource[0].start;
+	hw_cfg->dma     = dev->dma_resource[0].start;
+	hw_cfg->dma2    = dev->dma_resource[1].start;
 	
 	/* The MSS config: */
 	mss_cfg->io_base      = dev->resource[1].start;
@@ -944,9 +944,9 @@
 			 *  give pretty output from conf_printf. :)
 			 */
 			cfg[card].io_base = io;
-			cfg[card].irq     = 0;
-			cfg[card].dma     = -1;
-			cfg[card].dma2    = -1;
+			cfg[card].irq     = irq;
+			cfg[card].dma     = dma;
+			cfg[card].dma2    = dma2;
 	
 			/* The MSS config: */
 			cfg_mss[card].io_base      = mss_io;
diff -u --recursive --new-file v2.4.12/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.4.12/linux/drivers/sound/sb_card.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/sound/sb_card.c	Thu Oct 11 09:43:30 2001
@@ -53,6 +53,9 @@
  *
  * 28-10-2000 Added pnplegacy support
  * 	Daniel Church <dchurch@mbhs.edu>
+ *
+ * 01-10-2001 Added a new flavor of Creative SB AWE64 PnP (CTL00E9).
+ *      Jerome Cornet <jcornet@free.fr>
  */
 
 #include <linux/config.h>
@@ -434,6 +437,11 @@
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
 		0,0,0,0,
 		0,1,1,-1},
+	{"Sound Blaster AWE 64",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00E9), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
+		0,0,0,0,
+		0,1,1,-1},
 	{"ESS 1688",
 		ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x0968), 
 		ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968),
@@ -621,6 +629,9 @@
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), 0 },
 
 	{	ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00E4), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), 0 },
+
+	{	ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00E9),
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), 0 },
 
 	{	ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x0968), 
diff -u --recursive --new-file v2.4.12/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
--- v2.4.12/linux/drivers/sound/trident.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/sound/trident.c	Thu Oct 11 09:43:30 2001
@@ -36,6 +36,10 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  History
+ *  v0.14.9d
+ *  	October 8 2001 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *	use set_current_state, properly release resources on failure in
+ *	trident_probe, get rid of check_region
  *  v0.14.9c
  *	August 10 2001 Peter Wächtler <pwaechtler@loewe-komp.de>
  *	added support for Tvia (formerly Integraphics/IGST) CyberPro5050
@@ -176,7 +180,7 @@
 
 #include <linux/pm.h>
 
-#define DRIVER_VERSION "0.14.9c"
+#define DRIVER_VERSION "0.14.9d"
 
 /* magic numbers to protect our data structures */
 #define TRIDENT_CARD_MAGIC	0x5072696E /* "Prin" */
@@ -1358,7 +1362,7 @@
 	for (;;) {
 		/* It seems that we have to set the current state to TASK_INTERRUPTIBLE
 		   every time to make the process really go to sleep */
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 
 		spin_lock_irqsave(&state->card->lock, flags);
 		count = dmabuf->count;
@@ -1372,7 +1376,7 @@
 
 		if (nonblock) {
 			remove_wait_queue(&dmabuf->wait, &wait);
-			current->state = TASK_RUNNING;
+			set_current_state(TASK_RUNNING);
 			return -EBUSY;
 		}
 
@@ -1395,7 +1399,7 @@
 		}
 	}
 	remove_wait_queue(&dmabuf->wait, &wait);
-	current->state = TASK_RUNNING;
+	set_current_state(TASK_RUNNING);
 	if (signal_pending(current))
 		return -ERESTARTSYS;
 
@@ -3695,7 +3699,7 @@
 }
 
 #ifdef CONFIG_PROC_FS
-struct proc_dir_entry *res = NULL;
+struct proc_dir_entry *res;
 static int ali_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
 {
 	struct trident_card *card = (struct trident_card *)data;
@@ -3936,14 +3940,15 @@
 	int i = 0;
 	u16 temp;
 	struct pci_dev *pci_dev_m1533 = NULL;
+	int rc = -ENODEV;
 
 	if (pci_enable_device(pci_dev))
-		return -ENODEV;
+		goto out;
 
 	if (pci_set_dma_mask(pci_dev, TRIDENT_DMA_MASK)) {
 		printk(KERN_ERR "trident: architecture does not support"
 		       " 30bit PCI busmaster DMA\n");
-		return -ENODEV;
+		goto out;
 	}
 	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
 
@@ -3952,15 +3957,16 @@
 	else
 		iobase = pci_resource_start(pci_dev, 0);
 
-	if (check_region(iobase, 256)) {
+	if (!request_region(iobase, 256, card_names[pci_id->driver_data])) {
 		printk(KERN_ERR "trident: can't allocate I/O space at 0x%4.4lx\n",
 		       iobase);
-		return -ENODEV;
+		goto out;
 	}
 
+	rc = -ENOMEM;
 	if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) {
 		printk(KERN_ERR "trident: out of memory\n");
-		return -ENOMEM;
+		goto out_release_region;
 	}
 	memset(card, 0, sizeof(*card));
 
@@ -4014,8 +4020,9 @@
 		/* Add H/W Volume Control By Matt Wu Jul. 06, 2001 */
 		card->hwvolctl = 0;
 		pci_dev_m1533 = pci_find_device(PCI_VENDOR_ID_AL,PCI_DEVICE_ID_AL_M1533, pci_dev_m1533);
+		rc = -ENODEV;
 		if (pci_dev_m1533 == NULL)
-			return -ENODEV;
+			goto out_proc_fs;
 		pci_read_config_byte(pci_dev_m1533, 0x63, &bits);
 		if (bits & (1<<5))
 			card->hwvolctl = 1;
@@ -4044,22 +4051,17 @@
 		card->address_interrupt = trident_address_interrupt;
 	}
 
-	/* claim our iospace and irq */
-	request_region(card->iobase, 256, card_names[pci_id->driver_data]);
+	/* claim our irq */
+	rc = -ENODEV;
 	if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ,
 			card_names[pci_id->driver_data], card)) {
 		printk(KERN_ERR "trident: unable to allocate irq %d\n", card->irq);
-		release_region(card->iobase, 256);
-		kfree(card);
-		return -ENODEV;
+		goto out_proc_fs;
 	}
 	/* register /dev/dsp */
 	if ((card->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0) {
 		printk(KERN_ERR "trident: couldn't register DSP device!\n");
-		release_region(iobase, 256);
-		free_irq(card->irq, card);
-		kfree(card);
-		return -ENODEV;
+		goto out_free_irq;
 	}
 	card->mixer_regs_ready = 0;
 	/* initialize AC97 codec and register /dev/mixer */
@@ -4071,11 +4073,7 @@
 				kfree (card->ac97_codec[i]);
 			}
 		}
-		unregister_sound_dsp(card->dev_audio);
-		release_region(iobase, 256);
-		free_irq(card->irq, card);
-		kfree(card);
-		return -ENODEV;
+		goto out_unregister_sound_dsp;
 	}
 	card->mixer_regs_ready = 1;
 	outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
@@ -4112,13 +4110,28 @@
 #endif
 		/* edited by HMSEO for GT sound*/
 	}
-
+	rc = 0;
 	pci_set_drvdata(pci_dev, card);
 
 	/* Enable Address Engine Interrupts */
 	trident_enable_loop_interrupts(card);
-
-	return 0;
+out:	return rc;
+out_unregister_sound_dsp:
+	unregister_sound_dsp(card->dev_audio);
+out_free_irq:
+	free_irq(card->irq, card);
+out_proc_fs:
+#ifdef CONFIG_PROC_FS
+	if (res) {
+		remove_proc_entry("ALi5451", NULL);
+		res = NULL;
+	}
+#endif
+	kfree(card);
+	devs = NULL;
+out_release_region:
+	release_region(iobase, 256);
+	goto out;
 }
 
 static void __exit trident_remove(struct pci_dev *pci_dev)
diff -u --recursive --new-file v2.4.12/linux/drivers/sound/vidc.c linux/drivers/sound/vidc.c
--- v2.4.12/linux/drivers/sound/vidc.c	Fri Apr 13 20:26:07 2001
+++ linux/drivers/sound/vidc.c	Thu Oct 11 09:43:30 2001
@@ -542,3 +542,8 @@
 
 module_init(init_vidc);
 module_exit(cleanup_vidc);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("VIDC20 audio driver");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.12/linux/drivers/tc/tc.c linux/drivers/tc/tc.c
--- v2.4.12/linux/drivers/tc/tc.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/tc/tc.c	Thu Oct 11 09:43:30 2001
@@ -25,6 +25,7 @@
 
 #define TC_DEBUG
 
+MODULE_LICENSE("GPL");
 slot_info tc_bus[MAX_SLOT];
 static int max_tcslot;
 static tcinfo *info;
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.4.12/linux/drivers/usb/Config.in	Tue Oct  9 17:06:52 2001
+++ linux/drivers/usb/Config.in	Wed Oct 17 14:35:17 2001
@@ -4,8 +4,8 @@
 mainmenu_option next_comment
 comment 'USB support'
 
-tristate 'Support for USB' CONFIG_USB
-if [ ! "$CONFIG_USB" = "n" ]; then
+dep_tristate 'Support for USB' CONFIG_USB $CONFIG_PCI
+if [ "$CONFIG_USB" = "y" -o  "$CONFIG_USB" = "m" ]; then
    bool '  USB verbose debug messages' CONFIG_USB_DEBUG
 
 comment 'Miscellaneous USB options'
@@ -15,73 +15,84 @@
    else
       define_bool CONFIG_USB_BANDWIDTH n
    fi
+   bool '  Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT
+   bool '  Large report fetching for "broken" devices (some APC UPSes)' CONFIG_USB_LARGE_CONFIG
+fi
 
 comment 'USB Controllers'
-   if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
-      dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
-   fi
-   if [ "$CONFIG_USB_UHCI" != "y" ]; then
-      dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
-   fi
-   dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
+if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
+   dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+fi
+if [ "$CONFIG_USB_UHCI" != "y" ]; then
+   dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
+else
+   define_bool CONFIG_USB_UHCI_ALT n
+fi
+dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
 
-   comment 'USB Device Class drivers'
-   dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
-   dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
-   if [ "$CONFIG_USB_STORAGE" != "n" ]; then
-      bool '    USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
-      bool '    Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM
-      bool '    ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200
-      bool '    Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-         bool '    HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e
-         bool '    SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09
-      fi
+comment 'USB Device Class drivers'
+dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
+dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
+   dep_mbool '    USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE
+   dep_mbool '    Datafab MDCFE-B Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+   dep_mbool '    Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM  $CONFIG_USB_STORAGE
+   dep_mbool '    ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE
+   dep_mbool '    Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE
+   dep_mbool '    HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+   dep_mbool '    SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+   dep_mbool '    Lexar Jumpshot Compact Flash Reader' CONFIG_USB_STORAGE_JUMPSHOT $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
+dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
+
+comment 'USB Human Interface Devices (HID)'
+if [ "$CONFIG_INPUT" = "n" ]; then
+   comment '  Input core support is needed for USB HID'
+else
+   dep_tristate '  USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT
+      dep_mbool '    /dev/hiddev raw HID device support (EXPERIMENTAL)' CONFIG_USB_HIDDEV $CONFIG_USB_HID
+   if [ "$CONFIG_USB_HID" != "y" ]; then
+      dep_tristate '  USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT
+      dep_tristate '  USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT
    fi
-   dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
-   dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
-
-   comment 'USB Human Interface Devices (HID)'
-   if [ "$CONFIG_INPUT" = "n" ]; then
-      comment '  Input core support is needed for USB HID'
-   else
-      dep_tristate '  USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT
-      if [ "$CONFIG_USB_HID" != "y" ]; then
-         dep_tristate '  USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT
-         dep_tristate '  USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT
-      fi
-      dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
-   fi
-
-   comment 'USB Imaging devices'
-   dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
-   dep_tristate '  USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
-   dep_tristate '  Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI
-   dep_tristate '  HP53xx USB scanner support (EXPERIMENTAL)' CONFIG_USB_HPUSBSCSI $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
+   dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
+fi
 
-   comment 'USB Multimedia devices'
+comment 'USB Imaging devices'
+dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
+dep_tristate '  USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
+dep_tristate '  Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI
+dep_tristate '  HP53xx USB scanner support (EXPERIMENTAL)' CONFIG_USB_HPUSBSCSI $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
+
+comment 'USB Multimedia devices'
+if [ "$CONFIG_VIDEO_DEV" = "n" ]; then
+   comment '  Video4Linux support is needed for USB Multimedia device support'
+else
    dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
    dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
+fi
 
-   comment 'USB Network adaptors'
+comment 'USB Network adaptors'
+if [ "$CONFIG_NET" = "n" ]; then
+   comment '  Networking support is needed for USB Networking device support'
+else
    dep_tristate '  USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB CATC NetMate-based Ethernet driver (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB CDC Ethernet class (USB cable modem) support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
    dep_tristate '  USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB-to-USB Networking (NetChip, Prolific, ...) (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB Communication Class Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB-to-USB Networking cable device support (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+fi
 
-   comment 'USB port drivers'
-   dep_tristate '  USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
-   source drivers/usb/serial/Config.in
+comment 'USB port drivers'
+dep_tristate '  USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
+source drivers/usb/serial/Config.in
 
-   comment 'USB misc drivers'
-   dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
-fi
+comment 'USB Miscellaneous drivers'
+dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
 
 endmenu
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/devices.c linux/drivers/usb/devices.c
--- v2.4.12/linux/drivers/usb/devices.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/devices.c	Sat Oct 20 19:13:11 2001
@@ -488,7 +488,7 @@
 		return -EFAULT;
 
 	/* enumerate busses */
-	read_lock_irq (&usb_bus_list_lock);
+	down (&usb_bus_list_lock);
 	for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) {
 		/* print devices for this bus */
 		bus = list_entry(buslist, struct usb_bus, bus_list);
@@ -498,7 +498,7 @@
 			return ret;
 		total_written += ret;
 	}
-	read_unlock_irq (&usb_bus_list_lock);
+	up (&usb_bus_list_lock);
 	return total_written;
 }
 
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/hiddev.c linux/drivers/usb/hiddev.c
--- v2.4.12/linux/drivers/usb/hiddev.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/hiddev.c	Sat Oct 20 19:13:11 2001
@@ -264,7 +264,7 @@
 	if (list->head == list->tail) {
 
 		add_wait_queue(&list->hiddev->wait, &wait);
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 
 		while (list->head == list->tail) {
 
@@ -284,7 +284,7 @@
 			schedule();
 		}
 
-		current->state = TASK_RUNNING;
+		set_current_state(TASK_RUNNING);
 		remove_wait_queue(&list->hiddev->wait, &wait);
 	}
 
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/inode.c linux/drivers/usb/inode.c
--- v2.4.12/linux/drivers/usb/inode.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/inode.c	Sat Oct 20 19:13:11 2001
@@ -260,15 +260,15 @@
         struct list_head *list;
         struct usb_bus *bus;
 
-	read_lock_irq (&usb_bus_list_lock);
+	down (&usb_bus_list_lock);
         for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
                 bus = list_entry(list, struct usb_bus, bus_list);
                 if (bus->busnum == busnr) {
-			read_unlock_irq (&usb_bus_list_lock);
+			up (&usb_bus_list_lock);
                         return bus;
 		}
         }
-	read_unlock_irq (&usb_bus_list_lock);
+	up (&usb_bus_list_lock);
         return NULL;
 }
 
@@ -416,7 +416,7 @@
 		if (i < 2+NRSPECIAL)
 			return 0;
 		i -= 2+NRSPECIAL;
-		read_lock_irq (&usb_bus_list_lock);
+		down (&usb_bus_list_lock);
 		for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
 			if (i > 0) {
 				i--;
@@ -428,7 +428,7 @@
 				break;
 			filp->f_pos++;
 		}
-		read_unlock_irq (&usb_bus_list_lock);
+		up (&usb_bus_list_lock);
 		return 0;
 	}
 }
@@ -639,13 +639,13 @@
 		list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist);
 		list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes);
 	}
-	read_lock_irq (&usb_bus_list_lock);
+	down (&usb_bus_list_lock);
 	for (blist = usb_bus_list.next; blist != &usb_bus_list; blist = blist->next) {
 		bus = list_entry(blist, struct usb_bus, bus_list);
 		new_bus_inode(bus, s);
 		recurse_new_dev_inode(bus->root_hub, s);
 	}
-	read_unlock_irq (&usb_bus_list_lock);
+	up (&usb_bus_list_lock);
         return s;
 
  out_no_root:
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/kaweth.c linux/drivers/usb/kaweth.c
--- v2.4.12/linux/drivers/usb/kaweth.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/usb/kaweth.c	Sat Oct 20 19:13:11 2001
@@ -969,14 +969,14 @@
         init_waitqueue_head(&awd.wqh);
         awd.done = 0;
         
-        current->state = TASK_INTERRUPTIBLE;
+        set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&awd.wqh, &wait);
         urb->context = &awd;
         status = usb_submit_urb(urb);
         if (status) {
                 // something went wrong
                 usb_free_urb(urb);
-                current->state = TASK_RUNNING;
+                set_current_state(TASK_RUNNING);
                 remove_wait_queue(&awd.wqh, &wait);
                 return status;
         }
@@ -984,7 +984,7 @@
 	while (timeout && !awd.done)
 		timeout = schedule_timeout(timeout);
 
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         remove_wait_queue(&awd.wqh, &wait);
 
         if (!timeout) {
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/pegasus.h linux/drivers/usb/pegasus.h
--- v2.4.12/linux/drivers/usb/pegasus.h	Tue Oct  9 17:06:52 2001
+++ linux/drivers/usb/pegasus.h	Wed Oct 17 14:34:06 2001
@@ -131,6 +131,8 @@
 #define	VENDOR_ABOCOM		0x07b8
 #define	VENDOR_ACCTON		0x083a
 #define	VENDOR_ADMTEK		0x07a6
+#define	VENDOR_ALLIEDTEL	0x07c9
+#define	VENDOR_BELKIN		0x050d
 #define	VENDOR_BILLIONTON	0x08dd
 #define	VENDOR_COREGA		0x07aa
 #define	VENDOR_DLINK		0x2001
@@ -142,7 +144,7 @@
 #define	VENDOR_SMARTBRIDGES	0x08d1
 #define	VENDOR_SMC		0x0707
 #define	VENDOR_SOHOWARE		0x15e8
-#define	VENDOR_BELKIN		0x050d
+
 
 #else	/* PEGASUS_DEV */
 
@@ -176,6 +178,10 @@
 PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)",
 		VENDOR_ADMTEK, 0x0986,
 		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
@@ -236,8 +242,6 @@
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
 		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Belkin F5D5050 USB Ethernet",
-		VENDOR_BELKIN, 0x0121,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
+
 
 #endif	/* PEGASUS_DEV */
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/pwc-ctrl.c linux/drivers/usb/pwc-ctrl.c
--- v2.4.12/linux/drivers/usb/pwc-ctrl.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/pwc-ctrl.c	Wed Oct 17 14:34:06 2001
@@ -495,7 +495,7 @@
 }
 
 
-#ifdef __KERNEL__
+
 /* BRIGHTNESS */
 
 int pwc_get_brightness(struct pwc_device *pdev)
@@ -983,6 +983,7 @@
 	
 	return (buf << 8);
 }
+
 static inline int pwc_read_blue_gain(struct pwc_device *pdev)
 {
 	unsigned char buf;
@@ -1001,43 +1002,55 @@
 	return (buf << 8);
 }
 
-/* still unused (it doesn't work yet...) */
-static inline int pwc_set_led(struct pwc_device *pdev, int value)
+int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
 {
-	unsigned char buf;
+	unsigned char buf[2];
 
-	if (value < 0)
-		value = 0;
-	if (value > 0xffff)
-		value = 0xffff;
+	if (pdev->type < 730)
+		return 0;
+	if (on_value < 0)
+		on_value = 0;
+	if (on_value > 0xff)
+		on_value = 0xff;
+	if (off_value < 0)
+		off_value = 0;
+	if (off_value > 0xff)
+		off_value = 0xff;
 
-	buf = (value >> 8);
+	buf[0] = on_value;
+	buf[1] = off_value;
 
 	return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
 		SET_STATUS_CTL,
 		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 		LED_FORMATTER,
 		pdev->vcinterface,
-		&buf, 1, HZ / 2);
+		&buf, 2, HZ / 2);
 }
 
-/* still unused (it doesn't work yet...) */
-static inline int pwc_get_led(struct pwc_device *pdev)
+int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
 {
-	unsigned char buf;
+	unsigned char buf[2];
 	int ret;
 	
+	if (pdev->type < 730) {
+		*on_value = -1;
+		*off_value = -1;
+		return 0;
+	}
+
 	ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
    	        GET_STATUS_CTL,
 		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 		LED_FORMATTER,
 		pdev->vcinterface,
-		&buf, 1, HZ / 2);
+		&buf, 2, HZ / 2);
 
 	if (ret < 0)
-	    return ret;
-	
-	return (buf << 8);
+		return ret;
+	*on_value = buf[0];
+	*off_value = buf[1];
+	return 0;
 }
 
  /* End of Add-Ons                                    */
@@ -1167,15 +1180,15 @@
 
         case VIDIOCPWCSLED:
 	{
-	    int led, ret;
-	    if (copy_from_user(&led,arg,sizeof(led)))
-		return -EFAULT;
-	    else {
-		/* ret = pwc_set_led(pdev, led); */
-		ret = 0;
+		int ret;
+		struct pwc_leds leds;
+
+		if (copy_from_user(&leds, arg, sizeof(leds)))
+			return -EFAULT;
+
+		ret = pwc_set_leds(pdev, leds.led_on, leds.led_off);
 		if (ret<0)
 		    return ret;
-	    }
 	    break;
 	}
 
@@ -1184,11 +1197,12 @@
 	case VIDIOCPWCGLED:
 	{
 		int led;
+		struct pwc_leds leds;
 		
-		led = pwc_get_led(pdev); 
+		led = pwc_get_leds(pdev, &leds.led_on, &leds.led_off); 
 		if (led < 0)
 			return -EINVAL;
-		if (copy_to_user(arg, &led, sizeof(led)))
+		if (copy_to_user(arg, &leds, sizeof(leds)))
 			return -EFAULT;
 		break;
 	}
@@ -1202,9 +1216,6 @@
 	}
 	return 0;
 }
-
-#endif
-
 
 
 
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/pwc-if.c linux/drivers/usb/pwc-if.c
--- v2.4.12/linux/drivers/usb/pwc-if.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/pwc-if.c	Wed Oct 17 14:34:06 2001
@@ -73,7 +73,9 @@
 	{ USB_DEVICE(0x0471, 0x0311) },
 	{ USB_DEVICE(0x0471, 0x0312) },
 	{ USB_DEVICE(0x069A, 0x0001) },
-	{ USB_DEVICE(0x046D, 0x0b80) },
+	{ USB_DEVICE(0x046D, 0x08b0) },
+	{ USB_DEVICE(0x055D, 0x9000) },
+	{ USB_DEVICE(0x055D, 0x9001) },
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, pwc_device_table);
@@ -96,6 +98,7 @@
 static int default_mbufs = 2;	/* Default number of mmap() buffers */
        int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
 static int power_save = 0;
+static int led_on = 1, led_off = 0; /* defaults to LED that is on while in use */
 int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
 
 static struct semaphore mem_lock;
@@ -592,7 +595,8 @@
 	pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
 }
 
-/* XXX: 2001-06-17: The YUV420 palette will be phased out soon */
+/* 2001-10-14: The YUV420 is still there, but you can only set it from within 
+   a program (YUV420P being the default) */
 static int pwc_set_palette(struct pwc_device *pdev, int pal)
 {
 	if (   pal == VIDEO_PALETTE_YUV420
@@ -947,14 +951,16 @@
 			Info("Failed to set alternate interface to 0.\n");
 		pdev->usb_init = 1;
 	}
-	else {
-		/* Turn on camera */
-		if (power_save) {
-			i = pwc_camera_power(pdev, 1);
-			if (i < 0)
-				Info("Failed to restore power to the camera! (%d)\n", i);
-		}
+
+	/* Turn on camera */
+	if (power_save) {
+		i = pwc_camera_power(pdev, 1);
+		if (i < 0)
+			Info("Failed to restore power to the camera! (%d)\n", i);
 	}
+	/* Set LED on/off time */
+	if (pwc_set_leds(pdev, led_on, led_off) < 0)
+		Info("Failed to set LED on/off time.\n");
 
 	/* Find our decompressor, if any */
 	pdev->decompressor = pwc_find_decompressor(pdev->type);
@@ -1007,6 +1013,7 @@
 		up(&pdev->modlock);
 		return i;
 	}
+	
 	i = usb_set_interface(pdev->udev, 0, pdev->valternate);
 	if (i) {
 		Trace(TRACE_OPEN, "Failed to set alternate interface = %d.\n", i);
@@ -1066,7 +1073,10 @@
 		Trace(TRACE_OPEN, "Normal close(): setting interface to 0.\n");
 		usb_set_interface(pdev->udev, 0, 0);
 
-		/* Turn off LED by powering down camera */
+		/* Turn LEDs off */
+		if (pwc_set_leds(pdev, 0, 0) < 0)
+			Info("Failed to set LED on/off time..\n");
+		/* Power down camere to save energy */
 		if (power_save) {
 			i = pwc_camera_power(pdev, 0);
 			if (i < 0) 
@@ -1121,19 +1131,19 @@
 		while (pdev->full_frames == NULL) {
 	                if (noblock) {
 	                	remove_wait_queue(&pdev->frameq, &wait);
-	                	current->state = TASK_RUNNING;
+	                	set_current_state(TASK_RUNNING);
 	                	return -EWOULDBLOCK;
 	                }
 	                if (signal_pending(current)) {
 	                	remove_wait_queue(&pdev->frameq, &wait);
-	                	current->state = TASK_RUNNING;
+	                	set_current_state(TASK_RUNNING);
 	                	return -ERESTARTSYS;
 	                }
 	                schedule();
-	                current->state = TASK_INTERRUPTIBLE;
+	                set_current_state(TASK_INTERRUPTIBLE);
 		}
 		remove_wait_queue(&pdev->frameq, &wait);
-		current->state = TASK_RUNNING;
+		set_current_state(TASK_RUNNING);
 	                                                                                                                                                                                
 		/* Decompress [, convert] and release frame */
 		if (pwc_handle_frame(pdev))
@@ -1473,14 +1483,14 @@
 			while (pdev->full_frames == NULL) {
 	                	if (signal_pending(current)) {
 	                		remove_wait_queue(&pdev->frameq, &wait);
-		                	current->state = TASK_RUNNING;
+		                	set_current_state(TASK_RUNNING);
 		                	return -ERESTARTSYS;
 	        	        }
 	                	schedule();
-		                current->state = TASK_INTERRUPTIBLE;
+		                set_current_state(TASK_INTERRUPTIBLE);
 			}
 			remove_wait_queue(&pdev->frameq, &wait);
-			current->state = TASK_RUNNING;
+			set_current_state(TASK_RUNNING);
 				
 			/* The frame is ready. Expand in the image buffer 
 			   requested by the user. I don't care if you 
@@ -1656,18 +1666,37 @@
 			break;
 		}
 	}
-        else if (vendor_id == 0x046d) {
-        	switch(product_id) {
-        	case 0x08b0:
-        		Info("Logitech QuickCam 3000 Pro detected.\n");
-        		type_id = 730;
+	else if (vendor_id == 0x046d) {
+		switch(product_id) {
+		case 0x08b0:
+			Info("Logitech QuickCam 3000 Pro detected.\n");
+			type_id = 730;
         		break;
         	default:
         		return NULL;
         		break;
         	}
         }
-        else return NULL; /* Not Philips or Askey, for sure. */
+	else if (vendor_id == 0x055d) {
+		/* I don't know the difference between the C10 and the C30;
+		   I suppose the difference is the sensor, but both cameras
+		   work equally well with a type_id of 675
+		 */
+		switch(product_id) {
+		case 0x9000:
+			Info("Samsung MPC-C10 USB webcam detected.\n");
+			type_id = 675;
+			break;
+		case 0x9001:
+			Info("Samsung MPC-C30 USB webcam detected.\n");
+			type_id = 675;
+			break;
+		default:
+			return NULL;
+			break;
+		}
+	}
+	else return NULL; /* Not Philips, Askey, Logitech or Samsung, for sure. */
 
 	if (udev->descriptor.bNumConfigurations > 1)
 		Info("Warning: more than 1 configuration available.\n");
@@ -1799,19 +1828,17 @@
 
 static char *size = NULL;
 static int fps = 0;
-static char *palette = NULL;
 static int fbufs = 0;
 static int mbufs = 0;
 static int trace = -1;
 static int compression = -1;
+static int leds[2] = { -1, -1 };
 
 MODULE_PARM(video_nr, "i");
 MODULE_PARM(size, "s");
 MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
 MODULE_PARM(fps, "i");
 MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
-MODULE_PARM(palette, "s");
-MODULE_PARM_DESC(palette, "Initial colour format of images. One of yuv420, yuv420p");
 MODULE_PARM(fbufs, "i");
 MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
 MODULE_PARM(mbufs, "i");
@@ -1822,7 +1849,8 @@
 MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
 MODULE_PARM(compression, "i");
 MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
-
+MODULE_PARM(leds, "2i");
+MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
 MODULE_DESCRIPTION("Philips USB webcam driver");
 MODULE_AUTHOR("Nemosoft Unv. <nemosoft@smcc.demon.nl>");
 MODULE_LICENSE("GPL");
@@ -1833,7 +1861,7 @@
 	char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
 
 	Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740/750 webcam module version " PWC_VERSION " loaded.\n");
-	Info("Also supports Askey VC010 cam.\n");
+	Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro and the Samsung MPC-C10 and MPC-C30.\n");
 
 	if (fps) {
 		if (fps < 5 || fps > 30) {
@@ -1858,18 +1886,6 @@
 		}
 		Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
 	}
-	if (palette) {
-		/* Determine default palette */
-		if (!strcmp(palette, "yuv420"))
-			default_palette = VIDEO_PALETTE_YUV420;
-		else if (!strcmp(palette, "yuv420p"))
-			default_palette = VIDEO_PALETTE_YUV420P;
-		else {
-			Err("Palette not recognized: try palette=yuv420 or yuv420p.\n");
-			return -EINVAL;
-		}
-		Info("Default palette set to %d.\n", default_palette);
-	}
 	if (mbufs) {
 		if (mbufs < 1 || mbufs > MAX_IMAGES) {
 			Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
@@ -1900,6 +1916,10 @@
 	}
 	if (power_save)
 		Info("Enabling power save on open/close.\n");
+	if (leds[0] >= 0)
+		led_on = leds[0] / 100;
+	if (leds[1] >= 0)
+		led_off = leds[1] / 100;
 
 	init_MUTEX(&mem_lock);
  	Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/pwc-ioctl.h linux/drivers/usb/pwc-ioctl.h
--- v2.4.12/linux/drivers/usb/pwc-ioctl.h	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/pwc-ioctl.h	Wed Oct 17 14:34:06 2001
@@ -76,6 +76,15 @@
 };
 
 
+/* Used with VIDIOCPWC[SG]LED */
+struct pwc_leds
+{
+	int led_on;			/* Led on-time; range = 0..255 */
+	int led_off;			/*  */
+};
+
+
+
  /* Restore user settings */
 #define VIDIOCPWCRUSER		_IO('v', 192)
  /* Save user settings */
@@ -107,9 +116,8 @@
 #define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
 
  /* Turn LED on/off ; int range 0..65535 */
-#define VIDIOCPWCSLED           _IOW('v', 205, int)
-
+#define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
  /* Get state of LED; int range 0..65535 */
-#define VIDIOCPWCGLED           _IOR('v', 205, int)
+#define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
 
 #endif
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/pwc.h linux/drivers/usb/pwc.h
--- v2.4.12/linux/drivers/usb/pwc.h	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/pwc.h	Wed Oct 17 14:34:06 2001
@@ -60,8 +60,8 @@
 
 /* Version block */
 #define PWC_MAJOR	8
-#define PWC_MINOR	2
-#define PWC_VERSION 	"8.2"
+#define PWC_MINOR	3
+#define PWC_VERSION 	"8.3"
 #define PWC_NAME 	"pwc"
 
 /* Turn certain features on/off */
@@ -245,6 +245,8 @@
 extern int pwc_set_gamma(struct pwc_device *pdev, int value);
 extern int pwc_get_saturation(struct pwc_device *pdev);
 extern int pwc_set_saturation(struct pwc_device *pdev, int value);
+extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
+extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value);
 
 /* Power down or up the camera; not supported by all models */
 extern int pwc_camera_power(struct pwc_device *pdev, int power);
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- v2.4.12/linux/drivers/usb/scanner.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/scanner.c	Sat Oct 20 19:13:11 2001
@@ -1,9 +1,9 @@
 /* -*- linux-c -*- */
 
 /* 
- * Driver for USB Scanners (linux-2.4.0)
+ * Driver for USB Scanners (linux-2.4.12)
  *
- * Copyright (C) 1999, 2000 David E. Nelson
+ * Copyright (C) 1999, 2000, 2001 David E. Nelson
  *
  * Portions may be copyright Brad Keryan and Michael Gee.
  *
@@ -226,13 +226,59 @@
  *      read_timeout.  Thanks to Mark W. Webb <markwebb@adelphia.net> for
  *      reporting this bug.
  *    - Added Epson Perfection 1640SU and 1640SU Photo.  Thanks to
- *      Jean-Luc <f5ibh@db0bm.ampr.org>.
+ *      Jean-Luc <f5ibh@db0bm.ampr.org> and Manuel
+ *      Pelayo <Manuel.Pelayo@sesips.org>. Reported to work fine by Manuel.
  *
- * 0.4.6 08/16/2001 Yves Duret <yduret@mandrakesoft.com>
- *    - added devfs support (from printer.c)
- *
- *  TODO
+ * 0.4.6  9/27/2001
+ *    - Added IOCTL's to report back scanner USB ID's.  Thanks to
+ *      Karl Heinz <khk@lynx.phpwebhosting.com>
+ *    - Added Umax Astra 2100U ID's.  Thanks to Ron
+ *      Wellsted <ron@wellsted.org.uk>.
+ *      and Manuel Pelayo <Manuel.Pelayo@sesips.org>.
+ *    - Added HP 3400 ID's. Thanks to Harald Hannelius <harald@iki.fi>
+ *      and Bertrik Sikken <bertrik@zonnet.nl>.  Reported to work at
+ *      htpp://home.zonnet.nl/bertrik/hp3300c/hp3300c.htm.
+ *    - Added Minolta Dimage Scan Dual II ID's.  Thanks to Jose Paulo
+ *      Moitinho de Almeida <moitinho@civil.ist.utl.pt>
+ *    - Confirmed addition for SnapScan E20.  Thanks to Steffen Hübner
+ *      <hueb_s@gmx.de>.
+ *    - Added Lifetec LT9385 ID's.  Thanks to Van Bruwaene Kris
+ *      <krvbr@yahoo.co.uk>
+ *    - Added Agfa SnapScan e26 ID's.  Reported to work with SANE
+ *      1.0.5.  Thanks to Falk Sauer <falk@mgnkatze.franken.de>.
+ *    - Added HP 4300 ID's.  Thanks to Stefan Schlosser
+ *      <castla@grmmbl.org>.
+ *    - Added Relisis Episode ID's.  Thanks to Manfred
+ *      Morgner <odb-devel@gmx.net>.
+ *    - Added many Acer ID's. Thanks to Oliver
+ *      Schwartz <Oliver.Schwartz@gmx.de>.
+ *    - Added Snapscan e40 ID's.  Thanks to Oliver
+ *      Schwartz <Oliver.Schwartz@gmx.de>.
+ *    - Thanks to Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
+ *      for helping with races.
+ *    - Added Epson Perfection 1650 ID's. Thanks to Karl Heinz
+ *      Kremer <khk@khk.net>.
+ *    - Added Epson Perfection 2450 ID's (aka GT-9700 for the Japanese
+ *      market).  Thanks to Karl Heinz Kremer <khk@khk.net>.
+ *    - Added Mustek 600 USB ID's.  Thanks to Marcus
+ *      Alanen <maalanen@ra.abo.fi>.
+ *    - Added Acer ScanPrisa 1240UT ID's.  Thanks to Morgan
+ *      Collins <sirmorcant@morcant.org>.
+ *    - Incorporated devfs patches!! Thanks to Tom Rini
+ *      <trini@kernel.crashing.org>, Pavel Roskin <proski@gnu.org>,
+ *      Greg KH <greg@kroah.com>, Yves Duret <yduret@mandrakesoft.com>,
+ *      Flavio Stanchina <flavio.stanchina@tin.it>.
+ *    - Removed Minolta ScanImage II.  This scanner uses USB SCSI.  Thanks
+ *      to Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de> for pointing
+ *      this out.
+ *    - Added additional SMP locking.  Thanks to David Brownell and 
+ *      Oliver Neukum for their help.
+ *    - Added version reporting - reports for both module load and modinfo
+ *    - Started path to hopefully straighten/clean out ioctl()'s.
+ *    - Users are now notified to consult the Documentation/usb/scanner.txt
+ *      for common error messages rather than the maintainer.
  *
+ * TODO
  *    - Performance
  *    - Select/poll methods
  *    - More testing
@@ -266,7 +312,6 @@
  */ 
 #include "scanner.h"
 
-
 static void
 irq_scanner(struct urb *urb)
 {
@@ -276,19 +321,23 @@
  * all I want to do with it -- or somebody else for that matter.
  */
 
-	struct scn_usb_data *scn = urb->context;
-	unsigned char *data = &scn->button;
+	struct scn_usb_data *scn;
+	unsigned char *data;
+	scn = urb->context;
+	down(&(scn->sem));
+	data = &scn->button;
 	data += 0;		/* Keep gcc from complaining about unused var */
 
 	if (urb->status) {
+		up(&(scn->sem));
 		return;
 	}
 
 	dbg("irq_scanner(%d): data:%x", scn->scn_minor, *data);
+	up(&(scn->sem));
 	return;
 }
 
-
 static int
 open_scanner(struct inode * inode, struct file * file)
 {
@@ -299,22 +348,28 @@
 
 	int err=0;
 
-	lock_kernel();
+	MOD_INC_USE_COUNT;
+
+	down(&scn_mutex);
 
 	scn_minor = USB_SCN_MINOR(inode);
 
 	dbg("open_scanner: scn_minor:%d", scn_minor);
 
 	if (!p_scn_table[scn_minor]) {
+		up(&scn_mutex);
 		err("open_scanner(%d): Unable to access minor data", scn_minor);
-		err = -ENODEV;
-		goto out_error;
+		return -ENODEV;
 	}
 
 	scn = p_scn_table[scn_minor];
 
 	dev = scn->scn_dev;
 
+	down(&(scn->sem));	/* Now protect the scn_usb_data structure */ 
+
+	up(&scn_mutex); /* Now handled by the above */
+
 	if (!dev) {
 		err("open_scanner(%d): Scanner device not present", scn_minor);
 		err = -ENODEV;
@@ -337,13 +392,15 @@
 
 	scn->isopen = 1;
 
-	file->private_data = scn; /* Used by the read and write metheds */
+	file->private_data = scn; /* Used by the read and write methods */
 
-	MOD_INC_USE_COUNT;
 
 out_error:
 
-	unlock_kernel();
+	up(&(scn->sem)); /* Wake up any possible contending processes */
+
+	if (err)
+		MOD_DEC_USE_COUNT;
 
 	return err;
 }
@@ -364,12 +421,17 @@
 		return -ENODEV;
 	}
 
-	scn = p_scn_table[scn_minor];
+	down(&scn_mutex);
 
+	scn = p_scn_table[scn_minor];
+	down(&(scn->sem));
 	scn->isopen = 0;
 
 	file->private_data = NULL;
 
+	up(&scn_mutex);
+	up(&(scn->sem));
+
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -395,6 +457,8 @@
 
 	scn = file->private_data;
 
+	down(&(scn->sem));
+
 	scn_minor = scn->scn_minor;
 
 	obuf = scn->obuf;
@@ -403,12 +467,10 @@
 
 	file->f_dentry->d_inode->i_atime = CURRENT_TIME;
 
-	down(&(scn->gen_lock));
-
 	while (count > 0) {
 
 		if (signal_pending(current)) {
-			ret = -EINTR;
+			ret = -ERESTARTSYS;
 			break;
 		}
 
@@ -427,7 +489,7 @@
 			ret = result;
 			break;
 		} else if (result < 0) { /* We should not get any I/O errors */
-			warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn_minor, result);
+			warn("write_scanner(%d): funky result: %d. Consult Documentataion/usb/scanner.txt.", scn_minor, result);
 			ret = -EIO;
 			break;
 		}
@@ -457,7 +519,7 @@
 			break;
 		}
 	}
-	up(&(scn->gen_lock));
+	up(&(scn->sem));
 	mdelay(5);		/* This seems to help with SANE queries */
 	return ret ? ret : bytes_written;
 }
@@ -483,6 +545,8 @@
 
 	scn = file->private_data;
 
+	down(&(scn->sem));
+
 	scn_minor = scn->scn_minor;
 
 	ibuf = scn->ibuf;
@@ -496,11 +560,9 @@
                                                             atime of
                                                             the device
                                                             node */
-	down(&(scn->gen_lock));
-
 	while (count > 0) {
 		if (signal_pending(current)) {
-			ret = -EINTR;
+			ret = -ERESTARTSYS;
 			break;
 		}
 
@@ -545,7 +607,7 @@
 			ret = result;
 			break;
 		} else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {
-			warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn_minor, (int)result);
+			warn("read_scanner(%d): funky result:%d. Consult Documentation/usb/scanner.txt.", scn_minor, (int)result);
 			ret = -EIO;
 			break;
 		}
@@ -577,20 +639,16 @@
 			break;
 		}
 	}
-	up(&(scn->gen_lock));
-
+	up(&(scn->sem));
 	return ret ? ret : bytes_read;
 }
 
-#ifdef SCN_IOCTL
 static int
 ioctl_scanner(struct inode *inode, struct file *file,
 	      unsigned int cmd, unsigned long arg)
 {
 	struct usb_device *dev;
 
-	int result;
-
 	kdev_t scn_minor;
 
 	scn_minor = USB_SCN_MINOR(inode);
@@ -604,12 +662,15 @@
 
 	switch (cmd)
 	{
-	case IOCTL_SCANNER_VENDOR :
+	case SCANNER_IOCTL_VENDOR :
 		return (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
-	case IOCTL_SCANNER_PRODUCT :
+	case SCANNER_IOCTL_PRODUCT :
 		return (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
+#ifdef PV8630
 	case PV8630_IOCTL_INREQUEST :
 	{
+		int result;
+
 		struct {
 			__u8  data;
 			__u8  request;
@@ -637,6 +698,8 @@
 	}
 	case PV8630_IOCTL_OUTREQUEST :
 	{
+		int result;
+
 		struct {
 			__u8  request;
 			__u16 value;
@@ -658,20 +721,59 @@
 
 		return result;
 	}
+#endif /* PV8630 */
+ 	case SCANNER_IOCTL_CTRLMSG:
+ 	{
+ 		struct ctrlmsg_ioctl {
+ 			devrequest	req;
+ 			void		*data;
+ 		} cmsg;
+ 		int pipe, nb, ret;
+ 		unsigned char buf[64];
+ 
+ 		if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg)))
+ 			return -EFAULT;
+
+ 		nb = le16_to_cpup(&cmsg.req.length);
+
+ 		if (nb > sizeof(buf))
+ 			return -EINVAL;
+
+ 		if ((cmsg.req.requesttype & 0x80) == 0) {
+ 			pipe = usb_sndctrlpipe(dev, 0);
+ 			if (nb > 0 && copy_from_user(buf, cmsg.data, nb))
+ 				return -EFAULT;
+ 		} else {
+ 			pipe = usb_rcvctrlpipe(dev, 0);
+		}
+
+ 		ret = usb_control_msg(dev, pipe, cmsg.req.request,
+ 				      cmsg.req.requesttype,
+ 				      le16_to_cpup(&cmsg.req.value),
+ 				      le16_to_cpup(&cmsg.req.index),
+ 				      buf, nb, HZ);
+
+ 		if (ret < 0) {
+ 			err("ioctl_scanner(%d): control_msg returned %d\n", scn_minor, ret);
+ 			return -EIO;
+ 		}
+
+ 		if (nb > 0 && (cmsg.req.requesttype & 0x80) && copy_to_user(cmsg.data, buf, nb))
+ 			return -EFAULT;
+
+ 		return 0;
+ 	}
 	default:
 		return -ENOTTY;
 	}
 	return 0;
 }
-#endif /* SCN_IOCTL */
 
 static struct
 file_operations usb_scanner_fops = {
 	read:		read_scanner,
 	write:		write_scanner,
-#ifdef SCN_IOCTL
 	ioctl:		ioctl_scanner,
-#endif /* SCN_IOCTL */
 	open:		open_scanner,
 	release:	close_scanner,
 };
@@ -691,6 +793,7 @@
 
 	char valid_device = 0;
 	char have_bulk_in, have_bulk_out, have_intr;
+	char name[10];
 
 	if (vendor != -1 && product != -1) {
 		info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
@@ -791,7 +894,7 @@
 			dbg("probe_scanner: intr_ep:%d", have_intr);
 			continue;
 		}
-		info("probe_scanner: Undetected endpoint. Notify the maintainer.");
+		info("probe_scanner: Undetected endpoint -- consult Documentation/usb/scanner.txt.");
 		return NULL;	/* Shouldn't ever get here unless we have something weird */
 	}
 
@@ -815,7 +918,7 @@
 		}
 		break;
 	default:
-		info("probe_scanner: Endpoint determination failed.  Notify the maintainer.");
+		info("probe_scanner: Endpoint determination failed --  consult Documentation/usb/scanner.txt");
 		return NULL;
 	}
 
@@ -825,6 +928,8 @@
  * with it.  The problem with this is that we are counting on the fact
  * that the user will sequentially add device nodes for the scanner
  * devices.  */
+	
+	down(&scn_mutex);
 
 	for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {
 		if (!p_scn_table[scn_minor])
@@ -844,8 +949,10 @@
 		return NULL;
 	}
 	memset (scn, 0, sizeof(struct scn_usb_data));
-	dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
 
+	init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
+
+	dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
 
 /* Ok, if we detected an interrupt EP, setup a handler for it */
 	if (have_intr) {
@@ -859,6 +966,7 @@
 	        if (usb_submit_urb(&scn->scn_irq)) {
 			err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
                 	kfree(scn);
+			up(&scn_mutex);
                 	return NULL;
         	}
 	}
@@ -868,6 +976,7 @@
 	if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
 		err("probe_scanner(%d): Not enough memory for the output buffer.", scn_minor);
 		kfree(scn);
+		up(&scn_mutex);
 		return NULL;
 	}
 	dbg("probe_scanner(%d): obuf address:%p", scn_minor, scn->obuf);
@@ -876,6 +985,7 @@
 		err("probe_scanner(%d): Not enough memory for the input buffer.", scn_minor);
 		kfree(scn->obuf);
 		kfree(scn);
+		up(&scn_mutex);
 		return NULL;
 	}
 	dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf);
@@ -908,15 +1018,17 @@
 	scn->scn_minor = scn_minor;
 	scn->isopen = 0;
 
-	init_MUTEX(&(scn->gen_lock));
-
-	/* if we have devfs, create with perms=660 */
-	scn->devfs = devfs_register(usb_devfs_handle, "scanner",
-				      DEVFS_FL_DEFAULT, USB_MAJOR,
-				      SCN_BASE_MNR + scn_minor,
-				      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
-				      S_IWGRP, &usb_scanner_fops, NULL);
+	sprintf(name, "scanner%d", scn->scn_minor);
+	
+	scn->devfs = devfs_register(usb_devfs_handle, name,
+				    DEVFS_FL_DEFAULT, USB_MAJOR,
+				    SCN_BASE_MNR + scn->scn_minor,
+				    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
+				    S_IWGRP | S_IROTH | S_IWOTH, &usb_scanner_fops, NULL);
+	if (scn->devfs == NULL)
+		dbg("scanner%d: device node registration failed", scn_minor);
 
+	up(&scn_mutex);
 
 	return p_scn_table[scn_minor] = scn;
 }
@@ -926,6 +1038,9 @@
 {
 	struct scn_usb_data *scn = (struct scn_usb_data *) ptr;
 
+	down (&scn_mutex);
+	down (&(scn->sem));
+
 	if(scn->intr_ep) {
 		dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor);
 		usb_unlink_urb(&scn->scn_irq);
@@ -933,17 +1048,17 @@
         usb_driver_release_interface(&scanner_driver,
                 &scn->scn_dev->actconfig->interface[scn->ifnum]);
 
-	devfs_unregister (scn->devfs);
-
 	kfree(scn->ibuf);
 	kfree(scn->obuf);
 
 	dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
+	devfs_unregister(scn->devfs);
 	p_scn_table[scn->scn_minor] = NULL;
+	up (&(scn->sem));
 	kfree (scn);
+	up (&scn_mutex);
 }
 
-
 static struct
 usb_driver scanner_driver = {
 	name:		"usbscanner",
@@ -968,7 +1083,7 @@
         if (usb_register(&scanner_driver) < 0)
                 return -1;
 
-	info("USB Scanner support registered.");
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/scanner.h linux/drivers/usb/scanner.h
--- v2.4.12/linux/drivers/usb/scanner.h	Tue Oct  9 17:06:52 2001
+++ linux/drivers/usb/scanner.h	Sat Oct 20 19:13:11 2001
@@ -1,12 +1,10 @@
 /*
- * Driver for USB Scanners (linux-2.4.0)
+ * Driver for USB Scanners (linux-2.4.12)
  *
- * Copyright (C) 1999, 2000 David E. Nelson
+ * Copyright (C) 1999, 2000, 2001 David E. Nelson
  *
  * David E. Nelson (dnelson@jump.net)
  *
- * 08/16/2001 added devfs support Yves Duret <yduret@mandrakesoft.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
@@ -37,12 +35,21 @@
 
 // #define DEBUG
 
+/* Enable this to support the older ioctl interfaces scanners that
+ * a PV8630 Scanner-On-Chip.  The prefered method is the
+ * SCANNER_IOCTL_CTRLMSG ioctl.
+ */
+// #define PV8630 
+
+#define DRIVER_VERSION "0.4.6"
+#define DRIVER_DESC "USB Scanner Driver"
+
 #include <linux/usb.h>
 
 static __s32 vendor=-1, product=-1, read_timeout=0;
 
 MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");
-MODULE_DESCRIPTION("USB Scanner Driver");
+MODULE_DESCRIPTION(DRIVER_DESC" "DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(vendor, "i");
@@ -55,10 +62,6 @@
 MODULE_PARM_DESC(read_timeout, "User specified read timeout in seconds");
 
 
-/* Enable to activate the ioctl interface.  This is mainly meant for */
-/* development purposes until an ioctl number is officially registered */
-#define SCN_IOCTL
-
 /* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
 // #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
 // #define WR_DATA_DUMP /* DEBUG does not have to be defined. */
@@ -69,26 +72,42 @@
 	{ USB_DEVICE(0x04a5, 0x2040) },	/* Prisa AcerScan 620U (!) */
 	{ USB_DEVICE(0x04a5, 0x20c0) },  /* Prisa AcerScan 1240UT */
 	{ USB_DEVICE(0x04a5, 0x2022) },	/* Vuego Scan Brisa 340U */
+	{ USB_DEVICE(0x04a5, 0x1a20) },	/* Unknown - Oliver Schwartz */
+	{ USB_DEVICE(0x04a5, 0x1a2a) },	/* Unknown - Oliver Schwartz */
+	{ USB_DEVICE(0x04a5, 0x207e) },	/* Prisa 640BU */
+	{ USB_DEVICE(0x04a5, 0x20be) },	/* Unknown - Oliver Schwartz */
+	{ USB_DEVICE(0x04a5, 0x20c0) },	/* Unknown - Oliver Schwartz */
+	{ USB_DEVICE(0x04a5, 0x20de) },	/* S2W 3300U */
+	{ USB_DEVICE(0x04a5, 0x20b0) },	/* Unknown - Oliver Schwartz */
+	{ USB_DEVICE(0x04a5, 0x20fe) },	/* Unknown - Oliver Schwartz */
 	/* Agfa */
 	{ USB_DEVICE(0x06bd, 0x0001) },	/* SnapScan 1212U */
 	{ USB_DEVICE(0x06bd, 0x0002) },	/* SnapScan 1236U */
 	{ USB_DEVICE(0x06bd, 0x2061) },	/* Another SnapScan 1212U (?)*/
 	{ USB_DEVICE(0x06bd, 0x0100) },	/* SnapScan Touch */
+	{ USB_DEVICE(0x06bd, 0x2091) }, /* SnapScan e20 */
+	{ USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */
+	{ USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */
 	/* Colorado -- See Primax/Colorado below */
 	/* Epson -- See Seiko/Epson below */
 	/* Genius */
 	{ USB_DEVICE(0x0458, 0x2001) },	/* ColorPage-Vivid Pro */
 	/* Hewlett Packard */
 	{ USB_DEVICE(0x03f0, 0x0205) },	/* 3300C */
+	{ USB_DEVICE(0x03f0, 0x0405) }, /* 3400C */
 	{ USB_DEVICE(0x03f0, 0x0101) },	/* 4100C */
 	{ USB_DEVICE(0x03f0, 0x0105) },	/* 4200C */
+	{ USB_DEVICE(0x03f0, 0x0305) }, /* 4300C */
 	{ USB_DEVICE(0x03f0, 0x0102) },	/* PhotoSmart S20 */
 	{ USB_DEVICE(0x03f0, 0x0401) },	/* 5200C */
 	//	{ USB_DEVICE(0x03f0, 0x0701) },	/* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */
 	{ USB_DEVICE(0x03f0, 0x0201) },	/* 6200C */
 	{ USB_DEVICE(0x03f0, 0x0601) },	/* 6300C */
+	{ USB_DEVICE(0x03f0, 0x605) },	/* 2200C */
 	/* iVina */
-	{ USB_DEVICE(0x0638, 0x0268) },     /* 1200U */
+	{ USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
+	/* Lifetec */
+	{ USB_DEVICE(0x05d8, 0x4002) }, /* Lifetec LT9385 */
 	/* Microtek -- No longer supported - Enable SCSI and USB Microtek in kernel config */
 	//	{ USB_DEVICE(0x05da, 0x0099) },	/* ScanMaker X6 - X6U */
 	//	{ USB_DEVICE(0x05da, 0x0094) },	/* Phantom 336CX - C3 */
@@ -97,10 +116,13 @@
 	//	{ USB_DEVICE(0x05da, 0x00a3) },	/* ScanMaker V6USL */
 	//	{ USB_DEVICE(0x05da, 0x80a3) },	/* ScanMaker V6USL #2 */
 	//	{ USB_DEVICE(0x05da, 0x80ac) },	/* ScanMaker V6UL - SpicyU */
+	/* Minolta */
+	//	{ USB_DEVICE(0x0638,0x026a) }, /* Minolta Dimage Scan Dual II */
 	/* Mustek */
 	{ USB_DEVICE(0x055f, 0x0001) },	/* 1200 CU */
 	{ USB_DEVICE(0x0400, 0x1000) },	/* BearPaw 1200 */
 	{ USB_DEVICE(0x055f, 0x0002) },	/* 600 CU */
+	{ USB_DEVICE(0x055f, 0x0873) }, /* 600 USB */
 	{ USB_DEVICE(0x055f, 0x0003) },	/* 1200 USB */
 	{ USB_DEVICE(0x055f, 0x0006) },	/* 1200 UB */
 	{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */
@@ -116,9 +138,11 @@
 	{ USB_DEVICE(0x0461, 0x0303) },	/* G2E-300 #2 */
 	{ USB_DEVICE(0x0461, 0x0383) },	/* G2E-600 */
 	{ USB_DEVICE(0x0461, 0x0340) },	/* Colorado USB 9600 */
-	{ USB_DEVICE(0x0461, 0x0360) },	/* Colorado USB 19200 */
+	// { USB_DEVICE(0x0461, 0x0360) },	/* Colorado USB 19200 - undetected endpoint */
 	{ USB_DEVICE(0x0461, 0x0341) },	/* Colorado 600u */
 	{ USB_DEVICE(0x0461, 0x0361) },	/* Colorado 1200u */
+	/* Relisis */
+	// { USB_DEVICE(0x0475, 0x0103) },	/* Episode - undetected endpoint */
 	/* Seiko/Epson Corp. */
 	{ USB_DEVICE(0x04b8, 0x0101) },	/* Perfection 636U and 636Photo */
 	{ USB_DEVICE(0x04b8, 0x0103) },	/* Perfection 610 */
@@ -129,9 +153,12 @@
 	{ USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
 	{ USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
 	{ USB_DEVICE(0x04b8, 0x010e) }, /* Expression 1680 */
+	{ USB_DEVICE(0x04b8, 0x0110) }, /* Perfection 1650 */
+	{ USB_DEVICE(0x04b8, 0x0112) }, /* Perfection 2450 - GT-9700 for the Japanese mkt */
 	/* Umax */
 	{ USB_DEVICE(0x1606, 0x0010) },	/* Astra 1220U */
 	{ USB_DEVICE(0x1606, 0x0030) },	/* Astra 2000U */
+	{ USB_DEVICE(0x1606, 0x0130) }, /* Astra 2100U */
 	{ USB_DEVICE(0x1606, 0x0230) },	/* Astra 2200U */
 	/* Visioneer */
 	{ USB_DEVICE(0x04a7, 0x0221) },	/* OneTouch 5300 USB */
@@ -167,16 +194,24 @@
 
 
 /* FIXME: These are NOT registered ioctls()'s */
+#ifdef PV8630
 #define PV8630_IOCTL_INREQUEST 69
 #define PV8630_IOCTL_OUTREQUEST 70
+#endif /* PV8630 */
+
+
+/* read vendor and product IDs from the scanner */
+#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
+#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
+/* send/recv a control message to the scanner */
+#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, devrequest )
 
-/* read vendor and product IDs */
-#define IOCTL_SCANNER_VENDOR _IOR('u', 0xa0, int)
-#define IOCTL_SCANNER_PRODUCT _IOR('u', 0xa1, int)
 
 #define SCN_MAX_MNR 16		/* We're allocated 16 minors */
 #define SCN_BASE_MNR 48		/* USB Scanners start at minor 48 */
 
+static DECLARE_MUTEX (scn_mutex); /* Initializes to unlocked */
+
 struct scn_usb_data {
 	struct usb_device *scn_dev;
 	devfs_handle_t devfs;	/* devfs device */
@@ -189,12 +224,12 @@
 	char *obuf, *ibuf;	/* transfer buffers */
 	char bulk_in_ep, bulk_out_ep, intr_ep; /* Endpoint assignments */
 	wait_queue_head_t rd_wait_q; /* read timeouts */
-	struct semaphore gen_lock; /* lock to prevent concurrent reads or writes */
+	struct semaphore sem; /* lock to prevent concurrent reads or writes */
 	unsigned int rd_nak_timeout; /* Seconds to wait before read() timeout. */
 };
 
+extern devfs_handle_t usb_devfs_handle;
+
 static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */};
 
 static struct usb_driver scanner_driver;
-
-extern devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/serial/Config.in linux/drivers/usb/serial/Config.in
--- v2.4.12/linux/drivers/usb/serial/Config.in	Tue Oct  9 17:06:52 2001
+++ linux/drivers/usb/serial/Config.in	Wed Oct 17 14:35:17 2001
@@ -5,36 +5,32 @@
 comment 'USB Serial Converter support'
 
 dep_tristate 'USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
-if [ "$CONFIG_USB_SERIAL" != "n" ]; then
-  if [ "$CONFIG_USB_SERIAL" = "y" ]; then
-     bool '  USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
-  fi
-  bool '  USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC
-  dep_tristate '  USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  dep_tristate '  USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  dep_tristate '  USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
-  dep_tristate '  USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  dep_tristate '  USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  dep_tristate '  USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
-  dep_tristate '  USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  dep_tristate '  USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  dep_tristate '  USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  if [ "$CONFIG_USB_SERIAL_KEYSPAN" != "n" ]; then
-     bool '    USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28
-     bool '    USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X
-     bool '    USB Keyspan USA-28XA Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28XA
-     bool '    USB Keyspan USA-28XB Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28XB
-     bool '    USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19
-     bool '    USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
-     bool '    USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
-     bool '    USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W
-  fi
-  dep_tristate '  USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  dep_tristate '  USB Prolific 2303 Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  dep_tristate '  USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  dep_tristate '  USB Xircom / Entregra Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  dep_tristate '  USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+if [ "$CONFIG_USB_SERIAL" = "y" ]; then
+  dep_mbool '  USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG $CONFIG_USB_SERIAL
 fi
+dep_mbool '  USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC $CONFIG_USB_SERIAL
+dep_tristate '  USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
+dep_tristate '  USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
+dep_tristate '  USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+   dep_mbool '    USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28 $CONFIG_USB_SERIAL_KEYSPAN
+   dep_mbool '    USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X $CONFIG_USB_SERIAL_KEYSPAN
+   dep_mbool '    USB Keyspan USA-28XA Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28XA $CONFIG_USB_SERIAL_KEYSPAN
+   dep_mbool '    USB Keyspan USA-28XB Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28XB $CONFIG_USB_SERIAL_KEYSPAN
+   dep_mbool '    USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19 $CONFIG_USB_SERIAL_KEYSPAN
+   dep_mbool '    USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X $CONFIG_USB_SERIAL_KEYSPAN
+   dep_mbool '    USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W $CONFIG_USB_SERIAL_KEYSPAN
+   dep_mbool '    USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W $CONFIG_USB_SERIAL_KEYSPAN
+dep_tristate '  USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Prolific 2303 Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Xircom / Entregra Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 
 endmenu
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- v2.4.12/linux/drivers/usb/serial/ftdi_sio.c	Thu Oct 11 08:02:26 2001
+++ linux/drivers/usb/serial/ftdi_sio.c	Sat Oct 20 19:13:11 2001
@@ -454,7 +454,7 @@
 		while (port->write_urb->status == -EINPROGRESS) {
 			dbg(__FUNCTION__ " write in progress - retrying");
 			if (signal_pending(current)) {
-				current->state = TASK_RUNNING;
+				set_current_state(TASK_RUNNING);
 				remove_wait_queue(&port->write_wait, &wait);
 				rc = -ERESTARTSYS;
 				goto err;
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.4.12/linux/drivers/usb/uhci.c	Thu Oct 11 08:02:26 2001
+++ linux/drivers/usb/uhci.c	Sat Oct 20 19:13:11 2001
@@ -113,44 +113,6 @@
 
 static int uhci_free_dev(struct usb_device *dev)
 {
-	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
-	struct list_head list, *tmp, *head;
-	unsigned long flags;
-
-	/* Walk through the entire URB list and forcefully remove any */
-	/*  URBs that are still active for that device */
-
-	/* Two stage unlink so we don't deadlock on urb_list_lock */
-	INIT_LIST_HEAD(&list);
-
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *urb = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		if (urb->dev == dev) {
-			list_del(&urb->urb_list);
-			list_add(&urb->urb_list, &list);
-		}
-	}
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-	head = &list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *urb = list_entry(tmp, struct urb, urb_list);
-		tmp = tmp->next;
-
-		/* Make sure we block waiting on these to die */
-		urb->transfer_flags &= ~USB_ASYNC_UNLINK;
-
-		/* uhci_unlink_urb will unlink from the temp list */
-		uhci_unlink_urb(urb);
-	}
-
 	return 0;
 }
 
@@ -159,7 +121,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	uhci->skel_term_td->status |= TD_CTRL_IOC;
+	set_bit(TD_CTRL_IOC_BIT, &uhci->skel_term_td->status);
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
@@ -168,7 +130,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	uhci->skel_term_td->status &= ~TD_CTRL_IOC;
+	clear_bit(TD_CTRL_IOC_BIT, &uhci->skel_term_td->status);
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
@@ -396,50 +358,96 @@
 	pci_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
 
-static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhci_qh *qh)
+static void _uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
 {
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head, *tmp;
 	struct uhci_qh *lqh;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
 	/* Grab the last QH */
 	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
 
-	qh->link = lqh->link;
+	if (lqh->urbp) {
+		head = &lqh->urbp->queue_list;
+		tmp = head->next;
+		while (head != tmp) {
+			struct urb_priv *turbp =
+				list_entry(tmp, struct urb_priv, queue_list);
+
+			tmp = tmp->next;
+
+			turbp->qh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
+		}
+	}
+
+	head = &urbp->queue_list;
+	tmp = head->next;
+	while (head != tmp) {
+		struct urb_priv *turbp =
+			list_entry(tmp, struct urb_priv, queue_list);
+
+		tmp = tmp->next;
+
+		turbp->qh->link = lqh->link;
+	}
+
+	urbp->qh->link = lqh->link;
 	mb();				/* Ordering is important */
-	lqh->link = qh->dma_handle | UHCI_PTR_QH;
+	lqh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
+
+	list_add_tail(&urbp->qh->list, &skelqh->list);
+}
 
-	list_add_tail(&qh->list, &skelqh->list);
+static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
+{
+	unsigned long flags;
 
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	_uhci_insert_qh(uhci, skelqh, urb);
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
-static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
+static void uhci_remove_qh(struct uhci *uhci, struct urb *urb)
 {
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	unsigned long flags;
-	struct uhci_qh *prevqh;
+	struct uhci_qh *qh = urbp->qh, *pqh;
+
+	if (!qh)
+		return;
 
 	/* Only go through the hoops if it's actually linked in */
-	if (list_empty(&qh->list)) {
-		goto list;
-	}
+	if (!list_empty(&qh->list)) {
+		qh->urbp = NULL;
 
-	qh->urbp = NULL;
+		spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
 
-	prevqh = list_entry(qh->list.prev, struct uhci_qh, list);
+		if (pqh->urbp) {
+			struct list_head *head, *tmp;
 
-	prevqh->link = qh->link;
-	mb();
-	qh->element = qh->link = UHCI_PTR_TERM;
+			head = &pqh->urbp->queue_list;
+			tmp = head->next;
+			while (head != tmp) {
+				struct urb_priv *turbp =
+					list_entry(tmp, struct urb_priv, queue_list);
 
-	list_del_init(&qh->list);
+				tmp = tmp->next;
 
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+				turbp->qh->link = qh->link;
+			}
+		}
+
+		pqh->link = qh->link;
+		mb();
+		qh->element = qh->link = UHCI_PTR_TERM;
+
+		list_del_init(&qh->list);
+
+		spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+	}
 
-list:
 	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
 
 	/* Check to see if the remove list is empty. Set the IOC bit */
@@ -464,9 +472,10 @@
 
 		tmp = tmp->next;
 
-		td->info &= ~(1 << TD_TOKEN_TOGGLE);
 		if (toggle)
-			td->info |= (1 << TD_TOKEN_TOGGLE);
+			set_bit(TD_TOKEN_TOGGLE, &td->info);
+		else
+			clear_bit(TD_TOKEN_TOGGLE, &td->info);
 
 		toggle ^= 1;
 	}
@@ -481,7 +490,7 @@
 {
 	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
 	struct list_head *tmp;
-	struct uhci_td *ftd, *lltd;
+	struct uhci_td *lltd;
 	unsigned long flags;
 
 	eurbp = eurb->hcpriv;
@@ -510,13 +519,15 @@
 	lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
 
 	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
-	ftd = list_entry(urbp->td_list.next, struct uhci_td, list);
 
 	uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1);
 
+	/* All qh's in the queue need to link to the next queue */
+	urbp->qh->link = eurbp->qh->link;
+
 	mb();			/* Make sure we flush everything */
 	/* Only support bulk right now, so no depth */
-	lltd->link = ftd->dma_handle;
+	lltd->link = urbp->qh->dma_handle | UHCI_PTR_QH;
 
 	list_add_tail(&urbp->queue_list, &furbp->queue_list);
 
@@ -576,30 +587,9 @@
 		usb_pipeout(urb->pipe), toggle);
 
 	if (!urbp->queued) {
-		int status;
-
-		/*  The HC may continue using the current QH if it finished */
-		/* all of the TD's in this URB and may have started on the */
-		/* next URB's TD's already, so we'll take over ownership */
-		/* of this QH and use it instead. Don't forget to delete */
-		/* the old QH first */
-		uhci_free_qh(uhci, nurbp->qh);
-
-		nurbp->qh = urbp->qh;
-		nurbp->qh->urbp = nurbp;
-		urbp->qh = NULL;
-
-		/* If the last TD from the first (this) urb didn't */
-		/*  complete, reset qh->element to the first TD in the */
-		/*  next urb */
-		pltd = list_entry(urbp->td_list.prev, struct uhci_td, list);
-		status = uhci_status_bits(pltd->status);
-		if ((status & TD_CTRL_ACTIVE) || uhci_actual_length(pltd->status) < uhci_expected_length(pltd->info)) {
-			struct uhci_td *ftd = list_entry(nurbp->td_list.next, struct uhci_td, list);
-			nurbp->qh->element = ftd->dma_handle;
-		}
-
 		nurbp->queued = 0;
+
+		_uhci_insert_qh(uhci, uhci->skel_bulk_qh, nurbp->urb);
 	} else {
 		/* We're somewhere in the middle (or end). A bit trickier */
 		/*  than the head scenario */
@@ -607,15 +597,10 @@
 				queue_list);
 
 		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
-		if (nurbp->queued) {
-			struct uhci_td *nftd;
-
-			/* Close the gap between the two */
-			nftd = list_entry(nurbp->td_list.next, struct uhci_td,
-					list);
-			pltd->link = nftd->dma_handle;
-		} else
-			/* The next URB happens to be the beggining, so */
+		if (nurbp->queued)
+			pltd->link = nurbp->qh->dma_handle | UHCI_PTR_QH;
+		else
+			/* The next URB happens to be the beginning, so */
 			/*  we're the last, end the chain */
 			pltd->link = UHCI_PTR_TERM;
 	}
@@ -639,6 +624,7 @@
 	memset((void *)urbp, 0, sizeof(*urbp));
 
 	urbp->inserttime = jiffies;
+	urbp->fsbrtime = jiffies;
 	urbp->urb = urb;
 	urbp->dev = urb->dev;
 	
@@ -796,7 +782,7 @@
 	if (status & TD_CTRL_NAK)			/* NAK */
 		return -ETIMEDOUT;
 	if (status & TD_CTRL_BABBLE)			/* Babble */
-		return -EPIPE;
+		return -EOVERFLOW;
 	if (status & TD_CTRL_DBUFERR)			/* Buffer error */
 		return -ENOSR;
 	if (status & TD_CTRL_STALLED)			/* Stalled */
@@ -900,19 +886,19 @@
 	if (!qh)
 		return -ENOMEM;
 
+	urbp->qh = qh;
+	qh->urbp = urbp;
+
 	/* Low speed or small transfers gets a different queue and treatment */
 	if (urb->pipe & TD_CTRL_LS) {
 		uhci_insert_tds_in_qh(qh, urb, 0);
-		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, qh);
+		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
 	} else {
 		uhci_insert_tds_in_qh(qh, urb, 1);
-		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, qh);
+		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
 		uhci_inc_fsbr(uhci, urb);
 	}
 
-	urbp->qh = qh;
-	qh->urbp = urbp;
-
 	return -EINPROGRESS;
 }
 
@@ -961,7 +947,8 @@
 		    !(td->status & TD_CTRL_ACTIVE)) {
 			uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
 			urbp->fsbr_timeout = 0;
-			td->status &= ~TD_CTRL_IOC;
+			urbp->fsbrtime = jiffies;
+			clear_bit(TD_CTRL_IOC_BIT, &td->status);
 		}
 
 		status = uhci_status_bits(td->status);
@@ -1043,7 +1030,7 @@
 	urbp->short_control_packet = 1;
 
 	/* Create a new QH to avoid pointer overwriting problems */
-	uhci_remove_qh(uhci, urbp->qh);
+	uhci_remove_qh(uhci, urb);
 
 	/* Delete all of the TD's except for the status TD at the end */
 	head = &urbp->td_list;
@@ -1071,9 +1058,9 @@
 
 	/* Low speed or small transfers gets a different queue and treatment */
 	if (urb->pipe & TD_CTRL_LS)
-		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urbp->qh);
+		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
 	else
-		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urbp->qh);
+		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
 
 	return -EINPROGRESS;
 }
@@ -1134,7 +1121,8 @@
 		    !(td->status & TD_CTRL_ACTIVE)) {
 			uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
 			urbp->fsbr_timeout = 0;
-			td->status &= ~TD_CTRL_IOC;
+			urbp->fsbrtime = jiffies;
+			clear_bit(TD_CTRL_IOC_BIT, &td->status);
 		}
 
 		status = uhci_status_bits(td->status);
@@ -1147,10 +1135,6 @@
 			goto td_error;
 
 		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
-			usb_settoggle(urb->dev, uhci_endpoint(td->info),
-				uhci_packetout(td->info),
-				uhci_toggle(td->info) ^ 1);
-
 			if (urb->transfer_flags & USB_DISABLE_SPD) {
 				ret = -EREMOTEIO;
 				goto err;
@@ -1303,7 +1287,7 @@
 	if (urb->transfer_flags & USB_QUEUE_BULK && eurb)
 		uhci_append_queued_urb(uhci, eurb, urb);
 	else
-		uhci_insert_qh(uhci, uhci->skel_bulk_qh, qh);
+		uhci_insert_qh(uhci, uhci->skel_bulk_qh, urb);
 
 	uhci_inc_fsbr(uhci, urb);
 
@@ -1681,6 +1665,7 @@
 
 static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
 {
+	struct list_head *head, *tmp;
 	struct urb_priv *urbp = urb->hcpriv;
 
 	/* We can get called when urbp allocation fails, so check */
@@ -1689,15 +1674,30 @@
 
 	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
 
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		/* Control and Isochronous ignore the toggle, so this */
+		/* is safe for all types */
+		if (!(td->status & TD_CTRL_ACTIVE) &&
+		    (uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
+		    tmp == head)) {
+			usb_settoggle(urb->dev, uhci_endpoint(td->info),
+				uhci_packetout(td->info),
+				uhci_toggle(td->info) ^ 1);
+		}
+	}
+
 	uhci_delete_queued_urb(uhci, urb);
 
-	if (urbp->qh)
-		/* The interrupt loop will reclaim the QH's */
-		uhci_remove_qh(uhci, urbp->qh);
+	/* The interrupt loop will reclaim the QH's */
+	uhci_remove_qh(uhci, urb);
 }
 
-/* FIXME: If we forcefully unlink an urb, we should reset the toggle for */
-/*  that pipe to match what actually completed */
 static int uhci_unlink_urb(struct urb *urb)
 {
 	struct uhci *uhci;
@@ -1796,7 +1796,7 @@
 		tmp = tmp->next;
 
 		if (td->status & TD_CTRL_ACTIVE) {
-			td->status |= TD_CTRL_IOC;
+			set_bit(TD_CTRL_IOC_BIT, &td->status);
 			break;
 		}
 	}
@@ -1951,11 +1951,11 @@
 		tmp = tmp->next;
 
 		/* Check if the FSBR timed out */
-		if (urbp->fsbr && time_after_eq(jiffies, urbp->inserttime + IDLE_TIMEOUT))
+		if (urbp->fsbr && !urbp->fsbr_timeout && time_after_eq(jiffies, urbp->fsbrtime + IDLE_TIMEOUT))
 			uhci_fsbr_timeout(uhci, u);
 
 		/* Check if the URB timed out */
-		if (u->timeout && time_after_eq(jiffies, u->timeout)) {
+		if (u->timeout && time_after_eq(jiffies, urbp->inserttime + u->timeout)) {
 			list_del(&u->urb_list);
 			list_add_tail(&u->urb_list, &list);
 		}
@@ -2565,7 +2565,7 @@
 static int alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsigned int io_size)
 {
 	struct uhci *uhci;
-	int retval = -EBUSY;
+	int retval;
 	char buf[8], *bufp = buf;
 	int i, port;
 	struct usb_bus *bus;
@@ -2574,27 +2574,27 @@
 	struct proc_dir_entry *ent;
 #endif
 
-	if (!request_region(io_addr, io_size, "usb-uhci")) {
-		err("couldn't allocate I/O range %x - %x", io_addr,
-			io_addr + io_size - 1);
-		goto err_request_region;
+	retval = -ENODEV;
+	if (pci_enable_device(dev) < 0) {
+		err("couldn't enable PCI device");
+		goto err_enable_device;
 	}
 
 	if (!dev->irq) {
 		err("found UHCI device with no IRQ assigned. check BIOS settings!");
-		retval = -EINVAL;
 		goto err_invalid_irq;
 	}
 
 	if (!pci_dma_supported(dev, 0xFFFFFFFF)) {
 		err("PCI subsystem doesn't support 32 bit addressing?");
-		retval = -ENODEV;
 		goto err_pci_dma_supported;
 	}
 
-	if (pci_enable_device(dev) < 0) {
-		err("couldn't enable PCI device");
-		goto err_enable_device;
+	retval = -EBUSY;
+	if (!request_region(io_addr, io_size, "usb-uhci")) {
+		err("couldn't allocate I/O range %x - %x", io_addr,
+			io_addr + io_size - 1);
+		goto err_request_region;
 	}
 
 	pci_set_master(dev);
@@ -2897,15 +2897,15 @@
 err_alloc_uhci:
 
 err_pci_set_dma_mask:
+	release_region(io_addr, io_size);
 
-err_enable_device:
+err_request_region:
 
 err_pci_dma_supported:
-	release_region(io_addr, io_size);
 
 err_invalid_irq:
 
-err_request_region:
+err_enable_device:
 
 	return retval;
 }
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- v2.4.12/linux/drivers/usb/uhci.h	Thu Oct 18 13:50:37 2001
+++ linux/drivers/usb/uhci.h	Thu Oct 18 17:47:09 2001
@@ -100,6 +100,7 @@
 #define TD_CTRL_C_ERR_SHIFT	27
 #define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
 #define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
+#define TD_CTRL_IOC_BIT		24
 #define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
 #define TD_CTRL_ACTIVE		(1 << 23)	/* TD Active */
 #define TD_CTRL_STALLED		(1 << 22)	/* TD Stalled */
@@ -344,6 +345,7 @@
 	int status;			/* Final status */
 
 	unsigned long inserttime;	/* In jiffies */
+	unsigned long fsbrtime;	/* In jiffies */
 
 	struct list_head queue_list;
 	struct list_head complete_list;
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/ultracam.c linux/drivers/usb/ultracam.c
--- v2.4.12/linux/drivers/usb/ultracam.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/usb/ultracam.c	Wed Oct 17 14:34:06 2001
@@ -537,11 +537,7 @@
  * 12-Nov-2000 Reworked to comply with new probe() signature.
  * 23-Jan-2001 Added compatibility with 2.2.x kernels.
  */
-static void *ultracam_probe(struct usb_device *dev, unsigned int ifnum
-#if defined(usb_device_id_ver)
-	,const struct usb_device_id *devid
-#endif
-	)
+static void *ultracam_probe(struct usb_device *dev, unsigned int ifnum ,const struct usb_device_id *devid)
 {
 	uvd_t *uvd = NULL;
 	int i, nas;
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- v2.4.12/linux/drivers/usb/usb-ohci.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/usb-ohci.c	Sat Oct 20 19:13:11 2001
@@ -779,7 +779,7 @@
 				set_current_state(TASK_UNINTERRUPTIBLE);
 				while (timeout && (urb->status == USB_ST_URB_PENDING))
 					timeout = schedule_timeout (timeout);
-				current->state = TASK_RUNNING;
+				set_current_state(TASK_RUNNING);
 				remove_wait_queue (&unlink_wakeup, &wait); 
 				if (urb->status == USB_ST_URB_PENDING) {
 					err ("unlink URB timeout");
@@ -884,7 +884,7 @@
 				set_current_state(TASK_UNINTERRUPTIBLE);
 				while (timeout && dev->ed_cnt)
 					timeout = schedule_timeout (timeout);
-				current->state = TASK_RUNNING;
+				set_current_state(TASK_RUNNING);
 				remove_wait_queue (&freedev_wakeup, &wait);
 				if (dev->ed_cnt) {
 					err ("free device %d timeout", usb_dev->devnum);
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- v2.4.12/linux/drivers/usb/usb-uhci.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/usb/usb-uhci.c	Wed Oct 17 14:34:06 2001
@@ -2193,7 +2193,7 @@
 	if (status & TD_CTRL_NAK)	/* NAK */
 		return -ETIMEDOUT;
 	if (status & TD_CTRL_BABBLE)	/* Babble */
-		return -EPIPE;
+		return -EOVERFLOW;
 	if (status & TD_CTRL_DBUFERR)	/* Buffer error */
 		return -ENOSR;
 	if (status & TD_CTRL_STALLED)	/* Stalled */
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.4.12/linux/drivers/usb/usb.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/usb/usb.c	Sat Oct 20 19:13:11 2001
@@ -60,7 +60,7 @@
  */
 LIST_HEAD(usb_driver_list);
 LIST_HEAD(usb_bus_list);
-rwlock_t usb_bus_list_lock = RW_LOCK_UNLOCKED;
+struct semaphore usb_bus_list_lock;
 
 devfs_handle_t usb_devfs_handle;	/* /dev/usb dir. */
 
@@ -112,7 +112,7 @@
 {
 	struct list_head *tmp;
 
-	read_lock_irq (&usb_bus_list_lock);
+	down (&usb_bus_list_lock);
 	tmp = usb_bus_list.next;
 	while (tmp != &usb_bus_list) {
 		struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list);
@@ -120,7 +120,7 @@
 		tmp = tmp->next;
 		usb_check_support(bus->root_hub);
 	}
-	read_unlock_irq (&usb_bus_list_lock);
+	up (&usb_bus_list_lock);
 }
 
 /*
@@ -182,7 +182,7 @@
 	 */
 	list_del(&driver->driver_list);
 
-	read_lock_irq (&usb_bus_list_lock);
+	down (&usb_bus_list_lock);
 	tmp = usb_bus_list.next;
 	while (tmp != &usb_bus_list) {
 		struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list);
@@ -190,7 +190,7 @@
 		tmp = tmp->next;
 		usb_drivers_purge(driver, bus->root_hub);
 	}
-	read_unlock_irq (&usb_bus_list_lock);
+	up (&usb_bus_list_lock);
 }
 
 struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
@@ -421,7 +421,7 @@
 {
 	int busnum;
 
-	write_lock_irq (&usb_bus_list_lock);
+	down (&usb_bus_list_lock);
 	busnum = find_next_zero_bit(busmap.busmap, USB_MAXBUS, 1);
 	if (busnum < USB_MAXBUS) {
 		set_bit(busnum, busmap.busmap);
@@ -433,7 +433,7 @@
 
 	/* Add it to the list of buses */
 	list_add(&bus->bus_list, &usb_bus_list);
-	write_unlock_irq (&usb_bus_list_lock);
+	up (&usb_bus_list_lock);
 
 	usbdevfs_add_bus(bus);
 
@@ -455,9 +455,9 @@
 	 * controller code, as well as having it call this when cleaning
 	 * itself up
 	 */
-	write_lock_irq (&usb_bus_list_lock);
+	down (&usb_bus_list_lock);
 	list_del(&bus->bus_list);
-	write_unlock_irq (&usb_bus_list_lock);
+	up (&usb_bus_list_lock);
 
 	usbdevfs_remove_bus(bus);
 
@@ -2332,6 +2332,7 @@
  */
 static int __init usb_init(void)
 {
+	init_MUTEX(&usb_bus_list_lock);
 	usb_major_init();
 	usbdevfs_init();
 	usb_hub_init();
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/usbnet.c linux/drivers/usb/usbnet.c
--- v2.4.12/linux/drivers/usb/usbnet.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/usbnet.c	Sat Oct 20 19:13:11 2001
@@ -15,7 +15,7 @@
  * support as appropriate.  Devices currently supported include:
  *
  *	- AnchorChip 2720
- *	- Belkin F5U104 (custom)
+ *	- Belkin, eTEK (interops with Win32 drivers)
  *	- "Linux Devices" (like iPaq and similar SA-1100 based PDAs)
  *	- NetChip 1080 (interoperates with NetChip Win32 drivers)
  *	- Prolific PL-2301/2302 (replaces "plusb" driver)
@@ -73,6 +73,9 @@
  *		Win32 Belkin driver; other cleanups (db).
  * 16-jul-2001	Bugfixes for uhci oops-on-unplug, Belkin support, various
  *		cleanups for problems not yet seen in the field. (db)
+ * 17-oct-2001	Handle "Advance USBNET" product, like Belkin/eTEK devices,
+ *		from Ioannis Mavroukakis <i.mavroukakis@btinternet.com>;
+ *		rx unlinks somehow weren't async; minor cleanup.
  *
  *-------------------------------------------------------------------------*/
 
@@ -97,7 +100,7 @@
 
 
 #define	CONFIG_USB_AN2720
-#define	CONFIG_USB_BELKIN_F5U104
+#define	CONFIG_USB_BELKIN
 #define	CONFIG_USB_LINUXDEV
 #define	CONFIG_USB_NET1080
 #define	CONFIG_USB_PL2301
@@ -119,7 +122,7 @@
 #endif
 
 // packets are always ethernet inside
-// ... except they can be bigger (up to 64K with this framing)
+// ... except they can be bigger (limit of 64K with NetChip framing)
 #define MIN_PACKET	sizeof(struct ethhdr)
 #define MAX_PACKET	32768
 
@@ -161,7 +164,7 @@
 	struct sk_buff_head	txq;
 	struct sk_buff_head	done;
 	struct tasklet_struct	bh;
-	struct tq_struct ctrl_task;
+	struct tq_struct	ctrl_task;
 };
 
 // device-specific info used by the driver
@@ -169,7 +172,8 @@
 	char		*description;
 
 	int		flags;
-#define FLAG_FRAMING	0x0001		/* guard against device dropouts */ 
+#define FLAG_FRAMING_NC	0x0001		/* guard against device dropouts */ 
+#define FLAG_NO_SETINT	0x0010		/* device can't set_interface() */
 
 	/* reset device ... can sleep */
 	int	(*reset)(struct usbnet *);
@@ -251,7 +255,7 @@
 	u16	packet_id;
 } __attribute__((__packed__));
 
-// packets may use FLAG_FRAMING and optional pad
+// packets may use FLAG_FRAMING_NC and optional pad
 #define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
 				+ sizeof (struct ethhdr) \
 				+ (mtu) \
@@ -288,22 +292,24 @@
 
 
 
-#ifdef	CONFIG_USB_BELKIN_F5U104
+#ifdef	CONFIG_USB_BELKIN
 
 /*-------------------------------------------------------------------------
  *
  * Belkin F5U104 ... two NetChip 2280 devices + Atmel microcontroller
  *
+ * ... also two eTEK designs, including one sold as "Advance USBNET"
+ *
  *-------------------------------------------------------------------------*/
 
 static const struct driver_info	belkin_info = {
-	description:	"Belkin USB Direct Connect (F5U104)",
+	description:	"Belkin, eTEK, or compatible",
 
 	in: 1, out: 1,		// direction distinguishes these
 	epsize:	64,
 };
 
-#endif	/* CONFIG_USB_BELKIN_F5U104 */
+#endif	/* CONFIG_USB_BELKIN */
 
 
 
@@ -632,7 +638,7 @@
 
 static const struct driver_info	net1080_info = {
 	description:	"NetChip TurboCONNECT",
-	flags:		FLAG_FRAMING,
+	flags:		FLAG_FRAMING_NC,
 	reset:		net1080_reset,
 	check_connect:	net1080_check_connect,
 
@@ -729,9 +735,9 @@
 {
 	struct usbnet	*dev = (struct usbnet *) net->priv;
 
-	if (new_mtu <= sizeof (struct ethhdr) || new_mtu > MAX_PACKET)
+	if (new_mtu <= MIN_PACKET || new_mtu > MAX_PACKET)
 		return -EINVAL;
-	if (((dev->driver_info->flags) & FLAG_FRAMING)) {
+	if (((dev->driver_info->flags) & FLAG_FRAMING_NC)) {
 		if (FRAMED_SIZE (new_mtu) > MAX_PACKET)
 			return -EINVAL;
 	// no second zero-length packet read wanted after mtu-sized packets
@@ -779,9 +785,11 @@
 	unsigned long		lockflags;
 	size_t			size;
 
-	size = (dev->driver_info->flags & FLAG_FRAMING)
-			? FRAMED_SIZE (dev->net.mtu)
-			: (sizeof (struct ethhdr) + dev->net.mtu);
+	if (dev->driver_info->flags & FLAG_FRAMING_NC)
+		size = FRAMED_SIZE (dev->net.mtu);
+	else
+		size = (sizeof (struct ethhdr) + dev->net.mtu);
+
 	if ((skb = alloc_skb (size, flags)) == 0) {
 		dbg ("no rx skb");
 		tasklet_schedule (&dev->bh);
@@ -798,9 +806,15 @@
 	FILL_BULK_URB (urb, dev->udev,
 		usb_rcvbulkpipe (dev->udev, dev->driver_info->in),
 		skb->data, size, rx_complete, skb);
+	urb->transfer_flags |= USB_ASYNC_UNLINK;
 #ifdef	REALLY_QUEUE
 	urb->transfer_flags |= USB_QUEUE_BULK;
 #endif
+#if 0
+	// Idle-but-posted reads with UHCI really chew up
+	// PCI bandwidth unless FSBR is disabled
+	urb->transfer_flags |= USB_NO_FSBR;
+#endif
 
 	spin_lock_irqsave (&dev->rxq.lock, lockflags);
 
@@ -827,7 +841,7 @@
 
 static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
 {
-	if (dev->driver_info->flags & FLAG_FRAMING) {
+	if (dev->driver_info->flags & FLAG_FRAMING_NC) {
 		struct nc_header	*header;
 		struct nc_trailer	*trailer;
 
@@ -1042,7 +1056,7 @@
 	while (skb_queue_len (&dev->rxq)
 			&& skb_queue_len (&dev->txq)
 			&& skb_queue_len (&dev->done)) {
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout (UNLINK_TIMEOUT_JIFFIES);
 		dbg ("waited for %d urb completions", temp);
 	}
@@ -1083,9 +1097,11 @@
 	}
 
 	netif_start_queue (net);
-	devdbg (dev, "open: enable queueing (rx %d, tx %d) mtu %d %sframed",
+	devdbg (dev, "open: enable queueing (rx %d, tx %d) mtu %d %s framing",
 		RX_QLEN, TX_QLEN, dev->net.mtu,
-		(info->flags & FLAG_FRAMING) ? "" : "un"
+		(info->flags & FLAG_FRAMING_NC)
+		    ? "NetChip"
+		    : "raw"
 		);
 
 	// delay posting reads until we're fully open
@@ -1194,7 +1210,7 @@
 
 	flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
 
-	if (info->flags & FLAG_FRAMING) {
+	if (info->flags & FLAG_FRAMING_NC) {
 		struct sk_buff	*skb2;
 		skb2 = fixup_skb (skb, flags);
 		if (!skb2) {
@@ -1215,7 +1231,7 @@
 	entry->state = tx_start;
 	entry->length = length;
 
-	if (info->flags & FLAG_FRAMING) {
+	if (info->flags & FLAG_FRAMING_NC) {
 		header = (struct nc_header *) skb_push (skb, sizeof *header);
 		header->hdr_len = cpu_to_le16 (sizeof (*header));
 		header->packet_len = cpu_to_le16 (length);
@@ -1223,31 +1239,31 @@
 			*skb_put (skb, 1) = PAD_BYTE;
 		trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer);
 	} else if ((length % EP_SIZE (dev)) == 0) {
-			if (skb_shared (skb)) {
-				struct sk_buff *skb2;
-				skb2 = skb_unshare (skb, flags);
-				if (!skb2) {
-					dbg ("can't unshare skb");
-					goto drop;
-				}
-				skb = skb2;
+		// not all hardware behaves with USB_ZERO_PACKET,
+		// so we add an extra one-byte packet
+		if (skb_shared (skb)) {
+			struct sk_buff *skb2;
+			skb2 = skb_unshare (skb, flags);
+			if (!skb2) {
+				dbg ("can't unshare skb");
+				goto drop;
 			}
-			skb->len++;
+			skb = skb2;
 		}
+		skb->len++;
+	}
 
 	FILL_BULK_URB (urb, dev->udev,
 			usb_sndbulkpipe (dev->udev, info->out),
 			skb->data, skb->len, tx_complete, skb);
-	// Idle-but-posted reads with UHCI really chew up
-	// PCI bandwidth unless FSBR is disabled
-	urb->transfer_flags |= USB_ASYNC_UNLINK | USB_NO_FSBR;
+	urb->transfer_flags |= USB_ASYNC_UNLINK;
 #ifdef	REALLY_QUEUE
 	urb->transfer_flags |= USB_QUEUE_BULK;
 #endif
 	// FIXME urb->timeout = ... jiffies ... ;
 
 	spin_lock_irqsave (&dev->txq.lock, flags);
-	if (info->flags & FLAG_FRAMING) {
+	if (info->flags & FLAG_FRAMING_NC) {
 		header->packet_id = cpu_to_le16 (dev->packet_id++);
 		put_unaligned (header->packet_id, &trailer->packet_id);
 #if 0
@@ -1408,9 +1424,12 @@
 		return 0;
 	}
 
-	if (usb_set_interface (udev, ifnum, altnum) < 0) {
-		err ("set_interface failed");
-		return 0;
+	// more sanity (unless the device is broken)
+	if (!(info->flags & FLAG_NO_SETINT)) {
+		if (usb_set_interface (udev, ifnum, altnum) < 0) {
+			err ("set_interface failed");
+			return 0;
+		}
 	}
 
 	// set up our own records
@@ -1484,6 +1503,18 @@
 },
 #endif
 
+#ifdef	CONFIG_USB_BELKIN
+{
+	USB_DEVICE (0x050d, 0x0004),	// Belkin
+	driver_info:	(unsigned long) &belkin_info,
+}, {
+	USB_DEVICE (0x056c, 0x8100),	// eTEK
+	driver_info:	(unsigned long) &belkin_info,
+}, {
+	USB_DEVICE (0x0525, 0x9901),	// Advance USBNET (eTEK)
+	driver_info:	(unsigned long) &belkin_info,
+},
+#endif
 
 // GeneSys GL620USB (www.genesyslogic.com.tw)
 // (patch exists against an older driver version)
@@ -1508,16 +1539,6 @@
 },
 #endif
 
-#ifdef	CONFIG_USB_BELKIN_F5U104
-{
-	USB_DEVICE (0x050d, 0x0004),	// Belkin
-	driver_info:	(unsigned long) &belkin_info,
-}, {
-	USB_DEVICE (0x056c, 0x8100),	// eTEK
-	driver_info:	(unsigned long) &belkin_info,
-},
-#endif
-
 #ifdef CONFIG_USB_PL2301
 {
 	USB_DEVICE (0x067b, 0x0000),	// PL-2301
@@ -1563,6 +1584,7 @@
 }
 module_exit (usbnet_exit);
 
+EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR ("David Brownell <dbrownell@users.sourceforge.net>");
-MODULE_DESCRIPTION ("USB Host-to-Host Link Drivers (Belkin, Linux, NetChip, Prolific, ...)");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION ("USB Host-to-Host Link Drivers (numerous vendors)");
+MODULE_LICENSE ("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/usb/uss720.c linux/drivers/usb/uss720.c
--- v2.4.12/linux/drivers/usb/uss720.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/usb/uss720.c	Sat Oct 20 19:13:11 2001
@@ -159,7 +159,7 @@
 				if (time_after_eq (jiffies, expire))
 					/* The FIFO is stuck. */
 					return -EBUSY;
-				current->state = TASK_INTERRUPTIBLE;
+				set_current_state(TASK_INTERRUPTIBLE);
 				schedule_timeout((HZ + 99) / 100);
 				if (signal_pending (current))
 					break;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.4.12/linux/drivers/video/Config.in	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/Config.in	Mon Oct 15 13:43:24 2001
@@ -135,9 +135,6 @@
 	 if [ "$CONFIG_FB_ATY" != "n" ]; then
 	    bool '    Mach64 GX support (EXPERIMENTAL)' CONFIG_FB_ATY_GX
 	    bool '    Mach64 CT/VT/GT/LT (incl. 3D RAGE) support' CONFIG_FB_ATY_CT
-	       if [ "$CONFIG_FB_ATY_CT" = "y" ]; then
-	          bool '      Sony Vaio C1VE 1024x480 LCD support' CONFIG_FB_ATY_CT_VAIO_LCD
-	       fi
 	 fi
  	 tristate '  ATI Radeon display support (EXPERIMENTAL)' CONFIG_FB_RADEON
 	 tristate '  ATI Rage128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128
@@ -198,13 +195,6 @@
    fi
    if [ "$CONFIG_NINO" = "y" ]; then
       bool '  TMPTX3912/PR31700 frame buffer support' CONFIG_FB_TX3912
-   fi
-   if [ "$CONFIG_DECSTATION" = "y" ]; then
-     if [ "$CONFIG_TC" = "y" ]; then
-       bool '  PMAG-BA TURBOchannel framebuffer support' CONFIG_FB_PMAG_BA
-       bool '  PMAGB-B TURBOchannel framebuffer spport' CONFIG_FB_PMAGB_B
-       bool '  Maxine (Personal DECstation) onboard framebuffer spport' CONFIG_FB_MAXINE
-     fi
    fi
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate '  Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
diff -u --recursive --new-file v2.4.12/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c
--- v2.4.12/linux/drivers/video/acornfb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/acornfb.c	Sun Oct 21 10:13:07 2001
@@ -1528,7 +1528,7 @@
 
 	acornfb_init_fbinfo();
 
-	for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
+	while (opt = strsep(&options, ",")) {
 		if (!*opt)
 			continue;
 
@@ -1772,4 +1772,7 @@
 	return 0;
 }
 
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver");
 MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/amifb.c linux/drivers/video/amifb.c
--- v2.4.12/linux/drivers/video/amifb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/amifb.c	Sun Oct 21 10:14:38 2001
@@ -1192,7 +1192,7 @@
 	if (!options || !*options)
 		return 0;
 
-	for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!strcmp(this_opt, "inverse")) {
 			amifb_inverse = 1;
 			fb_invert_cmaps();
diff -u --recursive --new-file v2.4.12/linux/drivers/video/aty/atyfb_base.c linux/drivers/video/aty/atyfb_base.c
--- v2.4.12/linux/drivers/video/aty/atyfb_base.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/aty/atyfb_base.c	Sun Oct 21 10:14:38 2001
@@ -2521,8 +2521,7 @@
     if (!options || !*options)
 	return 0;
 
-    for (this_opt = strtok(options, ","); this_opt;
-	 this_opt = strtok(NULL, ",")) {
+    while (this_opt = strsep(&options, ",")) {
 	if (!strncmp(this_opt, "font:", 5)) {
 		char *p;
 		int i;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
--- v2.4.12/linux/drivers/video/aty128fb.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/video/aty128fb.c	Sun Oct 21 10:14:38 2001
@@ -1613,8 +1613,7 @@
     if (!options || !*options)
 	return 0;
 
-    for (this_opt = strtok(options, ","); this_opt;
-	 this_opt = strtok(NULL, ",")) {
+    while (this_opt = strsep(&options, ",")) {
 	if (!strncmp(this_opt, "font:", 5)) {
 	    char *p;
 	    int i;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/cgsixfb.c linux/drivers/video/cgsixfb.c
--- v2.4.12/linux/drivers/video/cgsixfb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/cgsixfb.c	Wed Oct 17 14:16:39 2001
@@ -1,4 +1,4 @@
-/* $Id: cgsixfb.c,v 1.25 2001/09/19 00:04:33 davem Exp $
+/* $Id: cgsixfb.c,v 1.26 2001/10/16 05:44:44 davem Exp $
  * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
@@ -364,13 +364,15 @@
 	unsigned long flags;
 	int i, x, y;
 	u8 *fd1, *fd2, *fd3, *fd4;
+	u16 c;
 
 	spin_lock_irqsave(&fb->lock, flags);
 	do {
 		i = sbus_readl(&fbc->s);
 	} while (i & 0x10000000);
-	sbus_writel(attr_fgcol(p, scr_readw(s)), &fbc->fg);
-	sbus_writel(attr_bgcol(p, scr_readw(s)), &fbc->bg);
+	c = scr_readw(s);
+	sbus_writel(attr_fgcol(p, c), &fbc->fg);
+	sbus_writel(attr_bgcol(p, c), &fbc->bg);
 	sbus_writel(0x140000, &fbc->mode);
 	sbus_writel(0xe880fc30, &fbc->alu);
 	sbus_writel(~0, &fbc->pixelm);
diff -u --recursive --new-file v2.4.12/linux/drivers/video/controlfb.c linux/drivers/video/controlfb.c
--- v2.4.12/linux/drivers/video/controlfb.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/video/controlfb.c	Sun Oct 21 10:14:38 2001
@@ -1423,8 +1423,7 @@
 	if (!options || !*options)
 		return;
 
-	for (this_opt = strtok(options, ","); this_opt;
-	     this_opt = strtok(NULL, ",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!strncmp(this_opt, "font:", 5)) {
 			char *p;
 			int i;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/creatorfb.c linux/drivers/video/creatorfb.c
--- v2.4.12/linux/drivers/video/creatorfb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/creatorfb.c	Wed Oct 17 14:16:39 2001
@@ -1,4 +1,4 @@
-/* $Id: creatorfb.c,v 1.36 2001/09/19 00:04:33 davem Exp $
+/* $Id: creatorfb.c,v 1.37 2001/10/16 05:44:44 davem Exp $
  * creatorfb.c: Creator/Creator3D frame buffer driver
  *
  * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -475,11 +475,13 @@
 	unsigned long flags;
 	int i, xy;
 	u8 *fd1, *fd2, *fd3, *fd4;
+	u16 c;
 	u64 fgbg;
 
 	spin_lock_irqsave(&fb->lock, flags);
-	fgbg = (((u64)(((u32 *)p->dispsw_data)[attr_fgcol(p,scr_readw(s))])) << 32) |
-	       ((u32 *)p->dispsw_data)[attr_bgcol(p,scr_readw(s))];
+	c = scr_readw(s);
+	fgbg = (((u64)(((u32 *)p->dispsw_data)[attr_fgcol(p, c)])) << 32) |
+	       ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
 	if (fgbg != *(u64 *)&fb->s.ffb.fg_cache) {
 		FFBFifo(fb, 2);
 		upa_writeq(fgbg, &fbc->fg);
diff -u --recursive --new-file v2.4.12/linux/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c
--- v2.4.12/linux/drivers/video/cyber2000fb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/cyber2000fb.c	Thu Oct 11 09:43:30 2001
@@ -3,6 +3,9 @@
  *
  *  Copyright (C) 1998-2000 Russell King
  *
+ *  MIPS and 50xx clock support
+ *  Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -53,14 +56,14 @@
  */
 /*#define CFB16_IS_CFB15*/
 
-static char			*CyberRegs;
-
 #include "cyber2000fb.h"
 
 struct cfb_info {
 	struct fb_info		fb;
 	struct display_switch	*dispsw;
 	struct pci_dev		*dev;
+	unsigned char 		*region;
+	unsigned char		*regs;
 	signed int		currcon;
 	int			func_use_count;
 	u_long			ref_ps;
@@ -80,19 +83,67 @@
 	u_char			mclk_div;
 };
 
+static char default_font_storage[40];
+static char *default_font = "Acorn8x8";
+MODULE_PARM(default_font, "s");
+MODULE_PARM_DESC(default_font, "Default font name");
+
+/*
+ * Our access methods.
+ */
+#define cyber2000fb_writel(val,reg,cfb)	writel(val, (cfb)->regs + (reg))
+#define cyber2000fb_writew(val,reg,cfb)	writew(val, (cfb)->regs + (reg))
+#define cyber2000fb_writeb(val,reg,cfb)	writeb(val, (cfb)->regs + (reg))
+
+#define cyber2000fb_readb(reg,cfb)	readb((cfb)->regs + (reg))
+
+static inline void
+cyber2000_crtcw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
+{
+	cyber2000fb_writew((reg & 255) | val << 8, 0x3d4, cfb);
+}
+
+static inline void
+cyber2000_grphw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
+{
+	cyber2000fb_writew((reg & 255) | val << 8, 0x3ce, cfb);
+}
+
+static inline unsigned int
+cyber2000_grphr(unsigned int reg, struct cfb_info *cfb)
+{
+	cyber2000fb_writeb(reg, 0x3ce, cfb);
+	return cyber2000fb_readb(0x3cf, cfb);
+}
+
+static inline void
+cyber2000_attrw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
+{
+	cyber2000fb_readb(0x3da, cfb);
+	cyber2000fb_writeb(reg, 0x3c0, cfb);
+	cyber2000fb_readb(0x3c1, cfb);
+	cyber2000fb_writeb(val, 0x3c0, cfb);
+}
+
+static inline void
+cyber2000_seqw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
+{
+	cyber2000fb_writew((reg & 255) | val << 8, 0x3c4, cfb);
+}
+
 /* -------------------- Hardware specific routines ------------------------- */
 
 /*
  * Hardware Cyber2000 Acceleration
  */
-static void cyber2000_accel_wait(void)
+static void cyber2000_accel_wait(struct cfb_info *cfb)
 {
 	int count = 100000;
 
-	while (cyber2000_inb(CO_REG_CONTROL) & 0x80) {
+	while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & 0x80) {
 		if (!count--) {
 			debug_printf("accel_wait timed out\n");
-			cyber2000_outb(0, CO_REG_CONTROL);
+			cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
 			return;
 		}
 		udelay(1);
@@ -110,6 +161,7 @@
 cyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
 		      int height, int width)
 {
+	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
 	struct fb_var_screeninfo *var = &p->fb_info->var;
 	u_long src, dst;
 	u_int fh, fw;
@@ -142,29 +194,30 @@
 	src    = sx + sy * var->xres_virtual;
 	dst    = dx + dy * var->xres_virtual;
 
-	cyber2000_accel_wait();
-	cyber2000_outb(0x00,  CO_REG_CONTROL);
-	cyber2000_outb(0x03,  CO_REG_FORE_MIX);
-	cyber2000_outw(width, CO_REG_WIDTH);
+	cyber2000_accel_wait(cfb);
+	cyber2000fb_writeb(0x00,  CO_REG_CONTROL, cfb);
+	cyber2000fb_writeb(0x03,  CO_REG_FORE_MIX, cfb);
+	cyber2000fb_writew(width, CO_REG_WIDTH, cfb);
 
 	if (var->bits_per_pixel != 24) {
-		cyber2000_outl(dst, CO_REG_DEST_PTR);
-		cyber2000_outl(src, CO_REG_SRC_PTR);
+		cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
+		cyber2000fb_writel(src, CO_REG_SRC_PTR, cfb);
 	} else {
-		cyber2000_outl(dst * 3, CO_REG_DEST_PTR);
-		cyber2000_outb(dst,     CO_REG_X_PHASE);
-		cyber2000_outl(src * 3, CO_REG_SRC_PTR);
+		cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
+		cyber2000fb_writeb(dst,     CO_REG_X_PHASE, cfb);
+		cyber2000fb_writel(src * 3, CO_REG_SRC_PTR, cfb);
 	}
 
-	cyber2000_outw(height, CO_REG_HEIGHT);
-	cyber2000_outw(cmd,    CO_REG_CMD_L);
-	cyber2000_outw(0x2800, CO_REG_CMD_H);
+	cyber2000fb_writew(height, CO_REG_HEIGHT, cfb);
+	cyber2000fb_writew(cmd,    CO_REG_CMD_L, cfb);
+	cyber2000fb_writew(0x2800, CO_REG_CMD_H, cfb);
 }
 
 static void
 cyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 		      int height, int width)
 {
+	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
 	struct fb_var_screeninfo *var = &p->fb_info->var;
 	u_long dst;
 	u_int fw, fh;
@@ -177,30 +230,30 @@
 	width  = width * fw - 1;
 	height = height * fh - 1;
 
-	cyber2000_accel_wait();
-	cyber2000_outb(0x00,   CO_REG_CONTROL);
-	cyber2000_outb(0x03,   CO_REG_FORE_MIX);
-	cyber2000_outw(width,  CO_REG_WIDTH);
-	cyber2000_outw(height, CO_REG_HEIGHT);
+	cyber2000_accel_wait(cfb);
+	cyber2000fb_writeb(0x00,   CO_REG_CONTROL,  cfb);
+	cyber2000fb_writeb(0x03,   CO_REG_FORE_MIX, cfb);
+	cyber2000fb_writew(width,  CO_REG_WIDTH,    cfb);
+	cyber2000fb_writew(height, CO_REG_HEIGHT,   cfb);
 
 	switch (var->bits_per_pixel) {
 	case 15:
 	case 16:
 		bgx = ((u16 *)p->dispsw_data)[bgx];
 	case 8:
-		cyber2000_outl(dst, CO_REG_DEST_PTR);
+		cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
 		break;
 
 	case 24:
-		cyber2000_outl(dst * 3, CO_REG_DEST_PTR);
-		cyber2000_outb(dst, CO_REG_X_PHASE);
+		cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
+		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
 		bgx = ((u32 *)p->dispsw_data)[bgx];
 		break;
 	}
 
-	cyber2000_outl(bgx, CO_REG_FOREGROUND);
-	cyber2000_outw(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L);
-	cyber2000_outw(0x0800, CO_REG_CMD_H);
+	cyber2000fb_writel(bgx, CO_REG_FOREGROUND, cfb);
+	cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
+	cyber2000fb_writew(0x0800, CO_REG_CMD_H, cfb);
 }
 
 static void
@@ -209,7 +262,7 @@
 {
 	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
 
-	cyber2000_accel_wait();
+	cyber2000_accel_wait(cfb);
 	cfb->dispsw->putc(conp, p, c, yy, xx);
 }
 
@@ -219,7 +272,7 @@
 {
 	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
 
-	cyber2000_accel_wait();
+	cyber2000_accel_wait(cfb);
 	cfb->dispsw->putcs(conp, p, s, count, yy, xx);
 }
 
@@ -227,7 +280,7 @@
 {
 	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
 
-	cyber2000_accel_wait();
+	cyber2000_accel_wait(cfb);
 	cfb->dispsw->revc(p, xx, yy);
 }
 
@@ -274,10 +327,10 @@
 	switch (cfb->fb.var.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
 	case 8:
-		cyber2000_outb(regno, 0x3c8);
-		cyber2000_outb(red,   0x3c9);
-		cyber2000_outb(green, 0x3c9);
-		cyber2000_outb(blue,  0x3c9);
+		cyber2000fb_writeb(regno, 0x3c8, cfb);
+		cyber2000fb_writeb(red,   0x3c9, cfb);
+		cyber2000fb_writeb(green, 0x3c9, cfb);
+		cyber2000fb_writeb(blue,  0x3c9, cfb);
 		break;
 #endif
 
@@ -286,18 +339,18 @@
 #ifndef CFB16_IS_CFB15
 		if (regno < 64) {
 			/* write green */
-			cyber2000_outb(regno << 2, 0x3c8);
-			cyber2000_outb(cfb->palette[regno >> 1].red, 0x3c9);
-			cyber2000_outb(green, 0x3c9);
-			cyber2000_outb(cfb->palette[regno >> 1].blue, 0x3c9);
+			cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
+			cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb);
+			cyber2000fb_writeb(green, 0x3c9, cfb);
+			cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb);
 		}
 
 		if (regno < 32) {
 			/* write red,blue */
-			cyber2000_outb(regno << 3, 0x3c8);
-			cyber2000_outb(red, 0x3c9);
-			cyber2000_outb(cfb->palette[regno << 1].green, 0x3c9);
-			cyber2000_outb(blue, 0x3c9);
+			cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
+			cyber2000fb_writeb(red, 0x3c9, cfb);
+			cyber2000fb_writeb(cfb->palette[regno << 1].green, 0x3c9, cfb);
+			cyber2000fb_writeb(blue, 0x3c9, cfb);
 		}
 
 		if (regno < 16)
@@ -308,10 +361,10 @@
 
 	case 15:
 		if (regno < 32) {
-			cyber2000_outb(regno << 3, 0x3c8);
-			cyber2000_outb(red, 0x3c9);
-			cyber2000_outb(green, 0x3c9);
-			cyber2000_outb(blue, 0x3c9);
+			cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
+			cyber2000fb_writeb(red, 0x3c9, cfb);
+			cyber2000fb_writeb(green, 0x3c9, cfb);
+			cyber2000fb_writeb(blue, 0x3c9, cfb);
 		}
 		if (regno < 16)
 			((u16 *)cfb->fb.pseudo_palette)[regno] =
@@ -322,10 +375,10 @@
 
 #ifdef FBCON_HAS_CFB24
 	case 24:
-		cyber2000_outb(regno, 0x3c8);
-		cyber2000_outb(red,   0x3c9);
-		cyber2000_outb(green, 0x3c9);
-		cyber2000_outb(blue,  0x3c9);
+		cyber2000fb_writeb(regno, 0x3c8, cfb);
+		cyber2000fb_writeb(red,   0x3c9, cfb);
+		cyber2000fb_writeb(green, 0x3c9, cfb);
+		cyber2000fb_writeb(blue,  0x3c9, cfb);
 
 		if (regno < 16)
 			((u32 *)cfb->fb.pseudo_palette)[regno] =
@@ -375,92 +428,92 @@
 	 * Blank palette
 	 */
 	for (i = 0; i < NR_PALETTE; i++) {
-		cyber2000_outb(i, 0x3c8);
-		cyber2000_outb(0, 0x3c9);
-		cyber2000_outb(0, 0x3c9);
-		cyber2000_outb(0, 0x3c9);
-	}
-
-	cyber2000_outb(0xef, 0x3c2);
-	cyber2000_crtcw(0x11, 0x0b);
-	cyber2000_attrw(0x11, 0x00);
-
-	cyber2000_seqw(0x00, 0x01);
-	cyber2000_seqw(0x01, 0x01);
-	cyber2000_seqw(0x02, 0x0f);
-	cyber2000_seqw(0x03, 0x00);
-	cyber2000_seqw(0x04, 0x0e);
-	cyber2000_seqw(0x00, 0x03);
+		cyber2000fb_writeb(i, 0x3c8, cfb);
+		cyber2000fb_writeb(0, 0x3c9, cfb);
+		cyber2000fb_writeb(0, 0x3c9, cfb);
+		cyber2000fb_writeb(0, 0x3c9, cfb);
+	}
+
+	cyber2000fb_writeb(0xef, 0x3c2, cfb);
+	cyber2000_crtcw(0x11, 0x0b, cfb);
+	cyber2000_attrw(0x11, 0x00, cfb);
+
+	cyber2000_seqw(0x00, 0x01, cfb);
+	cyber2000_seqw(0x01, 0x01, cfb);
+	cyber2000_seqw(0x02, 0x0f, cfb);
+	cyber2000_seqw(0x03, 0x00, cfb);
+	cyber2000_seqw(0x04, 0x0e, cfb);
+	cyber2000_seqw(0x00, 0x03, cfb);
 
 	for (i = 0; i < sizeof(crtc_idx); i++)
-		cyber2000_crtcw(crtc_idx[i], hw->crtc[i]);
+		cyber2000_crtcw(crtc_idx[i], hw->crtc[i], cfb);
 
 	for (i = 0x0a; i < 0x10; i++)
-		cyber2000_crtcw(i, 0);
+		cyber2000_crtcw(i, 0, cfb);
 
-	cyber2000_grphw(0x11, hw->crtc_ofl);
-	cyber2000_grphw(0x00, 0x00);
-	cyber2000_grphw(0x01, 0x00);
-	cyber2000_grphw(0x02, 0x00);
-	cyber2000_grphw(0x03, 0x00);
-	cyber2000_grphw(0x04, 0x00);
-	cyber2000_grphw(0x05, 0x60);
-	cyber2000_grphw(0x06, 0x05);
-	cyber2000_grphw(0x07, 0x0f);
-	cyber2000_grphw(0x08, 0xff);
+	cyber2000_grphw(0x11, hw->crtc_ofl, cfb);
+	cyber2000_grphw(0x00, 0x00, cfb);
+	cyber2000_grphw(0x01, 0x00, cfb);
+	cyber2000_grphw(0x02, 0x00, cfb);
+	cyber2000_grphw(0x03, 0x00, cfb);
+	cyber2000_grphw(0x04, 0x00, cfb);
+	cyber2000_grphw(0x05, 0x60, cfb);
+	cyber2000_grphw(0x06, 0x05, cfb);
+	cyber2000_grphw(0x07, 0x0f, cfb);
+	cyber2000_grphw(0x08, 0xff, cfb);
 
 	/* Attribute controller registers */
 	for (i = 0; i < 16; i++)
-		cyber2000_attrw(i, i);
+		cyber2000_attrw(i, i, cfb);
 
-	cyber2000_attrw(0x10, 0x01);
-	cyber2000_attrw(0x11, 0x00);
-	cyber2000_attrw(0x12, 0x0f);
-	cyber2000_attrw(0x13, 0x00);
-	cyber2000_attrw(0x14, 0x00);
+	cyber2000_attrw(0x10, 0x01, cfb);
+	cyber2000_attrw(0x11, 0x00, cfb);
+	cyber2000_attrw(0x12, 0x0f, cfb);
+	cyber2000_attrw(0x13, 0x00, cfb);
+	cyber2000_attrw(0x14, 0x00, cfb);
 
 	/* woody: set the interlaced bit... */
 	/* FIXME: what about doublescan? */
-	cyber2000_outb(0x11, 0x3ce);
-	i = cyber2000_inb(0x3cf);
+	cyber2000fb_writeb(0x11, 0x3ce, cfb);
+	i = cyber2000fb_readb(0x3cf, cfb);
 	if (hw->vmode == FB_VMODE_INTERLACED)
 		i |= 0x20;
 	else
 		i &= ~0x20;
-	cyber2000_outb(i, 0x3cf);
+	cyber2000fb_writeb(i, 0x3cf, cfb);
 
 	/* PLL registers */
-	cyber2000_grphw(DCLK_MULT, hw->clock_mult);
-	cyber2000_grphw(DCLK_DIV,  hw->clock_div);
-	cyber2000_grphw(MCLK_MULT, cfb->mclk_mult);
-	cyber2000_grphw(MCLK_DIV,  cfb->mclk_div);
-	cyber2000_grphw(0x90, 0x01);
-	cyber2000_grphw(0xb9, 0x80);
-	cyber2000_grphw(0xb9, 0x00);
-
-	cyber2000_outb(0x56, 0x3ce);
-	i = cyber2000_inb(0x3cf);
-	cyber2000_outb(i | 4, 0x3cf);
-	cyber2000_outb(hw->palette_ctrl, 0x3c6);
-	cyber2000_outb(i,    0x3cf);
+	cyber2000_grphw(DCLK_MULT, hw->clock_mult, cfb);
+	cyber2000_grphw(DCLK_DIV,  hw->clock_div, cfb);
+	cyber2000_grphw(MCLK_MULT, cfb->mclk_mult, cfb);
+	cyber2000_grphw(MCLK_DIV,  cfb->mclk_div, cfb);
+	cyber2000_grphw(0x90, 0x01, cfb);
+	cyber2000_grphw(0xb9, 0x80, cfb);
+	cyber2000_grphw(0xb9, 0x00, cfb);
+
+	cyber2000fb_writeb(0x56, 0x3ce, cfb);
+	i = cyber2000fb_readb(0x3cf, cfb);
+	cyber2000fb_writeb(i | 4, 0x3cf, cfb);
+	cyber2000fb_writeb(hw->palette_ctrl, 0x3c6, cfb);
+	cyber2000fb_writeb(i,    0x3cf, cfb);
 
-	cyber2000_outb(0x20, 0x3c0);
-	cyber2000_outb(0xff, 0x3c6);
+	cyber2000fb_writeb(0x20, 0x3c0, cfb);
+	cyber2000fb_writeb(0xff, 0x3c6, cfb);
 
-	cyber2000_grphw(0x14, hw->fetch);
+	cyber2000_grphw(0x14, hw->fetch, cfb);
 	cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) |
-			      ((hw->pitch >> 4) & 0x30));
-	cyber2000_grphw(0x77, hw->visualid);
+			      ((hw->pitch >> 4) & 0x30), cfb);
+	cyber2000_grphw(0x77, hw->visualid, cfb);
 
 	/* make sure we stay in linear mode */
-	cyber2000_grphw(0x33, 0x0d);
+	cyber2000_grphw(0x33, 0x0d, cfb);
 
 	/*
 	 * Set up accelerator registers
 	 */
-	cyber2000_outw(hw->width, CO_REG_SRC_WIDTH);
-	cyber2000_outw(hw->width, CO_REG_DEST_WIDTH);
-	cyber2000_outb(hw->pixformat, CO_REG_PIX_FORMAT);
+	cyber2000fb_writew(hw->width,     CO_REG_SRC_WIDTH,  cfb);
+	cyber2000fb_writew(hw->width,     CO_REG_DEST_WIDTH, cfb);
+	cyber2000fb_writeb(hw->pixformat, CO_REG_PIX_FORMAT, cfb);
 }
 
 static inline int
@@ -475,9 +528,9 @@
 	if (base >= 1 << 20)
 		return -EINVAL;
 
-	cyber2000_grphw(0x10, base >> 16 | 0x10);
-	cyber2000_crtcw(0x0c, base >> 8);
-	cyber2000_crtcw(0x0d, base);
+	cyber2000_grphw(0x10, base >> 16 | 0x10, cfb);
+	cyber2000_crtcw(0x0c, base >> 8, cfb);
+	cyber2000_crtcw(0x0d, base, cfb);
 
 	return 0;
 }
@@ -623,6 +676,7 @@
 	const u_long ref_ps = cfb->ref_ps;
 	u_int div2, t_div1, best_div1, best_mult;
 	int best_diff;
+	int vco;
 
 	/*
 	 * Step 1:
@@ -697,6 +751,11 @@
 	hw->clock_mult = best_mult - 1;
 	hw->clock_div  = div2 << 6 | (best_div1 - 1);
 
+	vco = ref_ps * best_div1 / best_mult;
+	if ((ref_ps == 40690) && (vco < 5556))
+		/* Set VFSEL when VCO > 180MHz (5.556 ps). */
+		hw->clock_div |= DCLK_DIV_VFSEL;
+
 	return 0;
 }
 
@@ -1057,30 +1116,30 @@
      
 	switch (blank) {
 	case 4:	/* powerdown - both sync lines down */
-    		cyber2000_grphw(0x16, 0x05);
+    		cyber2000_grphw(0x16, 0x05, cfb);
 		break;	
 	case 3:	/* hsync off */
-    		cyber2000_grphw(0x16, 0x01);
+    		cyber2000_grphw(0x16, 0x01, cfb);
 		break;	
 	case 2:	/* vsync off */
-    		cyber2000_grphw(0x16, 0x04);
+    		cyber2000_grphw(0x16, 0x04, cfb);
 		break;	
 	case 1:	/* soft blank */
-		cyber2000_grphw(0x16, 0x00);
+		cyber2000_grphw(0x16, 0x00, cfb);
 		for (i = 0; i < NR_PALETTE; i++) {
-			cyber2000_outb(i, 0x3c8);
-			cyber2000_outb(0, 0x3c9);
-			cyber2000_outb(0, 0x3c9);
-			cyber2000_outb(0, 0x3c9);
+			cyber2000fb_writeb(i, 0x3c8, cfb);
+			cyber2000fb_writeb(0, 0x3c9, cfb);
+			cyber2000fb_writeb(0, 0x3c9, cfb);
+			cyber2000fb_writeb(0, 0x3c9, cfb);
 		}
 		break;
 	default: /* unblank */
-		cyber2000_grphw(0x16, 0x00);
+		cyber2000_grphw(0x16, 0x00, cfb);
 		for (i = 0; i < NR_PALETTE; i++) {
-			cyber2000_outb(i, 0x3c8);
-			cyber2000_outb(cfb->palette[i].red, 0x3c9);
-			cyber2000_outb(cfb->palette[i].green, 0x3c9);
-			cyber2000_outb(cfb->palette[i].blue, 0x3c9);
+			cyber2000fb_writeb(i, 0x3c8, cfb);
+			cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);
+			cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);
+			cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);
 		}
 		break;
 	}
@@ -1136,8 +1195,8 @@
 	if (cfb->func_use_count == 1) {
 		int old;
 
-		old = cyber2000_grphr(FUNC_CTL);
-		cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL);
+		old = cyber2000_grphr(FUNC_CTL, cfb);
+		cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL, cfb);
 	}
 }
 
@@ -1149,8 +1208,8 @@
 	if (cfb->func_use_count == 1) {
 		int old;
 
-		old = cyber2000_grphr(FUNC_CTL);
-		cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL);
+		old = cyber2000_grphr(FUNC_CTL, cfb);
+		cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL, cfb);
 	}
 
 	cfb->func_use_count -= 1;
@@ -1170,7 +1229,7 @@
 {
 	if (int_cfb_info != NULL) {
 		info->dev	      = int_cfb_info->dev;
-		info->regs	      = CyberRegs;
+		info->regs	      = int_cfb_info->regs;
 		info->fb	      = int_cfb_info->fb.screen_base;
 		info->fb_size	      = int_cfb_info->fb.fix.smem_len;
 		info->enable_extregs  = cyber2000fb_enable_extregs;
@@ -1281,14 +1340,14 @@
 		 * initialising this card for the first time.
 		 * FIXME: what about hotplug?
 		 */
-		cfb->mclk_mult = cyber2000_grphr(MCLK_MULT);
-		cfb->mclk_div  = cyber2000_grphr(MCLK_DIV);
+		cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb);
+		cfb->mclk_div  = cyber2000_grphr(MCLK_DIV, cfb);
 	}
 #endif
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
 	/*
-	 * x86 is simple, we just do regular outb's instead of
-	 * cyber2000_outb.
+	 * x86 and MIPS are simple, we just do regular
+	 * outb's instead of cyber2000fb_writeb.
 	 */
 	outb(0x18, 0x46e8);
 	outb(0x01, 0x102);
@@ -1302,16 +1361,16 @@
 		 * initialising this card for the first time.
 		 * FIXME: what about hotplug?
 		 */
-		cfb->mclk_mult = cyber2000_grphr(MCLK_MULT);
-		cfb->mclk_div  = cyber2000_grphr(MCLK_DIV);
+		cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb);
+		cfb->mclk_div  = cyber2000_grphr(MCLK_DIV, cfb);
 	}
 #endif
 #ifdef __arm__
-	cyber2000_outb(0x18, 0x46e8);
-	cyber2000_outb(0x01, 0x102);
-	cyber2000_outb(0x08, 0x46e8);
-	cyber2000_outb(0x33, 0x3ce);
-	cyber2000_outb(0x01, 0x3cf);
+	cyber2000fb_writeb(0x18, 0x46e8, cfb);
+	cyber2000fb_writeb(0x01, 0x102, cfb);
+	cyber2000fb_writeb(0x08, 0x46e8, cfb);
+	cyber2000fb_writeb(0x33, 0x3ce, cfb);
+	cyber2000fb_writeb(0x01, 0x3cf, cfb);
 
 	/*
 	 * MCLK on the NetWinder and the Shark is fixed at 75MHz
@@ -1324,7 +1383,7 @@
 	 * Initialise the CyberPro
 	 */
 	for (i = 0; i < sizeof(igs_regs); i += 2)
-		cyber2000_grphw(igs_regs[i], igs_regs[i+1]);
+		cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb);
 
 	if (at_boot) {
 		/*
@@ -1332,14 +1391,14 @@
 		 * This should have been already initialised by the BIOS,
 		 * but if it's garbage, claim default 1MB VRAM (woody)
 		 */
-		cfb->mem_ctl1 = cyber2000_grphr(MEM_CTL1);
-		cfb->mem_ctl2 = cyber2000_grphr(MEM_CTL2);
+		cfb->mem_ctl1 = cyber2000_grphr(MEM_CTL1, cfb);
+		cfb->mem_ctl2 = cyber2000_grphr(MEM_CTL2, cfb);
 	} else {
 		/*
 		 * Reprogram the MEM_CTL1 and MEM_CTL2 registers
 		 */
-		cyber2000_grphw(MEM_CTL1, cfb->mem_ctl1);
-		cyber2000_grphw(MEM_CTL2, cfb->mem_ctl2);
+		cyber2000_grphw(MEM_CTL1, cfb->mem_ctl1, cfb);
+		cyber2000_grphw(MEM_CTL2, cfb->mem_ctl2, cfb);
 	}
 
 	/*
@@ -1347,8 +1406,8 @@
 	 * (CyberPro 5000's may be programmed to use
 	 * an additional set of PLLs.
 	 */
-	cyber2000_outb(0xba, 0x3ce);
-	cyber2000_outb(cyber2000_inb(0x3cf) & 0x80, 0x3cf);
+	cyber2000fb_writeb(0xba, 0x3ce, cfb);
+	cyber2000fb_writeb(cyber2000fb_readb(0x3cf, cfb) & 0x80, 0x3cf, cfb);
 }
 
 static struct cfb_info * __devinit
@@ -1366,15 +1425,20 @@
 
 	cfb->currcon		= -1;
 	cfb->dev		= dev;
-	cfb->ref_ps		= 69842;
+
+	if (id->driver_data == FB_ACCEL_IGS_CYBER5000)
+		cfb->ref_ps	= 40690; // 24.576 MHz
+	else
+		cfb->ref_ps	= 69842; // 14.31818 MHz (69841?)
+
 	cfb->divisors[0]	= 1;
 	cfb->divisors[1]	= 2;
 	cfb->divisors[2]	= 4;
 
-	if (id->driver_data == FB_ACCEL_IGS_CYBER2010)
-		cfb->divisors[3] = 6;
-	else
+	if (id->driver_data == FB_ACCEL_IGS_CYBER2000)
 		cfb->divisors[3] = 8;
+	else
+		cfb->divisors[3] = 6;
 
 	strcpy(cfb->fb.fix.id, name);
 
@@ -1392,7 +1456,7 @@
 	cfb->fb.var.accel_flags	= FB_ACCELF_TEXT;
 
 	strcpy(cfb->fb.modename, cfb->fb.fix.id);
-	strcpy(cfb->fb.fontname, "Acorn8x8");
+	strcpy(cfb->fb.fontname, default_font);
 
 	cfb->fb.fbops		= &cyber2000fb_ops;
 	cfb->fb.changevar	= NULL;
@@ -1422,69 +1486,32 @@
 }
 
 /*
- * Map in the registers
- */
-static int __devinit
-cyberpro_map_mmio(struct cfb_info *cfb, struct pci_dev *dev)
-{
-	u_long mmio_base;
-
-	mmio_base = pci_resource_start(dev, 0) + MMIO_OFFSET;
-
-	cfb->fb.fix.mmio_start = mmio_base;
-	cfb->fb.fix.mmio_len   = MMIO_SIZE;
-
-	CyberRegs = ioremap(mmio_base, MMIO_SIZE);
-	if (!CyberRegs) {
-		printk("%s: unable to map memory mapped IO\n",
-		       cfb->fb.fix.id);
-		return -ENOMEM;
-	}
-	return 0;
-}
-
-/*
- * Unmap registers
+ * Parse Cyber2000fb options.  Usage:
+ *  video=cyber2000:font:fontname
  */
-static void __devinit cyberpro_unmap_mmio(struct cfb_info *cfb)
+int
+cyber2000fb_setup(char *options)
 {
-	if (cfb && CyberRegs) {
-		iounmap(CyberRegs);
-		CyberRegs = NULL;
-	}
-}
+	char *opt;
 
-/*
- * Map in screen memory
- */
-static int __devinit
-cyberpro_map_smem(struct cfb_info *cfb, struct pci_dev *dev, u_long smem_len)
-{
-	u_long smem_base;
+	if (!options || !*options)
+		return 0;
 
-	smem_base = pci_resource_start(dev, 0);
+	while ((opt = strsep(&options, ",")) != NULL) {
+		if (!*opt)
+			continue;
 
-	cfb->fb.fix.smem_start	= smem_base;
-	cfb->fb.fix.smem_len	= smem_len;
+		if (strncmp(opt, "font:", 5) == 0) {
+			strncpy(default_font_storage, opt + 5, sizeof(default_font_storage));
+			default_font = default_font_storage;
+			continue;
+		}
 
-	cfb->fb.screen_base = ioremap(smem_base, smem_len);
-	if (!cfb->fb.screen_base) {
-		printk("%s: unable to map screen memory\n",
-		       cfb->fb.fix.id);
-		return -ENOMEM;
+		printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n", opt);
 	}
-
 	return 0;
 }
 
-static void __devinit cyberpro_unmap_smem(struct cfb_info *cfb)
-{
-	if (cfb && cfb->fb.screen_base) {
-		iounmap(cfb->fb.screen_base);
-		cfb->fb.screen_base = NULL;
-	}
-}
-
 static int __devinit
 cyberpro_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
@@ -1507,11 +1534,14 @@
 	err = -ENOMEM;
 	cfb = cyberpro_alloc_fb_info(dev, id, name);
 	if (!cfb)
-		goto failed;
+		goto failed_release;
 
-	err = cyberpro_map_mmio(cfb, dev);
-	if (err)
-		goto failed;
+	cfb->region = ioremap(pci_resource_start(dev, 0),
+			      pci_resource_len(dev, 0));
+	if (!cfb->region)
+		goto failed_ioremap;
+
+	cfb->regs = cfb->region + MMIO_OFFSET;
 
 	cyberpro_init_hw(cfb, 1);
 
@@ -1521,9 +1551,15 @@
 	default:		smem_size = 0x00100000; break;
 	}
 
-	err = cyberpro_map_smem(cfb, dev, smem_size);
-	if (err)
-		goto failed;
+	/*
+	 * Hmm, we _need_ a portable way of finding the address for
+	 * the remap stuff, both for mmio and for smem.
+	 */
+	cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
+	cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+	cfb->fb.fix.mmio_len   = MMIO_SIZE;
+	cfb->fb.fix.smem_len   = smem_size;
+	cfb->fb.screen_base    = cfb->region;
 
 	if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
 	    		  &cyber2000fb_default_mode, 8)) {
@@ -1570,11 +1606,10 @@
 	return 0;
 
 failed:
-	cyberpro_unmap_smem(cfb);
-	cyberpro_unmap_mmio(cfb);
+	iounmap(cfb->region);
+failed_ioremap:
 	cyberpro_free_fb_info(cfb);
-
-release:
+failed_release:
 	pci_release_regions(dev);
 
 	return err;
@@ -1594,8 +1629,7 @@
 			printk(KERN_WARNING "%s: danger Will Robinson, "
 				"danger danger!  Oopsen imminent!\n",
 				cfb->fb.fix.id);
-		cyberpro_unmap_smem(cfb);
-		cyberpro_unmap_mmio(cfb);
+		iounmap(cfb->region);
 		cyberpro_free_fb_info(cfb);
 
 		/*
@@ -1673,7 +1707,10 @@
 }
 
 #ifdef MODULE
-MODULE_LICENSE("GPL");
 module_init(cyber2000fb_init);
 #endif
 module_exit(cyberpro_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/drivers/video/cyber2000fb.h linux/drivers/video/cyber2000fb.h
--- v2.4.12/linux/drivers/video/cyber2000fb.h	Mon Sep 18 15:15:22 2000
+++ linux/drivers/video/cyber2000fb.h	Thu Oct 11 09:43:30 2001
@@ -11,14 +11,6 @@
  */
 #include <linux/config.h>
 
-#define cyber2000_outb(dat,reg)	writeb(dat, CyberRegs + reg)
-#define cyber2000_outw(dat,reg)	writew(dat, CyberRegs + reg)
-#define cyber2000_outl(dat,reg)	writel(dat, CyberRegs + reg)
-
-#define cyber2000_inb(reg)	readb(CyberRegs + reg)
-#define cyber2000_inw(reg)	readw(CyberRegs + reg)
-#define cyber2000_inl(reg)	readl(CyberRegs + reg)
-
 /*
  * Internal CyberPro sizes and offsets.
  */
@@ -30,6 +22,7 @@
 #if defined(DEBUG) && defined(CONFIG_DEBUG_LL)
 static void debug_printf(char *fmt, ...)
 {
+	extern void printascii(const char *);
 	char buffer[128];
 	va_list ap;
 
@@ -43,38 +36,6 @@
 #define debug_printf(x...) do { } while (0)
 #endif
 
-static inline void cyber2000_crtcw(int reg, int val)
-{
-	cyber2000_outb(reg, 0x3d4);
-	cyber2000_outb(val, 0x3d5);
-}
-
-static inline void cyber2000_grphw(int reg, int val)
-{
-	cyber2000_outb(reg, 0x3ce);
-	cyber2000_outb(val, 0x3cf);
-}
-
-static inline unsigned int cyber2000_grphr(int reg)
-{
-	cyber2000_outb(reg, 0x3ce);
-	return cyber2000_inb(0x3cf);
-}
-
-static inline void cyber2000_attrw(int reg, int val)
-{
-	cyber2000_inb(0x3da);
-	cyber2000_outb(reg, 0x3c0);
-	cyber2000_inb(0x3c1);
-	cyber2000_outb(val, 0x3c0);
-}
-
-static inline void cyber2000_seqw(int reg, int val)
-{
-	cyber2000_outb(reg, 0x3c4);
-	cyber2000_outb(val, 0x3c5);
-}
-
 #define PIXFORMAT_8BPP		0
 #define PIXFORMAT_16BPP		1
 #define PIXFORMAT_24BPP		2
@@ -166,6 +127,7 @@
 
 #define DCLK_MULT		0xb0
 #define DCLK_DIV		0xb1
+#define DCLK_DIV_VFSEL			0x20
 #define MCLK_MULT		0xb2
 #define MCLK_DIV		0xb3
 
diff -u --recursive --new-file v2.4.12/linux/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c
--- v2.4.12/linux/drivers/video/cyberfb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/cyberfb.c	Sun Oct 21 10:14:38 2001
@@ -1022,8 +1022,7 @@
 		return 0;
 	}
 
-	for (this_opt = strtok(options, ","); this_opt;
-	     this_opt = strtok(NULL, ",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!strcmp(this_opt, "inverse")) {
 			Cyberfb_inverse = 1;
 			fb_invert_cmaps();
diff -u --recursive --new-file v2.4.12/linux/drivers/video/dn_cfb8.c linux/drivers/video/dn_cfb8.c
--- v2.4.12/linux/drivers/video/dn_cfb8.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/dn_cfb8.c	Mon Oct 15 13:47:13 2001
@@ -518,7 +518,7 @@
     underl = attr_underline(p,conp);
 
     while (count--) {
-	c = *s++;
+	c = scr_readw(s++);
 	dest = dest0++;
 	cdat = p->fontdata+c*p->fontheight;
 	for (rows = p->fontheight; rows--; dest += p->next_line) {
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-afb.c linux/drivers/video/fbcon-afb.c
--- v2.4.12/linux/drivers/video/fbcon-afb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-afb.c	Mon Oct 15 13:47:13 2001
@@ -290,8 +290,9 @@
     int fg0, bg0, fg, bg;
 
     dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
-    fg0 = attr_fgcol(p, scr_readw(s));
-    bg0 = attr_bgcol(p, scr_readw(s));
+    c1 = scr_readw(s);
+    fg0 = attr_fgcol(p, c1);
+    bg0 = attr_bgcol(p, c1);
 
     while (count--)
 	if (xx&3 || count < 3) {	/* Slow version */
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-cfb16.c linux/drivers/video/fbcon-cfb16.c
--- v2.4.12/linux/drivers/video/fbcon-cfb16.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-cfb16.c	Mon Oct 15 13:47:13 2001
@@ -178,8 +178,9 @@
     u32 eorx, fgx, bgx;
 
     dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
-    fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
-    bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, scr_readw(s))];
+    c = scr_readw(s);
+    fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
+    bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
     fgx |= (fgx << 16);
     bgx |= (bgx << 16);
     eorx = fgx ^ bgx;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-cfb2.c linux/drivers/video/fbcon-cfb2.c
--- v2.4.12/linux/drivers/video/fbcon-cfb2.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-cfb2.c	Mon Oct 15 13:47:13 2001
@@ -154,8 +154,9 @@
 	u32 eorx, fgx, bgx;
 
 	dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * 2;
-	fgx=3/*attr_fgcol(p,scr_readw(s))*/;
-	bgx=attr_bgcol(p,scr_readw(s));
+	c = scr_readw(s);
+	fgx = 3/*attr_fgcol(p, c)*/;
+	bgx = attr_bgcol(p, c);
 	fgx |= (fgx << 2);
 	fgx |= (fgx << 4);
 	bgx |= (bgx << 2);
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-cfb24.c linux/drivers/video/fbcon-cfb24.c
--- v2.4.12/linux/drivers/video/fbcon-cfb24.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-cfb24.c	Mon Oct 15 13:47:13 2001
@@ -191,8 +191,9 @@
     u32 eorx, fgx, bgx, d1, d2, d3, d4;
 
     dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3;
-    fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
-    bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, scr_readw(s))];
+    c = scr_readw(s);
+    fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)];
+    bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
     eorx = fgx ^ bgx;
     while (count--) {
 	c = scr_readw(s++) & p->charmask;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-cfb32.c linux/drivers/video/fbcon-cfb32.c
--- v2.4.12/linux/drivers/video/fbcon-cfb32.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-cfb32.c	Mon Oct 15 13:47:13 2001
@@ -164,8 +164,9 @@
     u32 eorx, fgx, bgx, *pt;
 
     dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
-    fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
-    bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, scr_readw(s))];
+    c = scr_readw(s);
+    fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)];
+    bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
     eorx = fgx ^ bgx;
     while (count--) {
 	c = scr_readw(s++) & p->charmask;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-cfb4.c linux/drivers/video/fbcon-cfb4.c
--- v2.4.12/linux/drivers/video/fbcon-cfb4.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-cfb4.c	Mon Oct 15 13:47:13 2001
@@ -156,8 +156,9 @@
 	u32 eorx, fgx, bgx;
 
 	dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * 4;
-	fgx=attr_fgcol(p,scr_readw(s));
-	bgx=attr_bgcol(p,scr_readw(s));
+	c = scr_readw(s);
+	fgx = attr_fgcol(p, c);
+	bgx = attr_bgcol(p, c);
 	fgx |= (fgx << 4);
 	fgx |= (fgx << 8);
 	fgx |= (fgx << 16);
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-cfb8.c linux/drivers/video/fbcon-cfb8.c
--- v2.4.12/linux/drivers/video/fbcon-cfb8.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-cfb8.c	Mon Oct 15 13:47:13 2001
@@ -163,8 +163,9 @@
     u32 eorx, fgx, bgx;
 
     dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
-    fgx=attr_fgcol(p,scr_readw(s));
-    bgx=attr_bgcol(p,scr_readw(s));
+    c = scr_readw(s);
+    fgx = attr_fgcol(p, c);
+    bgx = attr_bgcol(p, c);
     fgx |= (fgx << 8);
     fgx |= (fgx << 16);
     bgx |= (bgx << 8);
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-hga.c linux/drivers/video/fbcon-hga.c
--- v2.4.12/linux/drivers/video/fbcon-hga.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-hga.c	Mon Oct 15 13:47:13 2001
@@ -148,9 +148,10 @@
 	u8 d;
 	u16 c;
 	
-	bold = attr_bold(p,scr_readw(s));
-	revs = attr_reverse(p,scr_readw(s));
-	underl = attr_underline(p,scr_readw(s));
+	c = scr_readw(s);
+	bold = attr_bold(p, c);
+	revs = attr_reverse(p, c);
+	underl = attr_underline(p, c);
 	y0 = yy*fontheight(p);
 
 	while (count--) {
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-ilbm.c linux/drivers/video/fbcon-ilbm.c
--- v2.4.12/linux/drivers/video/fbcon-ilbm.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-ilbm.c	Mon Oct 15 13:47:13 2001
@@ -154,8 +154,9 @@
     int fg0, bg0, fg, bg;
 
     dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
-    fg0 = attr_fgcol(p,scr_readw(s));
-    bg0 = attr_bgcol(p,scr_readw(s));
+    c1 = scr_readw(s);
+    fg0 = attr_fgcol(p, c1);
+    bg0 = attr_bgcol(p, c1);
 
     while (count--)
 	if (xx&3 || count < 3) {	/* Slow version */
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-iplan2p2.c linux/drivers/video/fbcon-iplan2p2.c
--- v2.4.12/linux/drivers/video/fbcon-iplan2p2.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-iplan2p2.c	Mon Oct 15 13:47:13 2001
@@ -364,8 +364,9 @@
     else
 	dest0 = (p->screen_base + yy * bytes * fontheight(p) +
 		 (xx>>1)*4 + (xx & 1));
-    fgx = expand2w(COLOR_2P(attr_fgcol(p,scr_readw(s))));
-    bgx = expand2w(COLOR_2P(attr_bgcol(p,scr_readw(s))));
+    c = scr_readw(s);
+    fgx = expand2w(COLOR_2P(attr_fgcol(p, c)));
+    bgx = expand2w(COLOR_2P(attr_bgcol(p, c)));
     eorx = fgx ^ bgx;
 
     while (count--) {
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-iplan2p4.c linux/drivers/video/fbcon-iplan2p4.c
--- v2.4.12/linux/drivers/video/fbcon-iplan2p4.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-iplan2p4.c	Mon Oct 15 13:47:13 2001
@@ -374,8 +374,9 @@
     else
 	dest0 = (p->screen_base + yy * bytes * fontheight(p) +
 		 (xx>>1)*8 + (xx & 1));
-    fgx = expand4l(attr_fgcol(p,scr_readw(s)));
-    bgx = expand4l(attr_bgcol(p,scr_readw(s)));
+    c = scr_readw(s);
+    fgx = expand4l(attr_fgcol(p, c));
+    bgx = expand4l(attr_bgcol(p, c));
     eorx = fgx ^ bgx;
 
     while (count--) {
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-iplan2p8.c linux/drivers/video/fbcon-iplan2p8.c
--- v2.4.12/linux/drivers/video/fbcon-iplan2p8.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-iplan2p8.c	Mon Oct 15 13:47:13 2001
@@ -407,8 +407,9 @@
 	dest0 = (p->screen_base + yy * bytes * fontheight(p) +
 		 (xx>>1)*16 + (xx & 1));
 
-    expand8dl(attr_fgcol(p,scr_readw(s)), &fgx1, &fgx2);
-    expand8dl(attr_bgcol(p,scr_readw(s)), &bgx1, &bgx2);
+    c = scr_readw(s);
+    expand8dl(attr_fgcol(p, c), &fgx1, &fgx2);
+    expand8dl(attr_bgcol(p, c), &bgx1, &bgx2);
     eorx1 = fgx1 ^ bgx1; eorx2  = fgx2 ^ bgx2;
 
     while (count--) {
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-mfb.c linux/drivers/video/fbcon-mfb.c
--- v2.4.12/linux/drivers/video/fbcon-mfb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-mfb.c	Mon Oct 15 13:47:13 2001
@@ -117,9 +117,10 @@
     u16 c;
 
     dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
-    bold = attr_bold(p,scr_readw(s));
-    revs = attr_reverse(p,scr_readw(s));
-    underl = attr_underline(p,scr_readw(s));
+    c = scr_readw(s);
+    bold = attr_bold(p, c);
+    revs = attr_reverse(p, c);
+    underl = attr_underline(p, c);
 
     while (count--) {
 	c = scr_readw(s++) & p->charmask;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-sti.c linux/drivers/video/fbcon-sti.c
--- v2.4.12/linux/drivers/video/fbcon-sti.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-sti.c	Mon Oct 15 13:47:13 2001
@@ -257,9 +257,10 @@
 		return;
 	}	
 
-	bold = attr_bold(p,scr_readw(s));
-	revs = attr_reverse(p,scr_readw(s));
-	underl = attr_underline(p,scr_readw(s));
+	c = scr_readw(s);
+	bold = attr_bold(p, c);
+	revs = attr_reverse(p, c);
+	underl = attr_underline(p, c);
 
 	while (count--) {
 		c = scr_readw(s++) & p->charmask;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon-vga-planes.c linux/drivers/video/fbcon-vga-planes.c
--- v2.4.12/linux/drivers/video/fbcon-vga-planes.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon-vga-planes.c	Mon Oct 15 13:47:13 2001
@@ -236,8 +236,9 @@
 void fbcon_ega_planes_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
 		   int count, int yy, int xx)
 {
-	int fg = attr_fgcol(p,scr_readw(s));
-	int bg = attr_bgcol(p,scr_readw(s));
+	u16 c = scr_readw(s);
+	int fg = attr_fgcol(p, c);
+	int bg = attr_bgcol(p, c);
 
 	char *where;
 	int n;
@@ -274,8 +275,9 @@
 void fbcon_vga_planes_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
 		   int count, int yy, int xx)
 {
-	int fg = attr_fgcol(p,*s);
-	int bg = attr_bgcol(p,*s);
+	u16 c = scr_readw(s);
+	int fg = attr_fgcol(p, c);
+	int bg = attr_bgcol(p, c);
 
 	char *where;
 	int n;
@@ -295,7 +297,7 @@
 	wmb();
 	for (n = 0; n < count; n++) {
 		int y;
-		int c = *s++ & p->charmask;
+		int c = scr_readw(s++) & p->charmask;
 		u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
 
 		for (y = 0; y < fontheight(p); y++, cdat++) {
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- v2.4.12/linux/drivers/video/fbcon.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbcon.c	Mon Oct 15 13:47:13 2001
@@ -664,7 +664,7 @@
     	    	scr_memsetw(save, conp->vc_video_erase_char, logo_lines * nr_cols * 2);
     	    	r = q - step;
     	    	for (cnt = 0; cnt < logo_lines; cnt++, r += i)
-    	    		scr_memcpyw_from(save + cnt * nr_cols, r, 2 * i);
+    	    		scr_memcpyw(save + cnt * nr_cols, r, 2 * i);
     	    	r = q;
     	    }
     	}
@@ -682,7 +682,7 @@
     	}
     	scr_memsetw((unsigned short *)conp->vc_origin,
 		    conp->vc_video_erase_char, 
-    		conp->vc_size_row * logo_lines);
+		    conp->vc_size_row * logo_lines);
     }
     
     /*
@@ -2010,17 +2010,14 @@
 static void fbcon_invert_region(struct vc_data *conp, u16 *p, int cnt)
 {
     while (cnt--) {
+	u16 a = scr_readw(p);
 	if (!conp->vc_can_do_color)
-	    *p++ ^= 0x0800;
-	else if (conp->vc_hi_font_mask == 0x100) {
-	    u16 a = *p;
+	    a ^= 0x0800;
+	else if (conp->vc_hi_font_mask == 0x100)
 	    a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
-	    *p++ = a;
-	} else {
-	    u16 a = *p;
+	else
 	    a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
-	    *p++ = a;
-	}
+	scr_writew(a, p++);
 	if (p == (u16 *)softback_end)
 	    p = (u16 *)softback_buf;
 	if (p == (u16 *)softback_in)
diff -u --recursive --new-file v2.4.12/linux/drivers/video/fm2fb.c linux/drivers/video/fm2fb.c
--- v2.4.12/linux/drivers/video/fm2fb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fm2fb.c	Sun Oct 21 10:14:38 2001
@@ -430,8 +430,7 @@
     if (!options || !*options)
 	return 0;
 
-    for (this_opt = strtok(options, ","); this_opt;
-	 this_opt = strtok(NULL, ",")) {
+    while (this_opt = strsep(&options, ",")) {
 	if (!strncmp(this_opt, "pal", 3))
 	    fm2fb_mode = FM2FB_MODE_PAL;
 	else if (!strncmp(this_opt, "ntsc", 4))
diff -u --recursive --new-file v2.4.12/linux/drivers/video/hgafb.c linux/drivers/video/hgafb.c
--- v2.4.12/linux/drivers/video/hgafb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/hgafb.c	Sun Oct 21 10:14:38 2001
@@ -203,7 +203,7 @@
 		fillchar = 0x00;
 	spin_unlock_irqrestore(&hga_reg_lock, flags);
 	if (fillchar != 0xbf)
-		memset((char *)hga_vram_base, fillchar, hga_vram_len);
+		isa_memset_io(hga_vram_base, fillchar, hga_vram_len);
 }
 
 
@@ -275,11 +275,12 @@
 static void hga_show_logo(void)
 {
 	int x, y;
-	char *dest = (char *)hga_vram_base;
+	unsigned long dest = hga_vram_base;
 	char *logo = linux_logo_bw;
 	for (y = 134; y < 134 + 80 ; y++) /* this needs some cleanup */
 		for (x = 0; x < 10 ; x++)
-			*(dest + (y%4)*8192 + (y>>2)*90 + x + 40) = ~*(logo++);
+			isa_writeb(~*(logo++),
+				   (dest + (y%4)*8192 + (y>>2)*90 + x + 40));
 }
 #endif /* MODULE */	
 
@@ -794,8 +795,7 @@
 	if (!options || !*options)
 		return 0;
 
-	for (this_opt = strtok(options, ","); this_opt;
-			this_opt = strtok(NULL, ",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!strncmp(this_opt, "font:", 5))
 			strcpy(fb_info.fontname, this_opt+5);
 	}
diff -u --recursive --new-file v2.4.12/linux/drivers/video/igafb.c linux/drivers/video/igafb.c
--- v2.4.12/linux/drivers/video/igafb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/igafb.c	Sun Oct 21 10:14:38 2001
@@ -773,8 +773,7 @@
     if (!options || !*options)
         return 0;
 
-    for (this_opt = strtok(options, ","); this_opt;
-         this_opt = strtok(NULL, ",")) {
+    while (this_opt = strsep(&options, ",")) {
         if (!strncmp(this_opt, "font:", 5)) {
                 char *p;
                 int i;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- v2.4.12/linux/drivers/video/imsttfb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/imsttfb.c	Sun Oct 21 10:14:38 2001
@@ -1977,8 +1977,7 @@
 	if (!options || !*options)
 		return 0;
 
-	for (this_opt = strtok(options, ","); this_opt;
-	     this_opt = strtok(NULL, ",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!strncmp(this_opt, "font:", 5)) {
 			char *p;
 			int i;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/leofb.c linux/drivers/video/leofb.c
--- v2.4.12/linux/drivers/video/leofb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/leofb.c	Wed Oct 17 14:16:39 2001
@@ -1,4 +1,4 @@
-/* $Id: leofb.c,v 1.13 2001/09/19 00:04:33 davem Exp $
+/* $Id: leofb.c,v 1.14 2001/10/16 05:44:44 davem Exp $
  * leofb.c: Leo (ZX) 24/8bit frame buffer driver
  *
  * Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -285,14 +285,16 @@
 	unsigned long flags;
 	int i, x, y;
 	u8 *fd1, *fd2, *fd3, *fd4;
+	u16 c;
 	u32 *u;
 
 	spin_lock_irqsave(&fb->lock, flags);
 	do {
 		i = sbus_readl(&us->csr);
 	} while (i & 0x20000000);
-	sbus_writel(attr_fgcol(p,scr_readw(s)) << 24, &ss->fg);
-	sbus_writel(attr_bgcol(p,scr_readw(s)) << 24, &ss->bg);
+	c = scr_readw(s);
+	sbus_writel(attr_fgcol(p, c) << 24, &ss->fg);
+	sbus_writel(attr_bgcol(p, c) << 24, &ss->bg);
 	sbus_writel(0xFFFFFFFF<<(32-fontwidth(p)), &us->fontmsk);
 	if (fontwidthlog(p))
 		x = (xx << fontwidthlog(p));
diff -u --recursive --new-file v2.4.12/linux/drivers/video/macfb.c linux/drivers/video/macfb.c
--- v2.4.12/linux/drivers/video/macfb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/macfb.c	Sun Oct 21 10:14:38 2001
@@ -848,7 +848,7 @@
 	if (!options || !*options)
 		return;
 	
-	for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!*this_opt) continue;
 		
 		if (! strcmp(this_opt, "inverse"))
diff -u --recursive --new-file v2.4.12/linux/drivers/video/matrox/matroxfb_accel.c linux/drivers/video/matrox/matroxfb_accel.c
--- v2.4.12/linux/drivers/video/matrox/matroxfb_accel.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/video/matrox/matroxfb_accel.c	Mon Oct 15 13:47:13 2001
@@ -654,13 +654,15 @@
 
 #ifdef FBCON_HAS_CFB8
 static void matrox_cfb8_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+	u_int16_t c;
 	u_int32_t fgx, bgx;
 	MINFO_FROM_DISP(p);
 
 	DBG_HEAVY("matroxfb_cfb8_putcs");
 
-	fgx = attr_fgcol(p, scr_readw(s));
-	bgx = attr_bgcol(p, scr_readw(s));
+	c = scr_readw(s);
+	fgx = attr_fgcol(p, c);
+	bgx = attr_bgcol(p, c);
 	fgx |= (fgx << 8);
 	fgx |= (fgx << 16);
 	bgx |= (bgx << 8);
@@ -671,13 +673,15 @@
 
 #ifdef FBCON_HAS_CFB16
 static void matrox_cfb16_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+	u_int16_t c;
 	u_int32_t fgx, bgx;
 	MINFO_FROM_DISP(p);
 
 	DBG_HEAVY("matroxfb_cfb16_putcs");
 
-	fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
-	bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, scr_readw(s))];
+	c = scr_readw(s);
+	fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, c)];
+	bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, c)];
 	fgx |= (fgx << 16);
 	bgx |= (bgx << 16);
 	ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx);
@@ -686,13 +690,15 @@
 
 #if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
 static void matrox_cfb32_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+	u_int16_t c;
 	u_int32_t fgx, bgx;
 	MINFO_FROM_DISP(p);
 
 	DBG_HEAVY("matroxfb_cfb32_putcs");
 
-	fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
-	bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, scr_readw(s))];
+	c = scr_readw(s);
+	fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, c)];
+	bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, c)];
 	ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx);
 }
 #endif
@@ -900,12 +906,14 @@
 	unsigned int offs;
 	unsigned int attr;
 	unsigned int step;
+	u_int16_t c;
 	CRITFLAGS
 	MINFO_FROM_DISP(p);
 
 	step = ACCESS_FBINFO(devflags.textstep);
 	offs = yy * p->next_line + xx * step;
-	attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4);
+	c = scr_readw(s);
+	attr = attr_fgcol(p, c) | (attr_bgcol(p, c) << 4);
 
 	CRITBEGIN
 
diff -u --recursive --new-file v2.4.12/linux/drivers/video/matrox/matroxfb_base.c linux/drivers/video/matrox/matroxfb_base.c
--- v2.4.12/linux/drivers/video/matrox/matroxfb_base.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/video/matrox/matroxfb_base.c	Sun Oct 21 10:14:38 2001
@@ -2355,7 +2355,7 @@
 	if (!options || !*options)
 		return 0;
 
-	for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!*this_opt) continue;
 
 		dprintk("matroxfb_setup: option %s\n", this_opt);
diff -u --recursive --new-file v2.4.12/linux/drivers/video/newport_con.c linux/drivers/video/newport_con.c
--- v2.4.12/linux/drivers/video/newport_con.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/newport_con.c	Mon Oct 15 13:47:24 2001
@@ -379,7 +379,7 @@
 	int charattr;
 	unsigned char *p;
 
-	charattr = (*s >> 8) & 0xff;
+	charattr = (scr_readw(s) >> 8) & 0xff;
 
 	xpos <<= 3;
 	ypos <<= 4;
@@ -399,7 +399,7 @@
 				 NPORT_DMODE0_L32);
 
 	for (i = 0; i < count; i++, xpos += 8) {
-		p = &font_data[vc->vc_num][(s[i] & 0xff) << 4];
+		p = &font_data[vc->vc_num][(scr_readw(s++) & 0xff) << 4];
 
 		newport_wait();
 
diff -u --recursive --new-file v2.4.12/linux/drivers/video/platinumfb.c linux/drivers/video/platinumfb.c
--- v2.4.12/linux/drivers/video/platinumfb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/platinumfb.c	Sun Oct 21 10:14:38 2001
@@ -841,8 +841,7 @@
 	if (!options || !*options)
 		return 0;
 
-	for (this_opt = strtok(options, ","); this_opt;
-	     this_opt = strtok(NULL, ",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!strncmp(this_opt, "font:", 5)) {
 			char *p;
 			int i;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/promcon.c linux/drivers/video/promcon.c
--- v2.4.12/linux/drivers/video/promcon.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/promcon.c	Mon Oct 15 13:47:13 2001
@@ -51,27 +51,30 @@
 {
 	unsigned short *s = (unsigned short *)
 			(conp->vc_origin + py * conp->vc_size_row + (px << 1));
+	u16 cs;
 
+	cs = scr_readw(s);
 	if (px == pw) {
 		unsigned short *t = s - 1;
+		u16 ct = scr_readw(t);
 
-		if (inverted(*s) && inverted(*t))
-			return sprintf(b, "\b\033[7m%c\b\033[@%c\033[m",
-				       *s, *t);
-		else if (inverted(*s))
-			return sprintf(b, "\b\033[7m%c\033[m\b\033[@%c",
-				       *s, *t);
-		else if (inverted(*t))
-			return sprintf(b, "\b%c\b\033[@\033[7m%c\033[m",
-				       *s, *t);
+		if (inverted(cs) && inverted(ct))
+			return sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs,
+				       ct);
+		else if (inverted(cs))
+			return sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs,
+				       ct);
+		else if (inverted(ct))
+			return sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs,
+				       ct);
 		else
-			return sprintf(b, "\b%c\b\033[@%c", *s, *t);
+			return sprintf(b, "\b%c\b\033[@%c", cs, ct);
 	}
 
-	if (inverted(*s))
-		return sprintf(b, "\033[7m%c\033[m\b", *s);
+	if (inverted(cs))
+		return sprintf(b, "\033[7m%c\033[m\b", cs);
 	else
-		return sprintf(b, "%c\b", *s);
+		return sprintf(b, "%c\b", cs);
 }
 
 static int
@@ -80,27 +83,30 @@
 	unsigned short *s = (unsigned short *)
 			(conp->vc_origin + py * conp->vc_size_row + (px << 1));
 	char *p = b;
+	u16 cs;
 
 	b += sprintf(b, "\033[%d;%dH", py + 1, px + 1);
 
+	cs = scr_readw(s);
 	if (px == pw) {
 		unsigned short *t = s - 1;
+		u16 ct = scr_readw(t);
 
-		if (inverted(*s) && inverted(*t))
-			b += sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", *s, *t);
-		else if (inverted(*s))
-			b += sprintf(b, "\b%c\b\033[@%c", *s, *t);
-		else if (inverted(*t))
-			b += sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", *s, *t);
+		if (inverted(cs) && inverted(ct))
+			b += sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs, ct);
+		else if (inverted(cs))
+			b += sprintf(b, "\b%c\b\033[@%c", cs, ct);
+		else if (inverted(ct))
+			b += sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs, ct);
 		else
-			b += sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", *s, *t);
+			b += sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs, ct);
 		return b - p;
 	}
 
-	if (inverted(*s))
-		b += sprintf(b, "%c\b", *s);
+	if (inverted(cs))
+		b += sprintf(b, "%c\b", cs);
 	else
-		b += sprintf(b, "\033[7m%c\033[m\b", *s);
+		b += sprintf(b, "\033[7m%c\033[m\b", cs);
 	return b - p;
 }
 
@@ -206,8 +212,9 @@
 	unsigned char *b = *bp;
 
 	while (cnt--) {
-		if (attr != inverted(*s)) {
-			attr = inverted(*s);
+		u16 c = scr_readw(s);
+		if (attr != inverted(c)) {
+			attr = inverted(c);
 			if (attr) {
 				strcpy (b, "\033[7m");
 				b += 4;
@@ -216,7 +223,8 @@
 				b += 3;
 			}
 		}
-		*b++ = *s++;
+		*b++ = c;
+		s++;
 		if (b - buf >= 224) {
 			promcon_puts(buf, b - buf);
 			b = buf;
@@ -246,9 +254,9 @@
 	if (x + count >= pw + 1) {
 		if (count == 1) {
 			x -= 1;
-			save = *(unsigned short *)(conp->vc_origin
+			save = scr_readw((unsigned short *)(conp->vc_origin
 						   + y * conp->vc_size_row
-						   + (x << 1));
+						   + (x << 1)));
 
 			if (px != x || py != y) {
 				b += sprintf(b, "\033[%d;%dH", y + 1, x + 1);
diff -u --recursive --new-file v2.4.12/linux/drivers/video/pvr2fb.c linux/drivers/video/pvr2fb.c
--- v2.4.12/linux/drivers/video/pvr2fb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/pvr2fb.c	Mon Oct 15 13:36:48 2001
@@ -286,7 +286,7 @@
 
     {
 	/* 640x480 @ 60hz (VGA) */
-	"vga_640x480", 60, 640, 480, 38, 33, 0, 18, 146, 26,
+	"vga_640x480", 60, 640, 480, VGA_CLK, 38, 33, 0, 18, 146, 26,
 	0, FB_VMODE_YWRAP
     },
 
@@ -382,6 +382,7 @@
 
 			pvr2_encode_fix(&fix, &par);
 			display->screen_base = (char *)fix.smem_start;
+			display->scrollmode = SCROLL_YREDRAW;
 			display->visual = fix.visual;
 			display->type = fix.type;
 			display->type_aux = fix.type_aux;
@@ -589,7 +590,7 @@
 #ifdef FBCON_HAS_CFB16
 		    case 16: /* RGB 565 */
 			fbcon_cmap.cfb16[regno] = (red & 0xf800) |
-			                          ((green & 0xf800) >> 6) |
+			                          ((green & 0xfc00) >> 5) |
 						  ((blue & 0xf800) >> 11);
 			break;
 #endif
@@ -1076,8 +1077,8 @@
 	printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", 
 	       GET_FB_IDX(fb_info.node), var.xres, var.yres, var.bits_per_pixel, 
 	       get_line_length(var.xres, var.bits_per_pixel),
-	       (char *)pvr2_get_param(cables, NULL, cable_type, 6),
-	       (char *)pvr2_get_param(outputs, NULL, video_output, 6));
+	       (char *)pvr2_get_param(cables, NULL, cable_type, 3),
+	       (char *)pvr2_get_param(outputs, NULL, video_output, 3));
 
 	return 0;
 }
@@ -1155,10 +1156,10 @@
 	}
 
 	if (*cable_arg)
-		cable_type = pvr2_get_param(cables, cable_arg, 0, 6);
+		cable_type = pvr2_get_param(cables, cable_arg, 0, 3);
 
 	if (*output_arg)
-		video_output = pvr2_get_param(outputs, output_arg, 0, 6);
+		video_output = pvr2_get_param(outputs, output_arg, 0, 3);
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.12/linux/drivers/video/radeonfb.c linux/drivers/video/radeonfb.c
--- v2.4.12/linux/drivers/video/radeonfb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/radeonfb.c	Sun Oct 21 10:14:38 2001
@@ -537,8 +537,7 @@
         if (!options || !*options)
                 return 0;
  
-        for (this_opt = strtok (options, ","); this_opt;
-             this_opt = strtok (NULL, ",")) {
+	while (this_opt = strsep (&options, ",")) {
                 if (!strncmp (this_opt, "font:", 5)) {
                         char *p;
                         int i;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/retz3fb.c linux/drivers/video/retz3fb.c
--- v2.4.12/linux/drivers/video/retz3fb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/retz3fb.c	Sun Oct 21 10:14:38 2001
@@ -1348,8 +1348,7 @@
 	if (!options || !*options)
 		return 0;
 
-	for (this_opt = strtok(options, ","); this_opt;
-	     this_opt = strtok(NULL, ",")){
+	while (this_opt = strsep(&options, ",")) {
 		if (!strcmp(this_opt, "inverse")) {
 			z3fb_inverse = 1;
 			fb_invert_cmaps();
diff -u --recursive --new-file v2.4.12/linux/drivers/video/riva/accel.c linux/drivers/video/riva/accel.c
--- v2.4.12/linux/drivers/video/riva/accel.c	Sat Feb  3 12:48:00 2001
+++ linux/drivers/video/riva/accel.c	Mon Oct 15 13:47:13 2001
@@ -207,10 +207,11 @@
 	xx *= fontwidth(p);
 	yy *= fontheight(p);
 
+	c = scr_readw(s);
+	fgx = attr_fgcol(p, c);
+	bgx = attr_bgcol(p, c);
 	while (count--) {
 		c = scr_readw(s++);
-		fgx = attr_fgcol(p,c);
-		bgx = attr_bgcol(p,c);
 		fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
 		xx += fontwidth(p);
 	}
@@ -321,12 +322,13 @@
 	xx *= fontwidth(p);
 	yy *= fontheight(p);
 
+	c = scr_readw(s);
+	fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
+	bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
+	if (p->var.green.length == 6)
+		convert_bgcolor_16(&bgx);
 	while (count--) {
 		c = scr_readw(s++);
-		fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p,c)];
-		bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p,c)];
-		if (p->var.green.length == 6)
-			convert_bgcolor_16(&bgx);
 		fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
 		xx += fontwidth(p);
 	}
@@ -396,10 +398,11 @@
 	xx *= fontwidth(p);
 	yy *= fontheight(p);
 
+	c = scr_readw(s);
+	fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)];
+	bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
 	while (count--) {
 		c = scr_readw(s++);
-		fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p,c)];
-		bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p,c)];
 		fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
 		xx += fontwidth(p);
 	}
diff -u --recursive --new-file v2.4.12/linux/drivers/video/riva/fbdev.c linux/drivers/video/riva/fbdev.c
--- v2.4.12/linux/drivers/video/riva/fbdev.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/video/riva/fbdev.c	Sun Oct 21 10:14:38 2001
@@ -2045,8 +2045,7 @@
 	if (!options || !*options)
 		return 0;
 
-	for (this_opt = strtok(options, ","); this_opt;
-	     this_opt = strtok(NULL, ",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!strncmp(this_opt, "font:", 5)) {
 			char *p;
 			int i;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/sa1100fb.c linux/drivers/video/sa1100fb.c
--- v2.4.12/linux/drivers/video/sa1100fb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/sa1100fb.c	Sun Oct 21 10:14:38 2001
@@ -2299,8 +2299,7 @@
 	if (!options || !*options)
 		return 0;
 
-	for (this_opt = strtok(options, ","); this_opt;
-	     this_opt = strtok(NULL, ",")) {
+	while (this_opt = strsep(&options, ",")) {
 
 		if (!strncmp(this_opt, "bpp:", 4))
 			current_par.max_bpp =
diff -u --recursive --new-file v2.4.12/linux/drivers/video/sgivwfb.c linux/drivers/video/sgivwfb.c
--- v2.4.12/linux/drivers/video/sgivwfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/sgivwfb.c	Sun Oct 21 10:14:38 2001
@@ -862,8 +862,7 @@
   if (!options || !*options)
     return 0;
 
-  for (this_opt = strtok(options, ","); this_opt;
-       this_opt = strtok(NULL, ",")) {
+  while (this_opt = strsep(&options, ",")) {
     if (!strncmp(this_opt, "font:", 5))
       strcpy(fb_info.fontname, this_opt+5);
   }
diff -u --recursive --new-file v2.4.12/linux/drivers/video/sis/sis_main.c linux/drivers/video/sis/sis_main.c
--- v2.4.12/linux/drivers/video/sis/sis_main.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/sis/sis_main.c	Sun Oct 21 10:14:38 2001
@@ -1726,8 +1726,7 @@
 	if (!options || !*options)
 		return 0;
 
-	for (this_opt = strtok(options, ","); this_opt;
-	     this_opt = strtok(NULL, ",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!*this_opt)
 			continue;
 
diff -u --recursive --new-file v2.4.12/linux/drivers/video/sstfb.c linux/drivers/video/sstfb.c
--- v2.4.12/linux/drivers/video/sstfb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/sstfb.c	Sun Oct 21 10:14:38 2001
@@ -1697,8 +1697,7 @@
 	if (!options || !*options)
 		return 0;
 
-	for(this_opt = strtok(options, ","); this_opt;
-	    this_opt = strtok(NULL, ",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!*this_opt) continue;
 
 		f_ddprintk("option %s\n", this_opt);
diff -u --recursive --new-file v2.4.12/linux/drivers/video/sticon-bmode.c linux/drivers/video/sticon-bmode.c
--- v2.4.12/linux/drivers/video/sticon-bmode.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/sticon-bmode.c	Mon Oct 15 13:47:13 2001
@@ -318,7 +318,7 @@
 	int count, int ypos, int xpos)
 {
 	while(count--) {
-		sti_putc(&default_sti, *s++, ypos, xpos++);
+		sti_putc(&default_sti, scr_readw(s++), ypos, xpos++);
 	}
 }
 
@@ -402,16 +402,6 @@
 	return 0;
 }
 
-static u16 *sticon_screen_pos(struct vc_data *conp, int offset)
-{
-	return NULL;
-}
-
-static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos, int *px, int *py)
-{
-	return 0;
-}
-
 static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, u8 blink, u8 underline, u8 reverse)
 {
 	u8 attr = ((color & 0x70) >> 1) | ((color & 7));
@@ -440,11 +430,7 @@
 	con_set_palette:	sticon_set_palette,
 	con_scrolldelta:	sticon_scrolldelta,
 	con_set_origin: 	sticon_set_origin,
-	con_save_screen:	NULL,
 	con_build_attr:		sticon_build_attr,
-	con_invert_region:	NULL,
-	con_screen_pos:		sticon_screen_pos,
-	con_getxy:		sticon_getxy,
 };
 
 #include <asm/pgalloc.h>	/* need cache flush routines */
diff -u --recursive --new-file v2.4.12/linux/drivers/video/sticon.c linux/drivers/video/sticon.c
--- v2.4.12/linux/drivers/video/sticon.c	Tue Dec  5 12:29:39 2000
+++ linux/drivers/video/sticon.c	Mon Oct 15 13:47:13 2001
@@ -86,7 +86,7 @@
 	int count, int ypos, int xpos)
 {
 	while(count--) {
-		sti_putc(&default_sti, *s++, ypos, xpos++);
+		sti_putc(&default_sti, scr_readw(s++), ypos, xpos++);
 	}
 }
 
@@ -170,16 +170,6 @@
 	return 0;
 }
 
-static u16 *sticon_screen_pos(struct vc_data *conp, int offset)
-{
-	return NULL;
-}
-
-static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos, int *px, int *py)
-{
-	return 0;
-}
-
 static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, u8 blink, u8 underline, u8 reverse)
 {
 	u8 attr = ((color & 0x70) >> 1) | ((color & 7));
@@ -208,11 +198,7 @@
 	con_set_palette:	sticon_set_palette,
 	con_scrolldelta:	sticon_scrolldelta,
 	con_set_origin: 	sticon_set_origin,
-	con_save_screen:	NULL,
 	con_build_attr:		sticon_build_attr,
-	con_invert_region:	NULL,
-	con_screen_pos:		sticon_screen_pos,
-	con_getxy:		sticon_getxy,
 };
 
 static int __init sti_init(void)
diff -u --recursive --new-file v2.4.12/linux/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c
--- v2.4.12/linux/drivers/video/tdfxfb.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/video/tdfxfb.c	Sun Oct 21 10:14:38 2001
@@ -1088,27 +1088,27 @@
 			    struct display* p,
 			    const unsigned short *s,int count,int yy,int xx)
 {
-   u32 fgx,bgx;
-   fgx=attr_fgcol(p, *s);
-   bgx=attr_bgcol(p, *s);
+   u16 c = scr_readw(s);
+   u32 fgx = attr_fgcol(p, c);
+   u32 bgx = attr_bgcol(p, c);
    do_putcs( fgx,bgx,p,s,count,yy,xx );
 }
 static void tdfx_cfb16_putcs(struct vc_data* conp,
 			    struct display* p,
 			    const unsigned short *s,int count,int yy,int xx)
 {
-   u32 fgx,bgx;
-   fgx=((u16*)p->dispsw_data)[attr_fgcol(p,*s)];
-   bgx=((u16*)p->dispsw_data)[attr_bgcol(p,*s)];
+   u16 c = scr_readw(s);
+   u32 fgx = ((u16*)p->dispsw_data)[attr_fgcol(p, c)];
+   u32 bgx = ((u16*)p->dispsw_data)[attr_bgcol(p, c)];
    do_putcs( fgx,bgx,p,s,count,yy,xx );
 }
 static void tdfx_cfb32_putcs(struct vc_data* conp,
 			    struct display* p,
 			    const unsigned short *s,int count,int yy,int xx)
 {
-   u32 fgx,bgx;
-   fgx=((u32*)p->dispsw_data)[attr_fgcol(p,*s)];
-   bgx=((u32*)p->dispsw_data)[attr_bgcol(p,*s)];
+   u16 c = scr_readw(s);
+   u32 fgx = ((u32*)p->dispsw_data)[attr_fgcol(p, c)];
+   u32 bgx = ((u32*)p->dispsw_data)[attr_bgcol(p, c)];
    do_putcs( fgx,bgx,p,s,count,yy,xx );
 }
 
@@ -2086,9 +2086,7 @@
   if(!options || !*options)
     return;
 
-  for(this_opt = strtok(options, ","); 
-      this_opt;
-      this_opt = strtok(NULL, ",")) {
+  while(this_opt = strsep(&options, ",")) {
     if(!strcmp(this_opt, "inverse")) {
       inverse = 1;
       fb_invert_cmaps();
diff -u --recursive --new-file v2.4.12/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c
--- v2.4.12/linux/drivers/video/tgafb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/tgafb.c	Sun Oct 21 10:14:38 2001
@@ -889,7 +889,7 @@
     int i;
     
     if (options && *options) {
-    	for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+    	while (this_opt = strsep(&options, ",")) {
        	    if (!*this_opt) { continue; }
         
 	    if (!strncmp(this_opt, "font:", 5)) {
diff -u --recursive --new-file v2.4.12/linux/drivers/video/valkyriefb.c linux/drivers/video/valkyriefb.c
--- v2.4.12/linux/drivers/video/valkyriefb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/valkyriefb.c	Sun Oct 21 10:14:38 2001
@@ -801,8 +801,7 @@
 	if (!options || !*options)
 		return 0;
 
-	for (this_opt = strtok(options, ","); this_opt;
-	     this_opt = strtok(NULL, ",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!strncmp(this_opt, "font:", 5)) {
 			char *p;
 			int i;
diff -u --recursive --new-file v2.4.12/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- v2.4.12/linux/drivers/video/vesafb.c	Wed Apr 18 11:49:12 2001
+++ linux/drivers/video/vesafb.c	Sun Oct 21 10:14:38 2001
@@ -457,7 +457,7 @@
 	if (!options || !*options)
 		return 0;
 	
-	for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!*this_opt) continue;
 		
 		if (! strcmp(this_opt, "inverse"))
diff -u --recursive --new-file v2.4.12/linux/drivers/video/vfb.c linux/drivers/video/vfb.c
--- v2.4.12/linux/drivers/video/vfb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/vfb.c	Sun Oct 21 10:14:38 2001
@@ -382,8 +382,7 @@
     if (!options || !*options)
 	return 0;
 
-    for (this_opt = strtok(options, ","); this_opt;
-	 this_opt = strtok(NULL, ",")) {
+    while (this_opt = strsep(&options, ",")) {
 	if (!strncmp(this_opt, "font:", 5))
 	    strcpy(fb_info.fontname, this_opt+5);
     }
diff -u --recursive --new-file v2.4.12/linux/drivers/video/vga16fb.c linux/drivers/video/vga16fb.c
--- v2.4.12/linux/drivers/video/vga16fb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/vga16fb.c	Sun Oct 21 10:14:38 2001
@@ -692,7 +692,7 @@
 	if (!options || !*options)
 		return 0;
 	
-	for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+	while (this_opt = strsep(&options, ",")) {
 		if (!*this_opt) continue;
 		
 		if (!strncmp(this_opt, "font:", 5))
diff -u --recursive --new-file v2.4.12/linux/drivers/video/vgacon.c linux/drivers/video/vgacon.c
--- v2.4.12/linux/drivers/video/vgacon.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/vgacon.c	Mon Oct 15 13:47:13 2001
@@ -487,7 +487,7 @@
 	vga_video_num_columns = c->vc_cols;
 	vga_video_num_lines = c->vc_rows;
 	if (!vga_is_gfx)
-		scr_memcpyw_to((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size);
+		scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size);
 	return 0;	/* Redrawing not needed */
 }
 
@@ -978,7 +978,7 @@
 		c->vc_y = ORIG_Y;
 	}
 	if (!vga_is_gfx)
-		scr_memcpyw_from((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, c->vc_screenbuf_size);
+		scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, c->vc_screenbuf_size);
 }
 
 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
diff -u --recursive --new-file v2.4.12/linux/drivers/video/virgefb.c linux/drivers/video/virgefb.c
--- v2.4.12/linux/drivers/video/virgefb.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/virgefb.c	Sun Oct 21 10:14:38 2001
@@ -1085,7 +1085,7 @@
 	if (!options || !*options)
 		return 0;
 
-	for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ","))
+	while (this_opt = strsep(&options, ",")) {
 		if (!strcmp(this_opt, "inverse")) {
 			Cyberfb_inverse = 1;
 			fb_invert_cmaps();
diff -u --recursive --new-file v2.4.12/linux/fs/attr.c linux/fs/attr.c
--- v2.4.12/linux/fs/attr.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/attr.c	Thu Oct 11 09:43:30 2001
@@ -137,7 +137,7 @@
 			    (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
 				error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
 			if (!error)
-				inode_setattr(inode, attr);
+				error = inode_setattr(inode, attr);
 		}
 	}
 	unlock_kernel();
diff -u --recursive --new-file v2.4.12/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.4.12/linux/fs/binfmt_elf.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/binfmt_elf.c	Sat Oct 20 19:16:59 2001
@@ -270,6 +270,8 @@
 	 */
 	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
 		goto out;
+	if (interp_elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr))
+		goto out;
 
 	/* Now read in all of the header information */
 
@@ -757,8 +759,7 @@
 	printk("(brk) %lx\n" , (long) current->mm->brk);
 #endif
 
-	if ( current->personality == PER_SVR4 )
-	{
+	if (current->personality & MMAP_PAGE_ZERO) {
 		/* Why this, you ask???  Well SVr4 maps page 0 as read-only,
 		   and some applications "depend" upon this behavior.
 		   Since we do not have the power to recompile these, we
diff -u --recursive --new-file v2.4.12/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- v2.4.12/linux/fs/binfmt_misc.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/binfmt_misc.c	Sat Oct 20 19:14:42 2001
@@ -13,165 +13,80 @@
  *  1997-06-26 hpa: pass the real filename rather than argv[0]
  *  1997-06-30 minor cleanup
  *  1997-08-09 removed extension stripping, locking cleanup
+ *  2001-02-28 AV: rewritten into something that resembles C. Original didn't.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/init.h>
 
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
 #include <linux/binfmts.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/string.h>
+#include <linux/slab.h>
 #include <linux/ctype.h>
 #include <linux/file.h>
-#include <linux/spinlock.h>
+#include <linux/pagemap.h>
+
 #include <asm/uaccess.h>
 
-/*
- * We should make this work with a "stub-only" /proc,
- * which would just not be able to be configured.
- * Right now the /proc-fs support is too black and white,
- * though, so just remind people that this should be
- * fixed..
- */
-#ifndef CONFIG_PROC_FS
-#error You really need /proc support for binfmt_misc. Please reconfigure!
-#endif
-
-#define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
-
-struct binfmt_entry {
-	struct binfmt_entry *next;
-	long id;
+enum {
+	VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */
+};
+
+static LIST_HEAD(entries);
+static int enabled = 1;
+
+enum {Enabled, Magic};
+
+typedef struct {
+	struct list_head list;
 	int flags;			/* type, status, etc. */
 	int offset;			/* offset of magic */
 	int size;			/* size of magic/mask */
 	char *magic;			/* magic or filename extension */
 	char *mask;			/* mask, NULL for exact match */
 	char *interpreter;		/* filename of interpreter */
-	char *proc_name;
-	struct proc_dir_entry *proc_dir;
-};
-
-#define ENTRY_ENABLED 1		/* the old binfmt_entry.enabled */
-#define	ENTRY_MAGIC 8		/* not filename detection */
-
-static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
-static void entry_proc_cleanup(struct binfmt_entry *e);
-static int entry_proc_setup(struct binfmt_entry *e);
-
-static struct linux_binfmt misc_format = {
-	NULL, THIS_MODULE, load_misc_binary, NULL, NULL, 0
-};
-
-static struct proc_dir_entry *bm_dir;
-
-static struct binfmt_entry *entries;
-static int free_id = 1;
-static int enabled = 1;
+	char *name;
+	struct dentry *dentry;
+} Node;
 
 static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
 
-
-/*
- * Unregister one entry
- */
-static void clear_entry(int id)
-{
-	struct binfmt_entry **ep, *e;
-
-	write_lock(&entries_lock);
-	ep = &entries;
-	while (*ep && ((*ep)->id != id))
-		ep = &((*ep)->next);
-	if ((e = *ep))
-		*ep = e->next;
-	write_unlock(&entries_lock);
-
-	if (e) {
-		entry_proc_cleanup(e);
-		kfree(e);
-	}
-}
-
-/*
- * Clear all registered binary formats
- */
-static void clear_entries(void)
-{
-	struct binfmt_entry *e, *n;
-
-	write_lock(&entries_lock);
-	n = entries;
-	entries = NULL;
-	write_unlock(&entries_lock);
-
-	while ((e = n)) {
-		n = e->next;
-		entry_proc_cleanup(e);
-		kfree(e);
-	}
-}
-
-/*
- * Find entry through id and lock it
- */
-static struct binfmt_entry *get_entry(int id)
-{
-	struct binfmt_entry *e;
-
-	read_lock(&entries_lock);
-	e = entries;
-	while (e && (e->id != id))
-		e = e->next;
-	if (!e)
-		read_unlock(&entries_lock);
-	return e;
-}
-
-/*
- * unlock entry
- */
-static inline void put_entry(struct binfmt_entry *e)
-{
-	if (e)
-		read_unlock(&entries_lock);
-}
-
-
 /* 
  * Check if we support the binfmt
- * if we do, return the binfmt_entry, else NULL
+ * if we do, return the node, else NULL
  * locking is done in load_misc_binary
  */
-static struct binfmt_entry *check_file(struct linux_binprm *bprm)
+static Node *check_file(struct linux_binprm *bprm)
 {
-	struct binfmt_entry *e;
 	char *p = strrchr(bprm->filename, '.');
-	int j;
+	struct list_head *l;
 
-	e = entries;
-	while (e) {
-		if (e->flags & ENTRY_ENABLED) {
-			if (!(e->flags & ENTRY_MAGIC)) {
-				if (p && !strcmp(e->magic, p + 1))
-					return e;
-			} else {
-				j = 0;
-				while ((j < e->size) &&
-				  !((bprm->buf[e->offset + j] ^ e->magic[j])
-				   & (e->mask ? e->mask[j] : 0xff)))
-					j++;
-				if (j == e->size)
-					return e;
-			}
+	for (l = entries.next; l != &entries; l = l->next) {
+		Node *e = list_entry(l, Node, list);
+		char *s;
+		int j;
+
+		if (!test_bit(Enabled, &e->flags))
+			continue;
+
+		if (!test_bit(Magic, &e->flags)) {
+			if (p && !strcmp(e->magic, p + 1))
+				return e;
+			continue;
 		}
-		e = e->next;
-	};
+
+		s = bprm->buf + e->offset;
+		if (e->mask) {
+			for (j = 0; j < e->size; j++)
+				if ((*s++ ^ e->magic[j]) & e->mask[j])
+					break;
+		} else {
+			for (j = 0; j < e->size; j++)
+				if ((*s++ ^ e->magic[j]))
+					break;
+		}
+		if (j == e->size)
+			return e;
+	}
 	return NULL;
 }
 
@@ -180,7 +95,7 @@
  */
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
-	struct binfmt_entry *fmt;
+	Node *fmt;
 	struct file * file;
 	char iname[BINPRM_BUF_SIZE];
 	char *iname_addr = iname;
@@ -228,11 +143,7 @@
 	return retval;
 }
 
-
-
-/*
- * /proc handling routines
- */
+/* Command parsers */
 
 /*
  * parses and copies one argument enclosed in del from *sp to *dp,
@@ -240,34 +151,38 @@
  * returns pointer to the copied argument or NULL in case of an
  * error (and sets err) or null argument length.
  */
-static char *copyarg(char **dp, const char **sp, int *count,
-		     char del, int special, int *err)
+static char *scanarg(char *s, char del)
 {
-	char c = 0, *res = *dp;
+	char c;
 
-	while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
-		switch (c) {
-		case '\\':
-			if (special && (**sp == 'x')) {
-				if (!isxdigit(c = toupper(*(++*sp))))
-					*err = -EINVAL;
-				**dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16;
-				if (!isxdigit(c = toupper(*(++*sp))))
-					*err = -EINVAL;
-				*((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10);
-				++*sp;
-				*count -= 3;
-				break;
-			}
-		default:
-			*((*dp)++) = c;
+	while ((c = *s++) != del) {
+		if (c == '\\' && *s == 'x') {
+			s++;
+			if (!isxdigit(*s++))
+				return NULL;
+			if (!isxdigit(*s++))
+				return NULL;
 		}
 	}
-	if (*err || (c != del) || (res == *dp))
-		res = NULL;
-	else if (!special)
-		*((*dp)++) = '\0';
-	return res;
+	return s;
+}
+
+static int unquote(char *from)
+{
+	char c = 0, *s = from, *p = from;
+
+	while ((c = *s++) != '\0') {
+		if (c == '\\' && *s == 'x') {
+			s++;
+			c = toupper(*s++);
+			*p = (c - (isdigit(c) ? '0' : 'A' - 10)) << 4;
+			c = toupper(*s++);
+			*p++ |= c - (isdigit(c) ? '0' : 'A' - 10);
+			continue;
+		}
+		*p++ = c;
+	}
+	return p - from;
 }
 
 /*
@@ -275,245 +190,533 @@
  * ':name:type:offset:magic:mask:interpreter:'
  * where the ':' is the IFS, that can be chosen with the first char
  */
-static int proc_write_register(struct file *file, const char *buffer,
-			       unsigned long count, void *data)
+static Node *create_entry(const char *buffer, size_t count)
 {
-	const char *sp;
-	char del, *dp;
-	struct binfmt_entry *e;
-	int memsize, cnt = count - 1, err;
+	Node *e;
+	int memsize, err;
+	char *buf, *p;
+	char del;
 
 	/* some sanity checks */
 	err = -EINVAL;
 	if ((count < 11) || (count > 256))
-		goto _err;
+		goto out;
 
 	err = -ENOMEM;
-	memsize = sizeof(struct binfmt_entry) + count;
-	if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
-		goto _err;
-
-	err = 0;
-	sp = buffer + 1;
-	del = buffer[0];
-	dp = (char *)e + sizeof(struct binfmt_entry);
-
-	e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
-
-	/* we can use bit 3 of type for ext/magic
-	   flag due to the nice encoding of E and M */
-	if ((*sp & ~('E' | 'M')) || (sp[1] != del))
-		err = -EINVAL;
-	else
-		e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_ENABLED));
-	cnt -= 2; sp++;
-
-	e->offset = 0;
-	while (cnt-- && isdigit(*sp))
-		e->offset = e->offset * 10 + *sp++ - '0';
-	if (*sp++ != del)
-		err = -EINVAL;
-
-	e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err);
-	e->size = dp - e->magic;
-	e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err);
-	if (e->mask && ((dp - e->mask) != e->size))
-		err = -EINVAL;
-	e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err);
-	e->id = free_id++;
-
-	/* more sanity checks */
-	if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
-	    (e->size < 1) || ((e->size + e->offset) > (BINPRM_BUF_SIZE - 1)) ||
-	    !(e->proc_name) || !(e->interpreter) || entry_proc_setup(e))
-		goto free_err;
+	memsize = sizeof(Node) + count + 8;
+	e = (Node *) kmalloc(memsize, GFP_USER);
+	if (!e)
+		goto out;
 
-	write_lock(&entries_lock);
-	e->next = entries;
-	entries = e;
-	write_unlock(&entries_lock);
+	p = buf = (char *)e + sizeof(Node);
 
-	err = count;
-_err:
-	return err;
-free_err:
+	memset(e, 0, sizeof(Node));
+	if (copy_from_user(buf, buffer, count))
+		goto Efault;
+
+	del = *p++;	/* delimeter */
+
+	memset(buf+count, del, 8);
+
+	e->name = p;
+	p = strchr(p, del);
+	if (!p)
+		goto Einval;
+	*p++ = '\0';
+	if (!e->name[0] ||
+	    !strcmp(e->name, ".") ||
+	    !strcmp(e->name, "..") ||
+	    strchr(e->name, '/'))
+		goto Einval;
+	switch (*p++) {
+		case 'E': e->flags = 1<<Enabled; break;
+		case 'M': e->flags = (1<<Enabled) | (1<<Magic); break;
+		default: goto Einval;
+	}
+	if (*p++ != del)
+		goto Einval;
+	if (test_bit(Magic, &e->flags)) {
+		char *s = strchr(p, del);
+		if (!s)
+			goto Einval;
+		*s++ = '\0';
+		e->offset = simple_strtoul(p, &p, 10);
+		if (*p++)
+			goto Einval;
+		e->magic = p;
+		p = scanarg(p, del);
+		if (!p)
+			goto Einval;
+		p[-1] = '\0';
+		if (!e->magic[0])
+			goto Einval;
+		e->mask = p;
+		p = scanarg(p, del);
+		if (!p)
+			goto Einval;
+		p[-1] = '\0';
+		if (!e->mask[0])
+			e->mask = NULL;
+		e->size = unquote(e->magic);
+		if (e->mask && unquote(e->mask) != e->size)
+			goto Einval;
+		if (e->size + e->offset > BINPRM_BUF_SIZE)
+			goto Einval;
+	} else {
+		p = strchr(p, del);
+		if (!p)
+			goto Einval;
+		*p++ = '\0';
+		e->magic = p;
+		p = strchr(p, del);
+		if (!p)
+			goto Einval;
+		*p++ = '\0';
+		if (!e->magic[0] || strchr(e->magic, '/'))
+			goto Einval;
+		p = strchr(p, del);
+		if (!p)
+			goto Einval;
+		*p++ = '\0';
+	}
+	e->interpreter = p;
+	p = strchr(p, del);
+	if (!p)
+		goto Einval;
+	*p++ = '\0';
+	if (!e->interpreter[0])
+		goto Einval;
+
+	if (*p == '\n')
+		p++;
+	if (p != buf + count)
+		goto Einval;
+	return e;
+
+out:
+	return ERR_PTR(err);
+
+Efault:
 	kfree(e);
-	err = -EINVAL;
-	goto _err;
+	return ERR_PTR(-EFAULT);
+Einval:
+	kfree(e);
+	return ERR_PTR(-EINVAL);
 }
 
 /*
- * Get status of entry/binfmt_misc
- * FIXME? should an entry be marked disabled if binfmt_misc is disabled though
- *        entry is enabled?
+ * Set status of entry/binfmt_misc:
+ * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
  */
-static int proc_read_status(char *page, char **start, off_t off,
-			    int count, int *eof, void *data)
+static int parse_command(const char *buffer, size_t count)
+{
+	char s[4];
+
+	if (!count)
+		return 0;
+	if (count > 3)
+		return -EINVAL;
+	if (copy_from_user(s, buffer, count))
+		return -EFAULT;
+	if (s[count-1] == '\n')
+		count--;
+	if (count == 1 && s[0] == '0')
+		return 1;
+	if (count == 1 && s[0] == '1')
+		return 2;
+	if (count == 2 && s[0] == '-' && s[1] == '1')
+		return 3;
+	return -EINVAL;
+}
+
+/* generic stuff */
+
+static void entry_status(Node *e, char *page)
 {
-	struct binfmt_entry *e;
 	char *dp;
-	int elen, i, err;
+	char *status = "disabled";
 
-#ifndef VERBOSE_STATUS
-	if (data) {
-		if (!(e = get_entry((int) data))) {
-			err = -ENOENT;
-			goto _err;
-		}
-		i = e->flags & ENTRY_ENABLED;
-		put_entry(e);
+	if (test_bit(Enabled, &e->flags))
+		status = "enabled";
+
+	if (!VERBOSE_STATUS) {
+		sprintf(page, "%s\n", status);
+		return;
+	}
+
+	sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter);
+	dp = page + strlen(page);
+	if (!test_bit(Magic, &e->flags)) {
+		sprintf(dp, "extension .%s\n", e->magic);
 	} else {
-		i = enabled;
-	} 
-	sprintf(page, "%s\n", (i ? "enabled" : "disabled"));
-#else
-	if (!data)
-		sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
-	else {
-		if (!(e = get_entry((long) data))) {
-			err = -ENOENT;
-			goto _err;
-		}
-		sprintf(page, "%s\ninterpreter %s\n",
-		        (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"),
-			e->interpreter);
+		int i;
+
+		sprintf(dp, "offset %i\nmagic ", e->offset);
 		dp = page + strlen(page);
-		if (!(e->flags & ENTRY_MAGIC)) {
-			sprintf(dp, "extension .%s\n", e->magic);
-			dp = page + strlen(page);
-		} else {
-			sprintf(dp, "offset %i\nmagic ", e->offset);
-			dp = page + strlen(page);
+		for (i = 0; i < e->size; i++) {
+			sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
+			dp += 2;
+		}
+		if (e->mask) {
+			sprintf(dp, "\nmask ");
+			dp += 6;
 			for (i = 0; i < e->size; i++) {
-				sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
+				sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
 				dp += 2;
 			}
-			if (e->mask) {
-				sprintf(dp, "\nmask ");
-				dp += 6;
-				for (i = 0; i < e->size; i++) {
-					sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
-					dp += 2;
-				}
-			}
-			*dp++ = '\n';
-			*dp = '\0';
 		}
-		put_entry(e);
+		*dp++ = '\n';
+		*dp = '\0';
 	}
-#endif
+}
 
-	elen = strlen(page) - off;
-	if (elen < 0)
-		elen = 0;
-	*eof = (elen <= count) ? 1 : 0;
-	*start = page + off;
-	err = elen;
+static struct inode *bm_get_inode(struct super_block *sb, int mode)
+{
+	struct inode * inode = new_inode(sb);
 
-_err:
-	return err;
+	if (inode) {
+		inode->i_mode = mode;
+		inode->i_uid = 0;
+		inode->i_gid = 0;
+		inode->i_blksize = PAGE_CACHE_SIZE;
+		inode->i_blocks = 0;
+		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	}
+	return inode;
 }
 
-/*
- * Set status of entry/binfmt_misc:
- * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
- */
-static int proc_write_status(struct file *file, const char *buffer,
-			     unsigned long count, void *data)
+static void bm_clear_inode(struct inode *inode)
 {
-	struct binfmt_entry *e;
-	int res = count;
+	Node *e = inode->u.generic_ip;
 
-	if (buffer[count-1] == '\n')
-		count--;
-	if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
-		if (data) {
-			if ((e = get_entry((long) data)))
-				e->flags = (e->flags & ~ENTRY_ENABLED)
-					    | (int)(buffer[0] - '0');
-			put_entry(e);
+	if (e) {
+		write_lock(&entries_lock);
+		list_del(&e->list);
+		write_unlock(&entries_lock);
+		kfree(e);
+	}
+}
+
+static void kill_node(Node *e)
+{
+	struct dentry *dentry;
+
+	write_lock(&entries_lock);
+	dentry = e->dentry;
+	if (dentry) {
+		list_del(&e->list);
+		INIT_LIST_HEAD(&e->list);
+		e->dentry = NULL;
+	}
+	write_unlock(&entries_lock);
+
+	if (dentry) {
+		dentry->d_inode->i_nlink--;
+		d_drop(dentry);
+		dput(dentry);
+	}
+}
+
+/* /<entry> */
+
+static ssize_t
+bm_entry_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
+{
+	Node *e = file->f_dentry->d_inode->u.generic_ip;
+	loff_t pos = *ppos;
+	ssize_t res;
+	char *page;
+	int len;
+
+	if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+
+	entry_status(e, page);
+	len = strlen(page);
+
+	res = -EINVAL;
+	if (pos < 0)
+		goto out;
+	res = 0;
+	if (pos >= len)
+		goto out;
+	if (len < pos + nbytes)
+		nbytes = len - pos;
+	res = -EFAULT;
+	if (copy_to_user(buf, page + pos, nbytes))
+		goto out;
+	*ppos = pos + nbytes;
+	res = nbytes;
+out:
+	free_page((unsigned long) page);
+	return res;
+}
+
+static ssize_t bm_entry_write(struct file *file, const char *buffer,
+				size_t count, loff_t *ppos)
+{
+	struct dentry *root;
+	Node *e = file->f_dentry->d_inode->u.generic_ip;
+	int res = parse_command(buffer, count);
+
+	switch (res) {
+		case 1: clear_bit(Enabled, &e->flags);
+			break;
+		case 2: set_bit(Enabled, &e->flags);
+			break;
+		case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root);
+			down(&root->d_inode->i_sem);
+			down(&root->d_inode->i_zombie);
+
+			kill_node(e);
+
+			up(&root->d_inode->i_zombie);
+			up(&root->d_inode->i_sem);
+			dput(root);
+			break;
+		default: return res;
+	}
+	return count;
+}
+
+static struct file_operations bm_entry_operations = {
+	read:		bm_entry_read,
+	write:		bm_entry_write,
+};
+
+/* /register */
+
+static ssize_t bm_register_write(struct file *file, const char *buffer,
+			       size_t count, loff_t *ppos)
+{
+	Node *e;
+	struct dentry *root, *dentry;
+	struct super_block *sb = file->f_vfsmnt->mnt_sb;
+	int err = 0;
+
+	e = create_entry(buffer, count);
+
+	if (IS_ERR(e))
+		return PTR_ERR(e);
+
+	root = dget(sb->s_root);
+	down(&root->d_inode->i_sem);
+	dentry = lookup_one_len(e->name, root, strlen(e->name));
+	err = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		down(&root->d_inode->i_zombie);
+		if (dentry->d_inode) {
+			err = -EEXIST;
 		} else {
-			enabled = buffer[0] - '0';
+			struct inode * inode = bm_get_inode(sb, S_IFREG | 0644);
+			err = -ENOMEM;
+
+			if (inode) {
+				write_lock(&entries_lock);
+
+				e->dentry = dget(dentry);
+				inode->u.generic_ip = e;
+				inode->i_fop = &bm_entry_operations;
+				d_instantiate(dentry, inode);
+
+				list_add(&e->list, &entries);
+				write_unlock(&entries_lock);
+
+				err = 0;
+			}
 		}
-	} else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) {
-		if (data)
-			clear_entry((long) data);
-		else
-			clear_entries();
-	} else {
-		res = -EINVAL;
+		up(&root->d_inode->i_zombie);
+		dput(dentry);
 	}
-	return res;
+	up(&root->d_inode->i_sem);
+	dput(root);
+
+	if (err) {
+		kfree(e);
+		return -EINVAL;
+	}
+	return count;
 }
 
-/*
- * Remove the /proc-dir entries of one binfmt
- */
-static void entry_proc_cleanup(struct binfmt_entry *e)
+static struct file_operations bm_register_operations = {
+	write:		bm_register_write,
+};
+
+/* /status */
+
+static ssize_t
+bm_status_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
 {
-	remove_proc_entry(e->proc_name, bm_dir);
+	char *s = enabled ? "enabled" : "disabled";
+	int len = strlen(s);
+	loff_t pos = *ppos;
+
+	if (pos < 0)
+		return -EINVAL;
+	if (pos >= len)
+		return 0;
+	if (len < pos + nbytes)
+		nbytes = len - pos;
+	if (copy_to_user(buf, s + pos, nbytes))
+		return -EFAULT;
+	*ppos = pos + nbytes;
+	return nbytes;
+}
+
+static ssize_t bm_status_write(struct file * file, const char * buffer,
+		size_t count, loff_t *ppos)
+{
+	int res = parse_command(buffer, count);
+	struct dentry *root;
+
+	switch (res) {
+		case 1: enabled = 0; break;
+		case 2: enabled = 1; break;
+		case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root);
+			down(&root->d_inode->i_sem);
+			down(&root->d_inode->i_zombie);
+
+			while (!list_empty(&entries))
+				kill_node(list_entry(entries.next, Node, list));
+
+			up(&root->d_inode->i_zombie);
+			up(&root->d_inode->i_sem);
+			dput(root);
+		default: return res;
+	}
+	return count;
 }
 
-/*
- * Create the /proc-dir entry for binfmt
- */
-static int entry_proc_setup(struct binfmt_entry *e)
+static struct file_operations bm_status_operations = {
+	read:		bm_status_read,
+	write:		bm_status_write,
+};
+
+/* / */
+
+static struct dentry * bm_lookup(struct inode *dir, struct dentry *dentry)
+{
+	d_add(dentry, NULL);
+	return NULL;
+}
+
+static struct file_operations bm_dir_operations = {
+	read:		generic_read_dir,
+	readdir:	dcache_readdir,
+};
+
+static struct inode_operations bm_dir_inode_operations = {
+	lookup:		bm_lookup,
+};
+
+/* Superblock handling */
+
+static int bm_statfs(struct super_block *sb, struct statfs *buf)
 {
-	if (!(e->proc_dir = create_proc_entry(e->proc_name,
-			 	S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
-	{
-		printk(KERN_WARNING "Unable to create /proc entry.\n");
-		return -ENOENT;
-	}
-	e->proc_dir->data = (void *) (e->id);
-	e->proc_dir->read_proc = proc_read_status;
-	e->proc_dir->write_proc = proc_write_status;
+	buf->f_type = sb->s_magic;
+	buf->f_bsize = PAGE_CACHE_SIZE;
+	buf->f_namelen = 255;
 	return 0;
 }
 
-static int __init init_misc_binfmt(void)
+static struct super_operations s_ops = {
+	statfs:		bm_statfs,
+	put_inode:	force_delete,
+	clear_inode:	bm_clear_inode,
+};
+
+static struct super_block *bm_read_super(struct super_block * sb, void * data, int silent)
 {
-	int error = -ENOENT;
-	struct proc_dir_entry *status = NULL, *reg;
+	struct qstr names[2] = {{name:"status"}, {name:"register"}};
+	struct inode * inode;
+	struct dentry * dentry[3];
+	int i;
+
+	for (i=0; i<sizeof(names)/sizeof(names[0]); i++) {
+		names[i].len = strlen(names[i].name);
+		names[i].hash = full_name_hash(names[i].name, names[i].len);
+	}
 
-	bm_dir = proc_mkdir("sys/fs/binfmt_misc", NULL); /* WTF??? */
-	if (!bm_dir)
-		goto out;
-	bm_dir->owner = THIS_MODULE;
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic = 0x42494e4d;
+	sb->s_op = &s_ops;
+
+	inode = bm_get_inode(sb, S_IFDIR | 0755);
+	if (!inode)
+		return NULL;
+	inode->i_op = &bm_dir_inode_operations;
+	inode->i_fop = &bm_dir_operations;
+	dentry[0] = d_alloc_root(inode);
+	if (!dentry[0]) {
+		iput(inode);
+		return NULL;
+	}
+	dentry[1] = d_alloc(dentry[0], &names[0]);
+	if (!dentry[1])
+		goto out1;
+	dentry[2] = d_alloc(dentry[0], &names[1]);
+	if (!dentry[2])
+		goto out2;
+	inode = bm_get_inode(sb, S_IFREG | 0644);
+	if (!inode)
+		goto out3;
+	inode->i_fop = &bm_status_operations;
+	d_add(dentry[1], inode);
+	inode = bm_get_inode(sb, S_IFREG | 0400);
+	if (!inode)
+		goto out3;
+	inode->i_fop = &bm_register_operations;
+	d_add(dentry[2], inode);
+
+	sb->s_root = dentry[0];
+	return sb;
+
+out3:
+	dput(dentry[2]);
+out2:
+	dput(dentry[1]);
+out1:
+	dput(dentry[0]);
+	return NULL;
+}
+
+static struct linux_binfmt misc_format = {
+	NULL, THIS_MODULE, load_misc_binary, NULL, NULL, 0
+};
 
-	status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR,
-					bm_dir);
-	if (!status)
-		goto cleanup_bm;
-	status->read_proc = proc_read_status;
-	status->write_proc = proc_write_status;
-
-	reg = create_proc_entry("register", S_IFREG | S_IWUSR, bm_dir);
-	if (!reg)
-		goto cleanup_status;
-	reg->write_proc = proc_write_register;
+static DECLARE_FSTYPE(bm_fs_type, "binfmt_misc", bm_read_super, FS_SINGLE|FS_LITTER);
 
-	error = register_binfmt(&misc_format);
-out:
-	return error;
+static struct vfsmount *bm_mnt;
 
-cleanup_status:
-	remove_proc_entry("status", bm_dir);
-cleanup_bm:
-	remove_proc_entry("sys/fs/binfmt_misc", NULL);
-	goto out;
+static int __init init_misc_binfmt(void)
+{
+	int err = register_filesystem(&bm_fs_type);
+	if (!err) {
+		bm_mnt = kern_mount(&bm_fs_type);
+		err = PTR_ERR(bm_mnt);
+		if (IS_ERR(bm_mnt))
+			unregister_filesystem(&bm_fs_type);
+		else {
+			err = register_binfmt(&misc_format);
+			if (err) {
+				unregister_filesystem(&bm_fs_type);
+				kern_umount(bm_mnt);
+			}
+		}
+	}
+	return err;
 }
 
 static void __exit exit_misc_binfmt(void)
 {
 	unregister_binfmt(&misc_format);
-	remove_proc_entry("register", bm_dir);
-	remove_proc_entry("status", bm_dir);
-	clear_entries();
-	remove_proc_entry("sys/fs/binfmt_misc", NULL);
+	unregister_filesystem(&bm_fs_type);
+	kern_umount(bm_mnt);
 }
 
 EXPORT_NO_SYMBOLS;
 
 module_init(init_misc_binfmt);
 module_exit(exit_misc_binfmt);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.4.12/linux/fs/block_dev.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/block_dev.c	Thu Oct 11 08:32:35 2001
@@ -24,29 +24,6 @@
 
 #define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
 
-static inline unsigned int blksize_bits(unsigned int size)
-{
-	unsigned int bits = 8;
-	do {
-		bits++;
-		size >>= 1;
-	} while (size > 256);
-	return bits;
-}
-
-static inline unsigned int block_size(kdev_t dev)
-{
-	int retval = BLOCK_SIZE;
-	int major = MAJOR(dev);
-
-	if (blksize_size[major]) {
-		int minor = MINOR(dev);
-		if (blksize_size[major][minor])
-			retval = blksize_size[major][minor];
-	}
-	return retval;
-}
-
 static unsigned long max_block(kdev_t dev)
 {
 	unsigned int retval = ~0U;
diff -u --recursive --new-file v2.4.12/linux/fs/buffer.c linux/fs/buffer.c
--- v2.4.12/linux/fs/buffer.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/buffer.c	Sun Oct 21 10:21:23 2001
@@ -480,10 +480,12 @@
 
 static __inline__ void __hash_unlink(struct buffer_head *bh)
 {
-	if (bh->b_pprev) {
-		if (bh->b_next)
-			bh->b_next->b_pprev = bh->b_pprev;
-		*(bh->b_pprev) = bh->b_next;
+	struct buffer_head **pprev = bh->b_pprev;
+	if (pprev) {
+		struct buffer_head *next = bh->b_next;
+		if (next)
+			next->b_pprev = pprev;
+		*pprev = next;
 		bh->b_pprev = NULL;
 	}
 }
@@ -506,16 +508,22 @@
 	size_buffers_type[blist] += bh->b_size;
 }
 
-static void __remove_from_lru_list(struct buffer_head * bh, int blist)
+static void __remove_from_lru_list(struct buffer_head * bh)
 {
-	if (bh->b_prev_free || bh->b_next_free) {
-		bh->b_prev_free->b_next_free = bh->b_next_free;
-		bh->b_next_free->b_prev_free = bh->b_prev_free;
-		if (lru_list[blist] == bh)
-			lru_list[blist] = bh->b_next_free;
-		if (lru_list[blist] == bh)
-			lru_list[blist] = NULL;
-		bh->b_next_free = bh->b_prev_free = NULL;
+	struct buffer_head *next = bh->b_next_free;
+	if (next) {
+		struct buffer_head *prev = bh->b_prev_free;
+		int blist = bh->b_list;
+
+		prev->b_next_free = next;
+		next->b_prev_free = prev;
+		if (lru_list[blist] == bh) {
+			if (next == bh)
+				next = NULL;
+			lru_list[blist] = next;
+		}
+		bh->b_next_free = NULL;
+		bh->b_prev_free = NULL;
 		nr_buffers_type[blist]--;
 		size_buffers_type[blist] -= bh->b_size;
 	}
@@ -526,7 +534,7 @@
 static void __remove_from_queues(struct buffer_head *bh)
 {
 	__hash_unlink(bh);
-	__remove_from_lru_list(bh, bh->b_list);
+	__remove_from_lru_list(bh);
 }
 
 struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
@@ -1095,7 +1103,7 @@
 	if (buffer_dirty(bh))
 		dispose = BUF_DIRTY;
 	if (dispose != bh->b_list) {
-		__remove_from_lru_list(bh, bh->b_list);
+		__remove_from_lru_list(bh);
 		bh->b_list = dispose;
 		if (dispose == BUF_CLEAN)
 			remove_inode_queue(bh);
@@ -1123,13 +1131,12 @@
 }
 
 /*
- * bforget() is like brelse(), except it puts the buffer on the
- * free list if it can.. We can NOT free the buffer if:
- *  - there are other users of it
- *  - it is locked and thus can have active IO
+ * bforget() is like brelse(), except it discards any
+ * potentially dirty data.
  */
 void __bforget(struct buffer_head * buf)
 {
+	mark_buffer_clean(buf);
 	__brelse(buf);
 }
 
@@ -1422,10 +1429,7 @@
 		mark_buffer_clean(old_bh);
 		wait_on_buffer(old_bh);
 		clear_bit(BH_Req, &old_bh->b_state);
-		/* Here we could run brelse or bforget. We use
-		   bforget because it will try to put the buffer
-		   in the freelist. */
-		__bforget(old_bh);
+		__brelse(old_bh);
 	}
 }
 
diff -u --recursive --new-file v2.4.12/linux/fs/devfs/util.c linux/fs/devfs/util.c
--- v2.4.12/linux/fs/devfs/util.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/devfs/util.c	Thu Oct 11 09:43:30 2001
@@ -52,7 +52,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/vmalloc.h>
 
 #include <asm/bitops.h>
diff -u --recursive --new-file v2.4.12/linux/fs/ext2/Makefile linux/fs/ext2/Makefile
--- v2.4.12/linux/fs/ext2/Makefile	Fri Dec 29 14:07:23 2000
+++ linux/fs/ext2/Makefile	Thu Oct 11 08:05:18 2001
@@ -9,7 +9,7 @@
 
 O_TARGET := ext2.o
 
-obj-y    := acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+obj-y    := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
 		ioctl.o namei.o super.o symlink.o
 obj-m    := $(O_TARGET)
 
diff -u --recursive --new-file v2.4.12/linux/fs/ext2/acl.c linux/fs/ext2/acl.c
--- v2.4.12/linux/fs/ext2/acl.c	Tue Dec 14 11:16:22 1999
+++ linux/fs/ext2/acl.c	Wed Dec 31 16:00:00 1969
@@ -1,17 +0,0 @@
-/*
- * linux/fs/ext2/acl.c
- *
- * Copyright (C) 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- */
-
-#include <linux/fs.h>
-#include <linux/sched.h>
-
-
-/*
- * This file will contain the Access Control Lists management for the
- * second extended file system.
- */
diff -u --recursive --new-file v2.4.12/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v2.4.12/linux/fs/ext2/file.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/ext2/file.c	Thu Oct 11 08:05:18 2001
@@ -22,51 +22,6 @@
 #include <linux/ext2_fs.h>
 #include <linux/sched.h>
 
-static loff_t ext2_file_lseek(struct file *, loff_t, int);
-static int ext2_open_file (struct inode *, struct file *);
-
-#define EXT2_MAX_SIZE(bits)							\
-	(((EXT2_NDIR_BLOCKS + (1LL << (bits - 2)) + 				\
-	   (1LL << (bits - 2)) * (1LL << (bits - 2)) + 				\
-	   (1LL << (bits - 2)) * (1LL << (bits - 2)) * (1LL << (bits - 2))) * 	\
-	  (1LL << bits)) - 1)
-
-static long long ext2_max_sizes[] = {
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-EXT2_MAX_SIZE(10), EXT2_MAX_SIZE(11), EXT2_MAX_SIZE(12), EXT2_MAX_SIZE(13)
-};
-
-/*
- * Make sure the offset never goes beyond the 32-bit mark..
- */
-static loff_t ext2_file_lseek(
-	struct file *file,
-	loff_t offset,
-	int origin)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-
-	switch (origin) {
-		case 2:
-			offset += inode->i_size;
-			break;
-		case 1:
-			offset += file->f_pos;
-	}
-	if (offset<0)
-		return -EINVAL;
-	if (((unsigned long long) offset >> 32) != 0) {
-		if (offset > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(inode->i_sb)])
-			return -EINVAL;
-	} 
-	if (offset != file->f_pos) {
-		file->f_pos = offset;
-		file->f_reada = 0;
-		file->f_version = ++event;
-	}
-	return offset;
-}
-
 /*
  * Called when an inode is released. Note that this is different
  * from ext2_open_file: open gets called at every open, but release
@@ -80,30 +35,16 @@
 }
 
 /*
- * Called when an inode is about to be open.
- * We use this to disallow opening RW large files on 32bit systems if
- * the caller didn't specify O_LARGEFILE.  On 64bit systems we force
- * on this flag in sys_open.
- */
-static int ext2_open_file (struct inode * inode, struct file * filp)
-{
-	if (!(filp->f_flags & O_LARGEFILE) &&
-	    inode->i_size > 0x7FFFFFFFLL)
-		return -EFBIG;
-	return 0;
-}
-
-/*
  * We have mostly NULL's here: the current defaults are ok for
  * the ext2 filesystem.
  */
 struct file_operations ext2_file_operations = {
-	llseek:		ext2_file_lseek,
+	llseek:		generic_file_llseek,
 	read:		generic_file_read,
 	write:		generic_file_write,
 	ioctl:		ext2_ioctl,
 	mmap:		generic_file_mmap,
-	open:		ext2_open_file,
+	open:		generic_file_open,
 	release:	ext2_release_file,
 	fsync:		ext2_sync_file,
 };
diff -u --recursive --new-file v2.4.12/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.4.12/linux/fs/ext2/inode.c	Thu Oct 11 08:02:26 2001
+++ linux/fs/ext2/inode.c	Thu Oct 11 09:43:38 2001
@@ -29,6 +29,12 @@
 #include <linux/sched.h>
 #include <linux/highuid.h>
 #include <linux/quotaops.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("Remy Card and others");
+MODULE_DESCRIPTION("Second Extended Filesystem");
+MODULE_LICENSE("GPL");
+
 
 static int ext2_update_inode(struct inode * inode, int do_sync);
 
@@ -592,7 +598,7 @@
 	sync_page: block_sync_page,
 	prepare_write: ext2_prepare_write,
 	commit_write: generic_commit_write,
-	bmap: ext2_bmap,
+	bmap: ext2_bmap
 };
 
 /*
diff -u --recursive --new-file v2.4.12/linux/fs/fat/cache.c linux/fs/fat/cache.c
--- v2.4.12/linux/fs/fat/cache.c	Thu May 24 15:36:33 2001
+++ linux/fs/fat/cache.c	Fri Oct 12 13:48:42 2001
@@ -15,8 +15,6 @@
 #include <linux/stat.h>
 #include <linux/fat_cvf.h>
 
-#include "msbuffer.h"
-
 #if 0
 #  define PRINTK(x) printk x
 #else
diff -u --recursive --new-file v2.4.12/linux/fs/fat/dir.c linux/fs/fat/dir.c
--- v2.4.12/linux/fs/fat/dir.c	Mon Aug 27 12:41:46 2001
+++ linux/fs/fat/dir.c	Fri Oct 12 13:48:42 2001
@@ -10,12 +10,9 @@
  *  VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
  *  Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
  *  Rewritten for constant inumbers. Plugged buffer overrun in readdir(). AV
- *  Short name translation 1999 by Wolfram Pienkoss <wp@bszh.de>
+ *  Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de>
  */
 
-#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
-
-#include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/msdos_fs.h>
 #include <linux/nls.h>
@@ -30,8 +27,6 @@
 
 #include <asm/uaccess.h>
 
-#include "msbuffer.h"
-
 #define PRINTK(X)
 
 struct file_operations fat_dir_operations = {
@@ -163,6 +158,27 @@
 	return 0;
 }
 
+static inline int
+fat_shortname2uni(struct nls_table *nls, char *buf, int buf_size,
+		  wchar_t *uni_buf, unsigned short opt, int lower)
+{
+	int len = 0;
+
+	if (opt & VFAT_SFN_DISPLAY_LOWER)
+		len =  fat_short2lower_uni(nls, buf, buf_size, uni_buf);
+	else if (opt & VFAT_SFN_DISPLAY_WIN95)
+		len = fat_short2uni(nls, buf, buf_size, uni_buf);
+	else if (opt & VFAT_SFN_DISPLAY_WINNT) {
+		if (lower)
+			len = fat_short2lower_uni(nls, buf, buf_size, uni_buf);
+		else 
+			len = fat_short2uni(nls, buf, buf_size, uni_buf);
+	} else
+		len = fat_short2uni(nls, buf, buf_size, uni_buf);
+
+	return len;
+}
+
 /*
  * Return values: negative -> error, 0 -> not found, positive -> found,
  * value is the total amount of slots, including the shortname entry.
@@ -176,11 +192,12 @@
 	struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
 	struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
 	wchar_t bufuname[14];
-	unsigned char xlate_len, long_slots, *unicode = NULL;
+	unsigned char xlate_len, long_slots;
+	wchar_t *unicode = NULL;
 	char work[8], bufname[260];	/* 256 + 4 */
 	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
 	int utf8 = MSDOS_SB(sb)->options.utf8;
-	int nocase = MSDOS_SB(sb)->options.nocase;
+	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
 	int ino, chl, i, j, last_u, res = 0;
 	loff_t cpos = 0;
 
@@ -197,7 +214,6 @@
 			continue;
 		if (de->attr == ATTR_EXT) {
 			struct msdos_dir_slot *ds;
-			int offset;
 			unsigned char id;
 			unsigned char slot;
 			unsigned char slots;
@@ -205,7 +221,7 @@
 			unsigned char alias_checksum;
 
 			if (!unicode) {
-				unicode = (unsigned char *)
+				unicode = (wchar_t *)
 					__get_free_page(GFP_KERNEL);
 				if (!unicode) {
 					fat_brelse(sb, bh);
@@ -214,7 +230,6 @@
 			}
 parse_long:
 			slots = 0;
-			offset = 0;
 			ds = (struct msdos_dir_slot *) de;
 			id = ds->id;
 			if (!(id & 0x40))
@@ -227,16 +242,16 @@
 
 			slot = slots;
 			while (1) {
+				int offset;
+
 				slot--;
-				offset = slot * 26;
-				memcpy(&unicode[offset], ds->name0_4, 10);
-				memcpy(&unicode[offset+10], ds->name5_10, 12);
-				memcpy(&unicode[offset+22], ds->name11_12, 4);
-				offset += 26;
+				offset = slot * 13;
+				fat16_towchar(unicode + offset, ds->name0_4, 5);
+				fat16_towchar(unicode + offset + 5, ds->name5_10, 6);
+				fat16_towchar(unicode + offset + 11, ds->name11_12, 2);
 
 				if (ds->id & 0x40) {
-					unicode[offset] = 0;
-					unicode[offset+1] = 0;
+					unicode[offset + 13] = 0;
 				}
 				if (fat_get_entry(inode,&cpos,&bh,&de,&ino)<0)
 					goto EODir;
@@ -271,10 +286,9 @@
 		}
 		for (i = 0, j = 0, last_u = 0; i < 8;) {
 			if (!work[i]) break;
-			if (nocase)
-				chl = fat_short2uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
-			else
-				chl = fat_short2lower_uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
+			chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
+						&bufuname[j++], opt_shortname,
+						de->lcase & CASE_LOWER_BASE);
 			if (chl <= 1) {
 				if (work[i] != ' ')
 					last_u = j;
@@ -287,10 +301,9 @@
 		fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
 		for (i = 0; i < 3;) {
 			if (!de->ext[i]) break;
-			if (nocase)
-				chl = fat_short2uni(nls_disk, &de->ext[i], 3 - i, &bufuname[j++]);
-			else
-				chl = fat_short2lower_uni(nls_disk, &de->ext[i], 3 - i, &bufuname[j++]);
+			chl = fat_shortname2uni(nls_disk, &de->ext[i], 3 - i,
+						&bufuname[j++], opt_shortname,
+						de->lcase & CASE_LOWER_EXT);
 			if (chl <= 1) {
 				if (de->ext[i] != ' ')
 					last_u = j;
@@ -314,8 +327,8 @@
 
 		if (long_slots) {
 			xlate_len = utf8
-				?utf8_wcstombs(bufname, (wchar_t *) unicode, sizeof(bufname))
-				:uni16_to_x8(bufname, (wchar_t *) unicode, uni_xlate, nls_io);
+				?utf8_wcstombs(bufname, unicode, sizeof(bufname))
+				:uni16_to_x8(bufname, unicode, uni_xlate, nls_io);
 			if (xlate_len != name_len)
 				continue;
 			if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
@@ -346,13 +359,15 @@
 	struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
 	struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
 	wchar_t bufuname[14];
-	unsigned char long_slots, *unicode = NULL;
+	unsigned char long_slots;
+	wchar_t *unicode = NULL;
 	char c, work[8], bufname[56], *ptname = bufname;
 	unsigned long lpos, dummy, *furrfu = &lpos;
 	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
 	int isvfat = MSDOS_SB(sb)->options.isvfat;
 	int utf8 = MSDOS_SB(sb)->options.utf8;
 	int nocase = MSDOS_SB(sb)->options.nocase;
+	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
 	int ino, inum, chi, chl, i, i2, j, last, last_u, dotoffset = 0;
 	loff_t cpos;
 
@@ -394,7 +409,6 @@
 
 	if (isvfat && de->attr == ATTR_EXT) {
 		struct msdos_dir_slot *ds;
-		int offset;
 		unsigned char id;
 		unsigned char slot;
 		unsigned char slots;
@@ -402,7 +416,7 @@
 		unsigned char alias_checksum;
 
 		if (!unicode) {
-			unicode = (unsigned char *)
+			unicode = (wchar_t *)
 				__get_free_page(GFP_KERNEL);
 			if (!unicode) {
 				filp->f_pos = cpos;
@@ -412,7 +426,6 @@
 		}
 ParseLong:
 		slots = 0;
-		offset = 0;
 		ds = (struct msdos_dir_slot *) de;
 		id = ds->id;
 		if (!(id & 0x40))
@@ -425,16 +438,16 @@
 
 		slot = slots;
 		while (1) {
+			int offset;
+
 			slot--;
-			offset = slot * 26;
-			memcpy(&unicode[offset], ds->name0_4, 10);
-			memcpy(&unicode[offset+10], ds->name5_10, 12);
-			memcpy(&unicode[offset+22], ds->name11_12, 4);
-			offset += 26;
+			offset = slot * 13;
+			fat16_towchar(unicode + offset, ds->name0_4, 5);
+			fat16_towchar(unicode + offset + 5, ds->name5_10, 6);
+			fat16_towchar(unicode + offset + 11, ds->name11_12, 2);
 
 			if (ds->id & 0x40) {
-				unicode[offset] = 0;
-				unicode[offset+1] = 0;
+				unicode[offset + 13] = 0;
 			}
 			if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
 				goto EODir;
@@ -474,10 +487,9 @@
 	}
 	for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) {
 		if (!(c = work[i])) break;
-		if (nocase)
-			chl = fat_short2uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
-		else
-			chl = fat_short2lower_uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
+		chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
+					&bufuname[j++], opt_shortname,
+					de->lcase & CASE_LOWER_BASE);
 		if (chl <= 1) {
 			ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
 			if (c != ' ') {
@@ -498,10 +510,9 @@
 	ptname[i++] = '.';
 	for (i2 = 0; i2 < 3;) {
 		if (!(c = de->ext[i2])) break;
-		if (nocase)
-			chl = fat_short2uni(nls_disk, &de->ext[i2], 3 - i2, &bufuname[j++]);
-		else
-			chl = fat_short2lower_uni(nls_disk, &de->ext[i2], 3 - i2, &bufuname[j++]);
+		chl = fat_shortname2uni(nls_disk, &de->ext[i2], 3 - i2,
+					&bufuname[j++], opt_shortname,
+					de->lcase & CASE_LOWER_EXT);
 		if (chl <= 1) {
 			i2++;
 			ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
@@ -553,8 +564,8 @@
 	} else {
 		char longname[275];
 		int long_len = utf8
-			? utf8_wcstombs(longname, (wchar_t *) unicode, sizeof(longname))
-			: uni16_to_x8(longname, (wchar_t *) unicode, uni_xlate,
+			? utf8_wcstombs(longname, unicode, sizeof(longname))
+			: uni16_to_x8(longname, unicode, uni_xlate,
 				      nls_io);
 		if (both) {
 			memcpy(&longname[long_len+1], bufname, i);
diff -u --recursive --new-file v2.4.12/linux/fs/fat/fatfs_syms.c linux/fs/fat/fatfs_syms.c
--- v2.4.12/linux/fs/fat/fatfs_syms.c	Wed Apr 18 11:49:12 2001
+++ linux/fs/fat/fatfs_syms.c	Fri Oct 12 13:48:42 2001
@@ -4,8 +4,7 @@
  * Exported kernel symbols for the low-level FAT-based fs support.
  *
  */
-#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
-#include <linux/version.h>
+
 #include <linux/module.h>
 #include <linux/init.h>
 
@@ -13,8 +12,6 @@
 #include <linux/msdos_fs.h>
 #include <linux/fat_cvf.h>
 
-#include "msbuffer.h"
-
 EXPORT_SYMBOL(fat_new_dir);
 EXPORT_SYMBOL(fat_get_block);
 EXPORT_SYMBOL(fat_clear_inode);
@@ -23,7 +20,6 @@
 EXPORT_SYMBOL(fat__get_entry);
 EXPORT_SYMBOL(fat_mark_buffer_dirty);
 EXPORT_SYMBOL(fat_notify_change);
-EXPORT_SYMBOL(fat_parent_ino);
 EXPORT_SYMBOL(fat_put_super);
 EXPORT_SYMBOL(fat_attach);
 EXPORT_SYMBOL(fat_detach);
diff -u --recursive --new-file v2.4.12/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.4.12/linux/fs/fat/inode.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/fat/inode.c	Fri Oct 12 13:48:42 2001
@@ -10,17 +10,14 @@
  *  	Max Cohan: Fixed invalid FSINFO offset when info_sector is 0
  */
 
-#include <linux/config.h>
-#include <linux/version.h>
-#define __NO_VERSION__
 #include <linux/module.h>
-
 #include <linux/msdos_fs.h>
 #include <linux/nls.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/bitops.h>
 #include <linux/major.h>
 #include <linux/blkdev.h>
 #include <linux/fs.h>
@@ -28,11 +25,8 @@
 #include <linux/locks.h>
 #include <linux/fat_cvf.h>
 #include <linux/slab.h>
-#include <linux/bitops.h>
 #include <linux/smp_lock.h>
 
-#include "msbuffer.h"
-
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
@@ -81,9 +75,10 @@
 static struct list_head fat_inode_hashtable[FAT_HASH_SIZE];
 spinlock_t fat_inode_lock = SPIN_LOCK_UNLOCKED;
 
-void fat_hash_init(void) {
+void fat_hash_init(void)
+{
 	int i;
-	for(i=0;i<FAT_HASH_SIZE;i++) {
+	for(i = 0; i < FAT_HASH_SIZE; i++) {
 		INIT_LIST_HEAD(&fat_inode_hashtable[i]);
 	}
 }
@@ -91,19 +86,21 @@
 static inline unsigned long fat_hash(struct super_block *sb, int i_pos)
 {
 	unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb;
-	tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS*2);
+	tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2);
 	return tmp & FAT_HASH_MASK;
 }
 
-void fat_attach(struct inode *inode, int i_pos) {
+void fat_attach(struct inode *inode, int i_pos)
+{
 	spin_lock(&fat_inode_lock);
 	MSDOS_I(inode)->i_location = i_pos;
 	list_add(&MSDOS_I(inode)->i_fat_hash,
-		fat_inode_hashtable+fat_hash(inode->i_sb, i_pos));
+		fat_inode_hashtable + fat_hash(inode->i_sb, i_pos));
 	spin_unlock(&fat_inode_lock);
 }
 
-void fat_detach(struct inode *inode) {
+void fat_detach(struct inode *inode)
+{
 	spin_lock(&fat_inode_lock);
 	MSDOS_I(inode)->i_location = 0;
 	list_del(&MSDOS_I(inode)->i_fat_hash);
@@ -111,13 +108,15 @@
 	spin_unlock(&fat_inode_lock);
 }
 
-struct inode *fat_iget(struct super_block *sb, int i_pos) {
+struct inode *fat_iget(struct super_block *sb, int i_pos)
+{
 	struct list_head *p = fat_inode_hashtable + fat_hash(sb, i_pos);
 	struct list_head *walk;
 	struct msdos_inode_info *i;
 	struct inode *inode = NULL;
+
 	spin_lock(&fat_inode_lock);
-	for(walk=p->next;walk!=p;walk=walk->next) {
+	list_for_each(walk, p) {
 		i = list_entry(walk, struct msdos_inode_info, i_fat_hash);
 		if (i->i_fat_inode->i_sb != sb)
 			continue;
@@ -222,6 +221,7 @@
 	opts->quiet = opts->sys_immutable = opts->dotsOK = opts->showexec = 0;
 	opts->codepage = 0;
 	opts->nocase = 0;
+	opts->shortname = 0;
 	opts->utf8 = 0;
 	opts->iocharset = NULL;
 	*debug = *fat = 0;
@@ -330,16 +330,22 @@
 		}
 		else if (!strcmp(this_char,"iocharset") && value) {
 			p = value;
-			while (*value && *value != ',') value++;
+			while (*value && *value != ',')
+				value++;
 			len = value - p;
-			if (len) { 
-				char * buffer = kmalloc(len+1, GFP_KERNEL);
-				if (buffer) {
+			if (len) {
+				char *buffer;
+
+				if (opts->iocharset != NULL) {
+					kfree(opts->iocharset);
+					opts->iocharset = NULL;
+				}
+				buffer = kmalloc(len + 1, GFP_KERNEL);
+				if (buffer != NULL) {
 					opts->iocharset = buffer;
 					memcpy(buffer, p, len);
 					buffer[len] = 0;
-					printk("MSDOS FS: IO charset %s\n",
-						buffer);
+					printk("MSDOS FS: IO charset %s\n", buffer);
 				} else
 					ret = 0;
 			}
@@ -647,7 +653,7 @@
 		fsinfo_offset =
 			(sbi->fsinfo_sector * logical_sector_size) % hard_blksize;
 		fsinfo_bh = bh;
-		if (bh->b_blocknr != fsinfo_block) {
+		if (fsinfo_block != 0) {
 			fsinfo_bh = bread(sb->s_dev, fsinfo_block, hard_blksize);
 			if (fsinfo_bh == NULL) {
 				printk("FAT: bread failed, FSINFO block"
@@ -667,7 +673,7 @@
 			sbi->free_clusters = CF_LE_L(fsinfo->free_clusters);
 		}
 
-		if (bh->b_blocknr != fsinfo_block)
+		if (fsinfo_block != 0)
 			brelse(fsinfo_bh);
 	} else {
 		fat32 = 0;
@@ -705,6 +711,9 @@
 	}
 	brelse(bh);
 
+	if (error)
+		goto out_invalid;
+
 	sb->s_blocksize = logical_sector_size;
 	sb->s_blocksize_bits = ffs(logical_sector_size) - 1;
 	set_blocksize(sb->s_dev, sb->s_blocksize);
@@ -740,7 +749,6 @@
 
 	sb->s_magic = MSDOS_SUPER_MAGIC;
 	/* set up enough so that it can read an inode */
-	init_waitqueue_head(&sbi->fat_wait);
 	init_MUTEX(&sbi->fat_lock);
 	sbi->prev_free = 0;
 
@@ -957,7 +965,7 @@
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *raw_entry;
-	int i_pos;
+	unsigned int i_pos;
 
 retry:
 	i_pos = MSDOS_I(inode)->i_location;
@@ -1036,7 +1044,9 @@
 	if (error)
 		return MSDOS_SB(sb)->options.quiet ? 0 : error;
 
-	inode_setattr(inode, attr);
+	error = inode_setattr(inode, attr);
+	if (error)
+		return error;
 
 	if (S_ISDIR(inode->i_mode))
 		inode->i_mode |= S_IXUGO;
@@ -1046,3 +1056,4 @@
 	    ~MSDOS_SB(sb)->options.fs_umask;
 	return 0;
 }
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.12/linux/fs/fat/misc.c linux/fs/fat/misc.c
--- v2.4.12/linux/fs/fat/misc.c	Thu May 24 15:36:34 2001
+++ linux/fs/fat/misc.c	Fri Oct 12 13:48:42 2001
@@ -2,6 +2,8 @@
  *  linux/fs/fat/misc.c
  *
  *  Written 1992,1993 by Werner Almesberger
+ *  22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980
+ *		 and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru)
  */
 
 #include <linux/fs.h>
@@ -12,8 +14,6 @@
 #include <linux/string.h>
 #include <linux/stat.h>
 
-#include "msbuffer.h"
-
 #if 0
 #  define PRINTK(x)	printk x
 #else
@@ -75,30 +75,11 @@
 	}
 }
 
-
-/* File creation lock. This is system-wide to avoid deadlocks in rename. */
-/* (rename might deadlock before detecting cross-FS moves.) */
-
-static DECLARE_MUTEX(creation_lock);
-
-void fat_lock_creation(void)
-{
-	down(&creation_lock);
-}
-
-
-void fat_unlock_creation(void)
-{
-	up(&creation_lock);
-}
-
-
 void lock_fat(struct super_block *sb)
 {
 	down(&(MSDOS_SB(sb)->fat_lock));
 }
 
-
 void unlock_fat(struct super_block *sb)
 {
 	up(&(MSDOS_SB(sb)->fat_lock));
@@ -132,39 +113,44 @@
 }
 
 /*
- * fat_add_cluster tries to allocate a new cluster and adds it to the file
- * represented by inode. The cluster is zero-initialized.
+ * fat_add_cluster tries to allocate a new cluster and adds it to the
+ * file represented by inode.
  */
-
-/* not a directory */
-
 int fat_add_cluster(struct inode *inode)
 {
 	struct super_block *sb = inode->i_sb;
-	int count,nr,limit,last,curr,file_cluster;
+	int count, nr, limit, last, curr, file_cluster;
+	int cluster_size = MSDOS_SB(sb)->cluster_size;
 	int res = -ENOSPC;
-
-	if (!MSDOS_SB(sb)->free_clusters) return res;
+	
 	lock_fat(sb);
+	
+	if (MSDOS_SB(sb)->free_clusters == 0) {
+		unlock_fat(sb);
+		return res;
+	}
 	limit = MSDOS_SB(sb)->clusters;
 	nr = limit; /* to keep GCC happy */
 	for (count = 0; count < limit; count++) {
-		nr = ((count+MSDOS_SB(sb)->prev_free) % limit)+2;
-		if (fat_access(sb,nr,-1) == 0) break;
+		nr = ((count + MSDOS_SB(sb)->prev_free) % limit) + 2;
+		if (fat_access(sb, nr, -1) == 0)
+			break;
 	}
-	MSDOS_SB(sb)->prev_free = (count+MSDOS_SB(sb)->prev_free+1) % limit;
 	if (count >= limit) {
 		MSDOS_SB(sb)->free_clusters = 0;
 		unlock_fat(sb);
 		return res;
 	}
-	fat_access(sb,nr,EOF_FAT(sb));
+	
+	MSDOS_SB(sb)->prev_free = (count + MSDOS_SB(sb)->prev_free + 1) % limit;
+	fat_access(sb, nr, EOF_FAT(sb));
 	if (MSDOS_SB(sb)->free_clusters != -1)
 		MSDOS_SB(sb)->free_clusters--;
 	if (MSDOS_SB(sb)->fat_bits == 32)
 		fat_clusters_flush(sb);
+	
 	unlock_fat(sb);
-
+	
 	/* We must locate the last cluster of the file to add this
 	   new one (nr) to the end of the link list (the FAT).
 	   
@@ -177,12 +163,12 @@
 	*/
 	last = file_cluster = 0;
 	if ((curr = MSDOS_I(inode)->i_start) != 0) {
-		fat_cache_lookup(inode,INT_MAX,&last,&curr);
+		fat_cache_lookup(inode, INT_MAX, &last, &curr);
 		file_cluster = last;
 		while (curr && curr != -1){
 			file_cluster++;
 			if (!(curr = fat_access(sb, last = curr,-1))) {
-				fat_fs_panic(sb,"File without EOF");
+				fat_fs_panic(sb, "File without EOF");
 				return res;
 			}
 		}
@@ -195,94 +181,34 @@
 		MSDOS_I(inode)->i_logstart = nr;
 		mark_inode_dirty(inode);
 	}
+	if (file_cluster
+	    != inode->i_blocks / cluster_size / (sb->s_blocksize / 512)) {
+		printk ("file_cluster badly computed!!! %d <> %ld\n",
+			file_cluster,
+			inode->i_blocks / cluster_size / (sb->s_blocksize / 512));
+		fat_cache_inval_inode(inode);
+	}
 	inode->i_blocks += (1 << MSDOS_SB(sb)->cluster_bits) / 512;
-	return 0;
+
+	return nr;
 }
 
 struct buffer_head *fat_extend_dir(struct inode *inode)
 {
 	struct super_block *sb = inode->i_sb;
-	int count,nr,limit,last,curr,sector,last_sector,file_cluster;
-	struct buffer_head *bh, *res=NULL;
+	int nr, sector, last_sector;
+	struct buffer_head *bh, *res = NULL;
 	int cluster_size = MSDOS_SB(sb)->cluster_size;
 
 	if (MSDOS_SB(sb)->fat_bits != 32) {
 		if (inode->i_ino == MSDOS_ROOT_INO)
 			return res;
 	}
-	if (!MSDOS_SB(sb)->free_clusters)
-		return res;
-
-	lock_fat(sb);
 
-	limit = MSDOS_SB(sb)->clusters;
-	nr = limit; /* to keep GCC happy */
-	for (count = 0; count < limit; count++) {
-		nr = ((count + MSDOS_SB(sb)->prev_free) % limit) + 2;
-		if (fat_access(sb, nr, -1) == 0)
-			break;
-	}
-	PRINTK (("cnt = %d --", count));
-#ifdef DEBUG
-	printk("free cluster: %d\n", nr);
-#endif
-	if (count >= limit) {
-		MSDOS_SB(sb)->free_clusters = 0;
-		unlock_fat(sb);
+	nr = fat_add_cluster(inode);
+	if (nr < 0)
 		return res;
-	}
-
-	MSDOS_SB(sb)->prev_free = (count + MSDOS_SB(sb)->prev_free + 1) % limit;
-	fat_access(sb, nr, EOF_FAT(sb));
-	if (MSDOS_SB(sb)->free_clusters != -1)
-		MSDOS_SB(sb)->free_clusters--;
-	if (MSDOS_SB(sb)->fat_bits == 32)
-		fat_clusters_flush(sb);
-
-	unlock_fat(sb);
-
-#ifdef DEBUG
-	printk("set to %x\n", fat_access(sb, nr, -1));
-#endif
-
-	/* We must locate the last cluster of the file to add this
-	   new one (nr) to the end of the link list (the FAT).
-	   
-	   Here file_cluster will be the number of the last cluster of the
-	   file (before we add nr).
-	   
-	   last is the corresponding cluster number on the disk. We will
-	   use last to plug the nr cluster. We will use file_cluster to
-	   update the cache.
-	*/
-	last = file_cluster = 0;
-	if ((curr = MSDOS_I(inode)->i_start) != 0) {
-		fat_cache_lookup(inode, INT_MAX, &last, &curr);
-		file_cluster = last;
-		while (curr && curr != -1){
-			PRINTK (("."));
-			file_cluster++;
-			if (!(curr = fat_access(sb, last = curr, -1))) {
-				fat_fs_panic(sb,"File without EOF");
-				return res;
-			}
-		}
-		PRINTK ((" --  "));
-	}
-#ifdef DEBUG
-	printk("last = %d\n", last);
-#endif
-	if (last)
-		fat_access(sb, last, nr);
-	else {
-		MSDOS_I(inode)->i_start = nr;
-		MSDOS_I(inode)->i_logstart = nr;
-		mark_inode_dirty(inode);
-	}
-#ifdef DEBUG
-	if (last)
-		printk("next set to %d\n",fat_access(sb, last, -1));
-#endif
+	
 	sector = MSDOS_SB(sb)->data_start + (nr - 2) * cluster_size;
 	last_sector = sector + cluster_size;
 	if (MSDOS_SB(sb)->cvf_format && MSDOS_SB(sb)->cvf_format->zero_out_cluster)
@@ -305,23 +231,15 @@
 			}
 		}
 	}
-	if (file_cluster
-	    != inode->i_blocks / cluster_size / (sb->s_blocksize / 512)) {
-		printk ("file_cluster badly computed!!! %d <> %ld\n",
-			file_cluster,
-			inode->i_blocks / cluster_size / (sb->s_blocksize / 512));
-	}else{
-		fat_cache_add(inode, file_cluster, nr);
-	}
-	inode->i_blocks += (1 << MSDOS_SB(sb)->cluster_bits) / 512;
 	if (inode->i_size & (sb->s_blocksize - 1)) {
 		fat_fs_panic(sb, "Odd directory size");
-		inode->i_size = (inode->i_size + sb->s_blocksize) &
-			~(sb->s_blocksize - 1);
+		inode->i_size = (inode->i_size + sb->s_blocksize)
+			& ~(sb->s_blocksize - 1);
 	}
 	inode->i_size += 1 << MSDOS_SB(sb)->cluster_bits;
 	MSDOS_I(inode)->mmu_private += 1 << MSDOS_SB(sb)->cluster_bits;
 	mark_inode_dirty(inode);
+
 	return res;
 }
 
@@ -340,7 +258,9 @@
 {
 	int month,year,secs;
 
-	month = ((date >> 5) & 15)-1;
+	/* first subtract and mask after that... Otherwise, if
+	   date == 0, bad things happen */
+	month = ((date >> 5) - 1) & 15;
 	year = date >> 9;
 	secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
 	    ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
@@ -359,7 +279,10 @@
 	int day,year,nl_day,month;
 
 	unix_date -= sys_tz.tz_minuteswest*60;
-	if (sys_tz.tz_dsttime) unix_date += 3600;
+
+	/* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
+	if (unix_date < 315532800)
+		unix_date = 315532800;
 
 	*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
 	    (((unix_date/3600) % 24) << 11);
@@ -592,61 +515,9 @@
 }
 
 /*
- * fat_parent_ino returns the inode number of the parent directory of dir.
- * File creation has to be deferred while fat_parent_ino is running to
- * prevent renames.
- *
- * AV. Bad, bad, bad... We need a mapping that would give us inode by
- * first cluster. Sheeeeit... OK, we can do it on fat_fill_inode() and
- * update on fat_add_cluster(). When will we remove it? fat_clear_inode()
- * and fat_truncate() to zero?
- */
-
-int fat_parent_ino(struct inode *dir,int locked)
-{
-	static int zero = 0;
-	int error,curr,prev,nr;
-
-	PRINTK(("fat_parent_ino: Debug 0\n"));
-	if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
-	if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
-	if (!locked) fat_lock_creation(); /* prevent renames */
-	if ((curr = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,MSDOS_DOTDOT,
-	    &zero,NULL,NULL,NULL)) < 0) {
-		if (!locked) fat_unlock_creation();
-		return curr;
-	}
-	PRINTK(("fat_parent_ino: Debug 1 curr=%d\n", curr));
-	if (!curr) nr = MSDOS_ROOT_INO;
-	else {
-		PRINTK(("fat_parent_ino: Debug 2\n"));
-		if ((prev = raw_scan(dir->i_sb,curr,MSDOS_DOTDOT,&zero,NULL,
-		    NULL,NULL)) < 0) {
-			PRINTK(("fat_parent_ino: Debug 3 prev=%d\n", prev));
-			if (!locked) fat_unlock_creation();
-			return prev;
-		}
-		PRINTK(("fat_parent_ino: Debug 4 prev=%d\n", prev));
-		if (prev == 0 && MSDOS_SB(dir->i_sb)->fat_bits == 32) {
-			prev = MSDOS_SB(dir->i_sb)->root_cluster;
-		}
-		if ((error = raw_scan(dir->i_sb,prev,NULL,&curr,&nr,NULL,
-		    NULL)) < 0) {
-			PRINTK(("fat_parent_ino: Debug 5 error=%d\n", error));
-			if (!locked) fat_unlock_creation();
-			return error;
-		}
-		PRINTK(("fat_parent_ino: Debug 6 nr=%d\n", nr));
-	}
-	if (!locked) fat_unlock_creation();
-	return nr;
-}
-
-/*
  * fat_subdirs counts the number of sub-directories of dir. It can be run
  * on directories being created.
  */
-
 int fat_subdirs(struct inode *dir)
 {
 	int count;
diff -u --recursive --new-file v2.4.12/linux/fs/fat/msbuffer.h linux/fs/fat/msbuffer.h
--- v2.4.12/linux/fs/fat/msbuffer.h	Tue Sep  5 14:07:29 2000
+++ linux/fs/fat/msbuffer.h	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/* Number of bytes to readahead on disc access */
-#define FAT_READAHEAD (18*1024)
-
-struct buffer_head *fat_bread (struct super_block *sb, int block);
-struct buffer_head *fat_getblk (struct super_block *sb, int block);
-void fat_brelse (struct super_block *sb, struct buffer_head *bh);
-void fat_mark_buffer_dirty (struct super_block *sb,
-	 struct buffer_head *bh);
-void fat_set_uptodate (struct super_block *sb,
-	 struct buffer_head *bh,
-	 int val);
-int fat_is_uptodate (struct super_block *sb, struct buffer_head *bh);
-void fat_ll_rw_block (struct super_block *sb, int opr,
-	int nbreq, struct buffer_head *bh[32]);
diff -u --recursive --new-file v2.4.12/linux/fs/fat/tables.c linux/fs/fat/tables.c
--- v2.4.12/linux/fs/fat/tables.c	Thu Oct 23 14:00:15 1997
+++ linux/fs/fat/tables.c	Wed Dec 31 16:00:00 1969
@@ -1,76 +0,0 @@
-/*
- * linux/fs/fat/tables.c
- *
- * Unicode escape translation tables for VFAT filename handling.
- * By Gordon Chaffee.
- *
- * Note: This file is used by all fat-based filesystems.
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/msdos_fs.h>
-
-unsigned char fat_uni2esc[64] = {
-	'0', '1', '2', '3', '4', '5', '6', '7',
-	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
-	'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
-	'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
-	'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
-	'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
-	'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
-	'u', 'v', 'w', 'x', 'y', 'z', '+', '-'
-};
-
-unsigned char fat_esc2uni[256] = {
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0x3e, 0xff, 0x3f, 0xff, 0xff, 
-	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
-	0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 
-	0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 
-	0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 
-	0x21, 0x22, 0x23, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 
-	0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 
-	0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 
-	0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-};
-
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
diff -u --recursive --new-file v2.4.12/linux/fs/fat/tables.h linux/fs/fat/tables.h
--- v2.4.12/linux/fs/fat/tables.h	Tue Mar  5 03:03:27 1996
+++ linux/fs/fat/tables.h	Wed Dec 31 16:00:00 1969
@@ -1,35 +0,0 @@
-struct unicode_value {
-	unsigned char uni1;
-	unsigned char uni2;
-};
-
-extern unsigned char fat_a2alias[];		/* Ascii to alias name conversion table */
-extern struct unicode_value fat_a2uni[];	/* Ascii to Unicode conversion table */
-extern unsigned char *fat_uni2asc_pg[];
-
-/*
- * Since Linux can't deal with Unicode in filenames, these provide
- * a method to encode the Unicode names in a manner that the vfat
- * filesystem can them decode back to Unicode.  This conversion
- * only occurs when the filesystem was mounted with the 'uni_xlate' mount
- * option.
- */
-extern unsigned char fat_uni2code[];
-extern unsigned char fat_code2uni[];
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
diff -u --recursive --new-file v2.4.12/linux/fs/freevxfs/vxfs_super.c linux/fs/freevxfs/vxfs_super.c
--- v2.4.12/linux/fs/freevxfs/vxfs_super.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/freevxfs/vxfs_super.c	Thu Oct 11 09:43:38 2001
@@ -49,6 +49,7 @@
 
 MODULE_AUTHOR("Christoph Hellwig");
 MODULE_DESCRIPTION("Veritas Filesystem (VxFS) driver");
+MODULE_LICENSE("Dual BSD/GPL");
 
 
 static void		vxfs_put_super(struct super_block *);
diff -u --recursive --new-file v2.4.12/linux/fs/hfs/catalog.c linux/fs/hfs/catalog.c
--- v2.4.12/linux/fs/hfs/catalog.c	Tue Feb 13 14:13:45 2001
+++ linux/fs/hfs/catalog.c	Mon Oct 15 19:30:33 2001
@@ -100,7 +100,7 @@
 static LIST_HEAD(entry_unused);
 static struct list_head hash_table[C_HASHSIZE];
 
-spinlock_t entry_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t entry_lock = SPIN_LOCK_UNLOCKED;
 
 static struct {
         int nr_entries;
diff -u --recursive --new-file v2.4.12/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.4.12/linux/fs/isofs/inode.c	Mon Aug 27 12:41:46 2001
+++ linux/fs/isofs/inode.c	Fri Oct 12 13:48:42 2001
@@ -1184,11 +1184,14 @@
 		inode->i_size = isonum_733 (de->size);
 	}
 
-	/* There are defective discs out there - we do this to protect
-	   ourselves.  A cdrom will never contain more than 800Mb 
-	   .. but a DVD may be up to 1Gig (Ulrich Habel) */
-
-	if ((inode->i_size < 0 || inode->i_size > 1073741824) &&
+	/*
+	 * The ISO-9660 filesystem only stores 32 bits for file size.
+	 * mkisofs handles files up to 2GB-2 = 2147483646 = 0x7FFFFFFE bytes
+	 * in size. This is according to the large file summit paper from 1996.
+	 * WARNING: ISO-9660 filesystems > 1 GB and even > 2 GB are fully
+	 *	    legal. Do not prevent to use DVD's schilling@fokus.gmd.de
+	 */
+	if ((inode->i_size < 0 || inode->i_size > 0x7FFFFFFE) &&
 	    inode->i_sb->u.isofs_sb.s_cruft == 'n') {
 		printk(KERN_WARNING "Warning: defective CD-ROM.  "
 		       "Enabling \"cruft\" mount option.\n");
diff -u --recursive --new-file v2.4.12/linux/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c
--- v2.4.12/linux/fs/lockd/clntproc.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/lockd/clntproc.c	Thu Oct 11 07:52:18 2001
@@ -6,6 +6,7 @@
  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -676,6 +677,18 @@
 	case NLM_LCK_BLOCKED:
 		printk(KERN_NOTICE "lockd: unexpected status NLM_BLOCKED\n");
 		return -ENOLCK;
+#ifdef CONFIG_LOCKD_V4
+	case NLM_DEADLCK:
+		return -EDEADLK;
+	case NLM_ROFS:
+		return -EROFS;
+	case NLM_STALE_FH:
+		return -ESTALE;
+	case NLM_FBIG:
+		return -EOVERFLOW;
+	case NLM_FAILED:
+		return -ENOLCK;
+#endif
 	}
 	printk(KERN_NOTICE "lockd: unexpected server status %d\n", status);
 	return -ENOLCK;
diff -u --recursive --new-file v2.4.12/linux/fs/lockd/svc.c linux/fs/lockd/svc.c
--- v2.4.12/linux/fs/lockd/svc.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/lockd/svc.c	Sun Oct 21 10:32:33 2001
@@ -323,6 +323,7 @@
 
 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
 MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION ".");
+MODULE_LICENSE("GPL");
 MODULE_PARM(nlm_grace_period, "10-240l");
 MODULE_PARM(nlm_timeout, "3-20l");
 MODULE_PARM(nlm_udpport, "0-65535l");
diff -u --recursive --new-file v2.4.12/linux/fs/lockd/svclock.c linux/fs/lockd/svclock.c
--- v2.4.12/linux/fs/lockd/svclock.c	Tue Nov  7 10:18:57 2000
+++ linux/fs/lockd/svclock.c	Thu Oct 11 07:52:18 2001
@@ -31,9 +31,14 @@
 #include <linux/lockd/nlm.h>
 #include <linux/lockd/lockd.h>
 
-
 #define NLMDBG_FACILITY		NLMDBG_SVCLOCK
 
+#ifdef CONFIG_LOCKD_V4
+#define nlm_deadlock	nlm4_deadlock
+#else
+#define nlm_deadlock	nlm_lck_denied
+#endif
+
 static void	nlmsvc_insert_block(struct nlm_block *block, unsigned long);
 static int	nlmsvc_remove_block(struct nlm_block *block);
 static void	nlmsvc_grant_callback(struct rpc_task *task);
@@ -330,12 +335,7 @@
 		case 0:
 			return nlm_granted;
 		case EDEADLK:
-#ifdef CONFIG_LOCKD_V4
-			return nlm4_deadlock; /* will be downgraded to lck_deined if this
-					       * is a NLMv1,3 request */
-#else
-			/* no applicable NLM status */
-#endif
+			return nlm_deadlock;
 		case EAGAIN:
 			return nlm_lck_denied;
 		default:			/* includes ENOLCK */
@@ -346,6 +346,11 @@
 	if (!wait) {
 		up(&file->f_sema);
 		return nlm_lck_denied;
+	}
+
+	if (posix_locks_deadlock(&lock->fl, conflock)) {
+		up(&file->f_sema);
+		return nlm_deadlock;
 	}
 
 	/* If we don't have a block, create and initialize it. Then
diff -u --recursive --new-file v2.4.12/linux/fs/lockd/svcproc.c linux/fs/lockd/svcproc.c
--- v2.4.12/linux/fs/lockd/svcproc.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/lockd/svcproc.c	Thu Oct 11 07:52:18 2001
@@ -29,17 +29,20 @@
 static u32
 cast_to_nlm(u32 status, u32 vers)
 {
-
+	/* Note: status is assumed to be in network byte order !!! */
 	if (vers != 4){
-		switch(ntohl(status)){
-		case NLM_LCK_GRANTED:
-		case NLM_LCK_DENIED:
-		case NLM_LCK_DENIED_NOLOCKS:
-		case NLM_LCK_BLOCKED:
-		case NLM_LCK_DENIED_GRACE_PERIOD:
+		switch (status) {
+		case nlm_granted:
+		case nlm_lck_denied:
+		case nlm_lck_denied_nolocks:
+		case nlm_lck_blocked:
+		case nlm_lck_denied_grace_period:
+			break;
+		case nlm4_deadlock:
+			status = nlm_lck_denied;
 			break;
 		default:
-			status = NLM_LCK_DENIED_NOLOCKS;
+			status = nlm_lck_denied_nolocks;
 		}
 	}
 
diff -u --recursive --new-file v2.4.12/linux/fs/locks.c linux/fs/locks.c
--- v2.4.12/linux/fs/locks.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/locks.c	Thu Oct 11 07:52:18 2001
@@ -548,7 +548,7 @@
 		return (1);
 
 	default:
-		printk("locks_conflict(): impossible lock type - %d\n",
+		printk(KERN_ERR "locks_conflict(): impossible lock type - %d\n",
 		       caller_fl->fl_type);
 		break;
 	}
@@ -660,7 +660,7 @@
  * from a broken NFS client. But broken NFS clients have a lot more to
  * worry about than proper deadlock detection anyway... --okir
  */
-static int posix_locks_deadlock(struct file_lock *caller_fl,
+int posix_locks_deadlock(struct file_lock *caller_fl,
 				struct file_lock *block_fl)
 {
 	struct list_head *tmp;
@@ -715,6 +715,9 @@
 	struct file_lock *new_fl = locks_alloc_lock(0);
 	int error;
 
+	if (new_fl == NULL)
+		return -ENOMEM;
+
 	new_fl->fl_owner = current->files;
 	new_fl->fl_pid = current->pid;
 	new_fl->fl_file = filp;
@@ -1428,6 +1431,9 @@
 	struct inode *inode;
 	int error;
 
+	if (file_lock == NULL)
+		return -ENOLCK;
+
 	/*
 	 * This might block, so we do it before checking the inode.
 	 */
@@ -1580,6 +1586,9 @@
 	struct flock64 flock;
 	struct inode *inode;
 	int error;
+
+	if (file_lock == NULL)
+		return -ENOLCK;
 
 	/*
 	 * This might block, so we do it before checking the inode.
diff -u --recursive --new-file v2.4.12/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.4.12/linux/fs/msdos/namei.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/msdos/namei.c	Fri Oct 12 13:48:42 2001
@@ -17,8 +17,6 @@
 
 #include <asm/uaccess.h>
 
-#include "../fat/msbuffer.h"
-
 #define MSDOS_DEBUG 0
 #define PRINTK(x)
 
diff -u --recursive --new-file v2.4.12/linux/fs/namei.c linux/fs/namei.c
--- v2.4.12/linux/fs/namei.c	Thu Oct 11 08:02:26 2001
+++ linux/fs/namei.c	Wed Oct 17 14:46:29 2001
@@ -646,10 +646,14 @@
 static int __emul_lookup_dentry(const char *name, struct nameidata *nd)
 {
 	if (path_walk(name, nd))
-		return 0;
+		return 0;		/* something went wrong... */
 
-	if (!nd->dentry->d_inode) {
+	if (!nd->dentry->d_inode || S_ISDIR(nd->dentry->d_inode->i_mode)) {
 		struct nameidata nd_root;
+		/*
+		 * NAME was not found in alternate root or it's a directory.  Try to find
+		 * it in the normal root:
+		 */
 		nd_root.last_type = LAST_ROOT;
 		nd_root.flags = nd->flags;
 		read_lock(&current->fs->lock);
diff -u --recursive --new-file v2.4.12/linux/fs/namespace.c linux/fs/namespace.c
--- v2.4.12/linux/fs/namespace.c	Thu Oct 11 08:02:26 2001
+++ linux/fs/namespace.c	Mon Oct 15 18:47:36 2001
@@ -153,6 +153,8 @@
 		atomic_inc(&sb->s_active);
 		mnt->mnt_sb = sb;
 		mnt->mnt_root = dget(root);
+		mnt->mnt_mountpoint = mnt->mnt_root;
+		mnt->mnt_parent = mnt;
 	}
 	return mnt;
 }
@@ -1086,7 +1088,7 @@
 		printk(KERN_NOTICE "Trying to unmount old root ... ");
 		if (!blivet) {
 			spin_lock(&dcache_lock);
-			list_del(&old_rootmnt->mnt_list);
+			list_del_init(&old_rootmnt->mnt_list);
  			spin_unlock(&dcache_lock);
  			mntput(old_rootmnt);
 			mntput(old_rootmnt);
diff -u --recursive --new-file v2.4.12/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.4.12/linux/fs/nfs/read.c	Tue Apr  3 13:45:37 2001
+++ linux/fs/nfs/read.c	Thu Oct 11 08:12:52 2001
@@ -59,7 +59,7 @@
 static __inline__ struct nfs_read_data *nfs_readdata_alloc(void)
 {
 	struct nfs_read_data   *p;
-	p = kmem_cache_alloc(nfs_rdata_cachep, SLAB_NFS);
+	p = kmem_cache_alloc(nfs_rdata_cachep, SLAB_NOFS);
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
diff -u --recursive --new-file v2.4.12/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.4.12/linux/fs/nfs/write.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/nfs/write.c	Thu Oct 11 08:12:52 2001
@@ -109,7 +109,7 @@
 static __inline__ struct nfs_page *nfs_page_alloc(void)
 {
 	struct nfs_page	*p;
-	p = kmem_cache_alloc(nfs_page_cachep, SLAB_KERNEL);
+	p = kmem_cache_alloc(nfs_page_cachep, SLAB_NOFS);
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->wb_hash);
@@ -127,7 +127,7 @@
 static __inline__ struct nfs_write_data *nfs_writedata_alloc(void)
 {
 	struct nfs_write_data	*p;
-	p = kmem_cache_alloc(nfs_wdata_cachep, SLAB_NFS);
+	p = kmem_cache_alloc(nfs_wdata_cachep, SLAB_NOFS);
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
diff -u --recursive --new-file v2.4.12/linux/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c
--- v2.4.12/linux/fs/nfsd/nfsctl.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/nfsd/nfsctl.c	Sun Oct 21 10:32:33 2001
@@ -309,6 +309,7 @@
 /* New-style module support since 2.1.18 */
 EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
+MODULE_LICENSE("GPL");
 
 struct nfsd_linkage nfsd_linkage_s = {
 	do_nfsservctl: handle_sys_nfsservctl,
diff -u --recursive --new-file v2.4.12/linux/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c
--- v2.4.12/linux/fs/nfsd/nfsproc.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/nfsd/nfsproc.c	Sun Oct 21 10:40:36 2001
@@ -86,8 +86,8 @@
 {
 	int	nfserr;
 
-	dprintk("nfsd: LOOKUP   %s %s\n",
-		SVCFH_fmt(&argp->fh), argp->name);
+	dprintk("nfsd: LOOKUP   %s %.*s\n",
+		SVCFH_fmt(&argp->fh), argp->len, argp->name);
 
 	fh_init(&resp->fh, NFS_FHSIZE);
 	nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
@@ -199,8 +199,8 @@
 	int		nfserr, type, mode;
 	dev_t		rdev = NODEV;
 
-	dprintk("nfsd: CREATE   %s %s\n",
-		SVCFH_fmt(dirfhp), argp->name);
+	dprintk("nfsd: CREATE   %s %.*s\n",
+		SVCFH_fmt(dirfhp), argp->len, argp->name);
 
 	/* First verify the parent file handle */
 	nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC);
@@ -349,7 +349,8 @@
 {
 	int	nfserr;
 
-	dprintk("nfsd: REMOVE   %s %s\n", SVCFH_fmt(&argp->fh), argp->name);
+	dprintk("nfsd: REMOVE   %s %.*s\n", SVCFH_fmt(&argp->fh),
+		argp->len, argp->name);
 
 	/* Unlink. -SIFDIR means file must not be a directory */
 	nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len);
@@ -363,10 +364,10 @@
 {
 	int	nfserr;
 
-	dprintk("nfsd: RENAME   %s %s -> \n",
-		SVCFH_fmt(&argp->ffh), argp->fname);
-	dprintk("nfsd:        ->  %s %s\n",
-		SVCFH_fmt(&argp->tfh), argp->tname);
+	dprintk("nfsd: RENAME   %s %.*s -> \n",
+		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
+	dprintk("nfsd:        ->  %s %.*s\n",
+		SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);
 
 	nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
 				    &argp->tfh, argp->tname, argp->tlen);
@@ -383,8 +384,9 @@
 
 	dprintk("nfsd: LINK     %s ->\n",
 		SVCFH_fmt(&argp->ffh));
-	dprintk("nfsd:    %s %s\n",
+	dprintk("nfsd:    %s %.*s\n",
 		SVCFH_fmt(&argp->tfh),
+		argp->tlen,
 		argp->tname);
 
 	nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
@@ -401,8 +403,9 @@
 	struct svc_fh	newfh;
 	int		nfserr;
 
-	dprintk("nfsd: SYMLINK  %s %s -> %s\n",
-		SVCFH_fmt(&argp->ffh), argp->fname, argp->tname);
+	dprintk("nfsd: SYMLINK  %s %.*s -> %.*s\n",
+		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
+		argp->tlen, argp->tname);
 
 	fh_init(&newfh, NFS_FHSIZE);
 	/*
@@ -428,7 +431,7 @@
 {
 	int	nfserr;
 
-	dprintk("nfsd: MKDIR    %s %s\n", SVCFH_fmt(&argp->fh), argp->name);
+	dprintk("nfsd: MKDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
 
 	if (resp->fh.fh_dentry) {
 		printk(KERN_WARNING
@@ -452,7 +455,7 @@
 {
 	int	nfserr;
 
-	dprintk("nfsd: RMDIR    %s %s\n", SVCFH_fmt(&argp->fh), argp->name);
+	dprintk("nfsd: RMDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
 
 	nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
 	fh_put(&argp->fh);
diff -u --recursive --new-file v2.4.12/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c
--- v2.4.12/linux/fs/nfsd/nfssvc.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/nfsd/nfssvc.c	Wed Oct 17 14:16:34 2001
@@ -162,7 +162,7 @@
 	lock_kernel();
 	daemonize();
 	sprintf(current->comm, "nfsd");
-	current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 
+	current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
 
 	nfsdstats.th_cnt++;
 	/* Let svc_process check client's authentication. */
diff -u --recursive --new-file v2.4.12/linux/fs/nfsd/nfsxdr.c linux/fs/nfsd/nfsxdr.c
--- v2.4.12/linux/fs/nfsd/nfsxdr.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/nfsd/nfsxdr.c	Wed Oct 17 14:16:34 2001
@@ -70,7 +70,6 @@
 			if (*name == '\0' || *name == '/')
 				return NULL;
 		}
-		*name = '\0';
 	}
 
 	return p;
@@ -87,7 +86,6 @@
 			if (*name == '\0')
 				return NULL;
 		}
-		*name = '\0';
 	}
 
 	return p;
diff -u --recursive --new-file v2.4.12/linux/fs/open.c linux/fs/open.c
--- v2.4.12/linux/fs/open.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/open.c	Fri Oct 12 13:48:42 2001
@@ -104,7 +104,12 @@
 		goto out;
 	inode = nd.dentry->d_inode;
 
-	error = -EACCES;
+	/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
+	error = -EISDIR;
+	if (S_ISDIR(inode->i_mode))
+		goto dput_and_out;
+
+	error = -EINVAL;
 	if (!S_ISREG(inode->i_mode))
 		goto dput_and_out;
 
@@ -146,10 +151,11 @@
 
 asmlinkage long sys_truncate(const char * path, unsigned long length)
 {
-	return do_sys_truncate(path, length);
+	/* on 32-bit boxen it will cut the range 2^31--2^32-1 off */
+	return do_sys_truncate(path, (long)length);
 }
 
-static inline long do_sys_ftruncate(unsigned int fd, loff_t length)
+static inline long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
 {
 	struct inode * inode;
 	struct dentry *dentry;
@@ -163,13 +169,24 @@
 	file = fget(fd);
 	if (!file)
 		goto out;
+
+	/* explicitly opened as large or we are on 64-bit box */
+	if (file->f_flags & O_LARGEFILE)
+		small = 0;
+
 	dentry = file->f_dentry;
 	inode = dentry->d_inode;
-	error = -EACCES;
+	error = -EINVAL;
 	if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
 		goto out_putf;
+
+	error = -EINVAL;
+	/* Cannot ftruncate over 2^31 bytes without large file support */
+	if (small && length > MAX_NON_LFS)
+		goto out_putf;
+
 	error = -EPERM;
-	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+	if (IS_APPEND(inode))
 		goto out_putf;
 
 	error = locks_verify_truncate(inode, file, length);
@@ -183,7 +200,7 @@
 
 asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length)
 {
-	return do_sys_ftruncate(fd, length);
+	return do_sys_ftruncate(fd, length, 1);
 }
 
 /* LFS versions of truncate are only needed on 32 bit machines */
@@ -195,7 +212,7 @@
 
 asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
 {
-	return do_sys_ftruncate(fd, length);
+	return do_sys_ftruncate(fd, length, 0);
 }
 #endif
 
@@ -507,7 +524,7 @@
 
 	error = -ENOENT;
 	if (!(inode = dentry->d_inode)) {
-		printk("chown_common: NULL inode\n");
+		printk(KERN_ERR "chown_common: NULL inode\n");
 		goto out;
 	}
 	error = -EROFS;
@@ -744,7 +761,7 @@
 #if 1
 	/* Sanity check */
 	if (files->fd[fd] != NULL) {
-		printk("get_unused_fd: slot %d not NULL!\n", fd);
+		printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd);
 		files->fd[fd] = NULL;
 	}
 #endif
@@ -807,7 +824,7 @@
 	int retval;
 
 	if (!file_count(filp)) {
-		printk("VFS: Close: file count is 0\n");
+		printk(KERN_ERR "VFS: Close: file count is 0\n");
 		return 0;
 	}
 	retval = 0;
diff -u --recursive --new-file v2.4.12/linux/fs/partitions/check.c linux/fs/partitions/check.c
--- v2.4.12/linux/fs/partitions/check.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/partitions/check.c	Thu Oct 11 17:25:10 2001
@@ -247,6 +247,7 @@
 		printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf));
 	bdev = bdget(kdev_t_to_nr(dev));
 	bdev->bd_inode->i_size = (loff_t)hd->part[MINOR(dev)].nr_sects << 9;
+	bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev));
 	for (i = 0; check_part[i]; i++) {
 		int res;
 		res = check_part[i](hd, bdev, first_sector, first_part_minor);
@@ -385,6 +386,12 @@
 	if (!size || minors == 1)
 		return;
 
+	if (dev->sizes) {
+		dev->sizes[first_minor] = size >> (BLOCK_SIZE_BITS - 9);
+		for (i = first_minor + 1; i < end_minor; i++)
+			dev->sizes[i] = 0;
+	}
+	blk_size[dev->major] = dev->sizes;
 	check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor);
 
  	/*
@@ -394,7 +401,6 @@
 	if (dev->sizes != NULL) {	/* optional safeguard in ll_rw_blk.c */
 		for (i = first_minor; i < end_minor; i++)
 			dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
-		blk_size[dev->major] = dev->sizes;
 	}
 }
 
diff -u --recursive --new-file v2.4.12/linux/fs/partitions/msdos.c linux/fs/partitions/msdos.c
--- v2.4.12/linux/fs/partitions/msdos.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/partitions/msdos.c	Thu Oct 11 08:07:07 2001
@@ -103,21 +103,20 @@
  */
 
 static void extended_partition(struct gendisk *hd, struct block_device *bdev,
-				int minor, int *current_minor)
+			int minor, unsigned long first_size, int *current_minor)
 {
 	struct partition *p;
 	Sector sect;
 	unsigned char *data;
-	unsigned long first_sector, first_size, this_sector, this_size;
+	unsigned long first_sector, this_sector, this_size;
 	int mask = (1 << hd->minor_shift) - 1;
 	int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512;
 	int loopct = 0;		/* number of links followed
 				   without finding a data partition */
 	int i;
 
-	first_sector = hd->part[minor].start_sect;
-	first_size = hd->part[minor].nr_sects;
-	this_sector = first_sector;
+	this_sector = first_sector = hd->part[minor].start_sect;
+	this_size = first_size;
 
 	while (1) {
 		if (++loopct > 100)
@@ -133,8 +132,6 @@
 
 		p = (struct partition *) (data + 0x1be);
 
-		this_size = hd->part[minor].nr_sects;
-
 		/*
 		 * Usually, the first entry is the real data partition,
 		 * the 2nd entry is the next extended partition, or empty,
@@ -196,6 +193,7 @@
 			goto done;	 /* nothing left to do */
 
 		this_sector = first_sector + START_SECT(p) * sector_size;
+		this_size = NR_SECTS(p) * sector_size;
 		minor = *current_minor;
 		put_dev_sector(sect);
 	}
@@ -586,12 +584,13 @@
 		}
 #endif
 		if (is_extended_partition(p)) {
+			unsigned long size = hd->part[minor].nr_sects;
 			printk(" <");
 			/* prevent someone doing mkfs or mkswap on an
 			   extended partition, but leave room for LILO */
-			if (hd->part[minor].nr_sects > 2)
+			if (size > 2)
 				hd->part[minor].nr_sects = 2;
-			extended_partition(hd, bdev, minor, &current_minor);
+			extended_partition(hd, bdev, minor, size, &current_minor);
 			printk(" >");
 		}
 	}
diff -u --recursive --new-file v2.4.12/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.4.12/linux/fs/proc/array.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/proc/array.c	Thu Oct 11 09:00:01 2001
@@ -151,12 +151,13 @@
 	read_lock(&tasklist_lock);
 	buffer += sprintf(buffer,
 		"State:\t%s\n"
+		"Tgid:\t%d\n"
 		"Pid:\t%d\n"
 		"PPid:\t%d\n"
 		"TracerPid:\t%d\n"
 		"Uid:\t%d\t%d\t%d\t%d\n"
 		"Gid:\t%d\t%d\t%d\t%d\n",
-		get_task_state(p),
+		get_task_state(p), p->tgid,
 		p->pid, p->pid ? p->p_opptr->pid : 0, 0,
 		p->uid, p->euid, p->suid, p->fsuid,
 		p->gid, p->egid, p->sgid, p->fsgid);
diff -u --recursive --new-file v2.4.12/linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c
--- v2.4.12/linux/fs/proc/proc_misc.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/proc/proc_misc.c	Thu Oct 11 10:46:57 2001
@@ -140,6 +140,7 @@
 {
 	struct sysinfo i;
 	int len;
+	int pg_size ;
 
 /*
  * display in kilobytes.
@@ -148,12 +149,14 @@
 #define B(x) ((unsigned long long)(x) << PAGE_SHIFT)
 	si_meminfo(&i);
 	si_swapinfo(&i);
+	pg_size = atomic_read(&page_cache_size) - i.bufferram ;
+
 	len = sprintf(page, "        total:    used:    free:  shared: buffers:  cached:\n"
 		"Mem:  %8Lu %8Lu %8Lu %8Lu %8Lu %8Lu\n"
 		"Swap: %8Lu %8Lu %8Lu\n",
 		B(i.totalram), B(i.totalram-i.freeram), B(i.freeram),
 		B(i.sharedram), B(i.bufferram),
-		B(atomic_read(&page_cache_size)), B(i.totalswap),
+		B(pg_size), B(i.totalswap),
 		B(i.totalswap-i.freeswap), B(i.freeswap));
 	/*
 	 * Tagged format, for easy grepping and expansion.
@@ -179,7 +182,7 @@
 		K(i.freeram),
 		K(i.sharedram),
 		K(i.bufferram),
-		K(atomic_read(&page_cache_size) - swapper_space.nrpages),
+		K(pg_size - swapper_space.nrpages),
 		K(swapper_space.nrpages),
 		K(nr_active_pages),
 		K(nr_inactive_pages),
diff -u --recursive --new-file v2.4.12/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.4.12/linux/fs/proc/root.c	Wed May 16 18:05:34 2001
+++ linux/fs/proc/root.c	Sat Oct 20 19:14:42 2001
@@ -44,6 +44,10 @@
 #ifdef CONFIG_SYSCTL
 	proc_sys_root = proc_mkdir("sys", 0);
 #endif
+#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
+	proc_mkdir("sys/fs", 0);
+	proc_mkdir("sys/fs/binfmt_misc", 0);
+#endif
 	proc_root_fs = proc_mkdir("fs", 0);
 	proc_root_driver = proc_mkdir("driver", 0);
 #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/Makefile linux/fs/reiserfs/Makefile
--- v2.4.12/linux/fs/reiserfs/Makefile	Mon Jan 15 12:42:32 2001
+++ linux/fs/reiserfs/Makefile	Fri Oct 12 14:19:28 2001
@@ -13,6 +13,16 @@
 
 obj-m   := $(O_TARGET)
 
+# gcc -O2 (the kernel default)  is overaggressive on ppc when many inline
+# functions are used.  This causes the compiler to advance the stack
+# pointer out of the available stack space, corrupting kernel space,
+# and causing a panic. Since this behavior only affects ppc, this ifeq
+# will work around it. If any other architecture displays this behavior,
+# add it here.
+ifeq ($(shell uname -m),ppc) 
+EXTRA_CFLAGS := -O1
+endif
+
 include $(TOPDIR)/Rules.make
 
 TAGS:
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/README linux/fs/reiserfs/README
--- v2.4.12/linux/fs/reiserfs/README	Mon Jan 15 12:42:32 2001
+++ linux/fs/reiserfs/README	Fri Oct 12 14:19:28 2001
@@ -145,6 +145,10 @@
 
 Vitaly Fertman is doing fsck.
 
+Jeff Mahoney, of SuSE, contributed a few cleanup fixes, most notably
+the endian safe patches which allow ReiserFS to run on any platform
+supported by the Linux kernel.
+
 SuSE, IntegratedLinux.com, Ecila, MP3.com, bigstorage.com, and the
 Alpha PC Company made it possible for me to not have a day job
 anymore, and to dramatically increase our staffing.  Ecila funded
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/bitmap.c linux/fs/reiserfs/bitmap.c
--- v2.4.12/linux/fs/reiserfs/bitmap.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/bitmap.c	Sun Oct 14 10:31:45 2001
@@ -116,7 +116,7 @@
 
   reiserfs_prepare_for_journal(s, sbh, 1) ;
   /* update super block */
-  rs->s_free_blocks = cpu_to_le32 (le32_to_cpu (rs->s_free_blocks) + 1);
+  set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );
 
   journal_mark_dirty (th, s, sbh);
   s->s_dirt = 1;
@@ -304,8 +304,7 @@
 
   /* We continue the while loop if another process snatches our found
    * free block from us after we find it but before we successfully
-   * mark it as in use, or if we need to use sync to free up some
-   * blocks on the preserve list.  */
+   * mark it as in use */
 
   while (amount_needed--) {
     /* skip over any blocknrs already gotten last time. */
@@ -405,26 +404,26 @@
 
   reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
   /* update free block count in super block */
-  s->u.reiserfs_sb.s_rs->s_free_blocks = cpu_to_le32 (SB_FREE_BLOCKS (s) - init_amount_needed);
+  PUT_SB_FREE_BLOCKS( s, SB_FREE_BLOCKS(s) - init_amount_needed );
   journal_mark_dirty (th, s, SB_BUFFER_WITH_SB (s));
   s->s_dirt = 1;
 
   return CARRY_ON;
 }
 
-// this is called only by get_empty_nodes with for_preserve_list==0
+// this is called only by get_empty_nodes
 int reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th, unsigned long * free_blocknrs,
 			    unsigned long search_start, int amount_needed) {
-  return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, amount_needed, 0/*for_preserve_list-priority*/, 0/*for_formatted*/, 0/*for_prealloc */) ;
+  return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, amount_needed, 0/*priority*/, 0/*for_formatted*/, 0/*for_prealloc */) ;
 }
 
 
-// called by get_new_buffer and by reiserfs_get_block with amount_needed == 1 and for_preserve_list == 0
+// called by get_new_buffer and by reiserfs_get_block with amount_needed == 1
 int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle *th, unsigned long * free_blocknrs,
 			      unsigned long search_start) {
   return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
                                   1/*amount_needed*/,
-				  0/*for_preserve_list-priority*/, 
+				  0/*priority*/, 
 				  1/*for formatted*/,
 				  0/*for prealloc */) ;
 }
@@ -478,14 +477,14 @@
     ** highest allocated oid, it is far from perfect, and files will tend
     ** to be grouped towards the start of the border
     */
-    border = (INODE_PKEY(p_s_inode)->k_dir_id) % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ;
+    border = le32_to_cpu(INODE_PKEY(p_s_inode)->k_dir_id) % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ;
   } else {
     /* why would we want to delcare a local variable to this if statement
     ** name border????? -chris
     ** unsigned long border = 0;
     */
     if (!reiserfs_hashed_relocation(th->t_super)) {
-      hash_in = (INODE_PKEY(p_s_inode))->k_dir_id;
+      hash_in = le32_to_cpu((INODE_PKEY(p_s_inode))->k_dir_id);
 				/* I wonder if the CPU cost of the
                                    hash will obscure the layout
                                    effect? Of course, whether that
@@ -666,10 +665,10 @@
   if (inode->u.reiserfs_i.i_prealloc_count < 0)
      reiserfs_warning("zam-4001:" __FUNCTION__ ": inode has negative prealloc blocks count.\n");
 #endif  
-  if (inode->u.reiserfs_i.i_prealloc_count > 0) {
+    if (inode->u.reiserfs_i.i_prealloc_count > 0) {
     __discard_prealloc(th, inode);
   }
-}
+      }
 
 void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
 {
@@ -684,6 +683,6 @@
     }
 #endif    
     __discard_prealloc(th, inode);
-  }
+    }
 }
 #endif
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/dir.c linux/fs/reiserfs/dir.c
--- v2.4.12/linux/fs/reiserfs/dir.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/dir.c	Fri Oct 12 14:20:42 2001
@@ -39,22 +39,10 @@
 };
 
 int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) {
-  int ret = 0 ;
-  int windex ;
-  struct reiserfs_transaction_handle th ;
-
   lock_kernel();
-
-  journal_begin(&th, dentry->d_inode->i_sb, 1) ;
-  windex = push_journal_writer("dir_fsync") ;
-  reiserfs_prepare_for_journal(th.t_super, SB_BUFFER_WITH_SB(th.t_super), 1) ;
-  journal_mark_dirty(&th, dentry->d_inode->i_sb, SB_BUFFER_WITH_SB (dentry->d_inode->i_sb)) ;
-  pop_journal_writer(windex) ;
-  journal_end_sync(&th, dentry->d_inode->i_sb, 1) ;
-
-  unlock_kernel();
-
-  return ret ;
+  reiserfs_commit_for_inode(dentry->d_inode) ;
+  unlock_kernel() ;
+  return 0 ;
 }
 
 
@@ -210,24 +198,3 @@
     reiserfs_check_path(&path_to_entry) ;
     return 0;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/do_balan.c linux/fs/reiserfs/do_balan.c
--- v2.4.12/linux/fs/reiserfs/do_balan.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/do_balan.c	Fri Oct 12 14:19:28 2001
@@ -104,20 +104,9 @@
     switch (flag) {
     case M_DELETE:   /* delete item in S[0] */
 
-	 RFALSE( le16_to_cpu (ih->ih_item_len) + IH_SIZE != -tb->insert_size [0],
-		 "vs-12013: mode Delete, insert size %d, ih to be deleted %h", 
-		 ih);
-
-#if 0 /* rigth delim key not supported */
-	if ( ! item_pos && (! tb->L[0] || COMP_KEYS(B_PRIGHT_DELIM_KEY(tb->L[0]), B_N_PKEY(tbS0, 0))) ) {
-	    print_cur_tb ("12015");
-	    reiserfs_panic (tb->tb_sb, "PAP-12015: balance_leaf_when_delete: L0's rkey does not match to 1st key of S0: "
-			    "rkey in L %k, first key in S0 %k, rkey in CFL %k",
-			    tb->L[0] ? B_PRIGHT_DELIM_KEY(tb->L[0]) : 0, 
-			    B_N_PKEY(tbS0, 0),
-			    tb->CFL[0] ? B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0]) : 0);
-	}
-#endif
+	RFALSE( ih_item_len(ih) + IH_SIZE != -tb->insert_size[0],
+	        "vs-12013: mode Delete, insert size %d, ih to be deleted %h",
+                ih);
 
 	bi.tb = tb;
 	bi.bi_bh = tbS0;
@@ -128,18 +117,10 @@
 	if ( ! item_pos && tb->CFL[0] ) {
 	    if ( B_NR_ITEMS(tbS0) ) {
 		replace_key(tb, tb->CFL[0],tb->lkey[0],tbS0,0);
-#if 0 /* right delim key support */
-		copy_key(B_PRIGHT_DELIM_KEY(tb->L[0]), B_N_PKEY(tbS0, 0));
-		reiserfs_mark_buffer_dirty (tb->L[0], 0);
-#endif
 	    }
 	    else {
 		if ( ! PATH_H_POSITION (tb->tb_path, 1) )
 		    replace_key(tb, tb->CFL[0],tb->lkey[0],PATH_H_PPARENT(tb->tb_path, 0),0);
-#if 0 /* right delim key support */
-		copy_key(B_PRIGHT_DELIM_KEY(tb->L[0]), B_PRIGHT_DELIM_KEY(tbS0));
-		reiserfs_mark_buffer_dirty (tb->L[0], 0);
-#endif
 	    }
 	} 
 
@@ -155,14 +136,6 @@
 	bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
 	if (is_direntry_le_ih (ih)) {
 
-#ifdef CONFIG_REISERFS_CHECK
-#if 0 /* right delim key support */
-	    if ( ! item_pos && ! pos_in_item && (! tb->L[0] || COMP_KEYS(B_PRIGHT_DELIM_KEY(tb->L[0]), 
-									 B_N_PKEY(tbS0, 0))) )
-		reiserfs_panic(tb->tb_sb, "PAP-12025: balance_leaf_when_delete: illegal right delimiting key");
-#endif
-#endif
-
 	    /* UFS unlink semantics are such that you can only delete one directory entry at a time. */
 	    /* when we cut a directory tb->insert_size[0] means number of entries to be cut (always 1) */
 	    tb->insert_size[0] = -1;
@@ -174,16 +147,12 @@
 
 	    if ( ! item_pos && ! pos_in_item && tb->CFL[0] ) {
 		replace_key(tb, tb->CFL[0],tb->lkey[0],tbS0,0);
-#if 0/* right delim key support */
-		copy_key(B_PRIGHT_DELIM_KEY(tb->L[0]), B_N_PKEY(tbS0, 0));
-		reiserfs_mark_buffer_dirty (tb->L[0], 0);
-#endif
 	    }
 	} else {
 	    leaf_cut_from_buffer (&bi, item_pos, pos_in_item, -tb->insert_size[0]);
 
-	    RFALSE( ! ih->ih_item_len,
-		    "PAP-12035: cut must leave non-zero dynamic length of item");
+	    RFALSE( ! ih_item_len(ih),
+		"PAP-12035: cut must leave non-zero dynamic length of item");
 	}
 	break;
     }
@@ -208,17 +177,9 @@
 		    if ( PATH_H_POSITION (tb->tb_path, 1) == 0 && 1 < B_NR_ITEMS(tb->FR[0]) )
 			replace_key(tb, tb->CFL[0],tb->lkey[0],tb->FR[0],1);
 
-		    /* update right_delimiting_key field */
-#if 0
-		    copy_key (B_PRIGHT_DELIM_KEY (tb->L[0]), B_PRIGHT_DELIM_KEY (tb->R[0]));
-#endif
 		    leaf_move_items (LEAF_FROM_S_TO_L, tb, n, -1, 0);
 		    leaf_move_items (LEAF_FROM_R_TO_L, tb, B_NR_ITEMS(tb->R[0]), -1, 0);
 
-#if 0/*preserve list*/
-		    preserve_invalidate(tb, tbS0, tb->L[0]); 
-		    preserve_invalidate(tb, tb->R[0], tb->L[0]);
-#endif
 		    reiserfs_invalidate_buffer (tb, tbS0);
 		    reiserfs_invalidate_buffer (tb, tb->R[0]);
 
@@ -231,11 +192,6 @@
 		/* right_delimiting_key is correct in R[0] */
 		replace_key(tb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
 
-#if 0
-		/* mark tb->R[0] as suspected recipient */
-		preserve_invalidate(tb,tbS0, tb->R[0]);
-		preserve_invalidate(tb,tb->L[0], tb->R[0]); 
-#endif
 		reiserfs_invalidate_buffer (tb, tbS0);
 		reiserfs_invalidate_buffer (tb, tb->L[0]);
 
@@ -247,9 +203,6 @@
 	    /* all contents of L[0] and S[0] will be in L[0] */
 	    leaf_shift_left(tb, n, -1);
 
-#if 0/*preserve list*/
-	    preserve_invalidate(tb, tbS0, tb->L[0]);  /* preserved, shifting */
-#endif
 	    reiserfs_invalidate_buffer (tb, tbS0);
 
 	    return 0;
@@ -272,10 +225,6 @@
 	leaf_shift_left (tb, tb->lnum[0], tb->lbytes);
 	leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
 
-#if 0/*preserve list*/
-	preserve_invalidate (tb, tbS0, tb->L[0]);
-	mark_suspected_recipient (tb->tb_sb, tb->R[0]);
-#endif
 	reiserfs_invalidate_buffer (tb, tbS0);
 
 	return 0;
@@ -284,9 +233,6 @@
     if ( tb->rnum[0] == -1 ) {
 	/* all contents of R[0] and S[0] will be in R[0] */
 	leaf_shift_right(tb, n, -1);
-#if 0/*preserve list*/
-	preserve_invalidate(tb, tbS0, tb->R[0]); 
-#endif
 	reiserfs_invalidate_buffer (tb, tbS0);
 	return 0;
     }
@@ -310,10 +256,6 @@
     )
 {
     struct buffer_head * tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#if 0/*preserve list*/
-    struct buffer_head * tbF0 = PATH_H_PPARENT (tb->tb_path, 0);
-    int S0_b_item_order = PATH_H_B_ITEM_ORDER (tb->tb_path, 0);
-#endif
     int item_pos = PATH_LAST_POSITION (tb->tb_path);	/*  index into the array of item headers in S[0] 
 							    of the affected item */
     struct buffer_info bi;
@@ -344,7 +286,7 @@
   
     zeros_num = 0;
     if (flag == M_INSERT && body == 0)
-	zeros_num = le16_to_cpu (ih->ih_item_len); 
+	zeros_num = ih_item_len( ih );
 
     pos_in_item = tb->tb_path->pos_in_item;
     /* for indirect item pos_in_item is measured in unformatted node
@@ -366,27 +308,18 @@
 		    int new_item_len;
 		    int version;
 
-		    RFALSE( !is_direct_le_ih (ih),
+		    RFALSE (!is_direct_le_ih (ih),
 			    "PAP-12075: only direct inserted item can be broken. %h", ih);
 		    ret_val = leaf_shift_left (tb, tb->lnum[0]-1, -1);
-		    /* when reading the if conditions preceding the subsequent preserve_shifted
-		       lines understand that their goal is to determine if all that we are
-		       shifting is the new data being added */
-#if 0/*preserve list*/
-		    if (tb->lnum[0] - 1 > 0) {
-			preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->L[0]);
-			tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-		    }
-#endif
 
 		    /* Calculate item length to insert to S[0] */
-		    new_item_len = le16_to_cpu (ih->ih_item_len) - tb->lbytes;
+		    new_item_len = ih_item_len(ih) - tb->lbytes;
 		    /* Calculate and check item length to insert to L[0] */
-		    ih->ih_item_len -= new_item_len;
+		    put_ih_item_len(ih, ih_item_len(ih) - new_item_len );
 
-		    RFALSE( (int)(ih->ih_item_len) <= 0,
+		    RFALSE( ih_item_len(ih) <= 0,
 			    "PAP-12080: there is nothing to insert into L[0]: ih_item_len=%d",
-			    (int)ih->ih_item_len);
+                            ih_item_len(ih));
 
 		    /* Insert new item into L[0] */
 		    bi.tb = tb;
@@ -394,14 +327,14 @@
 		    bi.bi_parent = tb->FL[0];
 		    bi.bi_position = get_left_neighbor_position (tb, 0);
 		    leaf_insert_into_buf (&bi, n + item_pos - ret_val, ih, body,
-					  zeros_num > ih->ih_item_len ? ih->ih_item_len : zeros_num);
+					  zeros_num > ih_item_len(ih) ? ih_item_len(ih) : zeros_num);
 
 		    version = ih_version (ih);
 
 		    /* Calculate key component, item length and body to insert into S[0] */
-		    set_le_key_k_offset (ih_version (ih), &(ih->ih_key),
-					 le_key_k_offset (ih_version (ih), &(ih->ih_key)) + tb->lbytes);
-		    ih->ih_item_len = cpu_to_le16 (new_item_len);
+                    set_le_ih_k_offset( ih, le_ih_k_offset( ih ) + tb->lbytes );
+
+		    put_ih_item_len( ih, new_item_len );
 		    if ( tb->lbytes >  zeros_num ) {
 			body += (tb->lbytes - zeros_num);
 			zeros_num = 0;
@@ -409,30 +342,19 @@
 		    else
 			zeros_num -= tb->lbytes;
 
-		    RFALSE( (int)(ih->ih_item_len) <= 0,
-			    "PAP-12085: there is nothing to insert into S[0]: ih_item_len=%d",
-			    (int)ih->ih_item_len);
+		    RFALSE( ih_item_len(ih) <= 0,
+			"PAP-12085: there is nothing to insert into S[0]: ih_item_len=%d",
+			ih_item_len(ih));
 		} else {
 		    /* new item in whole falls into L[0] */
 		    /* Shift lnum[0]-1 items to L[0] */
 		    ret_val = leaf_shift_left(tb, tb->lnum[0]-1, tb->lbytes);
-#if 0/*preserve list*/
-		    if (tb->lnum[0] > 1) {
-			preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->L[0]);
-			tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-		    }
-#endif
 		    /* Insert new item into L[0] */
 		    bi.tb = tb;
 		    bi.bi_bh = tb->L[0];
 		    bi.bi_parent = tb->FL[0];
 		    bi.bi_position = get_left_neighbor_position (tb, 0);
 		    leaf_insert_into_buf (&bi, n + item_pos - ret_val, ih, body, zeros_num);
-#if 0/*preserve list*/
-		    if (tb->preserve_mode == PRESERVE_INDIRECT_TO_DIRECT){
-			mark_suspected_recipient (tb->tb_sb, bi.bi_bh);
-		    }
-#endif
 		    tb->insert_size[0] = 0;
 		    zeros_num = 0;
 		}
@@ -454,10 +376,6 @@
 							  
 			    /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */
 			    ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes - 1);
-#if 0/*preserve list*/
-			    preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->L[0]);
-			    tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
 			    if ( ret_val && ! item_pos ) {
 				pasted =  B_N_PITEM_HEAD(tb->L[0],B_NR_ITEMS(tb->L[0])-1);
 				l_pos_in_item += I_ENTRY_COUNT(pasted) - (tb->lbytes-1);
@@ -485,10 +403,6 @@
 			    /* new directory item doesn't fall into L[0] */
 			    /* Shift lnum[0]-1 items in whole. Shift lbytes directory entries from directory item number lnum[0] */
 			    leaf_shift_left (tb, tb->lnum[0], tb->lbytes);
-#if 0/*preserve list*/
-			    preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->L[0]);
-			    tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
 			}
 			/* Calculate new position to append in item body */
 			pos_in_item -= tb->lbytes;
@@ -496,11 +410,12 @@
 		    else {
 			/* regular object */
 			RFALSE( tb->lbytes <= 0,
-				"PAP-12095: there is nothing to shift to L[0]. lbytes=%d",
+			        "PAP-12095: there is nothing to shift to L[0]. lbytes=%d",
 				tb->lbytes);
-			RFALSE( pos_in_item != B_N_PITEM_HEAD(tbS0, item_pos)->ih_item_len,
-				"PAP-12100: incorrect position to paste: item_len=%d, pos_in_item=%d",
-				B_N_PITEM_HEAD(tbS0,item_pos)->ih_item_len, pos_in_item);
+			RFALSE( pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)),
+                                "PAP-12100: incorrect position to paste: item_len=%d, pos_in_item=%d",
+				ih_item_len(B_N_PITEM_HEAD(tbS0,item_pos)), pos_in_item);
+
 			if ( tb->lbytes >= pos_in_item ) {
 			    /* appended item will be in L[0] in whole */
 			    int l_n;
@@ -515,11 +430,7 @@
 				    "PAP-12105: there is nothing to paste into L[0]. insert_size=%d",
 				    tb->insert_size[0]);
 			    ret_val =  leaf_shift_left(tb,tb->lnum[0], 
-						       B_N_PITEM_HEAD(tbS0,item_pos)->ih_item_len);
-#if 0/*preserve list*/
-			    preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->L[0]);
-			    tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
+						       ih_item_len(B_N_PITEM_HEAD(tbS0,item_pos)));
 			    /* Append to body of item in L[0] */
 			    bi.tb = tb;
 			    bi.bi_bh = tb->L[0];
@@ -527,7 +438,7 @@
 			    bi.bi_position = get_left_neighbor_position (tb, 0);
 			    leaf_paste_in_buffer(
 				&bi,n + item_pos - ret_val,
-				B_N_PITEM_HEAD(tb->L[0],n+item_pos-ret_val)->ih_item_len,
+				ih_item_len( B_N_PITEM_HEAD(tb->L[0],n+item_pos-ret_val)),
 				l_n,body, zeros_num > l_n ? l_n : zeros_num
 				);
 
@@ -541,15 +452,13 @@
 			    {
 			      int version;
 
-			      version = le16_to_cpu (B_N_PITEM_HEAD (tbS0, 0)->ih_version);
+			      version = ih_version (B_N_PITEM_HEAD (tbS0, 0));
 			      set_le_key_k_offset (version, B_N_PKEY (tbS0, 0), 
 						   le_key_k_offset (version, B_N_PKEY (tbS0, 0)) + l_n);
+			      version = ih_version (B_N_PITEM_HEAD(tb->CFL[0],tb->lkey[0]));
 			      set_le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0]),
 						   le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0])) + l_n);
 			    }
-			    /*    k_offset (B_N_PKEY (tbS0, 0)) += l_n;
-				  k_offset (B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0])) += l_n;
-				  k_offset (B_PRIGHT_DELIM_KEY(tb->L[0])) += l_n;*/
 
 			    /* Calculate new body, position in item and insert_size[0] */
 			    if ( l_n > zeros_num ) {
@@ -581,10 +490,6 @@
 
 			    /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
 			    leaf_shift_left(tb,tb->lnum[0],tb->lbytes);
-#if 0/*preserve list*/
-			    preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->L[0]);
-			    tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
 			}
 		    }
 		}
@@ -597,17 +502,13 @@
 			    /* then increment pos_in_item by the size of the last item in L[0] */
 			    pasted = B_N_PITEM_HEAD(tb->L[0],n-1);
 			    if ( is_direntry_le_ih (pasted) )
-				pos_in_item += le16_to_cpu (pasted->u.ih_entry_count);
+				pos_in_item += ih_entry_count(pasted);
 			    else
-				pos_in_item += le16_to_cpu (pasted->ih_item_len);
+				pos_in_item += ih_item_len(pasted);
 			}
 
 		    /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
 		    ret_val = leaf_shift_left(tb,tb->lnum[0],tb->lbytes);
-#if 0/*preserve list*/
-		    preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->L[0]);
-		    tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
 		    /* Append to body of item in L[0] */
 		    bi.tb = tb;
 		    bi.bi_bh = tb->L[0];
@@ -637,10 +538,6 @@
 	} else { 
 	    /* new item doesn't fall into L[0] */
 	    leaf_shift_left(tb,tb->lnum[0],tb->lbytes);
-#if 0/*preserve list*/
-	    preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->L[0]);
-	    tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
 	}
     }	/* tb->lnum[0] > 0 */
 
@@ -667,22 +564,16 @@
 			    ih);
 
 		    leaf_shift_right(tb,tb->rnum[0]-1,-1);
-#if 0/*preserve list*/
-		    if (tb->rnum[0]>1) {
-			preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->R[0]);
-			tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-		    }
-#endif
 
-		    version = le16_to_cpu (ih->ih_version);
+		    version = ih_version(ih);
 		    /* Remember key component and item length */
-		    old_key_comp = le_key_k_offset (version, &(ih->ih_key));
-		    old_len = le16_to_cpu (ih->ih_item_len);
+                    old_key_comp = le_ih_k_offset( ih );
+		    old_len = ih_item_len(ih);
 
 		    /* Calculate key component and item length to insert into R[0] */
-		    offset = le_key_k_offset (version, &(ih->ih_key)) + (old_len - tb->rbytes);
-		    set_le_key_k_offset (version, &(ih->ih_key), offset);
-		    ih->ih_item_len = cpu_to_le16 (tb->rbytes);
+                    offset = le_ih_k_offset( ih ) + (old_len - tb->rbytes );
+                    set_le_ih_k_offset( ih, offset );
+		    put_ih_item_len( ih, tb->rbytes);
 		    /* Insert part of the item into R[0] */
 		    bi.tb = tb;
 		    bi.bi_bh = tb->R[0];
@@ -704,8 +595,8 @@
 		    replace_key(tb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
 
 		    /* Calculate key component and item length to insert into S[0] */
-		    set_le_key_k_offset (version, &(ih->ih_key), old_key_comp);
-		    ih->ih_item_len = cpu_to_le16 (old_len - tb->rbytes);
+                    set_le_ih_k_offset( ih, old_key_comp );
+		    put_ih_item_len( ih, old_len - tb->rbytes );
 
 		    tb->insert_size[0] -= tb->rbytes;
 
@@ -714,33 +605,16 @@
 		{					  
 		    /* Shift rnum[0]-1 items to R[0] */
 		    ret_val = leaf_shift_right(tb,tb->rnum[0]-1,tb->rbytes);
-#if 0/*preserve list*/
-		    if (tb->rnum[0]>1) {
-			preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->R[0]);
-			tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-		    }
-#endif
 		    /* Insert new item into R[0] */
 		    bi.tb = tb;
 		    bi.bi_bh = tb->R[0];
 		    bi.bi_parent = tb->FR[0];
 		    bi.bi_position = get_right_neighbor_position (tb, 0);
 		    leaf_insert_into_buf (&bi, item_pos - n + tb->rnum[0] - 1, ih, body, zeros_num);
-#if 0/*preserve list*/
-		    if (tb->preserve_mode == PRESERVE_INDIRECT_TO_DIRECT){
-			mark_suspected_recipient (tb->tb_sb, bi.bi_bh);
-		    }
-#endif
 
-		    /* If we insert new item in the begin of R[0] change the right delimiting key */
 		    if ( item_pos - n + tb->rnum[0] - 1 == 0 ) {
 			replace_key(tb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
 
-#if 0
-			/* update right delimiting key */
-			copy_key(B_PRIGHT_DELIM_KEY(tbS0), &(ih->ih_key));
-			reiserfs_mark_buffer_dirty (tbS0, 0);
-#endif
 		    }
 		    zeros_num = tb->insert_size[0] = 0;
 		}
@@ -748,10 +622,6 @@
 	    else /* new item or part of it doesn't fall into R[0] */
 	    {
 		leaf_shift_right(tb,tb->rnum[0],tb->rbytes);
-#if 0/*preserve list*/
-		preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->R[0]);
-		tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
 	    }
 	    break;
 
@@ -779,13 +649,6 @@
 				    tb->rbytes, entry_count);
 			    /* Shift rnum[0]-1 items in whole. Shift rbytes-1 directory entries from directory item number rnum[0] */
 			    leaf_shift_right(tb,tb->rnum[0],tb->rbytes - 1);
-#if 0/*preserve list*/
-			    /* if we are shifting more than just the new entry */
-			    if (tb->rbytes > 1 || tb->rnum[0] > 1) {
-				preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->R[0]);
-				tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-			    }
-#endif
 			    /* Paste given directory entry to directory item */
 			    paste_entry_position = pos_in_item - entry_count + tb->rbytes - 1;
 			    bi.tb = tb;
@@ -803,10 +666,6 @@
 			    if ( paste_entry_position == 0 ) {
 				/* change delimiting keys */
 				replace_key(tb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
-#if 0
-				copy_key(B_PRIGHT_DELIM_KEY(tbS0), B_N_PKEY(tb->R[0], 0));
-				reiserfs_mark_buffer_dirty (tbS0, 0);
-#endif
 			    }
 
 			    tb->insert_size[0] = 0;
@@ -815,10 +674,6 @@
 			else /* new directory entry doesn't fall into R[0] */
 			{
 			    leaf_shift_right(tb,tb->rnum[0],tb->rbytes);
-#if 0/*preserve list*/
-			    preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->R[0]);
-			    tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
 			}
 		    }
 		    else /* regular object */
@@ -830,18 +685,11 @@
 			if ( (n_shift = tb->rbytes - tb->insert_size[0]) < 0 )
 			    n_shift = 0;
 
-			RFALSE( pos_in_item != B_N_PITEM_HEAD (tbS0, item_pos)->ih_item_len,
-				"PAP-12155: invalid position to paste. ih_item_len=%d, pos_in_item=%d",
-				pos_in_item, B_N_PITEM_HEAD(tbS0,item_pos)->ih_item_len);
+			RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD (tbS0, item_pos)),
+			       "PAP-12155: invalid position to paste. ih_item_len=%d, pos_in_item=%d",
+                               pos_in_item, ih_item_len( B_N_PITEM_HEAD(tbS0,item_pos)));
 
 			leaf_shift_right(tb,tb->rnum[0],n_shift);
-#if 0/*preserve list*/
-			/* if we are shifting an old part from the appended item or more than the appended item is going into R */
-			if (n_shift || tb->rnum[0] > 1) {
-			    preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->R[0]);
-			    tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-			}
-#endif
 			/* Calculate number of bytes which must remain in body after appending to R[0] */
 			if ( (n_rem = tb->insert_size[0] - tb->rbytes) < 0 )
 			    n_rem = 0;
@@ -859,11 +707,6 @@
 		  k_offset (B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) += n_rem;*/
 			do_balance_mark_internal_dirty (tb, tb->CFR[0], 0);
 
-#if 0
-			set_le_key_k_offset (B_PRIGHT_DELIM_KEY(tbS0), le_key_k_offset (B_PRIGHT_DELIM_KEY(tbS0)) + n_rem);
-/*		  k_offset (B_PRIGHT_DELIM_KEY(tbS0)) += n_rem;*/
-			reiserfs_mark_buffer_dirty (tbS0, 0);
-#endif
 			/* Append part of body into R[0] */
 			bi.tb = tb;
 			bi.bi_bh = tb->R[0];
@@ -899,10 +742,6 @@
 		    struct item_head * pasted;
 
 		    ret_val = leaf_shift_right(tb,tb->rnum[0],tb->rbytes);
-#if 0/*preserve list*/
-		    preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->R[0]);
-		    tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
 		    /* append item in R[0] */
 		    if ( pos_in_item >= 0 ) {
 			bi.tb = tb;
@@ -927,10 +766,6 @@
 
 			    /* update delimiting keys */
 			    replace_key(tb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
-#if 0
-			    copy_key(B_PRIGHT_DELIM_KEY(tbS0),B_N_PKEY(tb->R[0], 0));
-			    reiserfs_mark_buffer_dirty (tbS0, 0);
-#endif
 			}
 		    }
 
@@ -942,10 +777,6 @@
 	    else /* new item doesn't fall into R[0] */
 	    {
 		leaf_shift_right(tb,tb->rnum[0],tb->rbytes);
-#if 0/*preserve list*/
-		preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, tb->R[0]);
-		tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
 	    }
 	    break;
 	default:    /* cases d and t */
@@ -967,7 +798,7 @@
     if ( tb->blknum[0] == 0 ) { /* node S[0] is empty now */
 
 	RFALSE( ! tb->lnum[0] || ! tb->rnum[0],
-		"PAP-12190: lnum and rnum must not be zero");
+	        "PAP-12190: lnum and rnum must not be zero");
 	/* if insertion was done before 0-th position in R[0], right
 	   delimiting key of the tb->L[0]'s and left delimiting key are
 	   not set correctly */
@@ -1000,7 +831,7 @@
 	S_new[i] = get_FEB(tb);
 
 	/* initialized block type and tree level */
-	B_BLK_HEAD(S_new[i])->blk_level = cpu_to_le16 (DISK_LEAF_NODE_LEVEL);
+        set_blkh_level( B_BLK_HEAD(S_new[i]), DISK_LEAF_NODE_LEVEL );
 
 
 	n = B_NR_ITEMS(tbS0);
@@ -1024,22 +855,16 @@
 
 		    /* Move snum[i]-1 items from S[0] to S_new[i] */
 		    leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i] - 1, -1, S_new[i]);
-#if 0/*preserve list*/
-		    if (snum[i] > 1 ) {
-			preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, S_new[i]);
-			tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-		    }
-#endif
 		    /* Remember key component and item length */
 		    version = ih_version (ih);
-		    old_key_comp = le_key_k_offset (version, &(ih->ih_key));
-		    old_len = le16_to_cpu (ih->ih_item_len);
+                    old_key_comp = le_ih_k_offset( ih );
+		    old_len = ih_item_len(ih);
 
 		    /* Calculate key component and item length to insert into S_new[i] */
-		    set_le_key_k_offset (version, &(ih->ih_key), 
-					 le_key_k_offset (version, &(ih->ih_key)) + (old_len - sbytes[i]));
+                    set_le_ih_k_offset( ih,
+                                le_ih_k_offset(ih) + (old_len - sbytes[i] ) );
 
-		    ih->ih_item_len = cpu_to_le16 (sbytes[i]);
+		    put_ih_item_len( ih, sbytes[i] );
 
 		    /* Insert part of the item into S_new[i] before 0-th item */
 		    bi.tb = tb;
@@ -1047,21 +872,21 @@
 		    bi.bi_parent = 0;
 		    bi.bi_position = 0;
 
-		    if ( le_key_k_offset (version, &(ih->ih_key)) - old_key_comp > zeros_num ) {
+		    if ( le_ih_k_offset (ih) - old_key_comp > zeros_num ) {
 			r_zeros_number = 0;
-			r_body = body + (le_key_k_offset (version, &(ih->ih_key)) - old_key_comp) - zeros_num;
+			r_body = body + (le_ih_k_offset(ih) - old_key_comp) - zeros_num;
 		    }
 		    else {
 			r_body = body;
-			r_zeros_number = zeros_num - (le_key_k_offset (version, &(ih->ih_key)) - old_key_comp);
+			r_zeros_number = zeros_num - (le_ih_k_offset (ih) - old_key_comp);
 			zeros_num -= r_zeros_number;
 		    }
 
 		    leaf_insert_into_buf (&bi, 0, ih, r_body, r_zeros_number);
 
 		    /* Calculate key component and item length to insert into S[i] */
-		    set_le_key_k_offset (version, &(ih->ih_key), old_key_comp);
-		    ih->ih_item_len = cpu_to_le16 (old_len - sbytes[i]);
+                    set_le_ih_k_offset( ih, old_key_comp );
+		    put_ih_item_len( ih, old_len - sbytes[i] );
 		    tb->insert_size[0] -= sbytes[i];
 		}
 		else /* whole new item falls into S_new[i] */
@@ -1075,11 +900,6 @@
 		    bi.bi_parent = 0;
 		    bi.bi_position = 0;
 		    leaf_insert_into_buf (&bi, item_pos - n + snum[i] - 1, ih, body, zeros_num);
-#if 0/*preserve list*/
-		    if (tb->preserve_mode == PRESERVE_INDIRECT_TO_DIRECT){
-			mark_suspected_recipient (tb->tb_sb, bi.bi_bh);
-		    }
-#endif
 
 		    zeros_num = tb->insert_size[0] = 0;
 		}
@@ -1088,10 +908,6 @@
 	    else /* new item or it part don't falls into S_new[i] */
 	    {
 		leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]);
-#if 0/*preserve list*/
-		preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, S_new[i]);
-		tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
 	    }
 	    break;
 
@@ -1110,7 +926,7 @@
 
 			int entry_count;
 		
-			entry_count = le16_to_cpu (aux_ih->u.ih_entry_count);
+			entry_count = ih_entry_count(aux_ih);
 
 			if ( entry_count - sbytes[i] < pos_in_item  && pos_in_item <= entry_count ) {
 			    /* new directory entry falls into S_new[i] */
@@ -1123,14 +939,6 @@
 
 			    /* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */
 			    leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i]-1, S_new[i]);
-#if 0/*preserve list*/
-			    /* if more than the affected item is shifted, or if more than
-			       one entry (from the affected item) is shifted */
-			    if (snum[i] > 1 || sbytes[i] > 1) {
-				preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, S_new[i]);
-				tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-			    }
-#endif
 			    /* Paste given directory entry to directory item */
 			    bi.tb = tb;
 			    bi.bi_bh = S_new[i];
@@ -1155,9 +963,9 @@
 			int n_shift, n_rem, r_zeros_number;
 			const char * r_body;
 
-			RFALSE( pos_in_item != B_N_PITEM_HEAD(tbS0,item_pos)->ih_item_len ||
-				tb->insert_size[0] <= 0,
-				"PAP-12225: item too short or insert_size <= 0");
+			RFALSE( pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0,item_pos)) ||
+			        tb->insert_size[0] <= 0,
+			        "PAP-12225: item too short or insert_size <= 0");
 
 			/* Calculate number of bytes which must be shifted from appended item */
 			n_shift = sbytes[i] - tb->insert_size[0];
@@ -1195,8 +1003,7 @@
 				    reiserfs_panic (tb->tb_sb, "PAP-12230: balance_leaf: invalid action with indirect item");
 				set_ih_free_space (tmp, ((struct unfm_nodeinfo*)body)->unfm_freespace);
 			    }
-			    set_le_key_k_offset (ih_version (tmp), &tmp->ih_key, 
-						 le_key_k_offset (ih_version (tmp), &tmp->ih_key) + n_rem);
+                            set_le_ih_k_offset( tmp, le_ih_k_offset(tmp) + n_rem );
 			}
 
 			tb->insert_size[0] = n_rem;
@@ -1213,17 +1020,12 @@
 #ifdef CONFIG_REISERFS_CHECK
 		    struct item_head * ih = B_N_PITEM_HEAD(tbS0,item_pos);
 
-		    if ( ! is_direntry_le_ih(ih) && (pos_in_item != ih->ih_item_len ||
+		    if ( ! is_direntry_le_ih(ih) && (pos_in_item != ih_item_len(ih) ||
 						     tb->insert_size[0] <= 0) )
 			reiserfs_panic (tb->tb_sb, "PAP-12235: balance_leaf: pos_in_item must be equal to ih_item_len");
 #endif /* CONFIG_REISERFS_CHECK */
 
 		    ret_val = leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]);
-#if 0/*preserve list*/
-		    /* we must preserve that which we are pasting onto the end of and shifting */
-		    preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, S_new[i]);
-		    tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
 
 		    RFALSE( ret_val,
 			    "PAP-12240: unexpected value returned by leaf_move_items (%d)",
@@ -1255,10 +1057,6 @@
 	    else /* pasted item doesn't fall into S_new[i] */
 	    {
 		leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]);
-#if 0/*preserve list*/
-		preserve_shifted(tb, &(PATH_PLAST_BUFFER (tb->tb_path)), tbF0, S0_b_item_order, S_new[i]);
-		tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
-#endif
 	    }
 	    break;
 	default:    /* cases d and t */
@@ -1275,12 +1073,6 @@
 		   buffer_journal_dirty(S_new[i]))), 
 		"PAP-12247: S_new[%d] : (%b)\n", i, S_new[i]);
 
-#if 0
-	/* update right_delimiting_key fields */
-	copy_key (B_PRIGHT_DELIM_KEY (S_new[i]), B_PRIGHT_DELIM_KEY (tbS0));
-	copy_key (B_PRIGHT_DELIM_KEY (tbS0), B_N_PKEY (S_new[i], 0));
-	reiserfs_mark_buffer_dirty (tbS0, 0);
-#endif
 
     }
 
@@ -1297,29 +1089,12 @@
 	    bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
 	    bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
 	    leaf_insert_into_buf (&bi, item_pos, ih, body, zeros_num);
-#if 0/*preserve list*/
-	    if (tb->preserve_mode == PRESERVE_INDIRECT_TO_DIRECT){
-		mark_suspected_recipient (tb->tb_sb, bi.bi_bh);
-	    }
-#endif
 
 	    /* If we insert the first key change the delimiting key */
 	    if( item_pos == 0 ) {
 		if (tb->CFL[0]) /* can be 0 in reiserfsck */
 		    replace_key(tb, tb->CFL[0], tb->lkey[0],tbS0,0);
 
-#if 0 /* right delim key support */
-#ifdef CONFIG_REISERFS_CHECK
-		if ( ! tb->CFL[0] || ! tb->L[0] || (B_NR_ITEMS (tbS0) > 1 && 
-						    COMP_KEYS(B_PRIGHT_DELIM_KEY(tb->L[0]), B_N_PKEY(tbS0, 1))) )
-		    reiserfs_panic(tb->tb_sb, "PAP-12250: balance_leaf: invalid right delimiting key");
-		if (!buffer_dirty (tb->L[0]) && !(buffer_journaled(tb->L[0]) ||
-		     buffer_journal_dirty(tb->L[0])))
-		    reiserfs_panic (tb->tb_sb, "PAP-12255: balance_leaf: tb->L[0] must be dirty");
-#endif
-		if (tb->L[0]) /* can be 0 in reiserfsck */
-		    copy_key (B_PRIGHT_DELIM_KEY (tb->L[0]), &(ih->ih_key));   
-#endif /* right delim key support */
 	    }
 	    break;
 
@@ -1329,7 +1104,8 @@
 	    pasted = B_N_PITEM_HEAD (tbS0, item_pos);
 	    /* when directory, may be new entry already pasted */
 	    if (is_direntry_le_ih (pasted)) {
-		if ( pos_in_item >= 0 && pos_in_item <= le16_to_cpu (pasted->u.ih_entry_count) ) {
+		if ( pos_in_item >= 0 &&
+		    pos_in_item <= ih_entry_count(pasted) ) {
 
 		    RFALSE( ! tb->insert_size[0], 
 			    "PAP-12260: insert_size is 0 already");
@@ -1341,15 +1117,6 @@
 		    bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
 		    leaf_paste_in_buffer(&bi, item_pos, pos_in_item, tb->insert_size[0], body, zeros_num);
 
-
-#ifdef CONFIG_REISERFS_CHECK
-#if 0
-		    if ( ! item_pos && ! pos_in_item  && (! tb->L[0] || COMP_KEYS(B_PRIGHT_DELIM_KEY(tb->L[0]), 
-										  B_N_PKEY(tbS0, 0))) )
-			reiserfs_panic(tb->tb_sb, "PAP-12265: balance_leaf: invalid right delimiting key");
-#endif
-#endif
-
 		    /* paste entry */
 		    leaf_paste_entries (
 			bi.bi_bh, item_pos, pos_in_item, 1, (struct reiserfs_de_head *)body,
@@ -1361,21 +1128,16 @@
 			if (tb->CFL[0]) {
 			    replace_key(tb, tb->CFL[0], tb->lkey[0],tbS0,0);
 
-#if 0
-			    /* update right delimiting key */
-			    copy_key (B_PRIGHT_DELIM_KEY (tb->L[0]), B_N_PKEY(tbS0, 0));   
-			    /* probably not needed as something has been shifted to tb->L[0] already */
-			    reiserfs_mark_buffer_dirty (tb->L[0], 0);
-#endif
 			}
 		    }
 		    tb->insert_size[0] = 0;
 		}
 	    } else { /* regular object */
-		if ( pos_in_item == pasted->ih_item_len ) {
+		if ( pos_in_item == ih_item_len(pasted) ) {
+
 		    RFALSE( tb->insert_size[0] <= 0,
-			    "PAP-12275: insert size must not be %d", 
-			    tb->insert_size[0]);
+			    "PAP-12275: insert size must not be %d",
+                            tb->insert_size[0]);
 		    bi.tb = tb;
 		    bi.bi_bh = tbS0;
 		    bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
@@ -1425,11 +1187,12 @@
 
     RFALSE( bi->bi_bh == NULL, "PAP-12295: pointer to the buffer is NULL");
 
-    (blkh = B_BLK_HEAD(bi->bi_bh))->blk_nr_item = cpu_to_le16 (0);
-    blkh->blk_free_space = cpu_to_le16 (MAX_CHILD_SIZE(bi->bi_bh));
+    blkh = B_BLK_HEAD(bi->bi_bh);
+    set_blkh_nr_item( blkh, 0 );
+    set_blkh_free_space( blkh, MAX_CHILD_SIZE(bi->bi_bh) );
 
     if (bi->bi_parent)
-	B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size = 0; 
+	B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size = 0; /* Endian safe if 0 */
 }
 
 
@@ -1494,8 +1257,11 @@
 
 void reiserfs_invalidate_buffer (struct tree_balance * tb, struct buffer_head * bh)
 {
-    B_BLK_HEAD (bh)->blk_level = cpu_to_le16 (FREE_LEVEL)/*0*/;
-    B_BLK_HEAD (bh)->blk_nr_item = cpu_to_le16 (0);
+    struct block_head *blkh;
+    blkh = B_BLK_HEAD(bh);
+    set_blkh_level( blkh, FREE_LEVEL );
+    set_blkh_nr_item( blkh, 0 );
+    
     mark_buffer_clean (bh);
     /* reiserfs_free_block is no longer schedule safe 
     reiserfs_free_block (tb->transaction_handle, tb->tb_sb, bh->b_blocknr);
@@ -1583,7 +1349,7 @@
   dc = B_N_CHILD (bh, 0);
 
   for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) {
-    if (!is_reusable (s, dc->dc_block_number, 1) ) {
+    if (!is_reusable (s, dc_block_number(dc), 1) ) {
       print_cur_tb (mes);
       reiserfs_panic (s, "PAP-12338: check_internal_node: invalid child pointer %y in %b", dc, bh);
     }
@@ -1636,23 +1402,37 @@
 {
     if (tb->lnum[0]) {
 	if (B_FREE_SPACE (tb->L[0]) != 
-	    MAX_CHILD_SIZE (tb->L[0]) - B_N_CHILD (tb->FL[0], get_left_neighbor_position (tb, 0))->dc_size) {
+	    MAX_CHILD_SIZE (tb->L[0]) - dc_size(B_N_CHILD (tb->FL[0], get_left_neighbor_position (tb, 0)))) {
 	    print_cur_tb ("12221");
 	    reiserfs_panic (tb->tb_sb, "PAP-12355: check_after_balance_leaf: shift to left was incorrect");
 	}
     }
     if (tb->rnum[0]) {
 	if (B_FREE_SPACE (tb->R[0]) != 
-	    MAX_CHILD_SIZE (tb->R[0]) - B_N_CHILD (tb->FR[0], get_right_neighbor_position (tb, 0))->dc_size) {
+	    MAX_CHILD_SIZE (tb->R[0]) - dc_size(B_N_CHILD (tb->FR[0], get_right_neighbor_position (tb, 0)))) {
 	    print_cur_tb ("12222");
 	    reiserfs_panic (tb->tb_sb, "PAP-12360: check_after_balance_leaf: shift to right was incorrect");
 	}
     }
-    if (PATH_H_PBUFFER(tb->tb_path,1) && (B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0)) != 
-					  (MAX_CHILD_SIZE (PATH_H_PBUFFER(tb->tb_path,0)) -
-					   B_N_CHILD (PATH_H_PBUFFER(tb->tb_path,1),
-						      PATH_H_POSITION (tb->tb_path, 1))->dc_size))) {
+    if (PATH_H_PBUFFER(tb->tb_path,1) &&
+	(B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0)) != 
+		    (MAX_CHILD_SIZE (PATH_H_PBUFFER(tb->tb_path,0)) -
+		    dc_size(B_N_CHILD (PATH_H_PBUFFER(tb->tb_path,1),
+		    PATH_H_POSITION (tb->tb_path, 1)))) )) {
+	int left = B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0));
+	int right = (MAX_CHILD_SIZE (PATH_H_PBUFFER(tb->tb_path,0)) -
+		    dc_size(B_N_CHILD (PATH_H_PBUFFER(tb->tb_path,1),
+			PATH_H_POSITION (tb->tb_path, 1))));
 	print_cur_tb ("12223");
+	reiserfs_warning(
+	    "B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0)) = %d; "
+    	    "MAX_CHILD_SIZE (%d) - dc_size( %y, %d ) [%d] = %d\n",
+	    left,
+	    MAX_CHILD_SIZE (PATH_H_PBUFFER(tb->tb_path,0)),
+	    PATH_H_PBUFFER(tb->tb_path,1),
+	    PATH_H_POSITION (tb->tb_path, 1),
+	    dc_size(B_N_CHILD (PATH_H_PBUFFER(tb->tb_path,1), PATH_H_POSITION (tb->tb_path, 1 )) ),
+	    right );
 	reiserfs_panic (tb->tb_sb, "PAP-12365: check_after_balance_leaf: S is incorrect");
     }
 }
@@ -1783,8 +1563,8 @@
 			       existing file or to insert a directory
 			       entry.  */
 {
-    int child_pos,					/* position of a child node in its parent */
-	h;								/* level of the tree being processed */
+    int child_pos, /* position of a child node in its parent */
+	h;	   /* level of the tree being processed */
     struct item_head insert_key[2]; /* in our processing of one level
 				       we sometimes determine what
 				       must be inserted into the next
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/file.c linux/fs/reiserfs/file.c
--- v2.4.12/linux/fs/reiserfs/file.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/reiserfs/file.c	Fri Oct 12 14:20:42 2001
@@ -42,6 +42,7 @@
     lock_kernel() ;
     down (&inode->i_sem); 
     journal_begin(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3) ;
+    reiserfs_update_inode_transaction(inode) ;
 
 #ifdef REISERFS_PREALLOCATE
     reiserfs_discard_prealloc (&th, inode);
@@ -75,10 +76,7 @@
 			      int datasync
 			      ) {
   struct inode * p_s_inode = p_s_dentry->d_inode;
-  struct reiserfs_transaction_handle th ;
   int n_err;
-  int windex ;
-  int jbegin_count = 1 ;
 
   lock_kernel() ;
 
@@ -87,14 +85,7 @@
 
   n_err = fsync_inode_buffers(p_s_inode) ;
   n_err |= fsync_inode_data_buffers(p_s_inode);
-  /* commit the current transaction to flush any metadata
-  ** changes.  sys_fsync takes care of flushing the dirty pages for us
-  */
-  journal_begin(&th, p_s_inode->i_sb, jbegin_count) ;
-  windex = push_journal_writer("sync_file") ;
-  reiserfs_update_sd(&th, p_s_inode);
-  pop_journal_writer(windex) ;
-  journal_end_sync(&th, p_s_inode->i_sb,jbegin_count) ;
+  reiserfs_commit_for_inode(p_s_inode) ;
   unlock_kernel() ;
   return ( n_err < 0 ) ? -EIO : 0;
 }
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c
--- v2.4.12/linux/fs/reiserfs/fix_node.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/fix_node.c	Fri Oct 12 14:19:28 2001
@@ -124,7 +124,7 @@
 	/* get item number in source node */
 	j = old_item_num (new_num, vn->vn_affected_item_num, vn->vn_mode);
     
-	vi->vi_item_len += ih[j].ih_item_len + IH_SIZE;
+	vi->vi_item_len += ih_item_len(ih + j) + IH_SIZE;
 	vi->vi_ih = ih + j;
 	vi->vi_item = B_I_PITEM (Sh, ih + j);
 	vi->vi_uarea = vn->vn_free_ptr;
@@ -658,9 +658,8 @@
 	    
 	    /* we might check that left neighbor exists and is of the
 	       same directory */
-	    RFALSE( le_key_k_offset 
-		    (ih_version (ih), &(ih->ih_key)) == DOT_OFFSET,
-		    "vs-8130: first directory item can not be removed until directory is not empty");
+	    RFALSE(le_ih_k_offset (ih) == DOT_OFFSET,
+		"vs-8130: first directory item can not be removed until directory is not empty");
       }
     
   }
@@ -857,7 +856,7 @@
 	f = l;
     }
 
-    return (MAX_CHILD_SIZE(f) - le16_to_cpu (B_N_CHILD(f,order)->dc_size));
+    return (MAX_CHILD_SIZE(f) - dc_size(B_N_CHILD(f,order)));
 }
 
 
@@ -879,7 +878,7 @@
       f = r;
   }
 
-  return (MAX_CHILD_SIZE(f) - B_N_CHILD(f,order)->dc_size);
+  return (MAX_CHILD_SIZE(f) - dc_size( B_N_CHILD(f,order)));
 
 }
 
@@ -959,7 +958,7 @@
     struct path * p_s_path = p_s_tb->tb_path;
     struct cpu_key	s_lr_father_key;
     int                   n_counter,
-	n_position = MAX_INT,
+	n_position = INT_MAX,
 	n_first_last_position = 0,
 	n_path_offset = PATH_H_PATH_OFFSET(p_s_path, n_h);
 
@@ -1134,17 +1133,8 @@
     decrement_bcount(p_s_tb->CFR[n_h]);
     p_s_tb->CFR[n_h] = p_s_curcf; /* New initialization of CFR[n_path_offset]. */
 
-#ifdef CONFIG_REISERFS_CHECK
-#if 0
-    if (n_h == 0 && p_s_tb->CFR[n_h] && COMP_KEYS (B_PRIGHT_DELIM_KEY (PATH_H_PBUFFER(p_s_path, n_h)), 
-						   B_N_PDELIM_KEY (p_s_tb->CFR[n_h], p_s_tb->rkey[n_h]))) {
-	reiserfs_panic (p_s_tb->tb_sb, "PAP-8200: get_parents: rdkey in S0 %k, rdkey in CFR0 %k do not match",
-			B_PRIGHT_DELIM_KEY (PATH_H_PBUFFER(p_s_path, n_h)), B_N_PDELIM_KEY (p_s_tb->CFR[n_h], p_s_tb->rkey[n_h]));
-    }
-#endif
-#endif
-    RFALSE( (p_s_curf && !B_IS_IN_TREE (p_s_curf)) || 
-	    (p_s_curcf && !B_IS_IN_TREE (p_s_curcf)),
+    RFALSE( (p_s_curf && !B_IS_IN_TREE (p_s_curf)) ||
+            (p_s_curcf && !B_IS_IN_TREE (p_s_curcf)),
 	    "PAP-8205: FR (%b) or CFR (%b) is invalid", p_s_curf, p_s_curcf);
 
     return CARRY_ON;
@@ -1590,7 +1580,7 @@
 	      int order_L;
 	      
 	      order_L = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==0) ? B_NR_ITEMS(tb->FL[h]) : n - 1;
-	      n = B_N_CHILD(tb->FL[h],order_L)->dc_size / (DC_SIZE + KEY_SIZE);
+	      n = dc_size(B_N_CHILD(tb->FL[h],order_L)) / (DC_SIZE + KEY_SIZE);
 	      set_parameters (tb, h, -n-1, 0, 0, NULL, -1, -1);
 	      return CARRY_ON;
 	    }
@@ -1602,7 +1592,7 @@
 	      int order_R;
 	    
 	      order_R = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==B_NR_ITEMS(Fh)) ? 0 : n + 1;
-	      n = B_N_CHILD(tb->FR[h],order_R)->dc_size / (DC_SIZE + KEY_SIZE);
+	      n = dc_size(B_N_CHILD(tb->FR[h],order_R)) / (DC_SIZE + KEY_SIZE);
 	      set_parameters (tb, h, 0, -n-1, 0, NULL, -1, -1);
 	      return CARRY_ON;   
 	    }
@@ -1633,7 +1623,7 @@
 	int order_L;
 	      
 	order_L = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==0) ? B_NR_ITEMS(tb->FL[h]) : n - 1;
-	n = B_N_CHILD(tb->FL[h],order_L)->dc_size / (DC_SIZE + KEY_SIZE);
+	n = dc_size(B_N_CHILD(tb->FL[h],order_L)) / (DC_SIZE + KEY_SIZE);
 	set_parameters (tb, h, -n-1, 0, 0, NULL, -1, -1);
 	return CARRY_ON;
       }
@@ -1645,7 +1635,7 @@
       int order_R;
 	    
       order_R = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==B_NR_ITEMS(Fh)) ? 0 : (n + 1);
-      n = B_N_CHILD(tb->FR[h],order_R)->dc_size / (DC_SIZE + KEY_SIZE);
+      n = dc_size(B_N_CHILD(tb->FR[h],order_R)) / (DC_SIZE + KEY_SIZE);
       set_parameters (tb, h, 0, -n-1, 0, NULL, -1, -1);
       return CARRY_ON;   
     }
@@ -1934,14 +1924,14 @@
 	    return REPEAT_SEARCH;
 	}
 	
-	RFALSE( ! B_IS_IN_TREE(p_s_tb->FL[n_h]) || 
-		n_child_position > B_NR_ITEMS(p_s_tb->FL[n_h]) ||
-		B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position) != 
-		p_s_bh->b_blocknr, "PAP-8275: invalid parent");
+	RFALSE( ! B_IS_IN_TREE(p_s_tb->FL[n_h]) ||
+                n_child_position > B_NR_ITEMS(p_s_tb->FL[n_h]) ||
+	        B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position) !=
+                p_s_bh->b_blocknr, "PAP-8275: invalid parent");
 	RFALSE( ! B_IS_IN_TREE(p_s_bh), "PAP-8280: invalid child");
-	RFALSE( ! n_h && 
-		B_FREE_SPACE (p_s_bh) != MAX_CHILD_SIZE (p_s_bh) - B_N_CHILD (p_s_tb->FL[0],n_child_position)->dc_size,
-		"PAP-8290: invalid child size of left neighbor");
+	RFALSE( ! n_h &&
+                B_FREE_SPACE (p_s_bh) != MAX_CHILD_SIZE (p_s_bh) - dc_size(B_N_CHILD (p_s_tb->FL[0],n_child_position)),
+                "PAP-8290: invalid child size of left neighbor");
 
 	decrement_bcount(p_s_tb->L[n_h]);
 	p_s_tb->L[n_h] = p_s_bh;
@@ -1967,10 +1957,10 @@
 	decrement_bcount(p_s_tb->R[n_h]);
 	p_s_tb->R[n_h] = p_s_bh;
 
-	RFALSE( ! n_h && B_FREE_SPACE (p_s_bh) != MAX_CHILD_SIZE (p_s_bh) - B_N_CHILD (p_s_tb->FR[0],n_child_position)->dc_size,
-		"PAP-8300: invalid child size of right neighbor (%d != %d - %d)",
-		B_FREE_SPACE (p_s_bh), MAX_CHILD_SIZE (p_s_bh), 
-		B_N_CHILD (p_s_tb->FR[0],n_child_position)->dc_size);
+	RFALSE( ! n_h && B_FREE_SPACE (p_s_bh) != MAX_CHILD_SIZE (p_s_bh) - dc_size(B_N_CHILD (p_s_tb->FR[0],n_child_position)),
+                "PAP-8300: invalid child size of right neighbor (%d != %d - %d)",
+                B_FREE_SPACE (p_s_bh), MAX_CHILD_SIZE (p_s_bh),
+                dc_size(B_N_CHILD (p_s_tb->FR[0],n_child_position)));
 	
     }
     return CARRY_ON;
@@ -2027,7 +2017,7 @@
     size += sizeof (struct virtual_item);
     if (is_direntry_le_ih (ih))
       /* each entry and new one occupeis 2 byte in the virtual node */
-      size += (le16_to_cpu (ih->u.ih_entry_count) + 1) * sizeof (__u16);
+      size += (ih_entry_count(ih) + 1) * sizeof( __u16 );
   }
   
   /* 1 bit for each bitmap block to note whether bitmap block was
@@ -2544,8 +2534,9 @@
 	    brelse (tb->used[i]);
 	}
     }
+
     if (tb->vn_buf) 
-	reiserfs_kfree (tb->vn_buf, tb->vn_buf_size, tb->tb_sb);
+    reiserfs_kfree (tb->vn_buf, tb->vn_buf_size, tb->tb_sb);
 
 } 
 
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/hashes.c linux/fs/reiserfs/hashes.c
--- v2.4.12/linux/fs/reiserfs/hashes.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/reiserfs/hashes.c	Fri Oct 12 14:19:28 2001
@@ -48,7 +48,7 @@
 	} while(0)
 
 
-u32 keyed_hash(const char *msg, int len)
+u32 keyed_hash(const signed char *msg, int len)
 {
 	u32 k[] = { 0x9464a485, 0x542e1a94, 0x3e846bff, 0xb75bcfc3}; 
 
@@ -174,7 +174,7 @@
 /* What follows in this file is copyright 2000 by Hans Reiser, and the
  * licensing of what follows is governed by reiserfs/README */
 
-u32 yura_hash (const char *msg, int len)
+u32 yura_hash (const signed char *msg, int len)
 {
     int j, pow;
     u32 a, c;
@@ -209,7 +209,7 @@
     return a;
 }
 
-u32 r5_hash (const char *msg, int len)
+u32 r5_hash (const signed char *msg, int len)
 {
   u32 a=0;
   while(*msg) { 
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/ibalance.c linux/fs/reiserfs/ibalance.c
--- v2.4.12/linux/fs/reiserfs/ibalance.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/ibalance.c	Fri Oct 12 14:19:28 2001
@@ -140,7 +140,8 @@
     if (count <= 0)
 	return;
 
-    nr = le16_to_cpu ((blkh = B_BLK_HEAD(cur))->blk_nr_item);
+    blkh = B_BLK_HEAD(cur);
+    nr = blkh_nr_item(blkh);
 
     RFALSE( count > 2,
 	    "too many children (%d) are to be inserted", count);
@@ -155,9 +156,8 @@
 
     /* copy to_be_insert disk children */
     for (i = 0; i < count; i ++) {
-	new_dc[i].dc_size =
-	    cpu_to_le16 (MAX_CHILD_SIZE(bh[i]) - B_FREE_SPACE (bh[i]));
-	new_dc[i].dc_block_number = cpu_to_le32 (bh[i]->b_blocknr);
+	put_dc_size( &(new_dc[i]), MAX_CHILD_SIZE(bh[i]) - B_FREE_SPACE(bh[i]));
+	put_dc_block_number( &(new_dc[i]), bh[i]->b_blocknr );
     }
     memcpy (dc, new_dc, DC_SIZE * count);
 
@@ -173,8 +173,9 @@
 	memcpy (ih + 1, inserted + 1, KEY_SIZE);
 
     /* sizes, item number */
-    blkh->blk_nr_item = cpu_to_le16 (le16_to_cpu (blkh->blk_nr_item) + count);
-    blkh->blk_free_space = cpu_to_le16 (le16_to_cpu (blkh->blk_free_space) - count * (DC_SIZE + KEY_SIZE));
+    set_blkh_nr_item( blkh, blkh_nr_item(blkh) + count );
+    set_blkh_free_space( blkh,
+                        blkh_free_space(blkh) - count * (DC_SIZE + KEY_SIZE ) );
 
     do_balance_mark_internal_dirty (cur_bi->tb, cur,0);
 
@@ -183,7 +184,8 @@
     /*&&&&&&&&&&&&&&&&&&&&&&&&*/
 
     if (cur_bi->bi_parent) {
-	B_N_CHILD (cur_bi->bi_parent,cur_bi->bi_position)->dc_size += count * (DC_SIZE + KEY_SIZE);
+	struct disk_child *t_dc = B_N_CHILD (cur_bi->bi_parent,cur_bi->bi_position);
+	put_dc_size( t_dc, dc_size(t_dc) + (count * (DC_SIZE + KEY_SIZE)));
 	do_balance_mark_internal_dirty(cur_bi->tb, cur_bi->bi_parent, 0);
 
 	/*&&&&&&&&&&&&&&&&&&&&&&&&*/
@@ -210,17 +212,18 @@
   struct disk_child * dc;
 
   RFALSE( cur == NULL, "buffer is 0");
-  RFALSE( del_num < 0, 
-	  "negative number of items (%d) can not be deleted", del_num);
+  RFALSE( del_num < 0,
+          "negative number of items (%d) can not be deleted", del_num);
   RFALSE( first_p < 0 || first_p + del_num > B_NR_ITEMS (cur) + 1 || first_i < 0,
-	  "first pointer order (%d) < 0 or "
-	  "no so many pointers (%d), only (%d) or "
-	  "first key order %d < 0", first_p, 
-	  first_p + del_num, B_NR_ITEMS (cur) + 1, first_i);
+          "first pointer order (%d) < 0 or "
+          "no so many pointers (%d), only (%d) or "
+          "first key order %d < 0", first_p, 
+          first_p + del_num, B_NR_ITEMS (cur) + 1, first_i);
   if ( del_num == 0 )
     return;
 
-  nr = le16_to_cpu ((blkh = B_BLK_HEAD(cur))->blk_nr_item);
+  blkh = B_BLK_HEAD(cur);
+  nr = blkh_nr_item(blkh);
 
   if ( first_p == 0 && del_num == nr + 1 ) {
     RFALSE( first_i != 0, "1st deleted key must have order 0, not %d", first_i);
@@ -229,9 +232,9 @@
   }
 
   RFALSE( first_i + del_num > B_NR_ITEMS (cur),
-	  "first_i = %d del_num = %d "
-	  "no so many keys (%d) in the node (%b)(%z)", 
-	  first_i, del_num, first_i + del_num, cur, cur);
+          "first_i = %d del_num = %d "
+          "no so many keys (%d) in the node (%b)(%z)",
+          first_i, del_num, first_i + del_num, cur, cur);
 
 
   /* deleting */
@@ -243,8 +246,9 @@
 
 
   /* sizes, item number */
-  blkh->blk_nr_item = cpu_to_le16 (le16_to_cpu (blkh->blk_nr_item) - del_num);
-  blkh->blk_free_space = cpu_to_le16 (le16_to_cpu (blkh->blk_free_space) + del_num * (KEY_SIZE +  DC_SIZE));
+  set_blkh_nr_item( blkh, blkh_nr_item(blkh) - del_num );
+  set_blkh_free_space( blkh,
+                    blkh_free_space(blkh) + (del_num * (KEY_SIZE + DC_SIZE) ) );
 
   do_balance_mark_internal_dirty (cur_bi->tb, cur, 0);
   /*&&&&&&&&&&&&&&&&&&&&&&&*/
@@ -252,7 +256,10 @@
   /*&&&&&&&&&&&&&&&&&&&&&&&*/
  
   if (cur_bi->bi_parent) {
-    B_N_CHILD (cur_bi->bi_parent, cur_bi->bi_position)->dc_size -= del_num * (KEY_SIZE +  DC_SIZE);
+    struct disk_child *t_dc;
+    t_dc = B_N_CHILD (cur_bi->bi_parent, cur_bi->bi_position);
+    put_dc_size( t_dc, dc_size(t_dc) - (del_num * (KEY_SIZE + DC_SIZE) ) );
+
     do_balance_mark_internal_dirty (cur_bi->tb, cur_bi->bi_parent,0);
     /*&&&&&&&&&&&&&&&&&&&&&&&&*/
     check_internal (cur_bi->bi_parent);
@@ -312,7 +319,8 @@
     return;
 
 	/* coping */
-  nr_dest = le16_to_cpu ((blkh = B_BLK_HEAD(dest))->blk_nr_item);
+  blkh = B_BLK_HEAD(dest);
+  nr_dest = blkh_nr_item(blkh);
 
   /*dest_order = (last_first == LAST_TO_FIRST) ? 0 : nr_dest;*/
   /*src_order = (last_first == LAST_TO_FIRST) ? (nr_src - cpy_num + 1) : 0;*/
@@ -338,8 +346,9 @@
   memcpy (key, B_N_PDELIM_KEY (src, src_order), KEY_SIZE * (cpy_num - 1));
 
   /* sizes, item number */
-  blkh->blk_nr_item = cpu_to_le16 (le16_to_cpu (blkh->blk_nr_item) + (cpy_num - 1));
-  blkh->blk_free_space = cpu_to_le16 (le16_to_cpu (blkh->blk_free_space) - (KEY_SIZE * (cpy_num - 1) + DC_SIZE * cpy_num));
+  set_blkh_nr_item( blkh, blkh_nr_item(blkh) + (cpy_num - 1 ) );
+  set_blkh_free_space( blkh,
+      blkh_free_space(blkh) - (KEY_SIZE * (cpy_num - 1) + DC_SIZE * cpy_num ) );
 
   do_balance_mark_internal_dirty (dest_bi->tb, dest, 0);
 
@@ -348,8 +357,9 @@
   /*&&&&&&&&&&&&&&&&&&&&&&&&*/
 
   if (dest_bi->bi_parent) {
-    B_N_CHILD(dest_bi->bi_parent,dest_bi->bi_position)->dc_size +=
-      KEY_SIZE * (cpy_num - 1) + DC_SIZE * cpy_num;
+    struct disk_child *t_dc;
+    t_dc = B_N_CHILD(dest_bi->bi_parent,dest_bi->bi_position);
+    put_dc_size( t_dc, dc_size(t_dc) + (KEY_SIZE * (cpy_num - 1) + DC_SIZE * cpy_num) );
 
     do_balance_mark_internal_dirty (dest_bi->tb, dest_bi->bi_parent,0);
     /*&&&&&&&&&&&&&&&&&&&&&&&&*/
@@ -413,7 +423,8 @@
     RFALSE( B_FREE_SPACE (dest) < KEY_SIZE,
 	    "no enough free space (%d) in dest buffer", B_FREE_SPACE (dest));
 
-    nr = le16_to_cpu ((blkh=B_BLK_HEAD(dest))->blk_nr_item);
+    blkh = B_BLK_HEAD(dest);
+    nr = blkh_nr_item(blkh);
 
     /* prepare space for inserting key */
     key = B_N_PDELIM_KEY (dest, dest_position_before);
@@ -423,13 +434,17 @@
     memcpy (key, B_N_PDELIM_KEY(src, src_position), KEY_SIZE);
 
     /* Change dirt, free space, item number fields. */
-    blkh->blk_nr_item = cpu_to_le16 (le16_to_cpu (blkh->blk_nr_item) + 1);
-    blkh->blk_free_space = cpu_to_le16 (le16_to_cpu (blkh->blk_free_space) - KEY_SIZE);
+
+    set_blkh_nr_item( blkh, blkh_nr_item(blkh) + 1 );
+    set_blkh_free_space( blkh, blkh_free_space(blkh) - KEY_SIZE );
 
     do_balance_mark_internal_dirty (dest_bi->tb, dest, 0);
 
     if (dest_bi->bi_parent) {
-	B_N_CHILD(dest_bi->bi_parent,dest_bi->bi_position)->dc_size += KEY_SIZE;
+	struct disk_child *t_dc;
+	t_dc = B_N_CHILD(dest_bi->bi_parent,dest_bi->bi_position);
+	put_dc_size( t_dc, dc_size(t_dc) + KEY_SIZE );
+
 	do_balance_mark_internal_dirty (dest_bi->tb, dest_bi->bi_parent,0);
     }
 }
@@ -607,9 +622,9 @@
 	    else
 		new_root = tb->L[h-1];
 	    /* switch super block's tree root block number to the new value */
-	    tb->tb_sb->u.reiserfs_sb.s_rs->s_root_block = cpu_to_le32 (new_root->b_blocknr);
+            PUT_SB_ROOT_BLOCK( tb->tb_sb, new_root->b_blocknr );
 	    //tb->tb_sb->u.reiserfs_sb.s_rs->s_tree_height --;
-	    tb->tb_sb->u.reiserfs_sb.s_rs->s_tree_height = cpu_to_le16 (SB_TREE_HEIGHT (tb->tb_sb) - 1);
+            PUT_SB_TREE_HEIGHT( tb->tb_sb, SB_TREE_HEIGHT(tb->tb_sb) - 1 );
 
 	    do_balance_mark_sb_dirty (tb, tb->tb_sb->u.reiserfs_sb.s_sbh, 1);
 	    /*&&&&&&&&&&&&&&&&&&&&&&*/
@@ -818,8 +833,8 @@
 
 	    /* replace the first node-ptr in S[h] by node-ptr to insert_ptr[k] */
 	    dc = B_N_CHILD(tbSh, 0);
-	    dc->dc_size = cpu_to_le16 (MAX_CHILD_SIZE(insert_ptr[k]) - B_FREE_SPACE (insert_ptr[k]));
-	    dc->dc_block_number = cpu_to_le32 (insert_ptr[k]->b_blocknr);
+	    put_dc_size( dc, MAX_CHILD_SIZE(insert_ptr[k]) - B_FREE_SPACE (insert_ptr[k]));
+	    put_dc_block_number( dc, insert_ptr[k]->b_blocknr );
 
 	    do_balance_mark_internal_dirty (tb, tbSh, 0);
 
@@ -874,10 +889,9 @@
 
 		/* replace the first node-ptr in R[h] by node-ptr insert_ptr[insert_num-k-1]*/
 		dc = B_N_CHILD(tb->R[h], 0);
-		dc->dc_size =
-		    cpu_to_le16 (MAX_CHILD_SIZE(insert_ptr[insert_num-k-1]) -
-				 B_FREE_SPACE (insert_ptr[insert_num-k-1]));
-		dc->dc_block_number = cpu_to_le32 (insert_ptr[insert_num-k-1]->b_blocknr);
+		put_dc_size( dc, MAX_CHILD_SIZE(insert_ptr[insert_num-k-1]) -
+    				    B_FREE_SPACE (insert_ptr[insert_num-k-1]));
+		put_dc_block_number( dc, insert_ptr[insert_num-k-1]->b_blocknr );
 
 		do_balance_mark_internal_dirty (tb, tb->R[h],0);
 
@@ -902,22 +916,24 @@
 	/* create new root */
 	struct disk_child  * dc;
 	struct buffer_head * tbSh_1 = PATH_H_PBUFFER (tb->tb_path, h - 1);
+        struct block_head *  blkh;
 
 
 	if ( tb->blknum[h] != 1 )
 	    reiserfs_panic(0, "balance_internal", "One new node required for creating the new root");
 	/* S[h] = empty buffer from the list FEB. */
 	tbSh = get_FEB (tb);
-	B_BLK_HEAD(tbSh)->blk_level = cpu_to_le16 (h + 1);
+        blkh = B_BLK_HEAD(tbSh);
+        set_blkh_level( blkh, h + 1 );
 
 	/* Put the unique node-pointer to S[h] that points to S[h-1]. */
 
 	dc = B_N_CHILD(tbSh, 0);
-	dc->dc_block_number = cpu_to_le32 (tbSh_1->b_blocknr);
-	dc->dc_size = cpu_to_le16 (MAX_CHILD_SIZE (tbSh_1) - B_FREE_SPACE (tbSh_1));
+	put_dc_block_number( dc, tbSh_1->b_blocknr );
+	put_dc_size( dc, (MAX_CHILD_SIZE (tbSh_1) - B_FREE_SPACE (tbSh_1)));
 
 	tb->insert_size[h] -= DC_SIZE;
-	B_BLK_HEAD(tbSh)->blk_free_space = cpu_to_le16 (B_FREE_SPACE (tbSh) - DC_SIZE);
+        set_blkh_free_space( blkh, blkh_free_space(blkh) - DC_SIZE );
 
 	do_balance_mark_internal_dirty (tb, tbSh, 0);
 
@@ -929,8 +945,8 @@
 	PATH_OFFSET_PBUFFER(tb->tb_path, ILLEGAL_PATH_ELEMENT_OFFSET) = tbSh;
 
 	/* Change root in structure super block. */
-	tb->tb_sb->u.reiserfs_sb.s_rs->s_root_block = cpu_to_le32 (tbSh->b_blocknr);
-	tb->tb_sb->u.reiserfs_sb.s_rs->s_tree_height = cpu_to_le16 (SB_TREE_HEIGHT (tb->tb_sb) + 1);
+        PUT_SB_ROOT_BLOCK( tb->tb_sb, tbSh->b_blocknr );
+        PUT_SB_TREE_HEIGHT( tb->tb_sb, SB_TREE_HEIGHT(tb->tb_sb) + 1 );
 	do_balance_mark_sb_dirty (tb, tb->tb_sb->u.reiserfs_sb.s_sbh, 1);
 	tb->tb_sb->s_dirt = 1;
     }
@@ -943,7 +959,7 @@
 	/* S_new = free buffer from list FEB */
 	S_new = get_FEB(tb);
 
-	B_BLK_HEAD(S_new)->blk_level = cpu_to_le16 (h + 1);
+        set_blkh_level( B_BLK_HEAD(S_new), h + 1 );
 
 	dest_bi.tb = tb;
 	dest_bi.bi_bh = S_new;
@@ -998,9 +1014,9 @@
 	    /* replace first node-ptr in S_new by node-ptr to insert_ptr[insert_num-k-1] */
 
 	    dc = B_N_CHILD(S_new,0);
-	    dc->dc_size = cpu_to_le16 (MAX_CHILD_SIZE(insert_ptr[insert_num-k-1]) -
-				       B_FREE_SPACE(insert_ptr[insert_num-k-1]));
-	    dc->dc_block_number =	cpu_to_le32 (insert_ptr[insert_num-k-1]->b_blocknr);
+	    put_dc_size( dc, (MAX_CHILD_SIZE(insert_ptr[insert_num-k-1]) -
+				B_FREE_SPACE(insert_ptr[insert_num-k-1])) );
+	    put_dc_block_number( dc, insert_ptr[insert_num-k-1]->b_blocknr );
 
 	    do_balance_mark_internal_dirty (tb, S_new,0);
 			
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c
--- v2.4.12/linux/fs/reiserfs/inode.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/inode.c	Sun Oct 14 10:31:45 2001
@@ -8,6 +8,7 @@
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
 #include <asm/uaccess.h>
+#include <asm/unaligned.h>
 
 /* args for the create parameter of reiserfs_get_block */
 #define GET_BLOCK_NO_CREATE 0 /* don't create new blocks or convert tails */
@@ -34,6 +35,7 @@
 	down (&inode->i_sem); 
 
 	journal_begin(&th, inode->i_sb, jbegin_count) ;
+	reiserfs_update_inode_transaction(inode) ;
 	windex = push_journal_writer("delete_inode") ;
 
 	reiserfs_delete_object (&th, inode);
@@ -53,26 +55,26 @@
 }
 
 static void _make_cpu_key (struct cpu_key * key, int version, __u32 dirid, __u32 objectid, 
-			   loff_t offset, int type, int length)
+	       loff_t offset, int type, int length )
 {
-  key->version = version;
+    key->version = version;
 
-  key->on_disk_key.k_dir_id = dirid;
-  key->on_disk_key.k_objectid = objectid;
-  set_cpu_key_k_offset (key, offset);
-  set_cpu_key_k_type (key, type);  
-  key->key_length = length;
+    key->on_disk_key.k_dir_id = dirid;
+    key->on_disk_key.k_objectid = objectid;
+    set_cpu_key_k_offset (key, offset);
+    set_cpu_key_k_type (key, type);  
+    key->key_length = length;
 }
 
 
 /* take base of inode_key (it comes from inode always) (dirid, objectid) and version from an inode, set
    offset and type of key */
 void make_cpu_key (struct cpu_key * key, const struct inode * inode, loff_t offset,
-		   int type, int length)
+	      int type, int length )
 {
   _make_cpu_key (key, inode_items_version (inode), le32_to_cpu (INODE_PKEY (inode)->k_dir_id),
-					  le32_to_cpu (INODE_PKEY (inode)->k_objectid), 
-		 offset, type, length);
+	  	   le32_to_cpu (INODE_PKEY (inode)->k_objectid), 
+		   offset, type, length);
 }
 
 
@@ -86,14 +88,14 @@
 	ih->ih_key.k_dir_id = cpu_to_le32 (key->on_disk_key.k_dir_id);
 	ih->ih_key.k_objectid = cpu_to_le32 (key->on_disk_key.k_objectid);
     }
-    ih->ih_version = cpu_to_le16 (version);
+    put_ih_version( ih, version );
     set_le_ih_k_offset (ih, offset);
     set_le_ih_k_type (ih, type);
-    ih->ih_item_len = cpu_to_le16 (length);
+    put_ih_item_len( ih, length );
     /*    set_ih_free_space (ih, 0);*/
     // for directory items it is entry count, for directs and stat
     // datas - 0xffff, for indirects - 0
-    ih->u.ih_entry_count = cpu_to_le16 (entry_count);
+    put_ih_entry_count( ih, entry_count );
 }
 
 static void add_to_flushlist(struct inode *inode, struct buffer_head *bh) {
@@ -159,6 +161,7 @@
 static b_blocknr_t find_tag (struct buffer_head * bh, struct item_head * ih,
 			     __u32 * item, int pos_in_item)
 {
+  __u32 block ;
   if (!is_indirect_le_ih (ih))
 	 /* something more complicated could be here */
 	 return bh->b_blocknr;
@@ -168,8 +171,9 @@
   if (pos_in_item == I_UNFM_NUM (ih))
 	 pos_in_item --;
   while (pos_in_item >= 0) {
-	 if (item [pos_in_item])
-		return item [pos_in_item];
+	 block = get_block_num(item, pos_in_item) ;
+	 if (block)
+		return block ;
 	 pos_in_item --;
   }
   return bh->b_blocknr;
@@ -184,7 +188,8 @@
 {
   if (allocated)
 	 return 0;
-  if (retval == POSITION_FOUND && is_indirect_le_ih (ih) && item[pos_in_item])
+  if (retval == POSITION_FOUND && is_indirect_le_ih (ih) && 
+      get_block_num(item, pos_in_item))
 	 return 0;
   return 1;
 }
@@ -226,6 +231,7 @@
   reiserfs_update_sd(th, inode) ;
   journal_end(th, s, len) ;
   journal_begin(th, s, len) ;
+  reiserfs_update_inode_transaction(inode) ;
 }
 
 // it is called by get_block when create == 0. Returns block number
@@ -276,7 +282,7 @@
 	/* FIXME: here we could cache indirect item or part of it in
 	   the inode to avoid search_by_key in case of subsequent
 	   access to file */
-	blocknr = le32_to_cpu (ind_item [path.pos_in_item]);
+	blocknr = get_block_num(ind_item, path.pos_in_item) ;
 	ret = 0 ;
 	if (blocknr) {
 	    bh_result->b_dev = inode->i_dev;
@@ -320,10 +326,10 @@
     ** kmap schedules
     */
     if (!p) {
-	p = (char *)kmap(bh_result->b_page) ;
-	if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
-	    goto research;
-	}
+    p = (char *)kmap(bh_result->b_page) ;
+    if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
+        goto research;
+    }
     }
     p += offset ;
     memset (p, 0, inode->i_sb->s_blocksize);
@@ -342,7 +348,7 @@
 	    chars = inode->i_size - (le_ih_k_offset(ih) - 1) - path.pos_in_item;
 	    done = 1 ;
 	} else {
-	    chars = le16_to_cpu (ih->ih_item_len) - path.pos_in_item;
+	    chars = ih_item_len(ih) - path.pos_in_item;
 	}
 	memcpy (p, B_I_PITEM (bh, ih) + path.pos_in_item, chars);
 
@@ -565,6 +571,7 @@
 		  TYPE_ANY, 3/*key length*/);
     if ((new_offset + inode->i_sb->s_blocksize - 1) > inode->i_size) {
 	journal_begin(&th, inode->i_sb, jbegin_count) ;
+	reiserfs_update_inode_transaction(inode) ;
 	transaction_started = 1 ;
     }
  research:
@@ -589,6 +596,7 @@
 	if (!transaction_started) {
 	    pathrelse(&path) ;
 	    journal_begin(&th, inode->i_sb, jbegin_count) ;
+	    reiserfs_update_inode_transaction(inode) ;
 	    transaction_started = 1 ;
 	    goto research ;
 	}
@@ -616,12 +624,11 @@
     }
 
     if (indirect_item_found (retval, ih)) {
-	b_blocknr_t unfm_ptr;
-
+        b_blocknr_t unfm_ptr;
 	/* 'block'-th block is in the file already (there is
 	   corresponding cell in some indirect item). But it may be
 	   zero unformatted node pointer (hole) */
-	unfm_ptr = le32_to_cpu (item[pos_in_item]);
+        unfm_ptr = get_block_num (item, pos_in_item);
 	if (unfm_ptr == 0) {
 	    /* use allocated block to plug the hole */
 	    reiserfs_prepare_for_journal(inode->i_sb, bh, 1) ;
@@ -630,8 +637,8 @@
 		goto research;
 	    }
 	    bh_result->b_state |= (1UL << BH_New);
-	    item[pos_in_item] = cpu_to_le32 (allocated_block_nr);
-	    unfm_ptr = allocated_block_nr;
+	    put_block_num(item, pos_in_item, allocated_block_nr) ;
+            unfm_ptr = allocated_block_nr;
 	    journal_mark_dirty (&th, inode->i_sb, bh);
 	    inode->i_blocks += (inode->i_sb->s_blocksize / 512) ;
 	    reiserfs_update_sd(&th, inode) ;
@@ -658,6 +665,7 @@
 	*/
 	pathrelse(&path) ;
 	journal_begin(&th, inode->i_sb, jbegin_count) ;
+	reiserfs_update_inode_transaction(inode) ;
 	transaction_started = 1 ;
 	goto research;
     }
@@ -758,7 +766,7 @@
 	    struct cpu_key tmp_key;
 	    struct unfm_nodeinfo un = {0, 0};
 
-	    RFALSE( pos_in_item != le16_to_cpu (ih->ih_item_len) / UNFM_P_SIZE,
+	    RFALSE( pos_in_item != ih_item_len(ih) / UNFM_P_SIZE,
 		    "vs-804: invalid position for append");
 	    /* indirect item has to be appended, set up key of that position */
 	    make_cpu_key (&tmp_key, inode,
@@ -871,17 +879,17 @@
 	unsigned long blocks;
 
 	inode_items_version (inode) = ITEM_VERSION_1;
-	inode->i_mode = le16_to_cpu (sd->sd_mode);
-	inode->i_nlink = le16_to_cpu (sd->sd_nlink);
-	inode->i_uid = le16_to_cpu (sd->sd_uid);
-	inode->i_gid = le16_to_cpu (sd->sd_gid);
-	inode->i_size = le32_to_cpu (sd->sd_size);
-	inode->i_atime = le32_to_cpu (sd->sd_atime);
-	inode->i_mtime = le32_to_cpu (sd->sd_mtime);
-	inode->i_ctime = le32_to_cpu (sd->sd_ctime);
+	inode->i_mode  = sd_v1_mode(sd);
+	inode->i_nlink = sd_v1_nlink(sd);
+	inode->i_uid   = sd_v1_uid(sd);
+	inode->i_gid   = sd_v1_gid(sd);
+	inode->i_size  = sd_v1_size(sd);
+	inode->i_atime = sd_v1_atime(sd);
+	inode->i_mtime = sd_v1_mtime(sd);
+	inode->i_ctime = sd_v1_ctime(sd);
 
-	inode->i_blocks = le32_to_cpu (sd->u.sd_blocks);
-	inode->i_generation = INODE_PKEY (inode)->k_dir_id;
+	inode->i_blocks = sd_v1_blocks(sd);
+	inode->i_generation = le32_to_cpu (INODE_PKEY (inode)->k_dir_id);
 	blocks = (inode->i_size + 511) >> 9;
 	blocks = _ROUND_UP (blocks, inode->i_blksize >> 9);
 	if (inode->i_blocks > blocks) {
@@ -893,8 +901,8 @@
 	    inode->i_blocks = blocks;
 	}
 
-	rdev = le32_to_cpu (sd->u.sd_rdev);
-	inode->u.reiserfs_i.i_first_direct_byte = le32_to_cpu (sd->sd_first_direct_byte);
+        rdev = sd_v1_rdev(sd);
+	inode->u.reiserfs_i.i_first_direct_byte = sd_v1_first_direct_byte(sd);
     } else {
 	// new stat data found, but object may have old items
 	// (directories and symlinks)
@@ -902,24 +910,26 @@
 
 	/* both old and new directories have old keys */
 	//version = (S_ISDIR (sd->sd_mode) ? ITEM_VERSION_1 : ITEM_VERSION_2);
-	if (S_ISDIR (sd->sd_mode) || S_ISLNK (sd->sd_mode))
+
+	inode->i_mode   = sd_v2_mode(sd);
+	inode->i_nlink  = sd_v2_nlink(sd);
+	inode->i_uid    = sd_v2_uid(sd);
+	inode->i_size   = sd_v2_size(sd);
+	inode->i_gid    = sd_v2_gid(sd);
+	inode->i_mtime  = sd_v2_mtime(sd);
+	inode->i_atime  = sd_v2_atime(sd);
+	inode->i_ctime  = sd_v2_ctime(sd);
+	inode->i_blocks = sd_v2_blocks(sd);
+        rdev            = sd_v2_rdev(sd);
+	if( S_ISCHR( inode -> i_mode ) || S_ISBLK( inode -> i_mode ) )
+	    inode->i_generation = le32_to_cpu (INODE_PKEY (inode)->k_dir_id);
+	else
+            inode->i_generation = sd_v2_generation(sd);
+
+	if (S_ISDIR (inode->i_mode) || S_ISLNK (inode->i_mode))
 	    inode_items_version (inode) = ITEM_VERSION_1;
 	else
 	    inode_items_version (inode) = ITEM_VERSION_2;
-	inode->i_mode = le16_to_cpu (sd->sd_mode);
-	inode->i_nlink = le32_to_cpu (sd->sd_nlink);
-	inode->i_uid = le32_to_cpu (sd->sd_uid);
-	inode->i_size = le64_to_cpu (sd->sd_size);
-	inode->i_gid = le32_to_cpu (sd->sd_gid);
-	inode->i_mtime = le32_to_cpu (sd->sd_mtime);
-	inode->i_atime = le32_to_cpu (sd->sd_atime);
-	inode->i_ctime = le32_to_cpu (sd->sd_ctime);
-	inode->i_blocks = le32_to_cpu (sd->sd_blocks);
-	rdev = le32_to_cpu (sd->u.sd_rdev);
-	if( S_ISCHR( inode -> i_mode ) || S_ISBLK( inode -> i_mode ) )
-	    inode->i_generation = INODE_PKEY (inode)->k_dir_id;
-	else
-	    inode->i_generation = le32_to_cpu( sd->u.sd_generation );
     }
 
     /* nopack = 0, by default */
@@ -948,19 +958,21 @@
 {
     struct stat_data * sd_v2 = (struct stat_data *)sd;
 
-    sd_v2->sd_mode = cpu_to_le16 (inode->i_mode);
-    sd_v2->sd_nlink = cpu_to_le16 (inode->i_nlink);
-    sd_v2->sd_uid = cpu_to_le32 (inode->i_uid);
-    sd_v2->sd_size = cpu_to_le64 (inode->i_size);
-    sd_v2->sd_gid = cpu_to_le32 (inode->i_gid);
-    sd_v2->sd_mtime = cpu_to_le32 (inode->i_mtime);
-    sd_v2->sd_atime = cpu_to_le32 (inode->i_atime);
-    sd_v2->sd_ctime = cpu_to_le32 (inode->i_ctime);
-    sd_v2->sd_blocks = cpu_to_le32 (inode->i_blocks);
+    set_sd_v2_mode(sd_v2, inode->i_mode );
+    set_sd_v2_nlink(sd_v2, inode->i_nlink );
+    set_sd_v2_uid(sd_v2, inode->i_uid );
+    set_sd_v2_size(sd_v2, inode->i_size );
+    set_sd_v2_gid(sd_v2, inode->i_gid );
+    set_sd_v2_mtime(sd_v2, inode->i_mtime );
+    set_sd_v2_atime(sd_v2, inode->i_atime );
+    set_sd_v2_ctime(sd_v2, inode->i_ctime );
+    set_sd_v2_blocks(sd_v2, inode->i_blocks );
     if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
-	sd_v2->u.sd_rdev = cpu_to_le32 (inode->i_rdev);
-    } else {
-	sd_v2->u.sd_generation = cpu_to_le32( inode -> i_generation );
+        set_sd_v2_rdev(sd_v2, inode->i_rdev );
+}
+    else
+    {
+        set_sd_v2_generation(sd_v2, inode->i_generation);
     }
 }
 
@@ -970,21 +982,22 @@
 {
     struct stat_data_v1 * sd_v1 = (struct stat_data_v1 *)sd;
 
-    sd_v1->sd_mode = cpu_to_le16 (inode->i_mode);
-    sd_v1->sd_uid = cpu_to_le16 (inode->i_uid);
-    sd_v1->sd_gid = cpu_to_le16 (inode->i_gid);
-    sd_v1->sd_nlink = cpu_to_le16 (inode->i_nlink);
-    sd_v1->sd_size = cpu_to_le32 (inode->i_size);
-    sd_v1->sd_atime = cpu_to_le32 (inode->i_atime);
-    sd_v1->sd_ctime = cpu_to_le32 (inode->i_ctime);
-    sd_v1->sd_mtime = cpu_to_le32 (inode->i_mtime);
+    set_sd_v1_mode(sd_v1, inode->i_mode );
+    set_sd_v1_uid(sd_v1, inode->i_uid );
+    set_sd_v1_gid(sd_v1, inode->i_gid );
+    set_sd_v1_nlink(sd_v1, inode->i_nlink );
+    set_sd_v1_size(sd_v1, inode->i_size );
+    set_sd_v1_atime(sd_v1, inode->i_atime );
+    set_sd_v1_ctime(sd_v1, inode->i_ctime );
+    set_sd_v1_mtime(sd_v1, inode->i_mtime );
+
     if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-	sd_v1->u.sd_rdev = cpu_to_le32 (inode->i_rdev);
+        set_sd_v1_rdev(sd_v1, inode->i_rdev );
     else
-	sd_v1->u.sd_blocks = cpu_to_le32 (inode->i_blocks);
+        set_sd_v1_blocks(sd_v1, inode->i_blocks );
 
     // Sigh. i_first_direct_byte is back
-    sd_v1->sd_first_direct_byte = cpu_to_le32 (inode->u.reiserfs_i.i_first_direct_byte);
+    set_sd_v1_first_direct_byte(sd_v1, inode->u.reiserfs_i.i_first_direct_byte);
 }
 
 
@@ -1110,8 +1123,8 @@
     retval = search_item (inode->i_sb, &key, &path_to_sd);
     if (retval == IO_ERROR) {
 	reiserfs_warning ("vs-13070: reiserfs_read_inode2: "
-			  "i/o failure occurred trying to find stat data of %K\n",
-			  &key);
+                    "i/o failure occurred trying to find stat data of %K\n",
+                    &key);
 	make_bad_inode(inode) ;
 	return;
     }
@@ -1297,6 +1310,10 @@
         return ;
     }
     lock_kernel() ;
+
+    /* this is really only used for atime updates, so they don't have
+    ** to be included in O_SYNC or fsync
+    */
     journal_begin(&th, inode->i_sb, 1) ;
     reiserfs_update_sd (&th, inode);
     journal_end(&th, inode->i_sb, 1) ;
@@ -1317,7 +1334,8 @@
 /* stat data of new object is inserted already, this inserts the item
    containing "." and ".." entries */
 static int reiserfs_new_directory (struct reiserfs_transaction_handle *th, 
-				   struct item_head * ih, struct path * path, const struct inode * dir)
+				   struct item_head * ih, struct path * path,
+				   const struct inode * dir)
 {
     struct super_block * sb = th->t_super;
     char empty_dir [EMPTY_DIR_SIZE];
@@ -1335,14 +1353,14 @@
 	make_le_item_head (ih, 0, ITEM_VERSION_1, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2);
 	
 	make_empty_dir_item_v1 (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid,
-				le32_to_cpu (INODE_PKEY (dir)->k_dir_id), 
-				le32_to_cpu (INODE_PKEY (dir)->k_objectid));
+				INODE_PKEY (dir)->k_dir_id, 
+				INODE_PKEY (dir)->k_objectid );
     } else {
 	make_le_item_head (ih, 0, ITEM_VERSION_1, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2);
 	
 	make_empty_dir_item (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid,
-			     le32_to_cpu (INODE_PKEY (dir)->k_dir_id), 
-			     le32_to_cpu (INODE_PKEY (dir)->k_objectid));
+		   		INODE_PKEY (dir)->k_dir_id, 
+		   		INODE_PKEY (dir)->k_objectid );
     }
     
     /* look for place in the tree for new item */
@@ -1441,7 +1459,7 @@
       ** note that the private part of inode isn't filled in yet, we have
       ** to use the directory.
       */
-      inode->i_generation = INODE_PKEY (dir)->k_objectid;
+      inode->i_generation = le32_to_cpu (INODE_PKEY (dir)->k_objectid);
     else
 #if defined( USE_INODE_GENERATION_COUNTER )
       inode->i_generation = 
@@ -1671,6 +1689,7 @@
     ** (it will unmap bh if it packs).
     */
     journal_begin(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 ) ;
+    reiserfs_update_inode_transaction(p_s_inode) ;
     windex = push_journal_writer("reiserfs_vfs_truncate_file") ;
     reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
     pop_journal_writer(windex) ;
@@ -1717,6 +1736,7 @@
 start_over:
     lock_kernel() ;
     journal_begin(&th, inode->i_sb, jbegin_count) ;
+    reiserfs_update_inode_transaction(inode) ;
 
     make_cpu_key(&key, inode, byte_offset, TYPE_ANY, 3) ;
 
@@ -1737,18 +1757,18 @@
 	if (bytes_copied > 0) {
 	    reiserfs_warning("clm-6002: bytes_copied %d\n", bytes_copied) ;
 	}
-        if (!item[pos_in_item]) {
+        if (!get_block_num(item, pos_in_item)) {
 	    /* crap, we are writing to a hole */
 	    use_get_block = 1;
 	    goto out ;
 	}
-	set_block_dev_mapped(bh_result, le32_to_cpu(item[pos_in_item]), inode);
-	mark_buffer_uptodate(bh_result, 1);
+	set_block_dev_mapped(bh_result, get_block_num(item,pos_in_item),inode);
+        mark_buffer_uptodate(bh_result, 1);
     } else if (is_direct_le_ih(ih)) {
         char *p ; 
         p = page_address(bh_result->b_page) ;
         p += (byte_offset -1) & (PAGE_CACHE_SIZE - 1) ;
-        copy_size = le16_to_cpu(ih->ih_item_len) - pos_in_item ;
+        copy_size = ih_item_len(ih) - pos_in_item;
 
 	fs_gen = get_generation(inode->i_sb) ;
 	copy_item_head(&tmp_ih, ih) ;
@@ -1763,7 +1783,7 @@
 	journal_mark_dirty(&th, inode->i_sb, bh) ;
 	bytes_copied += copy_size ;
 	set_block_dev_mapped(bh_result, 0, inode);
-	mark_buffer_uptodate(bh_result, 1);
+        mark_buffer_uptodate(bh_result, 1);
 
 	/* are there still bytes left? */
         if (bytes_copied < bh_result->b_size && 
@@ -1944,26 +1964,38 @@
   return generic_block_bmap(as, block, reiserfs_bmap) ;
 }
 
-static int reiserfs_commit_write(struct file *f, struct page *page,
-			         unsigned from, unsigned to) {
-    struct inode *inode = page->mapping->host;
-    int ret ;
-
+static int reiserfs_commit_write(struct file *f, struct page *page, 
+                                 unsigned from, unsigned to) {
+    struct inode *inode = page->mapping->host ;
+    loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+    int ret ; 
+    
     reiserfs_wait_on_write_block(inode->i_sb) ;
+ 
+    /* generic_commit_write does this for us, but does not update the
+    ** transaction tracking stuff when the size changes.  So, we have
+    ** to do the i_size updates here.
+    */
+    if (pos > inode->i_size) {
+	struct reiserfs_transaction_handle th ;
+	lock_kernel() ;
+	journal_begin(&th, inode->i_sb, 1) ;
+	reiserfs_update_inode_transaction(inode) ;
+	inode->i_size = pos ;
+	reiserfs_update_sd(&th, inode) ;
+	journal_end(&th, inode->i_sb, 1) ;
+	unlock_kernel() ;
+    }
+ 
     ret = generic_commit_write(f, page, from, to) ;
 
     /* we test for O_SYNC here so we can commit the transaction
     ** for any packed tails the file might have had
     */
     if (f->f_flags & O_SYNC) {
-	struct reiserfs_transaction_handle th ;
 	lock_kernel() ;
-	journal_begin(&th, inode->i_sb, 1) ;
-	reiserfs_prepare_for_journal(inode->i_sb, 
-	                             SB_BUFFER_WITH_SB(inode->i_sb), 1) ;
-	journal_mark_dirty(&th, inode->i_sb, SB_BUFFER_WITH_SB(inode->i_sb)) ;
-	journal_end_sync(&th, inode->i_sb, 1) ;
-	unlock_kernel() ;
+ 	reiserfs_commit_for_inode(inode) ;
+	unlock_kernel();
     }
     return ret ;
 }
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/item_ops.c linux/fs/reiserfs/item_ops.c
--- v2.4.12/linux/fs/reiserfs/item_ops.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/item_ops.c	Fri Oct 12 14:19:28 2001
@@ -48,13 +48,15 @@
     if (stat_data_v1 (ih)) {
       	struct stat_data_v1 * sd = (struct stat_data_v1 *)item;
 
-	printk ("\t0%-6o | %6u | %2u | %d | %s\n", sd->sd_mode, sd->sd_size,
-		sd->sd_nlink, sd->sd_first_direct_byte, print_time (sd->sd_mtime));
+	printk ("\t0%-6o | %6u | %2u | %d | %s\n", sd_v1_mode(sd),
+                sd_v1_size(sd), sd_v1_nlink(sd), sd_v1_first_direct_byte(sd),
+                print_time( sd_v1_mtime(sd) ) );
     } else {
 	struct stat_data * sd = (struct stat_data *)item;
 
-	printk ("\t0%-6o | %6Lu | %2u | %d | %s\n", sd->sd_mode, (unsigned long long)(sd->sd_size),
-		sd->sd_nlink, sd->u.sd_rdev, print_time (sd->sd_mtime));
+	printk ("\t0%-6o | %6Lu | %2u | %d | %s\n", sd_v2_mode(sd),
+            (unsigned long long)sd_v2_size(sd), sd_v2_nlink(sd),
+            sd_v2_rdev(sd), print_time(sd_v2_mtime(sd)));
     }
 }
 
@@ -130,7 +132,7 @@
 //
 static int direct_bytes_number (struct item_head * ih, int block_size)
 {
-  return le16_to_cpu (ih->ih_item_len);
+  return ih_item_len(ih);
 }
 
 
@@ -156,7 +158,7 @@
 
 //    return;
     printk ("\"");
-    while (j < ih->ih_item_len)
+    while (j < ih_item_len(ih))
 	printk ("%c", item[j++]);
     printk ("\"\n");
 }
@@ -234,7 +236,7 @@
 
 static int indirect_bytes_number (struct item_head * ih, int block_size)
 {
-  return le16_to_cpu (ih->ih_item_len) / UNFM_P_SIZE * block_size; //- get_ih_free_space (ih);
+  return ih_item_len(ih) / UNFM_P_SIZE * block_size; //- get_ih_free_space (ih);
 }
 
 
@@ -299,14 +301,14 @@
 
     unp = (__u32 *)item;
 
-    if (ih->ih_item_len % UNFM_P_SIZE)
+    if (ih_item_len(ih) % UNFM_P_SIZE)
 	printk ("indirect_print_item: invalid item len");  
 
     printk ("%d pointers\n[ ", (int)I_UNFM_NUM (ih));
     for (j = 0; j < I_UNFM_NUM (ih); j ++) {
-	if (sequence_finished (prev, &num, unp[j])) {
+	if (sequence_finished (prev, &num, get_block_num(unp, j))) {
 	    print_sequence (prev, num);
-	    start_new_sequence (&prev, &num, unp[j]);
+	    start_new_sequence (&prev, &num, get_block_num(unp, j));
 	}
     }
     print_sequence (prev, num);
@@ -424,8 +426,8 @@
     deh = (struct reiserfs_de_head *)item;
 
     for (i = 0; i < I_ENTRY_COUNT (ih); i ++, deh ++) {
-	namelen = (i ? ((deh - 1)->deh_location) : ih->ih_item_len) - deh->deh_location;
-	name = item + deh->deh_location;
+	namelen = (i ? (deh_location(deh - 1)) : ih_item_len(ih)) - deh_location(deh);
+	name = item + deh_location(deh);
 	if (name[namelen-1] == 0)
 	  namelen = strlen (name);
 	namebuf[0] = '"';
@@ -441,7 +443,7 @@
 
 	printk ("%d:  %-15s%-15d%-15d%-15Ld%-15Ld(%s)\n", 
 		i, namebuf,
-		deh->deh_dir_id, deh->deh_objectid,
+		deh_dir_id(deh), deh_objectid(deh),
 		GET_HASH_VALUE (deh_offset (deh)), GET_GENERATION_NUMBER ((deh_offset (deh))),
 		(de_hidden (deh)) ? "HIDDEN" : "VISIBLE");
     }
@@ -466,9 +468,9 @@
 
 struct direntry_uarea {
     int flags;
-    short entry_count;
-    short entry_sizes[1];
-};
+    __u16 entry_count;
+    __u16 entry_sizes[1];
+} __attribute__ ((__packed__)) ;
 
 
 /*
@@ -531,8 +533,9 @@
     
     for (i = 0; i < dir_u->entry_count; i ++) {
 	j = old_entry_num (is_affected, i, vn->vn_pos_in_item, vn->vn_mode);
-	dir_u->entry_sizes[i] = (j ? le16_to_cpu (deh[j - 1].deh_location) : le16_to_cpu (vi->vi_ih->ih_item_len)) -
-	    le16_to_cpu (deh[j].deh_location) + DEH_SIZE;
+        dir_u->entry_sizes[i] = (j ? deh_location( &(deh[j - 1]) ) :
+                                ih_item_len (vi->vi_ih)) -
+                                deh_location( &(deh[j])) + DEH_SIZE;
     }
 
     size += (dir_u->entry_count * sizeof (short));
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c
--- v2.4.12/linux/fs/reiserfs/journal.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/journal.c	Fri Oct 12 14:20:42 2001
@@ -746,7 +746,7 @@
   }
   atomic_set(&(jl->j_commit_flushing), 0) ;
   wake_up(&(jl->j_commit_wait)) ;
-  
+
   s->s_dirt = 1 ;
   return 0 ;
 }
@@ -1936,7 +1936,7 @@
                                          where it belongs */
 
   INIT_LIST_HEAD (&SB_JOURNAL(p_s_sb)->j_prealloc_list);
-  
+
   if (reiserfs_dont_log (p_s_sb))
     return 0;
 
@@ -2319,6 +2319,11 @@
 ** will wait until the current transaction is done/commited before returning 
 */
 int journal_end_sync(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
+
+  if (SB_JOURNAL(p_s_sb)->j_len == 0) {
+    reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
+    journal_mark_dirty(th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
+  }
   return do_journal_end(th, p_s_sb, nblocks, COMMIT_NOW | WAIT) ;
 }
 
@@ -2416,8 +2421,8 @@
     journal_mark_dirty(&th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
     do_journal_end(&th, p_s_sb,1, COMMIT_NOW | WAIT) ;
   }
-  reiserfs_journal_kupdate(p_s_sb) ;
-  return 0 ;
+   reiserfs_journal_kupdate(p_s_sb) ;
+   return 0 ;
 }
 
 /*
@@ -2603,6 +2608,41 @@
   return 0 ;
 }
 
+void reiserfs_update_inode_transaction(struct inode *inode) {
+  
+  inode->u.reiserfs_i.i_trans_index = SB_JOURNAL_LIST_INDEX(inode->i_sb);
+
+  inode->u.reiserfs_i.i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
+}
+
+static int reiserfs_inode_in_this_transaction(struct inode *inode) {
+  if (inode->u.reiserfs_i.i_trans_id == SB_JOURNAL(inode->i_sb)->j_trans_id || 
+      inode->u.reiserfs_i.i_trans_id == 0) {
+    return 1; 
+  } 
+  return 0 ;
+}
+
+void reiserfs_commit_for_inode(struct inode *inode) {
+  struct reiserfs_journal_list *jl ;
+  struct reiserfs_transaction_handle th ;
+  struct super_block *sb = inode->i_sb ;
+
+  jl = SB_JOURNAL_LIST(sb) + inode->u.reiserfs_i.i_trans_index ;
+
+  /* is it from the current transaction, or from an unknown transaction? */
+  if (reiserfs_inode_in_this_transaction(inode)) {
+    journal_join(&th, sb, 1) ;
+    reiserfs_update_inode_transaction(inode) ;
+    journal_end_sync(&th, sb, 1) ;
+  } else if (jl->j_trans_id == inode->u.reiserfs_i.i_trans_id) {
+    flush_commit_list(sb, jl, 1) ;
+  }
+  /* if the transaction id does not match, this list is long since flushed
+  ** and we don't have to do anything here
+  */
+}
+
 void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb, 
                                       struct buffer_head *bh) {
   if (reiserfs_dont_log (p_s_sb))
@@ -2645,7 +2685,7 @@
   }
 }
 
-/*
+/* 
 ** long and ugly.  If flush, will not return until all commit
 ** blocks and all real buffers in the trans are on disk.
 ** If no_async, won't return until all commit blocks are on disk.
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/lbalance.c linux/fs/reiserfs/lbalance.c
--- v2.4.12/linux/fs/reiserfs/lbalance.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/lbalance.c	Fri Oct 12 14:19:28 2001
@@ -42,9 +42,10 @@
     /* length of all record to be copied and first byte of the last of them */
     deh = B_I_DEH (source, ih);
     if (copy_count) {
-	copy_records_len = (from ? deh[from - 1].deh_location : ih->ih_item_len) - 
-	    deh[from + copy_count - 1].deh_location;
-	records = source->b_data + ih->ih_item_location + deh[from + copy_count - 1].deh_location;
+	copy_records_len = (from ? deh_location( &(deh[from - 1]) ) :
+            ih_item_len(ih)) - deh_location( &(deh[from + copy_count - 1]));
+	records = source->b_data + ih_location(ih) +
+                                deh_location( &(deh[from + copy_count - 1]));
     } else {
 	copy_records_len = 0;
 	records = 0;
@@ -55,26 +56,26 @@
 
     /* if there are no items in dest or the first/last item in dest is not item of the same directory */
     if ( (item_num_in_dest == - 1) ||
-	(last_first == FIRST_TO_LAST && le_key_k_offset (ih_version (ih), &(ih->ih_key)) == DOT_OFFSET) ||
+	(last_first == FIRST_TO_LAST && le_ih_k_offset (ih) == DOT_OFFSET) ||
 	    (last_first == LAST_TO_FIRST && comp_short_le_keys/*COMP_SHORT_KEYS*/ (&ih->ih_key, B_N_PKEY (dest, item_num_in_dest)))) {
 	/* create new item in dest */
 	struct item_head new_ih;
 
 	/* form item header */
 	memcpy (&new_ih.ih_key, &ih->ih_key, KEY_SIZE);
-	new_ih.ih_version = cpu_to_le16 (ITEM_VERSION_1);
+	put_ih_version( &new_ih, ITEM_VERSION_1 );
 	/* calculate item len */
-	new_ih.ih_item_len = cpu_to_le16 (DEH_SIZE * copy_count + copy_records_len);
-	I_ENTRY_COUNT(&new_ih) = 0;
+	put_ih_item_len( &new_ih, DEH_SIZE * copy_count + copy_records_len );
+	put_ih_entry_count( &new_ih, 0 );
     
 	if (last_first == LAST_TO_FIRST) {
 	    /* form key by the following way */
 	    if (from < I_ENTRY_COUNT(ih)) {
-		set_le_ih_k_offset (&new_ih, cpu_to_le32 (le32_to_cpu (deh[from].deh_offset)));
+		set_le_ih_k_offset( &new_ih, deh_offset( &(deh[from]) ) );
 		/*memcpy (&new_ih.ih_key.k_offset, &deh[from].deh_offset, SHORT_KEY_SIZE);*/
 	    } else {
 		/* no entries will be copied to this item in this function */
-		set_le_ih_k_offset (&new_ih, cpu_to_le32 (U32_MAX));
+		set_le_ih_k_offset (&new_ih, U32_MAX);
 		/* this item is not yet valid, but we want I_IS_DIRECTORY_ITEM to return 1 for it, so we -1 */
 	    }
 	    set_le_key_k_type (ITEM_VERSION_1, &(new_ih.ih_key), TYPE_DIRENTRY);
@@ -123,12 +124,12 @@
       /* there is nothing to merge */
       return 0;
       
-    RFALSE( ! ih->ih_item_len, "vs-10010: item can not have empty length");
+    RFALSE( ! ih_item_len(ih), "vs-10010: item can not have empty length");
       
     if ( is_direntry_le_ih (ih) ) {
       if ( bytes_or_entries == -1 )
 	/* copy all entries to dest */
-	bytes_or_entries = le16_to_cpu (ih->u.ih_entry_count);
+	bytes_or_entries = ih_entry_count(ih);
       leaf_copy_dir_entries (dest_bi, src, FIRST_TO_LAST, 0, 0, bytes_or_entries);
       return 1;
     }
@@ -137,11 +138,11 @@
        part defined by 'bytes_or_entries'; if bytes_or_entries == -1 copy whole body; don't create new item header
        */
     if ( bytes_or_entries == -1 )
-      bytes_or_entries = le16_to_cpu (ih->ih_item_len);
+      bytes_or_entries = ih_item_len(ih);
 
 #ifdef CONFIG_REISERFS_CHECK
     else {
-      if (bytes_or_entries == le16_to_cpu (ih->ih_item_len) && is_indirect_le_ih(ih))
+      if (bytes_or_entries == ih_item_len(ih) && is_indirect_le_ih(ih))
 	if (get_ih_free_space (ih))
 	  reiserfs_panic (0, "vs-10020: leaf_copy_boundary_item: "
 			  "last unformatted node must be filled entirely (%h)",
@@ -152,14 +153,14 @@
     /* merge first item (or its part) of src buffer with the last
        item of dest buffer. Both are of the same file */
     leaf_paste_in_buffer (dest_bi,
-			  dest_nr_item - 1, dih->ih_item_len, bytes_or_entries, B_I_PITEM(src,ih), 0
+			  dest_nr_item - 1, ih_item_len(dih), bytes_or_entries, B_I_PITEM(src,ih), 0
 			  );
       
     if (is_indirect_le_ih (dih)) {
       RFALSE( get_ih_free_space (dih),
-	      "vs-10030: merge to left: last unformatted node of non-last indirect item %h must have zero free space", 
-	      ih);
-      if (bytes_or_entries == le16_to_cpu (ih->ih_item_len))
+              "vs-10030: merge to left: last unformatted node of non-last indirect item %h must have zerto free space",
+              ih);
+      if (bytes_or_entries == ih_item_len(ih))
 	set_ih_free_space (dih, get_ih_free_space (ih));
     }
     
@@ -182,9 +183,9 @@
   if ( is_direntry_le_ih (ih)) {
     if ( bytes_or_entries == -1 )
       /* bytes_or_entries = entries number in last item body of SOURCE */
-      bytes_or_entries = le16_to_cpu (ih->u.ih_entry_count);
+      bytes_or_entries = ih_entry_count(ih);
     
-    leaf_copy_dir_entries (dest_bi, src, LAST_TO_FIRST, src_nr_item - 1, le16_to_cpu (ih->u.ih_entry_count) - bytes_or_entries, bytes_or_entries);
+    leaf_copy_dir_entries (dest_bi, src, LAST_TO_FIRST, src_nr_item - 1, ih_entry_count(ih) - bytes_or_entries, bytes_or_entries);
     return 1;
   }
 
@@ -194,16 +195,16 @@
      */
   
   RFALSE( is_indirect_le_ih(ih) && get_ih_free_space (ih),
-	  "vs-10040: merge to right: last unformatted node of non-last indirect item must be filled entirely (%h)",
+          "vs-10040: merge to right: last unformatted node of non-last indirect item must be filled entirely (%h)",
 		    ih);
 
   if ( bytes_or_entries == -1 ) {
     /* bytes_or_entries = length of last item body of SOURCE */
-    bytes_or_entries = ih->ih_item_len;
+    bytes_or_entries = ih_item_len(ih);
 
-    RFALSE( le_ih_k_offset (dih) != 
-	    le_ih_k_offset (ih) + op_bytes_number (ih, src->b_size),
-	    "vs-10050: items %h and %h do not match", ih, dih);
+    RFALSE( le_ih_k_offset (dih) !=
+            le_ih_k_offset (ih) + op_bytes_number (ih, src->b_size),
+            "vs-10050: items %h and %h do not match", ih, dih);
 
     /* change first item key of the DEST */
     set_le_ih_k_offset (dih, le_ih_k_offset (ih));
@@ -213,9 +214,9 @@
     set_le_ih_k_type (dih, le_ih_k_type (ih));
   } else {
     /* merge to right only part of item */
-    RFALSE( le16_to_cpu (ih->ih_item_len) <= bytes_or_entries,
-	    "vs-10060: no so much bytes %lu (needed %lu)",
-	    ih->ih_item_len, bytes_or_entries);
+    RFALSE( ih_item_len(ih) <= bytes_or_entries,
+            "vs-10060: no so much bytes %lu (needed %lu)",
+            ih_item_len(ih), bytes_or_entries);
     
     /* change first item key of the DEST */
     if ( is_direct_le_ih (dih) ) {
@@ -223,15 +224,15 @@
 	      "vs-10070: dih %h, bytes_or_entries(%d)", dih, bytes_or_entries);
       set_le_ih_k_offset (dih, le_ih_k_offset (dih) - bytes_or_entries);
     } else {
-      RFALSE( le_ih_k_offset (dih) <= 
-	      (bytes_or_entries / UNFM_P_SIZE) * dest->b_size,
-	      "vs-10080: dih %h, bytes_or_entries(%d)",
-	      dih, (bytes_or_entries/UNFM_P_SIZE)*dest->b_size);
+      RFALSE( le_ih_k_offset (dih) <=
+              (bytes_or_entries / UNFM_P_SIZE) * dest->b_size,
+              "vs-10080: dih %h, bytes_or_entries(%d)",
+              dih, (bytes_or_entries/UNFM_P_SIZE)*dest->b_size);
       set_le_ih_k_offset (dih, le_ih_k_offset (dih) - ((bytes_or_entries / UNFM_P_SIZE) * dest->b_size));
     }
   }
   
-  leaf_paste_in_buffer (dest_bi, 0, 0, bytes_or_entries, B_I_PITEM(src,ih) + ih->ih_item_len - bytes_or_entries, 0);
+  leaf_paste_in_buffer (dest_bi, 0, 0, bytes_or_entries, B_I_PITEM(src,ih) + ih_item_len(ih) - bytes_or_entries, 0);
   return 1;
 }
 
@@ -244,7 +245,7 @@
 				      int first, int cpy_num)
 {
     struct buffer_head * dest;
-    int nr;
+    int nr, free_space;
     int dest_before;
     int last_loc, last_inserted_loc, location;
     int i, j;
@@ -266,7 +267,9 @@
     if (cpy_num == 0)
 	return;
 
-    nr = le16_to_cpu ((blkh = B_BLK_HEAD(dest))->blk_nr_item);
+    blkh = B_BLK_HEAD(dest);
+    nr = blkh_nr_item( blkh );
+    free_space = blkh_free_space(blkh);
   
     /* we will insert items before 0-th or nr-th item in dest buffer. It depends of last_first parameter */
     dest_before = (last_first == LAST_TO_FIRST) ? 0 : nr;
@@ -274,9 +277,9 @@
     /* location of head of first new item */
     ih = B_N_PITEM_HEAD (dest, dest_before);
 
-    RFALSE( le16_to_cpu (blkh->blk_free_space) < cpy_num * IH_SIZE,
-	    "vs-10140: not enough free space for headers %d (needed %d)",
-	    B_FREE_SPACE (dest), cpy_num * IH_SIZE);
+    RFALSE( blkh_free_space(blkh) < cpy_num * IH_SIZE,
+            "vs-10140: not enough free space for headers %d (needed %d)",
+            B_FREE_SPACE (dest), cpy_num * IH_SIZE);
 
     /* prepare space for headers */
     memmove (ih + cpy_num, ih, (nr-dest_before) * IH_SIZE);
@@ -284,22 +287,24 @@
     /* copy item headers */
     memcpy (ih, B_N_PITEM_HEAD (src, first), cpy_num * IH_SIZE);
 
-    blkh->blk_free_space = cpu_to_le16 (le16_to_cpu (blkh->blk_free_space) - IH_SIZE * cpy_num);
+    free_space -= (IH_SIZE * cpy_num);
+    set_blkh_free_space( blkh, free_space );
 
     /* location of unmovable item */
-    j = location = (dest_before == 0) ? dest->b_size : (ih-1)->ih_item_location;
-    for (i = dest_before; i < nr + cpy_num; i ++)
-	ih[i-dest_before].ih_item_location =
-	    (location -= ih[i-dest_before].ih_item_len);
+    j = location = (dest_before == 0) ? dest->b_size : ih_location(ih-1);
+    for (i = dest_before; i < nr + cpy_num; i ++) {
+        location -= ih_item_len( ih + i - dest_before );
+        put_ih_location( ih + i - dest_before, location );
+    }
 
     /* prepare space for items */
-    last_loc = ih[nr+cpy_num-1-dest_before].ih_item_location;
-    last_inserted_loc = ih[cpy_num-1].ih_item_location;
+    last_loc = ih_location( &(ih[nr+cpy_num-1-dest_before]) );
+    last_inserted_loc = ih_location( &(ih[cpy_num-1]) );
 
     /* check free space */
-    RFALSE( le16_to_cpu (blkh->blk_free_space) < j - last_inserted_loc,
+    RFALSE( free_space < j - last_inserted_loc,
 	    "vs-10150: not enough free space for items %d (needed %d)",
-	    le16_to_cpu (blkh->blk_free_space), j - last_inserted_loc);
+            free_space, j - last_inserted_loc);
 
     memmove (dest->b_data + last_loc,
 	     dest->b_data + last_loc + j - last_inserted_loc,
@@ -310,17 +315,18 @@
 	    j - last_inserted_loc);
 
     /* sizes, item number */
-    blkh->blk_nr_item = cpu_to_le16 (le16_to_cpu (blkh->blk_nr_item) + cpy_num);
-    blkh->blk_free_space = cpu_to_le16 (le16_to_cpu (blkh->blk_free_space) - (j - last_inserted_loc));
+    set_blkh_nr_item( blkh, nr + cpy_num );
+    set_blkh_free_space( blkh, free_space - (j - last_inserted_loc) );
 
     do_balance_mark_leaf_dirty (dest_bi->tb, dest, 0);
 
     if (dest_bi->bi_parent) {
-	RFALSE( B_N_CHILD (dest_bi->bi_parent, dest_bi->bi_position)->dc_block_number != dest->b_blocknr,
-		"vs-10160: block number in bh does not match to field in disk_child structure %lu and %lu",
-		dest->b_blocknr, B_N_CHILD (dest_bi->bi_parent, dest_bi->bi_position)->dc_block_number);
-	B_N_CHILD (dest_bi->bi_parent, dest_bi->bi_position)->dc_size +=
-	    j - last_inserted_loc + IH_SIZE * cpy_num;
+	struct disk_child *t_dc;
+	t_dc = B_N_CHILD (dest_bi->bi_parent, dest_bi->bi_position);
+	RFALSE( dc_block_number(t_dc) != dest->b_blocknr,
+	        "vs-10160: block number in bh does not match to field in disk_child structure %lu and %lu",
+                dest->b_blocknr, dc_block_number(t_dc));
+	put_dc_size( t_dc, dc_size(t_dc) + (j - last_inserted_loc + IH_SIZE * cpy_num ) );
     
 	do_balance_mark_internal_dirty (dest_bi->tb, dest_bi->bi_parent, 0);
     }
@@ -349,18 +355,17 @@
 	       n_ih = new item_header;
 	    */
 	    memcpy (&n_ih, ih, IH_SIZE);
-	    n_ih.ih_item_len = cpu_to_le16 (cpy_bytes);
+	    put_ih_item_len( &n_ih, cpy_bytes );
 	    if (is_indirect_le_ih (ih)) {
-		RFALSE( cpy_bytes == le16_to_cpu (ih->ih_item_len) && 
-			get_ih_free_space (ih),
-			"vs-10180: when whole indirect item is bottle to left neighbor, it must have free_space==0 (not %lu)",
-			get_ih_free_space (ih));
+		RFALSE( cpy_bytes == ih_item_len(ih) && get_ih_free_space(ih),
+		        "vs-10180: when whole indirect item is bottle to left neighbor, it must have free_space==0 (not %lu)",
+                        get_ih_free_space (ih));
 		set_ih_free_space (&n_ih, 0);
 	    }
 
 	    RFALSE( op_is_left_mergeable (&(ih->ih_key), src->b_size),
 		    "vs-10190: bad mergeability of item %h", ih);
-	    n_ih.ih_version = ih->ih_version;;
+	    n_ih.ih_version = ih->ih_version; /* JDM Endian safe, both le */
 	    leaf_insert_into_buf (dest_bi, B_NR_ITEMS(dest), &n_ih, B_N_PITEM (src, item_num), 0);
 	}
     } else {
@@ -375,24 +380,28 @@
 	       n_ih = new item_header;
 	    */
 	    memcpy (&n_ih, ih, SHORT_KEY_SIZE);
-	    n_ih.ih_version = cpu_to_le16 (ih_version (ih));
+
+	    n_ih.ih_version = ih->ih_version; /* JDM Endian safe, both le */
+
 	    if (is_direct_le_ih (ih)) {
-		set_le_ih_k_offset (&n_ih, le_ih_k_offset (ih) + le16_to_cpu (ih->ih_item_len) - cpy_bytes);
+		set_le_ih_k_offset (&n_ih, le_ih_k_offset (ih) + ih_item_len(ih) - cpy_bytes);
 		set_le_ih_k_type (&n_ih, TYPE_DIRECT);
 		set_ih_free_space (&n_ih, MAX_US_INT);
 	    } else {
 		/* indirect item */
 		RFALSE( !cpy_bytes && get_ih_free_space (ih),
-			"vs-10200: ih->ih_free_space must be 0 when indirect item will be appended");
-		set_le_ih_k_offset (&n_ih, le_ih_k_offset (ih) + (le16_to_cpu (ih->ih_item_len) - cpy_bytes) / UNFM_P_SIZE * dest->b_size);
+		        "vs-10200: ih->ih_free_space must be 0 when indirect item will be appended");
+		set_le_ih_k_offset (&n_ih, le_ih_k_offset (ih) + (ih_item_len(ih) - cpy_bytes) / UNFM_P_SIZE * dest->b_size);
 		set_le_ih_k_type (&n_ih, TYPE_INDIRECT);
 		set_ih_free_space (&n_ih, get_ih_free_space (ih));
 	    }
       
 	    /* set item length */
-	    n_ih.ih_item_len = cpu_to_le16 (cpy_bytes);
-	    n_ih.ih_version = cpu_to_le16 (le16_to_cpu (ih->ih_version));
-	    leaf_insert_into_buf (dest_bi, 0, &n_ih, B_N_PITEM(src,item_num) + le16_to_cpu (ih->ih_item_len) - cpy_bytes, 0);
+	    put_ih_item_len( &n_ih, cpy_bytes );
+
+	    n_ih.ih_version = ih->ih_version; /* JDM Endian safe, both le */
+
+	    leaf_insert_into_buf (dest_bi, 0, &n_ih, B_N_PITEM(src,item_num) + ih_item_len(ih) - cpy_bytes, 0);
 	}
     }
 }
@@ -602,21 +611,13 @@
       if (PATH_H_POSITION (tb->tb_path, 1) == 0)
 	replace_key (tb, tb->CFL[0], tb->lkey[0], PATH_H_PPARENT (tb->tb_path, 0), 0);
 
-#if 0      
-      /* change right_delimiting_key field in L0's block header */
-      copy_key (B_PRIGHT_DELIM_KEY(tb->L[0]), B_PRIGHT_DELIM_KEY (S0));
-#endif
     } else {     
       /* replace lkey in CFL[0] by 0-th key from S[0]; */
       replace_key (tb, tb->CFL[0], tb->lkey[0], S0, 0);
       
-#if 0
-      /* change right_delimiting_key field in L0's block header */
-      copy_key (B_PRIGHT_DELIM_KEY(tb->L[0]), B_N_PKEY (S0, 0));
-#endif
-      RFALSE( (shift_bytes != -1 && 
-	       !(is_direntry_le_ih (B_N_PITEM_HEAD (S0, 0))
-		 && !I_ENTRY_COUNT (B_N_PITEM_HEAD (S0, 0)))) &&
+      RFALSE( (shift_bytes != -1 &&
+              !(is_direntry_le_ih (B_N_PITEM_HEAD (S0, 0))
+                && !I_ENTRY_COUNT (B_N_PITEM_HEAD (S0, 0)))) &&
 	      (!op_is_left_mergeable (B_N_PKEY (S0, 0), S0->b_size)),
 	      "vs-10280: item must be mergeable");
     }
@@ -651,10 +652,6 @@
   if (shift_num) {
     replace_key (tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
 
-#if 0
-    /* change right_delimiting_key field in S0's block header */
-    copy_key (B_PRIGHT_DELIM_KEY(S0), B_N_PKEY (tb->R[0], 0));
-#endif
   }
 
   return ret_value;
@@ -714,10 +711,10 @@
 
 	    if (is_direntry_le_ih (ih = B_N_PITEM_HEAD(bh, B_NR_ITEMS(bh)-1))) 	/* the last item is directory  */
 	        /* len = numbers of directory entries in this item */
-	        len = le16_to_cpu (ih->u.ih_entry_count);
+		len = ih_entry_count(ih);
 	    else
 	        /* len = body len of item */
- 	        len = le16_to_cpu (ih->ih_item_len);
+		len = ih_item_len(ih);
 
 	    /* delete the part of the last item of the bh 
 	       do not delete item header
@@ -735,7 +732,7 @@
 			   int zeros_number)
 {
     struct buffer_head * bh = bi->bi_bh;
-    int nr;
+    int nr, free_space;
     struct block_head * blkh;
     struct item_head * ih;
     int i;
@@ -743,37 +740,39 @@
     char * to;
 
 
-    nr = le16_to_cpu ((blkh = B_BLK_HEAD (bh))->blk_nr_item);
+    blkh = B_BLK_HEAD(bh);
+    nr = blkh_nr_item(blkh);
+    free_space = blkh_free_space( blkh );
 
     /* check free space */
-    RFALSE( le16_to_cpu (blkh->blk_free_space) < 
-	    le16_to_cpu (inserted_item_ih->ih_item_len) + IH_SIZE,
-	    "not enough free space in block %z, new item %h",
-	    bh, inserted_item_ih);
-    RFALSE( zeros_number > inserted_item_ih->ih_item_len,
-	    "vs-10172: zero number == %d, item length == %d", 
-	    zeros_number, inserted_item_ih->ih_item_len);
+    RFALSE( free_space < ih_item_len(inserted_item_ih) + IH_SIZE,
+            "vs-10170: not enough free space in block %z, new item %h",
+            bh, inserted_item_ih);
+    RFALSE( zeros_number > ih_item_len(inserted_item_ih),
+	    "vs-10172: zero number == %d, item length == %d",
+            zeros_number, ih_item_len(inserted_item_ih));
 
 
     /* get item new item must be inserted before */
     ih = B_N_PITEM_HEAD (bh, before);
 
     /* prepare space for the body of new item */
-    last_loc = nr ? ih[nr - before - 1].ih_item_location : bh->b_size;
-    unmoved_loc = before ? (ih-1)->ih_item_location : bh->b_size;
+    last_loc = nr ? ih_location( &(ih[nr - before - 1]) ) : bh->b_size;
+    unmoved_loc = before ? ih_location( ih-1 ) : bh->b_size;
+
 
-    memmove (bh->b_data + last_loc - inserted_item_ih->ih_item_len, 
+    memmove (bh->b_data + last_loc - ih_item_len(inserted_item_ih), 
 	     bh->b_data + last_loc, unmoved_loc - last_loc);
 
-    to = bh->b_data + unmoved_loc - inserted_item_ih->ih_item_len;
+    to = bh->b_data + unmoved_loc - ih_item_len(inserted_item_ih);
     memset (to, 0, zeros_number);
     to += zeros_number;
 
     /* copy body to prepared space */
     if (inserted_item_body)
-	memmove (to, inserted_item_body, inserted_item_ih->ih_item_len - zeros_number);
+	memmove (to, inserted_item_body, ih_item_len(inserted_item_ih) - zeros_number);
     else
-	memset(to, '\0', inserted_item_ih->ih_item_len - zeros_number);
+	memset(to, '\0', ih_item_len(inserted_item_ih) - zeros_number);
   
     /* insert item header */
     memmove (ih + 1, ih, IH_SIZE * (nr - before));
@@ -781,18 +780,21 @@
   
     /* change locations */
     for (i = before; i < nr + 1; i ++)
-	ih[i-before].ih_item_location =
-	    (unmoved_loc -= ih[i-before].ih_item_len);
+    {
+        unmoved_loc -= ih_item_len( &(ih[i-before]));
+	put_ih_location( &(ih[i-before]), unmoved_loc );
+    }
   
     /* sizes, free space, item number */
-    blkh->blk_nr_item = cpu_to_le16 (le16_to_cpu (blkh->blk_nr_item) + 1);
-    blkh->blk_free_space = cpu_to_le16 (le16_to_cpu (blkh->blk_free_space) - 
-					(IH_SIZE + inserted_item_ih->ih_item_len));
-
+    set_blkh_nr_item( blkh, blkh_nr_item(blkh) + 1 );
+    set_blkh_free_space( blkh,
+                    free_space - (IH_SIZE + ih_item_len(inserted_item_ih ) ) );
     do_balance_mark_leaf_dirty (bi->tb, bh, 1);
 
     if (bi->bi_parent) { 
-	B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size += (IH_SIZE + inserted_item_ih->ih_item_len);
+	struct disk_child *t_dc;
+	t_dc = B_N_CHILD (bi->bi_parent, bi->bi_position);
+	put_dc_size( t_dc, dc_size(t_dc) + (IH_SIZE + ih_item_len(inserted_item_ih)));
 	do_balance_mark_internal_dirty (bi->tb, bi->bi_parent, 0);
     }
 }
@@ -806,24 +808,27 @@
 			   int zeros_number)
 {
     struct buffer_head * bh = bi->bi_bh;
-    int nr;
+    int nr, free_space;
     struct block_head * blkh;
     struct item_head * ih;
     int i;
     int last_loc, unmoved_loc;
 
+    blkh = B_BLK_HEAD(bh);
+    nr = blkh_nr_item(blkh);
+    free_space = blkh_free_space(blkh);
 
-    nr = le16_to_cpu ((blkh = B_BLK_HEAD(bh))->blk_nr_item);
 
     /* check free space */
-    RFALSE( le16_to_cpu (blkh->blk_free_space) < paste_size,
-	    "10175: not enough free space: needed %d, available %d",
-	    paste_size, le16_to_cpu (blkh->blk_free_space));
+    RFALSE( free_space < paste_size,
+            "vs-10175: not enough free space: needed %d, available %d",
+            paste_size, free_space);
+
 #ifdef CONFIG_REISERFS_CHECK
     if (zeros_number > paste_size) {
 	print_cur_tb ("10177");
-	reiserfs_panic (0, "vs-10177: leaf_paste_in_buffer: zero number == %d, paste_size == %d",
-			zeros_number, paste_size);
+	reiserfs_panic ( 0, "vs-10177: leaf_paste_in_buffer: ero number == %d, paste_size == %d",
+                         zeros_number, paste_size);
     }
 #endif /* CONFIG_REISERFS_CHECK */
 
@@ -831,8 +836,8 @@
     /* item to be appended */
     ih = B_N_PITEM_HEAD(bh, affected_item_num);
 
-    last_loc = ih[nr - affected_item_num - 1].ih_item_location;
-    unmoved_loc = affected_item_num ? (ih-1)->ih_item_location : bh->b_size;  
+    last_loc = ih_location( &(ih[nr - affected_item_num - 1]) );
+    unmoved_loc = affected_item_num ? ih_location( ih-1 ) : bh->b_size;
 
     /* prepare space */
     memmove (bh->b_data + last_loc - paste_size, bh->b_data + last_loc,
@@ -841,17 +846,18 @@
 
     /* change locations */
     for (i = affected_item_num; i < nr; i ++)
-	ih[i-affected_item_num].ih_item_location -= paste_size;
+	put_ih_location( &(ih[i-affected_item_num]),
+                    ih_location( &(ih[i-affected_item_num])) - paste_size );
 
     if ( body ) {
 	if (!is_direntry_le_ih (ih)) {
 	    if (!pos_in_item) {
 		/* shift data to right */
-		memmove (bh->b_data + ih->ih_item_location + paste_size, 
-			 bh->b_data + ih->ih_item_location, ih->ih_item_len);
+		memmove (bh->b_data + ih_location(ih) + paste_size, 
+			 bh->b_data + ih_location(ih), ih_item_len(ih));
 		/* paste data in the head of item */
-		memset (bh->b_data + ih->ih_item_location, 0, zeros_number);
-		memcpy (bh->b_data + ih->ih_item_location + zeros_number, body, paste_size - zeros_number);
+		memset (bh->b_data + ih_location(ih), 0, zeros_number);
+		memcpy (bh->b_data + ih_location(ih) + zeros_number, body, paste_size - zeros_number);
 	    } else {
 		memset (bh->b_data + unmoved_loc - paste_size, 0, zeros_number);
 		memcpy (bh->b_data + unmoved_loc - paste_size + zeros_number, body, paste_size - zeros_number);
@@ -859,17 +865,18 @@
 	}
     }
     else
-	memset(bh->b_data + unmoved_loc - paste_size,'\0',paste_size);
+	memset(bh->b_data + unmoved_loc - paste_size, '\0', paste_size);
 
-    ih->ih_item_len += paste_size;
+    put_ih_item_len( ih, ih_item_len(ih) + paste_size );
 
     /* change free space */
-    blkh->blk_free_space = cpu_to_le16 (le16_to_cpu (blkh->blk_free_space) - paste_size);
+    set_blkh_free_space( blkh, free_space - paste_size );
 
     do_balance_mark_leaf_dirty (bi->tb, bh, 0);
 
     if (bi->bi_parent) { 
-	B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size += paste_size;
+	struct disk_child *t_dc = B_N_CHILD (bi->bi_parent, bi->bi_position);
+	put_dc_size( t_dc, dc_size(t_dc) + paste_size );
 	do_balance_mark_internal_dirty (bi->tb, bi->bi_parent, 0);
     }
 }
@@ -905,26 +912,29 @@
     return 0;
 
   /* first byte of item */
-  item = bh->b_data + ih->ih_item_location;
+  item = bh->b_data + ih_location(ih);
 
   /* entry head array */
   deh = B_I_DEH (bh, ih);
 
   /* first byte of remaining entries, those are BEFORE cut entries
      (prev_record) and length of all removed records (cut_records_len) */
-  prev_record_offset = (from ? deh[from - 1].deh_location : ih->ih_item_len);
-  cut_records_len = prev_record_offset/*from_record*/ - deh[from + del_count - 1].deh_location;
+  prev_record_offset = (from ? deh_location( &(deh[from - 1])) : ih_item_len(ih));
+  cut_records_len = prev_record_offset/*from_record*/ -
+                                deh_location( &(deh[from + del_count - 1]));
   prev_record = item + prev_record_offset;
 
 
   /* adjust locations of remaining entries */
   for (i = I_ENTRY_COUNT(ih) - 1; i > from + del_count - 1; i --)
-    deh[i].deh_location -= (DEH_SIZE * del_count);
+    put_deh_location( &(deh[i]),
+                        deh_location( &deh[i] ) - (DEH_SIZE * del_count ) );
 
   for (i = 0; i < from; i ++)
-    deh[i].deh_location -= DEH_SIZE * del_count + cut_records_len;
+    put_deh_location( &(deh[i]),
+        deh_location( &deh[i] ) - (DEH_SIZE * del_count + cut_records_len) );
 
-  I_ENTRY_COUNT(ih) -= del_count;
+  put_ih_entry_count( ih, ih_entry_count(ih) - del_count );
 
   /* shift entry head array and entries those are AFTER removed entries */
   memmove ((char *)(deh + from),
@@ -933,7 +943,7 @@
   
   /* shift records, those are BEFORE removed entries */
   memmove (prev_record - cut_records_len - DEH_SIZE * del_count,
-	   prev_record, item + ih->ih_item_len - prev_record);
+	   prev_record, item + ih_item_len(ih) - prev_record);
 
   return DEH_SIZE * del_count + cut_records_len;
 }
@@ -957,7 +967,8 @@
     int last_loc, unmoved_loc;
     int i;
 
-    nr = le16_to_cpu ((blkh = B_BLK_HEAD (bh))->blk_nr_item);
+    blkh = B_BLK_HEAD(bh);
+    nr = blkh_nr_item(blkh);
 
     /* item head of truncated item */
     ih = B_N_PITEM_HEAD (bh, cut_item_num);
@@ -967,43 +978,42 @@
         cut_size = leaf_cut_entries (bh, ih, pos_in_item, cut_size);
         if (pos_in_item == 0) {
 	        /* change key */
-	    RFALSE( cut_item_num,
+            RFALSE( cut_item_num,
                     "when 0-th enrty of item is cut, that item must be first in the node, not %d-th", cut_item_num);
             /* change item key by key of first entry in the item */
-	    set_le_ih_k_offset (ih, le32_to_cpu (B_I_DEH (bh, ih)->deh_offset));
+	    set_le_ih_k_offset (ih, deh_offset(B_I_DEH (bh, ih)));
             /*memcpy (&ih->ih_key.k_offset, &(B_I_DEH (bh, ih)->deh_offset), SHORT_KEY_SIZE);*/
 	    }
     } else {
         /* item is direct or indirect */
-	RFALSE( is_statdata_le_ih (ih), "10195: item is stat data");
-	RFALSE( pos_in_item && 
-		pos_in_item + cut_size != le16_to_cpu (ih->ih_item_len),
-		"invalid offset (%lu) or trunc_size (%lu) or ih_item_len (%lu)",
-                pos_in_item, cut_size, le16_to_cpu (ih->ih_item_len));
+        RFALSE( is_statdata_le_ih (ih), "10195: item is stat data");
+        RFALSE( pos_in_item && pos_in_item + cut_size != ih_item_len(ih),
+                "10200: invalid offset (%lu) or trunc_size (%lu) or ih_item_len (%lu)",
+                pos_in_item, cut_size, ih_item_len (ih));
 
         /* shift item body to left if cut is from the head of item */
         if (pos_in_item == 0) {
-            memmove (bh->b_data + le16_to_cpu (ih->ih_item_location), bh->b_data + le16_to_cpu (ih->ih_item_location) + cut_size,
-		     le16_to_cpu (ih->ih_item_len) - cut_size);
+            memmove( bh->b_data + ih_location(ih),
+		     bh->b_data + ih_location(ih) + cut_size,
+		     ih_item_len(ih) - cut_size);
 	    
             /* change key of item */
             if (is_direct_le_ih (ih))
 		set_le_ih_k_offset (ih, le_ih_k_offset (ih) + cut_size);
             else {
 		set_le_ih_k_offset (ih, le_ih_k_offset (ih) + (cut_size / UNFM_P_SIZE) * bh->b_size);
-		RFALSE( le16_to_cpu (ih->ih_item_len) == cut_size && 
-			get_ih_free_space (ih),
-			"10205: invalid ih_free_space (%h)", ih);
+                RFALSE( ih_item_len(ih) == cut_size && get_ih_free_space (ih),
+                        "10205: invalid ih_free_space (%h)", ih);
 	        }
 	    }
     }
   
 
     /* location of the last item */
-    last_loc = le16_to_cpu (ih[nr - cut_item_num - 1].ih_item_location);
+    last_loc = ih_location( &(ih[nr - cut_item_num - 1]) );
 
     /* location of the item, which is remaining at the same place */
-    unmoved_loc = cut_item_num ? le16_to_cpu ((ih-1)->ih_item_location) : bh->b_size;
+    unmoved_loc = cut_item_num ? ih_location(ih-1) : bh->b_size;
 
 
     /* shift */
@@ -1011,8 +1021,7 @@
 	       unmoved_loc - last_loc - cut_size);
 
     /* change item length */
-/*    ih->ih_item_len -= cut_size;*/
-    ih->ih_item_len = cpu_to_le16 (le16_to_cpu (ih->ih_item_len) - cut_size);
+    put_ih_item_len( ih, ih_item_len(ih) - cut_size );
   
     if (is_indirect_le_ih (ih)) {
         if (pos_in_item)
@@ -1021,17 +1030,17 @@
 
     /* change locations */
     for (i = cut_item_num; i < nr; i ++)
-/*        ih[i-cut_item_num].ih_item_location += cut_size;*/
-        ih[i-cut_item_num].ih_item_location = 
-	  cpu_to_le16 (le16_to_cpu (ih[i-cut_item_num].ih_item_location) + cut_size);
+    put_ih_location( &(ih[i-cut_item_num]), ih_location( &ih[i-cut_item_num]) + cut_size );
 
     /* size, free space */
-    blkh->blk_free_space = cpu_to_le16 (le16_to_cpu (blkh->blk_free_space) + cut_size);
+    set_blkh_free_space( blkh, blkh_free_space(blkh) + cut_size );
 
     do_balance_mark_leaf_dirty (bi->tb, bh, 0);
     
     if (bi->bi_parent) { 
-      B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size -= cut_size; 
+      struct disk_child *t_dc;
+      t_dc = B_N_CHILD (bi->bi_parent, bi->bi_position);
+      put_dc_size( t_dc, dc_size(t_dc) - cut_size );
       do_balance_mark_internal_dirty (bi->tb, bi->bi_parent, 0);
     }
 }
@@ -1054,10 +1063,11 @@
   if (del_num == 0)
     return;
 
-  nr = le16_to_cpu ((blkh = B_BLK_HEAD(bh))->blk_nr_item);
+  blkh = B_BLK_HEAD(bh);
+  nr = blkh_nr_item(blkh);
 
   RFALSE( first < 0 || first + del_num > nr,
-	  "10220: first=%d, number=%d, there is %d items", first, del_num, nr);
+          "10220: first=%d, number=%d, there is %d items", first, del_num, nr);
 
   if (first == 0 && del_num == nr) {
     /* this does not work */
@@ -1070,11 +1080,11 @@
   ih = B_N_PITEM_HEAD (bh, first);
   
   /* location of unmovable item */
-  j = (first == 0) ? bh->b_size : (ih-1)->ih_item_location;
+  j = (first == 0) ? bh->b_size : ih_location(ih-1);
       
   /* delete items */
-  last_loc = ih[nr-1-first].ih_item_location;
-  last_removed_loc = ih[del_num-1].ih_item_location;
+  last_loc = ih_location( &(ih[nr-1-first]) );
+  last_removed_loc = ih_location( &(ih[del_num-1]) );
 
   memmove (bh->b_data + last_loc + j - last_removed_loc,
 	   bh->b_data + last_loc, last_removed_loc - last_loc);
@@ -1084,16 +1094,18 @@
   
   /* change item location */
   for (i = first; i < nr - del_num; i ++)
-    ih[i-first].ih_item_location += j - last_removed_loc;
+    put_ih_location( &(ih[i-first]), ih_location( &(ih[i-first]) ) + (j - last_removed_loc) );
 
   /* sizes, item number */
-  blkh->blk_nr_item = cpu_to_le16 (le16_to_cpu (blkh->blk_nr_item) - del_num);
-  blkh->blk_free_space = cpu_to_le16 (le16_to_cpu (blkh->blk_free_space) + (j - last_removed_loc + IH_SIZE * del_num));
+  set_blkh_nr_item( blkh, blkh_nr_item(blkh) - del_num );
+  set_blkh_free_space( blkh, blkh_free_space(blkh) + (j - last_removed_loc + IH_SIZE * del_num) );
 
   do_balance_mark_leaf_dirty (bi->tb, bh, 0);
   
   if (bi->bi_parent) {
-    B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size -= j - last_removed_loc + IH_SIZE * del_num;
+    struct disk_child *t_dc = B_N_CHILD (bi->bi_parent, bi->bi_position);
+    put_dc_size( t_dc, dc_size(t_dc) -
+				(j - last_removed_loc + IH_SIZE * del_num));
     do_balance_mark_internal_dirty (bi->tb, bi->bi_parent, 0);
   }
 }
@@ -1132,27 +1144,28 @@
 
 
   /* first byte of dest item */
-  item = bh->b_data + ih->ih_item_location;
+  item = bh->b_data + ih_location(ih);
 
   /* entry head array */
   deh = B_I_DEH (bh, ih);
 
   /* new records will be pasted at this point */
-  insert_point = item + (before ? deh[before - 1].deh_location : (ih->ih_item_len - paste_size));
+  insert_point = item + (before ? deh_location( &(deh[before - 1])) : (ih_item_len(ih) - paste_size));
 
   /* adjust locations of records that will be AFTER new records */
   for (i = I_ENTRY_COUNT(ih) - 1; i >= before; i --)
-    deh[i].deh_location += DEH_SIZE * new_entry_count;
+    put_deh_location( &(deh[i]),
+                deh_location(&(deh[i])) + (DEH_SIZE * new_entry_count )); 
 
   /* adjust locations of records that will be BEFORE new records */
   for (i = 0; i < before; i ++)
-    deh[i].deh_location += paste_size;
+    put_deh_location( &(deh[i]), deh_location(&(deh[i])) + paste_size );
 
   old_entry_num = I_ENTRY_COUNT(ih);
-  I_ENTRY_COUNT(ih) += new_entry_count;
+  put_ih_entry_count( ih, ih_entry_count(ih) + new_entry_count );
 
   /* prepare space for pasted records */
-  memmove (insert_point + paste_size, insert_point, item + (ih->ih_item_len - paste_size) - insert_point);
+  memmove (insert_point + paste_size, insert_point, item + (ih_item_len(ih) - paste_size) - insert_point);
 
   /* copy new records */
   memcpy (insert_point + DEH_SIZE * new_entry_count, records,
@@ -1168,14 +1181,18 @@
 
   /* set locations of new records */
   for (i = 0; i < new_entry_count; i ++)
-    deh[i].deh_location += 
-      (- new_dehs[new_entry_count - 1].deh_location + insert_point + DEH_SIZE * new_entry_count - item);
+  {
+    put_deh_location( &(deh[i]),
+        deh_location( &(deh[i] )) +
+        (- deh_location( &(new_dehs[new_entry_count - 1])) +
+        insert_point + DEH_SIZE * new_entry_count - item));
+  }
 
 
   /* change item key if neccessary (when we paste before 0-th entry */
   if (!before)
     {
-	set_le_ih_k_offset (ih, le32_to_cpu (new_dehs->deh_offset));
+	set_le_ih_k_offset (ih, deh_offset(new_dehs));
 /*      memcpy (&ih->ih_key.k_offset, 
 		       &new_dehs->deh_offset, SHORT_KEY_SIZE);*/
     }
@@ -1186,13 +1203,13 @@
     /* check record locations */
     deh = B_I_DEH (bh, ih);
     for (i = 0; i < I_ENTRY_COUNT(ih); i ++) {
-      next = (i < I_ENTRY_COUNT(ih) - 1) ? deh[i + 1].deh_location : 0;
-      prev = (i != 0) ? deh[i - 1].deh_location : 0;
+      next = (i < I_ENTRY_COUNT(ih) - 1) ? deh_location( &(deh[i + 1])) : 0;
+      prev = (i != 0) ? deh_location( &(deh[i - 1]) ) : 0;
       
-      if (prev && prev <= deh[i].deh_location)
+      if (prev && prev <= deh_location( &(deh[i])))
 	reiserfs_warning ("vs-10240: leaf_paste_entries: directory item (%h) corrupted (prev %a, cur(%d) %a)\n", 
 			  ih, deh + i - 1, i, deh + i);
-      if (next && next >= deh[i].deh_location)
+      if (next && next >= deh_location( &(deh[i])))
 	reiserfs_warning ("vs-10250: leaf_paste_entries: directory item (%h) corrupted (cur(%d) %a, next %a)\n",
 			  ih, i, deh + i, deh + i + 1);
     }
@@ -1200,6 +1217,3 @@
 #endif
 
 }
-
-
-
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/namei.c linux/fs/reiserfs/namei.c
--- v2.4.12/linux/fs/reiserfs/namei.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/namei.c	Fri Oct 12 14:20:42 2001
@@ -81,7 +81,7 @@
 
     de->de_entrylen = entry_length (de->de_bh, de->de_ih, de->de_entry_num);
     de->de_namelen = de->de_entrylen - (de_with_sd (deh) ? SD_SIZE : 0);
-    de->de_name = B_I_PITEM (de->de_bh, de->de_ih) + le16_to_cpu (deh->deh_location);
+    de->de_name = B_I_PITEM (de->de_bh, de->de_ih) + deh_location(deh);
     if (de->de_name[de->de_namelen - 1] == 0)
 	de->de_namelen = strlen (de->de_name);
 }
@@ -92,8 +92,8 @@
 {
     if (de->de_entry_num >= ih_entry_count (de->de_ih))
 	BUG ();
-    de->de_dir_id = le32_to_cpu (de->de_deh[de->de_entry_num].deh_dir_id);
-    de->de_objectid = le32_to_cpu (de->de_deh[de->de_entry_num].deh_objectid);
+    de->de_dir_id = deh_dir_id( &(de->de_deh[de->de_entry_num]));
+    de->de_objectid = deh_objectid( &(de->de_deh[de->de_entry_num]));
 }
 
 
@@ -159,7 +159,7 @@
 	COMP_SHORT_KEYS (&(de->de_ih->ih_key), key)) {
 	print_block (de->de_bh, 0, -1, -1);
 	reiserfs_panic (sb, "vs-7005: search_by_entry_key: found item %h is not directory item or "
-			"does not belong to the same directory as key %k", de->de_ih, key);
+                        "does not belong to the same directory as key %K", de->de_ih, key);
     }
 #endif /* CONFIG_REISERFS_CHECK */
 
@@ -322,12 +322,7 @@
 	retval = search_by_entry_key (dir->i_sb, &key_to_search, path_to_entry, de);
 	if (retval == IO_ERROR)
 	    // FIXME: still has to be dealt with
-
-				/* I want you to conform to our error
-                                   printing standard.  How many times
-                                   do I have to ask? -Hans */
-
-	    BUG ();
+	    reiserfs_panic (dir->i_sb, "zam-7001: io error in " __FUNCTION__ "\n");
 
 	/* compare names for all entries having given hash value */
 	retval = linear_search_in_dir_item (&key_to_search, de, name, namelen);
@@ -434,12 +429,12 @@
 
     /* fill buffer : directory entry head, name[, dir objectid | , stat data | ,stat data, dir objectid ] */
     deh = (struct reiserfs_de_head *)buffer;
-    deh->deh_location = 0;
-    deh->deh_offset = cpu_to_le32 (cpu_key_k_offset (&entry_key));
-    deh->deh_state = 0;
+    deh->deh_location = 0; /* JDM Endian safe if 0 */
+    put_deh_offset( deh, cpu_key_k_offset( &entry_key ) );
+    deh->deh_state = 0; /* JDM Endian safe if 0 */
     /* put key (ino analog) to de */
-    deh->deh_dir_id = INODE_PKEY (inode)->k_dir_id;
-    deh->deh_objectid = INODE_PKEY (inode)->k_objectid;
+    deh->deh_dir_id = INODE_PKEY (inode)->k_dir_id; /* safe: k_dir_id is le */
+    deh->deh_objectid = INODE_PKEY (inode)->k_objectid; /* safe: k_objectid is le */
 
     /* copy name */
     memcpy ((char *)(deh + 1), name, namelen);
@@ -454,36 +449,37 @@
     memset (bit_string, 0, sizeof (bit_string));
     de.de_gen_number_bit_string = (char *)bit_string;
     retval = reiserfs_find_entry (dir, name, namelen, &path, &de);
-    if (retval != NAME_NOT_FOUND) {
+    if( retval != NAME_NOT_FOUND ) {
 	if (buffer != small_buf)
 	    reiserfs_kfree (buffer, buflen, dir->i_sb);
 	pathrelse (&path);
-	
-	if (retval != NAME_FOUND) {
+
+        if (retval != NAME_FOUND) {
 	    reiserfs_warning ("zam-7002:" __FUNCTION__ ": \"reiserfs_find_entry\" has returned"
-			      " unexpected value (%d)\n", retval);
-	}
-	
+                              " unexpected value (%d)\n", retval);
+       }
+
 	return -EEXIST;
     }
 
     gen_number = find_first_zero_bit (bit_string, MAX_GENERATION_NUMBER + 1);
     if (gen_number > MAX_GENERATION_NUMBER) {
-	/* there is no free generation number */
-	reiserfs_warning ("reiserfs_add_entry: Congratulations! we have got hash function screwed up\n");
-	if (buffer != small_buf)
-	    reiserfs_kfree (buffer, buflen, dir->i_sb);
-	pathrelse (&path);
-	return -EBUSY;
+      /* there is no free generation number */
+      reiserfs_warning ("reiserfs_add_entry: Congratulations! we have got hash function screwed up\n");
+      if (buffer != small_buf)
+          reiserfs_kfree (buffer, buflen, dir->i_sb);
+      pathrelse (&path);
+      return -EBUSY;
     }
     /* adjust offset of directory enrty */
-    deh->deh_offset = cpu_to_le32 (SET_GENERATION_NUMBER (deh_offset (deh), gen_number));
-    set_cpu_key_k_offset (&entry_key, le32_to_cpu (deh->deh_offset));
-
+    put_deh_offset(deh, SET_GENERATION_NUMBER(deh_offset(deh), gen_number));
+    set_cpu_key_k_offset (&entry_key, deh_offset(deh));
+ 
     if (gen_number != 0) {	/* we need to re-search for the insertion point */
-	if (search_by_entry_key (dir->i_sb, &entry_key, &path, &de) != NAME_NOT_FOUND) {
-	    reiserfs_warning ("vs-7032: reiserfs_add_entry: "
-			      "entry with this key (%k) already exists\n", &entry_key);
+      if (search_by_entry_key (dir->i_sb, &entry_key, &path, &de) != NAME_NOT_FOUND) {
+            reiserfs_warning ("vs-7032: reiserfs_add_entry: "
+                            "entry with this key (%k) already exists\n", &entry_key);
+
 	    if (buffer != small_buf)
 		reiserfs_kfree (buffer, buflen, dir->i_sb);
 	    pathrelse (&path);
@@ -558,6 +554,8 @@
 	iput (inode);
 	return retval;
     }
+    reiserfs_update_inode_transaction(inode) ;
+    reiserfs_update_inode_transaction(dir) ;
 
     d_instantiate(dentry, inode);
     pop_journal_writer(windex) ;
@@ -600,6 +598,9 @@
     //FIXME: needed for block and char devices only
     reiserfs_update_sd (&th, inode);
 
+    reiserfs_update_inode_transaction(inode) ;
+    reiserfs_update_inode_transaction(dir) ;
+
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				 inode, 1/*visible*/);
     if (retval) {
@@ -655,6 +656,8 @@
 	journal_end(&th, dir->i_sb, jbegin_count) ;
 	return retval;
     }
+    reiserfs_update_inode_transaction(inode) ;
+    reiserfs_update_inode_transaction(dir) ;
 
     inode->i_op = &reiserfs_dir_inode_operations;
     inode->i_fop = &reiserfs_dir_operations;
@@ -723,6 +726,9 @@
     }
     inode = dentry->d_inode;
 
+    reiserfs_update_inode_transaction(inode) ;
+    reiserfs_update_inode_transaction(dir) ;
+
     if (de.de_objectid != inode->i_ino) {
 	// FIXME: compare key of an object and a key found in the
 	// entry
@@ -796,6 +802,9 @@
     }
     inode = dentry->d_inode;
 
+    reiserfs_update_inode_transaction(inode) ;
+    reiserfs_update_inode_transaction(dir) ;
+
     if (de.de_objectid != inode->i_ino) {
 	// FIXME: compare key of an object and a key found in the
 	// entry
@@ -885,6 +894,9 @@
 	return retval;
     }
 
+    reiserfs_update_inode_transaction(inode) ;
+    reiserfs_update_inode_transaction(dir) ;
+
     inode->i_op = &page_symlink_inode_operations;
     inode->i_mapping->a_ops = &reiserfs_address_space_operations;
 
@@ -940,6 +952,10 @@
     /* create new entry */
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len,
 				 inode, 1/*visible*/);
+
+    reiserfs_update_inode_transaction(inode) ;
+    reiserfs_update_inode_transaction(dir) ;
+
     if (retval) {
 	pop_journal_writer(windex) ;
 	journal_end(&th, dir->i_sb, jbegin_count) ;
@@ -994,6 +1010,7 @@
 /* sets key of objectid the entry has to point to */
 static void set_ino_in_dir_entry (struct reiserfs_dir_entry * de, struct key * key)
 {
+    /* JDM These operations are endian safe - both are le */
     de->de_deh[de->de_entry_num].deh_dir_id = key->k_dir_id;
     de->de_deh[de->de_entry_num].deh_objectid = key->k_objectid;
 }
@@ -1085,6 +1102,16 @@
 	return retval;
     }
 
+    reiserfs_update_inode_transaction(old_dir) ;
+    reiserfs_update_inode_transaction(new_dir) ;
+
+    /* this makes it so an fsync on an open fd for the old name will
+    ** commit the rename operation
+    */
+    reiserfs_update_inode_transaction(old_inode) ;
+
+    if (new_inode) 
+	reiserfs_update_inode_transaction(new_inode) ;
 
     while (1) {
 	// look for old name using corresponding entry key (found by reiserfs_find_entry)
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/objectid.c linux/fs/reiserfs/objectid.c
--- v2.4.12/linux/fs/reiserfs/objectid.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/objectid.c	Fri Oct 12 14:19:28 2001
@@ -80,10 +80,9 @@
        first two odd sequences into one sequence.  If so, then the net
        result is to eliminate a pair of objectids from oids.  We do this
        by shifting the entire map to the left. */
-    if (le16_to_cpu (rs->s_oid_cursize) > 2 && map[1] == map[2]) {
-	memmove (map + 1, map + 3, (le16_to_cpu (rs->s_oid_cursize) - 3) * sizeof(__u32));
-	//rs->s_oid_cursize -= 2;
-	rs->s_oid_cursize = cpu_to_le16 (le16_to_cpu (rs->s_oid_cursize) - 2);
+    if (sb_oid_cursize(rs) > 2 && map[1] == map[2]) {
+	memmove (map + 1, map + 3, (sb_oid_cursize(rs) - 3) * sizeof(__u32));
+        set_sb_oid_cursize( rs, sb_oid_cursize(rs) - 2 );
     }
 
     journal_mark_dirty(th, s, SB_BUFFER_WITH_SB (s));
@@ -114,7 +113,7 @@
        what we use, though it is possible that binary search would be
        more efficient after performing lots of deletions (which is
        when oids is large.)  We only check even i's. */
-    while (i < le16_to_cpu (rs->s_oid_cursize)) {
+    while (i < sb_oid_cursize(rs)) {
 	if (objectid_to_release == le32_to_cpu (map[i])) {
 	    /* This incrementation unallocates the objectid. */
 	    //map[i]++;
@@ -124,14 +123,14 @@
 	    if (map[i] == map[i+1]) {
 		/* shrink objectid map */
 		memmove (map + i, map + i + 2, 
-			 (le16_to_cpu (rs->s_oid_cursize) - i - 2) * sizeof (__u32));
+			 (sb_oid_cursize(rs) - i - 2) * sizeof (__u32));
 		//disk_sb->s_oid_cursize -= 2;
-		rs->s_oid_cursize = cpu_to_le16 (le16_to_cpu (rs->s_oid_cursize) - 2);
+                set_sb_oid_cursize( rs, sb_oid_cursize(rs) - 2 );
 
-		RFALSE( le16_to_cpu (rs->s_oid_cursize) < 2 || 
-			le16_to_cpu (rs->s_oid_cursize) > le16_to_cpu (rs->s_oid_maxsize),
-			"vs-15005: objectid map corrupted cur_size == %d (max == %d)",
-			le16_to_cpu (rs->s_oid_cursize), le16_to_cpu (rs->s_oid_maxsize));
+		RFALSE( sb_oid_cursize(rs) < 2 || 
+		        sb_oid_cursize(rs) > sb_oid_maxsize(rs),
+		        "vs-15005: objectid map corrupted cur_size == %d (max == %d)",
+                        sb_oid_cursize(rs), sb_oid_maxsize(rs));
 	    }
 	    return;
 	}
@@ -145,16 +144,17 @@
 		return;
 	    }
 
+            /* JDM comparing two little-endian values for equality -- safe */
 	    if (rs->s_oid_cursize == rs->s_oid_maxsize)
 		/* objectid map must be expanded, but there is no space */
 		return;
 
 	    /* expand the objectid map*/
 	    memmove (map + i + 3, map + i + 1, 
-		     (le16_to_cpu (rs->s_oid_cursize) - i - 1) * sizeof(__u32));
+		     (sb_oid_cursize(rs) - i - 1) * sizeof(__u32));
 	    map[i + 1] = cpu_to_le32 (objectid_to_release);
 	    map[i + 2] = cpu_to_le32 (objectid_to_release + 1);
-	    rs->s_oid_cursize = cpu_to_le16 (le16_to_cpu (rs->s_oid_cursize) + 2);
+            set_sb_oid_cursize( rs, sb_oid_cursize(rs) + 2 );
 	    return;
 	}
 	i += 2;
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/prints.c linux/fs/reiserfs/prints.c
--- v2.4.12/linux/fs/reiserfs/prints.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/reiserfs/prints.c	Sun Oct 14 10:31:45 2001
@@ -15,7 +15,7 @@
 static char off_buf[80];
 
 
-static char * cpu_offset (struct cpu_key * key)
+static char * reiserfs_cpu_offset (struct cpu_key * key)
 {
   if (cpu_key_k_type(key) == TYPE_DIRENTRY)
     sprintf (off_buf, "%Lu(%Lu)", 
@@ -90,11 +90,21 @@
 {
   if (key)
     sprintf (buf, "[%d %d %s %s]", key->on_disk_key.k_dir_id,
-	     key->on_disk_key.k_objectid, cpu_offset (key), cpu_type (key));
+	     key->on_disk_key.k_objectid, reiserfs_cpu_offset (key),
+             cpu_type (key));
   else
     sprintf (buf, "[NULL]");
 }
 
+static void sprintf_de_head( char *buf, struct reiserfs_de_head *deh )
+{
+    if( deh )
+        sprintf( buf, "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]", deh_offset(deh), deh_dir_id(deh),
+                 deh_objectid(deh), deh_location(deh), deh_state(deh) );
+    else
+        sprintf( buf, "[NULL]" );
+
+}
 
 static void sprintf_item_head (char * buf, struct item_head * ih)
 {
@@ -103,7 +113,7 @@
 	sprintf_le_key (buf + strlen (buf), &(ih->ih_key));
 	sprintf (buf + strlen (buf), ", item_len %d, item_location %d, "
 		 "free_space(entry_count) %d",
-		 ih->ih_item_len, ih->ih_item_location, ih_free_space (ih));
+		 ih_item_len(ih), ih_location(ih), ih_free_space (ih));
     } else
 	sprintf (buf, "[NULL]");
 }
@@ -123,10 +133,6 @@
 {
   sprintf (buf, "level=%d, nr_items=%d, free_space=%d rdkey ",
 	   B_LEVEL (bh), B_NR_ITEMS (bh), B_FREE_SPACE (bh));
-#if 0
-  if (B_LEVEL (bh) == DISK_LEAF_NODE_LEVEL)
-    sprintf_le_key (buf + strlen (buf), B_PRIGHT_DELIM_KEY (bh));
-#endif
 }
 
 
@@ -143,7 +149,7 @@
 
 static void sprintf_disk_child (char * buf, struct disk_child * dc)
 {
-  sprintf (buf, "[dc_number=%d, dc_size=%u]", dc->dc_block_number, dc->dc_size);
+  sprintf (buf, "[dc_number=%d, dc_size=%u]", dc_block_number(dc), dc_size(dc));
 }
 
 
@@ -153,12 +159,10 @@
 
   *skip = 0;
   
-  while (1) {
-    k = strstr (k, "%");
-    if (!k)
-      break;
-    if (k && (k[1] == 'k' || k[1] == 'K' || k[1] == 'h' || k[1] == 't' ||
-	      k[1] == 'z' || k[1] == 'b' || k[1] == 'y')) {
+  while ((k = strstr (k, "%")) != NULL)
+  {
+    if (k[1] == 'k' || k[1] == 'K' || k[1] == 'h' || k[1] == 't' ||
+	      k[1] == 'z' || k[1] == 'b' || k[1] == 'y' || k[1] == 'a' ) {
       *what = k[1];
       break;
     }
@@ -182,59 +186,58 @@
            key->k_offset, key->k_uniqueness); 
 */
 
-#define do_reiserfs_warning \
-{\
-  char * fmt1 = fmt_buf;\
-  va_list args;\
-  int i, j;\
-  char * k;\
-  char * p = error_buf;\
-  int what, skip;\
-\
-  strcpy (fmt1, fmt);\
-  va_start(args, fmt);\
-\
-  while (1) {\
-    k = is_there_reiserfs_struct (fmt1, &what, &skip);\
-    if (k != 0) {\
-      *k = 0;\
-      p += vsprintf (p, fmt1, args);\
-\
-      for (i = 0; i < skip; i ++)\
-	j = va_arg (args, int);\
-\
-      switch (what) {\
-      case 'k':\
-	sprintf_le_key (p, va_arg(args, struct key *));\
-	break;\
-      case 'K':\
-	sprintf_cpu_key (p, va_arg(args, struct cpu_key *));\
-	break;\
-      case 'h':\
-	sprintf_item_head (p, va_arg(args, struct item_head *));\
-	break;\
-      case 't':\
-	sprintf_direntry (p, va_arg(args, struct reiserfs_dir_entry *));\
-	break;\
-      case 'y':\
-	sprintf_disk_child (p, va_arg(args, struct disk_child *));\
-	break;\
-      case 'z':\
-	sprintf_block_head (p, va_arg(args, struct buffer_head *));\
-	break;\
-      case 'b':\
-	sprintf_buffer_head (p, va_arg(args, struct buffer_head *));\
-	break;\
-      }\
-      p += strlen (p);\
-      fmt1 = k + 2;\
-    } else {\
-      i = vsprintf (p, fmt1, args);\
-      break;\
-    }\
-  }\
-\
-  va_end(args);\
+
+static void
+prepare_error_buf( const char *fmt, va_list args )
+{
+    char * fmt1 = fmt_buf;
+    char * k;
+    char * p = error_buf;
+    int i, j, what, skip;
+
+    strcpy (fmt1, fmt);
+
+    while( (k = is_there_reiserfs_struct( fmt1, &what, &skip )) != NULL )
+    {
+        *k = 0;
+
+        p += vsprintf (p, fmt1, args);
+
+        for (i = 0; i < skip; i ++)
+            j = va_arg (args, int);
+
+        switch (what) {
+        case 'k':
+            sprintf_le_key (p, va_arg(args, struct key *));
+            break;
+        case 'K':
+            sprintf_cpu_key (p, va_arg(args, struct cpu_key *));
+            break;
+        case 'h':
+            sprintf_item_head (p, va_arg(args, struct item_head *));
+            break;
+        case 't':
+            sprintf_direntry (p, va_arg(args, struct reiserfs_dir_entry *));
+            break;
+        case 'y':
+            sprintf_disk_child (p, va_arg(args, struct disk_child *));
+            break;
+        case 'z':
+            sprintf_block_head (p, va_arg(args, struct buffer_head *));
+            break;
+        case 'b':
+            sprintf_buffer_head (p, va_arg(args, struct buffer_head *));
+            break;
+        case 'a':
+            sprintf_de_head (p, va_arg(args, struct reiserfs_de_head *));
+            break;
+        }
+
+        p += strlen (p);
+        fmt1 = k + 2;
+    }
+    vsprintf (p, fmt1, args);
+
 }
 
 
@@ -247,9 +250,18 @@
    %z to print block head (arg must be struct buffer_head *
    %b to print buffer_head
 */
+
+#define do_reiserfs_warning(fmt)\
+{\
+    va_list args;\
+    va_start( args, fmt );\
+    prepare_error_buf( fmt, args );\
+    va_end( args );\
+}
+
 void reiserfs_warning (const char * fmt, ...)
 {
-  do_reiserfs_warning;
+  do_reiserfs_warning(fmt);
   /* console_print (error_buf); */
   printk (KERN_WARNING "%s", error_buf);
 }
@@ -257,7 +269,7 @@
 void reiserfs_debug (struct super_block *s, int level, const char * fmt, ...)
 {
 #ifdef CONFIG_REISERFS_CHECK
-  do_reiserfs_warning;
+  do_reiserfs_warning(fmt);
   printk (KERN_DEBUG "%s", error_buf);
 #else
   ; 
@@ -291,7 +303,7 @@
 
     panics in reiserfs_fs.h have numbers from 1000 to 1999
     super.c				        2000 to 2999
-    preserve.c				    3000 to 3999
+    preserve.c (unused)			    3000 to 3999
     bitmap.c				    4000 to 4999
     stree.c				        5000 to 5999
     prints.c				    6000 to 6999
@@ -317,8 +329,8 @@
 void reiserfs_panic (struct super_block * sb, const char * fmt, ...)
 {
   show_reiserfs_locks() ;
-  do_reiserfs_warning;
-  printk ("%s", error_buf);
+  do_reiserfs_warning(fmt);
+  printk ( KERN_EMERG "%s", error_buf);
   BUG ();
   // console_print (error_buf);
   // for (;;);
@@ -437,7 +449,7 @@
 {
     struct block_head * blkh;
     struct item_head * ih;
-    int i;
+    int i, nr;
     int from, to;
 
     if (!B_IS_ITEMS_LEVEL (bh))
@@ -447,23 +459,24 @@
 
     blkh = B_BLK_HEAD (bh);
     ih = B_N_PITEM_HEAD (bh,0);
+    nr = blkh_nr_item(blkh);
 
     printk ("\n===================================================================\n");
     reiserfs_warning ("LEAF NODE (%ld) contains %z\n", bh->b_blocknr, bh);
 
     if (!(print_mode & PRINT_LEAF_ITEMS)) {
 	reiserfs_warning ("FIRST ITEM_KEY: %k, LAST ITEM KEY: %k\n",
-			  &(ih->ih_key), &((ih + le16_to_cpu (blkh->blk_nr_item) - 1)->ih_key));
+			  &(ih->ih_key), &((ih + nr - 1)->ih_key));
 	return 0;
     }
 
-    if (first < 0 || first > le16_to_cpu (blkh->blk_nr_item) - 1) 
+    if (first < 0 || first > nr - 1) 
 	from = 0;
     else 
 	from = first;
 
-    if (last < 0 || last > le16_to_cpu (blkh->blk_nr_item))
-	to = le16_to_cpu (blkh->blk_nr_item);
+    if (last < 0 || last > nr )
+	to = nr;
     else
 	to = last;
 
@@ -482,52 +495,50 @@
     return 0;
 }
 
-static char * reiserfs_version (char * buf)
-{
-    __u16 * pversion;
-
-    pversion = (__u16 *)(buf) + 36;
-    if (*pversion == 0)
-	return "0";
-    if (*pversion == 2)
-	return "2";
-    return "Unknown";
-}
-
-
 /* return 1 if this is not super block */
 static int print_super_block (struct buffer_head * bh)
 {
     struct reiserfs_super_block * rs = (struct reiserfs_super_block *)(bh->b_data);
     int skipped, data_blocks;
+    char *version;
     
 
-    if (strncmp (rs->s_magic,  REISERFS_SUPER_MAGIC_STRING, strlen ( REISERFS_SUPER_MAGIC_STRING)) &&
-	strncmp (rs->s_magic,  REISER2FS_SUPER_MAGIC_STRING, strlen ( REISER2FS_SUPER_MAGIC_STRING)))
+    if (strncmp (rs->s_magic,  REISERFS_SUPER_MAGIC_STRING,
+                 strlen ( REISERFS_SUPER_MAGIC_STRING)) == 0) {
+        version = "3.5";
+    } else if( strncmp (rs->s_magic,  REISER2FS_SUPER_MAGIC_STRING,
+                        strlen ( REISER2FS_SUPER_MAGIC_STRING)) == 0) {
+        version = "3.6";
+    } else {
 	return 1;
+    }
 
-    printk ("%s\'s super block in block %ld\n======================\n", kdevname (bh->b_dev), bh->b_blocknr);
-    printk ("Reiserfs version %s\n", reiserfs_version (bh->b_data));
-    printk ("Block count %u\n", le32_to_cpu (rs->s_block_count));
-    printk ("Blocksize %d\n", le16_to_cpu (rs->s_blocksize));
-    printk ("Free blocks %u\n", le32_to_cpu (rs->s_free_blocks));
-    skipped = bh->b_blocknr; // FIXME: this would be confusing if
+    printk ("%s\'s super block in block %ld\n======================\n",
+            kdevname (bh->b_dev), bh->b_blocknr);
+    printk ("Reiserfs version %s\n", version );
+    printk ("Block count %u\n", sb_block_count(rs));
+    printk ("Blocksize %d\n", sb_blocksize(rs));
+    printk ("Free blocks %u\n", sb_free_blocks(rs));
+    // FIXME: this would be confusing if
     // someone stores reiserfs super block in some data block ;)
-    data_blocks = le32_to_cpu (rs->s_block_count) - skipped - 1 -
-      le16_to_cpu (rs->s_bmap_nr) - (le32_to_cpu (rs->s_orig_journal_size) + 1) -
-      le32_to_cpu (rs->s_free_blocks);
+//    skipped = (bh->b_blocknr * bh->b_size) / sb_blocksize(rs);
+    skipped = bh->b_blocknr;
+    data_blocks = sb_block_count(rs) - skipped - 1 -
+                  sb_bmap_nr(rs) - (sb_orig_journal_size(rs) + 1) -
+                  sb_free_blocks(rs);
     printk ("Busy blocks (skipped %d, bitmaps - %d, journal blocks - %d\n"
 	    "1 super blocks, %d data blocks\n", 
-	    skipped, le16_to_cpu (rs->s_bmap_nr), 
-	    (le32_to_cpu (rs->s_orig_journal_size) + 1), data_blocks);
-    printk ("Root block %u\n", le32_to_cpu (rs->s_root_block));
-    printk ("Journal block (first) %d\n", le32_to_cpu (rs->s_journal_block));
-    printk ("Journal dev %d\n", le32_to_cpu (rs->s_journal_dev));    
-    printk ("Journal orig size %d\n", le32_to_cpu (rs->s_orig_journal_size));
+	    skipped, sb_bmap_nr(rs), 
+	    (sb_orig_journal_size(rs) + 1), data_blocks);
+    printk ("Root block %u\n", sb_root_block(rs));
+    printk ("Journal block (first) %d\n", sb_journal_block(rs));
+    printk ("Journal dev %d\n", sb_journal_dev(rs));
+    printk ("Journal orig size %d\n", sb_orig_journal_size(rs));
     printk ("Filesystem state %s\n", 
-	    (le16_to_cpu (rs->s_state) == REISERFS_VALID_FS) ? "VALID" : "ERROR");
-    printk ("Hash function \"%s\"\n", le16_to_cpu (rs->s_hash_function_code) == TEA_HASH ? "tea" :
-	    ((le16_to_cpu (rs->s_hash_function_code) == YURA_HASH) ? "rupasov" : "unknown"));
+	    (sb_state(rs) == REISERFS_VALID_FS) ? "VALID" : "ERROR");
+    printk ("Hash function \"%s\"\n",
+            sb_hash_function_code(rs) == TEA_HASH ? "tea" :
+	    ((sb_hash_function_code(rs) == YURA_HASH) ? "rupasov" : "unknown"));
 
 #if 0
     __u32 s_journal_trans_max ;           /* max number of blocks in a transaction.  */
@@ -536,7 +547,7 @@
     __u32 s_journal_max_commit_age ;      /* in seconds, how old can an async commit be */
     __u32 s_journal_max_trans_age ;       /* in seconds, how old can a transaction be */
 #endif
-    printk ("Tree height %d\n", rs->s_tree_height);
+    printk ("Tree height %d\n", sb_tree_height(rs));
     return 0;
 }
 
@@ -665,12 +676,14 @@
 static void check_leaf_block_head (struct buffer_head * bh)
 {
   struct block_head * blkh;
+  int nr;
 
   blkh = B_BLK_HEAD (bh);
-  if (le16_to_cpu (blkh->blk_nr_item) > (bh->b_size - BLKH_SIZE) / IH_SIZE)
+  nr = blkh_nr_item(blkh);
+  if ( nr > (bh->b_size - BLKH_SIZE) / IH_SIZE)
     reiserfs_panic (0, "vs-6010: check_leaf_block_head: invalid item number %z", bh);
-  if (le16_to_cpu (blkh->blk_free_space) > 
-      bh->b_size - BLKH_SIZE - IH_SIZE * le16_to_cpu (blkh->blk_nr_item))
+  if ( blkh_free_space(blkh) > 
+      bh->b_size - BLKH_SIZE - IH_SIZE * nr )
     reiserfs_panic (0, "vs-6020: check_leaf_block_head: invalid free space %z", bh);
     
 }
@@ -718,9 +731,9 @@
 {
 
   /*
-  printk ("reiserfs_put_super: session statistics: balances %d, fix_nodes %d, preserve list freeings %d, \
+  printk ("reiserfs_put_super: session statistics: balances %d, fix_nodes %d, \
 bmap with search %d, without %d, dir2ind %d, ind2dir %d\n",
-	  s->u.reiserfs_sb.s_do_balance, s->u.reiserfs_sb.s_fix_nodes, s->u.reiserfs_sb.s_preserve_list_freeings,
+	  s->u.reiserfs_sb.s_do_balance, s->u.reiserfs_sb.s_fix_nodes,
 	  s->u.reiserfs_sb.s_bmaps, s->u.reiserfs_sb.s_bmaps_without_search,
 	  s->u.reiserfs_sb.s_direct2indirect, s->u.reiserfs_sb.s_indirect2direct);
   */
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c
--- v2.4.12/linux/fs/reiserfs/stree.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/stree.c	Fri Oct 12 14:20:42 2001
@@ -226,8 +226,8 @@
 	to->on_disk_key.u.k_offset_v1.k_offset = le32_to_cpu (from->u.k_offset_v1.k_offset);
 	to->on_disk_key.u.k_offset_v1.k_uniqueness = le32_to_cpu (from->u.k_offset_v1.k_uniqueness);
     } else {
-	to->on_disk_key.u.k_offset_v2.k_offset = le64_to_cpu (from->u.k_offset_v2.k_offset);
-	to->on_disk_key.u.k_offset_v2.k_type = le16_to_cpu (from->u.k_offset_v2.k_type);
+	to->on_disk_key.u.k_offset_v2.k_offset = offset_v2_k_offset(&from->u.k_offset_v2);
+	to->on_disk_key.u.k_offset_v2.k_type = offset_v2_k_type(&from->u.k_offset_v2);
     } 
 }
 
@@ -268,19 +268,19 @@
 				       the item size.                      */
 	      int     * p_n_pos     /* Number of the searched for element. */
             ) {
-  int   n_rbound, n_lbound, n_j;
+    int   n_rbound, n_lbound, n_j;
 
-  for ( n_j = ((n_rbound = p_n_num - 1) + (n_lbound = 0))/2; n_lbound <= n_rbound; n_j = (n_rbound + n_lbound)/2 )
-    switch( COMP_KEYS((struct key *)((char * )p_v_base + n_j * p_n_width), (struct cpu_key *)p_v_key) )  {
-    case -1: n_lbound = n_j + 1; continue;
-    case  1: n_rbound = n_j - 1; continue;
-    case  0: *p_n_pos = n_j;     return ITEM_FOUND; /* Key found in the array.  */
-    }
-
-  /* bin_search did not find given key, it returns position of key,
-     that is minimal and greater than the given one. */
-  *p_n_pos = n_lbound;
-  return ITEM_NOT_FOUND;
+   for ( n_j = ((n_rbound = p_n_num - 1) + (n_lbound = 0))/2; n_lbound <= n_rbound; n_j = (n_rbound + n_lbound)/2 )
+     switch( COMP_KEYS((struct key *)((char * )p_v_base + n_j * p_n_width), (struct cpu_key *)p_v_key) )  {
+     case -1: n_lbound = n_j + 1; continue;
+     case  1: n_rbound = n_j - 1; continue;
+     case  0: *p_n_pos = n_j;     return ITEM_FOUND; /* Key found in the array.  */
+        }
+
+    /* bin_search did not find given key, it returns position of key,
+        that is minimal and greater than the given one. */
+    *p_n_pos = n_lbound;
+    return ITEM_NOT_FOUND;
 }
 
 #ifdef CONFIG_REISERFS_CHECK
@@ -495,12 +495,12 @@
     int nr;
 
     blkh = (struct block_head *)buf;
-    if (le16_to_cpu (blkh->blk_level) != DISK_LEAF_NODE_LEVEL) {
+    if ( blkh_level(blkh) != DISK_LEAF_NODE_LEVEL) {
 	printk ("is_leaf: this should be caught earlier\n");
 	return 0;
     }
 
-    nr = le16_to_cpu (blkh->blk_nr_item);
+    nr = blkh_nr_item(blkh);
     if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN))) {
 	/* item number is too big or too small */
 	reiserfs_warning ("is_leaf: nr_item seems wrong: %z\n", bh);
@@ -508,7 +508,7 @@
     }
     ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1;
     used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location (ih));
-    if (used_space != blocksize - le16_to_cpu (blkh->blk_free_space)) {
+    if (used_space != blocksize - blkh_free_space(blkh)) {
 	/* free space does not match to calculated amount of use space */
 	reiserfs_warning ("is_leaf: free space seems wrong: %z\n", bh);
 	return 0;
@@ -549,14 +549,14 @@
     int used_space;
 
     blkh = (struct block_head *)buf;
-    if (le16_to_cpu (blkh->blk_level) <= DISK_LEAF_NODE_LEVEL ||
-	le16_to_cpu (blkh->blk_level) > MAX_HEIGHT) {
+    nr = blkh_level(blkh);
+    if (nr <= DISK_LEAF_NODE_LEVEL || nr > MAX_HEIGHT) {
 	/* this level is not possible for internal nodes */
 	printk ("is_internal: this should be caught earlier\n");
 	return 0;
     }
     
-    nr = le16_to_cpu (blkh->blk_nr_item);
+    nr = blkh_nr_item(blkh);
     if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE)) {
 	/* for internal which is not root we might check min number of keys */
 	reiserfs_warning ("is_internal: number of key seems wrong: %z\n", bh);
@@ -564,7 +564,7 @@
     }
 
     used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1);
-    if (used_space != blocksize - le16_to_cpu (blkh->blk_free_space)) {
+    if (used_space != blocksize - blkh_free_space(blkh)) {
 	reiserfs_warning ("is_internal: free space seems wrong: %z\n", bh);
 	return 0;
     }
@@ -741,8 +741,10 @@
 		"vs-5152: tree level is less than stop level (%d)",
 		n_node_level, n_stop_level);
 
-	n_retval = bin_search (p_s_key, B_N_PITEM_HEAD(p_s_bh, 0), B_NR_ITEMS(p_s_bh),
-			       ( n_node_level == DISK_LEAF_NODE_LEVEL ) ? IH_SIZE : KEY_SIZE, &(p_s_last_element->pe_position));
+	n_retval = bin_search( p_s_key, B_N_PITEM_HEAD(p_s_bh, 0),
+                B_NR_ITEMS(p_s_bh),
+                ( n_node_level == DISK_LEAF_NODE_LEVEL ) ? IH_SIZE : KEY_SIZE,
+                &(p_s_last_element->pe_position));
 	if (n_node_level == n_stop_level) {
 	    return n_retval;
 	}
@@ -808,16 +810,16 @@
 	return retval;
     if ( retval == ITEM_FOUND )  {
 
-	RFALSE( ! B_N_PITEM_HEAD
-		(PATH_PLAST_BUFFER(p_s_search_path),
-		 PATH_LAST_POSITION(p_s_search_path))->ih_item_len,
-		"PAP-5165: item length equals zero");
+	RFALSE( ! ih_item_len(
+                B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_search_path),
+			       PATH_LAST_POSITION(p_s_search_path))),
+	        "PAP-5165: item length equals zero");
 
 	pos_in_item(p_s_search_path) = 0;
 	return POSITION_FOUND;
     }
 
-    RFALSE( ! PATH_LAST_POSITION(p_s_search_path), 
+    RFALSE( ! PATH_LAST_POSITION(p_s_search_path),
 	    "PAP-5170: position equals zero");
 
     /* Item is not found. Set path to the previous item. */
@@ -846,9 +848,9 @@
     /* Needed byte is not contained in the item pointed to by the
      path. Set pos_in_item out of the item. */
     if ( is_indirect_le_ih (p_le_ih) )
-	pos_in_item (p_s_search_path) = le16_to_cpu (p_le_ih->ih_item_len) / UNFM_P_SIZE;
+	pos_in_item (p_s_search_path) = ih_item_len(p_le_ih) / UNFM_P_SIZE;
     else
-	pos_in_item (p_s_search_path) = le16_to_cpu (p_le_ih->ih_item_len);
+        pos_in_item (p_s_search_path) = ih_item_len( p_le_ih );
   
     return POSITION_NOT_FOUND;
 }
@@ -880,9 +882,9 @@
 	return 1;
 
     /* Compare other items fields. */
-    if ( le16_to_cpu (p_s_path_item->u.ih_entry_count) != p_cpu_ih->u.ih_entry_count ||
-	 le16_to_cpu (p_s_path_item->ih_item_len) != p_cpu_ih->ih_item_len ||
-	 le16_to_cpu ( p_s_path_item->ih_item_location) != p_cpu_ih->ih_item_location )
+    if( ih_entry_count(p_s_path_item) != ih_entry_count(p_cpu_ih) ||
+	ih_item_len(p_s_path_item) != ih_item_len(p_cpu_ih) ||
+	ih_location(p_s_path_item) != ih_location(p_cpu_ih) )
 	return 1;
 
     /* Items are equal. */
@@ -913,7 +915,7 @@
 
     if ( new_file_length == max_reiserfs_offset (inode) ) {
 	/* item has to be deleted */
-	*cut_size = -(IH_SIZE + le16_to_cpu (le_ih->ih_item_len));
+	*cut_size = -(IH_SIZE + ih_item_len(le_ih));
 	return M_DELETE;
     }
 	
@@ -923,12 +925,12 @@
 	round_len = ROUND_UP (new_file_length); 
 	/* this was n_new_file_length < le_ih ... */
 	if ( round_len < le_ih_k_offset (le_ih) )  {
-	    *cut_size = -(IH_SIZE + le16_to_cpu (le_ih->ih_item_len));
+	    *cut_size = -(IH_SIZE + ih_item_len(le_ih));
 	    return M_DELETE; /* Delete this item. */
 	}
 	/* Calculate first position and size for cutting from item. */
 	pos_in_item (path) = round_len - (le_ih_k_offset (le_ih) - 1);
-	*cut_size = -(le16_to_cpu (le_ih->ih_item_len) - pos_in_item(path));
+	*cut_size = -(ih_item_len(le_ih) - pos_in_item(path));
 	
 	return M_CUT; /* Cut from this item. */
     }
@@ -937,11 +939,11 @@
     // old file: items may have any length
 
     if ( new_file_length < le_ih_k_offset (le_ih) )  {
-	*cut_size = -(IH_SIZE + le16_to_cpu (le_ih->ih_item_len));
+	*cut_size = -(IH_SIZE + ih_item_len(le_ih));
 	return M_DELETE; /* Delete this item. */
     }
     /* Calculate first position and size for cutting from item. */
-    *cut_size = -(le16_to_cpu (le_ih->ih_item_len) -
+    *cut_size = -(ih_item_len(le_ih) -
 		      (pos_in_item (path) = new_file_length + 1 - le_ih_k_offset (le_ih)));
     return M_CUT; /* Cut from this item. */
 }
@@ -956,15 +958,15 @@
     if (le_ih_k_offset (le_ih) == DOT_OFFSET && 
 	new_file_length == max_reiserfs_offset (inode)) {
 	RFALSE( ih_entry_count (le_ih) != 2,
-		"PAP-5220: incorrect empty directory item (%h)", le_ih);
-	*cut_size = -(IH_SIZE + le16_to_cpu (le_ih->ih_item_len));
+	        "PAP-5220: incorrect empty directory item (%h)", le_ih);
+	*cut_size = -(IH_SIZE + ih_item_len(le_ih));
 	return M_DELETE; /* Delete the directory item containing "." and ".." entry. */
     }
     
     if ( ih_entry_count (le_ih) == 1 )  {
 	/* Delete the directory item such as there is one record only
 	   in this item*/
-	*cut_size = -(IH_SIZE + le16_to_cpu (le_ih->ih_item_len));
+	*cut_size = -(IH_SIZE + ih_item_len(le_ih));
 	return M_DELETE;
     }
     
@@ -1003,7 +1005,7 @@
 	RFALSE( n_new_file_length != max_reiserfs_offset (inode),
 		"PAP-5210: mode must be M_DELETE");
 
-	*p_n_cut_size = -(IH_SIZE + le16_to_cpu (p_le_ih->ih_item_len));
+	*p_n_cut_size = -(IH_SIZE + ih_item_len(p_le_ih));
 	return M_DELETE;
     }
 
@@ -1051,13 +1053,13 @@
 	    /* Calculate balance mode and position in the item to remove unformatted nodes. */
 	    if ( n_new_file_length == max_reiserfs_offset (inode) ) {/* Case of delete. */
 		pos_in_item (p_s_path) = 0;
-		*p_n_cut_size = -(IH_SIZE + le16_to_cpu (s_ih.ih_item_len));
+		*p_n_cut_size = -(IH_SIZE + ih_item_len(&s_ih));
 		c_mode = M_DELETE;
 	    }
 	    else  { /* Case of truncate. */
 		if ( n_new_file_length < le_ih_k_offset (&s_ih) )  {
 		    pos_in_item (p_s_path) = 0;
-		    *p_n_cut_size = -(IH_SIZE + le16_to_cpu (s_ih.ih_item_len));
+		    *p_n_cut_size = -(IH_SIZE + ih_item_len(&s_ih));
 		    c_mode = M_DELETE; /* Delete this item. */
 		}
 		else  {
@@ -1074,7 +1076,7 @@
 			return M_CONVERT; /* Maybe convert last unformatted node to the direct item. */
 		    }
 		    /* Calculate size to cut. */
-		    *p_n_cut_size = -(s_ih.ih_item_len - pos_in_item (p_s_path) * UNFM_P_SIZE);
+		    *p_n_cut_size = -(ih_item_len(&s_ih) - pos_in_item(p_s_path) * UNFM_P_SIZE);
 
 		    c_mode = M_CUT;     /* Cut from this indirect item. */
 		}
@@ -1111,29 +1113,29 @@
 			p_n_unfm_pointer > (__u32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1,
 			"vs-5265: pointer out of range");
 
-		if ( ! *p_n_unfm_pointer )  { /* Hole, nothing to remove. */
+		if ( ! get_block_num(p_n_unfm_pointer,0) )  { /* Hole, nothing to remove. */
 		    if ( ! n_retry )
 			(*p_n_removed)++;
 		    continue;
 		}
 		/* Search for the buffer in cache. */
-		p_s_un_bh = get_hash_table(p_s_sb->s_dev, *p_n_unfm_pointer, n_blk_size);
+		p_s_un_bh = get_hash_table(p_s_sb->s_dev, get_block_num(p_n_unfm_pointer,0), n_blk_size);
 
 		if (p_s_un_bh) {
 		    mark_buffer_clean(p_s_un_bh) ;
 		    if (buffer_locked(p_s_un_bh)) {
-		        __wait_on_buffer(p_s_un_bh) ;
+		  __wait_on_buffer(p_s_un_bh) ;
 		    }
 		    /* even if the item moves, the block number of the
 		    ** unformatted node we want to cut won't.  So, it was
 		    ** safe to clean the buffer here, this block _will_
 		    ** get freed during this call to prepare_for_delete_or_cut
 		    */
-		    if ( item_moved (&s_ih, p_s_path) )  {
-		        need_research = 1;
-		        brelse(p_s_un_bh) ;
-		        break ;
-		    }
+		  if ( item_moved (&s_ih, p_s_path) )  {
+		      need_research = 1;
+		      brelse(p_s_un_bh) ;
+		      break ;
+		  }
 		}
 		if ( p_s_un_bh && block_in_use (p_s_un_bh)) {
 		    /* Block is locked or held more than by one holder and by
@@ -1157,15 +1159,15 @@
 		if ( ! n_retry )
 		    (*p_n_removed)++;
       
-		RFALSE( p_s_un_bh && 
-			(*p_n_unfm_pointer != p_s_un_bh->b_blocknr ),
+		RFALSE( p_s_un_bh &&
+                     get_block_num(p_n_unfm_pointer, 0) != p_s_un_bh->b_blocknr,
 		    // note: minix_truncate allows that. As truncate is
 		    // protected by down (inode->i_sem), two truncates can not
 		    // co-exist
-			"PAP-5280: blocks numbers are different");	
+		    "PAP-5280: blocks numbers are different");	
 
-		tmp = *p_n_unfm_pointer;
-		*p_n_unfm_pointer = 0;
+		tmp = get_block_num(p_n_unfm_pointer,0);
+		put_block_num(p_n_unfm_pointer, 0, 0);
 		journal_mark_dirty (th, p_s_sb, p_s_bh);
 		bforget (p_s_un_bh);
 		inode->i_blocks -= p_s_sb->s_blocksize / 512;
@@ -1173,7 +1175,7 @@
 		if ( item_moved (&s_ih, p_s_path) )  {
 		    need_research = 1;
 		    break ;
-		}
+		    }
 	    }
 
 	    /* a trick.  If the buffer has been logged, this
@@ -1237,9 +1239,9 @@
 	// we can't use EMPTY_DIR_SIZE, as old format dirs have a different
 	// empty size.  ick. FIXME, is this right?
 	//
-        return le16_to_cpu(p_le_ih->ih_item_len) ;
+	return ih_item_len(p_le_ih);
     }
-    n_del_size = ( c_mode == M_DELETE ) ? le16_to_cpu (p_le_ih->ih_item_len) : -p_s_tb->insert_size[0];
+    n_del_size = ( c_mode == M_DELETE ) ? ih_item_len(p_le_ih) : -p_s_tb->insert_size[0];
 
     if ( is_indirect_le_ih (p_le_ih) )
 	n_del_size = (n_del_size/UNFM_P_SIZE)*
@@ -1416,7 +1418,7 @@
 	}
 	if (!tb_init) {
 	    tb_init = 1 ;
-	    item_len = le16_to_cpu (PATH_PITEM_HEAD (&path)->ih_item_len);
+	    item_len = ih_item_len( PATH_PITEM_HEAD(&path) );
 	    init_tb_struct (th, &tb, th->t_super, &path, - (IH_SIZE + item_len));
 	}
 
@@ -1523,14 +1525,14 @@
 	/* look for the last byte of the tail */
 	if (search_for_position_by_key (inode->i_sb, &tail_key, path) == POSITION_NOT_FOUND)
 	    reiserfs_panic (inode->i_sb, "vs-5615: indirect_to_direct_roll_back: found invalid item");
-	RFALSE( path->pos_in_item != PATH_PITEM_HEAD (path)->ih_item_len - 1,
-		"vs-5616: appended bytes found");
+	RFALSE( path->pos_in_item != ih_item_len(PATH_PITEM_HEAD (path)) - 1,
+	        "vs-5616: appended bytes found");
 	PATH_LAST_POSITION (path) --;
 	
 	removed = reiserfs_delete_item (th, path, &tail_key, inode, 0/*unbh not needed*/);
 	RFALSE( removed <= 0 || removed > tail_len,
-		"vs-5617: there was tail %d bytes, removed item length %d bytes",
-		tail_len, removed);
+	        "vs-5617: there was tail %d bytes, removed item length %d bytes",
+                tail_len, removed);
 	tail_len -= removed;
 	set_cpu_key_k_offset (&tail_key, cpu_key_k_offset (&tail_key) - removed);
     }
@@ -1672,7 +1674,7 @@
 	    reiserfs_panic (p_s_sb, "vs-5652: reiserfs_cut_from_item: "
 			    "item must be indirect %h", le_ih);
 
-	if (c_mode == M_DELETE && le16_to_cpu (le_ih->ih_item_len) != UNFM_P_SIZE)
+	if (c_mode == M_DELETE && ih_item_len(le_ih) != UNFM_P_SIZE)
 	    reiserfs_panic (p_s_sb, "vs-5653: reiserfs_cut_from_item: "
 			    "completing indirect2direct conversion indirect item %h"
 			    "being deleted must be of 4 byte long", le_ih);
@@ -1825,6 +1827,7 @@
 
 	  journal_end(th, p_s_inode->i_sb, orig_len_alloc) ;
 	  journal_begin(th, p_s_inode->i_sb, orig_len_alloc) ;
+	  reiserfs_update_inode_transaction(p_s_inode) ;
 	}
     } while ( n_file_size > ROUND_UP (n_new_file_size) &&
 	      search_for_position_by_key(p_s_inode->i_sb, &s_item_key, &s_search_path) == POSITION_FOUND )  ;
@@ -1923,11 +1926,11 @@
     struct tree_balance s_ins_balance;
     int                 retval;
 
-    init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path, IH_SIZE + p_s_ih->ih_item_len);
+    init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path, IH_SIZE + ih_item_len(p_s_ih));
 
     /*
     if (p_c_body == 0)
-      n_zeros_num = p_s_ih->ih_item_len;
+      n_zeros_num = ih_item_len(p_s_ih);
     */
     //    le_key2cpu_key (&key, &(p_s_ih->ih_key));
 
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/super.c linux/fs/reiserfs/super.c
--- v2.4.12/linux/fs/reiserfs/super.c	Sun Sep 23 11:41:00 2001
+++ linux/fs/reiserfs/super.c	Sun Oct 21 10:14:38 2001
@@ -79,9 +79,6 @@
 // at the ext2 code and comparing. It's subfunctions contain no code
 // used as a template unless they are so labeled.
 //
-/* there should be no suspected recipients already. True and cautious
-   bitmaps should not differ. We only have to free preserve list and
-   write both bitmaps */
 void reiserfs_put_super (struct super_block * s)
 {
   int i;
@@ -91,7 +88,7 @@
   if (!(s->s_flags & MS_RDONLY)) {
     journal_begin(&th, s, 10) ;
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
-    s->u.reiserfs_sb.s_rs->s_state = le16_to_cpu (s->u.reiserfs_sb.s_mount_state);
+    set_sb_state( SB_DISK_SUPER_BLOCK(s), s->u.reiserfs_sb.s_mount_state );
     journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
   }
 
@@ -250,26 +247,26 @@
   
   if (*flags & MS_RDONLY) {
     /* try to remount file system with read-only permissions */
-    if (le16_to_cpu (rs->s_state) == REISERFS_VALID_FS || s->u.reiserfs_sb.s_mount_state != REISERFS_VALID_FS) {
+    if (sb_state(rs) == REISERFS_VALID_FS || s->u.reiserfs_sb.s_mount_state != REISERFS_VALID_FS) {
       return 0;
     }
 
     journal_begin(&th, s, 10) ;
     /* Mounting a rw partition read-only. */
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
-    rs->s_state = cpu_to_le16 (s->u.reiserfs_sb.s_mount_state);
+    set_sb_state( rs, s->u.reiserfs_sb.s_mount_state );
     journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
     s->s_dirt = 0;
   } else {
-    s->u.reiserfs_sb.s_mount_state = le16_to_cpu(rs->s_state) ;
+    s->u.reiserfs_sb.s_mount_state = sb_state(rs) ;
     s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
     journal_begin(&th, s, 10) ;
 
     /* Mount a partition which is read-only, read-write */
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
-    s->u.reiserfs_sb.s_mount_state = le16_to_cpu (rs->s_state);
+    s->u.reiserfs_sb.s_mount_state = sb_state(rs);
     s->s_flags &= ~MS_RDONLY;
-    rs->s_state = cpu_to_le16 (REISERFS_ERROR_FS);
+    set_sb_state( rs, REISERFS_ERROR_FS );
     /* mark_buffer_dirty (SB_BUFFER_WITH_SB (s), 1); */
     journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
     s->s_dirt = 0;
@@ -287,10 +284,10 @@
     int i, bmp, dl ;
     struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK(s);
 
-    SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * le16_to_cpu (rs->s_bmap_nr), GFP_NOFS, s);
+    SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * sb_bmap_nr(rs), GFP_NOFS, s);
     if (SB_AP_BITMAP (s) == 0)
 	return 1;
-    memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * le16_to_cpu (rs->s_bmap_nr));
+    memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * sb_bmap_nr(rs));
 
     /* reiserfs leaves the first 64k unused so that any partition
        labeling scheme currently used will have enough space. Then we
@@ -299,7 +296,7 @@
     SB_AP_BITMAP (s)[0] = reiserfs_bread (s->s_dev, bmp, s->s_blocksize);
     if(!SB_AP_BITMAP(s)[0])
 	return 1;
-    for (i = 1, bmp = dl = rs->s_blocksize * 8; i < le16_to_cpu (rs->s_bmap_nr); i ++) {
+    for (i = 1, bmp = dl = s->s_blocksize * 8; i < sb_bmap_nr(rs); i ++) {
 	SB_AP_BITMAP (s)[i] = reiserfs_bread (s->s_dev, bmp, s->s_blocksize);
 	if (!SB_AP_BITMAP (s)[i])
 	    return 1;
@@ -316,13 +313,13 @@
   int bmp1 = (REISERFS_OLD_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1;  /* first of bitmap blocks */
 
   /* read true bitmap */
-  SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * le16_to_cpu (rs->s_bmap_nr), GFP_NOFS, s);
+  SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * sb_bmap_nr(rs), GFP_NOFS, s);
   if (SB_AP_BITMAP (s) == 0)
     return 1;
 
-  memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * le16_to_cpu (rs->s_bmap_nr));
+  memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * sb_bmap_nr(rs));
 
-  for (i = 0; i < le16_to_cpu (rs->s_bmap_nr); i ++) {
+  for (i = 0; i < sb_bmap_nr(rs); i ++) {
     SB_AP_BITMAP (s)[i] = reiserfs_bread (s->s_dev, bmp1 + i, s->s_blocksize);
     if (!SB_AP_BITMAP (s)[i])
       return 1;
@@ -349,35 +346,33 @@
 		      free, SB_FREE_BLOCKS (s));
 }
 
-
-
 static int read_super_block (struct super_block * s, int size, int offset)
 {
     struct buffer_head * bh;
     struct reiserfs_super_block * rs;
-
+ 
 
     bh = bread (s->s_dev, offset / size, size);
     if (!bh) {
-	printk ("read_super_block: "
-		"bread failed (dev %s, block %d, size %d)\n", 
-		kdevname (s->s_dev), offset / size, size);
-	return 1;
+      printk ("read_super_block: "
+              "bread failed (dev %s, block %d, size %d)\n",
+              kdevname (s->s_dev), offset / size, size);
+      return 1;
     }
-
+ 
     rs = (struct reiserfs_super_block *)bh->b_data;
     if (!is_reiserfs_magic_string (rs)) {
-	printk ("read_super_block: "
-		"can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
-		kdevname(s->s_dev), bh->b_blocknr, size);
-	brelse (bh);
-	return 1;
+      printk ("read_super_block: "
+              "can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
+              kdevname(s->s_dev), bh->b_blocknr, size);
+      brelse (bh);
+      return 1;
     }
-
+ 
     //
     // ok, reiserfs signature (old or new) found in at the given offset
-    //
-    s->s_blocksize = le16_to_cpu (rs->s_blocksize);
+    //    
+    s->s_blocksize = sb_blocksize(rs);
     s->s_blocksize_bits = 0;
     while ((1 << s->s_blocksize_bits) != s->s_blocksize)
 	s->s_blocksize_bits ++;
@@ -387,21 +382,22 @@
     if (s->s_blocksize != size)
 	set_blocksize (s->s_dev, s->s_blocksize);
 
-    bh = bread (s->s_dev, offset / s->s_blocksize, s->s_blocksize);
+    bh = reiserfs_bread (s->s_dev, offset / s->s_blocksize, s->s_blocksize);
     if (!bh) {
-	printk ("read_super_block: "
-		"bread failed (dev %s, block %d, size %d)\n", 
-		kdevname (s->s_dev), offset / size, size);
+	printk("read_super_block: "
+                "bread failed (dev %s, block %d, size %d)\n",
+                kdevname (s->s_dev), offset / size, size);
 	return 1;
     }
     
     rs = (struct reiserfs_super_block *)bh->b_data;
     if (!is_reiserfs_magic_string (rs) ||
-	le16_to_cpu (rs->s_blocksize) != s->s_blocksize) {
+	sb_blocksize(rs) != s->s_blocksize) {
 	printk ("read_super_block: "
 		"can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
 		kdevname(s->s_dev), bh->b_blocknr, size);
 	brelse (bh);
+	printk ("read_super_block: can't find a reiserfs filesystem on dev %s.\n", kdevname(s->s_dev));
 	return 1;
     }
     /* must check to be sure we haven't pulled an old format super out
@@ -409,8 +405,8 @@
     ** will work.  If block we've just read in is inside the
     ** journal for that super, it can't be valid.  
     */
-    if (bh->b_blocknr >= le32_to_cpu(rs->s_journal_block) && 
-	bh->b_blocknr < (le32_to_cpu(rs->s_journal_block) + JOURNAL_BLOCK_COUNT)) {
+    if (bh->b_blocknr >= sb_journal_block(rs) && 
+	bh->b_blocknr < (sb_journal_block(rs) + JOURNAL_BLOCK_COUNT)) {
 	brelse(bh) ;
 	printk("super-459: read_super_block: "
 	       "super found at block %lu is within its own log. "
@@ -483,7 +479,7 @@
 	if (retval == NAME_NOT_FOUND)
 	    de.de_entry_num --;
 	set_de_name_and_namelen (&de);
-	if (le32_to_cpu (de.de_deh[de.de_entry_num].deh_offset) == DOT_DOT_OFFSET) {
+	if (deh_offset( &(de.de_deh[de.de_entry_num]) ) == DOT_DOT_OFFSET) {
 	    /* allow override in this case */
 	    if (reiserfs_rupasov_hash(s)) {
 		hash = YURA_HASH ;
@@ -499,7 +495,7 @@
 	    hash = UNSET_HASH ;
 	    break;
 	}
-	if (GET_HASH_VALUE(le32_to_cpu(de.de_deh[de.de_entry_num].deh_offset))==
+	if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) ==
 	    GET_HASH_VALUE (yura_hash (de.de_name, de.de_namelen)))
 	    hash = YURA_HASH;
 	else
@@ -516,7 +512,7 @@
 {
     __u32 code;
 
-    code = le32_to_cpu (s->u.reiserfs_sb.s_rs->s_hash_function_code);
+    code = sb_hash_function_code(SB_DISK_SUPER_BLOCK(s));
 
     /* reiserfs_hash_detect() == true if any of the hash mount options
     ** were used.  We must check them to make sure the user isn't
@@ -558,8 +554,8 @@
     */
     if (code != UNSET_HASH && 
 	!(s->s_flags & MS_RDONLY) && 
-        code != le32_to_cpu (s->u.reiserfs_sb.s_rs->s_hash_function_code)) {
-        s->u.reiserfs_sb.s_rs->s_hash_function_code = cpu_to_le32(code) ;
+        code != sb_hash_function_code(SB_DISK_SUPER_BLOCK(s))) {
+        set_sb_hash_function_code(SB_DISK_SUPER_BLOCK(s), code);
     }
     return code;
 }
@@ -646,7 +642,7 @@
 	    old_format = 1;
     }
 
-    s->u.reiserfs_sb.s_mount_state = le16_to_cpu (SB_DISK_SUPER_BLOCK (s)->s_state); /* journal victim */
+    s->u.reiserfs_sb.s_mount_state = SB_REISERFS_STATE(s);
     s->u.reiserfs_sb.s_mount_state = REISERFS_VALID_FS ;
 
     if (old_format ? read_old_bitmaps(s) : read_bitmaps(s)) { 
@@ -702,10 +698,10 @@
 
     if (!(s->s_flags & MS_RDONLY)) {
 	struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
-	int old_magic;
+        int old_magic;
 
-	old_magic = strncmp (rs->s_magic,  REISER2FS_SUPER_MAGIC_STRING, 
-			     strlen ( REISER2FS_SUPER_MAGIC_STRING));
+      old_magic = strncmp (rs->s_magic,  REISER2FS_SUPER_MAGIC_STRING,
+                           strlen ( REISER2FS_SUPER_MAGIC_STRING));
 	if( old_magic && le16_to_cpu(rs->s_version) != 0 ) {
 	  dput(s->s_root) ;
 	  s->s_root = NULL ;
@@ -716,7 +712,7 @@
 	journal_begin(&th, s, 1) ;
 	reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
 
-	rs->s_state = cpu_to_le16 (REISERFS_ERROR_FS);
+        set_sb_state( rs, REISERFS_ERROR_FS );
 
         if ( old_magic ) {
 	    // filesystem created under 3.5.x found
@@ -736,7 +732,7 @@
 	}
 
 	// mark hash in super block: it could be unset. overwrite should be ok
-	rs->s_hash_function_code = cpu_to_le32 (function2code (s->u.reiserfs_sb.s_hash_function));
+        set_sb_hash_function_code( rs, function2code(s->u.reiserfs_sb.s_hash_function ) );
 
 	journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
 	journal_end(&th, s, 1) ;
@@ -785,13 +781,13 @@
   struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
   
 				/* changed to accomodate gcc folks.*/
-  buf->f_type =  REISERFS_SUPER_MAGIC;
-  buf->f_bsize = le32_to_cpu (s->s_blocksize);
-  buf->f_blocks = le32_to_cpu (rs->s_block_count) - le16_to_cpu (rs->s_bmap_nr) - 1;
-  buf->f_bfree = le32_to_cpu (rs->s_free_blocks);
-  buf->f_bavail = buf->f_bfree;
-  buf->f_files = -1;
-  buf->f_ffree = -1;
+  buf->f_type    =  REISERFS_SUPER_MAGIC;
+  buf->f_bsize   = s->s_blocksize;
+  buf->f_blocks  = sb_block_count(rs) - sb_bmap_nr(rs) - 1;
+  buf->f_bfree   = sb_free_blocks(rs);
+  buf->f_bavail  = buf->f_bfree;
+  buf->f_files   = -1;
+  buf->f_ffree   = -1;
   buf->f_namelen = (REISERFS_MAX_NAME_LEN (s->s_blocksize));
   return 0;
 }
@@ -806,6 +802,9 @@
         return register_filesystem(&reiserfs_fs_type);
 }
 
+MODULE_DESCRIPTION("ReiserFS journaled filesystem");
+MODULE_AUTHOR("Hans Reiser <reiser@namesys.com>");
+MODULE_LICENSE("GPL");
 EXPORT_NO_SYMBOLS;
 
 //
diff -u --recursive --new-file v2.4.12/linux/fs/reiserfs/tail_conversion.c linux/fs/reiserfs/tail_conversion.c
--- v2.4.12/linux/fs/reiserfs/tail_conversion.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/reiserfs/tail_conversion.c	Fri Oct 12 14:19:28 2001
@@ -61,7 +61,7 @@
     if ( is_statdata_le_ih (p_le_ih) )  {
 	/* Insert new indirect item. */
 	set_ih_free_space (&ind_ih, 0); /* delete at nearest future */
-	ind_ih.ih_item_len = cpu_to_le16 (UNFM_P_SIZE);
+        put_ih_item_len( &ind_ih, UNFM_P_SIZE );
 	PATH_LAST_POSITION (path)++;
 	n_retval = reiserfs_insert_item (th, path, &end_key, &ind_ih, 
 					 (char *)&unfm_ptr);
@@ -93,10 +93,10 @@
 			    "direct item (%k) not found", &end_key);
 	p_le_ih = PATH_PITEM_HEAD (path);
 	RFALSE( !is_direct_le_ih (p_le_ih),
-		"vs-14055: direct item expected(%k), found %h", 
-		&end_key, p_le_ih);
-	tail_size = (le_ih_k_offset (p_le_ih) & (n_blk_size - 1))
-	    + ih_item_len(p_le_ih) - 1;
+	        "vs-14055: direct item expected(%k), found %h",
+                &end_key, p_le_ih);
+        tail_size = (le_ih_k_offset (p_le_ih) & (n_blk_size - 1))
+            + ih_item_len(p_le_ih) - 1;
 
 	/* we only send the unbh pointer if the buffer is not up to date.
 	** this avoids overwriting good data from writepage() with old data
@@ -214,7 +214,7 @@
     else
 	round_tail_len = tail_len;
 
-    pos = le_ih_k_offset (&s_ih) - 1 + (le16_to_cpu (s_ih.ih_item_len) / UNFM_P_SIZE - 1) * p_s_sb->s_blocksize;
+    pos = le_ih_k_offset (&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * p_s_sb->s_blocksize;
     pos1 = pos;
 
     // we are protected by i_sem. The tail can not disapper, not
@@ -231,7 +231,7 @@
 	copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
 #ifdef CONFIG_REISERFS_CHECK
 	pos = le_ih_k_offset (&s_ih) - 1 + 
-	    (le16_to_cpu (s_ih.ih_item_len) / UNFM_P_SIZE - 1) * p_s_sb->s_blocksize;
+	    (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * p_s_sb->s_blocksize;
 	if (pos != pos1)
 	    reiserfs_panic (p_s_sb, "vs-5530: indirect2direct: "
 			    "tail position changed while we were reading it");
diff -u --recursive --new-file v2.4.12/linux/fs/super.c linux/fs/super.c
--- v2.4.12/linux/fs/super.c	Thu Oct 11 08:02:26 2001
+++ linux/fs/super.c	Sat Oct 20 19:14:42 2001
@@ -681,6 +681,7 @@
 	} else {
 		kdev_t dev = get_unnamed_dev();
 		if (!dev) {
+			spin_unlock(&sb_lock);
 			put_super(s);
 			return ERR_PTR(-EMFILE);
 		}
@@ -865,13 +866,21 @@
 	return do_kern_mount((char *)type->name, 0, (char *)type->name, NULL);
 }
 
+static char * __initdata root_mount_data;
+static int __init root_data_setup(char *str)
+{
+	root_mount_data = str;
+	return 1;
+}
+
 static char * __initdata root_fs_names;
 static int __init fs_names_setup(char *str)
 {
 	root_fs_names = str;
-	return 0;
+	return 1;
 }
 
+__setup("rootflags=", root_data_setup);
 __setup("rootfstype=", fs_names_setup);
 
 static void __init get_fs_names(char *page)
@@ -1022,7 +1031,8 @@
 		struct file_system_type * fs_type = get_fs_type(p);
 		if (!fs_type)
   			continue;
-  		sb = read_super(ROOT_DEV,bdev,fs_type,root_mountflags,NULL);
+  		sb = read_super(ROOT_DEV, bdev, fs_type,
+				root_mountflags, root_mount_data);
 		if (sb) 
 			goto mount_it;
 		put_filesystem(fs_type);
diff -u --recursive --new-file v2.4.12/linux/fs/udf/balloc.c linux/fs/udf/balloc.c
--- v2.4.12/linux/fs/udf/balloc.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/udf/balloc.c	Thu Oct 11 08:59:24 2001
@@ -44,12 +44,15 @@
 #define leBPL_to_cpup(x) leNUM_to_cpup(BITS_PER_LONG, x)
 #define leNUM_to_cpup(x,y) xleNUM_to_cpup(x,y)
 #define xleNUM_to_cpup(x,y) (le ## x ## _to_cpup(y))
+#define UintBPL Uint(BITS_PER_LONG)
+#define Uint(x) xUint(x)
+#define xUint(x) Uint ## x
 
 extern inline int find_next_one_bit (void * addr, int size, int offset)
 {
-	unsigned long * p = ((unsigned long *) addr) + (offset / BITS_PER_LONG);
-	unsigned long result = offset & ~(BITS_PER_LONG-1);
-	unsigned long tmp;
+	UintBPL * p = ((UintBPL *) addr) + (offset / BITS_PER_LONG);
+	UintBPL result = offset & ~(BITS_PER_LONG-1);
+	UintBPL tmp;
 
 	if (offset >= size)
 		return size;
@@ -126,7 +129,7 @@
 	}
 }
 
-static inline int load_block_bitmap(struct super_block *sb,
+static inline int load_block_bitmap(struct super_block * sb,
 	struct udf_bitmap *bitmap, unsigned int block_group)
 {
 	int slot;
@@ -142,7 +145,8 @@
 	return slot;
 }
 
-static void udf_bitmap_free_blocks(struct inode * inode,
+static void udf_bitmap_free_blocks(struct super_block * sb,
+	struct inode * inode,
 	struct udf_bitmap *bitmap, lb_addr bloc, Uint32 offset, Uint32 count)
 {
 	struct buffer_head * bh = NULL;
@@ -152,14 +156,6 @@
 	unsigned long i;
 	int bitmap_nr;
 	unsigned long overflow;
-	struct super_block * sb;
-
-	sb = inode->i_sb;
-	if (!sb)
-	{
-		udf_debug("nonexistent device");
-		return;
-	}
 
 	lock_super(sb);
 	if (bloc.logicalBlockNum < 0 ||
@@ -200,7 +196,8 @@
 		}
 		else
 		{
-			DQUOT_FREE_BLOCK(inode, 1);
+			if (inode)
+				DQUOT_FREE_BLOCK(inode, 1);
 			if (UDF_SB_LVIDBH(sb))
 			{
 				UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
@@ -223,7 +220,8 @@
 	return;
 }
 
-static int udf_bitmap_prealloc_blocks(struct inode * inode,
+static int udf_bitmap_prealloc_blocks(struct super_block * sb,
+	struct inode * inode,
 	struct udf_bitmap *bitmap, Uint16 partition, Uint32 first_block,
 	Uint32 block_count)
 {
@@ -231,14 +229,7 @@
 	int bit, block, block_group, group_start;
 	int nr_groups, bitmap_nr;
 	struct buffer_head *bh;
-	struct super_block *sb;
 
-	sb = inode->i_sb;
-	if (!sb)
-	{
-		udf_debug("nonexistent device\n");
-		return 0;
-	}
 	lock_super(sb);
 
 	if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
@@ -293,23 +284,17 @@
 	return alloc_count;
 }
 
-static int udf_bitmap_new_block(struct inode * inode,
+static int udf_bitmap_new_block(struct super_block * sb,
+	struct inode * inode,
 	struct udf_bitmap *bitmap, Uint16 partition, Uint32 goal, int *err)
 {
 	int newbit, bit=0, block, block_group, group_start;
 	int end_goal, nr_groups, bitmap_nr, i;
 	struct buffer_head *bh = NULL;
-	struct super_block *sb;
 	char *ptr;
 	int newblock = 0;
 
 	*err = -ENOSPC;
-	sb = inode->i_sb;
-	if (!sb)
-	{
-		udf_debug("nonexistent device\n");
-		return newblock;
-	}
 	lock_super(sb);
 
 repeat:
@@ -404,7 +389,7 @@
 	/*
 	 * Check quota for allocation of this block.
 	 */
-	if (DQUOT_ALLOC_BLOCK(inode, 1))
+	if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
 	{
 		unlock_super(sb);
 		*err = -EDQUOT;
@@ -439,30 +424,17 @@
 	return 0;
 }
 
-static void udf_table_free_blocks(struct inode * inode,
+static void udf_table_free_blocks(struct super_block * sb,
+	struct inode * inode,
 	struct inode * table, lb_addr bloc, Uint32 offset, Uint32 count)
 {
-	struct super_block * sb;
 	Uint32 start, end;
 	Uint32 nextoffset, oextoffset, elen;
 	lb_addr nbloc, obloc, eloc;
 	struct buffer_head *obh, *nbh;
-	char etype;
+	Sint8 etype;
 	int i;
 
-	udf_debug("ino=%ld, bloc=%d, offset=%d, count=%d\n",
-		inode->i_ino, bloc.logicalBlockNum, offset, count);
-
-	sb = inode->i_sb;
-	if (!sb)
-	{
-		udf_debug("nonexistent device");
-		return;
-	}
-
-	if (table == NULL)
-		return;
-
 	lock_super(sb);
 	if (bloc.logicalBlockNum < 0 ||
 		(bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
@@ -475,7 +447,8 @@
 
 	/* We do this up front - There are some error conditions that could occure,
 	   but.. oh well */
-	DQUOT_FREE_BLOCK(inode, count);
+	if (inode)
+		DQUOT_FREE_BLOCK(inode, count);
 	if (UDF_SB_LVIDBH(sb))
 	{
 		UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
@@ -690,33 +663,20 @@
 	return;
 }
 
-static int udf_table_prealloc_blocks(struct inode * inode,
+static int udf_table_prealloc_blocks(struct super_block * sb,
+	struct inode * inode,
 	struct inode *table, Uint16 partition, Uint32 first_block,
 	Uint32 block_count)
 {
-	struct super_block *sb;
 	int alloc_count = 0;
 	Uint32 extoffset, elen, adsize;
 	lb_addr bloc, eloc;
 	struct buffer_head *bh;
-	char etype = -1;
-
-	udf_debug("ino=%ld, partition=%d, first_block=%d, block_count=%d\n",
-		inode->i_ino, partition, first_block, block_count);
-
-	sb = inode->i_sb;
-	if (!sb)
-	{
-		udf_debug("nonexistent device\n");
-		return 0;
-	}
+	Sint8 etype = -1;
 
 	if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
 		return 0;
 
-	if (table == NULL)
-		return 0;
-
 	if (UDF_I_ALLOCTYPE(table) == ICB_FLAG_AD_SHORT)
 		adsize = sizeof(short_ad);
 	else if (UDF_I_ALLOCTYPE(table) == ICB_FLAG_AD_LONG)
@@ -745,7 +705,9 @@
 		extoffset -= adsize;
 
 		alloc_count = (elen >> sb->s_blocksize_bits);
-		if (alloc_count > block_count)
+		if (inode && DQUOT_PREALLOC_BLOCK(inode, alloc_count > block_count ? block_count : alloc_count))
+			alloc_count = 0;
+		else if (alloc_count > block_count)
 		{
 			alloc_count = block_count;
 			eloc.logicalBlockNum += alloc_count;
@@ -765,37 +727,24 @@
 		UDF_SB_LVID(sb)->freeSpaceTable[partition] =
 			cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
+		sb->s_dirt = 1;
 	}
-	sb->s_dirt = 1;
 	unlock_super(sb);
-	udf_debug("alloc_count=%d\n", alloc_count);
 	return alloc_count;
 }
 
-static int udf_table_new_block(const struct inode * inode,
+static int udf_table_new_block(struct super_block * sb,
+	struct inode * inode,
 	struct inode *table, Uint16 partition, Uint32 goal, int *err)
 {
-	struct super_block *sb;
 	Uint32 spread = 0xFFFFFFFF, nspread;
 	Uint32 newblock = 0, adsize;
 	Uint32 extoffset, goal_extoffset, elen, goal_elen = 0;
 	lb_addr bloc, goal_bloc, eloc, goal_eloc;
 	struct buffer_head *bh, *goal_bh;
-	char etype;
-
-	udf_debug("ino=%ld, partition=%d, goal=%d\n",
-		inode->i_ino, partition, goal);
+	Sint8 etype;
 
 	*err = -ENOSPC;
-	sb = inode->i_sb;
-	if (!sb)
-	{
-		udf_debug("nonexistent device\n");
-		return newblock;
-	}
-
-	if (table == NULL)
-		return newblock;
 
 	if (UDF_I_ALLOCTYPE(table) == ICB_FLAG_AD_SHORT)
 		adsize = sizeof(short_ad);
@@ -868,6 +817,14 @@
 	goal_eloc.logicalBlockNum ++;
 	goal_elen -= sb->s_blocksize;
 
+	if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
+	{
+		udf_release_data(goal_bh);
+		unlock_super(sb);
+		*err = -EDQUOT;
+		return 0;
+	}
+
 	if (goal_elen)
 		udf_write_aext(table, goal_bloc, &goal_extoffset, goal_eloc, goal_elen, goal_bh, 1);
 	else
@@ -887,93 +844,98 @@
 	return newblock;
 }
 
-inline void udf_free_blocks(struct inode * inode, lb_addr bloc,
-	Uint32 offset, Uint32 count)
+inline void udf_free_blocks(struct super_block * sb,
+	struct inode * inode,
+	lb_addr bloc, Uint32 offset, Uint32 count)
 {
-	if (UDF_SB_PARTFLAGS(inode->i_sb, bloc.partitionReferenceNum) & UDF_PART_FLAG_UNALLOC_BITMAP)
+	Uint16 partition = bloc.partitionReferenceNum;
+
+	if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
 	{
-		return udf_bitmap_free_blocks(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[bloc.partitionReferenceNum].s_uspace.s_bitmap,
+		return udf_bitmap_free_blocks(sb, inode,
+			UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
 			bloc, offset, count);
 	}
-	else if (UDF_SB_PARTFLAGS(inode->i_sb, bloc.partitionReferenceNum) & UDF_PART_FLAG_UNALLOC_TABLE)
+	else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
 	{
-		return udf_table_free_blocks(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[bloc.partitionReferenceNum].s_uspace.s_table,
+		return udf_table_free_blocks(sb, inode,
+			UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
 			bloc, offset, count);
 	}
-	else if (UDF_SB_PARTFLAGS(inode->i_sb, bloc.partitionReferenceNum) & UDF_PART_FLAG_FREED_BITMAP)
+	else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
 	{
-		return udf_bitmap_free_blocks(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[bloc.partitionReferenceNum].s_fspace.s_bitmap,
+		return udf_bitmap_free_blocks(sb, inode,
+			UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
 			bloc, offset, count);
 	}
-	else if (UDF_SB_PARTFLAGS(inode->i_sb, bloc.partitionReferenceNum) & UDF_PART_FLAG_FREED_TABLE)
+	else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
 	{
-		return udf_table_free_blocks(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[bloc.partitionReferenceNum].s_fspace.s_table,
+		return udf_table_free_blocks(sb, inode,
+			UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
 			bloc, offset, count);
 	}
 	else
 		return;
 }
 
-inline int udf_prealloc_blocks(struct inode * inode, Uint16 partition,
-	Uint32 first_block, Uint32 block_count)
+inline int udf_prealloc_blocks(struct super_block * sb,
+	struct inode * inode,
+	Uint16 partition, Uint32 first_block, Uint32 block_count)
 {
-	if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
+	if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
 	{
-		return udf_bitmap_prealloc_blocks(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_uspace.s_bitmap,
+		return udf_bitmap_prealloc_blocks(sb, inode,
+			UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
 			partition, first_block, block_count);
 	}
-	else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
+	else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
 	{
-		return udf_table_prealloc_blocks(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_uspace.s_table,
+		return udf_table_prealloc_blocks(sb, inode,
+			UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
 			partition, first_block, block_count);
 	}
-	else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
+	else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
 	{
-		return udf_bitmap_prealloc_blocks(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_fspace.s_bitmap,
+		return udf_bitmap_prealloc_blocks(sb, inode,
+			UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
 			partition, first_block, block_count);
 	}
-	else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_FREED_TABLE)
+	else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
 	{
-		return udf_table_prealloc_blocks(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_fspace.s_table,
+		return udf_table_prealloc_blocks(sb, inode,
+			UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
 			partition, first_block, block_count);
 	}
 	else
 		return 0;
 }
 
-inline int udf_new_block(struct inode * inode, Uint16 partition,
-	Uint32 goal, int *err)
+inline int udf_new_block(struct super_block * sb,
+	struct inode * inode,
+	Uint16 partition, Uint32 goal, int *err)
 {
-	if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
+	if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
 	{
-		return udf_bitmap_new_block(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_uspace.s_bitmap,
+		return udf_bitmap_new_block(sb, inode,
+			UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
 			partition, goal, err);
 	}
-	else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
+	else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
 	{
-		return udf_table_new_block(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_uspace.s_table,
+		return udf_table_new_block(sb, inode,
+			UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
 			partition, goal, err);
 	}
-	else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
+	else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
 	{
-		return udf_bitmap_new_block(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_fspace.s_bitmap,
+		return udf_bitmap_new_block(sb, inode,
+			UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
 			partition, goal, err);
 	}
-	else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_FREED_TABLE)
+	else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
 	{
-		return udf_table_new_block(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_fspace.s_table,
+		return udf_table_new_block(sb, inode,
+			UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
 			partition, goal, err);
 	}
 	else
diff -u --recursive --new-file v2.4.12/linux/fs/udf/dir.c linux/fs/udf/dir.c
--- v2.4.12/linux/fs/udf/dir.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/udf/dir.c	Thu Oct 11 08:59:24 2001
@@ -186,7 +186,7 @@
 				udf_release_data(fibh.ebh);
 			udf_release_data(fibh.sbh);
 			udf_release_data(bh);
-			return -ENOENT;
+			return 0;
 		}
 
 		liu = le16_to_cpu(cfi.lengthOfImpUse);
diff -u --recursive --new-file v2.4.12/linux/fs/udf/file.c linux/fs/udf/file.c
--- v2.4.12/linux/fs/udf/file.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/udf/file.c	Thu Oct 11 08:59:24 2001
@@ -206,7 +206,7 @@
 int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 	unsigned long arg)
 {
-	int result = -1;
+	int result = -EINVAL;
 	struct buffer_head *bh = NULL;
 	long_ad eaicb;
 	Uint8 *ea = NULL;
@@ -228,16 +228,16 @@
 	switch (cmd)
 	{
 		case UDF_GETVOLIDENT:
-			if ( (result == verify_area(VERIFY_WRITE, (char *)arg, 32)) == 0)
-				result = copy_to_user((char *)arg, UDF_SB_VOLIDENT(inode->i_sb), 32);
-			return result;
+			return copy_to_user((char *)arg,
+				UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0;
 		case UDF_RELOCATE_BLOCKS:
 		{
 			long old, new;
 
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-			get_user(old, (long *)arg);
-			if ((result = udf_relocate_blocks(inode->i_sb, old, &new)) == 0)
+			if (get_user(old, (long *)arg)) return -EFAULT;
+			if ((result = udf_relocate_blocks(inode->i_sb,
+					old, &new)) == 0)
 				result = put_user(new, (long *)arg);
 
 			return result;
@@ -277,16 +277,12 @@
 	switch (cmd) 
 	{
 		case UDF_GETEASIZE:
-			if ( (result = verify_area(VERIFY_WRITE, (char *)arg, 4)) == 0) 
-				result = put_user(UDF_I_LENEATTR(inode), (int *)arg);
+			result = put_user(UDF_I_LENEATTR(inode), (int *)arg);
 			break;
 
 		case UDF_GETEABLOCK:
-			if ( (result = verify_area(VERIFY_WRITE, (char *)arg, UDF_I_LENEATTR(inode))) == 0) 
-				result = copy_to_user((char *)arg, ea, UDF_I_LENEATTR(inode));
-			break;
-
-		default:
+			result = copy_to_user((char *)arg, ea,
+				UDF_I_LENEATTR(inode)) ? -EFAULT : 0;
 			break;
 	}
 
diff -u --recursive --new-file v2.4.12/linux/fs/udf/ialloc.c linux/fs/udf/ialloc.c
--- v2.4.12/linux/fs/udf/ialloc.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/udf/ialloc.c	Thu Oct 11 08:59:24 2001
@@ -64,10 +64,9 @@
 		
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
 	}
-
 	unlock_super(sb);
 
-	udf_free_blocks(inode, UDF_I_LOCATION(inode), 0, 1);
+	udf_free_blocks(sb, NULL, UDF_I_LOCATION(inode), 0, 1);
 }
 
 struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
@@ -87,7 +86,7 @@
 	}
 	*err = -ENOSPC;
 
-	block = udf_new_block(dir, UDF_I_LOCATION(dir).partitionReferenceNum,
+	block = udf_new_block(dir->i_sb, NULL, UDF_I_LOCATION(dir).partitionReferenceNum,
 		start, err);
 	if (*err)
 	{
diff -u --recursive --new-file v2.4.12/linux/fs/udf/inode.c linux/fs/udf/inode.c
--- v2.4.12/linux/fs/udf/inode.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/udf/inode.c	Fri Oct 12 13:48:42 2001
@@ -37,10 +37,15 @@
 #include <linux/locks.h>
 #include <linux/mm.h>
 #include <linux/smp_lock.h>
+#include <linux/module.h>
 
 #include "udf_i.h"
 #include "udf_sb.h"
 
+MODULE_AUTHOR("Ben Fennema");
+MODULE_DESCRIPTION("Universal Disk Format Filesystem");
+MODULE_LICENSE("GPL");
+
 #define EXTENT_MERGE_SIZE 5
 
 static mode_t udf_convert_permissions(struct FileEntry *);
@@ -236,7 +241,7 @@
 	}
 
 	/* alloc block, and copy data to it */
-	*block = udf_new_block(inode,
+	*block = udf_new_block(inode->i_sb, inode,
 		UDF_I_LOCATION(inode).partitionReferenceNum,
 		UDF_I_LOCATION(inode).logicalBlockNum, err);
 
@@ -302,7 +307,6 @@
 	udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &sbh, 0);
 	/* UniqueID stuff */
 
-	inode->i_blocks = inode->i_sb->s_blocksize / 512;
 	mark_buffer_dirty(sbh);
 	udf_release_data(sbh);
 	mark_inode_dirty(inode);
@@ -402,14 +406,14 @@
 	Uint32 elen = 0;
 	lb_addr eloc, pbloc, cbloc, nbloc;
 	int c = 1;
-	int lbcount = 0, b_off = 0, offset = 0;
-	Uint32 newblocknum, newblock;
-	char etype;
+	Uint64 lbcount = 0, b_off = 0;
+	Uint32 newblocknum, newblock, offset = 0;
+	Sint8 etype;
 	int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum;
 	char lastblock = 0;
 
 	pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode);
-	b_off = block << inode->i_sb->s_blocksize_bits;
+	b_off = (Uint64)block << inode->i_sb->s_blocksize_bits;
 	pbloc = cbloc = nbloc = UDF_I_LOCATION(inode);
 
 	/* find the extent which contains the block we are looking for.
@@ -546,7 +550,7 @@
 				goal = UDF_I_LOCATION(inode).logicalBlockNum + 1;
 		}
 
-		if (!(newblocknum = udf_new_block(inode,
+		if (!(newblocknum = udf_new_block(inode->i_sb, inode,
 			UDF_I_LOCATION(inode).partitionReferenceNum, goal, err)))
 		{
 			udf_release_data(pbh);
@@ -588,7 +592,7 @@
 	UDF_I_NEXT_ALLOC_GOAL(inode) = newblocknum;
 	inode->i_ctime = CURRENT_TIME;
 	UDF_I_UCTIME(inode) = CURRENT_UTIME;
-	inode->i_blocks += inode->i_sb->s_blocksize / 512;
+
 	if (IS_SYNC(inode))
 		udf_sync_inode(inode);
 	else
@@ -622,8 +626,17 @@
 
 		if (offset)
 		{
-			laarr[curr].extLength = type |
-				(offset << inode->i_sb->s_blocksize_bits);
+			if ((type >> 30) == EXTENT_NOT_RECORDED_ALLOCATED)
+			{
+				udf_free_blocks(inode->i_sb, inode, laarr[curr].extLocation, 0, offset);
+				laarr[curr].extLength = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) |
+					(offset << inode->i_sb->s_blocksize_bits);
+				laarr[curr].extLocation.logicalBlockNum = 0;
+				laarr[curr].extLocation.partitionReferenceNum = 0;
+			}
+			else
+				laarr[curr].extLength = type |
+					(offset << inode->i_sb->s_blocksize_bits);
 			curr ++;
 			(*c) ++;
 			(*endnum) ++;
@@ -692,7 +705,7 @@
 		int next = laarr[start].extLocation.logicalBlockNum +
 			(((laarr[start].extLength & UDF_EXTENT_LENGTH_MASK) +
 			inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
-		int numalloc = udf_prealloc_blocks(inode,
+		int numalloc = udf_prealloc_blocks(inode->i_sb, inode,
 			laarr[start].extLocation.partitionReferenceNum,
 			next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ? length :
 				UDF_DEFAULT_PREALLOC_BLOCKS) - currlength);
@@ -825,9 +838,6 @@
 	int create, int * err)
 {
 	struct buffer_head * bh = NULL;
-	int prev_blocks;
-
-	prev_blocks = inode->i_blocks;
 
 	bh = udf_getblk(inode, block, create, err);
 	if (!bh)
@@ -1602,7 +1612,7 @@
 	return inode;
 }
 
-int udf_add_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
+Sint8 udf_add_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
 	lb_addr eloc, Uint32 elen, struct buffer_head **bh, int inc)
 {
 	int adsize;
@@ -1637,7 +1647,7 @@
 		int err, loffset;
 		lb_addr obloc = *bloc;
 
-		if (!(bloc->logicalBlockNum = udf_new_block(inode,
+		if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, inode,
 			obloc.partitionReferenceNum, obloc.logicalBlockNum, &err)))
 		{
 			return -1;
@@ -1739,7 +1749,7 @@
 	return ret;
 }
 
-int udf_write_aext(struct inode *inode, lb_addr bloc, int *extoffset,
+Sint8 udf_write_aext(struct inode *inode, lb_addr bloc, int *extoffset,
     lb_addr eloc, Uint32 elen, struct buffer_head *bh, int inc)
 {
 	int adsize;
@@ -1808,12 +1818,12 @@
 	return (elen >> 30);
 }
 
-int udf_next_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
+Sint8 udf_next_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
 	lb_addr *eloc, Uint32 *elen, struct buffer_head **bh, int inc)
 {
 	Uint16 tagIdent;
 	int pos, alen;
-	Uint8 etype;
+	Sint8 etype;
 
 	if (!(*bh))
 	{
@@ -1932,11 +1942,11 @@
 	return -1;
 }
 
-int udf_current_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
+Sint8 udf_current_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
 	lb_addr *eloc, Uint32 *elen, struct buffer_head **bh, int inc)
 {
 	int pos, alen;
-	Uint8 etype;
+	Sint8 etype;
 
 	if (!(*bh))
 	{
@@ -2013,12 +2023,12 @@
 	return -1;
 }
 
-int udf_insert_aext(struct inode *inode, lb_addr bloc, int extoffset,
+Sint8 udf_insert_aext(struct inode *inode, lb_addr bloc, int extoffset,
 	lb_addr neloc, Uint32 nelen, struct buffer_head *bh)
 {
 	lb_addr oeloc;
 	Uint32 oelen;
-	int type;
+	Sint8 etype;
 
 	if (!bh)
 	{
@@ -2034,25 +2044,25 @@
 	else
 		atomic_inc(&bh->b_count);
 
-	while ((type = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1)
+	while ((etype = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1)
 	{
 		udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
 
 		neloc = oeloc;
-		nelen = (type << 30) | oelen;
+		nelen = (etype << 30) | oelen;
 	}
 	udf_add_aext(inode, &bloc, &extoffset, neloc, nelen, &bh, 1);
 	udf_release_data(bh);
 	return (nelen >> 30);
 }
 
-int udf_delete_aext(struct inode *inode, lb_addr nbloc, int nextoffset,
+Sint8 udf_delete_aext(struct inode *inode, lb_addr nbloc, int nextoffset,
 	lb_addr eloc, Uint32 elen, struct buffer_head *nbh)
 {
 	struct buffer_head *obh;
 	lb_addr obloc;
 	int oextoffset, adsize;
-	char type;
+	Sint8 etype;
 	struct AllocExtDesc *aed;
 
 	if (!(nbh))
@@ -2084,9 +2094,9 @@
 	if (udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1) == -1)
 		return -1;
 
-	while ((type = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
+	while ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
 	{
-		udf_write_aext(inode, obloc, &oextoffset, eloc, (type << 30) | elen, obh, 1);
+		udf_write_aext(inode, obloc, &oextoffset, eloc, (etype << 30) | elen, obh, 1);
 		if (memcmp(&nbloc, &obloc, sizeof(lb_addr)))
 		{
 			obloc = nbloc;
@@ -2101,7 +2111,7 @@
 
 	if (memcmp(&nbloc, &obloc, sizeof(lb_addr)))
 	{
-		udf_free_blocks(inode, nbloc, 0, 1);
+		udf_free_blocks(inode->i_sb, inode, nbloc, 0, 1);
 		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
 		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
 		if (!memcmp(&UDF_I_LOCATION(inode), &obloc, sizeof(lb_addr)))
@@ -2147,11 +2157,11 @@
 	return (elen >> 30);
 }
 
-int inode_bmap(struct inode *inode, int block, lb_addr *bloc, Uint32 *extoffset,
+Sint8 inode_bmap(struct inode *inode, int block, lb_addr *bloc, Uint32 *extoffset,
 	lb_addr *eloc, Uint32 *elen, Uint32 *offset, struct buffer_head **bh)
 {
-	Uint64 lbcount = 0, bcount = block << inode->i_sb->s_blocksize_bits;
-	char etype;
+	Uint64 lbcount = 0, bcount = (Uint64)block << inode->i_sb->s_blocksize_bits;
+	Sint8 etype;
 
 	if (block < 0)
 	{
diff -u --recursive --new-file v2.4.12/linux/fs/udf/lowlevel.c linux/fs/udf/lowlevel.c
--- v2.4.12/linux/fs/udf/lowlevel.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/udf/lowlevel.c	Mon Oct 15 13:27:41 2001
@@ -67,7 +67,7 @@
 	return vol_desc_start;
 }
 
-unsigned int
+unsigned long
 udf_get_last_block(struct super_block *sb)
 {
 	struct block_device *bdev = sb->s_bdev;
diff -u --recursive --new-file v2.4.12/linux/fs/udf/namei.c linux/fs/udf/namei.c
--- v2.4.12/linux/fs/udf/namei.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/udf/namei.c	Thu Oct 11 08:59:24 2001
@@ -835,7 +835,7 @@
 static int udf_rmdir(struct inode * dir, struct dentry * dentry)
 {
 	int retval;
-	struct inode * inode;
+	struct inode * inode = dentry->d_inode;
 	struct udf_fileident_bh fibh;
 	struct FileIdentDesc *fi, cfi;
 
@@ -844,9 +844,6 @@
 	if (!fi)
 		goto out;
 
-	inode = dentry->d_inode;
-	DQUOT_INIT(inode);
-
 	retval = -EIO;
 	if (udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0) != inode->i_ino)
 		goto end_rmdir;
@@ -881,7 +878,7 @@
 static int udf_unlink(struct inode * dir, struct dentry * dentry)
 {
 	int retval;
-	struct inode * inode;
+	struct inode * inode = dentry->d_inode;
 	struct udf_fileident_bh fibh;
 	struct FileIdentDesc *fi;
 	struct FileIdentDesc cfi;
@@ -891,9 +888,6 @@
 	if (!fi)
 		goto out;
 
-	inode = dentry->d_inode;
-	DQUOT_INIT(inode);
-
 	retval = -EIO;
 
 	if (udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0) !=
@@ -954,7 +948,7 @@
 		lb_addr bloc, eloc;
 		Uint32 elen, extoffset;
 
-		block = udf_new_block(inode,
+		block = udf_new_block(inode->i_sb, inode,
 			UDF_I_LOCATION(inode).partitionReferenceNum,
 			UDF_I_LOCATION(inode).logicalBlockNum, &err);
 		if (!block)
@@ -968,7 +962,6 @@
 		udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 0);
 		udf_release_data(bh);
 
-		inode->i_blocks = inode->i_sb->s_blocksize / 512;
 		block = udf_get_pblock(inode->i_sb, block,
 			UDF_I_LOCATION(inode).partitionReferenceNum, 0);
 		bh = udf_tread(inode->i_sb, block, inode->i_sb->s_blocksize);
@@ -1150,13 +1143,13 @@
 static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
 	struct inode * new_dir, struct dentry * new_dentry)
 {
-	struct inode * old_inode, * new_inode;
+	struct inode * old_inode = old_dentry->d_inode;
+	struct inode * new_inode = new_dentry->d_inode;
 	struct udf_fileident_bh ofibh, nfibh;
 	struct FileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi;
 	struct buffer_head *dir_bh = NULL;
 	int retval = -ENOENT;
 
-	old_inode = old_dentry->d_inode;
 	if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi)))
 	{
 		if (ofibh.sbh != ofibh.ebh)
@@ -1169,7 +1162,6 @@
 		goto end_rename;
 	}
 
-	new_inode = new_dentry->d_inode;
 	nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
 	if (nfi)
 	{
@@ -1179,10 +1171,6 @@
 				udf_release_data(nfibh.ebh);
 			udf_release_data(nfibh.sbh);
 			nfi = NULL;
-		}
-		else
-		{
-			DQUOT_INIT(new_inode);
 		}
 	}
 	if (S_ISDIR(old_inode->i_mode))
diff -u --recursive --new-file v2.4.12/linux/fs/udf/super.c linux/fs/udf/super.c
--- v2.4.12/linux/fs/udf/super.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/udf/super.c	Thu Oct 11 08:59:24 2001
@@ -85,7 +85,7 @@
 static int udf_load_partition(struct super_block *, lb_addr *);
 static int udf_load_logicalvol(struct super_block *, struct buffer_head *, lb_addr *);
 static void udf_load_logicalvolint(struct super_block *, extent_ad);
-static int udf_find_anchor(struct super_block *, int, int);
+static void udf_find_anchor(struct super_block *);
 static int udf_find_fileset(struct super_block *, lb_addr *, lb_addr *);
 static void udf_load_pvoldesc(struct super_block *, struct buffer_head *);
 static void udf_load_fileset(struct super_block *, struct buffer_head *, lb_addr *);
@@ -164,7 +164,7 @@
  *	noadinicb	Don't embed data in the inode
  *	shortad		Use short ad's
  *	longad		Use long ad's (default)
- *	strict		Set strict conformance
+ *	nostrict	Unset strict conformance
  *	iocharset=	Set the NLS character set
  *
  *	The remaining are for debugging and disaster recovery:
@@ -208,8 +208,8 @@
 	uopt->blocksize = 2048;
 	uopt->partition = 0xFFFF;
 	uopt->session = 0xFFFFFFFF;
-	uopt->lastblock = 0xFFFFFFFF;
-	uopt->anchor = 0xFFFFFFFF;
+	uopt->lastblock = 0;
+	uopt->anchor = 0;
 	uopt->volume = 0xFFFFFFFF;
 	uopt->rootdir = 0xFFFFFFFF;
 	uopt->fileset = 0xFFFFFFFF;
@@ -244,8 +244,8 @@
 			uopt->gid = simple_strtoul(val, NULL, 0);
 		else if (!strcmp(opt, "umask") && val)
 			uopt->umask = simple_strtoul(val, NULL, 0);
-		else if (!strcmp(opt, "strict") && !val)
-			uopt->flags |= (1 << UDF_FLAG_STRICT);
+		else if (!strcmp(opt, "nostrict") && !val)
+			uopt->flags &= ~(1 << UDF_FLAG_STRICT);
 		else if (!strcmp(opt, "uid") && val)
 			uopt->uid = simple_strtoul(val, NULL, 0);
 		else if (!strcmp(opt, "session") && val)
@@ -496,72 +496,36 @@
  *	July 1, 1997 - Andrew E. Mileski
  *	Written, tested, and released.
  */
-static int
-udf_find_anchor(struct super_block *sb, int useranchor, int lastblock)
+static void
+udf_find_anchor(struct super_block *sb)
 {
-	int varlastblock = udf_variable_to_fixed(lastblock);
-	int last[] =  { lastblock, lastblock - 2,
-			lastblock - 150, lastblock - 152,
-			varlastblock, varlastblock - 2,
-			varlastblock - 150, varlastblock - 152 };
+	int lastblock = UDF_SB_LASTBLOCK(sb);
 	struct buffer_head *bh = NULL;
 	Uint16 ident;
 	Uint32 location;
 	int i;
 
-	UDF_SB_ANCHOR(sb)[0] = 0;
-	UDF_SB_ANCHOR(sb)[1] = 0;
-	UDF_SB_ANCHOR(sb)[2] = 0;
-	UDF_SB_ANCHOR(sb)[3] = 256 + UDF_SB_SESSION(sb);
+	if (lastblock)
+	{
+		int varlastblock = udf_variable_to_fixed(lastblock);
+		int last[] =  { lastblock, lastblock - 2,
+				lastblock - 150, lastblock - 152,
+				varlastblock, varlastblock - 2,
+				varlastblock - 150, varlastblock - 152 };
 
-	lastblock = 0;
+		lastblock = 0;
 
-	/* Search for an anchor volume descriptor pointer */
+		/* Search for an anchor volume descriptor pointer */
 
-	/*  according to spec, anchor is in either:
-	 *     block 256
-	 *     lastblock-256
-	 *     lastblock
-	 *  however, if the disc isn't closed, it could be 512 */
+		/*  according to spec, anchor is in either:
+		 *     block 256
+		 *     lastblock-256
+		 *     lastblock
+		 *  however, if the disc isn't closed, it could be 512 */
 
-	for (i=0; (!lastblock && i<sizeof(last)/sizeof(int)); i++)
-	{
-		if (last[i] < 0 || !(bh = bread(sb->s_dev, last[i], sb->s_blocksize)))
-		{
-			ident = location = 0;
-		}
-		else
+		for (i=0; (!lastblock && i<sizeof(last)/sizeof(int)); i++)
 		{
-			ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
-			location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
-			udf_release_data(bh);
-		}
-
-		if (ident == TID_ANCHOR_VOL_DESC_PTR)
-		{
-			if (location == last[i] - UDF_SB_SESSION(sb))
-			{
-				lastblock = UDF_SB_ANCHOR(sb)[0] = last[i];
-				UDF_SB_ANCHOR(sb)[1] = last[i] - 256;
-			}
-			else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb))
-			{
-				UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
-				lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]);
-				UDF_SB_ANCHOR(sb)[1] = lastblock - 256;
-			}
-			else
-				udf_debug("Anchor found at block %d, location mismatch %d.\n",
-					last[i], location);
-		}
-		else if (ident == TID_FILE_ENTRY || ident == TID_EXTENDED_FILE_ENTRY)
-		{
-			lastblock = last[i];
-			UDF_SB_ANCHOR(sb)[2] = 512 + UDF_SB_SESSION(sb);
-		}
-		else
-		{
-			if (!(bh = bread(sb->s_dev, last[i] - 256, sb->s_blocksize)))
+			if (last[i] < 0 || !(bh = bread(sb->s_dev, last[i], sb->s_blocksize)))
 			{
 				ident = location = 0;
 			}
@@ -571,17 +535,32 @@
 				location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
 				udf_release_data(bh);
 			}
-
-			if (ident == TID_ANCHOR_VOL_DESC_PTR &&
-				location == last[i] - 256 - UDF_SB_SESSION(sb))
+	
+			if (ident == TID_ANCHOR_VOL_DESC_PTR)
+			{
+				if (location == last[i] - UDF_SB_SESSION(sb))
+				{
+					lastblock = UDF_SB_ANCHOR(sb)[0] = last[i];
+					UDF_SB_ANCHOR(sb)[1] = last[i] - 256;
+				}
+				else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb))
+				{
+					UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+					lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]);
+					UDF_SB_ANCHOR(sb)[1] = lastblock - 256;
+				}
+				else
+					udf_debug("Anchor found at block %d, location mismatch %d.\n",
+						last[i], location);
+			}
+			else if (ident == TID_FILE_ENTRY || ident == TID_EXTENDED_FILE_ENTRY)
 			{
 				lastblock = last[i];
-				UDF_SB_ANCHOR(sb)[1] = last[i] - 256;
+				UDF_SB_ANCHOR(sb)[3] = 512 + UDF_SB_SESSION(sb);
 			}
 			else
 			{
-				if (!(bh = bread(sb->s_dev, last[i] - 312 - UDF_SB_SESSION(sb),
-					sb->s_blocksize)))
+				if (last[i] < 256 || !(bh = bread(sb->s_dev, last[i] - 256, sb->s_blocksize)))
 				{
 					ident = location = 0;
 				}
@@ -591,13 +570,34 @@
 					location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
 					udf_release_data(bh);
 				}
-
+	
 				if (ident == TID_ANCHOR_VOL_DESC_PTR &&
-					location == udf_variable_to_fixed(last[i]) - 256)
+					location == last[i] - 256 - UDF_SB_SESSION(sb))
 				{
-					UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
-					lastblock = udf_variable_to_fixed(last[i]);
-					UDF_SB_ANCHOR(sb)[1] = lastblock - 256;
+					lastblock = last[i];
+					UDF_SB_ANCHOR(sb)[1] = last[i] - 256;
+				}
+				else
+				{
+					if (last[i] < 312 + UDF_SB_SESSION(sb) || !(bh = bread(sb->s_dev, last[i] - 312 - UDF_SB_SESSION(sb),
+						sb->s_blocksize)))
+					{
+						ident = location = 0;
+					}
+					else
+					{
+						ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+						location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
+						udf_release_data(bh);
+					}
+	
+					if (ident == TID_ANCHOR_VOL_DESC_PTR &&
+						location == udf_variable_to_fixed(last[i]) - 256)
+					{
+						UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+						lastblock = udf_variable_to_fixed(last[i]);
+						UDF_SB_ANCHOR(sb)[1] = lastblock - 256;
+					}
 				}
 			}
 		}
@@ -636,15 +636,9 @@
 				}
 			}
 		}
-		else if (useranchor != 0xFFFFFFFF)
-		{
-			UDF_SB_ANCHOR(sb)[i] = useranchor;
-			useranchor = 0xFFFFFFFF;
-			i --;
-		}
 	}
 
-	return lastblock;
+	UDF_SB_LASTBLOCK(sb) = lastblock;
 }
 
 static int 
@@ -985,8 +979,10 @@
 	struct buffer_head *bh = NULL;
 	Uint16 ident;
 
-	while ((bh = udf_read_tagged(sb, loc.extLocation, loc.extLocation, &ident)) &&
-		ident == TID_LOGICAL_VOL_INTEGRITY_DESC && loc.extLength > 0)
+	while (loc.extLength > 0 &&
+		(bh = udf_read_tagged(sb, loc.extLocation,
+			loc.extLocation, &ident)) &&
+		ident == TID_LOGICAL_VOL_INTEGRITY_DESC)
 	{
 		UDF_SB_LVIDBH(sb) = bh;
 		
@@ -1152,6 +1148,8 @@
 	else if ((block = udf_vrs(sb, silent)) == -1)
 	{
 		udf_debug("Failed to read byte 32768. Assuming open disc. Skipping validity check\n");
+		if (!UDF_SB_LASTBLOCK(sb))
+			UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
 		return 0;
 	}
 	else 
@@ -1220,6 +1218,12 @@
 
 				if (!UDF_SB_LASTBLOCK(sb))
 				{
+					UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
+					udf_find_anchor(sb);
+				}
+
+				if (!UDF_SB_LASTBLOCK(sb))
+				{
 					udf_debug("Unable to determine Lastblock (For Virtual Partition)\n");
 					return 1;
 				}
@@ -1355,7 +1359,7 @@
 	struct udf_options uopt;
 	lb_addr rootdir, fileset;
 
-	uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB);
+	uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT);
 	uopt.uid = -1;
 	uopt.gid = -1;
 	uopt.umask = 0;
@@ -1409,14 +1413,10 @@
 
 	udf_debug("Multi-session=%d\n", UDF_SB_SESSION(sb));
 
-	if ( uopt.lastblock == 0xFFFFFFFF )
-		UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
-	else
-		UDF_SB_LASTBLOCK(sb) = uopt.lastblock;
-
-	UDF_SB_LASTBLOCK(sb) = udf_find_anchor(sb, uopt.anchor, UDF_SB_LASTBLOCK(sb));
-
-	udf_debug("Lastblock=%d\n", UDF_SB_LASTBLOCK(sb));
+	UDF_SB_LASTBLOCK(sb) = uopt.lastblock;
+	UDF_SB_ANCHOR(sb)[0] = UDF_SB_ANCHOR(sb)[1] = 0;
+	UDF_SB_ANCHOR(sb)[2] = uopt.anchor;
+	UDF_SB_ANCHOR(sb)[3] = UDF_SB_SESSION(sb) + 256;
 
 	if (udf_check_valid(sb, uopt.novrs, silent)) /* read volume recognition sequences */
 	{
@@ -1424,6 +1424,8 @@
  		goto error_out;
 	}
 
+	udf_find_anchor(sb);
+
 	/* Fill in the rest of the superblock */
 	sb->s_op = &udf_sb_ops;
 	sb->dq_op = NULL;
@@ -1436,6 +1438,8 @@
 		goto error_out;
 	}
 
+	udf_debug("Lastblock=%d\n", UDF_SB_LASTBLOCK(sb));
+
 	if ( UDF_SB_LVIDBH(sb) )
 	{
 		Uint16 minUDFReadRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev);
@@ -1744,7 +1748,7 @@
 	unsigned int accum = 0;
 	Uint32 extoffset, elen;
 	lb_addr bloc, eloc;
-	char etype;
+	Sint8 etype;
 	struct buffer_head *bh = NULL;
 
 	bloc = UDF_I_LOCATION(table);
@@ -1763,6 +1767,20 @@
 {
 	unsigned int accum = 0;
 
+	if (UDF_SB_LVIDBH(sb))
+	{
+		if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb))
+		{
+			accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]);
+
+			if (accum == 0xFFFFFFFF)
+				accum = 0;
+		}
+	}
+
+	if (accum)
+		return accum;
+
 	if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
 	{
 		accum += udf_count_free_bitmap(sb,
@@ -1786,18 +1804,6 @@
 		accum += udf_count_free_table(sb,
 			UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
 	}
-	if (accum)
-		return accum;
 
-	if (UDF_SB_LVIDBH(sb))
-	{
-		if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb))
-		{
-			accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]);
-
-			if (accum == 0xFFFFFFFF)
-				accum = 0;
-		}
-	}
 	return accum;
 }
diff -u --recursive --new-file v2.4.12/linux/fs/udf/truncate.c linux/fs/udf/truncate.c
--- v2.4.12/linux/fs/udf/truncate.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/udf/truncate.c	Thu Oct 11 08:59:24 2001
@@ -33,10 +33,9 @@
 #include "udf_sb.h"
 
 static void extent_trunc(struct inode * inode, lb_addr bloc, int extoffset,
-	lb_addr eloc, Uint8 etype, Uint32 elen, struct buffer_head *bh, Uint32 nelen)
+	lb_addr eloc, Sint8 etype, Uint32 elen, struct buffer_head *bh, Uint32 nelen)
 {
 	lb_addr neloc = { 0, 0 };
-	int blocks = inode->i_sb->s_blocksize / 512;
 	int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
 	int first_block = (nelen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
 
@@ -52,12 +51,10 @@
 		if (last_block - first_block > 0)
 		{
 			if (etype == EXTENT_RECORDED_ALLOCATED)
-			{
-				inode->i_blocks -= (blocks * (last_block - first_block));
 				mark_inode_dirty(inode);
-			}
+
 			if (etype != EXTENT_NOT_RECORDED_NOT_ALLOCATED)
-				udf_free_blocks(inode, eloc, first_block, last_block - first_block);
+				udf_free_blocks(inode->i_sb, inode, eloc, first_block, last_block - first_block);
 		}
 	}
 }
@@ -66,7 +63,7 @@
 {
 	lb_addr bloc, eloc, neloc = { 0, 0 };
 	Uint32 extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc;
-	int etype;
+	Sint8 etype;
 	int first_block = inode->i_size >> inode->i_sb->s_blocksize_bits;
 	struct buffer_head *bh = NULL;
 	int adsize;
@@ -108,7 +105,7 @@
 						memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode));
 					else
 						memset(bh->b_data, 0x00, sizeof(struct AllocExtDesc));
-					udf_free_blocks(inode, bloc, 0, lelen);
+					udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
 				}
 				else
 				{
@@ -153,7 +150,7 @@
 				memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode));
 			else
 				memset(bh->b_data, 0x00, sizeof(struct AllocExtDesc));
-			udf_free_blocks(inode, bloc, 0, lelen);
+			udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
 		}
 		else
 		{
diff -u --recursive --new-file v2.4.12/linux/fs/udf/udfdecl.h linux/fs/udf/udfdecl.h
--- v2.4.12/linux/fs/udf/udfdecl.h	Tue Oct  9 17:06:53 2001
+++ linux/fs/udf/udfdecl.h	Mon Oct 15 18:49:21 2001
@@ -11,7 +11,6 @@
 
 #include <linux/config.h>
 #include <linux/types.h>
-
 #include <linux/fs.h>
 
 #if !defined(CONFIG_UDF_FS) && !defined(CONFIG_UDF_FS_MODULE)
@@ -129,13 +128,13 @@
 extern void udf_delete_inode(struct inode *);
 extern void udf_write_inode(struct inode *, int);
 extern long udf_block_map(struct inode *, long);
-extern int inode_bmap(struct inode *, int, lb_addr *, Uint32 *, lb_addr *, Uint32 *, Uint32 *, struct buffer_head **);
-extern int udf_add_aext(struct inode *, lb_addr *, int *, lb_addr, Uint32, struct buffer_head **, int);
-extern int udf_write_aext(struct inode *, lb_addr, int *, lb_addr, Uint32, struct buffer_head *, int);
-extern int udf_insert_aext(struct inode *, lb_addr, int, lb_addr, Uint32, struct buffer_head *);
-extern int udf_delete_aext(struct inode *, lb_addr, int, lb_addr, Uint32, struct buffer_head *);
-extern int udf_next_aext(struct inode *, lb_addr *, int *, lb_addr *, Uint32 *, struct buffer_head **, int);
-extern int udf_current_aext(struct inode *, lb_addr *, int *, lb_addr *, Uint32 *, struct buffer_head **, int);
+extern Sint8 inode_bmap(struct inode *, int, lb_addr *, Uint32 *, lb_addr *, Uint32 *, Uint32 *, struct buffer_head **);
+extern Sint8 udf_add_aext(struct inode *, lb_addr *, int *, lb_addr, Uint32, struct buffer_head **, int);
+extern Sint8 udf_write_aext(struct inode *, lb_addr, int *, lb_addr, Uint32, struct buffer_head *, int);
+extern Sint8 udf_insert_aext(struct inode *, lb_addr, int, lb_addr, Uint32, struct buffer_head *);
+extern Sint8 udf_delete_aext(struct inode *, lb_addr, int, lb_addr, Uint32, struct buffer_head *);
+extern Sint8 udf_next_aext(struct inode *, lb_addr *, int *, lb_addr *, Uint32 *, struct buffer_head **, int);
+extern Sint8 udf_current_aext(struct inode *, lb_addr *, int *, lb_addr *, Uint32 *, struct buffer_head **, int);
 extern void udf_discard_prealloc(struct inode *);
 
 /* misc.c */
@@ -151,7 +150,7 @@
 
 /* lowlevel.c */
 extern unsigned int udf_get_last_session(struct super_block *);
-extern unsigned int udf_get_last_block(struct super_block *);
+extern unsigned long udf_get_last_block(struct super_block *);
 
 /* partition.c */
 extern Uint32 udf_get_pblock(struct super_block *, Uint32, Uint16, Uint32);
@@ -171,9 +170,9 @@
 extern void udf_truncate_extents(struct inode *);
 
 /* balloc.c */
-extern void udf_free_blocks(struct inode *, lb_addr, Uint32, Uint32);
-extern int udf_prealloc_blocks(struct inode *, Uint16, Uint32, Uint32);
-extern int udf_new_block(struct inode *, Uint16, Uint32, int *);
+extern void udf_free_blocks(struct super_block *, struct inode *, lb_addr, Uint32, Uint32);
+extern int udf_prealloc_blocks(struct super_block *, struct inode *, Uint16, Uint32, Uint32);
+extern int udf_new_block(struct super_block *, struct inode *, Uint16, Uint32, int *);
 
 /* fsync.c */
 extern int udf_fsync_file(struct file *, struct dentry *, int);
diff -u --recursive --new-file v2.4.12/linux/fs/ufs/dir.c linux/fs/ufs/dir.c
--- v2.4.12/linux/fs/ufs/dir.c	Fri Aug 11 14:29:02 2000
+++ linux/fs/ufs/dir.c	Sat Oct 20 19:14:42 2001
@@ -13,6 +13,8 @@
  * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
  */
 
+#include <linux/sched.h>
+#include <linux/locks.h>
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
 
@@ -28,6 +30,21 @@
 #endif
 
 /*
+ * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure.
+ *
+ * len <= UFS_MAXNAMLEN and de != NULL are guaranteed by caller.
+ */
+static inline int ufs_match (int len, const char * const name,
+	struct ufs_dir_entry * de, unsigned flags, unsigned swab)
+{
+	if (len != ufs_get_de_namlen(de))
+		return 0;
+	if (!de->d_ino)
+		return 0;
+	return !memcmp(name, de->d_name, len);
+}
+
+/*
  * This is blatantly stolen from ext2fs
  */
 static int
@@ -145,6 +162,130 @@
 	return 0;
 }
 
+/*
+ * define how far ahead to read directories while searching them.
+ */
+#define NAMEI_RA_CHUNKS  2
+#define NAMEI_RA_BLOCKS  4
+#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
+
+/*
+ *	ufs_find_entry()
+ *
+ * finds an entry in the specified directory with the wanted name. It
+ * returns the cache buffer in which the entry was found, and the entry
+ * itself (as a parameter - res_bh). It does NOT read the inode of the
+ * entry - you'll have to do that yourself if you want to.
+ */
+struct ufs_dir_entry * ufs_find_entry (struct dentry *dentry,
+	struct buffer_head ** res_bh)
+{
+	struct super_block * sb;
+	struct buffer_head * bh_use[NAMEI_RA_SIZE];
+	struct buffer_head * bh_read[NAMEI_RA_SIZE];
+	unsigned long offset;
+	int block, toread, i, err;
+	unsigned flags, swab;
+	struct inode *dir = dentry->d_parent->d_inode;
+	const char *name = dentry->d_name.name;
+	int namelen = dentry->d_name.len;
+
+	UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen))
+	
+	*res_bh = NULL;
+	
+	sb = dir->i_sb;
+	flags = sb->u.ufs_sb.s_flags;
+	swab = sb->u.ufs_sb.s_swab;
+	
+	if (namelen > UFS_MAXNAMLEN)
+		return NULL;
+
+	memset (bh_use, 0, sizeof (bh_use));
+	toread = 0;
+	for (block = 0; block < NAMEI_RA_SIZE; ++block) {
+		struct buffer_head * bh;
+
+		if ((block << sb->s_blocksize_bits) >= dir->i_size)
+			break;
+		bh = ufs_getfrag (dir, block, 0, &err);
+		bh_use[block] = bh;
+		if (bh && !buffer_uptodate(bh))
+			bh_read[toread++] = bh;
+	}
+
+	for (block = 0, offset = 0; offset < dir->i_size; block++) {
+		struct buffer_head * bh;
+		struct ufs_dir_entry * de;
+		char * dlimit;
+
+		if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
+			ll_rw_block (READ, toread, bh_read);
+			toread = 0;
+		}
+		bh = bh_use[block % NAMEI_RA_SIZE];
+		if (!bh) {
+			ufs_error (sb, "ufs_find_entry", 
+				"directory #%lu contains a hole at offset %lu",
+				dir->i_ino, offset);
+			offset += sb->s_blocksize;
+			continue;
+		}
+		wait_on_buffer (bh);
+		if (!buffer_uptodate(bh)) {
+			/*
+			 * read error: all bets are off
+			 */
+			break;
+		}
+
+		de = (struct ufs_dir_entry *) bh->b_data;
+		dlimit = bh->b_data + sb->s_blocksize;
+		while ((char *) de < dlimit && offset < dir->i_size) {
+			/* this code is executed quadratically often */
+			/* do minimal checking by hand */
+			int de_len;
+
+			if ((char *) de + namelen <= dlimit &&
+			    ufs_match (namelen, name, de, flags, swab)) {
+				/* found a match -
+				just to be sure, do a full check */
+				if (!ufs_check_dir_entry("ufs_find_entry",
+				    dir, de, bh, offset))
+					goto failed;
+				for (i = 0; i < NAMEI_RA_SIZE; ++i) {
+					if (bh_use[i] != bh)
+						brelse (bh_use[i]);
+				}
+				*res_bh = bh;
+				return de;
+			}
+                        /* prevent looping on a bad block */
+			de_len = SWAB16(de->d_reclen);
+			if (de_len <= 0)
+				goto failed;
+			offset += de_len;
+			de = (struct ufs_dir_entry *) ((char *) de + de_len);
+		}
+
+		brelse (bh);
+		if (((block + NAMEI_RA_SIZE) << sb->s_blocksize_bits ) >=
+		    dir->i_size)
+			bh = NULL;
+		else
+			bh = ufs_getfrag (dir, block + NAMEI_RA_SIZE, 0, &err);
+		bh_use[block % NAMEI_RA_SIZE] = bh;
+		if (bh && !buffer_uptodate(bh))
+			bh_read[toread++] = bh;
+	}
+
+failed:
+	for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]);
+	UFSD(("EXIT\n"))
+	return NULL;
+}
+
 int ufs_check_dir_entry (const char * function,	struct inode * dir,
 	struct ufs_dir_entry * de, struct buffer_head * bh, 
 	unsigned long offset)
@@ -178,6 +319,312 @@
 			    SWAB16(de->d_reclen), ufs_get_de_namlen(de));
 	
 	return (error_msg == NULL ? 1 : 0);
+}
+
+struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct buffer_head **p)
+{
+	int err;
+	struct buffer_head *bh = ufs_bread (dir, 0, 0, &err);
+	struct ufs_dir_entry *res = NULL;
+
+	if (bh) {
+		unsigned swab = dir->i_sb->u.ufs_sb.s_swab;
+
+		res = (struct ufs_dir_entry *) bh->b_data;
+		res = (struct ufs_dir_entry *)((char *)res +
+			SWAB16(res->d_reclen));
+	}
+	*p = bh;
+	return res;
+}
+ino_t ufs_inode_by_name(struct inode * dir, struct dentry *dentry)
+{
+	unsigned swab = dir->i_sb->u.ufs_sb.s_swab;
+	ino_t res = 0;
+	struct ufs_dir_entry * de;
+	struct buffer_head *bh;
+
+	de = ufs_find_entry (dentry, &bh);
+	if (de) {
+		res = SWAB32(de->d_ino);
+		brelse(bh);
+	}
+	return res;
+}
+
+void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
+		struct buffer_head *bh, struct inode *inode)
+{
+	unsigned swab = dir->i_sb->u.ufs_sb.s_swab;
+	dir->i_version = ++event;
+	de->d_ino = SWAB32(inode->i_ino);
+	mark_buffer_dirty(bh);
+	if (IS_SYNC(dir)) {
+		ll_rw_block (WRITE, 1, &bh);
+		wait_on_buffer(bh);
+	}
+	brelse (bh);
+}
+
+/*
+ *	ufs_add_entry()
+ *
+ * adds a file entry to the specified directory, using the same
+ * semantics as ufs_find_entry(). It returns NULL if it failed.
+ */
+int ufs_add_link(struct dentry *dentry, struct inode *inode)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	unsigned long offset;
+	unsigned fragoff;
+	unsigned short rec_len;
+	struct buffer_head * bh;
+	struct ufs_dir_entry * de, * de1;
+	unsigned flags, swab;
+	struct inode *dir = dentry->d_parent->d_inode;
+	const char *name = dentry->d_name.name;
+	int namelen = dentry->d_name.len;
+	int err;
+
+	UFSD(("ENTER, name %s, namelen %u\n", name, namelen))
+	
+	sb = dir->i_sb;
+	flags = sb->u.ufs_sb.s_flags;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+
+	if (!namelen)
+		return -EINVAL;
+	bh = ufs_bread (dir, 0, 0, &err);
+	if (!bh)
+		return err;
+	rec_len = UFS_DIR_REC_LEN(namelen);
+	offset = 0;
+	de = (struct ufs_dir_entry *) bh->b_data;
+	while (1) {
+		if ((char *)de >= UFS_SECTOR_SIZE + bh->b_data) {
+			fragoff = offset & ~uspi->s_fmask;
+			if (fragoff != 0 && fragoff != UFS_SECTOR_SIZE)
+				ufs_error (sb, "ufs_add_entry", "internal error"
+					" fragoff %u", fragoff);
+			if (!fragoff) {
+				brelse (bh);
+				bh = ufs_bread (dir, offset >> sb->s_blocksize_bits, 1, &err);
+				if (!bh)
+					return err;
+			}
+			if (dir->i_size <= offset) {
+				if (dir->i_size == 0) {
+					brelse(bh);
+					return -ENOENT;
+				}
+				de = (struct ufs_dir_entry *) (bh->b_data + fragoff);
+				de->d_ino = SWAB32(0);
+				de->d_reclen = SWAB16(UFS_SECTOR_SIZE);
+				ufs_set_de_namlen(de,0);
+				dir->i_size = offset + UFS_SECTOR_SIZE;
+				mark_inode_dirty(dir);
+			} else {
+				de = (struct ufs_dir_entry *) bh->b_data;
+			}
+		}
+		if (!ufs_check_dir_entry ("ufs_add_entry", dir, de, bh, offset)) {
+			brelse (bh);
+			return -ENOENT;
+		}
+		if (ufs_match (namelen, name, de, flags, swab)) {
+			brelse (bh);
+			return -EEXIST;
+		}
+		if (SWAB32(de->d_ino) == 0 && SWAB16(de->d_reclen) >= rec_len)
+			break;
+			
+		if (SWAB16(de->d_reclen) >= UFS_DIR_REC_LEN(ufs_get_de_namlen(de)) + rec_len)
+			break;
+		offset += SWAB16(de->d_reclen);
+		de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
+	}
+
+	if (SWAB32(de->d_ino)) {
+		de1 = (struct ufs_dir_entry *) ((char *) de +
+			UFS_DIR_REC_LEN(ufs_get_de_namlen(de)));
+		de1->d_reclen = SWAB16(SWAB16(de->d_reclen) -
+			UFS_DIR_REC_LEN(ufs_get_de_namlen(de)));
+		de->d_reclen = SWAB16(UFS_DIR_REC_LEN(ufs_get_de_namlen(de)));
+		de = de1;
+	}
+	de->d_ino = SWAB32(0);
+	ufs_set_de_namlen(de, namelen);
+	memcpy (de->d_name, name, namelen + 1);
+	de->d_ino = SWAB32(inode->i_ino);
+	ufs_set_de_type (de, inode->i_mode);
+	mark_buffer_dirty(bh);
+	if (IS_SYNC(dir)) {
+		ll_rw_block (WRITE, 1, &bh);
+		wait_on_buffer (bh);
+	}
+	brelse (bh);
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+	dir->i_version = ++event;
+	mark_inode_dirty(dir);
+
+	UFSD(("EXIT\n"))
+	return 0;
+}
+
+/*
+ * ufs_delete_entry deletes a directory entry by merging it with the
+ * previous entry.
+ */
+int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir,
+	struct buffer_head * bh )
+	
+{
+	struct super_block * sb;
+	struct ufs_dir_entry * de, * pde;
+	unsigned i;
+	unsigned flags, swab;
+	
+	UFSD(("ENTER\n"))
+
+	sb = inode->i_sb;
+	flags = sb->u.ufs_sb.s_flags;
+	swab = sb->u.ufs_sb.s_swab;
+	i = 0;
+	pde = NULL;
+	de = (struct ufs_dir_entry *) bh->b_data;
+	
+	UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(de->d_ino),
+		SWAB16(de->d_reclen), ufs_get_de_namlen(de), de->d_name))
+
+	while (i < bh->b_size) {
+		if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i)) {
+			brelse(bh);
+			return -EIO;
+		}
+		if (de == dir)  {
+			if (pde)
+				pde->d_reclen =
+				    SWAB16(SWAB16(pde->d_reclen) +
+				    SWAB16(dir->d_reclen));
+			dir->d_ino = SWAB32(0);
+			inode->i_version = ++event;
+			inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+			mark_inode_dirty(inode);
+			mark_buffer_dirty(bh);
+			if (IS_SYNC(inode)) {
+				ll_rw_block(WRITE, 1, &bh);
+				wait_on_buffer(bh);
+			}
+			brelse(bh);
+			UFSD(("EXIT\n"))
+			return 0;
+		}
+		i += SWAB16(de->d_reclen);
+		if (i == UFS_SECTOR_SIZE) pde = NULL;
+		else pde = de;
+		de = (struct ufs_dir_entry *)
+		    ((char *) de + SWAB16(de->d_reclen));
+		if (i == UFS_SECTOR_SIZE && SWAB16(de->d_reclen) == 0)
+			break;
+	}
+	UFSD(("EXIT\n"))
+	brelse(bh);
+	return -ENOENT;
+}
+
+int ufs_make_empty(struct inode * inode, struct inode *dir)
+{
+	struct super_block * sb = dir->i_sb;
+	unsigned flags = sb->u.ufs_sb.s_flags;
+	unsigned swab = sb->u.ufs_sb.s_swab;
+	struct buffer_head * dir_block;
+	struct ufs_dir_entry * de;
+	int err;
+
+	dir_block = ufs_bread (inode, 0, 1, &err);
+	if (!dir_block)
+		return err;
+
+	inode->i_blocks = sb->s_blocksize / UFS_SECTOR_SIZE;
+	de = (struct ufs_dir_entry *) dir_block->b_data;
+	de->d_ino = SWAB32(inode->i_ino);
+	ufs_set_de_type (de, inode->i_mode);
+	ufs_set_de_namlen(de,1);
+	de->d_reclen = SWAB16(UFS_DIR_REC_LEN(1));
+	strcpy (de->d_name, ".");
+	de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
+	de->d_ino = SWAB32(dir->i_ino);
+	ufs_set_de_type (de, dir->i_mode);
+	de->d_reclen = SWAB16(UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1));
+	ufs_set_de_namlen(de,2);
+	strcpy (de->d_name, "..");
+	mark_buffer_dirty(dir_block);
+	brelse (dir_block);
+	mark_inode_dirty(inode);
+	return 0;
+}
+
+/*
+ * routine to check that the specified directory is empty (for rmdir)
+ */
+int ufs_empty_dir (struct inode * inode)
+{
+	struct super_block * sb;
+	unsigned long offset;
+	struct buffer_head * bh;
+	struct ufs_dir_entry * de, * de1;
+	int err;
+	unsigned swab;	
+	
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+
+	if (inode->i_size < UFS_DIR_REC_LEN(1) + UFS_DIR_REC_LEN(2) ||
+	    !(bh = ufs_bread (inode, 0, 0, &err))) {
+	    	ufs_warning (inode->i_sb, "empty_dir",
+			      "bad directory (dir #%lu) - no data block",
+			      inode->i_ino);
+		return 1;
+	}
+	de = (struct ufs_dir_entry *) bh->b_data;
+	de1 = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
+	if (SWAB32(de->d_ino) != inode->i_ino || !SWAB32(de1->d_ino) || 
+	    strcmp (".", de->d_name) || strcmp ("..", de1->d_name)) {
+	    	ufs_warning (inode->i_sb, "empty_dir",
+			      "bad directory (dir #%lu) - no `.' or `..'",
+			      inode->i_ino);
+		return 1;
+	}
+	offset = SWAB16(de->d_reclen) + SWAB16(de1->d_reclen);
+	de = (struct ufs_dir_entry *) ((char *) de1 + SWAB16(de1->d_reclen));
+	while (offset < inode->i_size ) {
+		if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
+			brelse (bh);
+			bh = ufs_bread (inode, offset >> sb->s_blocksize_bits, 1, &err);
+	 		if (!bh) {
+				ufs_error (sb, "empty_dir",
+					    "directory #%lu contains a hole at offset %lu",
+					    inode->i_ino, offset);
+				offset += sb->s_blocksize;
+				continue;
+			}
+			de = (struct ufs_dir_entry *) bh->b_data;
+		}
+		if (!ufs_check_dir_entry ("empty_dir", inode, de, bh, offset)) {
+			brelse (bh);
+			return 1;
+		}
+		if (SWAB32(de->d_ino)) {
+			brelse (bh);
+			return 0;
+		}
+		offset += SWAB16(de->d_reclen);
+		de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
+	}
+	brelse (bh);
+	return 1;
 }
 
 struct file_operations ufs_dir_operations = {
diff -u --recursive --new-file v2.4.12/linux/fs/ufs/ialloc.c linux/fs/ufs/ialloc.c
--- v2.4.12/linux/fs/ufs/ialloc.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/ufs/ialloc.c	Sat Oct 20 19:14:42 2001
@@ -143,7 +143,7 @@
  * For other inodes, search forward from the parent directory's block
  * group to find a free inode.
  */
-struct inode * ufs_new_inode (const struct inode * dir,	int mode, int * err )
+struct inode * ufs_new_inode (const struct inode * dir,	int mode)
 {
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
@@ -157,24 +157,18 @@
 	UFSD(("ENTER\n"))
 	
 	/* Cannot create files in a deleted directory */
-	if (!dir || !dir->i_nlink) {
-		*err = -EPERM;
-		return NULL;
-	}
+	if (!dir || !dir->i_nlink)
+		return ERR_PTR(-EPERM);
 	sb = dir->i_sb;
 	inode = new_inode(sb);
-	if (!inode) {
-		*err = -ENOMEM;
-		return NULL;
-	}
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
 	swab = sb->u.ufs_sb.s_swab;
 	uspi = sb->u.ufs_sb.s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 
 	lock_super (sb);
 
-	*err = -ENOSPC;
-
 	/*
 	 * Try to place the inode in its parent directory
 	 */
@@ -262,7 +256,7 @@
 	if (dir->i_mode & S_ISGID) {
 		inode->i_gid = dir->i_gid;
 		if (S_ISDIR(mode))
-			mode |= S_ISGID;
+			inode->i_mode |= S_ISGID;
 	} else
 		inode->i_gid = current->fsgid;
 
@@ -283,12 +277,10 @@
 		inode->i_flags |= S_NOQUOTA;
 		inode->i_nlink = 0;
 		iput(inode);
-		*err = -EDQUOT;
-		return NULL;
+		return ERR_PTR(-EDQUOT);
 	}
 
 	UFSD(("allocating inode %lu\n", inode->i_ino))
-	*err = 0;
 	UFSD(("EXIT\n"))
 	return inode;
 
@@ -297,5 +289,5 @@
 	make_bad_inode(inode);
 	iput (inode);
 	UFSD(("EXIT (FAILED)\n"))
-	return NULL;
+	return ERR_PTR(-ENOSPC);
 }
diff -u --recursive --new-file v2.4.12/linux/fs/ufs/inode.c linux/fs/ufs/inode.c
--- v2.4.12/linux/fs/ufs/inode.c	Mon Dec  4 19:00:54 2000
+++ linux/fs/ufs/inode.c	Sat Oct 20 19:14:42 2001
@@ -50,130 +50,84 @@
 #define UFSD(x)
 #endif
 
-#ifdef UFS_INODE_DEBUG_MORE
-static void ufs_print_inode(struct inode * inode)
-{
-	unsigned swab = inode->i_sb->u.ufs_sb.s_swab;
-	printk("ino %lu  mode 0%6.6o  nlink %d  uid %d  gid %d"
-	       "  size %lu blocks %lu\n",
-	       inode->i_ino, inode->i_mode, inode->i_nlink,
-	       inode->i_uid, inode->i_gid, 
-	       inode->i_size, inode->i_blocks);
-	printk("  db <%u %u %u %u %u %u %u %u %u %u %u %u>\n",
-		SWAB32(inode->u.ufs_i.i_u1.i_data[0]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[1]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[2]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[3]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[4]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[5]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[6]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[7]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[8]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[9]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[10]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[11]));
-	printk("  gen %u ib <%u %u %u>\n",
-		inode->u.ufs_i.i_gen,
-		SWAB32(inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK]),
-		SWAB32(inode->u.ufs_i.i_u1.i_data[UFS_TIND_BLOCK]));
-}
-#endif
-
-#define ufs_inode_bmap(inode, nr) \
-	(SWAB32((inode)->u.ufs_i.i_u1.i_data[(nr) >> uspi->s_fpbshift]) + ((nr) & uspi->s_fpbmask))
-
-static inline unsigned int ufs_block_bmap (struct buffer_head * bh, unsigned nr, 
+static inline unsigned int ufs_block_bmap1(struct buffer_head * bh, unsigned nr, 
 	struct ufs_sb_private_info * uspi, unsigned swab)
 {
 	unsigned int tmp;
-
-	UFSD(("ENTER, nr %u\n", nr))
 	if (!bh)
 		return 0;
-	tmp = SWAB32(((u32 *) bh->b_data)[nr >> uspi->s_fpbshift]) + (nr & uspi->s_fpbmask);
+	tmp = SWAB32(((u32 *) bh->b_data)[nr]);
 	brelse (bh);
-	UFSD(("EXIT, result %u\n", tmp))
 	return tmp;
 }
 
+static int ufs_block_to_path(struct inode *inode, long i_block, int offsets[4])
+{
+	struct ufs_sb_private_info *uspi = inode->i_sb->u.ufs_sb.s_uspi;
+	int ptrs = uspi->s_apb;
+	int ptrs_bits = uspi->s_apbshift;
+	const long direct_blocks = UFS_NDADDR,
+		indirect_blocks = ptrs,
+		double_blocks = (1 << (ptrs_bits * 2));
+	int n = 0;
+
+	if (i_block < 0) {
+		ufs_warning(inode->i_sb, "ufs_block_to_path", "block < 0");
+	} else if (i_block < direct_blocks) {
+		offsets[n++] = i_block;
+	} else if ((i_block -= direct_blocks) < indirect_blocks) {
+		offsets[n++] = UFS_IND_BLOCK;
+		offsets[n++] = i_block;
+	} else if ((i_block -= indirect_blocks) < double_blocks) {
+		offsets[n++] = UFS_DIND_BLOCK;
+		offsets[n++] = i_block >> ptrs_bits;
+		offsets[n++] = i_block & (ptrs - 1);
+	} else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) {
+		offsets[n++] = UFS_TIND_BLOCK;
+		offsets[n++] = i_block >> (ptrs_bits * 2);
+		offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1);
+		offsets[n++] = i_block & (ptrs - 1);
+	} else {
+		ufs_warning(inode->i_sb, "ufs_block_to_path", "block > big");
+	}
+	return n;
+}
+
 int ufs_frag_map(struct inode *inode, int frag)
 {
-	struct super_block *sb;
-	struct ufs_sb_private_info *uspi;
-	unsigned int swab;
-	int i, ret;
+	struct super_block *sb = inode->i_sb;
+	struct ufs_sb_private_info *uspi = sb->u.ufs_sb.s_uspi;
+	unsigned int swab = sb->u.ufs_sb.s_swab;
+	int mask = uspi->s_apbmask>>uspi->s_fpbshift;
+	int shift = uspi->s_apbshift-uspi->s_fpbshift;
+	int offsets[4], *p;
+	int depth = ufs_block_to_path(inode, frag >> uspi->s_fpbshift, offsets);
+	int ret = 0;
+	u32 block;
 
-	ret = 0;
-	lock_kernel();
-	
-	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
-	swab = sb->u.ufs_sb.s_swab;
-	if (frag < 0) {
-		ufs_warning(sb, "ufs_frag_map", "frag < 0");
-		goto out;
-	}
-	if (frag >=
-	    ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb)
-	     << uspi->s_fpbshift)) {
-		ufs_warning(sb, "ufs_frag_map", "frag > big");
-		goto out;
-	}
+	if (depth == 0)
+		return 0;
 
-	if (frag < UFS_NDIR_FRAGMENT) {
-		ret = uspi->s_sbbase + ufs_inode_bmap(inode, frag);
-		goto out;
-	}
+	p = offsets;
 
-	frag -= UFS_NDIR_FRAGMENT;
-	if (frag < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
-		i = ufs_inode_bmap(inode,
-				   UFS_IND_FRAGMENT + (frag >> uspi->s_apbshift));
-		if (!i)
-			goto out;
-		ret = (uspi->s_sbbase +
-		       ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
-					    sb->s_blocksize),
-				      frag & uspi->s_apbmask, uspi, swab));
+	lock_kernel();
+	block = inode->u.ufs_i.i_u1.i_data[*p++];
+	if (!block)
 		goto out;
-	}
-	frag -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
-	if (frag < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
-		i = ufs_inode_bmap (inode,
-				    UFS_DIND_FRAGMENT + (frag >> uspi->s_2apbshift));
-		if (!i)
+	while (--depth) {
+		struct buffer_head *bh;
+		int n = *p++;
+
+		bh = bread(sb->s_dev, uspi->s_sbbase+SWAB32(block)+(n>>shift),
+				sb->s_blocksize);
+		if (!bh)
 			goto out;
-		i = ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
-					 sb->s_blocksize),
-				   (frag >> uspi->s_apbshift) & uspi->s_apbmask,
-				   uspi, swab);
-		if (!i)
+		block = ((u32*) bh->b_data)[n & mask];
+		brelse (bh);
+		if (!block)
 			goto out;
-		ret = (uspi->s_sbbase +
-		       ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
-					    sb->s_blocksize),
-				      (frag & uspi->s_apbmask), uspi, swab));
-		goto out;
 	}
-	frag -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
-	i = ufs_inode_bmap(inode,
-			   UFS_TIND_FRAGMENT + (frag >> uspi->s_3apbshift));
-	if (!i)
-		goto out;
-	i = ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i, sb->s_blocksize),
-			   (frag >> uspi->s_2apbshift) & uspi->s_apbmask,
-			   uspi, swab);
-	if (!i)
-		goto out;
-	i = ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i, sb->s_blocksize),
-			   (frag >> uspi->s_apbshift) & uspi->s_apbmask,
-			   uspi, swab);
-	if (!i)
-		goto out;
-	ret = (uspi->s_sbbase +
-	       ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i, sb->s_blocksize),
-			      (frag & uspi->s_apbmask), uspi, swab));
+	ret = uspi->s_sbbase + SWAB32(block) + (frag & uspi->s_fpbmask);
 out:
 	unlock_kernel();
 	return ret;
@@ -640,9 +594,6 @@
 
 	brelse (bh);
 
-#ifdef UFS_INODE_DEBUG_MORE
-	ufs_print_inode (inode);
-#endif
 	UFSD(("EXIT\n"))
 }
 
diff -u --recursive --new-file v2.4.12/linux/fs/ufs/namei.c linux/fs/ufs/namei.c
--- v2.4.12/linux/fs/ufs/namei.c	Tue Sep  5 14:07:30 2000
+++ linux/fs/ufs/namei.c	Sat Oct 20 19:14:42 2001
@@ -24,20 +24,9 @@
  *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
-#include <asm/uaccess.h>
-
-#include <linux/errno.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-#include <linux/quotaops.h>
-
-#include "swab.h"
-#include "util.h"
 
 #undef UFS_NAMEI_DEBUG
 
@@ -47,345 +36,49 @@
 #define UFSD(x)
 #endif
 
-/*
- * define how far ahead to read directories while searching them.
- */
-#define NAMEI_RA_CHUNKS  2
-#define NAMEI_RA_BLOCKS  4
-#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
-#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
-
-/*
- * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure.
- *
- * len <= UFS_MAXNAMLEN and de != NULL are guaranteed by caller.
- */
-static inline int ufs_match (int len, const char * const name,
-	struct ufs_dir_entry * de, unsigned flags, unsigned swab)
+static inline void ufs_inc_count(struct inode *inode)
 {
-	if (len != ufs_get_de_namlen(de))
-		return 0;
-	if (!de->d_ino)
-		return 0;
-	return !memcmp(name, de->d_name, len);
+	inode->i_nlink++;
+	mark_inode_dirty(inode);
 }
 
-/*
- *	ufs_find_entry()
- *
- * finds an entry in the specified directory with the wanted name. It
- * returns the cache buffer in which the entry was found, and the entry
- * itself (as a parameter - res_dir). It does NOT read the inode of the
- * entry - you'll have to do that yourself if you want to.
- */
-static struct buffer_head * ufs_find_entry (struct inode * dir,
-	const char * const name, int namelen, struct ufs_dir_entry ** res_dir)
+static inline void ufs_dec_count(struct inode *inode)
 {
-	struct super_block * sb;
-	struct buffer_head * bh_use[NAMEI_RA_SIZE];
-	struct buffer_head * bh_read[NAMEI_RA_SIZE];
-	unsigned long offset;
-	int block, toread, i, err;
-	unsigned flags, swab;
-
-	UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen))
-	
-	*res_dir = NULL;
-	
-	sb = dir->i_sb;
-	flags = sb->u.ufs_sb.s_flags;
-	swab = sb->u.ufs_sb.s_swab;
-	
-	if (namelen > UFS_MAXNAMLEN)
-		return NULL;
-
-	memset (bh_use, 0, sizeof (bh_use));
-	toread = 0;
-	for (block = 0; block < NAMEI_RA_SIZE; ++block) {
-		struct buffer_head * bh;
-
-		if ((block << sb->s_blocksize_bits) >= dir->i_size)
-			break;
-		bh = ufs_getfrag (dir, block, 0, &err);
-		bh_use[block] = bh;
-		if (bh && !buffer_uptodate(bh))
-			bh_read[toread++] = bh;
-	}
-
-	for (block = 0, offset = 0; offset < dir->i_size; block++) {
-		struct buffer_head * bh;
-		struct ufs_dir_entry * de;
-		char * dlimit;
-
-		if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
-			ll_rw_block (READ, toread, bh_read);
-			toread = 0;
-		}
-		bh = bh_use[block % NAMEI_RA_SIZE];
-		if (!bh) {
-			ufs_error (sb, "ufs_find_entry", 
-				"directory #%lu contains a hole at offset %lu",
-				dir->i_ino, offset);
-			offset += sb->s_blocksize;
-			continue;
-		}
-		wait_on_buffer (bh);
-		if (!buffer_uptodate(bh)) {
-			/*
-			 * read error: all bets are off
-			 */
-			break;
-		}
-
-		de = (struct ufs_dir_entry *) bh->b_data;
-		dlimit = bh->b_data + sb->s_blocksize;
-		while ((char *) de < dlimit && offset < dir->i_size) {
-			/* this code is executed quadratically often */
-			/* do minimal checking by hand */
-			int de_len;
-
-			if ((char *) de + namelen <= dlimit &&
-			    ufs_match (namelen, name, de, flags, swab)) {
-				/* found a match -
-				just to be sure, do a full check */
-				if (!ufs_check_dir_entry("ufs_find_entry",
-				    dir, de, bh, offset))
-					goto failed;
-				for (i = 0; i < NAMEI_RA_SIZE; ++i) {
-					if (bh_use[i] != bh)
-						brelse (bh_use[i]);
-				}
-				*res_dir = de;
-				return bh;
-			}
-                        /* prevent looping on a bad block */
-			de_len = SWAB16(de->d_reclen);
-			if (de_len <= 0)
-				goto failed;
-			offset += de_len;
-			de = (struct ufs_dir_entry *) ((char *) de + de_len);
-		}
+	inode->i_nlink--;
+	mark_inode_dirty(inode);
+}
 
-		brelse (bh);
-		if (((block + NAMEI_RA_SIZE) << sb->s_blocksize_bits ) >=
-		    dir->i_size)
-			bh = NULL;
-		else
-			bh = ufs_getfrag (dir, block + NAMEI_RA_SIZE, 0, &err);
-		bh_use[block % NAMEI_RA_SIZE] = bh;
-		if (bh && !buffer_uptodate(bh))
-			bh_read[toread++] = bh;
+static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode)
+{
+	int err = ufs_add_link(dentry, inode);
+	if (!err) {
+		d_instantiate(dentry, inode);
+		return 0;
 	}
-
-failed:
-	for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]);
-	UFSD(("EXIT\n"))
-	return NULL;
+	ufs_dec_count(inode);
+	iput(inode);
+	return err;
 }
 
 static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry)
 {
-	struct super_block * sb;
-	struct inode * inode;
-	struct ufs_dir_entry * de;
-	struct buffer_head * bh;
-	unsigned swab;
-	
-	UFSD(("ENTER\n"))
-	
-	sb = dir->i_sb;
-	swab = sb->u.ufs_sb.s_swab;
+	struct inode * inode = NULL;
+	ino_t ino;
 	
 	if (dentry->d_name.len > UFS_MAXNAMLEN)
 		return ERR_PTR(-ENAMETOOLONG);
 
-	bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
-	inode = NULL;
-	if (bh) {
-		unsigned long ino = SWAB32(de->d_ino);
-		brelse (bh);
-		inode = iget(sb, ino);
+	ino = ufs_inode_by_name(dir, dentry);
+	if (ino) {
+		inode = iget(dir->i_sb, ino);
 		if (!inode) 
 			return ERR_PTR(-EACCES);
 	}
 	d_add(dentry, inode);
-	UFSD(("EXIT\n"))
-	return NULL;
-}
-
-/*
- *	ufs_add_entry()
- *
- * adds a file entry to the specified directory, using the same
- * semantics as ufs_find_entry(). It returns NULL if it failed.
- *
- * NOTE!! The inode part of 'de' is left at 0 - which means you
- * may not sleep between calling this and putting something into
- * the entry, as someone else might have used it while you slept.
- */
-static struct buffer_head * ufs_add_entry (struct inode * dir,
-	const char * name, int namelen, struct ufs_dir_entry ** res_dir, 
-	int *err )
-{
-	struct super_block * sb;
-	struct ufs_sb_private_info * uspi;
-	unsigned long offset;
-	unsigned fragoff;
-	unsigned short rec_len;
-	struct buffer_head * bh;
-	struct ufs_dir_entry * de, * de1;
-	unsigned flags, swab;
-
-	UFSD(("ENTER, name %s, namelen %u\n", name, namelen))
-	
-	*err = -EINVAL;
-	*res_dir = NULL;
-		
-	sb = dir->i_sb;
-	flags = sb->u.ufs_sb.s_flags;
-	swab = sb->u.ufs_sb.s_swab;
-	uspi = sb->u.ufs_sb.s_uspi;
-
-	if (!namelen)
-		return NULL;
-	bh = ufs_bread (dir, 0, 0, err);
-	if (!bh)
-		return NULL;
-	rec_len = UFS_DIR_REC_LEN(namelen);
-	offset = 0;
-	de = (struct ufs_dir_entry *) bh->b_data;
-	*err = -ENOSPC;
-	while (1) {
-		if ((char *)de >= UFS_SECTOR_SIZE + bh->b_data) {
-			fragoff = offset & ~uspi->s_fmask;
-			if (fragoff != 0 && fragoff != UFS_SECTOR_SIZE)
-				ufs_error (sb, "ufs_add_entry", "internal error"
-					" fragoff %u", fragoff);
-			if (!fragoff) {
-				brelse (bh);
-				bh = NULL;
-				bh = ufs_bread (dir, offset >> sb->s_blocksize_bits, 1, err);
-			}
-			if (!bh)
-				return NULL;
-			if (dir->i_size <= offset) {
-				if (dir->i_size == 0) {
-					*err = -ENOENT;
-					return NULL;
-				}
-				de = (struct ufs_dir_entry *) (bh->b_data + fragoff);
-				de->d_ino = SWAB32(0);
-				de->d_reclen = SWAB16(UFS_SECTOR_SIZE);
-				ufs_set_de_namlen(de,0);
-				dir->i_size = offset + UFS_SECTOR_SIZE;
-				mark_inode_dirty(dir);
-			} else {
-				de = (struct ufs_dir_entry *) bh->b_data;
-			}
-		}
-		if (!ufs_check_dir_entry ("ufs_add_entry", dir, de, bh, offset)) {
-			*err = -ENOENT;
-			brelse (bh);
-			return NULL;
-		}
-		if (ufs_match (namelen, name, de, flags, swab)) {
-				*err = -EEXIST;
-				brelse (bh);
-				return NULL;
-		}
-		if ((SWAB32(de->d_ino) == 0 && SWAB16(de->d_reclen) >= rec_len) ||
-		    (SWAB16(de->d_reclen) >= UFS_DIR_REC_LEN(ufs_get_de_namlen(de)) + rec_len)) {
-			offset += SWAB16(de->d_reclen);
-			if (SWAB32(de->d_ino)) {
-				de1 = (struct ufs_dir_entry *) ((char *) de +
-					UFS_DIR_REC_LEN(ufs_get_de_namlen(de)));
-				de1->d_reclen = SWAB16(SWAB16(de->d_reclen) -
-					UFS_DIR_REC_LEN(ufs_get_de_namlen(de)));
-				de->d_reclen = SWAB16(UFS_DIR_REC_LEN(ufs_get_de_namlen(de)));
-				de = de1;
-			}
-			de->d_ino = SWAB32(0);
-			ufs_set_de_namlen(de, namelen);
-			memcpy (de->d_name, name, namelen + 1);
-			/*
-			 * XXX shouldn't update any times until successful
-			 * completion of syscall, but too many callers depend
-			 * on this.
-			 *
-			 * XXX similarly, too many callers depend on
-			 * ufs_new_inode() setting the times, but error
-			 * recovery deletes the inode, so the worst that can
-			 * happen is that the times are slightly out of date
-			 * and/or different from the directory change time.
-			 */
-			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-			mark_inode_dirty(dir);
-			dir->i_version = ++event;
-			mark_buffer_dirty(bh);
-			*res_dir = de;
-			*err = 0;
-			
-			UFSD(("EXIT\n"))
-			return bh;
-		}
-		offset += SWAB16(de->d_reclen);
-		de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
-	}
-	brelse (bh);
-	UFSD(("EXIT (FAILED)\n"))
 	return NULL;
 }
 
 /*
- * ufs_delete_entry deletes a directory entry by merging it with the
- * previous entry.
- */
-static int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir,
-	struct buffer_head * bh )
-	
-{
-	struct super_block * sb;
-	struct ufs_dir_entry * de, * pde;
-	unsigned i;
-	unsigned flags, swab;
-	
-	UFSD(("ENTER\n"))
-
-	sb = inode->i_sb;
-	flags = sb->u.ufs_sb.s_flags;
-	swab = sb->u.ufs_sb.s_swab;
-	i = 0;
-	pde = NULL;
-	de = (struct ufs_dir_entry *) bh->b_data;
-	
-	UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(de->d_ino),
-		SWAB16(de->d_reclen), ufs_get_de_namlen(de), de->d_name))
-
-	while (i < bh->b_size) {
-		if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i))
-			return -EIO;
-		if (de == dir)  {
-			if (pde)
-				pde->d_reclen =
-				    SWAB16(SWAB16(pde->d_reclen) +
-				    SWAB16(dir->d_reclen));
-			dir->d_ino = SWAB32(0);
-			UFSD(("EXIT\n"))
-			return 0;
-		}
-		i += SWAB16(de->d_reclen);
-		if (i == UFS_SECTOR_SIZE) pde = NULL;
-		else pde = de;
-		de = (struct ufs_dir_entry *)
-		    ((char *) de + SWAB16(de->d_reclen));
-		if (i == UFS_SECTOR_SIZE && SWAB16(de->d_reclen) == 0)
-			break;
-	}
-	UFSD(("EXIT\n"))
-	return -ENOENT;
-}
-
-/*
  * By the time this is called, we already have created
  * the directory cache entry for the new file, but it
  * is so far negative - it has no inode.
@@ -395,375 +88,45 @@
  */
 static int ufs_create (struct inode * dir, struct dentry * dentry, int mode)
 {
-	struct super_block * sb;
-	struct inode * inode;
-	struct buffer_head * bh;
-	struct ufs_dir_entry * de;
-	int err = -EIO;
-	unsigned flags, swab;
-	
-	sb = dir->i_sb;
-	swab = sb->u.ufs_sb.s_swab;
-	flags = sb->u.ufs_sb.s_flags;
-	/*
-	 * N.B. Several error exits in ufs_new_inode don't set err.
-	 */
-	UFSD(("ENTER\n"))
-	
-	inode = ufs_new_inode (dir, mode, &err);
-	if (!inode)
-		return err;
-	inode->i_op = &ufs_file_inode_operations;
-	inode->i_fop = &ufs_file_operations;
-	inode->i_mapping->a_ops = &ufs_aops;
-	inode->i_mode = mode;
-	mark_inode_dirty(inode);
-	bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
-	if (!bh) {
-		inode->i_nlink--;
+	struct inode * inode = ufs_new_inode(dir, mode);
+	int err = PTR_ERR(inode);
+	if (!IS_ERR(inode)) {
+		inode->i_op = &ufs_file_inode_operations;
+		inode->i_fop = &ufs_file_operations;
+		inode->i_mapping->a_ops = &ufs_aops;
 		mark_inode_dirty(inode);
-		iput (inode);
-		return err;
-	}
-	de->d_ino = SWAB32(inode->i_ino);
-	ufs_set_de_type (de, inode->i_mode);
-	dir->i_version = ++event;
-	mark_buffer_dirty(bh);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
-	}
-	brelse (bh);
-	d_instantiate(dentry, inode);
-	
-	UFSD(("EXIT\n"))
-	
-	return 0;
-}
-
-static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
-{
-	struct super_block * sb;
-	struct inode * inode;
-	struct buffer_head * bh;
-	struct ufs_dir_entry * de;
-	int err = -EIO;
-	unsigned flags, swab;
-	
-	sb = dir->i_sb;
-	flags = sb->u.ufs_sb.s_flags;
-	swab = sb->u.ufs_sb.s_swab;
-
-	inode = ufs_new_inode (dir, mode, &err);
-	if (!inode)
-		goto out;
-
-	inode->i_uid = current->fsuid;
-	init_special_inode(inode, mode, rdev);
-	mark_inode_dirty(inode);
-	bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
-	if (!bh)
-		goto out_no_entry;
-	de->d_ino = SWAB32(inode->i_ino);
-	ufs_set_de_type (de, inode->i_mode);
-	dir->i_version = ++event;
-	mark_buffer_dirty(bh);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
+		err = ufs_add_nondir(dentry, inode);
 	}
-	d_instantiate(dentry, inode);
-	brelse(bh);
-	err = 0;
-out:
 	return err;
-
-out_no_entry:
-	inode->i_nlink--;
-	mark_inode_dirty(inode);
-	iput(inode);
-	goto out;
 }
 
-static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
 {
-	struct super_block * sb;
-	struct inode * inode;
-	struct buffer_head * bh, * dir_block;
-	struct ufs_dir_entry * de;
-	int err;
-	unsigned flags, swab;
-	
-	sb = dir->i_sb;
-	flags = sb->u.ufs_sb.s_flags;
-	swab = sb->u.ufs_sb.s_swab;
-
-	err = -EMLINK;
-	if (dir->i_nlink >= UFS_LINK_MAX)
-		goto out;
-	err = -EIO;
-	inode = ufs_new_inode (dir, S_IFDIR, &err);
-	if (!inode)
-		goto out;
-
-	inode->i_op = &ufs_dir_inode_operations;
-	inode->i_fop = &ufs_dir_operations;
-	inode->i_size = UFS_SECTOR_SIZE;
-	dir_block = ufs_bread (inode, 0, 1, &err);
-	if (!dir_block) {
-		inode->i_nlink--; /* is this nlink == 0? */
+	struct inode * inode = ufs_new_inode(dir, mode);
+	int err = PTR_ERR(inode);
+	if (!IS_ERR(inode)) {
+		init_special_inode(inode, mode, rdev);
 		mark_inode_dirty(inode);
-		iput (inode);
-		return err;
-	}
-	inode->i_blocks = sb->s_blocksize / UFS_SECTOR_SIZE;
-	de = (struct ufs_dir_entry *) dir_block->b_data;
-	de->d_ino = SWAB32(inode->i_ino);
-	ufs_set_de_type (de, inode->i_mode);
-	ufs_set_de_namlen(de,1);
-	de->d_reclen = SWAB16(UFS_DIR_REC_LEN(1));
-	strcpy (de->d_name, ".");
-	de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
-	de->d_ino = SWAB32(dir->i_ino);
-	ufs_set_de_type (de, dir->i_mode);
-	de->d_reclen = SWAB16(UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1));
-	ufs_set_de_namlen(de,2);
-	strcpy (de->d_name, "..");
-	inode->i_nlink = 2;
-	mark_buffer_dirty(dir_block);
-	brelse (dir_block);
-	inode->i_mode = S_IFDIR | mode;
-	if (dir->i_mode & S_ISGID)
-		inode->i_mode |= S_ISGID;
-	mark_inode_dirty(inode);
-	bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
-	if (!bh)
-		goto out_no_entry;
-	de->d_ino = SWAB32(inode->i_ino);
-	ufs_set_de_type (de, inode->i_mode);
-	dir->i_version = ++event;
-	mark_buffer_dirty(bh);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
+		err = ufs_add_nondir(dentry, inode);
 	}
-	dir->i_nlink++;
-	mark_inode_dirty(dir);
-	d_instantiate(dentry, inode);
-	brelse (bh);
-	err = 0;
-out:
 	return err;
-
-out_no_entry:
-	inode->i_nlink = 0;
-	mark_inode_dirty(inode);
-	iput (inode);
-	goto out;
-}
-
-/*
- * routine to check that the specified directory is empty (for rmdir)
- */
-static int ufs_empty_dir (struct inode * inode)
-{
-	struct super_block * sb;
-	unsigned long offset;
-	struct buffer_head * bh;
-	struct ufs_dir_entry * de, * de1;
-	int err;
-	unsigned swab;	
-	
-	sb = inode->i_sb;
-	swab = sb->u.ufs_sb.s_swab;
-
-	if (inode->i_size < UFS_DIR_REC_LEN(1) + UFS_DIR_REC_LEN(2) ||
-	    !(bh = ufs_bread (inode, 0, 0, &err))) {
-	    	ufs_warning (inode->i_sb, "empty_dir",
-			      "bad directory (dir #%lu) - no data block",
-			      inode->i_ino);
-		return 1;
-	}
-	de = (struct ufs_dir_entry *) bh->b_data;
-	de1 = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
-	if (SWAB32(de->d_ino) != inode->i_ino || !SWAB32(de1->d_ino) || 
-	    strcmp (".", de->d_name) || strcmp ("..", de1->d_name)) {
-	    	ufs_warning (inode->i_sb, "empty_dir",
-			      "bad directory (dir #%lu) - no `.' or `..'",
-			      inode->i_ino);
-		return 1;
-	}
-	offset = SWAB16(de->d_reclen) + SWAB16(de1->d_reclen);
-	de = (struct ufs_dir_entry *) ((char *) de1 + SWAB16(de1->d_reclen));
-	while (offset < inode->i_size ) {
-		if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
-			brelse (bh);
-			bh = ufs_bread (inode, offset >> sb->s_blocksize_bits, 1, &err);
-	 		if (!bh) {
-				ufs_error (sb, "empty_dir",
-					    "directory #%lu contains a hole at offset %lu",
-					    inode->i_ino, offset);
-				offset += sb->s_blocksize;
-				continue;
-			}
-			de = (struct ufs_dir_entry *) bh->b_data;
-		}
-		if (!ufs_check_dir_entry ("empty_dir", inode, de, bh, offset)) {
-			brelse (bh);
-			return 1;
-		}
-		if (SWAB32(de->d_ino)) {
-			brelse (bh);
-			return 0;
-		}
-		offset += SWAB16(de->d_reclen);
-		de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
-	}
-	brelse (bh);
-	return 1;
 }
 
-static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
-{
-	struct super_block *sb;
-	int retval;
-	struct inode * inode;
-	struct buffer_head * bh;
-	struct ufs_dir_entry * de;
-	unsigned swab;
-	
-	sb = dir->i_sb;
-	swab = sb->u.ufs_sb.s_swab;
-		
-	UFSD(("ENTER\n"))
-
-	retval = -ENOENT;
-	bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
-	if (!bh)
-		goto end_rmdir;
-
-	inode = dentry->d_inode;
-	DQUOT_INIT(inode);
-
-	retval = -EIO;
-	if (SWAB32(de->d_ino) != inode->i_ino)
-		goto end_rmdir;
-
-	retval = -ENOTEMPTY;
-	if (!ufs_empty_dir (inode))
-		goto end_rmdir;
-
-	retval = ufs_delete_entry (dir, de, bh);
-	dir->i_version = ++event;
-	if (retval)
-		goto end_rmdir;
-	mark_buffer_dirty(bh);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
-	}
-	if (inode->i_nlink != 2)
-		ufs_warning (inode->i_sb, "ufs_rmdir",
-			      "empty directory has nlink!=2 (%d)",
-			      inode->i_nlink);
-	inode->i_version = ++event;
-	inode->i_nlink = 0;
-	inode->i_size = 0;
-	mark_inode_dirty(inode);
-	dir->i_nlink--;
-	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	mark_inode_dirty(dir);
-
-end_rmdir:
-	brelse (bh);
-	UFSD(("EXIT\n"))
-	
-	return retval;
-}
-
-static int ufs_unlink(struct inode * dir, struct dentry *dentry)
-{
-	struct super_block * sb;
-	int retval;
-	struct inode * inode;
-	struct buffer_head * bh;
-	struct ufs_dir_entry * de;
-	unsigned flags, swab;
-
-	sb = dir->i_sb;
-	flags = sb->u.ufs_sb.s_flags;
-	swab = sb->u.ufs_sb.s_swab;
-
-	retval = -ENOENT;
-	bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
-	UFSD(("de: ino %u, reclen %u, namelen %u, name %s\n", SWAB32(de->d_ino),
-		SWAB16(de->d_reclen), ufs_get_de_namlen(de), de->d_name))
-	if (!bh)
-		goto end_unlink;
-
-	inode = dentry->d_inode;
-	DQUOT_INIT(inode);
-
-	retval = -EIO;
-	if (SWAB32(de->d_ino) != inode->i_ino)
-		goto end_unlink;
-	
-	if (!inode->i_nlink) {
-		ufs_warning (inode->i_sb, "ufs_unlink",
-			      "Deleting nonexistent file (%lu), %d",
-			      inode->i_ino, inode->i_nlink);
-		inode->i_nlink = 1;
-	}
-	retval = ufs_delete_entry (dir, de, bh);
-	if (retval)
-		goto end_unlink;
-	dir->i_version = ++event;
-	mark_buffer_dirty(bh);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
-	}
-	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	mark_inode_dirty(dir);
-	inode->i_nlink--;
-	mark_inode_dirty(inode);
-	inode->i_ctime = dir->i_ctime;
-	retval = 0;
-
-end_unlink:
-	brelse (bh);
-	return retval;
-}
-
-
-/*
- * Create symbolic link. We use only slow symlinks at this time.
- */
 static int ufs_symlink (struct inode * dir, struct dentry * dentry,
 	const char * symname)
 {
 	struct super_block * sb = dir->i_sb;
-	struct ufs_dir_entry * de;
+	int err = -ENAMETOOLONG;
+	unsigned l = strlen(symname)+1;
 	struct inode * inode;
-	struct buffer_head * bh = NULL;
-	unsigned l;
-	int err;
-	unsigned swab = sb->u.ufs_sb.s_swab;
-	
-	UFSD(("ENTER\n"))
-	
 
-	err = -ENAMETOOLONG;
-	l = strlen(symname)+1;
 	if (l > sb->s_blocksize)
 		goto out;
 
-	err = -EIO;
-	
-	if (!(inode = ufs_new_inode (dir, S_IFLNK, &err))) {
-		return err;
-	}
-	inode->i_mode = S_IFLNK | S_IRWXUGO;
+	inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO);
+	err = PTR_ERR(inode);
+	if (IS_ERR(inode))
+		goto out;
 
 	if (l > sb->u.ufs_sb.s_uspi->s_maxsymlinklen) {
 		/* slow symlink */
@@ -771,7 +134,7 @@
 		inode->i_mapping->a_ops = &ufs_aops;
 		err = block_symlink(inode, symname, l);
 		if (err)
-			goto out_no_entry;
+			goto out_fail;
 	} else {
 		/* fast symlink */
 		inode->i_op = &ufs_fast_symlink_inode_operations;
@@ -780,26 +143,13 @@
 	}
 	mark_inode_dirty(inode);
 
-	bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
-	if (!bh)
-		goto out_no_entry;
-	de->d_ino = SWAB32(inode->i_ino);
-	dir->i_version = ++event;
-	mark_buffer_dirty(bh);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
-	}
-	brelse (bh);
-	d_instantiate(dentry, inode);
-	err = 0;
+	err = ufs_add_nondir(dentry, inode);
 out:
 	return err;
 
-out_no_entry:
-	inode->i_nlink--;
-	mark_inode_dirty(inode);
-	iput (inode);
+out_fail:
+	ufs_dec_count(inode);
+	iput(inode);
 	goto out;
 }
 
@@ -807,161 +157,171 @@
 	struct dentry *dentry)
 {
 	struct inode *inode = old_dentry->d_inode;
-	struct super_block * sb = inode->i_sb;
-	struct ufs_dir_entry * de;
-	struct buffer_head * bh;
-	int err;
-	unsigned swab = sb->u.ufs_sb.s_swab;
-	
+
 	if (S_ISDIR(inode->i_mode))
 		return -EPERM;
 
 	if (inode->i_nlink >= UFS_LINK_MAX)
 		return -EMLINK;
 
-	bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
-	if (!bh)
-		return err;
-
-	de->d_ino = SWAB32(inode->i_ino);
-	dir->i_version = ++event;
-	mark_buffer_dirty(bh);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
-	}
-	brelse (bh);
-	inode->i_nlink++;
 	inode->i_ctime = CURRENT_TIME;
-	mark_inode_dirty(inode);
+	ufs_inc_count(inode);
 	atomic_inc(&inode->i_count);
+
+	return ufs_add_nondir(dentry, inode);
+}
+
+static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+{
+	struct inode * inode;
+	int err = -EMLINK;
+
+	if (dir->i_nlink >= UFS_LINK_MAX)
+		goto out;
+
+	ufs_inc_count(dir);
+
+	inode = ufs_new_inode(dir, S_IFDIR|mode);
+	err = PTR_ERR(inode);
+	if (IS_ERR(inode))
+		goto out_dir;
+
+	inode->i_op = &ufs_dir_inode_operations;
+	inode->i_fop = &ufs_dir_operations;
+
+	ufs_inc_count(inode);
+
+	err = ufs_make_empty(inode, dir);
+	if (err)
+		goto out_fail;
+
+	err = ufs_add_link(dentry, inode);
+	if (err)
+		goto out_fail;
+
 	d_instantiate(dentry, inode);
-	return 0;
+out:
+	return err;
+
+out_fail:
+	ufs_dec_count(inode);
+	ufs_dec_count(inode);
+	iput (inode);
+out_dir:
+	ufs_dec_count(dir);
+	goto out;
 }
 
+static int ufs_unlink(struct inode * dir, struct dentry *dentry)
+{
+	struct inode * inode = dentry->d_inode;
+	struct buffer_head * bh;
+	struct ufs_dir_entry * de;
+	int err = -ENOENT;
 
-#define PARENT_INO(buffer) \
-	((struct ufs_dir_entry *) ((char *) buffer + \
-	SWAB16(((struct ufs_dir_entry *) buffer)->d_reclen)))->d_ino
-/*
- * Anybody can rename anything with this: the permission checks are left to the
- * higher-level routines.
- */
-static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
-	struct inode * new_dir,	struct dentry * new_dentry )
+	de = ufs_find_entry (dentry, &bh);
+	if (!de)
+		goto out;
+
+	err = ufs_delete_entry (dir, de, bh);
+	if (err)
+		goto out;
+
+	inode->i_ctime = dir->i_ctime;
+	ufs_dec_count(inode);
+	err = 0;
+out:
+	return err;
+}
+
+static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
 {
-	struct super_block * sb;
-	struct inode * old_inode, * new_inode;
-	struct buffer_head * old_bh, * new_bh, * dir_bh;
-	struct ufs_dir_entry * old_de, * new_de;
-	int retval;
-	unsigned flags, swab;
-	
-	sb = old_dir->i_sb;
-	flags = sb->u.ufs_sb.s_flags;
-	swab = sb->u.ufs_sb.s_swab;
+	struct inode * inode = dentry->d_inode;
+	int err= -ENOTEMPTY;
 
-	UFSD(("ENTER\n"))
-	
-	old_inode = new_inode = NULL;
-	old_bh = new_bh = dir_bh = NULL;
-	new_de = NULL;
-
-	old_bh = ufs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
-	/*
-	 *  Check for inode number is _not_ due to possible IO errors.
-	 *  We might rmdir the source, keep it as pwd of some process
-	 *  and merrily kill the link to whatever was created under the
-	 *  same name. Goodbye sticky bit ;-<
-	 */
-	retval = -ENOENT;
-	old_inode = old_dentry->d_inode;
-	if (!old_bh || SWAB32(old_de->d_ino) != old_inode->i_ino)
-		goto end_rename;
-
-	new_inode = new_dentry->d_inode;
-	new_bh = ufs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de);
-	if (new_bh) {
-		if (!new_inode) {
-			brelse (new_bh);
-			new_bh = NULL;
-		} else {
-			DQUOT_INIT(new_inode);
+	if (ufs_empty_dir (inode)) {
+		err = ufs_unlink(dir, dentry);
+		if (!err) {
+			inode->i_size = 0;
+			ufs_dec_count(inode);
+			ufs_dec_count(dir);
 		}
 	}
-	if (S_ISDIR(old_inode->i_mode)) {
-		if (new_inode) {
-			retval = -ENOTEMPTY;
-			if (!ufs_empty_dir (new_inode))
-				goto end_rename;
-		}
+	return err;
+}
 
-		retval = -EIO;
-		dir_bh = ufs_bread (old_inode, 0, 0, &retval);
-		if (!dir_bh)
-			goto end_rename;
-		if (SWAB32(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
-			goto end_rename;
-		retval = -EMLINK;
-		if (!new_inode && new_dir->i_nlink >= UFS_LINK_MAX)
-			goto end_rename;
-	}
+static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
+	struct inode * new_dir,	struct dentry * new_dentry )
+{
+	struct inode *old_inode = old_dentry->d_inode;
+	struct inode *new_inode = new_dentry->d_inode;
+	struct buffer_head *dir_bh = NULL;
+	struct ufs_dir_entry *dir_de = NULL;
+	struct buffer_head *old_bh;
+	struct ufs_dir_entry *old_de;
+	int err = -ENOENT;
 
-	if (!new_bh)
-		new_bh = ufs_add_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de,
-					 &retval);
-	if (!new_bh)
-		goto end_rename;
-	new_dir->i_version = ++event;
-
-	/*
-	 * ok, that's it
-	 */
-	new_de->d_ino = SWAB32(old_inode->i_ino);
-	ufs_delete_entry (old_dir, old_de, old_bh);
+	old_de = ufs_find_entry (old_dentry, &old_bh);
+	if (!old_de)
+		goto out;
+
+	if (S_ISDIR(old_inode->i_mode)) {
+		err = -EIO;
+		dir_de = ufs_dotdot(old_inode, &dir_bh);
+		if (!dir_de)
+			goto out_old;
+	}
 
-	old_dir->i_version = ++event;
 	if (new_inode) {
-		new_inode->i_nlink--;
+		struct buffer_head *new_bh;
+		struct ufs_dir_entry *new_de;
+
+		err = -ENOTEMPTY;
+		if (dir_de && !ufs_empty_dir (new_inode))
+			goto out_dir;
+		err = -ENOENT;
+		new_de = ufs_find_entry (new_dentry, &new_bh);
+		if (!new_de)
+			goto out_dir;
+		ufs_inc_count(old_inode);
+		ufs_set_link(new_dir, new_de, new_bh, old_inode);
 		new_inode->i_ctime = CURRENT_TIME;
-		mark_inode_dirty(new_inode);
-	}
-	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-	mark_inode_dirty(old_dir);
-	if (dir_bh) {
-		PARENT_INO(dir_bh->b_data) = SWAB32(new_dir->i_ino);
-		mark_buffer_dirty(dir_bh);
-		old_dir->i_nlink--;
-		mark_inode_dirty(old_dir);
-		if (new_inode) {
+		if (dir_de)
 			new_inode->i_nlink--;
-			mark_inode_dirty(new_inode);
-		} else {
-			new_dir->i_nlink++;
-			mark_inode_dirty(new_dir);
+		ufs_dec_count(new_inode);
+	} else {
+		if (dir_de) {
+			err = -EMLINK;
+			if (new_dir->i_nlink >= UFS_LINK_MAX)
+				goto out_dir;
+		}
+		ufs_inc_count(old_inode);
+		err = ufs_add_link(new_dentry, old_inode);
+		if (err) {
+			ufs_dec_count(old_inode);
+			goto out_dir;
 		}
+		if (dir_de)
+			ufs_inc_count(new_dir);
 	}
-	mark_buffer_dirty(old_bh);
-	if (IS_SYNC(old_dir)) {
-		ll_rw_block (WRITE, 1, &old_bh);
-		wait_on_buffer (old_bh);
-	}
-	
-	mark_buffer_dirty(new_bh);
-	if (IS_SYNC(new_dir)) {
-		ll_rw_block (WRITE, 1, &new_bh);
-		wait_on_buffer (new_bh);
+
+	ufs_delete_entry (old_dir, old_de, old_bh);
+
+	ufs_dec_count(old_inode);
+
+	if (dir_de) {
+		ufs_set_link(old_inode, dir_de, dir_bh, new_dir);
+		ufs_dec_count(old_dir);
 	}
+	return 0;
 
-	retval = 0;
-end_rename:
-	brelse (dir_bh);
+out_dir:
+	if (dir_de)
+		brelse(dir_bh);
+out_old:
 	brelse (old_bh);
-	brelse (new_bh);
-	
-	UFSD(("EXIT\n"))
-	
-	return retval;
+out:
+	return err;
 }
 
 struct inode_operations ufs_dir_inode_operations = {
diff -u --recursive --new-file v2.4.12/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.4.12/linux/fs/vfat/namei.c	Fri Apr  6 10:51:19 2001
+++ linux/fs/vfat/namei.c	Fri Oct 12 13:48:42 2001
@@ -9,13 +9,12 @@
  *    what file operation caused you trouble and if you can duplicate
  *    the problem, send a script that demonstrates it.
  *
- *  Short name translation 1999 by Wolfram Pienkoss <wp@bszh.de>
+ *  Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de>
  *
  *  Support Multibyte character and cleanup by
  *  				OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/sched.h>
@@ -29,8 +28,6 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 
-#include "../fat/msbuffer.h"
-
 #define DEBUG_LEVEL 0
 #if (DEBUG_LEVEL >= 1)
 #  define PRINTK1(x) printk x
@@ -48,12 +45,6 @@
 #  define PRINTK3(x)
 #endif
 
-#ifndef DEBUG
-# define CHECK_STACK
-#else
-# define CHECK_STACK check_stack(__FILE__, __LINE__)
-#endif
-
 static int vfat_hashi(struct dentry *parent, struct qstr *qstr);
 static int vfat_hash(struct dentry *parent, struct qstr *qstr);
 static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
@@ -117,6 +108,13 @@
 	opts->unicode_xlate = opts->posixfs = 0;
 	opts->numtail = 1;
 	opts->utf8 = 0;
+	opts->shortname = VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95;
+	/* for backward compatible */
+	if (opts->nocase) {
+		opts->nocase = 0;
+		opts->shortname = VFAT_SFN_DISPLAY_WIN95
+		  		| VFAT_SFN_CREATE_WIN95;
+	}
 
 	if (!options) return 1;
 	save = 0;
@@ -142,6 +140,21 @@
 			if (ret) {
 				opts->numtail = !val;
 			}
+		} else if (!strcmp(this_char, "shortname")) {
+			if (!strcmp(value, "lower"))
+				opts->shortname = VFAT_SFN_DISPLAY_LOWER
+						| VFAT_SFN_CREATE_WIN95;
+			else if (!strcmp(value, "win95"))
+				opts->shortname = VFAT_SFN_DISPLAY_WIN95
+						| VFAT_SFN_CREATE_WIN95;
+			else if (!strcmp(value, "winnt"))
+				opts->shortname = VFAT_SFN_DISPLAY_WINNT
+						| VFAT_SFN_CREATE_WINNT;
+			else if (!strcmp(value, "mixed"))
+				opts->shortname = VFAT_SFN_DISPLAY_WINNT
+						| VFAT_SFN_CREATE_WIN95;
+			else
+				ret = 0;
 		}
 		if (this_char != options)
 			*(this_char-1) = ',';
@@ -157,167 +170,7 @@
 	}
 	return 1;
 }
-#if 0 /* not used functions */
-static inline unsigned char
-vfat_getlower(struct nls_table *t, unsigned char c)
-{
-	return t->charset2lower[c];
-}
-
-static inline unsigned char
-vfat_getupper(struct nls_table *t, unsigned char c)
-{
-	return t->charset2upper[c];
-}
-
-static inline int
-vfat_uni2short(struct nls_table *t, wchar_t uc, unsigned char *op, int bound)
-{
-	int charlen;
-
-	if ( (charlen = t->uni2char(uc, op, bound)) < 0)
-		charlen = 0;
-
-	return charlen;
-}
-
-static int vfat_valid_shortname(struct nls_table *nls, wchar_t *name, int len)
-{
-	wchar_t *walk;
-	unsigned char c, charbuf[NLS_MAX_CHARSET_SIZE];
-	int chl, chi;
-	int space;
-
-	if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0)
-		return -EINVAL;
-
-	if (IS_FREE(charbuf))
-		return -EINVAL;
-
-	chl = 0;
-	c = 0;
-	space = 1; /* disallow names starting with a dot */
-	for (walk = name; len && walk-name < 8;) {
-		len--;
-		chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE);
-		if (chl < 0)
-			return -EINVAL;
-
-		for (chi = 0; chi < chl; chi++) {
-			c = vfat_getupper(nls, charbuf[chi]);
-			if (!c) return -EINVAL;
-			if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL;
-			if (strchr(replace_chars,c)) return -EINVAL;
-			if (c < ' '|| c==':') return -EINVAL;
-			if (c == '.') goto dot;
-			space = c == ' ';
-		}
-	}
-dot:;
-	if (space) return -EINVAL;
-	if (len && c != '.') {
-		len--;
-		if (vfat_uni2upper_short(nls, *walk++, charbuf, NLS_MAX_CHARSET_SIZE) == 1) {
-			if (charbuf[0] != '.') return -EINVAL;
-		} else
-			return -EINVAL;
-		c = '.';
-	}
-	if (c == '.') {
-		if (len >= 4) return -EINVAL;
-		while (len > 0) {
-			len--;
-			chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE);
-			if (chl < 0)
-				return -EINVAL;
-			for (chi = 0; chi < chl; chi++) {
-				c = vfat_getupper(nls, charbuf[chi]);
-				if (!c) return -EINVAL;
-				if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL;
-				if (strchr(replace_chars,c))
-					return -EINVAL;
-				if (c < ' ' || c == '.'|| c==':')
-					return -EINVAL;
-				space = c == ' ';
-			}
-		}
-		if (space) return -EINVAL;
-	}
-
-	return 0;
-}
 
-static int vfat_format_name(struct nls_table *nls, wchar_t *name,
-				int len, char *res)
-{
-	char *walk;
-	unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
-	int chi, chl;
-	int space;
-
-	if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0)
-		return -EINVAL;
-
-	if (IS_FREE(charbuf))
-		return -EINVAL;
-
-	space = 1; /* disallow names starting with a dot */
-	for (walk = res; len--; ) {
-		chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE);
-		if (chl == 0)
-			return -EINVAL;
-		for (chi = 0; chi < chl; chi++){
-			if (charbuf[chi] == '.') goto dot;
-			if (!charbuf[chi]) return -EINVAL;
-			if (walk-res == 8) return -EINVAL;
-			if (strchr(replace_chars,charbuf[chi])) return -EINVAL;
-			if (charbuf[chi] < ' '|| charbuf[chi]==':') return -EINVAL;
-			space = charbuf[chi] == ' ';
-			*walk = charbuf[chi];
-			walk++;
-		}
-	}
-dot:;
-	if (space) return -EINVAL;
-	if (len >= 0) {
-		while (walk-res < 8) *walk++ = ' ';
-		while (len > 0 && walk-res < MSDOS_NAME) {
-			chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE);
-			if (len < chl)
-				chl = len;
-			len -= chl;
-			for (chi = 0; chi < chl; chi++){
-				if (!charbuf[chi]) return -EINVAL;
-				if (strchr(replace_chars,charbuf[chi]))
-					return -EINVAL;
-				if (charbuf[chi] < ' ' || charbuf[chi] == '.'|| charbuf[chi]==':')
-					return -EINVAL;
-				space = charbuf[chi] == ' ';
-				*walk++ = charbuf[chi];
-			}
-		}
-		if (space) return -EINVAL;
-		if (len) return -EINVAL;
-	}
-	while (walk-res < MSDOS_NAME) *walk++ = ' ';
-
-	return 0;
-}
-
-static inline int
-vfat_uni2upper_short(struct nls_table *t, wchar_t uc, char *op, int bound)
-{
-	int chl;
-
-	if ( (chl = t->uni2char(uc, op, bound)) < 0)
-		chl = 0;
-
-	if (chl == 1)
-		op[0] = vfat_toupper(t, op[0]);
-
-	return chl;
-}
-#endif
 static inline unsigned char
 vfat_tolower(struct nls_table *t, unsigned char c)
 {
@@ -437,33 +290,6 @@
 
 #ifdef DEBUG
 
-static void
-check_stack(const char *fname, int lineno)
-{
-	int stack_level;
-	char *pg_dir;
-
-	stack_level = (long)(&pg_dir)-current->kernel_stack_page;
-	if (stack_level < 0)
-	        printk("*-*-*-* vfat kstack overflow in %s line %d: SL=%d\n",
-		       fname, lineno, stack_level);
-	else if (stack_level < 500)
-	        printk("*-*-*-* vfat kstack low in %s line %d: SL=%d\n",
-		       fname, lineno, stack_level);
-#if 0
-	else
-		printk("------- vfat kstack ok in %s line %d: SL=%d\n",
-		       fname, lineno, stack_level);
-#endif
-#if 0
-	if (*(unsigned long *) current->kernel_stack_page != STACK_MAGIC) {
-		printk("******* vfat stack corruption detected in %s at line %d\n",
-		       fname, lineno);
-	}
-#endif
-}
-
-static int debug = 0;
 static void dump_fat(struct super_block *sb,int start)
 {
 	printk("[");
@@ -510,8 +336,10 @@
 /* Characters that are undesirable in an MS-DOS file name */
 
 static wchar_t bad_chars[] = {
-	/*  `*'     `?'     `<'    `>'      `|'     `"'     `:'     `/'     `\' */
-	0x002A, 0x003F, 0x003C, 0x003E, 0x007C, 0x0022, 0x003A, 0x002F, 0x005C, 0,
+	/*  `*'     `?'     `<'    `>'      `|'     `"'     `:'     `/' */
+	0x002A, 0x003F, 0x003C, 0x003E, 0x007C, 0x0022, 0x003A, 0x002F,
+	/*  `\' */
+	0x005C, 0,
 };
 #define IS_BADCHAR(uni)	(vfat_unistrchr(bad_chars, (uni)) != NULL)
 
@@ -521,6 +349,13 @@
 };
 #define IS_REPLACECHAR(uni)	(vfat_unistrchr(replace_chars, (uni)) != NULL)
 
+static wchar_t skip_chars[] = {
+	/*  `.'     ` ' */
+	0x002E, 0x0020, 0,
+};
+#define IS_SKIPCHAR(uni) \
+	((wchar_t)(uni) == skip_chars[0] || (wchar_t)(uni) == skip_chars[1])
+
 static inline wchar_t *vfat_unistrchr(const wchar_t *s, const wchar_t c)
 {
 	for(; *s != c; ++s)
@@ -582,47 +417,119 @@
 	return 0;
 }
 
-static wchar_t skip_chars[] = {
-	/*  `.'     ` ' */
-	0x002E, 0x0020, 0,
+/* 
+ * 1) Valid characters for the 8.3 format alias are any combination of
+ * letters, uppercase alphabets, digits, any of the
+ * following special characters:
+ *     $ % ' ` - @ { } ~ ! # ( ) & _ ^
+ * In this case Longfilename is not stored in disk.
+ *
+ * WinNT's Extension:
+ * File name and extension name is contain uppercase/lowercase
+ * only. And it is expressed by CASE_LOWER_BASE and CASE_LOWER_EXT.
+ *     
+ * 2) File name is 8.3 format, but it contain the uppercase and
+ * lowercase char, muliti bytes char, etc. In this case numtail is not
+ * added, but Longfilename is stored.
+ * 
+ * 3) When the one except for the above, or the following special
+ * character are contained:
+ *        .   [ ] ; , + =
+ * numtail is added, and Longfilename must be stored in disk .
+ */
+struct shortname_info {
+	unsigned char lower:1,
+		      upper:1,
+		      valid:1;
 };
-#define IS_SKIPCHAR(uni) \
-	((wchar_t)(uni) == skip_chars[0] || (wchar_t)(uni) == skip_chars[1])
+#define INIT_SHORTNAME_INFO(x)	do {		\
+	(x)->lower = 1;				\
+	(x)->upper = 1;				\
+	(x)->valid = 1;				\
+} while (0);
 
-/* Given a valid longname, create a unique shortname.  Make sure the
+static inline unsigned char
+shortname_info_to_lcase(struct shortname_info *base,
+			struct shortname_info *ext)
+{
+	unsigned char lcase = 0;
+
+	if (base->valid && ext->valid) {
+		if (!base->upper && base->lower && (ext->lower || ext->upper))
+			lcase |= CASE_LOWER_BASE;
+		if (!ext->upper && ext->lower && (base->lower || base->upper))
+			lcase |= CASE_LOWER_EXT;
+	}
+
+	return lcase;
+}
+
+static inline int to_shortname_char(struct nls_table *nls,
+				    char *buf, int buf_size, wchar_t *src,
+				    struct shortname_info *info)
+{
+	int len;
+
+	if (IS_SKIPCHAR(*src)) {
+		info->valid = 0;
+		return 0;
+	}
+	if (IS_REPLACECHAR(*src)) {
+		info->valid = 0;
+		buf[0] = '_';
+		return 1;
+	}
+	
+	len = nls->uni2char(*src, buf, buf_size);
+	if (len <= 0) {
+		info->valid = 0;
+		buf[0] = '_';
+		len = 1;
+	} else if (len == 1) {
+		unsigned char prev = buf[0];
+
+		if (buf[0] >= 0x7F) {
+			info->lower = 0;
+			info->upper = 0;
+		}
+
+		buf[0] = vfat_toupper(nls, buf[0]);
+		if (isalpha(buf[0])) {
+			if (buf[0] == prev)
+				info->lower = 0;
+			else
+				info->upper = 0;
+		}
+	} else {
+		info->lower = 0;
+		info->upper = 0;
+	}
+	
+	return len;
+}
+
+/*
+ * Given a valid longname, create a unique shortname.  Make sure the
  * shortname does not exist
  * Returns negative number on error, 0 for a normal
  * return, and 1 for valid shortname
  */
 static int vfat_create_shortname(struct inode *dir, struct nls_table *nls,
 				 wchar_t *uname, int ulen,
-				 char *name_res)
+				 char *name_res, unsigned char *lcase)
 {
 	wchar_t *ip, *ext_start, *end, *name_start;
 	unsigned char base[9], ext[4], buf[8], *p;
 	unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
 	int chl, chi;
 	int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen;
-	int is_uppercase, is_shortname;
+	int is_shortname;
+	struct shortname_info base_info, ext_info;
+	unsigned short opt_shortname = MSDOS_SB(dir->i_sb)->options.shortname;
 
-	/* 
-	 * 1) Valid characters for the 8.3 format alias are any
-	 * combination of letters, uppercase alphabets, digits, any of
-	 * the following special characters:
-	 *     $ % ' ` - @ { } ~ ! # ( ) & _ ^
-	 * In this case Longfilename is not stored in disk.
-	 *     
-	 * 2) File name is 8.3 format, but it contain the lowercase
-	 * alphabet etc. In this case numtail is not added, but
-	 * Longfilename is stored.
-	 * 
-	 * 3) When the one except for the above, or the following special
-	 * character are contained:
-	 *        .   [ ] ; , + =
-	 * numtail is added, and Longfilename must be stored in disk .
-	 */
-	is_uppercase = 1;
 	is_shortname = 1;
+	INIT_SHORTNAME_INFO(&base_info);
+	INIT_SHORTNAME_INFO(&ext_info);
 
 	/* Now, we need to create a shortname from the long name */
 	ext_start = end = &uname[ulen];
@@ -662,31 +569,11 @@
 
 	numtail_baselen = 6;
 	numtail2_baselen = 2;
-	for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++)
-	{
-		if (IS_SKIPCHAR(*ip)) {
-			is_shortname = 0;
+	for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++) {
+		chl = to_shortname_char(nls, charbuf, sizeof(charbuf),
+					ip, &base_info);
+		if (chl == 0)
 			continue;
-		}
-		if (IS_REPLACECHAR(*ip)) {
-			is_shortname = 0;
-			charbuf[0] = '_';
-			chl = 1;
-		} else {
-			chl = nls->uni2char(*ip, charbuf, sizeof(charbuf));
-			if (chl <= 0) {
-				is_shortname = 0;
-				charbuf[0]  = '_';
-				chl = 1;
-			} else if (chl == 1) {
-				unsigned char c = charbuf[0];
-				charbuf[0] = vfat_toupper(nls, charbuf[0]);
-				if (c >= 0x7F || charbuf[0] != c)
-					is_uppercase = 0;
-			} else {
-				is_uppercase = 0;
-			}
-		}
 
 		if (baselen < 2 && (baselen + chl) > 2)
 			numtail2_baselen = baselen;
@@ -711,30 +598,11 @@
 	extlen = 0;
 	if (ext_start) {
 		for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
-			if (IS_SKIPCHAR(*ip)) {
-				is_shortname = 0;
+			chl = to_shortname_char(nls, charbuf, sizeof(charbuf),
+						ip, &ext_info);
+			if (chl == 0)
 				continue;
-			}
-			if (IS_REPLACECHAR(*ip)) {
-				is_shortname = 0;
-				charbuf[0] = '_';
-				chl = 1;
-			} else {
-				chl = nls->uni2char(*ip, charbuf, sizeof(charbuf));
-				if (chl <= 0) {
-					is_shortname = 0;
-					charbuf[0] = '_';
-					chl = 1;
-				} else if (chl == 1) {
-					unsigned char c = charbuf[0];
-					charbuf[0] = vfat_toupper(nls, charbuf[0]);
-					if (c >= 0x7F || charbuf[0] != c)
-						is_uppercase = 0;
-				} else {
-					is_uppercase = 0;
-				}
-			}
-				
+
 			if ((extlen + chl) > 3) {
 				is_shortname = 0;
 				break;
@@ -763,14 +631,26 @@
 	 */
 
 	memset(name_res, ' ', MSDOS_NAME);
-	memcpy(name_res,base,baselen);
-	memcpy(name_res+8,ext,extlen);
-
-	if (is_shortname) {
-		if (vfat_find_form(dir, name_res) < 0)
-			return is_uppercase;
-		else
+	memcpy(name_res, base, baselen);
+	memcpy(name_res + 8, ext, extlen);
+	*lcase = 0;
+	if (is_shortname && base_info.valid && ext_info.valid) {
+		if (vfat_find_form(dir, name_res) == 0)
 			return -EEXIST;
+
+		if (opt_shortname & VFAT_SFN_CREATE_WIN95) {
+			return (base_info.upper && ext_info.upper);
+		} else if (opt_shortname & VFAT_SFN_CREATE_WINNT) {
+			if ((base_info.upper || base_info.lower)
+			    && (ext_info.upper || ext_info.lower)) {
+				*lcase = shortname_info_to_lcase(&base_info,
+								 &ext_info);
+				return 1;
+			}
+			return 0;
+		} else {
+			BUG();
+		}
 	}
 	
 	if (MSDOS_SB(dir->i_sb)->options.numtail == 0)
@@ -866,7 +746,6 @@
 				} else {
 					if ((charlen = nls->char2uni(ip, len-i, (wchar_t *)op)) < 0)
 						return -EINVAL;
-
 					ip += charlen;
 					i += charlen;
 					op += 2;
@@ -904,31 +783,31 @@
 
 static int
 vfat_fill_slots(struct inode *dir, struct msdos_dir_slot *ds, const char *name,
-		int len, int *slots, int uni_xlate)
+		int len, int *slots, int is_dir, int uni_xlate)
 {
 	struct nls_table *nls_io, *nls_disk;
 	wchar_t *uname;
 	struct msdos_dir_slot *ps;
 	struct msdos_dir_entry *de;
 	unsigned long page;
-	unsigned char cksum;
-	const char *ip;
+	unsigned char cksum, lcase;
 	char *uniname, msdos_name[MSDOS_NAME];
 	int res, utf8, slot, ulen, unilen, i;
 	loff_t offset;
 
-	de = (struct msdos_dir_entry *) ds;
+	*slots = 0;
 	utf8 = MSDOS_SB(dir->i_sb)->options.utf8;
 	nls_io = MSDOS_SB(dir->i_sb)->nls_io;
 	nls_disk = MSDOS_SB(dir->i_sb)->nls_disk;
 
-	if (name[len-1] == '.') len--;
+	if (name[len-1] == '.')
+		len--;
 	if(!(page = __get_free_page(GFP_KERNEL)))
 		return -ENOMEM;
-	uniname = (char *) page;
 
+	uniname = (char *) page;
 	res = xlate_to_uni(name, len, uniname, &ulen, &unilen, uni_xlate,
-								utf8, nls_io);
+			   utf8, nls_io);
 	if (res < 0)
 		goto out_free;
 
@@ -937,15 +816,17 @@
 	if (res < 0)
 		goto out_free;
 
-	res = vfat_create_shortname(dir, nls_disk, uname, ulen, msdos_name);
+	res = vfat_create_shortname(dir, nls_disk, uname, ulen,
+				    msdos_name, &lcase);
 	if (res < 0)
 		goto out_free;
 	else if (res == 1) {
-		strncpy(de->name, msdos_name, MSDOS_NAME);
+		de = (struct msdos_dir_entry *)ds;
 		res = 0;
-		goto out_free;
+		goto shortname;
 	}
 
+	/* build the entry of long file name */
 	*slots = unilen / 13;
 	for (cksum = i = 0; i < 11; i++) {
 		cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i];
@@ -958,18 +839,26 @@
 		ps->reserved = 0;
 		ps->alias_checksum = cksum;
 		ps->start = 0;
-		offset = (slot - 1) * 26;
-		ip = &uniname[offset];
-		memcpy(ps->name0_4, ip, 10);
-		memcpy(ps->name5_10, ip+10, 12);
-		memcpy(ps->name11_12, ip+22, 4);
+		offset = (slot - 1) * 13;
+		fatwchar_to16(ps->name0_4, uname + offset, 5);
+		fatwchar_to16(ps->name5_10, uname + offset + 5, 6);
+		fatwchar_to16(ps->name11_12, uname + offset + 11, 2);
 	}
 	ds[0].id |= 0x40;
-
 	de = (struct msdos_dir_entry *) ps;
+
+shortname:
 	PRINTK3(("vfat_fill_slots 9\n"));
-	strncpy(de->name, msdos_name, MSDOS_NAME);
+	/* build the entry of 8.3 alias name */
 	(*slots)++;
+	strncpy(de->name, msdos_name, MSDOS_NAME);
+	de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
+	de->lcase = lcase;
+	de->adate = de->cdate = de->date = 0;
+	de->ctime_ms = de->ctime = de->time = 0;
+	de->start = 0;
+	de->starthi = 0;
+	de->size = 0;
 
 out_free:
 	free_page(page);
@@ -978,96 +867,92 @@
 
 /* We can't get "." or ".." here - VFS takes care of those cases */
 
-static int vfat_build_slots(struct inode *dir,const char *name,int len,
-     struct msdos_dir_slot *ds, int *slots)
+static int vfat_build_slots(struct inode *dir, const char *name, int len,
+			    struct msdos_dir_slot *ds, int *slots, int is_dir)
 {
 	int res, xlate;
 
 	xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate;
-	*slots = 1;
 	res = vfat_valid_longname(name, len, xlate);
 	if (res < 0)
 		return res;
-	return vfat_fill_slots(dir, ds, name, len, slots, xlate);
+
+	return vfat_fill_slots(dir, ds, name, len, slots, is_dir, xlate);
 }
 
 static int vfat_add_entry(struct inode *dir,struct qstr* qname,
-	int is_dir,struct vfat_slot_info *sinfo_out,
-	struct buffer_head **bh, struct msdos_dir_entry **de)
+			  int is_dir, struct vfat_slot_info *sinfo_out,
+			  struct buffer_head **bh, struct msdos_dir_entry **de)
 {
 	struct super_block *sb = dir->i_sb;
-	struct msdos_dir_slot *ps;
+	struct msdos_dir_slot *dir_slots;
 	loff_t offset;
-	struct msdos_dir_slot *ds;
 	int slots, slot;
-	int res;
-	struct msdos_dir_entry *de1;
-	struct buffer_head *bh1;
-	int ino;
-	int len;
+	int res, len;
+	struct msdos_dir_entry *dummy_de;
+	struct buffer_head *dummy_bh;
+	int dummy_ino;
 	loff_t dummy;
 
-	ds = (struct msdos_dir_slot *)
-	    kmalloc(sizeof(struct msdos_dir_slot)*MSDOS_SLOTS, GFP_KERNEL);
-	if (ds == NULL) return -ENOMEM;
+	dir_slots = (struct msdos_dir_slot *)
+	       kmalloc(sizeof(struct msdos_dir_slot) * MSDOS_SLOTS, GFP_KERNEL);
+	if (dir_slots == NULL)
+		return -ENOMEM;
 
 	len = qname->len;
 	while (len && qname->name[len-1] == '.')
 		len--;
 	res = fat_search_long(dir, qname->name, len,
-			(MSDOS_SB(sb)->options.name_check != 's') ||
-			!MSDOS_SB(sb)->options.posixfs,
-			&dummy, &dummy);
+			      (MSDOS_SB(sb)->options.name_check != 's')
+			      || !MSDOS_SB(sb)->options.posixfs,
+			      &dummy, &dummy);
 	if (res > 0) /* found */
 		res = -EEXIST;
 	if (res)
 		goto cleanup;
 
-	res = vfat_build_slots(dir, qname->name, len, ds, &slots);
+	res = vfat_build_slots(dir, qname->name, len,
+			       dir_slots, &slots, is_dir);
 	if (res < 0)
 		goto cleanup;
 
-	offset = fat_add_entries(dir, slots, &bh1, &de1, &ino);
+	/* build the empty directory entry of number of slots */
+	offset = fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_ino);
 	if (offset < 0) {
 		res = offset;
 		goto cleanup;
 	}
-	fat_brelse(sb, bh1);
+	fat_brelse(sb, dummy_bh);
 
 	/* Now create the new entry */
 	*bh = NULL;
-	for (slot = 0, ps = ds; slot < slots; slot++, ps++) {
-		if (fat_get_entry(dir,&offset,bh,de, &sinfo_out->ino) < 0) {
+	for (slot = 0; slot < slots; slot++) {
+		if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->ino) < 0) {
 			res = -EIO;
 			goto cleanup;
 		}
-		memcpy(*de, ps, sizeof(struct msdos_dir_slot));
+		memcpy(*de, dir_slots + slot, sizeof(struct msdos_dir_slot));
 		fat_mark_buffer_dirty(sb, *bh);
 	}
 
+	res = 0;
+	/* update timestamp */
 	dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
 	mark_inode_dirty(dir);
 
-	fat_date_unix2dos(dir->i_mtime,&(*de)->time,&(*de)->date);
-	(*de)->ctime_ms = 0;
+	fat_date_unix2dos(dir->i_mtime, &(*de)->time, &(*de)->date);
 	(*de)->ctime = (*de)->time;
 	(*de)->adate = (*de)->cdate = (*de)->date;
-	(*de)->start = 0;
-	(*de)->starthi = 0;
-	(*de)->size = 0;
-	(*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
-	(*de)->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT;
-
 
 	fat_mark_buffer_dirty(sb, *bh);
 
 	/* slots can't be less than 1 */
 	sinfo_out->long_slots = slots - 1;
-	sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;
-	res = 0;
+	sinfo_out->longname_offset =
+		offset - sizeof(struct msdos_dir_slot) * slots;
 
 cleanup:
-	kfree(ds);
+	kfree(dir_slots);
 	return res;
 }
 
diff -u --recursive --new-file v2.4.12/linux/fs/vfat/vfatfs_syms.c linux/fs/vfat/vfatfs_syms.c
--- v2.4.12/linux/fs/vfat/vfatfs_syms.c	Mon Mar 13 12:35:39 2000
+++ linux/fs/vfat/vfatfs_syms.c	Fri Oct 12 13:48:42 2001
@@ -5,8 +5,6 @@
  * These symbols are used by dmsdos.
  */
 
-#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-alpha/bitops.h linux/include/asm-alpha/bitops.h
--- v2.4.12/linux/include/asm-alpha/bitops.h	Thu May 24 15:20:18 2001
+++ linux/include/asm-alpha/bitops.h	Fri Oct 12 15:35:54 2001
@@ -20,7 +20,7 @@
  * bit 0 is the LSB of addr; bit 64 is the LSB of (addr+1).
  */
 
-extern __inline__ void
+static inline void
 set_bit(unsigned long nr, volatile void * addr)
 {
 	unsigned long temp;
@@ -41,7 +41,7 @@
 /*
  * WARNING: non atomic version.
  */
-extern __inline__ void
+static inline void
 __set_bit(unsigned long nr, volatile void * addr)
 {
 	int *m = ((int *) addr) + (nr >> 5);
@@ -52,7 +52,7 @@
 #define smp_mb__before_clear_bit()	smp_mb()
 #define smp_mb__after_clear_bit()	smp_mb()
 
-extern __inline__ void
+static inline void
 clear_bit(unsigned long nr, volatile void * addr)
 {
 	unsigned long temp;
@@ -81,7 +81,7 @@
 	*m ^= 1 << (nr & 31);
 }
 
-extern __inline__ void
+static inline void
 change_bit(unsigned long nr, volatile void * addr)
 {
 	unsigned long temp;
@@ -99,7 +99,7 @@
 	:"Ir" (1UL << (nr & 31)), "m" (*m));
 }
 
-extern __inline__ int
+static inline int
 test_and_set_bit(unsigned long nr, volatile void *addr)
 {
 	unsigned long oldbit;
@@ -129,7 +129,7 @@
 /*
  * WARNING: non atomic version.
  */
-extern __inline__ int
+static inline int
 __test_and_set_bit(unsigned long nr, volatile void * addr)
 {
 	unsigned long mask = 1 << (nr & 0x1f);
@@ -140,7 +140,7 @@
 	return (old & mask) != 0;
 }
 
-extern __inline__ int
+static inline int
 test_and_clear_bit(unsigned long nr, volatile void * addr)
 {
 	unsigned long oldbit;
@@ -170,7 +170,7 @@
 /*
  * WARNING: non atomic version.
  */
-extern __inline__ int
+static inline int
 __test_and_clear_bit(unsigned long nr, volatile void * addr)
 {
 	unsigned long mask = 1 << (nr & 0x1f);
@@ -195,7 +195,7 @@
 	return (old & mask) != 0;
 }
 
-extern __inline__ int
+static inline int
 test_and_change_bit(unsigned long nr, volatile void * addr)
 {
 	unsigned long oldbit;
@@ -220,7 +220,7 @@
 	return oldbit != 0;
 }
 
-extern __inline__ int
+static inline int
 test_bit(int nr, volatile void * addr)
 {
 	return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL;
@@ -233,7 +233,7 @@
  * Do a binary search on the bits.  Due to the nature of large
  * constants on the alpha, it is worthwhile to split the search.
  */
-extern inline unsigned long ffz_b(unsigned long x)
+static inline unsigned long ffz_b(unsigned long x)
 {
 	unsigned long sum = 0;
 
@@ -245,7 +245,7 @@
 	return sum;
 }
 
-extern inline unsigned long ffz(unsigned long word)
+static inline unsigned long ffz(unsigned long word)
 {
 #if defined(__alpha_cix__) && defined(__alpha_fix__)
 	/* Whee.  EV67 can calculate it directly.  */
@@ -272,12 +272,32 @@
  * differs in spirit from the above ffz (man ffs).
  */
 
-extern inline int ffs(int word)
+static inline int ffs(int word)
 {
 	int result = ffz(~word);
 	return word ? result+1 : 0;
 }
 
+/* Compute powers of two for the given integer.  */
+static inline int floor_log2(unsigned long word)
+{
+	long bit;
+#if defined(__alpha_cix__) && defined(__alpha_fix__)
+	__asm__("ctlz %1,%0" : "=r"(bit) : "r"(word));
+	return 63 - bit;
+#else
+	for (bit = -1; word ; bit++)
+		word >>= 1;
+	return bit;
+#endif
+}
+
+static inline int ceil_log2(unsigned int word)
+{
+	long bit = floor_log2(word);
+	return bit + (word > (1UL << bit));
+}
+
 /*
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
@@ -285,7 +305,7 @@
 
 #if defined(__alpha_cix__) && defined(__alpha_fix__)
 /* Whee.  EV67 can calculate it directly.  */
-extern __inline__ unsigned long hweight64(unsigned long w)
+static inline unsigned long hweight64(unsigned long w)
 {
 	unsigned long result;
 	__asm__("ctpop %1,%0" : "=r"(result) : "r"(w));
@@ -306,7 +326,7 @@
 /*
  * Find next zero bit in a bitmap reasonably efficiently..
  */
-extern inline unsigned long
+static inline unsigned long
 find_next_zero_bit(void * addr, unsigned long size, unsigned long offset)
 {
 	unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
diff -u --recursive --new-file v2.4.12/linux/include/asm-alpha/core_cia.h linux/include/asm-alpha/core_cia.h
--- v2.4.12/linux/include/asm-alpha/core_cia.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-alpha/core_cia.h	Fri Oct 12 15:35:54 2001
@@ -263,6 +263,9 @@
 #define PYXIS_IIC_CTRL			(IDENT_ADDR + 0x87A00002C0UL)
 #define PYXIS_RESET			(IDENT_ADDR + 0x8780000900UL)
 
+/* Offset between ram physical addresses and pci64 DAC bus addresses.  */
+#define PYXIS_DAC_OFFSET		(1UL << 40)
+
 /*
  * Data structure for handling CIA machine checks.
  */
diff -u --recursive --new-file v2.4.12/linux/include/asm-alpha/core_mcpcia.h linux/include/asm-alpha/core_mcpcia.h
--- v2.4.12/linux/include/asm-alpha/core_mcpcia.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-alpha/core_mcpcia.h	Fri Oct 12 15:35:54 2001
@@ -181,6 +181,8 @@
 #define MCPCIA_IO_BIAS		MCPCIA_IO(4)
 #define MCPCIA_MEM_BIAS		MCPCIA_DENSE(4)
 
+/* Offset between ram physical addresses and pci64 DAC bus addresses.  */
+#define MCPCIA_DAC_OFFSET	(1UL << 40)
 
 /*
  * Data structure for handling MCPCIA machine checks:
diff -u --recursive --new-file v2.4.12/linux/include/asm-alpha/core_titan.h linux/include/asm-alpha/core_titan.h
--- v2.4.12/linux/include/asm-alpha/core_titan.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-alpha/core_titan.h	Fri Oct 12 15:35:54 2001
@@ -308,14 +308,18 @@
  * devices can use their familiar numbers and have them map to bus 0.
  */
 
-#define TITAN_IO_BIAS          TITAN_IO(0)
-#define TITAN_MEM_BIAS         TITAN_MEM(0)
+#define TITAN_IO_BIAS		TITAN_IO(0)
+#define TITAN_MEM_BIAS		TITAN_MEM(0)
 
 /* The IO address space is larger than 0xffff */
 #define TITAN_IO_SPACE		(TITAN_CONF(0) - TITAN_IO(0))
 
 /* TIG Space */
 #define TITAN_TIG_SPACE		(TITAN_BASE + 0x100000000UL)
+
+/* Offset between ram physical addresses and pci64 DAC bus addresses.  */
+/* ??? Just a guess.  Ought to confirm it hasn't been moved.  */
+#define TITAN_DAC_OFFSET	(1UL << 40)
 
 /*
  * Data structure for handling TITAN machine checks:
diff -u --recursive --new-file v2.4.12/linux/include/asm-alpha/core_tsunami.h linux/include/asm-alpha/core_tsunami.h
--- v2.4.12/linux/include/asm-alpha/core_tsunami.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-alpha/core_tsunami.h	Fri Oct 12 15:35:54 2001
@@ -275,7 +275,7 @@
 /* The IO address space is larger than 0xffff */
 #define TSUNAMI_IO_SPACE	(TSUNAMI_CONF(0) - TSUNAMI_IO(0))
 
-/* Offset between ram physical addresses and pci64 DAC bus addresses */
+/* Offset between ram physical addresses and pci64 DAC bus addresses.  */
 #define TSUNAMI_DAC_OFFSET	(1UL << 40)
 
 /*
diff -u --recursive --new-file v2.4.12/linux/include/asm-alpha/machvec.h linux/include/asm-alpha/machvec.h
--- v2.4.12/linux/include/asm-alpha/machvec.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-alpha/machvec.h	Fri Oct 12 15:35:54 2001
@@ -39,6 +39,7 @@
 	unsigned long iack_sc;
 	unsigned long min_io_address;
 	unsigned long min_mem_address;
+	unsigned long pci_dac_offset;
 
 	void (*mv_pci_tbi)(struct pci_controller *hose,
 			   dma_addr_t start, dma_addr_t end);
diff -u --recursive --new-file v2.4.12/linux/include/asm-alpha/pci.h linux/include/asm-alpha/pci.h
--- v2.4.12/linux/include/asm-alpha/pci.h	Mon May 21 13:38:41 2001
+++ linux/include/asm-alpha/pci.h	Fri Oct 12 15:35:54 2001
@@ -15,6 +15,7 @@
 struct pci_bus;
 struct resource;
 struct pci_iommu_arena;
+struct page;
 
 /* A controller.  Used to manage multiple PCI busses.  */
 
@@ -60,12 +61,17 @@
 
 /* IOMMU controls.  */
 
+/* The PCI address space does not equal the physical memory address space.
+   The networking and block device layers use this boolean for bounce buffer
+   decisions.  */
+#define PCI_DMA_BUS_IS_PHYS  0
+
 /* Allocate and map kernel buffer using consistant mode DMA for PCI
    device.  Returns non-NULL cpu-view pointer to the buffer if
    successful and sets *DMA_ADDRP to the pci side dma address as well,
    else DMA_ADDRP is undefined.  */
 
-extern void *pci_alloc_consistent(struct pci_dev *, long, dma_addr_t *);
+extern void *pci_alloc_consistent(struct pci_dev *, size_t, dma_addr_t *);
 
 /* Free and unmap a consistant DMA buffer.  CPU_ADDR and DMA_ADDR must
    be values that were returned from pci_alloc_consistant.  SIZE must
@@ -73,14 +79,18 @@
    References to the memory and mappings assosciated with CPU_ADDR or
    DMA_ADDR past this call are illegal.  */
 
-extern void pci_free_consistent(struct pci_dev *, long, void *, dma_addr_t);
+extern void pci_free_consistent(struct pci_dev *, size_t, void *, dma_addr_t);
 
 /* Map a single buffer of the indicate size for PCI DMA in streaming
    mode.  The 32-bit PCI bus mastering address to use is returned.
    Once the device is given the dma address, the device owns this memory
    until either pci_unmap_single or pci_dma_sync_single is performed.  */
 
-extern dma_addr_t pci_map_single(struct pci_dev *, void *, long, int);
+extern dma_addr_t pci_map_single(struct pci_dev *, void *, size_t, int);
+
+/* Likewise, but for a page instead of an address.  */
+extern dma_addr_t pci_map_page(struct pci_dev *, struct page *,
+			       unsigned long, size_t, int);
 
 /* Unmap a single streaming mode DMA translation.  The DMA_ADDR and
    SIZE must match what was provided for in a previous pci_map_single
@@ -88,7 +98,8 @@
    the cpu to the buffer are guarenteed to see whatever the device
    wrote there.  */
 
-extern void pci_unmap_single(struct pci_dev *, dma_addr_t, long, int);
+extern void pci_unmap_single(struct pci_dev *, dma_addr_t, size_t, int);
+extern void pci_unmap_page(struct pci_dev *, dma_addr_t, size_t, int);
 
 /* Map a set of buffers described by scatterlist in streaming mode for
    PCI DMA.  This is the scather-gather version of the above
@@ -121,7 +132,7 @@
    point you give the PCI dma address back to the card, the device
    again owns the buffer.  */
 
-extern inline void
+static inline void
 pci_dma_sync_single(struct pci_dev *dev, dma_addr_t dma_addr, long size,
 		    int direction)
 {
@@ -132,7 +143,7 @@
    translations after a transfer.  The same as pci_dma_sync_single but
    for a scatter-gather list, same rules and usage.  */
 
-extern inline void
+static inline void
 pci_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sg, int nents,
 	        int direction)
 {
@@ -144,7 +155,22 @@
    only drive the low 24-bits during PCI bus mastering, then
    you would pass 0x00ffffff as the mask to this function.  */
 
-extern int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask);
+extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask);
+
+/* True if the machine supports DAC addressing, and DEV can
+   make use of it given MASK.  */
+extern int pci_dac_dma_supported(struct pci_dev *hwdev, u64 mask);
+
+/* Convert to/from DAC dma address and struct page.  */
+extern dma64_addr_t pci_dac_page_to_dma(struct pci_dev *, struct page *, unsigned long, int);
+extern struct page *pci_dac_dma_to_page(struct pci_dev *, dma64_addr_t);
+extern unsigned long pci_dac_dma_to_offset(struct pci_dev *, dma64_addr_t);
+
+static __inline__ void
+pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+{
+	/* Nothing to do. */
+}
 
 /* Return the index of the PCI controller for device PDEV. */
 extern int pci_controller_num(struct pci_dev *pdev);
diff -u --recursive --new-file v2.4.12/linux/include/asm-alpha/scatterlist.h linux/include/asm-alpha/scatterlist.h
--- v2.4.12/linux/include/asm-alpha/scatterlist.h	Mon Feb  7 20:09:05 2000
+++ linux/include/asm-alpha/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -1,19 +1,25 @@
 #ifndef _ALPHA_SCATTERLIST_H
 #define _ALPHA_SCATTERLIST_H
 
-#include <linux/types.h>
-
+#include <asm/page.h>
+  
 struct scatterlist {
-	char *address;			/* Source/target vaddr.  */
-	char *alt_address;		/* Location of actual if address is a
-					   dma indirect buffer, else NULL.  */
-	dma_addr_t dma_address;
+	/* This will disappear in 2.5.x */
+	char *address;
+
+	/* These two are only valid if ADDRESS member of this
+	   struct is NULL.  */
+	struct page *page;
+	unsigned int offset;
+
 	unsigned int length;
-	unsigned int dma_length;
+
+	dma_addr_t dma_address;
+	__u32 dma_length;
 };
 
-#define sg_dma_address(sg) ((sg)->dma_address)
-#define sg_dma_len(sg)     ((sg)->dma_length)
+#define sg_dma_address(sg)	((sg)->dma_address)
+#define sg_dma_len(sg)		((sg)->dma_length)
 
 #define ISA_DMA_THRESHOLD (~0UL)
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-alpha/types.h linux/include/asm-alpha/types.h
--- v2.4.12/linux/include/asm-alpha/types.h	Mon Feb  7 20:09:05 2000
+++ linux/include/asm-alpha/types.h	Fri Oct 12 15:35:54 2001
@@ -47,10 +47,8 @@
 
 #define BITS_PER_LONG 64
 
-/* PCI dma addresses are 32-bits wide.  Ignore PCI64 for now, since
-   we'll typically be sending it all through iommu tables anyway.  */
-
-typedef u32 dma_addr_t;
+typedef u64 dma_addr_t;
+typedef u64 dma64_addr_t;
 
 #endif /* __KERNEL__ */
 #endif /* _ALPHA_TYPES_H */
diff -u --recursive --new-file v2.4.12/linux/include/asm-alpha/vga.h linux/include/asm-alpha/vga.h
--- v2.4.12/linux/include/asm-alpha/vga.h	Fri Mar 17 13:01:38 2000
+++ linux/include/asm-alpha/vga.h	Mon Oct 15 13:47:28 2001
@@ -12,7 +12,6 @@
 #define VT_BUF_HAVE_RW
 #define VT_BUF_HAVE_MEMSETW
 #define VT_BUF_HAVE_MEMCPYW
-#define VT_BUF_HAVE_MEMCPYF
 
 extern inline void scr_writew(u16 val, volatile u16 *addr)
 {
@@ -40,8 +39,6 @@
 
 /* Do not trust that the usage will be correct; analyze the arguments.  */
 extern void scr_memcpyw(u16 *d, const u16 *s, unsigned int count);
-#define scr_memcpyw_from scr_memcpyw
-#define scr_memcpyw_to   scr_memcpyw
 
 /* ??? These are currently only used for downloading character sets.  As
    such, they don't need memory barriers.  Is this all they are intended
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/a.out.h linux/include/asm-arm/a.out.h
--- v2.4.12/linux/include/asm-arm/a.out.h	Sun Aug 13 09:54:15 2000
+++ linux/include/asm-arm/a.out.h	Thu Oct 11 09:04:57 2001
@@ -1,6 +1,7 @@
 #ifndef __ARM_A_OUT_H__
 #define __ARM_A_OUT_H__
 
+#include <linux/personality.h>
 #include <asm/types.h>
 
 struct exec
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/arch-sa1100/SA-1111.h linux/include/asm-arm/arch-sa1100/SA-1111.h
--- v2.4.12/linux/include/asm-arm/arch-sa1100/SA-1111.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/arch-sa1100/SA-1111.h	Thu Oct 11 09:04:57 2001
@@ -42,15 +42,15 @@
  *    SKID	ID Register
  */
 
-#define _SKCR		_SA1111( 0x0000 )
-#define _SMCR		_SA1111( 0x0004 )
-#define _SKID		_SA1111( 0x0008 )
+#define _SBI_SKCR	_SA1111( 0x0000 )
+#define _SBI_SMCR	_SA1111( 0x0004 )
+#define _SBI_SKID	_SA1111( 0x0008 )
 
 #if LANGUAGE == C
 
-#define SKCR		(*((volatile Word *) SA1111_p2v (_SKCR)))
-#define SMCR		(*((volatile Word *) SA1111_p2v (_SMCR)))
-#define SKID		(*((volatile Word *) SA1111_p2v (_SKID)))
+#define SBI_SKCR	(*((volatile Word *) SA1111_p2v (_SBI_SKCR)))
+#define SBI_SMCR	(*((volatile Word *) SA1111_p2v (_SBI_SMCR)))
+#define SBI_SKID	(*((volatile Word *) SA1111_p2v (_SBI_SKID)))
 
 #endif  /* LANGUAGE == C */
 
@@ -66,6 +66,18 @@
 #define SKCR_OPPC	(1<<9)
 #define SKCR_PLLTSTEN	(1<<10)
 #define SKCR_USBIOTSTEN	(1<<11)
+/*
+ * Don't believe the specs!  Take them, throw them outside.  Leave them
+ * there for a week.  Spit on them.  Walk on them.  Stamp on them.
+ * Pour gasoline over them and finally burn them.  Now think about coding.
+ *  - The October 1999 errata (278260-007) says its bit 13, 1 to enable.
+ *  - The Feb 2001 errata (278260-010) says that the previous errata
+ *    (278260-009) is wrong, and its bit actually 12, fixed in spec
+ *    278242-003.
+ *  - The SA1111 manual (278242) says bit 12, but 0 to enable.
+ *  - Reality is bit 13, 1 to enable.
+ *      -- rmk
+ */
 #define SKCR_OE_EN	(1<<13)
 
 #define SMCR_DTIM	(1<<0)
@@ -129,6 +141,34 @@
 #define SKPCR_PTCLKEN	(1<<6)
 #define SKPCR_DCLKEN	(1<<7)
 #define SKPCR_PWMCLKEN	(1<<8)
+
+/*
+ * USB Host controller
+ */
+#define _USB_OHCI_OP_BASE	_SA1111( 0x400 )
+#define _USB_STATUS		_SA1111( 0x518 )
+#define _USB_RESET		_SA1111( 0x51c )
+#define _USB_INTERRUPTEST	_SA1111( 0x520 )
+
+#define _USB_EXTENT		(_USB_INTERRUPTEST - _USB_OHCI_OP_BASE + 4)
+
+#if LANGUAGE == C
+
+#define USB_OHCI_OP_BASE	(*((volatile Word *) SA1111_p2v (_USB_OHCI_OP_BASE)))
+#define USB_STATUS		(*((volatile Word *) SA1111_p2v (_USB_STATUS)))
+#define USB_RESET		(*((volatile Word *) SA1111_p2v (_USB_RESET)))
+#define USB_INTERRUPTEST	(*((volatile Word *) SA1111_p2v (_USB_INTERRUPTEST)))
+
+#endif  /* LANGUAGE == C */
+
+#define USB_RESET_FORCEIFRESET	(1 << 0)
+#define USB_RESET_FORCEHCRESET	(1 << 1)
+#define USB_RESET_CLKGENRESET	(1 << 2)
+#define USB_RESET_SIMSCALEDOWN	(1 << 3)
+#define USB_RESET_USBINTTEST	(1 << 4)
+#define USB_RESET_SLEEPSTBYEN	(1 << 5)
+#define USB_RESET_PWRSENSELOW	(1 << 6)
+#define USB_RESET_PWRCTRLLOW	(1 << 7)
 
 /*
  * Serial Audio Controller
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/arch-sa1100/adsbitsy.h linux/include/asm-arm/arch-sa1100/adsbitsy.h
--- v2.4.12/linux/include/asm-arm/arch-sa1100/adsbitsy.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/adsbitsy.h	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,14 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/adsbitsy.h
+ *
+ * Created 7/3/01 by Woojung <whuh@applieddata.net>
+ *
+ * This file contains the hardware specific definitions for the
+ * ADS Bitsy Board
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#error "include <asm/hardware.h> instead"
+#endif
+
+#define	SA1111_BASE		(0x18000000)
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/arch-sa1100/assabet.h linux/include/asm-arm/arch-sa1100/assabet.h
--- v2.4.12/linux/include/asm-arm/arch-sa1100/assabet.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/arch-sa1100/assabet.h	Thu Oct 11 09:04:57 2001
@@ -38,7 +38,7 @@
 #define BCR_DB1111 \
 	(BCR_SPK_OFF  | BCR_QMUTE     | BCR_LED_GREEN  | BCR_LED_RED   | \
 	 BCR_RS232EN  | BCR_LCD_12RGB | BCR_CF_BUS_OFF | BCR_STEREO_LB | \
-	 BCR_IRDA_MD1 | BCR_CF_RST)
+	 BCR_IRDA_MD0 | BCR_CF_RST)
 
 #define BCR_CF_PWR	(1<<0)	/* Compact Flash Power (1 = 3.3v, 0 = off) */
 #define BCR_CF_RST	(1<<1)	/* Compact Flash Reset (1 = power up reset) */
@@ -183,6 +183,10 @@
 #define NCR_A1VPP		(1<<6)
 
 #ifndef __ASSEMBLY__
+#ifdef CONFIG_ASSABET_NEPONSET
 #define machine_has_neponset()  ((SCR_value & SCR_SA1111) == 0)
+#else
+#define machine_has_neponset()	(0)
+#endif
 #endif
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/arch-sa1100/bitsy.h linux/include/asm-arm/arch-sa1100/bitsy.h
--- v2.4.12/linux/include/asm-arm/arch-sa1100/bitsy.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/arch-sa1100/bitsy.h	Wed Dec 31 16:00:00 1969
@@ -1,81 +0,0 @@
-/*
-*
-* Definitions for H3600 Handheld Computer
-*
-* Copyright 2000 Compaq Computer Corporation.
-*
-* Use consistent with the GNU GPL is permitted,
-* provided that this copyright notice is
-* preserved in its entirety in all copies and derived works.
-*
-* COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
-* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
-* FITNESS FOR ANY PARTICULAR PURPOSE.
-*
-* Author: Jamey Hicks.
-*
-*/
-
-#ifndef _INCLUDE_BITSY_H_
-#define _INCLUDE_BITSY_H_
-
-#define GPIO_BITSY_NPOWER_BUTTON	GPIO_GPIO (0)
-#define GPIO_BITSY_ACTION_BUTTON	GPIO_GPIO (18)
-
-#define GPIO_BITSY_PCMCIA_CD0		GPIO_GPIO (17)
-#define GPIO_BITSY_PCMCIA_CD1		GPIO_GPIO (10)
-#define GPIO_BITSY_PCMCIA_IRQ0		GPIO_GPIO (21)
-#define GPIO_BITSY_PCMCIA_IRQ1		GPIO_GPIO (11)
-
-/* audio sample rate clock generator */
-#define GPIO_BITSY_CLK_SET0		GPIO_GPIO (12)
-#define GPIO_BITSY_CLK_SET1		GPIO_GPIO (13)
-
-/* UDA1341 L3 Interface */
-#define GPIO_BITSY_L3_DATA		GPIO_GPIO (14)
-#define GPIO_BITSY_L3_CLOCK		GPIO_GPIO (16)
-#define GPIO_BITSY_L3_MODE		GPIO_GPIO (15)
-
-#define GPIO_BITSY_OPT_LOCK		GPIO_GPIO (22)
-#define GPIO_BITSY_OPT_IRQ		GPIO_GPIO (24)
-#define GPIO_BITSY_OPT_DET		GPIO_GPIO (27)
-
-#define GPIO_BITSY_COM_DCD		GPIO_GPIO (23)
-#define GPIO_BITSY_COM_CTS		GPIO_GPIO (25)
-#define GPIO_BITSY_COM_RTS		GPIO_GPIO (26)
-
-#define IRQ_GPIO_BITSY_NPOWER_BUTTON    IRQ_GPIO0
-#define IRQ_GPIO_BITSY_ACTION_BUTTON    IRQ_GPIO18
-#define IRQ_GPIO_BITSY_PCMCIA_CD0	IRQ_GPIO17
-#define IRQ_GPIO_BITSY_PCMCIA_CD1	IRQ_GPIO10
-#define IRQ_GPIO_BITSY_PCMCIA_IRQ0	IRQ_GPIO21
-#define IRQ_GPIO_BITSY_PCMCIA_IRQ1	IRQ_GPIO11
-#define IRQ_GPIO_BITSY_OPT_IRQ		IRQ_GPIO24
-#define IRQ_GPIO_BITSY_OPT_DET		IRQ_GPIO27
-#define IRQ_GPIO_BITSY_COM_DCD          IRQ_GPIO23
-#define IRQ_GPIO_BITSY_COM_CTS          IRQ_GPIO25
-
-#define EGPIO_BITSY_VPP_ON		(1 << 0)
-#define EGPIO_BITSY_CARD_RESET		(1 << 1)  /* reset the attached pcmcia/compactflash card.  active high. */
-#define EGPIO_BITSY_OPT_RESET		(1 << 2)  /* reset the attached option pack.  active high. */
-#define EGPIO_BITSY_CODEC_NRESET	(1 << 3)  /* reset the onboard UDA1341.  active low. */
-#define EGPIO_BITSY_OPT_NVRAM_ON	(1 << 4)  /* apply power to optionpack nvram, active high. */
-#define EGPIO_BITSY_OPT_ON		(1 << 5)  /* full power to option pack.  active high. */
-#define EGPIO_BITSY_LCD_ON       	(1 << 6)  /* enable 3.3V to LCD.  active high. */
-#define EGPIO_BITSY_RS232_ON		(1 << 7)  /* UART3 transceiver force on.  Active high. */
-#define EGPIO_BITSY_LCD_PCI		(1 << 8)  /* LCD control IC enable.  active high. */
-#define EGPIO_BITSY_IR_ON		(1 << 9)  /* apply power to IR module.  active high. */
-#define EGPIO_BITSY_AUD_AMP_ON		(1 << 10) /* apply power to audio power amp.  active high. */
-#define EGPIO_BITSY_AUD_PWR_ON		(1 << 11) /* apply poewr to reset of audio circuit.  active high. */
-#define EGPIO_BITSY_QMUTE		(1 << 12) /* mute control for onboard UDA1341.  active high. */
-#define EGPIO_BITSY_IR_FSEL		(1 << 13) /* IR speed select: 1->fast, 0->slow */
-#define EGPIO_BITSY_LCD_5V_ON		(1 << 14) /* enable 5V to LCD. active high. */
-#define EGPIO_BITSY_LVDD_ON		(1 << 15) /* enable 9V and -6.5V to LCD. */
-
-#ifndef __ASSEMBLY__
-#define BITSY_EGPIO	(*(volatile int *)0xf0000000)
-extern void clr_bitsy_egpio(unsigned long x);
-extern void set_bitsy_egpio(unsigned long x);
-#endif
-
-#endif
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/arch-sa1100/dma.h linux/include/asm-arm/arch-sa1100/dma.h
--- v2.4.12/linux/include/asm-arm/arch-sa1100/dma.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/arch-sa1100/dma.h	Thu Oct 11 09:04:57 2001
@@ -109,8 +109,13 @@
 static inline void
 __arch_adjust_zones(int node, unsigned long *size, unsigned long *holes)
 {
-	size[1] = size[0] - 256;
-	size[0] = 256;
+	unsigned int sz = 256;
+
+	if (node != 0)
+		sz = 0;
+
+	size[1] = size[0] - sz;
+	size[0] = sz;
 }
 
 #define arch_adjust_zones(node,size,holes) __arch_adjust_zones(node,size,holes)
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/arch-sa1100/graphicsmaster.h linux/include/asm-arm/arch-sa1100/graphicsmaster.h
--- v2.4.12/linux/include/asm-arm/arch-sa1100/graphicsmaster.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/graphicsmaster.h	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,66 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/graphicsmaster.h
+ *
+ * Created 2000/12/18 by Woojung Huh <whuh@applieddata.net>
+ *
+ * This file comes from graphicsclient.h of Nicolas Pitre <nico@cam.org>
+ *
+ * This file contains the hardware specific definitions for the
+ * ADS GraphicsMaster
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#error "include <asm/hardware.h> instead"
+#endif
+
+#define ADS_CPLD_BASE		(0x10000000)
+#define ADS_p2v( x )		((x) - ADS_CPLD_BASE + 0xf0000000)
+#define ADS_v2p( x )		((x) - 0xf0000000 + ADS_CPLD_BASE)
+
+
+#define _ADS_SW_SWITCHES	0x10060000	/* Software Switches */
+
+/* Extra IRQ Controller */
+#define _ADS_INT_ST1		0x10080000	/* IRQ Status #1 */
+#define _ADS_INT_ST2		0x10080004	/* IRQ Status #2 */
+#define _ADS_INT_EN1		0x10080008	/* IRQ Enable #1 */
+#define _ADS_INT_EN2		0x1008000c	/* IRQ Enable #2 */
+#define _ADS_DCR			0x10080018	/* Discrete Control Reg */
+
+/* Discrete Controller (AVR:Atmel AT90LS8535) */
+#define _ADS_AVR_REG		0x10080018
+
+/* On-Board Ethernet */
+#define _ADS_ETHERNET		0x100e0000	/* Ethernet */
+
+/* On-Board Quad UART 16C554 */
+#define	ADS_QUAD_UART1		0x10100000
+#define	ADS_QUAD_UART2		0x10120000
+#define	ADS_QUAD_UART3		0x10140000
+#define	ADS_QUAD_UART4		0x10160000
+
+/* LEDs */
+#define ADS_LED0	GPIO_GPIO20		/* on-board Green */
+#define ADS_LED1	GPIO_GPIO25		/* on-board Yellow */
+#define ADS_LED2	GPIO_GPIO26		/* on-board Red */
+
+/* DCR */
+#define DCR_AVR_RESET		0x01
+#define DCR_SA1111_RESET	0x02
+#define	DCR_BACKLITE_ON		0x04
+
+/* Virtual register addresses */
+
+#ifndef __ASSEMBLY__
+#define ADS_INT_ST1	(*((volatile u_char *) ADS_p2v(_ADS_INT_ST1)))
+#define ADS_INT_ST2	(*((volatile u_char *) ADS_p2v(_ADS_INT_ST2)))
+#define ADS_INT_EN1	(*((volatile u_char *) ADS_p2v(_ADS_INT_EN1)))
+#define ADS_INT_EN2	(*((volatile u_char *) ADS_p2v(_ADS_INT_EN2)))
+#define ADS_ETHERNET	((int) ADS_p2v(_ADS_ETHERNET))
+#define ADS_AVR_REG	(*((volatile u_char *) ADS_p2v(_ADS_AVR_REG)))
+#define ADS_DCR		(*((volatile u_char *) ADS_p2v(_ADS_DCR)))
+#endif
+
+#define	SA1111_BASE	(0x18000000)
+
+#include "SA-1111.h"
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/arch-sa1100/h3600.h linux/include/asm-arm/arch-sa1100/h3600.h
--- v2.4.12/linux/include/asm-arm/arch-sa1100/h3600.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/h3600.h	Thu Oct 11 09:04:57 2001
@@ -0,0 +1,81 @@
+/*
+*
+* Definitions for H3600 Handheld Computer
+*
+* Copyright 2000 Compaq Computer Corporation.
+*
+* Use consistent with the GNU GPL is permitted,
+* provided that this copyright notice is
+* preserved in its entirety in all copies and derived works.
+*
+* COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+* FITNESS FOR ANY PARTICULAR PURPOSE.
+*
+* Author: Jamey Hicks.
+*
+*/
+
+#ifndef _INCLUDE_H3600_H_
+#define _INCLUDE_H3600_H_
+
+#define GPIO_H3600_NPOWER_BUTTON	GPIO_GPIO (0)
+#define GPIO_H3600_ACTION_BUTTON	GPIO_GPIO (18)
+
+#define GPIO_H3600_PCMCIA_CD0		GPIO_GPIO (17)
+#define GPIO_H3600_PCMCIA_CD1		GPIO_GPIO (10)
+#define GPIO_H3600_PCMCIA_IRQ0		GPIO_GPIO (21)
+#define GPIO_H3600_PCMCIA_IRQ1		GPIO_GPIO (11)
+
+/* audio sample rate clock generator */
+#define GPIO_H3600_CLK_SET0		GPIO_GPIO (12)
+#define GPIO_H3600_CLK_SET1		GPIO_GPIO (13)
+
+/* UDA1341 L3 Interface */
+#define GPIO_H3600_L3_DATA		GPIO_GPIO (14)
+#define GPIO_H3600_L3_CLOCK		GPIO_GPIO (16)
+#define GPIO_H3600_L3_MODE		GPIO_GPIO (15)
+
+#define GPIO_H3600_OPT_LOCK		GPIO_GPIO (22)
+#define GPIO_H3600_OPT_IRQ		GPIO_GPIO (24)
+#define GPIO_H3600_OPT_DET		GPIO_GPIO (27)
+
+#define GPIO_H3600_COM_DCD		GPIO_GPIO (23)
+#define GPIO_H3600_COM_CTS		GPIO_GPIO (25)
+#define GPIO_H3600_COM_RTS		GPIO_GPIO (26)
+
+#define IRQ_GPIO_H3600_NPOWER_BUTTON    IRQ_GPIO0
+#define IRQ_GPIO_H3600_ACTION_BUTTON    IRQ_GPIO18
+#define IRQ_GPIO_H3600_PCMCIA_CD0	IRQ_GPIO17
+#define IRQ_GPIO_H3600_PCMCIA_CD1	IRQ_GPIO10
+#define IRQ_GPIO_H3600_PCMCIA_IRQ0	IRQ_GPIO21
+#define IRQ_GPIO_H3600_PCMCIA_IRQ1	IRQ_GPIO11
+#define IRQ_GPIO_H3600_OPT_IRQ		IRQ_GPIO24
+#define IRQ_GPIO_H3600_OPT_DET		IRQ_GPIO27
+#define IRQ_GPIO_H3600_COM_DCD          IRQ_GPIO23
+#define IRQ_GPIO_H3600_COM_CTS          IRQ_GPIO25
+
+#define EGPIO_H3600_VPP_ON		(1 << 0)
+#define EGPIO_H3600_CARD_RESET		(1 << 1)  /* reset the attached pcmcia/compactflash card.  active high. */
+#define EGPIO_H3600_OPT_RESET		(1 << 2)  /* reset the attached option pack.  active high. */
+#define EGPIO_H3600_CODEC_NRESET	(1 << 3)  /* reset the onboard UDA1341.  active low. */
+#define EGPIO_H3600_OPT_NVRAM_ON	(1 << 4)  /* apply power to optionpack nvram, active high. */
+#define EGPIO_H3600_OPT_ON		(1 << 5)  /* full power to option pack.  active high. */
+#define EGPIO_H3600_LCD_ON       	(1 << 6)  /* enable 3.3V to LCD.  active high. */
+#define EGPIO_H3600_RS232_ON		(1 << 7)  /* UART3 transceiver force on.  Active high. */
+#define EGPIO_H3600_LCD_PCI		(1 << 8)  /* LCD control IC enable.  active high. */
+#define EGPIO_H3600_IR_ON		(1 << 9)  /* apply power to IR module.  active high. */
+#define EGPIO_H3600_AUD_AMP_ON		(1 << 10) /* apply power to audio power amp.  active high. */
+#define EGPIO_H3600_AUD_PWR_ON		(1 << 11) /* apply poewr to reset of audio circuit.  active high. */
+#define EGPIO_H3600_QMUTE		(1 << 12) /* mute control for onboard UDA1341.  active high. */
+#define EGPIO_H3600_IR_FSEL		(1 << 13) /* IR speed select: 1->fast, 0->slow */
+#define EGPIO_H3600_LCD_5V_ON		(1 << 14) /* enable 5V to LCD. active high. */
+#define EGPIO_H3600_LVDD_ON		(1 << 15) /* enable 9V and -6.5V to LCD. */
+
+#ifndef __ASSEMBLY__
+#define H3600_EGPIO	(*(volatile int *)0xf0000000)
+extern void clr_h3600_egpio(unsigned long x);
+extern void set_h3600_egpio(unsigned long x);
+#endif
+
+#endif
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/arch-sa1100/hardware.h linux/include/asm-arm/arch-sa1100/hardware.h
--- v2.4.12/linux/include/asm-arm/arch-sa1100/hardware.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/arch-sa1100/hardware.h	Thu Oct 11 09:04:57 2001
@@ -122,8 +122,8 @@
 #include "empeg.h"
 #endif
 
-#ifdef CONFIG_SA1100_BITSY
-#include "bitsy.h"
+#ifdef CONFIG_SA1100_H3600
+#include "h3600.h"
 #endif
 
 #ifdef CONFIG_SA1100_ITSY
@@ -152,6 +152,14 @@
 
 #ifdef CONFIG_SA1100_SIMPAD
 #include "simpad.h"
+#endif
+
+#if defined(CONFIG_SA1100_GRAPHICSMASTER)
+#include "graphicsmaster.h"
+#endif
+
+#if defined(CONFIG_SA1100_ADSBITSY)
+#include "adsbitsy.h"
 #endif
 
 #ifdef CONFIG_SA1101
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/arch-sa1100/irqs.h linux/include/asm-arm/arch-sa1100/irqs.h
--- v2.4.12/linux/include/asm-arm/arch-sa1100/irqs.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/arch-sa1100/irqs.h	Thu Oct 11 09:04:57 2001
@@ -72,7 +72,7 @@
 #define	NR_IRQS		(IRQ_GPIO27 + 1)
 
 
-#if defined(CONFIG_SA1100_GRAPHICSCLIENT)
+#if defined(CONFIG_SA1100_GRAPHICSCLIENT) || defined(CONFIG_SA1100_GRAPHICSMASTER)
 #define ADS_EXT_IRQ(x)	(IRQ_GPIO27 + 1 + (x))
 #undef NR_IRQS
 #define NR_IRQS		(ADS_EXT_IRQ(15) + 1)
@@ -81,7 +81,11 @@
 
 #if defined(CONFIG_SA1111)
 
+#if defined(CONFIG_SA1100_GRAPHICSMASTER)
+#define	SA1111_IRQ(x)	(ADS_EXT_IRQ(15) + 1 + 1 + (x))
+#else
 #define SA1111_IRQ(x)	(IRQ_GPIO27 + 1 + (x))
+#endif
 
 #define GPAIN0		SA1111_IRQ(0)
 #define GPAIN1		SA1111_IRQ(1)
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/arch-sa1100/keyboard.h linux/include/asm-arm/arch-sa1100/keyboard.h
--- v2.4.12/linux/include/asm-arm/arch-sa1100/keyboard.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/arch-sa1100/keyboard.h	Thu Oct 11 09:04:57 2001
@@ -8,11 +8,37 @@
 #define _SA1100_KEYBOARD_H
 
 #include <linux/config.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
 
+extern struct kbd_ops_struct *kbd_ops;
 
-// #ifdef CONFIG_SA1100_BRUTUS
-/* need fixing... */
-#if 0
+#define kbd_disable_irq()	do { } while(0);
+#define kbd_enable_irq()	do { } while(0);
+
+
+/*
+ * SA1111 keyboard driver
+ */
+extern void sa1111_kbd_init_hw(void);
+
+/*
+ * GraphicsClient keyboard driver
+ */
+extern void gc_kbd_init_hw(void);
+
+static inline void kbd_init_hw(void)
+{
+	if (machine_is_assabet() && machine_has_neponset())
+		sa1111_kbd_init_hw();
+
+	if (machine_is_graphicsclient())
+		gc_kbd_init_hw();
+}
+
+
+
+#if 0	 /* Brutus needs fixing */
 
 extern int Brutus_kbd_translate(unsigned char scancode, unsigned char *keycode,
 			   char raw_mode);
@@ -34,7 +60,9 @@
 
 #define SYSRQ_KEY 0x54
 
-#elif CONFIG_SA1100_GRAPHICSCLIENT
+#elif 0 // CONFIG_SA1100_GRAPHICSCLIENT
+extern int gc_kbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int gc_kbd_getkeycode(unsigned int scancode);
 extern int gc_kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode);
 extern void gc_kbd_leds(unsigned char leds);
 extern void gc_kbd_init_hw(void);
@@ -42,137 +70,17 @@
 extern void gc_kbd_disable_irq(void);
 extern unsigned char gc_kbd_sysrq_xlate[128];
 
-#define kbd_setkeycode(x...)    (-ENOSYS)
-#define kbd_getkeycode(x...)    (-ENOSYS)
+#define kbd_setkeycode(x...)    gc_kbd_setkeycode	//(-ENOSYS)
+#define kbd_getkeycode(x...)    gc_kbd_getkeycode	//(-ENOSYS)
 #define kbd_translate           gc_kbd_translate
 #define kbd_unexpected_up(x...) (1)
 #define kbd_leds                gc_kbd_leds
 #define kbd_init_hw             gc_kbd_init_hw
 #define kbd_enable_irq          gc_kbd_enable_irq
 #define kbd_disable_irq         gc_kbd_disable_irq
-#define kbd_sysrq_xlate         gc_kbd_sysrq_xlate
-
-#elif CONFIG_SA1100_BITSY
-
-#define kbd_setkeycode(x...)    (-ENOSYS)
-#define kbd_getkeycode(x...)    (-ENOSYS)
-#define kbd_translate(sc_,kc_,rm_)	((*(kc_)=(sc_)),1)
-#define kbd_unexpected_up(x...) (1)
-#define kbd_leds(x...)		do { } while (0)
-#define kbd_init_hw(x...)	do { } while (0)
-#define kbd_enable_irq(x...)	do { } while (0)
-#define kbd_disable_irq(x...)	do { } while (0)
-
-#elif 0 //defined(CONFIG_SA1111)   /*@@@@@*/
-
-#define KEYBOARD_IRQ           TPRXINT
-#define DISABLE_KBD_DURING_INTERRUPTS  0
-
-/* redefine some macros */
-#ifdef KBD_DATA_REG
-#undef KBD_DATA_REG
-#endif
-#ifdef KBD_STATUS_REG
-#undef KBD_STATUS_REG
-#endif
-#ifdef KBD_CNTL_REG
-#undef KBD_CNTL_REG
-#endif
-#define KBD_DATA_REG           KBDDATA
-#define KBD_STATUS_REG         KBDSTAT
-#define KBD_CNTL_REG           KBDCR
-
-extern int sa1111_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int sa1111_getkeycode(unsigned int scancode);
-extern int sa1111_translate(unsigned char scancode, unsigned char *keycode,
-				char raw_mode);
-extern char sa1111_unexpected_up(unsigned char keycode);
-extern void sa1111_leds(unsigned char leds);
-extern void sa1111_init_hw(void);
-extern unsigned char sa1111_sysrq_xlate[128];
-
-#define kbd_setkeycode		sa1111_setkeycode
-#define kbd_getkeycode		sa1111_getkeycode
-#define kbd_translate		sa1111_translate
-#define kbd_unexpected_up	sa1111_unexpected_up
-#define kbd_leds		sa1111_leds
-#define kbd_init_hw		sa1111_init_hw
-#define kbd_sysrq_xlate		sa1111_sysrq_xlate
-#define kbd_disable_irq(x...)	do{;}while(0)
-#define kbd_enable_irq(x...)	do{;}while(0)
-
-#define SYSRQ_KEY 0x54
-
-/* resource allocation */
-#define kbd_request_region()
-#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
-					"keyboard", NULL)
-
-/* How to access the keyboard macros on this platform.  */
-#define kbd_read_input()	(*KBDDATA & 0x00ff)
-#define kbd_read_status()	(*KBDSTAT & 0x01ff)
-#define kbd_write_output(val)	(*KBDDATA = (val))
-#define kbd_write_command(val)	(*KBDCR = (val))
-
-/* Some stoneage hardware needs delays after some operations.  */
-#define kbd_pause() do {;} while(0)
-
-/* bit definitions for some registers */
-#define KBD_CR_ENA	(1<<3)
-
-#define KBD_STAT_RXB	(1<<4)
-#define KBD_STAT_RXF	(1<<5)
-#define KBD_STAT_TXB	(1<<6)
-#define KBD_STAT_TXE	(1<<7)
-#define KBD_STAT_STP	(1<<8)
-
-/*
- * Machine specific bits for the PS/2 driver
- */
-
-#define AUX_IRQ		MSRXINT
-
-#define aux_request_irq(hand, dev_id)  \
-		request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
-#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
-
-/* How to access the mouse macros on this platform.  */
-#define mse_read_input()	(*MSEDATA & 0x00ff)
-#define mse_read_status()	(*MSESTAT & 0x01ff)
-#define mse_write_output(val)	(*MSEDATA = (val))
-#define mse_write_command(val)	(*MSECR = (val))
-
-/* bit definitions for some registers */
-#define MSE_CR_ENA	(1<<3)
-
-#define MSE_STAT_RXB	(1<<4)
-#define MSE_STAT_RXF	(1<<5)
-#define MSE_STAT_TXB	(1<<6)
-#define MSE_STAT_TXE	(1<<7)
-#define MSE_STAT_STP	(1<<8)
-
-
-#else
-
-/* dummy i.e. no real keyboard */
-#define kbd_setkeycode(x...)	(-ENOSYS)
-#define kbd_getkeycode(x...)	(-ENOSYS)
-#define kbd_translate(x...)	(0)
-#define kbd_unexpected_up(x...)	(1)
-#define kbd_leds(x...)		do {;} while (0)
-#define kbd_init_hw(x...)	do {;} while (0)
-#define kbd_enable_irq(x...)	do {;} while (0)
-#define kbd_disable_irq(x...)	do {;} while (0)
+#define kbd_sysrq_xlate         (1)
 
 #endif
-
-
-/* needed if MAGIC_SYSRQ is enabled for serial console */
-#ifndef SYSRQ_KEY
-#define SYSRQ_KEY		((unsigned char)(-1))
-#define kbd_sysrq_xlate         ((unsigned char *)NULL)
-#endif
-
 
 #endif  /* _SA1100_KEYBOARD_H */
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/arch-sa1100/pangolin.h linux/include/asm-arm/arch-sa1100/pangolin.h
--- v2.4.12/linux/include/asm-arm/arch-sa1100/pangolin.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/arch-sa1100/pangolin.h	Thu Oct 11 09:04:57 2001
@@ -11,6 +11,7 @@
 #error "include <asm/hardware.h> instead"
 #endif
 
+#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
 
 /* GPIOs for which the generic definition doesn't say much */
 #define GPIO_CF_BUS_ON		GPIO_GPIO (3)
@@ -20,3 +21,41 @@
 
 #define IRQ_GPIO_CF_IRQ		IRQ_GPIO21
 #define IRQ_GPIO_CF_CD		IRQ_GPIO22
+
+#else
+/*
+ *  These definitions are for PCMCIA/IDE card
+ *
+ *  PSKTSEL = 0 ---> PCMCIA
+ *  PCMCIA_RESET = GPIO_7        ( output )( 0: normal   1: reset )
+ *  PCMCIA_IRQ = GPIO_24         ( input )
+ *  PCMCIA_CD = GPIO_25          ( input )
+ *
+ *  PSKTSEL = 1 ---> IDE port
+ *  IDE_IRQ = GPIO_23            ( input )
+ *
+ *  !!WARNING!!
+ *  When the PCMCIA/IDE card is inserted, the CF slot
+ *  should not have any card inserted!!
+ *
+ */
+
+#define GPIO_PCMCIA_RESET       GPIO_GPIO (7)
+#define GPIO_PCMCIA_IRQ         GPIO_GPIO (24)
+#define GPIO_PCMCIA_CD          GPIO_GPIO (25)
+#define GPIO_IDE_IRQ            GPIO_GPIO (8)
+
+#define IRQ_PCMCIA_IRQ          IRQ_GPIO24
+#define IRQ_PCMCIA_CD           IRQ_GPIO25
+#define IRQ_IDE_IRQ             IRQ_GPIO8
+
+#endif
+
+/*
+ * On board LAN chip
+ */
+#define PANGOLIN_LAN_ADDR      0x32000000
+#define PANGOLIN_LAN_RESET     GPIO_GPIO (8)
+#define PANGOLIN_LAN_IRQ       GPIO_GPIO (26)
+#define PANGOLIN_IRQ_LAN_IRQ   IRQ_GPIO26
+
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/arch-sa1100/uncompress.h linux/include/asm-arm/arch-sa1100/uncompress.h
--- v2.4.12/linux/include/asm-arm/arch-sa1100/uncompress.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/arch-sa1100/uncompress.h	Thu Oct 11 09:04:57 2001
@@ -3,23 +3,16 @@
  *
  * (C) 1999 Nicolas Pitre <nico@cam.org>
  *
- * Reorganised to use machine_is_*() macros.
+ * Reorganised to be machine independent.
  */
 
 #include "hardware.h"
 
-#include <asm/mach-types.h>
-
-/* Assabet's Status Control "Register" */
-unsigned long SCR_value;
-
-/* sa1100_setup() will perform any special initialization for UART, etc. */
-extern void sa1100_setup( int arch_id );
-#define arch_decomp_setup()	sa1100_setup(arch_id)
-
 /*
  * The following code assumes the serial port has already been
- * initialized by the bootloader or such...
+ * initialized by the bootloader.  We search for the first enabled
+ * port in the most probable order.  If you didn't setup a port in
+ * your bootloader then nothing will appear (which might be desired).
  */
 
 #define UART(x)		(*(volatile unsigned long *)(serial_port + (x)))
@@ -28,22 +21,15 @@
 {
 	unsigned long serial_port;
 
-	if (machine_is_assabet()) {
-		if( machine_has_neponset() )
-			serial_port = _Ser3UTCR0;
-		else
-			serial_port = _Ser1UTCR0;
-	} else if (machine_is_brutus()||machine_is_nanoengine() ||
-		   machine_is_pangolin() || machine_is_freebird() ||
-		   machine_is_pfs168() || machine_is_flexanet())
-		serial_port = _Ser1UTCR0;
-	else if (machine_is_empeg() || machine_is_bitsy() ||
-		 machine_is_victor() || machine_is_lart() ||
-		 machine_is_sherman() || machine_is_yopy() ||
-		 machine_is_huw_webpanel() || machine_is_itsy() )
+	do {
 		serial_port = _Ser3UTCR0;
-	else
+		if (UART(UTCR3) & UTCR3_TXE) break;
+		serial_port = _Ser1UTCR0;
+		if (UART(UTCR3) & UTCR3_TXE) break;
+		serial_port = _Ser2UTCR0;
+		if (UART(UTCR3) & UTCR3_TXE) break;
 		return;
+	} while (0);
 
 	for (; *s; s++) {
 		/* wait for space in the UART's transmiter */
@@ -63,4 +49,5 @@
 /*
  * Nothing to do for these
  */
+#define arch_decomp_setup()
 #define arch_decomp_wdog()
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/atomic.h linux/include/asm-arm/atomic.h
--- v2.4.12/linux/include/asm-arm/atomic.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/atomic.h	Thu Oct 11 09:04:57 2001
@@ -22,11 +22,7 @@
 #error SMP not supported
 #endif
 
-#ifdef CONFIG_ARCH_CO285
 typedef struct { volatile int counter; } atomic_t;
-#else
-typedef struct { int counter; } atomic_t;
-#endif
 
 #define ATOMIC_INIT(i)	{ (i) }
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/cpu-multi32.h linux/include/asm-arm/cpu-multi32.h
--- v2.4.12/linux/include/asm-arm/cpu-multi32.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/cpu-multi32.h	Thu Oct 11 09:04:57 2001
@@ -9,6 +9,7 @@
  */
 #ifndef __ASSEMBLY__
 
+#include <asm/memory.h>
 #include <asm/page.h>
 
 /* forward-declare task_struct */
@@ -155,5 +156,14 @@
 #define cpu_set_pte(ptep, pte)			processor.pgtable.set_pte(ptep, pte)
 
 #define cpu_switch_mm(pgd,tsk)			cpu_set_pgd(__virt_to_phys((unsigned long)(pgd)))
+
+#define cpu_get_pgd()	\
+	({						\
+		unsigned long pg;			\
+		__asm__("mrc p15, 0, %0, c2, c0, 0"	\
+			 : "=r" (pg));			\
+		pg &= ~0x3fff;				\
+		(pgd_t *)phys_to_virt(pg);		\
+	})
 
 #endif
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/cpu-single.h linux/include/asm-arm/cpu-single.h
--- v2.4.12/linux/include/asm-arm/cpu-single.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/cpu-single.h	Thu Oct 11 09:04:57 2001
@@ -51,6 +51,7 @@
 
 #ifndef __ASSEMBLY__
 
+#include <asm/memory.h>
 #include <asm/page.h>
 
 /* forward declare task_struct */
@@ -85,5 +86,14 @@
 extern volatile void cpu_reset(unsigned long addr);
 
 #define cpu_switch_mm(pgd,tsk) cpu_set_pgd(__virt_to_phys((unsigned long)(pgd)))
+
+#define cpu_get_pgd()	\
+	({						\
+		unsigned long pg;			\
+		__asm__("mrc p15, 0, %0, c2, c0, 0"	\
+			 : "=r" (pg));			\
+		pg &= ~0x3fff;				\
+		(pgd_t *)phys_to_virt(pg);		\
+	})
 
 #endif
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/hardirq.h linux/include/asm-arm/hardirq.h
--- v2.4.12/linux/include/asm-arm/hardirq.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/hardirq.h	Thu Oct 11 09:04:57 2001
@@ -2,6 +2,7 @@
 #define __ASM_HARDIRQ_H
 
 #include <linux/config.h>
+#include <linux/cache.h>
 #include <linux/threads.h>
 
 /* softirq.h is sensitive to the offsets of these fields */
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/hardware/pci_v3.h linux/include/asm-arm/hardware/pci_v3.h
--- v2.4.12/linux/include/asm-arm/hardware/pci_v3.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/hardware/pci_v3.h	Thu Oct 11 09:04:57 2001
@@ -102,6 +102,10 @@
 
 /*  PCI_CFG bits
  */
+#define V3_PCI_CFG_M_I2O_EN		(1 << 15)
+#define V3_PCI_CFG_M_IO_REG_DIS		(1 << 14)
+#define V3_PCI_CFG_M_IO_DIS		(1 << 13)
+#define V3_PCI_CFG_M_EN3V		(1 << 12)
 #define V3_PCI_CFG_M_RETRY_EN           (1 << 10)
 #define V3_PCI_CFG_M_AD_LOW1            (1 << 9)
 #define V3_PCI_CFG_M_AD_LOW0            (1 << 8)
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/io.h linux/include/asm-arm/io.h
--- v2.4.12/linux/include/asm-arm/io.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/io.h	Thu Oct 11 09:04:57 2001
@@ -72,18 +72,22 @@
 #include <asm/arch/io.h>
 
 /*
- * IO definitions.  We define {out,in,outs,ins}[bwl] if __io is
- * defined by the machine.  Otherwise, these definitions are left
- * for the machine specific header files to pick up.
+ * IO definitions.  We define {out,in,outs,ins}[bwl] if __io is defined
+ * by the machine.  Otherwise, these definitions are left for the machine
+ * specific header files to pick up.
+ *
+ * Note that we prevent GCC re-ordering or caching values in expressions
+ * by introducing sequence points into the in*() definitions.  Note that
+ * __raw_* do not guarantee this behaviour.
  */
 #ifdef __io
 #define outb(v,p)			__raw_writeb(v,__io(p))
 #define outw(v,p)			__raw_writew(v,__io(p))
 #define outl(v,p)			__raw_writel(v,__io(p))
 
-#define inb(p)				__raw_readb(__io(p))
-#define inw(p)				__raw_readw(__io(p))
-#define inl(p)				__raw_readl(__io(p))
+#define inb(p)		({ unsigned int __v = __raw_readb(__io(p)); __v; })
+#define inw(p)		({ unsigned int __v = __raw_readw(__io(p)); __v; })
+#define inl(p)		({ unsigned int __v = __raw_readl(__io(p)); __v; })
 
 #define outsb(p,d,l)			__raw_writesb(__io(p),d,l)
 #define outsw(p,d,l)			__raw_writesw(__io(p),d,l)
@@ -168,9 +172,10 @@
  */
 #ifdef __mem_pci
 
-#define readb(addr)			__raw_readb(__mem_pci(addr))
-#define readw(addr)			__raw_readw(__mem_pci(addr))
-#define readl(addr)			__raw_readl(__mem_pci(addr))
+#define readb(addr) ({ unsigned int __v = __raw_readb(__mem_pci(addr)); __v; })
+#define readw(addr) ({ unsigned int __v = __raw_readw(__mem_pci(addr)); __v; })
+#define readl(addr) ({ unsigned int __v = __raw_readl(__mem_pci(addr)); __v; })
+
 #define writeb(val,addr)		__raw_writeb(val,__mem_pci(addr))
 #define writew(val,addr)		__raw_writew(val,__mem_pci(addr))
 #define writel(val,addr)		__raw_writel(val,__mem_pci(addr))
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/mach/arch.h linux/include/asm-arm/mach/arch.h
--- v2.4.12/linux/include/asm-arm/mach/arch.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/mach/arch.h	Thu Oct 11 09:04:57 2001
@@ -27,7 +27,8 @@
 	unsigned int		nr;		/* architecture number	*/
 	unsigned int		phys_ram;	/* start of physical ram */
 	unsigned int		phys_io;	/* start of physical io	*/
-	unsigned int		virt_io;	/* start of virtual io	*/
+	unsigned int		io_pg_offst;	/* byte offset for io 
+						 * page tabe entry	*/
 
 	const char		*name;		/* architecture name	*/
 	unsigned int		param_offset;	/* parameter page	*/
@@ -59,9 +60,9 @@
 #define MAINTAINER(n)
 
 #define BOOT_MEM(_pram,_pio,_vio)		\
-	phys_ram:	_pram,			\
-	phys_io:	_pio,			\
-	virt_io:	_vio,
+	phys_ram:	_pram,	                \
+	phys_io:	_pio,  	                \
+	io_pg_offst:	((_vio)>>18)&0xfffc,
 
 #define BOOT_PARAMS(_params)			\
 	param_offset:	_params,
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/param.h linux/include/asm-arm/param.h
--- v2.4.12/linux/include/asm-arm/param.h	Tue Mar  6 19:44:35 2001
+++ linux/include/asm-arm/param.h	Thu Oct 11 09:04:57 2001
@@ -16,6 +16,9 @@
 #ifndef HZ
 #define HZ 100
 #endif
+#if defined(__KERNEL__) && (HZ == 100)
+#define hz_to_std(a) (a)
+#endif
 
 #ifndef NGROUPS
 #define NGROUPS         32
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/pci.h linux/include/asm-arm/pci.h
--- v2.4.12/linux/include/asm-arm/pci.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/pci.h	Fri Oct 12 15:35:54 2001
@@ -44,7 +44,6 @@
 	consistent_free(vaddr, size, dma_handle);
 }
 
-#if !defined(CONFIG_SA1111)
 /* Map a single buffer of the indicated size for DMA in streaming mode.
  * The 32-bit bus address to use is returned.
  *
@@ -54,6 +53,17 @@
 static inline dma_addr_t
 pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
 {
+#ifdef CONFIG_SA1111
+	extern dma_addr_t sa1111_map_single(struct pci_dev *, void *, size_t, int);
+
+	/*
+	 * for SA1111 these functions are "magic" and relocate buffers.  We
+	 * only need to do these if hwdev is non-null; otherwise we expect
+	 * the buffer to already be suitable for DMA.
+	 */
+	if (hwdev != NULL)
+		return sa1111_map_single(hwdev, ptr, size, direction);
+#endif
 	consistent_sync(ptr, size, direction);
 	return virt_to_bus(ptr);
 }
@@ -68,16 +78,14 @@
 static inline void
 pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
 {
+#ifdef CONFIG_SA1111
+	extern void sa1111_unmap_single(struct pci_dev *, dma_addr_t, size_t, int);
+
+	if (hwdev != NULL)
+		sa1111_unmap_single(hwdev, dma_addr, size, direction);
+#endif
 	/* nothing to do */
 }
-#else
-/* for SA1111 these functions are "magic" and relocate buffers */
-extern dma_addr_t pci_map_single(struct pci_dev *hwdev,
-				 void *ptr, size_t size, int direction);
-extern void pci_unmap_single(struct pci_dev *hwdev,
-			     dma_addr_t dma_addr,
-			     size_t size, int direction);
-#endif
 
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
@@ -152,7 +160,7 @@
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 {
 	return 1;
 }
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h
--- v2.4.12/linux/include/asm-arm/pgtable.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/pgtable.h	Thu Oct 11 09:04:57 2001
@@ -175,6 +175,8 @@
 
 #include <asm-generic/pgtable.h>
 
+extern void pgtable_cache_init(void);
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASMARM_PGTABLE_H */
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/processor.h linux/include/asm-arm/processor.h
--- v2.4.12/linux/include/asm-arm/processor.h	Tue Oct  9 17:06:53 2001
+++ linux/include/asm-arm/processor.h	Thu Oct 11 09:04:57 2001
@@ -68,6 +68,13 @@
 	EXTRA_THREAD_STRUCT
 };
 
+#define INIT_MMAP {					\
+	vm_mm:		&init_mm,			\
+	vm_page_prot:	PAGE_SHARED,			\
+	vm_flags:	VM_READ | VM_WRITE | VM_EXEC,	\
+	vm_avl_height:	1,				\
+}
+
 #define INIT_THREAD  {					\
 	refcount:	ATOMIC_INIT(1),			\
 	EXTRA_THREAD_STRUCT_INIT			\
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/scatterlist.h linux/include/asm-arm/scatterlist.h
--- v2.4.12/linux/include/asm-arm/scatterlist.h	Sun Sep  3 11:19:11 2000
+++ linux/include/asm-arm/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -5,7 +5,6 @@
 
 struct scatterlist {
 	char		*address;	/* virtual address		 */
-	char		*alt_address;	/* indirect dma address, or NULL */
 	dma_addr_t	dma_address;	/* dma address			 */
 	unsigned int	length;		/* length			 */
 };
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/setup.h linux/include/asm-arm/setup.h
--- v2.4.12/linux/include/asm-arm/setup.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/setup.h	Thu Oct 11 09:04:57 2001
@@ -126,7 +126,7 @@
 
 struct tag_ramdisk {
 	u32 flags;	/* bit 0 = load, bit 1 = prompt */
-	u32 size;	/* decompressed ramdisk size */
+	u32 size;	/* decompressed ramdisk size in _kilo_ bytes */
 	u32 start;	/* starting block of floppy-based RAM disk image */
 };
 
@@ -135,7 +135,7 @@
 
 struct tag_initrd {
 	u32 start;	/* physical start address */
-	u32 size;	/* size of compressed ramdisk image */
+	u32 size;	/* size of compressed ramdisk image in bytes */
 };
 
 /* board serial number. "64 bits should be enough for everybody" */
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/signal.h linux/include/asm-arm/signal.h
--- v2.4.12/linux/include/asm-arm/signal.h	Thu Nov 18 19:37:03 1999
+++ linux/include/asm-arm/signal.h	Thu Oct 11 09:04:57 2001
@@ -75,13 +75,16 @@
 /*
  * SA_FLAGS values:
  *
- * SA_ONSTACK is not currently supported, but will allow sigaltstack(2).
- * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
+ * SA_NOCLDSTOP		flag to turn off SIGCHLD when children stop.
+ * SA_NOCLDWAIT		flag on SIGCHLD to inhibit zombies.
+ * SA_SIGINFO		deliver the signal with SIGINFO structs
+ * SA_THIRTYTWO		delivers the signal in 32-bit mode, even if the task 
+ *			is running in 26-bit.
+ * SA_ONSTACK		allows alternate signal stacks (see sigaltstack(2)).
+ * SA_RESTART		flag to get restarting signals (which were the default long ago)
+ * SA_INTERRUPT		is a no-op, but left due to historical reasons. Use the
+ * SA_NODEFER		prevents the current signal from being masked in the handler.
+ * SA_RESETHAND		clears the handler when the signal is delivered.
  *
  * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
  * Unix names RESETHAND and NODEFER respectively.
@@ -89,6 +92,8 @@
 #define SA_NOCLDSTOP	0x00000001
 #define SA_NOCLDWAIT	0x00000002 /* not supported yet */
 #define SA_SIGINFO	0x00000004
+#define SA_THIRTYTWO	0x02000000
+#define SA_RESTORER	0x04000000
 #define SA_ONSTACK	0x08000000
 #define SA_RESTART	0x10000000
 #define SA_NODEFER	0x40000000
@@ -98,9 +103,6 @@
 #define SA_ONESHOT	SA_RESETHAND
 #define SA_INTERRUPT	0x20000000 /* dummy -- ignored */
 
-#define SA_RESTORER	0x04000000
-#define SA_THIRTYTWO	0x02000000 /* deliver signal in 32-bit mode even if
-				      task is running 26 bits. */
 
 /* 
  * sigaltstack controls
diff -u --recursive --new-file v2.4.12/linux/include/asm-arm/uaccess.h linux/include/asm-arm/uaccess.h
--- v2.4.12/linux/include/asm-arm/uaccess.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-arm/uaccess.h	Thu Oct 11 09:04:57 2001
@@ -63,11 +63,81 @@
  * error occurs, and leave it unchanged on success.  Note that these
  * versions are void (ie, don't return a value as such).
  */
-#define get_user(x,p)		__get_user_check((x),(p),sizeof(*(p)))
+
+extern int __get_user_1(void *);
+extern int __get_user_2(void *);
+extern int __get_user_4(void *);
+extern int __get_user_8(void *);
+extern int __get_user_bad(void);
+
+#define __get_user_x(__r1,__p,__e,__s,__i...)				\
+	   __asm__ __volatile__ ("bl	__get_user_" #__s		\
+		: "=&r" (__e), "=r" (__r1)				\
+		: "0" (__p)						\
+		: __i)
+
+#define get_user(x,p)							\
+	({								\
+		const register typeof(*(p)) *__p asm("r0") = (p);	\
+		register typeof(*(p)) __r1 asm("r1");			\
+		register int __e asm("r0");				\
+		switch (sizeof(*(p))) {					\
+		case 1:							\
+			__get_user_x(__r1, __p, __e, 1, "lr");		\
+	       		break;						\
+		case 2:							\
+			__get_user_x(__r1, __p, __e, 2, "r2", "lr");	\
+			break;						\
+		case 4:							\
+	       		__get_user_x(__r1, __p, __e, 4, "lr");		\
+			break;						\
+		case 8:							\
+			__get_user_x(__r1, __p, __e, 8, "lr");		\
+	       		break;						\
+		default: __e = __get_user_bad(); break;			\
+		}							\
+		x = __r1;						\
+		__e;							\
+	})
+
 #define __get_user(x,p)		__get_user_nocheck((x),(p),sizeof(*(p)))
 #define __get_user_error(x,p,e)	__get_user_nocheck_error((x),(p),sizeof(*(p)),(e))
 
-#define put_user(x,p)		__put_user_check((__typeof(*(p)))(x),(p),sizeof(*(p)))
+extern int __put_user_1(void *, unsigned int);
+extern int __put_user_2(void *, unsigned int);
+extern int __put_user_4(void *, unsigned int);
+extern int __put_user_8(void *, unsigned long long);
+extern int __put_user_bad(void);
+
+#define __put_user_x(__r1,__p,__e,__s,__i...)				\
+	   __asm__ __volatile__ ("bl	__put_user_" #__s		\
+		: "=&r" (__e)						\
+		: "0" (__p), "r" (__r1)					\
+		: __i)
+
+#define put_user(x,p)							\
+	({								\
+		const register typeof(*(p)) *__p asm("r0") = (p);	\
+		const register typeof(*(p)) __r1 asm("r1") = (x);	\
+		register int __e asm("r0");				\
+		switch (sizeof(*(p))) {					\
+		case 1:							\
+			__put_user_x(__r1, __p, __e, 1, "r2", "lr");	\
+			break;						\
+		case 2:							\
+			__put_user_x(__r1, __p, __e, 2, "r2", "lr");	\
+			break;						\
+		case 4:							\
+			__put_user_x(__r1, __p, __e, 4, "r2", "lr");	\
+			break;						\
+		case 8:							\
+			__put_user_x(__r1, __p, __e, 8, "ip", "lr");	\
+			break;						\
+		default: __e = __put_user_bad(); break;			\
+		}							\
+		__e;							\
+	})
+
 #define __put_user(x,p)		__put_user_nocheck((__typeof(*(p)))(x),(p),sizeof(*(p)))
 #define __put_user_error(x,p,e)	__put_user_nocheck_error((x),(p),sizeof(*(p)),(e))
 
@@ -142,6 +212,7 @@
 /*
  * These are the work horses of the get/put_user functions
  */
+#if 0
 #define __get_user_check(x,ptr,size)					\
 ({									\
 	long __gu_err = -EFAULT, __gu_val = 0;				\
@@ -153,6 +224,7 @@
 	(x) = (__typeof__(*(ptr)))__gu_val;				\
 	__gu_err;							\
 })
+#endif
 
 #define __get_user_nocheck(x,ptr,size)					\
 ({									\
@@ -195,8 +267,6 @@
 	(void) 0;							\
 })
 
-extern long __get_user_bad(void);
-
 #define __get_user_size(x,ptr,size,retval)				\
 do {									\
 	switch (size) {							\
@@ -206,8 +276,6 @@
 	default: (x) = __get_user_bad();				\
 	}								\
 } while (0)
-
-extern long __put_user_bad(void);
 
 #define __put_user_size(x,ptr,size,retval)				\
 do {									\
diff -u --recursive --new-file v2.4.12/linux/include/asm-i386/page.h linux/include/asm-i386/page.h
--- v2.4.12/linux/include/asm-i386/page.h	Thu Oct 18 13:47:37 2001
+++ linux/include/asm-i386/page.h	Thu Oct 18 17:43:37 2001
@@ -15,7 +15,7 @@
 
 #include <asm/mmx.h>
 
-#define clear_page(page)	mmx_clear_page(page)
+#define clear_page(page)	mmx_clear_page((void *)(page))
 #define copy_page(to,from)	mmx_copy_page(to,from)
 
 #else
diff -u --recursive --new-file v2.4.12/linux/include/asm-i386/pci.h linux/include/asm-i386/pci.h
--- v2.4.12/linux/include/asm-i386/pci.h	Thu Oct 18 13:48:29 2001
+++ linux/include/asm-i386/pci.h	Thu Oct 18 17:44:20 2001
@@ -34,6 +34,12 @@
 
 struct pci_dev;
 
+/* The PCI address space does equal the physical memory
+ * address space.  The networking and block device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS	(1)
+
 /* Allocate and map kernel buffer using consistent mode DMA for a device.
  * hwdev should be valid struct pci_dev pointer for PCI devices,
  * NULL for PCI-like buses (ISA, EISA).
@@ -84,6 +90,27 @@
 	/* Nothing to do */
 }
 
+/*
+ * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
+ * to pci_map_single, but takes a struct page instead of a virtual address
+ */
+static inline dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page,
+				      unsigned long offset, size_t size, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+
+	return (page - mem_map) * PAGE_SIZE + offset;
+}
+
+static inline void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address,
+				  size_t size, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+	/* Nothing to do */
+}
+
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
@@ -102,8 +129,26 @@
 static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 			     int nents, int direction)
 {
+	int i;
+
 	if (direction == PCI_DMA_NONE)
 		BUG();
+
+	/*
+	 * temporary 2.4 hack
+	 */
+	for (i = 0; i < nents; i++ ) {
+		if (sg[i].address && sg[i].page)
+			BUG();
+		else if (!sg[i].address && !sg[i].page)
+			BUG();
+
+		if (sg[i].address)
+			sg[i].dma_address = virt_to_bus(sg[i].address);
+		else
+			sg[i].dma_address = page_to_bus(sg[i].page) + sg[i].offset;
+	}
+
 	return nents;
 }
 
@@ -157,7 +202,7 @@
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 {
         /*
          * we fall back to GFP_DMA when the mask isn't all 1s,
@@ -170,13 +215,42 @@
 	return 1;
 }
 
+/* This is always fine. */
+#define pci_dac_dma_supported(pci_dev, mask)	(1)
+
+static __inline__ dma64_addr_t
+pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
+{
+	return ((dma64_addr_t) page_to_bus(page) +
+		(dma64_addr_t) offset);
+}
+
+static __inline__ struct page *
+pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
+{
+	unsigned long poff = (dma_addr >> PAGE_SHIFT);
+
+	return mem_map + poff;
+}
+
+static __inline__ unsigned long
+pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
+{
+	return (dma_addr & ~PAGE_MASK);
+}
+
+static __inline__ void
+pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+{
+	/* Nothing to do. */
+}
+
 /* These macros should be used after a pci_map_sg call has been done
  * to get bus addresses of each of the SG entries and their lengths.
  * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
+ * returns.
  */
-#define sg_dma_address(sg)	(virt_to_bus((sg)->address))
+#define sg_dma_address(sg)	((sg)->dma_address)
 #define sg_dma_len(sg)		((sg)->length)
 
 /* Return the index of the PCI controller for device. */
diff -u --recursive --new-file v2.4.12/linux/include/asm-i386/scatterlist.h linux/include/asm-i386/scatterlist.h
--- v2.4.12/linux/include/asm-i386/scatterlist.h	Mon Dec 30 03:01:10 1996
+++ linux/include/asm-i386/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -2,9 +2,12 @@
 #define _I386_SCATTERLIST_H
 
 struct scatterlist {
-    char *  address;    /* Location data is to be transferred to */
-    char * alt_address; /* Location of actual if address is a 
-			 * dma indirect buffer.  NULL otherwise */
+    char *  address;    /* Location data is to be transferred to, NULL for
+			 * highmem page */
+    struct page * page; /* Location for highmem page, if any */
+    unsigned int offset;/* for highmem, page offset */
+
+    dma_addr_t dma_address;
     unsigned int length;
 };
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v2.4.12/linux/include/asm-i386/smp.h	Thu Oct 18 13:47:38 2001
+++ linux/include/asm-i386/smp.h	Thu Oct 18 17:43:37 2001
@@ -109,7 +109,7 @@
 	return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
 }
 
-extern __inline int logical_smp_processor_id(void)
+static __inline int logical_smp_processor_id(void)
 {
 	/* we don't want to mark this access volatile - bad code generation */
 	return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
diff -u --recursive --new-file v2.4.12/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.4.12/linux/include/asm-i386/system.h	Thu Oct 18 13:47:37 2001
+++ linux/include/asm-i386/system.h	Thu Oct 18 17:43:37 2001
@@ -281,10 +281,19 @@
  * I expect future Intel CPU's to have a weaker ordering,
  * but I'd also expect them to finally get their act together
  * and add some real memory barriers if so.
+ *
+ * Some non intel clones support out of order store. wmb() ceases to be a
+ * nop for these.
  */
+ 
 #define mb() 	__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
 #define rmb()	mb()
+
+#ifdef CONFIG_X86_OOSTORE
+#define wmb() 	__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
+#else
 #define wmb()	__asm__ __volatile__ ("": : :"memory")
+#endif
 
 #ifdef CONFIG_SMP
 #define smp_mb()	mb()
@@ -339,5 +348,7 @@
 #define HAVE_DISABLE_HLT
 void disable_hlt(void);
 void enable_hlt(void);
+
+extern int is_sony_vaio_laptop;
 
 #endif
diff -u --recursive --new-file v2.4.12/linux/include/asm-i386/types.h linux/include/asm-i386/types.h
--- v2.4.12/linux/include/asm-i386/types.h	Thu Jan 27 08:58:15 2000
+++ linux/include/asm-i386/types.h	Fri Oct 12 15:35:54 2001
@@ -27,6 +27,8 @@
  */
 #ifdef __KERNEL__
 
+#include <linux/config.h>
+
 typedef signed char s8;
 typedef unsigned char u8;
 
@@ -41,9 +43,14 @@
 
 #define BITS_PER_LONG 32
 
-/* Dma addresses are 32-bits wide.  */
+/* DMA addresses come in generic and 64-bit flavours.  */
 
+#ifdef CONFIG_HIGHMEM
+typedef u64 dma_addr_t;
+#else
 typedef u32 dma_addr_t;
+#endif
+typedef u64 dma64_addr_t;
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- v2.4.12/linux/include/asm-i386/unistd.h	Tue Oct  9 17:06:53 2001
+++ linux/include/asm-i386/unistd.h	Wed Oct 17 10:03:03 2001
@@ -229,6 +229,7 @@
 #define __NR_fcntl64		221
 #define __NR_security		223	/* syscall for security modules */
 #define __NR_gettid		224
+#define __NR_readahead		225
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-ia64/pci.h linux/include/asm-ia64/pci.h
--- v2.4.12/linux/include/asm-ia64/pci.h	Wed May 16 10:31:27 2001
+++ linux/include/asm-ia64/pci.h	Fri Oct 12 15:35:54 2001
@@ -52,7 +52,7 @@
  * you would pass 0x00ffffff as the mask to this function.
  */
 static inline int
-pci_dma_supported (struct pci_dev *hwdev, dma_addr_t mask)
+pci_dma_supported (struct pci_dev *hwdev, u64 mask)
 {
 	return 1;
 }
diff -u --recursive --new-file v2.4.12/linux/include/asm-ia64/scatterlist.h linux/include/asm-ia64/scatterlist.h
--- v2.4.12/linux/include/asm-ia64/scatterlist.h	Fri Aug 11 19:09:06 2000
+++ linux/include/asm-ia64/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -8,11 +8,6 @@
 
 struct scatterlist {
 	char *address;		/* location data is to be transferred to */
-	/*
-	 * Location of actual buffer if ADDRESS points to a DMA
-	 * indirection buffer, NULL otherwise:
-	 */
-	char *alt_address;
 	char *orig_address;	/* Save away the original buffer address (used by pci-dma.c) */
 	unsigned int length;	/* buffer length */
 };
diff -u --recursive --new-file v2.4.12/linux/include/asm-m68k/scatterlist.h linux/include/asm-m68k/scatterlist.h
--- v2.4.12/linux/include/asm-m68k/scatterlist.h	Tue May 11 09:57:14 1999
+++ linux/include/asm-m68k/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -3,8 +3,6 @@
 
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to */
-    char * alt_address; /* Location of actual if address is a 
-			 * dma indirect buffer.  NULL otherwise */
     unsigned int length;
     unsigned long dvma_address;
 };
diff -u --recursive --new-file v2.4.12/linux/include/asm-mips/pci.h linux/include/asm-mips/pci.h
--- v2.4.12/linux/include/asm-mips/pci.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-mips/pci.h	Fri Oct 12 15:35:54 2001
@@ -215,7 +215,7 @@
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 {
 	/*
 	 * we fall back to GFP_DMA when the mask isn't all 1s,
diff -u --recursive --new-file v2.4.12/linux/include/asm-mips/scatterlist.h linux/include/asm-mips/scatterlist.h
--- v2.4.12/linux/include/asm-mips/scatterlist.h	Tue Dec 16 12:46:12 1997
+++ linux/include/asm-mips/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -3,8 +3,6 @@
 
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to */
-    char * alt_address; /* Location of actual if address is a 
-			 * dma indirect buffer.  NULL otherwise */
     unsigned int length;
     
     __u32 dvma_address;
diff -u --recursive --new-file v2.4.12/linux/include/asm-mips64/pci.h linux/include/asm-mips64/pci.h
--- v2.4.12/linux/include/asm-mips64/pci.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-mips64/pci.h	Fri Oct 12 15:35:54 2001
@@ -220,7 +220,7 @@
 }
 #endif /* CONFIG_MAPPED_PCI_IO  */
 
-static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 {
 	/*
 	 * we fall back to GFP_DMA when the mask isn't all 1s,
diff -u --recursive --new-file v2.4.12/linux/include/asm-mips64/scatterlist.h linux/include/asm-mips64/scatterlist.h
--- v2.4.12/linux/include/asm-mips64/scatterlist.h	Thu Feb 24 22:53:35 2000
+++ linux/include/asm-mips64/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -3,8 +3,6 @@
 
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to */
-    char * alt_address; /* Location of actual if address is a 
-			 * dma indirect buffer.  NULL otherwise */
     unsigned int length;
     
     __u32 dvma_address;
diff -u --recursive --new-file v2.4.12/linux/include/asm-parisc/pci.h linux/include/asm-parisc/pci.h
--- v2.4.12/linux/include/asm-parisc/pci.h	Wed May 16 10:31:27 2001
+++ linux/include/asm-parisc/pci.h	Fri Oct 12 15:35:54 2001
@@ -113,7 +113,7 @@
 ** See Documentation/DMA-mapping.txt
 */
 struct pci_dma_ops {
-	int  (*dma_supported)(struct pci_dev *dev, dma_addr_t mask);
+	int  (*dma_supported)(struct pci_dev *dev, u64 mask);
 	void *(*alloc_consistent)(struct pci_dev *dev, size_t size, dma_addr_t *iova);
 	void (*free_consistent)(struct pci_dev *dev, size_t size, void *vaddr, dma_addr_t iova);
 	dma_addr_t (*map_single)(struct pci_dev *dev, void *addr, size_t size, int direction);
diff -u --recursive --new-file v2.4.12/linux/include/asm-parisc/scatterlist.h linux/include/asm-parisc/scatterlist.h
--- v2.4.12/linux/include/asm-parisc/scatterlist.h	Tue Dec  5 12:29:39 2000
+++ linux/include/asm-parisc/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -3,8 +3,6 @@
 
 struct scatterlist {
 	char *  address;    /* Location data is to be transferred to */
-	char * alt_address; /* Location of actual if address is a 
-			     * dma indirect buffer.  NULL otherwise */
 	unsigned int length;
 
 	/* an IOVA can be 64-bits on some PA-Risc platforms. */
diff -u --recursive --new-file v2.4.12/linux/include/asm-ppc/pci.h linux/include/asm-ppc/pci.h
--- v2.4.12/linux/include/asm-ppc/pci.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/pci.h	Sun Oct 21 10:13:07 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pci.h 1.12 05/21/01 01:31:30 cort
+ * BK Id: SCCS/s.pci.h 1.16 10/15/01 22:51:33 paulus
  */
 #ifndef __PPC_PCI_H
 #define __PPC_PCI_H
@@ -41,7 +41,7 @@
 extern unsigned long pci_phys_to_bus(unsigned long pa, int busnr);
 extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
     
-/* Dynamic DMA Mapping stuff
+/* Dynamic DMA Mapping stuff, stolen from i386
  * 	++ajoshi
  */
 
@@ -53,39 +53,139 @@
 
 struct pci_dev;
 
+/* The PCI address space does equal the physical memory
+ * address space.  The networking and block device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS	(1)
+	
+/* Allocate and map kernel buffer using consistent mode DMA for a device.
+ * hwdev should be valid struct pci_dev pointer for PCI devices,
+ * NULL for PCI-like buses (ISA, EISA).
+ * Returns non-NULL cpu-view pointer to the buffer if successful and
+ * sets *dma_addrp to the pci side dma address as well, else *dma_addrp
+ * is undefined.
+ */
 extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
 				  dma_addr_t *dma_handle);
+
+/* Free and unmap a consistent DMA buffer.
+ * cpu_addr is what was returned from pci_alloc_consistent,
+ * size must be the same as what as passed into pci_alloc_consistent,
+ * and likewise dma_addr must be the same as what *dma_addrp was set to.
+ *
+ * References to the memory and mappings associated with cpu_addr/dma_addr
+ * past this call are illegal.
+ */
 extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
 				void *vaddr, dma_addr_t dma_handle);
-extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+
+/* Map a single buffer of the indicated size for DMA in streaming mode.
+ * The 32-bit bus address to use is returned.
+ *
+ * Once the device is given the dma address, the device owns this memory
+ * until either pci_unmap_single or pci_dma_sync_single is performed.
+ */
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
 					size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
 		BUG();
 	return virt_to_bus(ptr);
 }
-extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+
+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
 				    size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
 		BUG();
 	/* nothing to do */
 }
-extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+
+
+/*
+ * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
+ * to pci_map_single, but takes a struct page instead of a virtual address
+ */
+static inline dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page,
+				      unsigned long offset, size_t size, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+	return (page - mem_map) * PAGE_SIZE + PCI_DRAM_OFFSET + offset;
+}
+
+static inline void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address,
+				  size_t size, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+	/* Nothing to do */
+}
+
+/* Map a set of buffers described by scatterlist in streaming
+ * mode for DMA.  This is the scather-gather version of the
+ * above pci_map_single interface.  Here the scatter gather list
+ * elements are each tagged with the appropriate dma address
+ * and length.  They are obtained via sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ *       DMA address/length pairs than there are SG table elements.
+ *       (for example via virtual mapping capabilities)
+ *       The routine returns the number of addr/length pairs actually
+ *       used, at most nents.
+ *
+ * Device ownership issues as mentioned above for pci_map_single are
+ * the same here.
+ */
+static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 			     int nents, int direction)
 {
+	int i;
+
 	if (direction == PCI_DMA_NONE)
 		BUG();
+
+	/*
+	 * temporary 2.4 hack
+	 */
+	for (i = 0; i < nents; i++) {
+		if (sg[i].address && sg[i].page)
+			BUG();
+		else if (!sg[i].address && !sg[i].page)
+			BUG();
+
+		if (sg[i].address)
+			sg[i].dma_address = virt_to_bus(sg[i].address);
+		else
+			sg[i].dma_address = page_to_bus(sg[i].page) + sg[i].offset;
+	}
+
 	return nents;
 }
-extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+
+/* Unmap a set of streaming mode DMA translations.
+ * Again, cpu read rules concerning calls here are the same as for
+ * pci_unmap_single() above.
+ */
+static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 				int nents, int direction)
 {
 	if (direction == PCI_DMA_NONE)
 		BUG();
 	/* nothing to do */
 }
-extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
+
+/* Make physical memory consistent for a single
+ * streaming mode DMA translation after a transfer.
+ *
+ * If you perform a pci_map_single() but wish to interrogate the
+ * buffer using the cpu, yet do not wish to teardown the PCI dma
+ * mapping, you must call this function before doing so.  At the
+ * next point you give the PCI dma address back to the card, the
+ * device again owns the buffer.
+ */
+static inline void pci_dma_sync_single(struct pci_dev *hwdev,
 				       dma_addr_t dma_handle,
 				       size_t size, int direction)
 {
@@ -94,7 +194,13 @@
 	/* nothing to do */
 }
 
-extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+/* Make physical memory consistent for a set of streaming
+ * mode DMA translations after a transfer.
+ *
+ * The same as pci_dma_sync_single but for a scatter-gather list,
+ * same rules and usage.
+ */
+static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
 				   struct scatterlist *sg,
 				   int nelems, int direction)
 {
@@ -108,11 +214,49 @@
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 {
 	return 1;
 }
 
+/*
+ * At present there are very few 32-bit PPC machines that can have
+ * memory above the 4GB point, and we don't support that.
+ */
+#define pci_dac_dma_supported(pci_dev, mask)	(0)
+
+static __inline__ dma64_addr_t
+pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
+{
+	return (dma64_addr_t) page_to_bus(page) + offset;
+}
+
+static __inline__ struct page *
+pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
+{
+	return mem_map + (unsigned long)(dma_addr >> PAGE_SHIFT);
+}
+
+static __inline__ unsigned long
+pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
+{
+	return (dma_addr & ~PAGE_MASK);
+}
+
+static __inline__ void
+pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+{
+	/* Nothing to do. */
+}
+
+/* These macros should be used after a pci_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns.
+ */
+#define sg_dma_address(sg)	((sg)->dma_address)
+#define sg_dma_len(sg)		((sg)->length)
+
 /* Return the index of the PCI controller for device PDEV. */
 extern int pci_controller_num(struct pci_dev *pdev);
 
@@ -122,9 +266,6 @@
 
 /* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
 #define HAVE_PCI_MMAP	1
-
-#define sg_dma_address(sg)	(virt_to_bus((sg)->address))
-#define sg_dma_len(sg)		((sg)->length)
 
 #endif	/* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-ppc/ppcboot.h linux/include/asm-ppc/ppcboot.h
--- v2.4.12/linux/include/asm-ppc/ppcboot.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-ppc/ppcboot.h	Mon Oct 15 13:35:26 2001
@@ -69,7 +69,7 @@
 	unsigned long	bi_vco;		/* VCO Out from PLL, in MHz		*/
 #endif
 	unsigned long	bi_baudrate;	/* Console Baudrate			*/
-#if defined(CONFIG_PPC405)
+#if defined(CONFIG_405GP)
 	unsigned char	bi_s_version[4];  /* Version of this structure		*/
 	unsigned char	bi_r_version[32]; /* Version of the ROM (IBM)		*/
 	unsigned int	bi_procfreq;	/* CPU (Internal) Freq, in Hz		*/
diff -u --recursive --new-file v2.4.12/linux/include/asm-ppc/scatterlist.h linux/include/asm-ppc/scatterlist.h
--- v2.4.12/linux/include/asm-ppc/scatterlist.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/scatterlist.h	Sun Oct 21 10:13:07 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.scatterlist.h 1.5 05/17/01 18:14:25 cort
+ * BK Id: SCCS/s.scatterlist.h 1.9 10/15/01 22:51:33 paulus
  */
 #ifdef __KERNEL__
 #ifndef _PPC_SCATTERLIST_H
@@ -8,12 +8,24 @@
 #include <asm/dma.h>
 
 struct scatterlist {
-    char *  address;    /* Location data is to be transferred to */
-    char * alt_address; /* Location of actual if address is a 
-			 * dma indirect buffer.  NULL otherwise */
-    unsigned int length;
+	char *address;		/* Location data is to be transferred to,
+				 * or NULL for highmem page */
+	struct page * page;	/* Location for highmem page, if any */
+	unsigned int offset;	/* for highmem, page offset */
+
+	dma_addr_t dma_address;	/* phys/bus dma address		 */
+	unsigned int length;	/* length			 */
 };
 
+/*
+ * These macros should be used after a pci_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns, or alternatively stop on the first sg_dma_len(sg) which
+ * is 0.
+ */
+#define sg_dma_address(sg)      ((sg)->dma_address)
+#define sg_dma_len(sg)          ((sg)->length)
 
 #endif /* !(_PPC_SCATTERLIST_H) */
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.12/linux/include/asm-ppc/types.h linux/include/asm-ppc/types.h
--- v2.4.12/linux/include/asm-ppc/types.h	Mon Aug 27 12:41:48 2001
+++ linux/include/asm-ppc/types.h	Sun Oct 21 10:13:07 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.types.h 1.8 07/07/01 13:37:26 paulus
+ * BK Id: SCCS/s.types.h 1.10 10/15/01 22:51:33 paulus
  */
 #ifndef _PPC_TYPES_H
 #define _PPC_TYPES_H
@@ -46,6 +46,7 @@
 
 /* DMA addresses are 32-bits wide */
 typedef u32 dma_addr_t;
+typedef u64 dma64_addr_t;
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/chandev.h linux/include/asm-s390/chandev.h
--- v2.4.12/linux/include/asm-s390/chandev.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390/chandev.h	Thu Oct 11 09:43:38 2001
@@ -139,6 +139,10 @@
  * not operational the previous status is sent in the prevstatus variable.
  * This can be used in cases when the default handling isn't quite adequete
  * e.g. if a ssch is needed to reinitialize long running channel programs.
+ *
+ * This returns the number of devices found or -ENOMEM if the code didn't
+ * have enough memory to allocate the chandev control block
+ * or -EPERM if a duplicate entry is found.
  */
 int chandev_register_and_probe(chandev_probefunc probefunc,
 			       chandev_shutdownfunc shutdownfunc,
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/current.h linux/include/asm-s390/current.h
--- v2.4.12/linux/include/asm-s390/current.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390/current.h	Thu Oct 11 09:43:38 2001
@@ -19,7 +19,7 @@
 {
         struct task_struct *current;
         __asm__("lhi   %0,-8192\n\t"
-                "nr    %0,15"
+                "al    %0,0xc40"
                 : "=&r" (current) : : "cc" );
         return current;
  }
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/dasd.h linux/include/asm-s390/dasd.h
--- v2.4.12/linux/include/asm-s390/dasd.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390/dasd.h	Thu Oct 11 09:43:38 2001
@@ -36,6 +36,7 @@
         unsigned int dasd_io_time2[32];	 /* histogram of time from start to irq */
         unsigned int dasd_io_time2ps[32]; /* histogram of time from start to irq */
         unsigned int dasd_io_time3[32];	 /* histogram of time from irq to end */
+        unsigned int dasd_io_nr_req[32]; /* histogram of # of requests in chanq */
 } dasd_profile_info_t;
 
 /* 
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/debug.h linux/include/asm-s390/debug.h
--- v2.4.12/linux/include/asm-s390/debug.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390/debug.h	Thu Oct 11 09:43:38 2001
@@ -44,6 +44,7 @@
 
 #define DEBUG_MAX_LEVEL            6  /* debug levels range from 0 to 6 */
 #define DEBUG_OFF_LEVEL            -1 /* level where debug is switched off */
+#define DEBUG_FLUSH_ALL            -1 /* parameter to flush all areas */
 #define DEBUG_MAX_VIEWS            10 /* max number of views in proc fs */
 #define DEBUG_MAX_PROCF_LEN        16 /* max length for a proc file name */
 #define DEBUG_DEFAULT_LEVEL        3  /* initial debug level */
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/gdb-stub.h linux/include/asm-s390/gdb-stub.h
--- v2.4.12/linux/include/asm-s390/gdb-stub.h	Fri May 12 11:41:44 2000
+++ linux/include/asm-s390/gdb-stub.h	Thu Oct 11 09:43:38 2001
@@ -10,9 +10,13 @@
 #define __S390_GDB_STUB__
 #include <linux/config.h>
 #if CONFIG_REMOTE_DEBUG
-#include <asm/s390-gdbregs.h>
 #include <asm/ptrace.h>
 extern int    gdb_stub_initialised;
-extern void gdb_stub_handle_exception(gdb_pt_regs *regs,int sigval);
+extern void gdb_stub_handle_exception(struct gdb_pt_regs *regs,int sigval);
+struct net_device;
+struct net_device *gdb_dev;
+void gdb_do_timers(void);
+extern int putDebugChar(char c);    /* write a single character      */
+extern char getDebugChar(void);     /* read and return a single char */
 #endif
 #endif
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/lowcore.h linux/include/asm-s390/lowcore.h
--- v2.4.12/linux/include/asm-s390/lowcore.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390/lowcore.h	Thu Oct 11 09:43:38 2001
@@ -41,7 +41,7 @@
 
 #define __LC_SAVE_AREA                  0xC00
 #define __LC_KERNEL_STACK               0xC40
-#define __LC_KERNEL_LEVEL               0xC44
+#define __LC_ASYNC_STACK                0xC44
 #define __LC_CPUID                      0xC60
 #define __LC_CPUADDR                    0xC68
 #define __LC_IPLDEV                     0xC7C
@@ -86,6 +86,12 @@
 #include <asm/atomic.h>
 #include <asm/sigp.h>
 
+void restart_int_handler(void);
+void ext_int_handler(void);
+void system_call(void);
+void pgm_check_handler(void);
+void mcck_int_handler(void);
+void io_int_handler(void);
 
 struct _lowcore
 {
@@ -107,7 +113,7 @@
 	__u16        cpu_addr;                 /* 0x084 */
 	__u16        ext_int_code;             /* 0x086 */
         __u16        svc_ilc;                  /* 0x088 */
-        __u16        scv_code;                 /* 0x08a */
+        __u16        svc_code;                 /* 0x08a */
         __u16        pgm_ilc;                  /* 0x08c */
         __u16        pgm_code;                 /* 0x08e */
 	__u32        trans_exc_code;           /* 0x090 */
@@ -147,7 +153,7 @@
         /* System info area */
 	__u32        save_area[16];            /* 0xc00 */
 	__u32        kernel_stack;             /* 0xc40 */
-	__u32        kernel_level;             /* 0xc44 */
+	__u32        async_stack;              /* 0xc44 */
 	/* entry.S sensitive area start */
 	__u8         pad10[0xc60-0xc48];       /* 0xc5c */
 	struct       cpuinfo_S390 cpu_data;    /* 0xc60 */
@@ -157,9 +163,7 @@
         /* SMP info area: defined by DJB */
         __u64        jiffy_timer_cc;           /* 0xc80 */
 	atomic_t     ext_call_fast;            /* 0xc88 */
-	atomic_t     ext_call_queue;           /* 0xc8c */
-        atomic_t     ext_call_count;           /* 0xc90 */
-        __u8         pad11[0xe00-0xc94];       /* 0xc94 */
+        __u8         pad11[0xe00-0xc8c];       /* 0xc8c */
 
         /* 0xe00 is used as indicator for dump tools */
         /* whether the kernel died with panic() or not */
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/pgalloc.h linux/include/asm-s390/pgalloc.h
--- v2.4.12/linux/include/asm-s390/pgalloc.h	Mon Apr 23 15:28:07 2001
+++ linux/include/asm-s390/pgalloc.h	Thu Oct 11 09:43:38 2001
@@ -84,6 +84,8 @@
 #define pmd_alloc_one_fast(mm, address) ({ BUG(); ((pmd_t *)1); })
 #define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); })
 #define pmd_free(x)                     do { } while (0)
+#define pmd_free_slow(x)		do { } while (0)
+#define pmd_free_fast(x)                do { } while (0)
 #define pgd_populate(mm, pmd, pte)      BUG()
 
 extern inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/pgtable.h linux/include/asm-s390/pgtable.h
--- v2.4.12/linux/include/asm-s390/pgtable.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390/pgtable.h	Thu Oct 11 09:43:38 2001
@@ -58,13 +58,6 @@
 #endif /* !__ASSEMBLY__ */
 
 /*
- * Certain architectures need to do special things when PTEs
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
-
-/*
  * PMD_SHIFT determines the size of the area a second-level page
  * table can map
  */
@@ -162,6 +155,7 @@
 
 /* Bits in the page table entry */
 #define _PAGE_PRESENT   0x001          /* Software                         */
+#define _PAGE_MKCLEAR   0x002          /* Software                         */
 #define _PAGE_RO        0x200          /* HW read-only                     */
 #define _PAGE_INVALID   0x400          /* HW invalid                       */
 
@@ -226,6 +220,25 @@
 #define __S111  PAGE_SHARED
 
 /*
+ * Certain architectures need to do special things when PTEs
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+extern inline void set_pte(pte_t *pteptr, pte_t pteval)
+{
+	if ((pte_val(pteval) & (_PAGE_MKCLEAR|_PAGE_INVALID))
+	    == _PAGE_MKCLEAR) 
+	{
+		pte_val(pteval) &= ~_PAGE_MKCLEAR;
+               
+		asm volatile ("sske %0,%1" 
+				: : "d" (0), "a" (pte_val(pteval)));
+	}
+
+	*pteptr = pteval;
+}
+
+/*
  * Permanent address of a page.
  */
 #define page_address(page) ((page)->virtual)
@@ -323,23 +336,22 @@
 
 extern inline pte_t pte_mkclean(pte_t pte)
 {
-	/* We can't clear the changed bit atomically. The iske/and/sske
-         * sequence has a race condition with the page referenced bit.
-         * At the moment pte_mkclean is always followed by a pte_mkold.
-         * So its safe to ignore the problem for now. Hope this will
-         * never change ... */
-	asm volatile ("sske %0,%1" 
-	              : : "d" (0), "a" (pte_val(pte)));
+	/* The only user of pte_mkclean is the fork() code.
+	   We must *not* clear the *physical* page dirty bit
+	   just because fork() wants to clear the dirty bit in
+	   *one* of the page's mappings.  So we just do nothing. */
 	return pte;
 }
 
 extern inline pte_t pte_mkdirty(pte_t pte)
 {
-	/* We can't set the changed bit atomically either. For now we
+	/* We can't set the changed bit atomically. For now we
          * set (!) the page referenced bit. */
 	asm volatile ("sske %0,%1" 
 	              : : "d" (_PAGE_CHANGED|_PAGE_REFERENCED),
 		          "a" (pte_val(pte)));
+
+	pte_val(pte) &= ~_PAGE_MKCLEAR;
 	return pte;
 }
 
@@ -411,7 +423,23 @@
 	pte_val(__pte) = physpage + pgprot_val(pgprot);
 	return __pte;
 }
-#define mk_pte(page,pgprot) mk_pte_phys(__pa(((page)-mem_map)<<PAGE_SHIFT),pgprot)
+
+#define mk_pte(pg, pgprot)                                                \
+({                                                                        \
+	struct page *__page = (pg);                                       \
+	unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT);  \
+	pte_t __pte = mk_pte_phys(__physpage, (pgprot));                  \
+	                                                                  \
+	if (__page != ZERO_PAGE(__physpage)) {                            \
+		int __users = page_count(__page);                         \
+		__users -= !!__page->buffers + !!__page->mapping;         \
+	                                                                  \
+		if (__users == 1)                                         \
+			pte_val(__pte) |= _PAGE_MKCLEAR;                  \
+        }                                                                 \
+	                                                                  \
+	__pte;                                                            \
+})
 
 #define pte_page(x) (mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT)))
 
@@ -472,6 +500,11 @@
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
 #define PageSkip(page)          (0)
 #define kern_addr_valid(addr)   (1)
+
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init()	do { } while (0)
 
 #endif /* _S390_PAGE_H */
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/ptrace.h linux/include/asm-s390/ptrace.h
--- v2.4.12/linux/include/asm-s390/ptrace.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/ptrace.h	Thu Oct 11 09:43:38 2001
@@ -191,6 +191,7 @@
 	__u32 trap;
 	__u32 crs[16];
 	s390_fp_regs fp_regs;
+	__u32 old_ilc;
 };
 #endif
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/scatterlist.h linux/include/asm-s390/scatterlist.h
--- v2.4.12/linux/include/asm-s390/scatterlist.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -3,8 +3,6 @@
 
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to */
-    char * alt_address; /* Location of actual if address is a 
-			 * dma indirect buffer.  NULL otherwise */
     unsigned int length;
 };
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/sigp.h linux/include/asm-s390/sigp.h
--- v2.4.12/linux/include/asm-s390/sigp.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/sigp.h	Thu Oct 11 09:43:38 2001
@@ -62,34 +62,9 @@
         ec_restart,
         ec_halt,
         ec_power_off,
-        ec_ptlb,
+	ec_call_function,
 	ec_bit_last
 } ec_bit_sig;
-
-/* Signals which come with a parameter area, synchronous */
-typedef enum
-{
-        ec_callback_async,
-        ec_callback_sync
-} ec_cmd_sig;
-
-/* state information for synchronous signals */
-typedef enum
-{
-	ec_pending,
-	ec_executing,
-	ec_done
-} ec_state;
-
-/* header for the queuing of signals with a parameter area */
-typedef struct ec_ext_call
-{
-	ec_cmd_sig cmd;
-	atomic_t status;
-	struct ec_ext_call *next;
-        void (*func)(void *info);
-        void *info;
-} ec_ext_call;
 
 /*
  * Signal processor
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/smp.h linux/include/asm-s390/smp.h
--- v2.4.12/linux/include/asm-s390/smp.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/smp.h	Thu Oct 11 09:43:38 2001
@@ -26,6 +26,8 @@
 	__u16      cpu;
 } sigp_info;
 
+extern unsigned long cpu_online_map;
+
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
 
 /*
@@ -64,12 +66,5 @@
 
 void smp_local_timer_interrupt(struct pt_regs * regs);
 
-sigp_ccode smp_ext_call(int cpu, void (*cb)(void *info), void *info, int wait);
-void smp_ext_call_others(void (*cb)(void *info), void *info, int wait);
-sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig);
-void smp_ext_bitcall_others(ec_bit_sig sig);
-
-int smp_signal_others(sigp_order_code order_code,__u32 parameter,
-                      int spin,sigp_info *info);
 #endif
 #endif
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/softirq.h linux/include/asm-s390/softirq.h
--- v2.4.12/linux/include/asm-s390/softirq.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-s390/softirq.h	Thu Oct 11 09:43:38 2001
@@ -18,22 +18,25 @@
 #include <asm/lowcore.h>
 
 #define __cpu_bh_enable(cpu) \
-		do { barrier(); local_bh_count(cpu)--; } while (0)
+                do { barrier(); local_bh_count(cpu)--; } while (0)
 #define cpu_bh_disable(cpu) \
-		do { local_bh_count(cpu)++; barrier(); } while (0)
+                do { local_bh_count(cpu)++; barrier(); } while (0)
 
 #define local_bh_disable()      cpu_bh_disable(smp_processor_id())
 #define __local_bh_enable()     __cpu_bh_enable(smp_processor_id())
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
+extern void do_call_softirq(void);
+
 #define local_bh_enable()			          	        \
 do {							                \
-	unsigned int *ptr = &local_bh_count(smp_processor_id());        \
-	barrier();                                                      \
-	if (!--*ptr)							\
+        unsigned int *ptr = &local_bh_count(smp_processor_id());        \
+        barrier();                                                      \
+        if (!--*ptr)							\
 		if (softirq_pending(smp_processor_id()))		\
-			do_softirq();					\
+			/* Use the async. stack for softirq */		\
+			do_call_softirq();				\
 } while (0)
 
 #endif	/* __ASM_SOFTIRQ_H */
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/spinlock.h linux/include/asm-s390/spinlock.h
--- v2.4.12/linux/include/asm-s390/spinlock.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/spinlock.h	Thu Oct 11 09:43:38 2001
@@ -32,20 +32,19 @@
         __asm__ __volatile("    bras  1,1f\n"
                            "0:  diag  0,0,68\n"
                            "1:  slr   0,0\n"
-                           "    cs    0,1,%1\n"
+                           "    cs    0,1,0(%0)\n"
                            "    jl    0b\n"
-                           : "=m" (lp->lock)
-                           : "0" (lp->lock) : "0", "1", "cc" );
+                           : : "a" (&lp->lock) : "0", "1", "cc", "memory" );
 }
 
 extern inline int spin_trylock(spinlock_t *lp)
 {
 	unsigned long result;
-	__asm__ __volatile("    slr   %1,%1\n"
+	__asm__ __volatile("    slr   %0,%0\n"
 			   "    basr  1,0\n"
-			   "0:  cs    %1,1,%0"
-			   : "=m" (lp->lock), "=&d" (result)
-			   : "0" (lp->lock) : "1", "cc" );
+			   "0:  cs    %0,1,0(%1)"
+			   : "=&d" (result)
+			   : "a" (&lp->lock) : "1", "cc", "memory" );
 	return !result;
 }
 
@@ -53,7 +52,7 @@
 {
 	__asm__ __volatile("    xc 0(4,%0),0(%0)\n"
                            "    bcr 15,0"
-			   : /* no output */ : "a" (lp) : "memory", "cc" );
+			   : : "a" (&lp->lock) : "memory", "cc" );
 }
 		
 /*
@@ -76,24 +75,24 @@
 #define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
 #define read_lock(rw)   \
-        asm volatile("   l     2,%0\n"   \
+        asm volatile("   l     2,0(%0)\n"   \
                      "   j     1f\n"     \
                      "0: diag  0,0,68\n" \
-                     "1: la    2,0(2)\n"  /* clear high (=write) bit */ \
-                     "   la    3,1(2)\n"  /* one more reader */ \
-                     "   cs    2,3,%0\n"  /* try to write new value */ \
+                     "1: la    2,0(2)\n"     /* clear high (=write) bit */ \
+                     "   la    3,1(2)\n"     /* one more reader */ \
+                     "   cs    2,3,0(%0)\n"  /* try to write new value */ \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "2", "3", "cc" );
+                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
 
 #define read_unlock(rw) \
-        asm volatile("   l     2,%0\n"   \
+        asm volatile("   l     2,0(%0)\n"   \
                      "   j     1f\n"     \
                      "0: diag  0,0,68\n" \
                      "1: lr    3,2\n"    \
                      "   ahi   3,-1\n"    /* one less reader */ \
-                     "   cs    2,3,%0\n" \
+                     "   cs    2,3,0(%0)\n" \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "2", "3", "cc" );
+                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
 
 #define write_lock(rw) \
         asm volatile("   lhi   3,1\n"    \
@@ -101,9 +100,9 @@
                      "   j     1f\n"     \
                      "0: diag  0,0,68\n" \
                      "1: slr   2,2\n"     /* old lock value must be 0 */ \
-                     "   cs    2,3,%0\n" \
+                     "   cs    2,3,0(%0)\n" \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "2", "3", "cc" );
+                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
 
 #define write_unlock(rw) \
         asm volatile("   slr   3,3\n"     /* new lock value = 0 */ \
@@ -111,8 +110,8 @@
                      "0: diag  0,0,68\n" \
                      "1: lhi   2,1\n"    \
                      "   sll   2,31\n"    /* old lock value must be 0x80000000 */ \
-                     "   cs    2,3,%0\n" \
+                     "   cs    2,3,0(%0)\n" \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "2", "3", "cc" );
+                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
 
 #endif /* __ASM_SPINLOCK_H */
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/uaccess.h linux/include/asm-s390/uaccess.h
--- v2.4.12/linux/include/asm-s390/uaccess.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390/uaccess.h	Thu Oct 11 09:43:38 2001
@@ -78,6 +78,35 @@
  * use the right size if we just have the right pointer type.
  */
 
+extern inline int __put_user_asm_8(__u64 x, void *ptr)
+{
+        int err;
+
+        __asm__ __volatile__ (  "   sr    %1,%1\n"
+				"   la    2,%2\n"
+				"   la    4,%0\n"
+                                "   sacf  512\n"
+                                "0: mvc   0(8,4),0(2)\n"
+                                "   sacf  0\n"
+				"1:\n"
+				".section .fixup,\"ax\"\n"
+				"2: sacf  0\n"
+				"   lhi   %1,%h3\n"
+				"   bras  4,3f\n"
+				"   .long 1b\n"
+				"3: l     4,0(4)\n"
+				"   br    4\n"
+				".previous\n"
+				".section __ex_table,\"a\"\n"
+				"   .align 4\n"
+				"   .long  0b,2b\n"
+				".previous"
+                                : "=m" (*((__u32*) ptr)), "=&d" (err)
+                                : "m" (x), "K" (-EFAULT)
+                                : "cc", "2", "4" );
+        return err;
+}
+
 extern inline int __put_user_asm_4(__u32 x, void *ptr)
 {
         int err;
@@ -179,6 +208,9 @@
                 case 4:                                         \
                         __pu_err = __put_user_asm_4((__u32) x,(ptr));\
                         break;                                  \
+		case 8:						\
+			__pu_err = __put_user_asm_8((__u64) x,(ptr));\
+			break;					\
                 default:                                        \
                 __pu_err = __put_user_bad();                    \
                 break;                                          \
@@ -200,6 +232,31 @@
 
 extern int __put_user_bad(void);
 
+#define __get_user_asm_8(x, ptr, err)                                      \
+({                                                                         \
+        __asm__ __volatile__ (  "   sr    %1,%1\n"                         \
+				"   la    2,%0\n"			   \
+                                "   la    4,%2\n"                          \
+                                "   sacf  512\n"                           \
+                                "0: mvc   0(8,2),0(4)\n"                   \
+                                "   sacf  0\n"                             \
+                                "1:\n"                                     \
+                                ".section .fixup,\"ax\"\n"                 \
+                                "2: sacf  0\n"                             \
+                                "   lhi   %1,%h3\n"                        \
+                                "   bras  4,3f\n"                          \
+                                "   .long 1b\n"                            \
+                                "3: l     4,0(4)\n"                        \
+                                "   br    4\n"                             \
+                                ".previous\n"                              \
+                                ".section __ex_table,\"a\"\n"              \
+                                "   .align 4\n"                            \
+                                "   .long 0b,2b\n"                         \
+                                ".previous"                                \
+                                : "=m" (x) , "=&d" (err)                   \
+                                : "m" (*(const __u64*)(ptr)),"K" (-EFAULT) \
+                                : "cc", "2", "4" );                        \
+})
 
 #define __get_user_asm_4(x, ptr, err)                                      \
 ({                                                                         \
@@ -290,6 +347,9 @@
                 case 4:                                         \
                         __get_user_asm_4(x,ptr,__gu_err);       \
                         break;                                  \
+                case 8:                                         \
+                        __get_user_asm_8(x,ptr,__gu_err);       \
+                        break;                                  \
                 default:                                        \
                         (x) = 0;                                \
                         __gu_err = __get_user_bad();            \
@@ -372,7 +432,7 @@
                                 "0: mvcle 2,4,0\n"
                                 "   jo    0b\n"
                                 "   sacf  0\n"
-                                "   lr    %0,3\n"
+                                "   lr    %0,5\n"
 				".section __ex_table,\"a\"\n"
 				"   .align 4\n"
 				"   .long  0b,__copy_from_user_fixup\n"
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/ucontext.h linux/include/asm-s390/ucontext.h
--- v2.4.12/linux/include/asm-s390/ucontext.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/ucontext.h	Thu Oct 11 09:43:38 2001
@@ -13,10 +13,8 @@
 	unsigned long	  uc_flags;
 	struct ucontext  *uc_link;
 	stack_t		  uc_stack;
+	_sigregs          uc_mcontext;
 	sigset_t	  uc_sigmask;	/* mask last for extensibility */
-	struct sigcontext *sc; /* Added for pthread support */
 };
-
-
 
 #endif /* !_ASM_S390_UCONTEXT_H */
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/unistd.h linux/include/asm-s390/unistd.h
--- v2.4.12/linux/include/asm-s390/unistd.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/unistd.h	Thu Oct 11 09:43:38 2001
@@ -178,6 +178,8 @@
 #define __NR_capset             185
 #define __NR_sigaltstack        186
 #define __NR_sendfile           187
+#define __NR_getpmsg		188
+#define __NR_putpmsg		189
 #define __NR_vfork		190
 #define __NR_ugetrlimit		191	/* SuS compliant getrlimit */
 #define __NR_mmap2		192
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/vtoc.h linux/include/asm-s390/vtoc.h
--- v2.4.12/linux/include/asm-s390/vtoc.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390/vtoc.h	Thu Oct 11 09:43:38 2001
@@ -39,135 +39,6 @@
 
 #define VTOC_ERROR "VTOC error:"
 
-enum failure {unable_to_open,
-	      unable_to_seek,
-	      unable_to_write,
-	      unable_to_read};
-
-unsigned char ASCtoEBC[256] =
-{
-  /*00  NL    SH    SX    EX    ET    NQ    AK    BL */
-  0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
-  /*08  BS    HT    LF    VT    FF    CR    SO    SI */
-  0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-  /*10  DL    D1    D2    D3    D4    NK    SN    EB */
-  0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26,
-  /*18  CN    EM    SB    EC    FS    GS    RS    US */
-  0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
-  /*20  SP     !     "     #     $     %     &     ' */
-  0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
-  /*28   (     )     *     +     ,     -    .      / */
-  0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
-  /*30   0     1     2     3     4     5     6     7 */
-  0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
-  /*38   8     9     :     ;     <     =     >     ? */
-  0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
-  /*40   @     A     B     C     D     E     F     G */
-  0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
-  /*48   H     I     J     K     L     M     N     O */
-  0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
-  /*50   P     Q     R     S     T     U     V     W */
-  0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
-  /*58   X     Y     Z     [     \     ]     ^     _ */
-  0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
-  /*60   `     a     b     c     d     e     f     g */
-  0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
-  /*68   h     i     j     k     l     m     n     o */
-  0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
-  /*70   p     q     r     s     t     u     v     w */
-  0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
-  /*78   x     y     z     {     |     }     ~    DL */
-  0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
-};
-
-
-unsigned char EBCtoASC[256] =
-{
- /* 0x00   NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
-          0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
- /* 0x08   -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
-          0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- /* 0x10   DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC
-                                  -ENP  ->LF             */
-          0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
- /* 0x18   CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB
-                                                    -IUS */
-          0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- /* 0x20   -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC
-                                  -INP                   */
-          0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
- /* 0x28   -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL
-                       -SW                               */ 
-          0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
- /* 0x30  ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
-          0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
- /* 0x38  -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
-          0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
- /* 0x40    SP   RSP           ä              ----       */
-          0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
- /* 0x48                       .     <     (     +     | */
-          0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
- /* 0x50     &                                      ---- */
-          0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
- /* 0x58           ß     !     $     *     )     ;       */
-          0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
- /* 0x60     -     /  ----     Ä  ----  ----  ----       */
-          0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
- /* 0x68              ----     ,     %     _     >     ? */ 
-          0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
- /* 0x70  ----        ----  ----  ----  ----  ----  ---- */
-          0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- /* 0x78     *     `     :     #     @     '     =     " */
-          0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
- /* 0x80     *     a     b     c     d     e     f     g */
-          0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- /* 0x88     h     i              ----  ----  ----       */
-          0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
- /* 0x90     °     j     k     l     m     n     o     p */
-          0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
- /* 0x98     q     r                    ----        ---- */
-          0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
- /* 0xA0           ~     s     t     u     v     w     x */
-          0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- /* 0xA8     y     z              ----  ----  ----  ---- */
-          0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
- /* 0xB0     ^                    ----     §  ----       */
-          0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
- /* 0xB8        ----     [     ]  ----  ----  ----  ---- */
-          0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
- /* 0xC0     {     A     B     C     D     E     F     G */
-          0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- /* 0xC8     H     I  ----           ö              ---- */
-          0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
- /* 0xD0     }     J     K     L     M     N     O     P */
-          0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
- /* 0xD8     Q     R  ----           ü                   */
-          0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
- /* 0xE0     \           S     T     U     V     W     X */
-          0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
- /* 0xE8     Y     Z        ----     Ö  ----  ----  ---- */
-          0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
- /* 0xF0     0     1     2     3     4     5     6     7 */
-          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- /* 0xF8     8     9  ----  ----     Ü  ----  ----  ---- */
-          0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
-};
 
 typedef struct ttr 
 {
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/chandev.h linux/include/asm-s390x/chandev.h
--- v2.4.12/linux/include/asm-s390x/chandev.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390x/chandev.h	Thu Oct 11 09:43:38 2001
@@ -139,6 +139,10 @@
  * not operational the previous status is sent in the prevstatus variable.
  * This can be used in cases when the default handling isn't quite adequete
  * e.g. if a ssch is needed to reinitialize long running channel programs.
+ *
+ * This returns the number of devices found or -ENOMEM if the code didn't
+ * have enough memory to allocate the chandev control block
+ * or -EPERM if a duplicate entry is found.
  */
 int chandev_register_and_probe(chandev_probefunc probefunc,
 			       chandev_shutdownfunc shutdownfunc,
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/current.h linux/include/asm-s390x/current.h
--- v2.4.12/linux/include/asm-s390x/current.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390x/current.h	Thu Oct 11 09:43:38 2001
@@ -19,7 +19,7 @@
 {
         struct task_struct *current;
         __asm__("lghi  %0,-16384\n\t"
-                "ngr   %0,15"
+                "alg   %0,0xd40"
                 : "=&r" (current) : : "cc" );
         return current;
  }
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/dasd.h linux/include/asm-s390x/dasd.h
--- v2.4.12/linux/include/asm-s390x/dasd.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390x/dasd.h	Thu Oct 11 09:43:38 2001
@@ -36,6 +36,7 @@
         unsigned int dasd_io_time2[32];	 /* histogram of time from start to irq */
         unsigned int dasd_io_time2ps[32]; /* histogram of time from start to irq */
         unsigned int dasd_io_time3[32];	 /* histogram of time from irq to end */
+        unsigned int dasd_io_nr_req[32]; /* histogram of # of requests in chanq */
 } dasd_profile_info_t;
 
 /* 
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/debug.h linux/include/asm-s390x/debug.h
--- v2.4.12/linux/include/asm-s390x/debug.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390x/debug.h	Thu Oct 11 09:43:38 2001
@@ -44,6 +44,7 @@
 
 #define DEBUG_MAX_LEVEL            6  /* debug levels range from 0 to 6 */
 #define DEBUG_OFF_LEVEL            -1 /* level where debug is switched off */
+#define DEBUG_FLUSH_ALL            -1 /* parameter to flush all areas */
 #define DEBUG_MAX_VIEWS            10 /* max number of views in proc fs */
 #define DEBUG_MAX_PROCF_LEN        16 /* max length for a proc file name */
 #define DEBUG_DEFAULT_LEVEL        3  /* initial debug level */
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/lowcore.h linux/include/asm-s390x/lowcore.h
--- v2.4.12/linux/include/asm-s390x/lowcore.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390x/lowcore.h	Thu Oct 11 09:43:38 2001
@@ -1,3 +1,4 @@
+
 /*
  *  include/asm-s390/lowcore.h
  *
@@ -39,7 +40,7 @@
 
 #define __LC_SAVE_AREA                  0xC00
 #define __LC_KERNEL_STACK               0xD40
-#define __LC_KERNEL_LEVEL               0xD48
+#define __LC_ASYNC_STACK                0xD48
 #define __LC_CPUID                      0xD90
 #define __LC_CPUADDR                    0xD98
 #define __LC_IPLDEV                     0xDB8
@@ -85,6 +86,12 @@
 #include <asm/atomic.h>
 #include <asm/sigp.h>
 
+void restart_int_handler(void);
+void ext_int_handler(void);
+void system_call(void);
+void pgm_check_handler(void);
+void mcck_int_handler(void);
+void io_int_handler(void);
 
 struct _lowcore
 {
@@ -96,7 +103,7 @@
 	__u16        cpu_addr;                 /* 0x084 */
 	__u16        ext_int_code;             /* 0x086 */
         __u16        svc_ilc;                  /* 0x088 */
-        __u16        scv_code;                 /* 0x08a */
+        __u16        svc_code;                 /* 0x08a */
         __u16        pgm_ilc;                  /* 0x08c */
         __u16        pgm_code;                 /* 0x08e */
 	__u32        data_exc_code;            /* 0x090 */
@@ -142,7 +149,7 @@
 	__u64        save_area[16];            /* 0xc00 */
         __u8         pad9[0xd40-0xc80];        /* 0xc80 */
  	__u64        kernel_stack;             /* 0xd40 */
-	__u64        kernel_level;             /* 0xd48 */
+	__u64        async_stack;              /* 0xd48 */
 	/* entry.S sensitive area start */
 	__u8         pad10[0xd80-0xd50];       /* 0xd64 */
 	struct       cpuinfo_S390 cpu_data;    /* 0xd80 */
@@ -153,10 +160,7 @@
         /* SMP info area: defined by DJB */
         __u64        jiffy_timer_cc;           /* 0xdc0 */
 	__u64        ext_call_fast;            /* 0xdc8 */
-	__u64        ext_call_queue;           /* 0xdd0 */
-        __u64        ext_call_count;           /* 0xdd8 */
-
-        __u8         pad12[0xe00-0xde0];       /* 0xde0 */
+        __u8         pad12[0xe00-0xdd0];       /* 0xdd0 */
 
         /* 0xe00 is used as indicator for dump tools */
         /* whether the kernel died with panic() or not */
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/mathemu.h linux/include/asm-s390x/mathemu.h
--- v2.4.12/linux/include/asm-s390x/mathemu.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/mathemu.h	Wed Dec 31 16:00:00 1969
@@ -1,48 +0,0 @@
-/*
- *  arch/s390/kernel/mathemu.h
- *    IEEE floating point emulation.
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
- */
-
-#ifndef __MATHEMU__
-#define __MATHEMU__
-
-extern int math_emu_b3(__u8 *, struct pt_regs *);
-extern int math_emu_ed(__u8 *, struct pt_regs *);
-extern void math_emu_ldr(__u8 *);
-extern void math_emu_ler(__u8 *);
-extern void math_emu_std(__u8 *, struct pt_regs *);
-extern void math_emu_ld(__u8 *, struct pt_regs *);
-extern void math_emu_ste(__u8 *, struct pt_regs *);
-extern void math_emu_le(__u8 *, struct pt_regs *);
-extern int math_emu_lfpc(__u8 *, struct pt_regs *);
-extern int math_emu_stfpc(__u8 *, struct pt_regs *);
-extern int math_emu_srnm(__u8 *, struct pt_regs *);
-
-
-extern __u64 __adddf3(__u64,__u64);
-extern __u64 __subdf3(__u64,__u64);
-extern __u64 __muldf3(__u64,__u64);
-extern __u64 __divdf3(__u64,__u64);
-extern long  __cmpdf2(__u64,__u64);
-extern __u64 __negdf2(__u64);
-extern __u64 __absdf2(__u64);
-extern __u32 __addsf3(__u32,__u32);
-extern __u32 __subsf3(__u32,__u32);
-extern __u32 __mulsf3(__u32,__u32);
-extern __u32 __divsf3(__u32,__u32);
-extern __u32 __negsf2(__u32);
-extern __u32 __abssf2(__u32);
-extern long  __cmpsf2(__u32,__u32);
-extern __u32 __truncdfsf2(__u64);
-extern __u32 __fixsfsi(__u32);
-extern __u32 __fixdfsi(__u64);
-extern __u64  __floatsidf(__u32);
-extern __u32  __floatsisf(__u32);
-extern __u64  __extendsfdf2(__u32);
-
-#endif                                 /* __MATHEMU__                      */
-
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/page.h linux/include/asm-s390x/page.h
--- v2.4.12/linux/include/asm-s390x/page.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-s390x/page.h	Thu Oct 11 09:43:38 2001
@@ -110,11 +110,6 @@
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)        (((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-/*
- *
- *
- */
-
 #define __PAGE_OFFSET           0x0UL
 #define PAGE_OFFSET             0x0UL
 #define __pa(x)                 (unsigned long)(x)
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/param.h linux/include/asm-s390x/param.h
--- v2.4.12/linux/include/asm-s390x/param.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/param.h	Thu Oct 11 09:43:38 2001
@@ -11,6 +11,9 @@
 
 #ifndef HZ
 #define HZ 100
+#ifdef __KERNEL__
+#define hz_to_std(a) (a)
+#endif
 #endif
 
 #define EXEC_PAGESIZE	4096
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/pgtable.h linux/include/asm-s390x/pgtable.h
--- v2.4.12/linux/include/asm-s390x/pgtable.h	Sun Aug 12 13:28:01 2001
+++ linux/include/asm-s390x/pgtable.h	Thu Oct 11 09:43:38 2001
@@ -54,13 +54,6 @@
 #endif /* !__ASSEMBLY__ */
 
 /*
- * Certain architectures need to do special things when PTEs
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
-
-/*
  * PMD_SHIFT determines the size of the area a second-level page
  * table can map
  */
@@ -164,6 +157,7 @@
 
 /* Bits in the page table entry */
 #define _PAGE_PRESENT   0x001          /* Software                         */
+#define _PAGE_MKCLEAR   0x002          /* Software                         */
 #define _PAGE_RO        0x200          /* HW read-only                     */
 #define _PAGE_INVALID   0x400          /* HW invalid                       */
 
@@ -180,7 +174,8 @@
  */
 #define _REGION_THIRD       0x4
 #define _REGION_THIRD_LEN   0x3 
-#define _REGION_TABLE       (_REGION_THIRD|_REGION_THIRD_LEN|0x40)
+#define _REGION_TABLE       (_REGION_THIRD|_REGION_THIRD_LEN|0x40|0x100)
+#define _KERN_REGION_TABLE  (_REGION_THIRD|_REGION_THIRD_LEN)
 
 /* Bits in the storage key */
 #define _PAGE_CHANGED    0x02          /* HW changed bit                   */
@@ -220,6 +215,25 @@
 #define __S111  PAGE_SHARED
 
 /*
+ * Certain architectures need to do special things when PTEs
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+extern inline void set_pte(pte_t *pteptr, pte_t pteval)
+{
+	if ((pte_val(pteval) & (_PAGE_MKCLEAR|_PAGE_INVALID))
+	    == _PAGE_MKCLEAR) 
+	{
+		pte_val(pteval) &= ~_PAGE_MKCLEAR;
+               
+		asm volatile ("sske %0,%1" 
+				: : "d" (0), "a" (pte_val(pteval)));
+	}
+
+	*pteptr = pteval;
+}
+
+/*
  * Permanent address of a page.
  */
 #define page_address(page) ((page)->virtual)
@@ -341,13 +355,10 @@
 
 extern inline pte_t pte_mkclean(pte_t pte)
 {
-	/* We can't clear the changed bit atomically. The iske/and/sske
-         * sequence has a race condition with the page referenced bit.
-         * At the moment pte_mkclean is always followed by a pte_mkold.
-         * So its safe to ignore the problem for now. Hope this will
-         * never change ... */
-	asm volatile ("sske %0,%1" 
-	              : : "d" (0), "a" (pte_val(pte)));
+	/* The only user of pte_mkclean is the fork() code.
+	   We must *not* clear the *physical* page dirty bit
+	   just because fork() wants to clear the dirty bit in
+	   *one* of the page's mappings.  So we just do nothing. */
 	return pte;
 }
 
@@ -358,6 +369,8 @@
 	asm volatile ("sske %0,%1" 
 	              : : "d" (_PAGE_CHANGED|_PAGE_REFERENCED),
 		          "a" (pte_val(pte)));
+
+	pte_val(pte) &= ~_PAGE_MKCLEAR;
 	return pte;
 }
 
@@ -429,7 +442,23 @@
 	pte_val(__pte) = physpage + pgprot_val(pgprot);
 	return __pte;
 }
-#define mk_pte(page,pgprot) mk_pte_phys(__pa(((page)-mem_map)<<PAGE_SHIFT),pgprot)
+
+#define mk_pte(pg, pgprot)                                                \
+({                                                                        \
+	struct page *__page = (pg);                                       \
+	unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT);  \
+	pte_t __pte = mk_pte_phys(__physpage, (pgprot));                  \
+	                                                                  \
+	if (__page != ZERO_PAGE(__physpage)) {                            \
+		int __users = page_count(__page);                         \
+		__users -= !!__page->buffers + !!__page->mapping;         \
+	                                                                  \
+		if (__users == 1)                                         \
+			pte_val(__pte) |= _PAGE_MKCLEAR;                  \
+        }                                                                 \
+	                                                                  \
+	__pte;                                                            \
+})
 
 #define pte_page(x) (mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT)))
 
@@ -491,6 +520,11 @@
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
 #define PageSkip(page)          (0)
 #define kern_addr_valid(addr)   (1)
+
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init()	do { } while (0)
 
 #endif /* _S390_PAGE_H */
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/scatterlist.h linux/include/asm-s390x/scatterlist.h
--- v2.4.12/linux/include/asm-s390x/scatterlist.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -3,8 +3,6 @@
 
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to */
-    char * alt_address; /* Location of actual if address is a 
-			 * dma indirect buffer.  NULL otherwise */
     unsigned int length;
 };
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/sigp.h linux/include/asm-s390x/sigp.h
--- v2.4.12/linux/include/asm-s390x/sigp.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/sigp.h	Thu Oct 11 09:43:38 2001
@@ -62,33 +62,10 @@
         ec_restart,
         ec_halt,
         ec_power_off,
+	ec_call_function,
 	ec_bit_last
 } ec_bit_sig;
 
-/* Signals which come with a parameter area */
-typedef enum
-{
-        ec_callback_sync,
-        ec_callback_async
-} ec_cmd_sig;
-
-/* state information for signals */
-typedef enum
-{
-	ec_pending,
-	ec_executing,
-	ec_done
-} ec_state;
-
-/* header for the queuing of callbacks */
-typedef struct ec_ext_call
-{
-	ec_cmd_sig cmd;
-	atomic_t status;
-	struct ec_ext_call *next;
-	void (*func)(void *info);
-	void *info;
-} ec_ext_call;
 
 /*
  * Signal processor
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/smp.h linux/include/asm-s390x/smp.h
--- v2.4.12/linux/include/asm-s390x/smp.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/smp.h	Thu Oct 11 09:43:38 2001
@@ -26,6 +26,8 @@
 	__u16      cpu;
 } sigp_info;
 
+extern unsigned long cpu_online_map;
+
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
 
 /*
@@ -64,12 +66,5 @@
 
 void smp_local_timer_interrupt(struct pt_regs * regs);
 
-sigp_ccode smp_ext_call(int cpu, void (*cb)(void *info), void *info, int wait);
-void smp_ext_call_others(void (*cb)(void *info), void *info, int wait);
-sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig);
-void smp_ext_bitcall_others(ec_bit_sig sig);
-
-int smp_signal_others(sigp_order_code order_code,__u32 parameter,
-                      int spin,sigp_info *info);
 #endif
 #endif
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/softirq.h linux/include/asm-s390x/softirq.h
--- v2.4.12/linux/include/asm-s390x/softirq.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-s390x/softirq.h	Thu Oct 11 09:43:38 2001
@@ -18,22 +18,25 @@
 #include <asm/lowcore.h>
 
 #define __cpu_bh_enable(cpu) \
-		do { barrier(); local_bh_count(cpu)--; } while (0)
+                do { barrier(); local_bh_count(cpu)--; } while (0)
 #define cpu_bh_disable(cpu) \
-		do { local_bh_count(cpu)++; barrier(); } while (0)
+                do { local_bh_count(cpu)++; barrier(); } while (0)
 
 #define local_bh_disable()      cpu_bh_disable(smp_processor_id())
 #define __local_bh_enable()     __cpu_bh_enable(smp_processor_id())
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
+extern void do_call_softirq(void);
+
 #define local_bh_enable()			          	        \
 do {							                \
-	unsigned int *ptr = &local_bh_count(smp_processor_id());        \
-	barrier();                                                      \
-	if (!--*ptr)							\
+        unsigned int *ptr = &local_bh_count(smp_processor_id());        \
+        barrier();                                                      \
+        if (!--*ptr)							\
 		if (softirq_pending(smp_processor_id()))		\
-			do_softirq();					\
+			/* Use the async. stack for softirq */		\
+			do_call_softirq();				\
 } while (0)
 
 #endif	/* __ASM_SOFTIRQ_H */
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/spinlock.h linux/include/asm-s390x/spinlock.h
--- v2.4.12/linux/include/asm-s390x/spinlock.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/spinlock.h	Thu Oct 11 09:43:38 2001
@@ -32,20 +32,19 @@
         __asm__ __volatile("    bras  1,1f\n"
                            "0:  # diag  0,0,68\n"
                            "1:  slr   0,0\n"
-                           "    cs    0,1,%1\n"
+                           "    cs    0,1,0(%0)\n"
                            "    jl    0b\n"
-                           : "=m" (lp->lock)
-                           : "0" (lp->lock) : "0", "1", "cc" );
+                           : : "a" (&lp->lock) : "0", "1", "cc", "memory" );
 }
 
 extern inline int spin_trylock(spinlock_t *lp)
 {
 	unsigned int result;
-	__asm__ __volatile("    slr   %1,%1\n"
+	__asm__ __volatile("    slr   %0,%0\n"
 			   "    basr  1,0\n"
-			   "0:  cs    %1,1,%0"
-			   : "=m" (lp->lock), "=&d" (result)
-			   : "0" (lp->lock) : "1", "cc" );
+			   "0:  cs    %0,1,0(%1)"
+			   : "=&d" (result)
+			   : "a" (&lp->lock) : "1", "cc", "memory" );
 	return !result;
 }
 
@@ -53,7 +52,7 @@
 {
 	__asm__ __volatile("    xc 0(4,%0),0(%0)\n"
                            "    bcr 15,0"
-			   : /* no output */ : "a" (lp) : "memory", "cc" );
+			   : : "a" (&lp->lock) : "memory", "cc" );
 }
 		
 /*
@@ -76,46 +75,42 @@
 #define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
 #define read_lock(rw)   \
-        asm volatile("   la    1,%0\n"   \
-                     "   lg    2,0(1)\n"   \
+        asm volatile("   lg    2,0(%0)\n"   \
                      "   j     1f\n"     \
                      "0: # diag  0,0,68\n" \
                      "1: nihh  2,0x7fff\n" /* clear high (=write) bit */ \
                      "   la    3,1(2)\n"   /* one more reader */  \
-                     "   csg   2,3,0(1)\n" /* try to write new value */ \
+                     "   csg   2,3,0(%0)\n" /* try to write new value */ \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "1", "2", "3", "cc" );
+                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
 
 #define read_unlock(rw) \
-        asm volatile("   la    1,%0\n"   \
-                     "   lg    2,0(1)\n"   \
+        asm volatile("   lg    2,0(%0)\n"   \
                      "   j     1f\n"     \
                      "0: # diag  0,0,68\n" \
                      "1: lgr   3,2\n"    \
                      "   bctgr 3,0\n"    /* one less reader */ \
-                     "   csg   2,3,0(1)\n" \
+                     "   csg   2,3,0(%0)\n" \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "1", "2", "3", "cc" );
+                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
 
 #define write_lock(rw) \
-        asm volatile("   la    1,%0\n"     \
-                     "   llihh 3,0x8000\n" /* new lock value = 0x80...0 */ \
+        asm volatile("   llihh 3,0x8000\n" /* new lock value = 0x80...0 */ \
                      "   j     1f\n"       \
                      "0: # diag  0,0,68\n"   \
                      "1: slgr  2,2\n"      /* old lock value must be 0 */ \
-                     "   csg   2,3,0(1)\n" \
+                     "   csg   2,3,0(%0)\n" \
                      "   jl    0b"         \
-                     : "+m" ((rw)->lock) : : "1", "2", "3", "cc" );
+                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
 
 #define write_unlock(rw) \
-        asm volatile("   la    1,%0\n"     \
-                     "   slgr  3,3\n"      /* new lock value = 0 */ \
+        asm volatile("   slgr  3,3\n"      /* new lock value = 0 */ \
                      "   j     1f\n"       \
                      "0: # diag  0,0,68\n"   \
                      "1: llihh 2,0x8000\n" /* old lock value must be 0x8..0 */\
-                     "   csg   2,3,0(1)\n"   \
+                     "   csg   2,3,0(%0)\n"   \
                      "   jl    0b"         \
-                     : "+m" ((rw)->lock) : : "1", "2", "3", "cc" );
+                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
 
 #endif /* __ASM_SPINLOCK_H */
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/ucontext.h linux/include/asm-s390x/ucontext.h
--- v2.4.12/linux/include/asm-s390x/ucontext.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/ucontext.h	Thu Oct 11 09:43:38 2001
@@ -13,10 +13,8 @@
 	unsigned long	  uc_flags;
 	struct ucontext  *uc_link;
 	stack_t		  uc_stack;
+	_sigregs          uc_mcontext;
 	sigset_t	  uc_sigmask;	/* mask last for extensibility */
-	struct sigcontext *sc; /* Added for pthread support */
 };
-
-
 
 #endif /* !_ASM_S390_UCONTEXT_H */
diff -u --recursive --new-file v2.4.12/linux/include/asm-s390x/unistd.h linux/include/asm-s390x/unistd.h
--- v2.4.12/linux/include/asm-s390x/unistd.h	Sun Aug 12 13:28:01 2001
+++ linux/include/asm-s390x/unistd.h	Thu Oct 11 09:43:38 2001
@@ -154,6 +154,8 @@
 #define __NR_capset             185
 #define __NR_sigaltstack        186
 #define __NR_sendfile           187
+#define __NR_getpmsg		188
+#define __NR_putpmsg		189
 #define __NR_vfork		190
 #define __NR_getrlimit		191	/* SuS compliant getrlimit */
 #define __NR_lchown  		198
@@ -199,7 +201,7 @@
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lr  %0,2"                               \
+                "    lgr  %0,2"                              \
                 : "=d" (__res)                               \
                 : "i" (__NR_##name)                          \
                 : _svc_clobber );                            \
@@ -212,7 +214,7 @@
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lr  %0,2"                               \
+                "    lgr  %0,2"                              \
                 : "=d" (__res)                               \
                 : "i" (__NR_##name),                         \
                   "d" (__arg1)                               \
@@ -227,7 +229,7 @@
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lr  %0,2"                               \
+                "    lgr  %0,2"                              \
                 : "=d" (__res)                               \
                 : "i" (__NR_##name),                         \
                   "d" (__arg1),                              \
@@ -244,7 +246,7 @@
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lr  %0,2"                               \
+                "    lgr  %0,2"                              \
                 : "=d" (__res)                               \
                 : "i" (__NR_##name),                         \
                   "d" (__arg1),                              \
@@ -264,7 +266,7 @@
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lr  %0,2"                               \
+                "    lgr  %0,2"                              \
                 : "=d" (__res)                               \
                 : "i" (__NR_##name),                         \
                   "d" (__arg1),                              \
@@ -287,7 +289,7 @@
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lr  %0,2"                               \
+                "    lgr  %0,2"                              \
                 : "=d" (__res)                               \
                 : "i" (__NR_##name),                         \
                   "d" (__arg1),                              \
diff -u --recursive --new-file v2.4.12/linux/include/asm-sh/ioctl.h linux/include/asm-sh/ioctl.h
--- v2.4.12/linux/include/asm-sh/ioctl.h	Mon Oct 18 11:16:13 1999
+++ linux/include/asm-sh/ioctl.h	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: ioctl.h,v 1.1 1999/09/18 17:29:53 gniibe Exp $
+/* $Id: ioctl.h,v 1.1 2000/04/14 16:48:21 mjd Exp $
  *
  * linux/ioctl.h for Linux by H.H. Bergman.
  */
diff -u --recursive --new-file v2.4.12/linux/include/asm-sh/namei.h linux/include/asm-sh/namei.h
--- v2.4.12/linux/include/asm-sh/namei.h	Sun Apr  2 15:49:07 2000
+++ linux/include/asm-sh/namei.h	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.1 1999/09/18 17:30:11 gniibe Exp $
+/* $Id: namei.h,v 1.3 2000/07/04 06:24:49 gniibe Exp $
  * linux/include/asm-sh/namei.h
  *
  * Included from linux/fs/namei.c
diff -u --recursive --new-file v2.4.12/linux/include/asm-sh/pci.h linux/include/asm-sh/pci.h
--- v2.4.12/linux/include/asm-sh/pci.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-sh/pci.h	Fri Oct 12 15:35:54 2001
@@ -191,7 +191,7 @@
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 {
 	return 1;
 }
diff -u --recursive --new-file v2.4.12/linux/include/asm-sh/scatterlist.h linux/include/asm-sh/scatterlist.h
--- v2.4.12/linux/include/asm-sh/scatterlist.h	Sun Mar  5 09:33:55 2000
+++ linux/include/asm-sh/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -3,8 +3,6 @@
 
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to */
-    char * alt_address; /* Location of actual if address is a 
-			 * dma indirect buffer.  NULL otherwise */
     unsigned int length;
 };
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-sh/uaccess.h linux/include/asm-sh/uaccess.h
--- v2.4.12/linux/include/asm-sh/uaccess.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-sh/uaccess.h	Mon Oct 15 13:36:48 2001
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.12 2001/07/27 06:09:47 gniibe Exp $
+/* $Id: uaccess.h,v 1.13 2001/10/01 02:22:01 gniibe Exp $
  *
  * User space memory access functions
  *
@@ -150,6 +150,7 @@
 case 1: __put_user_asm("b"); break; \
 case 2: __put_user_asm("w"); break; \
 case 4: __put_user_asm("l"); break; \
+case 8: __put_user_u64(__pu_val,__pu_addr,__pu_err); break; \
 default: __put_user_unknown(); break; \
 } __pu_err; })
 
@@ -165,6 +166,7 @@
 case 1: __put_user_asm("b"); break; \
 case 2: __put_user_asm("w"); break; \
 case 4: __put_user_asm("l"); break; \
+case 8: __put_user_u64(__pu_val,__pu_addr,__pu_err); break; \
 default: __put_user_unknown(); break; \
 } } __pu_err; })
 
@@ -189,6 +191,53 @@
 	:"=&r" (__pu_err) \
 	:"r" (__pu_val), "m" (__m(__pu_addr)), "i" (-EFAULT) \
         :"memory"); })
+
+#if defined(__LITTLE_ENDIAN__)
+#define __put_user_u64(val,addr,retval) \
+({ \
+__asm__ __volatile__( \
+	"1:\n\t" \
+	"mov.l	%R1,%2\n\t" \
+	"mov.l	%S1,%T2\n\t" \
+	"mov	#0,%0\n" \
+	"2:\n" \
+	".section	.fixup,\"ax\"\n" \
+	"3:\n\t" \
+	"nop\n\t" \
+	"mov.l	4f,%0\n\t" \
+	"jmp	@%0\n\t" \
+	" mov	%3,%0\n" \
+	"4:	.long	2b\n\t" \
+	".previous\n" \
+	".section	__ex_table,\"a\"\n\t" \
+	".long	1b, 3b\n\t" \
+	".previous" \
+	: "=r" (retval) \
+	: "r" (val), "m" (__m(addr)), "i" (-EFAULT) \
+        : "memory"); })
+#else
+({ \
+__asm__ __volatile__( \
+	"1:\n\t" \
+	"mov.l	%S1,%2\n\t" \
+	"mov.l	%R1,%T2\n\t" \
+	"mov	#0,%0\n" \
+	"2:\n" \
+	".section	.fixup,\"ax\"\n" \
+	"3:\n\t" \
+	"nop\n\t" \
+	"mov.l	4f,%0\n\t" \
+	"jmp	@%0\n\t" \
+	" mov	%3,%0\n" \
+	"4:	.long	2b\n\t" \
+	".previous\n" \
+	".section	__ex_table,\"a\"\n\t" \
+	".long	1b, 3b\n\t" \
+	".previous" \
+	: "=r" (retval) \
+	: "r" (val), "m" (__m(addr)), "i" (-EFAULT) \
+        : "memory"); })
+#endif
 
 extern void __put_user_unknown(void);
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc/highmem.h linux/include/asm-sparc/highmem.h
--- v2.4.12/linux/include/asm-sparc/highmem.h	Sun Feb 18 19:49:55 2001
+++ linux/include/asm-sparc/highmem.h	Wed Oct 17 14:16:39 2001
@@ -111,14 +111,11 @@
 
 static inline void kunmap_atomic(void *kvaddr, enum km_type type)
 {
-#if HIGHMEM_DEBUG
 	unsigned long vaddr = (unsigned long) kvaddr;
 	unsigned long idx = type + KM_TYPE_NR*smp_processor_id();
 
-#if 0
-	if (vaddr < FIXADDR_START) // FIXME
+	if (vaddr < FIX_KMAP_BEGIN) // FIXME
 		return;
-#endif
 
 	if (vaddr != FIX_KMAP_BEGIN + idx * PAGE_SIZE)
 		BUG();
@@ -130,6 +127,7 @@
 	flush_cache_all();
 #endif
 
+#ifdef HIGHMEM_DEBUG
 	/*
 	 * force other mappings to Oops if they'll try to access
 	 * this pte without first remap it
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc/pci.h linux/include/asm-sparc/pci.h
--- v2.4.12/linux/include/asm-sparc/pci.h	Wed May 16 10:31:27 2001
+++ linux/include/asm-sparc/pci.h	Fri Oct 12 15:35:54 2001
@@ -108,7 +108,7 @@
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 {
 	return 1;
 }
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc/pgalloc.h linux/include/asm-sparc/pgalloc.h
--- v2.4.12/linux/include/asm-sparc/pgalloc.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-sparc/pgalloc.h	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: pgalloc.h,v 1.13 2001/07/17 16:17:33 anton Exp $ */
+/* $Id: pgalloc.h,v 1.15 2001/10/18 09:06:37 davem Exp $ */
 #ifndef _SPARC_PGALLOC_H
 #define _SPARC_PGALLOC_H
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc/scatterlist.h linux/include/asm-sparc/scatterlist.h
--- v2.4.12/linux/include/asm-sparc/scatterlist.h	Mon Jan 31 23:37:19 2000
+++ linux/include/asm-sparc/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -1,4 +1,4 @@
-/* $Id: scatterlist.h,v 1.5 2000/01/29 16:27:07 jj Exp $ */
+/* $Id: scatterlist.h,v 1.6 2001/10/09 02:24:35 davem Exp $ */
 #ifndef _SPARC_SCATTERLIST_H
 #define _SPARC_SCATTERLIST_H
 
@@ -6,8 +6,6 @@
 
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to */
-    char * alt_address; /* Location of actual if address is a 
-			 * dma indirect buffer.  NULL otherwise */
     unsigned int length;
 
     __u32 dvma_address; /* A place to hang host-specific addresses at. */
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h
--- v2.4.12/linux/include/asm-sparc/unistd.h	Thu Oct 11 08:02:26 2001
+++ linux/include/asm-sparc/unistd.h	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.71 2001/10/09 10:54:39 davem Exp $ */
+/* $Id: unistd.h,v 1.72 2001/10/18 08:27:05 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -220,7 +220,7 @@
 #define __NR_oldlstat           202 /* Linux Specific                              */
 #define __NR_uselib             203 /* Linux Specific                              */
 #define __NR_readdir            204 /* Linux Specific                              */
-/* #define __NR_ioperm          205    Linux Specific - i386 specific, unused      */
+#define __NR_readahead          205 /* Linux Specific                              */
 #define __NR_socketcall         206 /* Linux Specific                              */
 #define __NR_syslog             207 /* Linux Specific                              */
 /* #define __NR_olduname        208    Linux Specific                              */
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc64/cache.h linux/include/asm-sparc64/cache.h
--- v2.4.12/linux/include/asm-sparc64/cache.h	Fri Aug  6 11:58:00 1999
+++ linux/include/asm-sparc64/cache.h	Wed Oct 17 14:16:39 2001
@@ -9,7 +9,8 @@
 
 #define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
 
-#define        SMP_CACHE_BYTES		64 /* L2 cache line size. */
+#define        SMP_CACHE_BYTES_SHIFT	6
+#define        SMP_CACHE_BYTES		(1 << SMP_CACHE_BYTES_SHIFT) /* L2 cache line size. */
 
 #ifdef MODULE
 #define __cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES)))
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h
--- v2.4.12/linux/include/asm-sparc64/hardirq.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-sparc64/hardirq.h	Wed Oct 17 14:16:39 2001
@@ -12,6 +12,7 @@
 #include <linux/spinlock.h>
 
 /* entry.S is sensitive to the offsets of these fields */
+/* rtrap.S is sensitive to the size of this structure */
 typedef struct {
 	unsigned int __softirq_pending;
 	unsigned int __unused_1;
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc64/pci.h linux/include/asm-sparc64/pci.h
--- v2.4.12/linux/include/asm-sparc64/pci.h	Wed May 16 10:31:27 2001
+++ linux/include/asm-sparc64/pci.h	Fri Oct 12 15:35:54 2001
@@ -28,6 +28,12 @@
 /* Dynamic DMA mapping stuff.
  */
 
+/* The PCI address space does not equal the physical memory
+ * address space.  The networking and block device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS	(0)
+
 #include <asm/scatterlist.h>
 
 struct pci_dev;
@@ -64,6 +70,11 @@
  */
 extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction);
 
+/* No highmem on sparc64, plus we have an IOMMU, so mapping pages is easy. */
+#define pci_map_page(dev, page, off, size, dir) \
+	pci_map_single(dev, (page_address(page) + (off)), size, dir)
+#define pci_unmap_page(dev,addr,sz,dir) pci_unmap_single(dev,addr,sz,dir)
+
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
@@ -79,13 +90,15 @@
  * Device ownership issues as mentioned above for pci_map_single are
  * the same here.
  */
-extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction);
+extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+		      int nents, int direction);
 
 /* Unmap a set of streaming mode DMA translations.
  * Again, cpu read rules concerning calls here are the same as for
  * pci_unmap_single() above.
  */
-extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction);
+extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+			 int nhwents, int direction);
 
 /* Make physical memory consistent for a single
  * streaming mode DMA translation after a transfer.
@@ -96,7 +109,8 @@
  * next point you give the PCI dma address back to the card, the
  * device again owns the buffer.
  */
-extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction);
+extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle,
+				size_t size, int direction);
 
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
@@ -111,7 +125,51 @@
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-extern int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask);
+extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask);
+
+/* PCI IOMMU mapping bypass support. */
+
+/* PCI 64-bit addressing works for all slots on all controller
+ * types on sparc64.  However, it requires that the device
+ * can drive enough of the 64 bits.
+ */
+#define PCI64_REQUIRED_MASK	(~(dma64_addr_t)0)
+#define PCI64_ADDR_BASE		0xfffc000000000000
+
+/* Usage of the pci_dac_foo interfaces is only valid if this
+ * test passes.
+ */
+#define pci_dac_dma_supported(pci_dev, mask) \
+	((((mask) & PCI64_REQUIRED_MASK) == PCI64_REQUIRED_MASK) ? 1 : 0)
+
+static __inline__ dma64_addr_t
+pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
+{
+	return (PCI64_ADDR_BASE +
+		__pa(page_address(page)) + offset);
+}
+
+static __inline__ struct page *
+pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
+{
+	unsigned long paddr = (dma_addr & PAGE_MASK) - PCI64_ADDR_BASE;
+
+	return virt_to_page(__va(paddr));
+}
+
+static __inline__ unsigned long
+pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
+{
+	return (dma_addr & ~PAGE_MASK);
+}
+
+static __inline__ void
+pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+{
+	/* DAC cycle addressing does not make use of the
+	 * PCI controller's streaming cache, so nothing to do.
+	 */
+}
 
 /* Return the index of the PCI controller for device PDEV. */
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc64/pgalloc.h linux/include/asm-sparc64/pgalloc.h
--- v2.4.12/linux/include/asm-sparc64/pgalloc.h	Tue Oct  9 17:06:53 2001
+++ linux/include/asm-sparc64/pgalloc.h	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: pgalloc.h,v 1.23 2001/09/25 20:21:48 kanoj Exp $ */
+/* $Id: pgalloc.h,v 1.26 2001/10/18 09:06:37 davem Exp $ */
 #ifndef _SPARC64_PGALLOC_H
 #define _SPARC64_PGALLOC_H
 
@@ -32,29 +32,14 @@
 
 extern void __flush_dcache_page(void *addr, int flush_icache);
 extern void __flush_icache_page(unsigned long);
-#if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
-#define flush_dcache_page(page) \
-do {	if ((page)->mapping && \
-	    !((page)->mapping->i_mmap) && \
-	    !((page)->mapping->i_mmap_shared)) \
-		set_bit(PG_dcache_dirty, &(page)->flags); \
-	else \
-		__flush_dcache_page((page)->virtual, \
-				    ((tlb_type == spitfire) && \
-				     (page)->mapping != NULL)); \
-} while(0)
-#else /* L1DCACHE_SIZE > PAGE_SIZE */
-#define flush_dcache_page(page) \
-do {	if ((page)->mapping && \
-	    !((page)->mapping->i_mmap) && \
-	    !((page)->mapping->i_mmap_shared)) \
-		set_bit(PG_dcache_dirty, &(page)->flags); \
-	else \
-		if ((tlb_type == spitfire) && \
-		    (page)->mapping != NULL) \
-			__flush_icache_page(__get_phys((unsigned long)((page)->virtual))); \
-} while(0)
-#endif /* L1DCACHE_SIZE > PAGE_SIZE */
+extern void flush_dcache_page_impl(struct page *page);
+#ifdef CONFIG_SMP
+extern void smp_flush_dcache_page_impl(struct page *page);
+#else
+#define smp_flush_dcache_page_impl flush_dcache_page_impl
+#endif
+
+extern void flush_dcache_page(struct page *page);
 
 extern void __flush_dcache_range(unsigned long start, unsigned long end);
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.4.12/linux/include/asm-sparc64/pgtable.h	Sun Sep 23 11:41:01 2001
+++ linux/include/asm-sparc64/pgtable.h	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.146 2001/09/11 02:20:23 kanoj Exp $
+/* $Id: pgtable.h,v 1.147 2001/10/17 18:26:58 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -47,6 +47,29 @@
 #ifndef __ASSEMBLY__
 
 #define PG_dcache_dirty		PG_arch_1
+
+#define dcache_dirty_cpu(page) \
+	(((page)->flags >> 24) & (NR_CPUS - 1UL))
+
+#define set_dcache_dirty(PAGE) \
+do {	unsigned long mask = smp_processor_id(); \
+	unsigned long non_cpu_bits = (1UL << 24UL) - 1UL; \
+	mask = (mask << 24) | (1UL << PG_dcache_dirty); \
+	__asm__ __volatile__("1:\n\t" \
+			     "ldx	[%2], %%g7\n\t" \
+			     "and	%%g7, %1, %%g5\n\t" \
+			     "or	%%g5, %0, %%g5\n\t" \
+			     "casx	[%2], %%g7, %%g5\n\t" \
+			     "cmp	%%g7, %%g5\n\t" \
+			     "bne,pn	%%xcc, 1b\n\t" \
+			     " nop" \
+			     : /* no outputs */ \
+			     : "r" (mask), "r" (non_cpu_bits), "r" (&(PAGE)->flags) \
+			     : "g5", "g7"); \
+} while (0)
+
+#define clear_dcache_dirty(PAGE) \
+	clear_bit(PG_dcache_dirty, &(PAGE)->flags)
 
 /* Certain architectures need to do special things when pte's
  * within a page table are directly modified.  Thus, the following
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc64/scatterlist.h linux/include/asm-sparc64/scatterlist.h
--- v2.4.12/linux/include/asm-sparc64/scatterlist.h	Mon Dec 20 22:05:52 1999
+++ linux/include/asm-sparc64/scatterlist.h	Fri Oct 12 15:35:54 2001
@@ -1,21 +1,27 @@
-/* $Id: scatterlist.h,v 1.9 1999/12/17 12:32:15 jj Exp $ */
+/* $Id: scatterlist.h,v 1.10 2001/10/09 02:24:35 davem Exp $ */
 #ifndef _SPARC64_SCATTERLIST_H
 #define _SPARC64_SCATTERLIST_H
 
 #include <asm/page.h>
 
 struct scatterlist {
-    char *  address;    /* Location data is to be transferred to */
-    char * alt_address; /* Location of actual if address is a 
-			 * dma indirect buffer.  NULL otherwise */
-    unsigned int length;
+	/* This will disappear in 2.5.x */
+	char *address;
 
-    __u32 dvma_address; /* A place to hang host-specific addresses at. */
-    __u32 dvma_length;
+	/* These two are only valid if ADDRESS member of this
+	 * struct is NULL.
+	 */
+	struct page *page;
+	unsigned int offset;
+
+	unsigned int length;
+
+	dma_addr_t dma_address;
+	__u32 dma_length;
 };
 
-#define sg_dma_address(sg) ((sg)->dvma_address)
-#define sg_dma_len(sg)     ((sg)->dvma_length)
+#define sg_dma_address(sg)	((sg)->dma_address)
+#define sg_dma_len(sg)     	((sg)->dma_length)
 
 #define ISA_DMA_THRESHOLD	(~0UL)
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc64/types.h linux/include/asm-sparc64/types.h
--- v2.4.12/linux/include/asm-sparc64/types.h	Mon Jan 31 23:37:19 2000
+++ linux/include/asm-sparc64/types.h	Fri Oct 12 15:35:54 2001
@@ -1,4 +1,4 @@
-/* $Id: types.h,v 1.3 2000/01/28 13:43:15 jj Exp $ */
+/* $Id: types.h,v 1.4 2001/10/09 02:24:35 davem Exp $ */
 #ifndef _SPARC64_TYPES_H
 #define _SPARC64_TYPES_H
 
@@ -45,9 +45,10 @@
 
 #define BITS_PER_LONG 64
 
-/* Dma addresses are 32-bits wide for now.  */
+/* Dma addresses come in generic and 64-bit flavours.  */
 
 typedef u32 dma_addr_t;
+typedef u64 dma64_addr_t;
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.12/linux/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h
--- v2.4.12/linux/include/asm-sparc64/unistd.h	Thu Oct 11 08:02:26 2001
+++ linux/include/asm-sparc64/unistd.h	Sun Oct 21 10:36:54 2001
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.48 2001/10/09 10:54:39 davem Exp $ */
+/* $Id: unistd.h,v 1.49 2001/10/18 08:27:05 davem Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
@@ -220,7 +220,7 @@
 #define __NR_oldlstat           202 /* Linux Specific                              */
 #define __NR_uselib             203 /* Linux Specific                              */
 #define __NR_readdir            204 /* Linux Specific                              */
-/* #define __NR_ioperm          205    Linux Specific - i386 specific, unused      */
+#define __NR_readahead          205 /* Linux Specific                              */
 #define __NR_socketcall         206 /* Linux Specific                              */
 #define __NR_syslog             207 /* Linux Specific                              */
 /* #define __NR_olduname        208    Linux Specific                              */
diff -u --recursive --new-file v2.4.12/linux/include/linux/b1lli.h linux/include/linux/b1lli.h
--- v2.4.12/linux/include/linux/b1lli.h	Sat May 19 17:54:14 2001
+++ linux/include/linux/b1lli.h	Thu Oct 11 09:47:33 2001
@@ -1,9 +1,11 @@
-/*
- * $Id: b1lli.h,v 1.8.8.2 2001/05/17 20:41:52 kai Exp $
+/* $Id: b1lli.h,v 1.8.8.3 2001/09/23 22:25:05 kai Exp $
  *
  * ISDN lowlevel-module for AVM B1-card.
  *
  * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
  *
  */
 
diff -u --recursive --new-file v2.4.12/linux/include/linux/b1pcmcia.h linux/include/linux/b1pcmcia.h
--- v2.4.12/linux/include/linux/b1pcmcia.h	Sat May 19 17:54:14 2001
+++ linux/include/linux/b1pcmcia.h	Thu Oct 11 09:47:33 2001
@@ -1,10 +1,12 @@
-/*
- * $Id: b1pcmcia.h,v 1.1.8.1 2001/05/17 20:41:52 kai Exp $
+/* $Id: b1pcmcia.h,v 1.1.8.2 2001/09/23 22:25:05 kai Exp $
  *
  * Exported functions of module b1pcmcia to be called by
  * avm_cs card services module.
  *
  * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
  *
  */
 
diff -u --recursive --new-file v2.4.12/linux/include/linux/blkdev.h linux/include/linux/blkdev.h
--- v2.4.12/linux/include/linux/blkdev.h	Thu Oct 18 13:49:40 2001
+++ linux/include/linux/blkdev.h	Thu Oct 18 17:45:29 2001
@@ -19,7 +19,6 @@
 struct request {
 	struct list_head queue;
 	int elevator_sequence;
-	struct list_head table;
 
 	volatile int rq_status;	/* should split this into a few status bits */
 #define RQ_INACTIVE		(-1)
@@ -202,5 +201,28 @@
 
 #define blk_finished_io(nsects)	do { } while (0)
 #define blk_started_io(nsects)	do { } while (0)
+
+static inline unsigned int blksize_bits(unsigned int size)
+{
+	unsigned int bits = 8;
+	do {
+		bits++;
+		size >>= 1;
+	} while (size > 256);
+	return bits;
+}
+
+static inline unsigned int block_size(kdev_t dev)
+{
+	int retval = BLOCK_SIZE;
+	int major = MAJOR(dev);
+
+	if (blksize_size[major]) {
+		int minor = MINOR(dev);
+		if (blksize_size[major][minor])
+			retval = blksize_size[major][minor];
+	}
+	return retval;
+}
 
 #endif
diff -u --recursive --new-file v2.4.12/linux/include/linux/console_struct.h linux/include/linux/console_struct.h
--- v2.4.12/linux/include/linux/console_struct.h	Mon Oct 16 12:53:18 2000
+++ linux/include/linux/console_struct.h	Thu Oct 11 11:17:22 2001
@@ -68,7 +68,7 @@
 	unsigned char	vc_utf		: 1;	/* Unicode UTF-8 encoding */
 	unsigned char	vc_utf_count;
 		 int	vc_utf_char;
-	unsigned int	vc_tab_stop[5];		/* Tab stops. 160 columns. */
+	unsigned int	vc_tab_stop[8];		/* Tab stops. 256 columns. */
 	unsigned char   vc_palette[16*3];       /* Colour palette for VGA+ */
 	unsigned short * vc_translate;
 	unsigned char 	vc_G0_charset;
diff -u --recursive --new-file v2.4.12/linux/include/linux/ethtool.h linux/include/linux/ethtool.h
--- v2.4.12/linux/include/linux/ethtool.h	Mon Aug 27 12:41:48 2001
+++ linux/include/linux/ethtool.h	Wed Oct 17 14:16:39 2001
@@ -53,7 +53,10 @@
 #define ETHTOOL_GDRVINFO	0x00000003 /* Get driver info. */
 #define ETHTOOL_GREGS		0x00000004 /* Get NIC registers, privileged. */
 #define ETHTOOL_GWOL		0x00000005 /* Get wake-on-lan options. */
-#define ETHTOOL_SWOL		0x00000006 /* Set wake-on-lan options. */
+#define ETHTOOL_SWOL		0x00000006 /* Set wake-on-lan options, priv. */
+#define ETHTOOL_GMSGLVL		0x00000007 /* Get driver message level */
+#define ETHTOOL_SMSGLVL		0x00000008 /* Set driver msg level, priv. */
+#define ETHTOOL_NWAY_RST	0X00000009 /* Restart autonegotiation, priv. */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET		ETHTOOL_GSET
@@ -71,6 +74,7 @@
 #define SUPPORTED_AUI			(1 << 8)
 #define SUPPORTED_MII			(1 << 9)
 #define SUPPORTED_FIBRE			(1 << 10)
+#define SUPPORTED_10base2		(1 << 11)
 
 /* Indicates what features are advertised by the interface. */
 #define ADVERTISED_10baseT_Half		(1 << 0)
@@ -84,6 +88,7 @@
 #define ADVERTISED_AUI			(1 << 8)
 #define ADVERTISED_MII			(1 << 9)
 #define ADVERTISED_FIBRE		(1 << 10)
+#define ADVERTISED_10base2		(1 << 11)
 
 /* The following are all involved in forcing a particular link
  * mode for the device for setting things.  When getting the
diff -u --recursive --new-file v2.4.12/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v2.4.12/linux/include/linux/ext2_fs.h	Thu Oct 18 13:48:05 2001
+++ linux/include/linux/ext2_fs.h	Thu Oct 18 17:44:03 2001
@@ -558,14 +558,15 @@
 						    unsigned int block_group,
 						    struct buffer_head ** bh);
 
-/* bitmap.c */
-extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
-
 /* dir.c */
-
-/* file.c */
-extern int ext2_read (struct inode *, struct file *, char *, int);
-extern int ext2_write (struct inode *, struct file *, char *, int);
+extern int ext2_add_link (struct dentry *, struct inode *);
+extern ino_t ext2_inode_by_name(struct inode *, struct dentry *);
+extern int ext2_make_empty(struct inode *, struct inode *);
+extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct dentry *, struct page **);
+extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *);
+extern int ext2_empty_dir (struct inode *);
+extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **);
+extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *);
 
 /* fsync.c */
 extern int ext2_sync_file (struct file *, struct dentry *, int);
@@ -576,26 +577,21 @@
 extern void ext2_free_inode (struct inode *);
 extern unsigned long ext2_count_free_inodes (struct super_block *);
 extern void ext2_check_inodes_bitmap (struct super_block *);
+extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
 
 /* inode.c */
-
-extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
-extern struct buffer_head * ext2_bread (struct inode *, int, int, int *);
-
 extern void ext2_read_inode (struct inode *);
 extern void ext2_write_inode (struct inode *, int);
 extern void ext2_put_inode (struct inode *);
 extern void ext2_delete_inode (struct inode *);
 extern int ext2_sync_inode (struct inode *);
 extern void ext2_discard_prealloc (struct inode *);
+extern void ext2_truncate (struct inode *);
 
 /* ioctl.c */
 extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
 		       unsigned long);
 
-/* namei.c */
-extern struct inode_operations ext2_dir_inode_operations;
-
 /* super.c */
 extern void ext2_error (struct super_block *, const char *, const char *, ...)
 	__attribute__ ((format (printf, 3, 4)));
@@ -611,32 +607,25 @@
 extern struct super_block * ext2_read_super (struct super_block *,void *,int);
 extern int ext2_statfs (struct super_block *, struct statfs *);
 
-/* truncate.c */
-extern void ext2_truncate (struct inode *);
-
 /*
  * Inodes and files operations
  */
 
 /* dir.c */
 extern struct file_operations ext2_dir_operations;
-extern int ext2_add_link (struct dentry *, struct inode *);
-extern ino_t ext2_inode_by_name(struct inode *, struct dentry *);
-extern int ext2_make_empty(struct inode *, struct inode *);
-extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct dentry *, struct page **);
-extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *);
-extern int ext2_empty_dir (struct inode *);
-extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **);
-extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *);
 
 /* file.c */
 extern struct inode_operations ext2_file_inode_operations;
 extern struct file_operations ext2_file_operations;
 
+/* inode.c */
+extern struct address_space_operations ext2_aops;
+
+/* namei.c */
+extern struct inode_operations ext2_dir_inode_operations;
+
 /* symlink.c */
 extern struct inode_operations ext2_fast_symlink_inode_operations;
-
-extern struct address_space_operations ext2_aops;
 
 #endif	/* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.12/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.4.12/linux/include/linux/fs.h	Thu Oct 18 13:47:38 2001
+++ linux/include/linux/fs.h	Thu Oct 18 17:43:37 2001
@@ -604,6 +604,7 @@
 extern int posix_lock_file(struct file *, struct file_lock *, unsigned int);
 extern void posix_block_lock(struct file_lock *, struct file_lock *);
 extern void posix_unblock_lock(struct file_lock *);
+extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);
 extern int __get_lease(struct inode *inode, unsigned int flags);
 extern time_t lease_get_mtime(struct inode *);
 extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
diff -u --recursive --new-file v2.4.12/linux/include/linux/genhd.h linux/include/linux/genhd.h
--- v2.4.12/linux/include/linux/genhd.h	Thu Oct 18 13:49:34 2001
+++ linux/include/linux/genhd.h	Thu Oct 18 17:45:26 2001
@@ -58,8 +58,8 @@
 #  include <linux/devfs_fs_kernel.h>
 
 struct hd_struct {
-	long start_sect;
-	long nr_sects;
+	unsigned long start_sect;
+	unsigned long nr_sects;
 	devfs_handle_t de;              /* primary (master) devfs entry  */
 	int number;                     /* stupid old code wastes space  */
 };
diff -u --recursive --new-file v2.4.12/linux/include/linux/i2c-dev.h linux/include/linux/i2c-dev.h
--- v2.4.12/linux/include/linux/i2c-dev.h	Sun Aug 12 13:28:01 2001
+++ linux/include/linux/i2c-dev.h	Thu Oct 11 08:05:47 2001
@@ -19,7 +19,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-/* $Id: i2c-dev.h,v 1.8 2000/08/12 16:37:15 mds Exp $ */
+/* $Id: i2c-dev.h,v 1.9 2001/08/15 03:04:58 mds Exp $ */
 
 #ifndef I2C_DEV_H
 #define I2C_DEV_H
diff -u --recursive --new-file v2.4.12/linux/include/linux/i2c-elektor.h linux/include/linux/i2c-elektor.h
--- v2.4.12/linux/include/linux/i2c-elektor.h	Fri Jan 28 19:36:23 2000
+++ linux/include/linux/i2c-elektor.h	Thu Oct 11 08:05:47 2001
@@ -22,22 +22,26 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c-elektor.h,v 1.4 2000/01/18 23:54:07 frodo Exp $ */
+/* $Id: i2c-elektor.h,v 1.5 2001/06/05 01:46:33 mds Exp $ */
 
 #ifndef I2C_PCF_ELEKTOR_H
 #define I2C_PCF_ELEKTOR_H 1
 
 /*
- * This struct contains the hw-dependent functions of PCF8584 adapters to 
- * manipulate the registers, and to init any hw-specific features. 
- */
+ * This struct contains the hw-dependent functions of PCF8584 adapters to
+ * manipulate the registers, and to init any hw-specific features.
+ * vdovikin: removed: this module in real supports only one device,
+ * due to missing arguments in some functions, called from the algo-pcf module.
+ * Sometimes it's need to be rewriten -
+ * but for now just remove this for simpler reading */
 
+/*
 struct i2c_pcf_isa {
 	int pi_base;
 	int pi_irq;
 	int pi_clock;
 	int pi_own;
 };
-
+*/
 
 #endif /* PCF_ELEKTOR_H */
diff -u --recursive --new-file v2.4.12/linux/include/linux/i2c-id.h linux/include/linux/i2c-id.h
--- v2.4.12/linux/include/linux/i2c-id.h	Sun Sep 23 11:41:01 2001
+++ linux/include/linux/i2c-id.h	Thu Oct 11 08:05:47 2001
@@ -20,7 +20,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
 /* ------------------------------------------------------------------------- */
 
-/* $Id: i2c-id.h,v 1.25 2000/10/12 07:27:29 simon Exp $ */
+/* $Id: i2c-id.h,v 1.35 2001/08/12 17:22:20 mds Exp $ */
 
 #ifndef I2C_ID_H
 #define I2C_ID_H
@@ -65,7 +65,7 @@
 #define I2C_DRIVERID_BT829	19	/* pc to tv encoder		*/
 #define I2C_DRIVERID_TDA9850	20	/* audio mixer			*/
 #define I2C_DRIVERID_TDA9855	21	/* audio mixer			*/
-#define I2C_DRIVERID_SAA7110	22	/* 				*/
+#define I2C_DRIVERID_SAA7110	22	/* video decoder		*/
 #define I2C_DRIVERID_MGATVO	23	/* Matrox TVOut			*/
 #define I2C_DRIVERID_SAA5249	24	/* SAA5249 and compatibles	*/
 #define I2C_DRIVERID_PCF8583	25	/* real time clock		*/
@@ -84,7 +84,12 @@
 #define I2C_DRIVERID_VES1820	37     /* VLSI DVB-C decoder		*/
 #define I2C_DRIVERID_SAA7113	38     /* video decoder			*/
 #define I2C_DRIVERID_TDA8444	39     /* octuple 6-bit DAC             */
-
+#define I2C_DRIVERID_BT819	40     /* video decoder			*/
+#define I2C_DRIVERID_BT856	41     /* video encoder			*/
+#define I2C_DRIVERID_VPX32XX	42     /* video decoder+vbi/vtxt	*/
+#define I2C_DRIVERID_DRP3510	43     /* ADR decoder (Astra Radio)	*/
+#define I2C_DRIVERID_SP5055	44     /* Satellite tuner		*/
+#define I2C_DRIVERID_STV0030	45     /* Multipurpose switch		*/
 
 #define I2C_DRIVERID_EXP0	0xF0	/* experimental use id's	*/
 #define I2C_DRIVERID_EXP1	0xF1
@@ -94,6 +99,35 @@
 #define I2C_DRIVERID_I2CDEV	900
 #define I2C_DRIVERID_I2CPROC	901
 
+/* IDs --   Use DRIVERIDs 1000-1999 for sensors. 
+   These were originally in sensors.h in the lm_sensors package */
+#define I2C_DRIVERID_LM78 1002
+#define I2C_DRIVERID_LM75 1003
+#define I2C_DRIVERID_GL518 1004
+#define I2C_DRIVERID_EEPROM 1005
+#define I2C_DRIVERID_W83781D 1006
+#define I2C_DRIVERID_LM80 1007
+#define I2C_DRIVERID_ADM1021 1008
+#define I2C_DRIVERID_ADM9240 1009
+#define I2C_DRIVERID_LTC1710 1010
+#define I2C_DRIVERID_SIS5595 1011
+#define I2C_DRIVERID_ICSPLL 1012
+#define I2C_DRIVERID_BT869 1013
+#define I2C_DRIVERID_MAXILIFE 1014
+#define I2C_DRIVERID_MATORB 1015
+#define I2C_DRIVERID_GL520 1016
+#define I2C_DRIVERID_THMC50 1017
+#define I2C_DRIVERID_DDCMON 1018
+#define I2C_DRIVERID_VIA686A 1019
+#define I2C_DRIVERID_ADM1025 1020
+#define I2C_DRIVERID_LM87 1021
+#define I2C_DRIVERID_PCF8574 1022
+#define I2C_DRIVERID_MTP008 1023
+#define I2C_DRIVERID_DS1621 1024
+#define I2C_DRIVERID_ADM1024 1025
+#define I2C_DRIVERID_IT87 1026
+#define I2C_DRIVERID_CH700X 1027 /* single driver for CH7003-7009 digital pc to tv encoders */
+
 /*
  * ---- Adapter types ----------------------------------------------------
  *
@@ -109,7 +143,6 @@
 #define I2C_ALGO_ISA 	0x050000	/* lm_sensors ISA pseudo-adapter */
 #define I2C_ALGO_SAA7146 0x060000	/* SAA 7146 video decoder bus	*/
 #define I2C_ALGO_ACB 	0x070000	/* ACCESS.bus algorithm         */
-#define I2C_ALGO_IIC    0x080000 	/* ITE IIC bus */
 
 #define I2C_ALGO_EC     0x100000        /* ACPI embedded controller     */
 
@@ -140,8 +173,10 @@
 #define I2C_HW_B_G400	0x09	/* Matrox G400				*/
 #define I2C_HW_B_I810	0x0a	/* Intel I810 				*/
 #define I2C_HW_B_VOO	0x0b	/* 3dfx Voodoo 3 / Banshee      	*/
+#define I2C_HW_B_PPORT  0x0c	/* Primitive parallel port adapter	*/
 #define I2C_HW_B_RIVA	0x10	/* Riva based graphics cards		*/
 #define I2C_HW_B_IOC	0x11	/* IOC bit-wiggling			*/
+#define I2C_HW_B_TSUNA  0x12	/* DEC Tsunami chipset			*/
 
 /* --- PCF 8584 based algorithms					*/
 #define I2C_HW_P_LP	0x00	/* Parallel port interface		*/
@@ -153,9 +188,6 @@
 
 /* --- MPC8xx PowerPC adapters						*/
 #define I2C_HW_MPC8XX_EPON 0x00	/* Eponymous MPC8xx I2C adapter 	*/
-
-/* --- ITE based algorithms						*/
-#define I2C_HW_I_IIC	0x00	/* controller on the ITE */
 
 /* --- SMBus only adapters						*/
 #define I2C_HW_SMBUS_PIIX4	0x00
diff -u --recursive --new-file v2.4.12/linux/include/linux/i2c-proc.h linux/include/linux/i2c-proc.h
--- v2.4.12/linux/include/linux/i2c-proc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/i2c-proc.h	Thu Oct 11 08:05:47 2001
@@ -0,0 +1,396 @@
+/*
+    sensors.h - Part of lm_sensors, Linux kernel modules for hardware
+                monitoring
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef SENSORS_SENSORS_H
+#define SENSORS_SENSORS_H
+
+#ifdef __KERNEL__
+
+/* Next two must be included before sysctl.h can be included, in 2.0 kernels */
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/sysctl.h>
+
+/* The type of callback functions used in sensors_{proc,sysctl}_real */
+typedef void (*i2c_real_callback) (struct i2c_client * client,
+				       int operation, int ctl_name,
+				       int *nrels_mag, long *results);
+
+/* Values for the operation field in the above function type */
+#define SENSORS_PROC_REAL_INFO 1
+#define SENSORS_PROC_REAL_READ 2
+#define SENSORS_PROC_REAL_WRITE 3
+
+/* These funcion reads or writes a 'real' value (encoded by the combination
+   of an integer and a magnitude, the last is the power of ten the value
+   should be divided with) to a /proc/sys directory. To use these functions,
+   you must (before registering the ctl_table) set the extra2 field to the
+   client, and the extra1 field to a function of the form:
+      void func(struct i2c_client *client, int operation, int ctl_name,
+                int *nrels_mag, long *results)
+   This last function can be called for three values of operation. If
+   operation equals SENSORS_PROC_REAL_INFO, the magnitude should be returned
+   in nrels_mag. If operation equals SENSORS_PROC_REAL_READ, values should
+   be read into results. nrels_mag should return the number of elements
+   read; the maximum number is put in it on entry. Finally, if operation
+   equals SENSORS_PROC_REAL_WRITE, the values in results should be
+   written to the chip. nrels_mag contains on entry the number of elements
+   found.
+   In all cases, client points to the client we wish to interact with,
+   and ctl_name is the SYSCTL id of the file we are accessing. */
+extern int i2c_sysctl_real(ctl_table * table, int *name, int nlen,
+			       void *oldval, size_t * oldlenp,
+			       void *newval, size_t newlen,
+			       void **context);
+extern int i2c_proc_real(ctl_table * ctl, int write, struct file *filp,
+			     void *buffer, size_t * lenp);
+
+
+
+/* These rather complex functions must be called when you want to add or
+   delete an entry in /proc/sys/dev/sensors/chips (not yet implemented). It
+   also creates a new directory within /proc/sys/dev/sensors/.
+   ctl_template should be a template of the newly created directory. It is
+   copied in memory. The extra2 field of each file is set to point to client.
+   If any driver wants subdirectories within the newly created directory,
+   these functions must be updated! */
+extern int i2c_register_entry(struct i2c_client *client,
+				  const char *prefix,
+				  ctl_table * ctl_template,
+				  struct module *controlling_mod);
+
+extern void i2c_deregister_entry(int id);
+
+
+/* A structure containing detect information.
+   Force variables overrule all other variables; they force a detection on
+   that place. If a specific chip is given, the module blindly assumes this
+   chip type is present; if a general force (kind == 0) is given, the module
+   will still try to figure out what type of chip is present. This is useful
+   if for some reasons the detect for SMBus or ISA address space filled
+   fails.
+   probe: insmod parameter. Initialize this list with SENSORS_I2C_END values.
+     A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
+     the ISA bus, -1 for any I2C bus), the second is the address. 
+   kind: The kind of chip. 0 equals any chip.
+*/
+struct i2c_force_data {
+	unsigned short *force;
+	unsigned short kind;
+};
+
+/* A structure containing the detect information.
+   normal_i2c: filled in by the module writer. Terminated by SENSORS_I2C_END.
+     A list of I2C addresses which should normally be examined.
+   normal_i2c_range: filled in by the module writer. Terminated by 
+     SENSORS_I2C_END
+     A list of pairs of I2C addresses, each pair being an inclusive range of
+     addresses which should normally be examined.
+   normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END.
+     A list of ISA addresses which should normally be examined.
+   normal_isa_range: filled in by the module writer. Terminated by 
+     SENSORS_ISA_END
+     A list of triples. The first two elements are ISA addresses, being an
+     range of addresses which should normally be examined. The third is the
+     modulo parameter: only addresses which are 0 module this value relative
+     to the first address of the range are actually considered.
+   probe: insmod parameter. Initialize this list with SENSORS_I2C_END values.
+     A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
+     the ISA bus, -1 for any I2C bus), the second is the address. These
+     addresses are also probed, as if they were in the 'normal' list.
+   probe_range: insmod parameter. Initialize this list with SENSORS_I2C_END 
+     values.
+     A list of triples. The first value is a bus number (SENSORS_ISA_BUS for
+     the ISA bus, -1 for any I2C bus), the second and third are addresses. 
+     These form an inclusive range of addresses that are also probed, as
+     if they were in the 'normal' list.
+   ignore: insmod parameter. Initialize this list with SENSORS_I2C_END values.
+     A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
+     the ISA bus, -1 for any I2C bus), the second is the I2C address. These
+     addresses are never probed. This parameter overrules 'normal' and 
+     'probe', but not the 'force' lists.
+   ignore_range: insmod parameter. Initialize this list with SENSORS_I2C_END 
+      values.
+     A list of triples. The first value is a bus number (SENSORS_ISA_BUS for
+     the ISA bus, -1 for any I2C bus), the second and third are addresses. 
+     These form an inclusive range of I2C addresses that are never probed.
+     This parameter overrules 'normal' and 'probe', but not the 'force' lists.
+   force_data: insmod parameters. A list, ending with an element of which
+     the force field is NULL.
+*/
+struct i2c_address_data {
+	unsigned short *normal_i2c;
+	unsigned short *normal_i2c_range;
+	unsigned int *normal_isa;
+	unsigned int *normal_isa_range;
+	unsigned short *probe;
+	unsigned short *probe_range;
+	unsigned short *ignore;
+	unsigned short *ignore_range;
+	struct i2c_force_data *forces;
+};
+
+/* Internal numbers to terminate lists */
+#define SENSORS_I2C_END 0xfffe
+#define SENSORS_ISA_END 0xfffefffe
+
+/* The numbers to use to set an ISA or I2C bus address */
+#define SENSORS_ISA_BUS 9191
+#define SENSORS_ANY_I2C_BUS 0xffff
+
+/* The length of the option lists */
+#define SENSORS_MAX_OPTS 48
+
+/* Default fill of many variables */
+#define SENSORS_DEFAULTS {SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END, \
+                          SENSORS_I2C_END, SENSORS_I2C_END, SENSORS_I2C_END}
+
+/* This is ugly. We need to evaluate SENSORS_MAX_OPTS before it is 
+   stringified */
+#define SENSORS_MODPARM_AUX1(x) "1-" #x "h"
+#define SENSORS_MODPARM_AUX(x) SENSORS_MODPARM_AUX1(x)
+#define SENSORS_MODPARM SENSORS_MODPARM_AUX(SENSORS_MAX_OPTS)
+
+/* SENSORS_MODULE_PARM creates a module parameter, and puts it in the
+   module header */
+#define SENSORS_MODULE_PARM(var,desc) \
+  static unsigned short var[SENSORS_MAX_OPTS] = SENSORS_DEFAULTS; \
+  MODULE_PARM(var,SENSORS_MODPARM); \
+  MODULE_PARM_DESC(var,desc)
+
+/* SENSORS_MODULE_PARM creates a 'force_*' module parameter, and puts it in
+   the module header */
+#define SENSORS_MODULE_PARM_FORCE(name) \
+  SENSORS_MODULE_PARM(force_ ## name, \
+                      "List of adapter,address pairs which are unquestionably" \
+                      " assumed to contain a `" # name "' chip")
+
+
+/* This defines several insmod variables, and the addr_data structure */
+#define SENSORS_INSMOD \
+  SENSORS_MODULE_PARM(probe, \
+                      "List of adapter,address pairs to scan additionally"); \
+  SENSORS_MODULE_PARM(probe_range, \
+                      "List of adapter,start-addr,end-addr triples to scan " \
+                      "additionally"); \
+  SENSORS_MODULE_PARM(ignore, \
+                      "List of adapter,address pairs not to scan"); \
+  SENSORS_MODULE_PARM(ignore_range, \
+                      "List of adapter,start-addr,end-addr triples not to " \
+                      "scan"); \
+  static struct i2c_address_data addr_data = \
+                                       {normal_i2c, normal_i2c_range, \
+                                        normal_isa, normal_isa_range, \
+                                        probe, probe_range, \
+                                        ignore, ignore_range, \
+                                        forces}
+
+/* The following functions create an enum with the chip names as elements. 
+   The first element of the enum is any_chip. These are the only macros
+   a module will want to use. */
+
+#define SENSORS_INSMOD_0 \
+  enum chips { any_chip }; \
+  SENSORS_MODULE_PARM(force, \
+                      "List of adapter,address pairs to boldly assume " \
+                      "to be present"); \
+  static struct i2c_force_data forces[] = {{force,any_chip},{NULL}}; \
+  SENSORS_INSMOD
+
+#define SENSORS_INSMOD_1(chip1) \
+  enum chips { any_chip, chip1 }; \
+  SENSORS_MODULE_PARM(force, \
+                      "List of adapter,address pairs to boldly assume " \
+                      "to be present"); \
+  SENSORS_MODULE_PARM_FORCE(chip1); \
+  static struct i2c_force_data forces[] = {{force,any_chip},\
+                                                 {force_ ## chip1,chip1}, \
+                                                 {NULL}}; \
+  SENSORS_INSMOD
+
+#define SENSORS_INSMOD_2(chip1,chip2) \
+  enum chips { any_chip, chip1, chip2 }; \
+  SENSORS_MODULE_PARM(force, \
+                      "List of adapter,address pairs to boldly assume " \
+                      "to be present"); \
+  SENSORS_MODULE_PARM_FORCE(chip1); \
+  SENSORS_MODULE_PARM_FORCE(chip2); \
+  static struct i2c_force_data forces[] = {{force,any_chip}, \
+                                                 {force_ ## chip1,chip1}, \
+                                                 {force_ ## chip2,chip2}, \
+                                                 {NULL}}; \
+  SENSORS_INSMOD
+
+#define SENSORS_INSMOD_3(chip1,chip2,chip3) \
+  enum chips { any_chip, chip1, chip2, chip3 }; \
+  SENSORS_MODULE_PARM(force, \
+                      "List of adapter,address pairs to boldly assume " \
+                      "to be present"); \
+  SENSORS_MODULE_PARM_FORCE(chip1); \
+  SENSORS_MODULE_PARM_FORCE(chip2); \
+  SENSORS_MODULE_PARM_FORCE(chip3); \
+  static struct i2c_force_data forces[] = {{force,any_chip}, \
+                                                 {force_ ## chip1,chip1}, \
+                                                 {force_ ## chip2,chip2}, \
+                                                 {force_ ## chip3,chip3}, \
+                                                 {NULL}}; \
+  SENSORS_INSMOD
+
+#define SENSORS_INSMOD_4(chip1,chip2,chip3,chip4) \
+  enum chips { any_chip, chip1, chip2, chip3, chip4 }; \
+  SENSORS_MODULE_PARM(force, \
+                      "List of adapter,address pairs to boldly assume " \
+                      "to be present"); \
+  SENSORS_MODULE_PARM_FORCE(chip1); \
+  SENSORS_MODULE_PARM_FORCE(chip2); \
+  SENSORS_MODULE_PARM_FORCE(chip3); \
+  SENSORS_MODULE_PARM_FORCE(chip4); \
+  static struct i2c_force_data forces[] = {{force,any_chip}, \
+                                                 {force_ ## chip1,chip1}, \
+                                                 {force_ ## chip2,chip2}, \
+                                                 {force_ ## chip3,chip3}, \
+                                                 {force_ ## chip4,chip4}, \
+                                                 {NULL}}; \
+  SENSORS_INSMOD
+
+#define SENSORS_INSMOD_5(chip1,chip2,chip3,chip4,chip5) \
+  enum chips { any_chip, chip1, chip2, chip3, chip4, chip5 }; \
+  SENSORS_MODULE_PARM(force, \
+                      "List of adapter,address pairs to boldly assume " \
+                      "to be present"); \
+  SENSORS_MODULE_PARM_FORCE(chip1); \
+  SENSORS_MODULE_PARM_FORCE(chip2); \
+  SENSORS_MODULE_PARM_FORCE(chip3); \
+  SENSORS_MODULE_PARM_FORCE(chip4); \
+  SENSORS_MODULE_PARM_FORCE(chip5); \
+  static struct i2c_force_data forces[] = {{force,any_chip}, \
+                                                 {force_ ## chip1,chip1}, \
+                                                 {force_ ## chip2,chip2}, \
+                                                 {force_ ## chip3,chip3}, \
+                                                 {force_ ## chip4,chip4}, \
+                                                 {force_ ## chip5,chip5}, \
+                                                 {NULL}}; \
+  SENSORS_INSMOD
+
+#define SENSORS_INSMOD_6(chip1,chip2,chip3,chip4,chip5,chip6) \
+  enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6 }; \
+  SENSORS_MODULE_PARM(force, \
+                      "List of adapter,address pairs to boldly assume " \
+                      "to be present"); \
+  SENSORS_MODULE_PARM_FORCE(chip1); \
+  SENSORS_MODULE_PARM_FORCE(chip2); \
+  SENSORS_MODULE_PARM_FORCE(chip3); \
+  SENSORS_MODULE_PARM_FORCE(chip4); \
+  SENSORS_MODULE_PARM_FORCE(chip5); \
+  SENSORS_MODULE_PARM_FORCE(chip6); \
+  static struct i2c_force_data forces[] = {{force,any_chip}, \
+                                                 {force_ ## chip1,chip1}, \
+                                                 {force_ ## chip2,chip2}, \
+                                                 {force_ ## chip3,chip3}, \
+                                                 {force_ ## chip4,chip4}, \
+                                                 {force_ ## chip5,chip5}, \
+                                                 {force_ ## chip6,chip6}, \
+                                                 {NULL}}; \
+  SENSORS_INSMOD
+
+#define SENSORS_INSMOD_7(chip1,chip2,chip3,chip4,chip5,chip6,chip7) \
+  enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, chip7 }; \
+  SENSORS_MODULE_PARM(force, \
+                      "List of adapter,address pairs to boldly assume " \
+                      "to be present"); \
+  SENSORS_MODULE_PARM_FORCE(chip1); \
+  SENSORS_MODULE_PARM_FORCE(chip2); \
+  SENSORS_MODULE_PARM_FORCE(chip3); \
+  SENSORS_MODULE_PARM_FORCE(chip4); \
+  SENSORS_MODULE_PARM_FORCE(chip5); \
+  SENSORS_MODULE_PARM_FORCE(chip6); \
+  SENSORS_MODULE_PARM_FORCE(chip7); \
+  static struct i2c_force_data forces[] = {{force,any_chip}, \
+                                                 {force_ ## chip1,chip1}, \
+                                                 {force_ ## chip2,chip2}, \
+                                                 {force_ ## chip3,chip3}, \
+                                                 {force_ ## chip4,chip4}, \
+                                                 {force_ ## chip5,chip5}, \
+                                                 {force_ ## chip6,chip6}, \
+                                                 {force_ ## chip7,chip7}, \
+                                                 {NULL}}; \
+  SENSORS_INSMOD
+
+typedef int i2c_found_addr_proc(struct i2c_adapter *adapter,
+				    int addr, unsigned short flags,
+				    int kind);
+
+/* Detect function. It iterates over all possible addresses itself. For
+   SMBus addresses, it will only call found_proc if some client is connected
+   to the SMBus (unless a 'force' matched); for ISA detections, this is not
+   done. */
+extern int i2c_detect(struct i2c_adapter *adapter,
+			  struct i2c_address_data *address_data,
+			  i2c_found_addr_proc * found_proc);
+
+
+/* This macro is used to scale user-input to sensible values in almost all
+   chip drivers. */
+extern inline int SENSORS_LIMIT(long value, long low, long high)
+{
+	if (value < low)
+		return low;
+	else if (value > high)
+		return high;
+	else
+		return value;
+}
+
+#endif				/* def __KERNEL__ */
+
+
+/* The maximum length of the prefix */
+#define SENSORS_PREFIX_MAX 20
+
+/* Sysctl IDs */
+#ifdef DEV_HWMON
+#define DEV_SENSORS DEV_HWMON
+#else				/* ndef DEV_HWMOM */
+#define DEV_SENSORS 2		/* The id of the lm_sensors directory within the
+				   dev table */
+#endif				/* def DEV_HWMON */
+
+#define SENSORS_CHIPS 1
+struct i2c_chips_data {
+	int sysctl_id;
+	char name[SENSORS_PREFIX_MAX + 13];
+};
+
+#endif				/* def SENSORS_SENSORS_H */
+
diff -u --recursive --new-file v2.4.12/linux/include/linux/i2c.h linux/include/linux/i2c.h
--- v2.4.12/linux/include/linux/i2c.h	Tue Mar  6 19:44:37 2001
+++ linux/include/linux/i2c.h	Thu Oct 11 08:05:47 2001
@@ -23,11 +23,14 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
    Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c.h,v 1.42 2000/09/06 20:14:06 frodo Exp $ */
+/* $Id: i2c.h,v 1.46 2001/08/31 00:04:07 phil Exp $ */
 
 #ifndef I2C_H
 #define I2C_H
 
+#define I2C_DATE "20010830"
+#define I2C_VERSION "2.6.1"
+
 #include <linux/i2c-id.h>	/* id values of adapters et. al. 	*/
 #include <linux/types.h>
 
@@ -202,7 +205,7 @@
 	char name[32];				/* textual description 	*/
 	unsigned int id;
 
-	/* If a adapter algorithm can't to I2C-level access, set master_xfer
+	/* If an adapter algorithm can't to I2C-level access, set master_xfer
 	   to NULL. If an adapter algorithm can do SMBus access, set 
 	   smbus_xfer. If set to NULL, the SMBus protocol is simulated
 	   using common I2C messages */
@@ -344,7 +347,7 @@
    you can cheat by simply not registering. Not recommended, of course! */
 extern int i2c_check_addr (struct i2c_adapter *adapter, int addr);
 
-/* Detect function. It itterates over all possible addresses itself.
+/* Detect function. It iterates over all possible addresses itself.
  * It will only call found_proc if some client is connected at the
  * specific address (unless a 'force' matched);
  */
@@ -360,7 +363,7 @@
 extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
 
 /* This call returns a unique low identifier for each registered adapter,
- * or -1 if the adapter was not regisitered. 
+ * or -1 if the adapter was not registered. 
  */
 extern int i2c_adapter_id(struct i2c_adapter *adap);
 
@@ -454,8 +457,9 @@
  *	corresponding header files.
  */
 				/* -> bit-adapter specific ioctls	*/
-#define I2C_RETRIES	0x0701	/* number times a device address should	*/
-				/* be polled when not acknowledging 	*/
+#define I2C_RETRIES	0x0701	/* number of times a device address      */
+				/* should be polled when not            */
+                                /* acknowledging 			*/
 #define I2C_TIMEOUT	0x0702	/* set timeout - call with int 		*/
 
 
@@ -548,6 +552,13 @@
                                         probe, probe_range, \
                                         ignore, ignore_range, \
                                         force}
+
+/* Detect whether we are on the isa bus. If this returns true, all i2c
+   access will fail! */
+#define i2c_is_isa_client(clientptr) \
+        ((clientptr)->adapter->algo->id == I2C_ALGO_ISA)
+#define i2c_is_isa_adapter(adapptr) \
+        ((adapptr)->algo->id == I2C_ALGO_ISA)
 
 #endif /* def __KERNEL__ */
 #endif /* I2C_H */
diff -u --recursive --new-file v2.4.12/linux/include/linux/i2o-dev.h linux/include/linux/i2o-dev.h
--- v2.4.12/linux/include/linux/i2o-dev.h	Wed Apr 12 09:38:53 2000
+++ linux/include/linux/i2o-dev.h	Thu Oct 11 11:17:22 2001
@@ -34,11 +34,11 @@
 #define I2OLCTGET		_IOWR(I2O_MAGIC_NUMBER,2,struct i2o_cmd_hrtlct)
 #define I2OPARMSET		_IOWR(I2O_MAGIC_NUMBER,3,struct i2o_cmd_psetget)
 #define I2OPARMGET		_IOWR(I2O_MAGIC_NUMBER,4,struct i2o_cmd_psetget)
-#define I2OSWDL			_IOWR(I2O_MAGIC_NUMBER,5,struct i2o_sw_xfer)
-#define I2OSWUL			_IOWR(I2O_MAGIC_NUMBER,6,struct i2o_sw_xfer)
+#define I2OSWDL 		_IOWR(I2O_MAGIC_NUMBER,5,struct i2o_sw_xfer)
+#define I2OSWUL 		_IOWR(I2O_MAGIC_NUMBER,6,struct i2o_sw_xfer)
 #define I2OSWDEL		_IOWR(I2O_MAGIC_NUMBER,7,struct i2o_sw_xfer)
 #define I2OVALIDATE		_IOR(I2O_MAGIC_NUMBER,8,u32)
-#define I2OHTML			_IOWR(I2O_MAGIC_NUMBER,9,struct i2o_html)
+#define I2OHTML 		_IOWR(I2O_MAGIC_NUMBER,9,struct i2o_html)
 #define I2OEVTREG		_IOW(I2O_MAGIC_NUMBER,10,struct i2o_evt_id)
 #define I2OEVTGET		_IOR(I2O_MAGIC_NUMBER,11,struct i2o_evt_info)
 
@@ -68,7 +68,7 @@
 	void *buf;		/* Pointer to software buffer */
 	unsigned int *swlen;	/* Length of software data */
 	unsigned int *maxfrag;	/* Maximum fragment count */
-        unsigned int *curfrag;	/* Current fragment count */
+	unsigned int *curfrag;	/* Current fragment count */
 };
 
 struct i2o_html
@@ -98,7 +98,7 @@
 {
 	struct i2o_evt_id id;
 	unsigned char evt_data[I2O_EVT_DATA_SIZE];
- 	unsigned int data_size;
+	unsigned int data_size;
 };
 
 struct i2o_evt_get
@@ -119,8 +119,8 @@
 #define I2O_BUS_PCI	4
 #define I2O_BUS_PCMCIA	5
 #define I2O_BUS_NUBUS	6
-#define I2O_BUS_CARDBUS	7
-#define I2O_BUS_UNKNOWN	0x80
+#define I2O_BUS_CARDBUS 7
+#define I2O_BUS_UNKNOWN 0x80
 
 #ifndef __KERNEL__
 
@@ -130,127 +130,139 @@
 
 #endif /* __KERNEL__ */
 
-typedef struct _i2o_pci_bus {
-	u8 PciFunctionNumber;
-	u8 PciDeviceNumber;
-	u8 PciBusNumber;
-	u8 reserved;
-	u16 PciVendorID;
-	u16 PciDeviceID;
+typedef struct _i2o_pci_bus
+{
+	u8	PciFunctionNumber;
+	u8	PciDeviceNumber;
+	u8	PciBusNumber;
+	u8	reserved;
+	u16	PciVendorID;
+	u16	PciDeviceID;
 } i2o_pci_bus;
 
-typedef struct _i2o_local_bus {
-	u16 LbBaseIOPort;
-	u16 reserved;
-	u32 LbBaseMemoryAddress;
+typedef struct _i2o_local_bus
+{
+	u16	LbBaseIOPort;
+	u16	reserved;
+	u32	LbBaseMemoryAddress;
 } i2o_local_bus;
 
-typedef struct _i2o_isa_bus {
-	u16 IsaBaseIOPort;
-	u8 CSN;
-	u8 reserved;
-	u32 IsaBaseMemoryAddress;
+typedef struct _i2o_isa_bus
+{
+	u16	IsaBaseIOPort;
+	u8	CSN;
+	u8	reserved;
+	u32	IsaBaseMemoryAddress;
 } i2o_isa_bus;
 
-typedef struct _i2o_eisa_bus_info {
-	u16 EisaBaseIOPort;
-	u8 reserved;
-	u8 EisaSlotNumber;
-	u32 EisaBaseMemoryAddress;
+typedef struct _i2o_eisa_bus_info
+{
+	u16	EisaBaseIOPort;
+	u8	reserved;
+	u8	EisaSlotNumber;
+	u32	EisaBaseMemoryAddress;
 } i2o_eisa_bus;
 
-typedef struct _i2o_mca_bus {
-	u16 McaBaseIOPort;
-	u8 reserved;
-	u8 McaSlotNumber;
-	u32 McaBaseMemoryAddress;
+typedef struct _i2o_mca_bus
+{
+	u16	McaBaseIOPort;
+	u8	reserved;
+	u8	McaSlotNumber;
+	u32	McaBaseMemoryAddress;
 } i2o_mca_bus;
 
-typedef struct _i2o_other_bus {
+typedef struct _i2o_other_bus
+{
 	u16 BaseIOPort;
 	u16 reserved;
 	u32 BaseMemoryAddress;
 } i2o_other_bus;
 
-typedef struct _i2o_hrt_entry {
-	u32 adapter_id;
-	u32 parent_tid:12;
-	u32 state:4;
-	u32 bus_num:8;
-	u32 bus_type:8;
-	union {
-		i2o_pci_bus pci_bus;
-		i2o_local_bus local_bus;
-		i2o_isa_bus isa_bus;
-		i2o_eisa_bus eisa_bus;
-		i2o_mca_bus mca_bus;
-		i2o_other_bus other_bus;
+typedef struct _i2o_hrt_entry
+{
+	u32	adapter_id;
+	u32	parent_tid:12;
+	u32 	tate:4;
+	u32	bus_num:8;
+	u32	bus_type:8;
+	union
+	{
+		i2o_pci_bus	pci_bus;
+		i2o_local_bus	local_bus;
+		i2o_isa_bus	isa_bus;
+		i2o_eisa_bus	eisa_bus;
+		i2o_mca_bus	mca_bus;
+		i2o_other_bus	other_bus;
 	} bus;
 } i2o_hrt_entry;
 
-typedef struct _i2o_hrt {
-	u16 num_entries;
-	u8 entry_len;
-	u8 hrt_version;
-	u32 change_ind;
+typedef struct _i2o_hrt
+{
+	u16	num_entries;
+	u8	entry_len;
+	u8	hrt_version;
+	u32	change_ind;
 	i2o_hrt_entry hrt_entry[1];
 } i2o_hrt;
 
-typedef struct _i2o_lct_entry {
-	u32 entry_size:16;
-	u32 tid:12;
-	u32 reserved:4;
-	u32 change_ind;
-	u32 device_flags;
-	u32 class_id:12;
-	u32 version:4;
-	u32 vendor_id:16;
-	u32 sub_class;
-	u32 user_tid:12;
-	u32 parent_tid:12;
-	u32 bios_info:8;
-	u8 identity_tag[8];
-	u32 event_capabilities;
+typedef struct _i2o_lct_entry
+{
+	u32	entry_size:16;
+	u32	tid:12;
+	u32	reserved:4;
+	u32	change_ind;
+	u32	device_flags;
+	u32	class_id:12;
+	u32	version:4;
+	u32	vendor_id:16;
+	u32	sub_class;
+	u32	user_tid:12;
+	u32	parent_tid:12;
+	u32	bios_info:8;
+	u8	identity_tag[8];
+	u32	event_capabilities;
 } i2o_lct_entry;
 
-typedef struct _i2o_lct {
-	u32 table_size:16;
-	u32 boot_tid:12;
-	u32 lct_ver:4;
-	u32 iop_flags;
-	u32 change_ind;
+typedef struct _i2o_lct
+{
+	u32	table_size:16;
+	u32	boot_tid:12;
+	u32	lct_ver:4;
+	u32	iop_flags;
+	u32	change_ind;
 	i2o_lct_entry lct_entry[1];
 } i2o_lct;
 
-typedef struct _i2o_status_block {
-	u16 org_id;
-	u16 reserved;
-	u16 iop_id:12;
-	u16 reserved1:4;
-	u16 host_unit_id;
-	u16 segment_number:12;
-	u16 i2o_version:4;
-	u8 iop_state;
-	u8 msg_type;
-	u16 inbound_frame_size;
-	u8 init_code;	
-	u8 reserved2;
-	u32 max_inbound_frames;
-	u32 cur_inbound_frames;
-	u32 max_outbound_frames;
-	char product_id[24];	
-	u32 expected_lct_size;
-	u32 iop_capabilities;
-	u32 desired_mem_size;
-	u32 current_mem_size;
-	u32 current_mem_base;
-	u32 desired_io_size;
-	u32 current_io_size;
-	u32 current_io_base;
-	u32 reserved3:24;
-	u32 cmd_status:8;
+typedef struct _i2o_status_block
+{
+	u16	org_id;
+	u16	reserved;
+	u16	iop_id:12;
+	u16	reserved1:4;
+	u16	host_unit_id;
+	u16	segment_number:12;
+	u16	i2o_version:4;
+	u8	iop_state;
+	u8	msg_type;
+	u16	inbound_frame_size;
+	u8	init_code;
+	u8	reserved2;
+	u32	max_inbound_frames;
+	u32	cur_inbound_frames;
+	u32	max_outbound_frames;
+	char	product_id[24];
+	u32	expected_lct_size;
+	u32	iop_capabilities;
+	u32	desired_mem_size;
+	u32	current_mem_size;
+	u32	current_mem_base;
+	u32	desired_io_size;
+	u32	current_io_size;
+	u32	current_io_base;
+	u32	reserved3:24;
+	u32	cmd_status:8;
 } i2o_status_block;
- 
+
 /* Event indicator mask flags */
 #define I2O_EVT_IND_STATE_CHANGE		0x80000000
 #define I2O_EVT_IND_GENERAL_WARNING		0x40000000
@@ -269,7 +281,7 @@
 #define I2O_EVT_IND_EXEC_ADAPTER_FAULT		0x00000004
 #define I2O_EVT_IND_EXEC_POWER_FAIL		0x00000008
 #define I2O_EVT_IND_EXEC_RESET_PENDING		0x00000010
-#define I2O_EVT_IND_EXEC_RESET_IMMINENT		0x00000020
+#define I2O_EVT_IND_EXEC_RESET_IMMINENT 	0x00000020
 #define I2O_EVT_IND_EXEC_HW_FAIL		0x00000040
 #define I2O_EVT_IND_EXEC_XCT_CHANGE		0x00000080
 #define I2O_EVT_IND_EXEC_NEW_LCT_ENTRY		0x00000100
@@ -280,14 +292,14 @@
 #define I2O_EVT_IND_BSA_VOLUME_LOAD		0x00000001
 #define I2O_EVT_IND_BSA_VOLUME_UNLOAD		0x00000002
 #define I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ	0x00000004
-#define I2O_EVT_IND_BSA_CAPACITY_CHANGE		0x00000008
+#define I2O_EVT_IND_BSA_CAPACITY_CHANGE 	0x00000008
 #define I2O_EVT_IND_BSA_SCSI_SMART		0x00000010
 
 /* Event data for generic events */
 #define I2O_EVT_STATE_CHANGE_NORMAL		0x00
 #define I2O_EVT_STATE_CHANGE_SUSPENDED		0x01
 #define I2O_EVT_STATE_CHANGE_RESTART		0x02
-#define I2O_EVT_STATE_CHANGE_NA_RECOVER		0x03
+#define I2O_EVT_STATE_CHANGE_NA_RECOVER 	0x03
 #define I2O_EVT_STATE_CHANGE_NA_NO_RECOVER	0x04
 #define I2O_EVT_STATE_CHANGE_QUIESCE_REQUEST	0x05
 #define I2O_EVT_STATE_CHANGE_FAILED		0x10
@@ -295,7 +307,7 @@
 
 #define I2O_EVT_GEN_WARNING_NORMAL		0x00
 #define I2O_EVT_GEN_WARNING_ERROR_THRESHOLD	0x01
-#define I2O_EVT_GEN_WARNING_MEDIA_FAULT		0x02
+#define I2O_EVT_GEN_WARNING_MEDIA_FAULT 	0x02
 
 #define I2O_EVT_CAPABILITY_OTHER		0x01
 #define I2O_EVT_CAPABILITY_CHANGED		0x02
@@ -309,89 +321,89 @@
 /*  Class ID and Code Assignments
  *  (LCT.ClassID.Version field)
  */
-#define    I2O_CLASS_VERSION_10                        0x00
-#define    I2O_CLASS_VERSION_11                        0x01
+#define I2O_CLASS_VERSION_10			0x00
+#define I2O_CLASS_VERSION_11			0x01
 
 /*  Class code names
  *  (from v1.5 Table 6-1 Class Code Assignments.)
  */
- 
-#define    I2O_CLASS_EXECUTIVE                         0x000
-#define    I2O_CLASS_DDM                               0x001
-#define    I2O_CLASS_RANDOM_BLOCK_STORAGE              0x010
-#define    I2O_CLASS_SEQUENTIAL_STORAGE                0x011
-#define    I2O_CLASS_LAN                               0x020
-#define    I2O_CLASS_WAN                               0x030
-#define    I2O_CLASS_FIBRE_CHANNEL_PORT                0x040
-#define    I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL          0x041
-#define    I2O_CLASS_SCSI_PERIPHERAL                   0x051
-#define    I2O_CLASS_ATE_PORT                          0x060
-#define    I2O_CLASS_ATE_PERIPHERAL                    0x061
-#define    I2O_CLASS_FLOPPY_CONTROLLER                 0x070
-#define    I2O_CLASS_FLOPPY_DEVICE                     0x071
-#define    I2O_CLASS_BUS_ADAPTER_PORT                  0x080
-#define    I2O_CLASS_PEER_TRANSPORT_AGENT              0x090
-#define    I2O_CLASS_PEER_TRANSPORT                    0x091
+
+#define I2O_CLASS_EXECUTIVE			0x000
+#define I2O_CLASS_DDM				0x001
+#define I2O_CLASS_RANDOM_BLOCK_STORAGE		0x010
+#define I2O_CLASS_SEQUENTIAL_STORAGE		0x011
+#define I2O_CLASS_LAN				0x020
+#define I2O_CLASS_WAN				0x030
+#define I2O_CLASS_FIBRE_CHANNEL_PORT		0x040
+#define I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL	0x041
+#define I2O_CLASS_SCSI_PERIPHERAL		0x051
+#define I2O_CLASS_ATE_PORT			0x060
+#define I2O_CLASS_ATE_PERIPHERAL		0x061
+#define I2O_CLASS_FLOPPY_CONTROLLER		0x070
+#define I2O_CLASS_FLOPPY_DEVICE 		0x071
+#define I2O_CLASS_BUS_ADAPTER_PORT		0x080
+#define I2O_CLASS_PEER_TRANSPORT_AGENT		0x090
+#define I2O_CLASS_PEER_TRANSPORT		0x091
 
 /* 
  *  Rest of 0x092 - 0x09f reserved for peer-to-peer classes
  */
- 
-#define    I2O_CLASS_MATCH_ANYCLASS                    0xffffffff
+
+#define I2O_CLASS_MATCH_ANYCLASS		0xffffffff
 
 /* 
  *  Subclasses
  */
 
-#define    I2O_SUBCLASS_i960                           0x001
-#define    I2O_SUBCLASS_HDM                            0x020
-#define    I2O_SUBCLASS_ISM                            0x021
- 
+#define I2O_SUBCLASS_i960			0x001
+#define I2O_SUBCLASS_HDM			0x020
+#define I2O_SUBCLASS_ISM			0x021
+
 /* Operation functions */
 
-#define I2O_PARAMS_FIELD_GET	0x0001
-#define I2O_PARAMS_LIST_GET	0x0002
-#define I2O_PARAMS_MORE_GET	0x0003
-#define I2O_PARAMS_SIZE_GET	0x0004
-#define I2O_PARAMS_TABLE_GET	0x0005
-#define I2O_PARAMS_FIELD_SET	0x0006
-#define I2O_PARAMS_LIST_SET	0x0007
-#define I2O_PARAMS_ROW_ADD	0x0008
-#define I2O_PARAMS_ROW_DELETE	0x0009
-#define I2O_PARAMS_TABLE_CLEAR	0x000A
+#define I2O_PARAMS_FIELD_GET			0x0001
+#define I2O_PARAMS_LIST_GET			0x0002
+#define I2O_PARAMS_MORE_GET			0x0003
+#define I2O_PARAMS_SIZE_GET			0x0004
+#define I2O_PARAMS_TABLE_GET			0x0005
+#define I2O_PARAMS_FIELD_SET			0x0006
+#define I2O_PARAMS_LIST_SET			0x0007
+#define I2O_PARAMS_ROW_ADD			0x0008
+#define I2O_PARAMS_ROW_DELETE			0x0009
+#define I2O_PARAMS_TABLE_CLEAR			0x000A
 
 /*
  * I2O serial number conventions / formats 
  * (circa v1.5)
  */
 
-#define    I2O_SNFORMAT_UNKNOWN                        0
-#define    I2O_SNFORMAT_BINARY                         1
-#define    I2O_SNFORMAT_ASCII                          2
-#define    I2O_SNFORMAT_UNICODE                        3
-#define    I2O_SNFORMAT_LAN48_MAC                      4
-#define    I2O_SNFORMAT_WAN                            5
+#define I2O_SNFORMAT_UNKNOWN			0
+#define I2O_SNFORMAT_BINARY			1
+#define I2O_SNFORMAT_ASCII			2
+#define I2O_SNFORMAT_UNICODE			3
+#define I2O_SNFORMAT_LAN48_MAC			4
+#define I2O_SNFORMAT_WAN			5
 
 /* 
  * Plus new in v2.0 (Yellowstone pdf doc)
  */
 
-#define    I2O_SNFORMAT_LAN64_MAC                      6
-#define    I2O_SNFORMAT_DDM                            7
-#define    I2O_SNFORMAT_IEEE_REG64                     8
-#define    I2O_SNFORMAT_IEEE_REG128                    9
-#define    I2O_SNFORMAT_UNKNOWN2                       0xff
+#define I2O_SNFORMAT_LAN64_MAC			6
+#define I2O_SNFORMAT_DDM			7
+#define I2O_SNFORMAT_IEEE_REG64 		8
+#define I2O_SNFORMAT_IEEE_REG128		9
+#define I2O_SNFORMAT_UNKNOWN2			0xff
 
 /*
  *	I2O Get Status State values 
  */
 
-#define	ADAPTER_STATE_INITIALIZING		0x01
-#define	ADAPTER_STATE_RESET			0x02
-#define	ADAPTER_STATE_HOLD			0x04
-#define 	ADAPTER_STATE_READY			0x05
-#define	ADAPTER_STATE_OPERATIONAL		0x08
-#define	ADAPTER_STATE_FAILED			0x10
-#define	ADAPTER_STATE_FAULTED			0x11
-	
+#define ADAPTER_STATE_INITIALIZING		0x01
+#define ADAPTER_STATE_RESET			0x02
+#define ADAPTER_STATE_HOLD			0x04
+#define ADAPTER_STATE_READY			0x05
+#define ADAPTER_STATE_OPERATIONAL		0x08
+#define ADAPTER_STATE_FAILED			0x10
+#define ADAPTER_STATE_FAULTED			0x11
+
 #endif /* _I2O_DEV_H */
diff -u --recursive --new-file v2.4.12/linux/include/linux/i2o.h linux/include/linux/i2o.h
--- v2.4.12/linux/include/linux/i2o.h	Mon Aug 27 12:41:48 2001
+++ linux/include/linux/i2o.h	Fri Oct 19 08:32:28 2001
@@ -17,24 +17,25 @@
 
 #ifndef _I2O_H
 #define _I2O_H
-#ifdef __KERNEL__	/* This file to be included by kernel only */
+
+#ifdef __KERNEL__ /* This file to be included by kernel only */
 
 #include <linux/i2o-dev.h>
 
-/* How many different OSM's are we allowing */ 
+/* How many different OSM's are we allowing */
 #define MAX_I2O_MODULES		64
 
 /* How many OSMs can register themselves for device status updates? */
 #define I2O_MAX_MANAGERS	4
 
-#include <asm/semaphore.h> /* Needed for MUTEX init macros */
+#include <asm/semaphore.h>	/* Needed for MUTEX init macros */
 #include <linux/config.h>
 #include <linux/notifier.h>
-#include <linux/ioport.h>
+#include <linux/ioport.h>	/* Needed for struct resource */
 #include <asm/atomic.h>
 
 /*
- * message structures
+ *	Message structures
  */
 struct i2o_message
 {
@@ -43,7 +44,7 @@
 	u16	size;
 	u32	target_tid:12;
 	u32	init_tid:12;
-	u32	function:8;	
+	u32	function:8;
 	u32	initiator_context;
 	/* List follows */
 };
@@ -54,18 +55,19 @@
  */
 struct i2o_device
 {
-	i2o_lct_entry lct_data; /* Device LCT information */
-	u32 flags;		
-	int i2oversion;		/* I2O version supported. Actually there
-				 * should be high and low version */
+	i2o_lct_entry lct_data;		/* Device LCT information */
+	u32 flags;
+	int i2oversion;			/* I2O version supported. Actually
+					 * there should be high and low
+					 * version */
 
-	struct proc_dir_entry* proc_entry;	/* /proc dir */
+	struct proc_dir_entry *proc_entry;	/* /proc dir */
 
 	/* Primary user */
 	struct i2o_handler *owner;
 
 	/* Management users */
-	struct i2o_handler *managers[I2O_MAX_MANAGERS];		
+	struct i2o_handler *managers[I2O_MAX_MANAGERS];
 	int num_managers;
 
 	struct i2o_controller *controller;	/* Controlling IOP */
@@ -76,24 +78,23 @@
 
 /*
  *	Resource data for each PCI I2O controller
- */	 	
+ */
 struct i2o_pci
 {
-	struct pci_dev *pdev;	/* PCI device */
-	int irq;
-	int queue_buggy:1;	/* Don't send a lot of messages */
-	int short_req:1;	/* Use small block sizes	*/
-	int dpt:1;		/* Don't quiesce		*/
+	int		irq;
+	int		queue_buggy:1;	/* Don't send a lot of messages */
+	int		short_req:1;	/* Use small block sizes        */
+	int		dpt:1;		/* Don't quiesce                */
 #ifdef CONFIG_MTRR
-	int mtrr_reg0;
-	int mtrr_reg1;
+	int		mtrr_reg0;
+	int		mtrr_reg1;
 #endif
 };
 
 /*
  * Transport types supported by I2O stack
  */
-#define I2O_TYPE_PCI		0x01		/* PCI I2O controller */	
+#define I2O_TYPE_PCI		0x01		/* PCI I2O controller */
 
 
 /*
@@ -101,6 +102,8 @@
  */
 struct i2o_controller
 {
+	struct pci_dev *pdev;		/* PCI device */
+
 	char name[16];
 	int unit;
 	int type;
@@ -126,35 +129,35 @@
 
 	u32 mem_offset;				/* MFA offset */
 	u32 mem_phys;				/* MFA physical */
-	
+
 	int battery:1;				/* Has a battery backup */
 	int io_alloc:1;				/* An I/O resource was allocated */
 	int mem_alloc:1;			/* A memory resource was allocated */
-	
+
 	struct resource io_resource;		/* I/O resource allocated to the IOP */
 	struct resource mem_resource;		/* Mem resource allocated to the IOP */
 
-	struct proc_dir_entry* proc_entry;	/* /proc dir */
+	struct proc_dir_entry *proc_entry;	/* /proc dir */
 
-	union
-	{					/* Bus information */
+	union {					/* Bus information */
 		struct i2o_pci pci;
 	} bus;
 
 	/* Bus specific destructor */
-	void (*destructor)(struct i2o_controller *);		
+	void (*destructor)(struct i2o_controller *);
 
 	/* Bus specific attach/detach */
-	int (*bind)(struct i2o_controller *, struct i2o_device *);	
+	int (*bind)(struct i2o_controller *, struct i2o_device *);
 
 	/* Bus specific initiator */
 	int (*unbind)(struct i2o_controller *, struct i2o_device *);
 
 	/* Bus specific enable/disable */
-	void (*bus_enable)(struct i2o_controller *c);
-	void (*bus_disable)(struct i2o_controller *c);
+	void (*bus_enable)(struct i2o_controller *);
+	void (*bus_disable)(struct i2o_controller *);
 
-	void *page_frame;		/* Message buffers */
+	void *page_frame;			/* Message buffers */
+	dma_addr_t page_frame_map;		/* Cache map */
 };
 
 /*
@@ -169,7 +172,8 @@
 struct i2o_handler
 {
 	/* Message reply handler */
-	void (*reply)(struct i2o_handler *, struct i2o_controller *, struct i2o_message *);
+	void (*reply)(struct i2o_handler *, struct i2o_controller *,
+		      struct i2o_message *);
 
 	/* New device notification handler */
 	void (*new_dev_notify)(struct i2o_controller *, struct i2o_device *);
@@ -181,7 +185,7 @@
 	void (*reboot_notify)(void);
 
 	char *name;		/* OSM name */
-	int context;	/* Low 8 bits of the transaction info */
+	int context;		/* Low 8 bits of the transaction info */
 	u32 class;		/* I2O classes that this driver handles */
 	/* User data follows */
 };
@@ -201,12 +205,12 @@
 {
 	int	(*install)(struct i2o_controller *);
 	int	(*activate)(struct i2o_controller *);
-	struct  i2o_controller*	(*find)(int);
+	struct i2o_controller *(*find)(int);
 	void	(*unlock)(struct i2o_controller *);
-	void	(*run_queue)(struct i2o_controller *c);
+	void	(*run_queue)(struct i2o_controller * c);
 	int	(*delete)(struct i2o_controller *);
 };
-#endif // MODULE
+#endif /* MODULE */
 
 /*
  * I2O System table entry
@@ -222,9 +226,9 @@
 	u32	iop_id:12;
 	u32	reserved2:20;
 	u16	seg_num:12;
-	u16 	i2o_version:4;
-	u8 	iop_state;
-	u8 	msg_type;
+	u16	i2o_version:4;
+	u8	iop_state;
+	u8	msg_type;
 	u16	frame_size;
 	u16	reserved3;
 	u32	last_changed;
@@ -235,14 +239,14 @@
 
 struct i2o_sys_tbl
 {
-	u8 	num_entries;
-	u8 	version;
-	u16 	reserved1;
+	u8	num_entries;
+	u8	version;
+	u16	reserved1;
 	u32	change_ind;
 	u32	reserved2;
 	u32	reserved3;
 	struct i2o_sys_tbl_entry iops[0];
-};	
+};
 
 /*
  *	Messenger inlines
@@ -265,9 +269,9 @@
 
 static inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 Val)
 {
-	*c->reply_port= Val;
+	*c->reply_port = Val;
 }
- 
+
 
 static inline u32 I2O_IRQ_READ32(struct i2o_controller *c)
 {
@@ -283,13 +287,13 @@
 static inline void i2o_post_message(struct i2o_controller *c, u32 m)
 {
 	/* The second line isnt spurious - thats forcing PCI posting */
-	I2O_POST_WRITE32(c,m);
+	I2O_POST_WRITE32(c, m);
 	(void) I2O_IRQ_READ32(c);
 }
 
 static inline void i2o_flush_reply(struct i2o_controller *c, u32 m)
 {
-	I2O_REPLY_WRITE32(c,m);
+	I2O_REPLY_WRITE32(c, m);
 }
 
 extern struct i2o_controller *i2o_find_controller(int);
@@ -304,23 +308,27 @@
 extern int i2o_claim_device(struct i2o_device *, struct i2o_handler *);
 extern int i2o_release_device(struct i2o_device *, struct i2o_handler *);
 extern int i2o_device_notify_on(struct i2o_device *, struct i2o_handler *);
-extern int i2o_device_notify_off(struct i2o_device *, struct i2o_handler *);
+extern int i2o_device_notify_off(struct i2o_device *,
+				 struct i2o_handler *);
 
 extern int i2o_post_this(struct i2o_controller *, u32 *, int);
 extern int i2o_post_wait(struct i2o_controller *, u32 *, int, int);
-extern int i2o_post_wait_mem(struct i2o_controller *, u32 *, int, int, void *, void *);
+extern int i2o_post_wait_mem(struct i2o_controller *, u32 *, int, int,
+			     void *, void *);
 
-extern int i2o_query_scalar(struct i2o_controller *, int, int, int, void *, int);
-extern int i2o_set_scalar(struct i2o_controller *, int, int, int, void *, int);
-extern int i2o_query_table(int, struct i2o_controller *, int, int, int, void *,
-			   int, void *, int);
-extern int i2o_clear_table(struct i2o_controller *, int, int); 
-extern int i2o_row_add_table(struct i2o_controller *, int, int, int, void *,
-			     int);
-extern int i2o_issue_params(int, struct i2o_controller *, int, void *,
-			    int, void *, int); 
+extern int i2o_query_scalar(struct i2o_controller *, int, int, int, void *,
+			    int);
+extern int i2o_set_scalar(struct i2o_controller *, int, int, int, void *,
+			  int);
+extern int i2o_query_table(int, struct i2o_controller *, int, int, int,
+			   void *, int, void *, int);
+extern int i2o_clear_table(struct i2o_controller *, int, int);
+extern int i2o_row_add_table(struct i2o_controller *, int, int, int,
+			     void *, int);
+extern int i2o_issue_params(int, struct i2o_controller *, int, void *, int,
+			    void *, int);
 
-extern int i2o_event_register(struct i2o_controller *, u32, u32, u32, u32); 
+extern int i2o_event_register(struct i2o_controller *, u32, u32, u32, u32);
 extern int i2o_event_ack(struct i2o_controller *, u32 *);
 
 extern void i2o_report_status(const char *, const char *, u32 *);
@@ -339,7 +347,7 @@
 
 /*
  * Executive Class
- */ 
+ */
 #define	I2O_CMD_ADAPTER_ASSIGN		0xB3
 #define	I2O_CMD_ADAPTER_READ		0xB2
 #define	I2O_CMD_ADAPTER_RELEASE		0xB5
@@ -524,7 +532,7 @@
 #define	I2O_CLAIM_MANAGEMENT					0x02000000
 #define	I2O_CLAIM_AUTHORIZED					0x03000000
 #define	I2O_CLAIM_SECONDARY					0x04000000
- 
+
 /* Message header defines for VersionOffset */
 #define I2OVER15	0x0001
 #define I2OVER20	0x0002
diff -u --recursive --new-file v2.4.12/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v2.4.12/linux/include/linux/msdos_fs.h	Thu May 24 15:36:34 2001
+++ linux/include/linux/msdos_fs.h	Fri Oct 12 13:48:42 2001
@@ -92,6 +92,15 @@
 #define	VFAT_IOCTL_READDIR_BOTH		_IOR('r', 1, struct dirent [2])
 #define	VFAT_IOCTL_READDIR_SHORT	_IOR('r', 2, struct dirent [2])
 
+/* 
+ * vfat shortname flags
+ */
+#define VFAT_SFN_DISPLAY_LOWER	0x0001 /* convert to lowercase for display */
+#define VFAT_SFN_DISPLAY_WIN95	0x0002 /* emulate win95 rule for display */
+#define VFAT_SFN_DISPLAY_WINNT	0x0004 /* emulate winnt rule for display */
+#define VFAT_SFN_CREATE_WIN95	0x0100 /* emulate win95 rule for create */
+#define VFAT_SFN_CREATE_WINNT	0x0200 /* emulate winnt rule for create */
+
 /*
  * Conversion from and to little-endian byte order. (no-op on i386/i486)
  *
@@ -132,7 +141,7 @@
 };
 
 struct fat_boot_fsinfo {
-	__u32   signature1;	/* 0x61417272L */
+	__u32   signature1;	/* 0x41615252L */
 	__u32   reserved1[120];	/* Nothing as far as I can tell */
 	__u32   signature2;	/* 0x61417272L */
 	__u32   free_clusters;	/* Free cluster count.  -1 if unknown */
@@ -188,6 +197,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/nls.h>
+
 struct fat_cache {
 	kdev_t device; /* device number. 0 means unused. */
 	int start_cluster; /* first cluster of the chain. */
@@ -196,21 +207,111 @@
 	struct fat_cache *next; /* next cache entry */
 };
 
-/* misc.c */
-extern int fat_is_binary(char conversion,char *extension);
+static inline void fat16_towchar(wchar_t *dst, const __u8 *src, size_t len)
+{
+#ifdef __BIG_ENDIAN
+	while (len--) {
+		*dst++ = src[0] | (src[1] << 8);
+		src += 2;
+	}
+#else
+	memcpy(dst, src, len * 2);
+#endif
+}
+
+static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len)
+{
+#ifdef __BIG_ENDIAN
+	while (len--) {
+		dst[0] = *src & 0x00FF;
+		dst[1] = (*src & 0xFF00) >> 8;
+		dst += 2;
+		src++;
+	}
+#else
+	memcpy(dst, src, len * 2);
+#endif
+}
+
+/* fat/buffer.c */
+extern struct buffer_head *fat_bread(struct super_block *sb, int block);
+extern struct buffer_head *fat_getblk(struct super_block *sb, int block);
+extern void fat_brelse(struct super_block *sb, struct buffer_head *bh);
+extern void fat_mark_buffer_dirty(struct super_block *sb, struct buffer_head *bh);
+extern void fat_set_uptodate(struct super_block *sb, struct buffer_head *bh,
+			     int val);
+extern int fat_is_uptodate(struct super_block *sb, struct buffer_head *bh);
+extern void fat_ll_rw_block(struct super_block *sb, int opr, int nbreq,
+			    struct buffer_head *bh[32]);
+
+/* fat/cache.c */
+extern int fat_access(struct super_block *sb, int nr, int new_value);
+extern int fat_bmap(struct inode *inode, int sector);
+extern void fat_cache_init(void);
+extern void fat_cache_lookup(struct inode *inode, int cluster, int *f_clu,
+			     int *d_clu);
+extern void fat_cache_add(struct inode *inode, int f_clu, int d_clu);
+extern void fat_cache_inval_inode(struct inode *inode);
+extern void fat_cache_inval_dev(kdev_t device);
+extern int fat_get_cluster(struct inode *inode, int cluster);
+extern int fat_free(struct inode *inode, int skip);
+
+/* fat/dir.c */
+extern struct file_operations fat_dir_operations;
+extern int fat_search_long(struct inode *inode, const char *name, int name_len,
+			   int anycase, loff_t *spos, loff_t *lpos);
+extern int fat_readdir(struct file *filp, void *dirent, filldir_t filldir);
+extern int fat_dir_ioctl(struct inode * inode, struct file * filp,
+			 unsigned int cmd, unsigned long arg);
+extern int fat_dir_empty(struct inode *dir);
+extern int fat_add_entries(struct inode *dir, int slots, struct buffer_head **bh,
+			   struct msdos_dir_entry **de, int *ino);
+extern int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat);
+
+/* fat/file.c */
+extern struct file_operations fat_file_operations;
+extern struct inode_operations fat_file_inode_operations;
+extern ssize_t fat_file_read(struct file *filp, char *buf, size_t count,
+			     loff_t *ppos);
+extern int fat_get_block(struct inode *inode, long iblock,
+			 struct buffer_head *bh_result, int create);
+extern ssize_t fat_file_write(struct file *filp, const char *buf, size_t count,
+			      loff_t *ppos);
+extern void fat_truncate(struct inode *inode);
+
+/* fat/inode.c */
+extern void fat_hash_init(void);
+extern void fat_attach(struct inode *inode, int i_pos);
+extern void fat_detach(struct inode *inode);
+extern struct inode *fat_iget(struct super_block *sb, int i_pos);
+extern struct inode *fat_build_inode(struct super_block *sb,
+				     struct msdos_dir_entry *de, int ino, int *res);
+extern void fat_delete_inode(struct inode *inode);
+extern void fat_clear_inode(struct inode *inode);
+extern void fat_put_super(struct super_block *sb);
+extern struct super_block *
+fat_read_super(struct super_block *sb, void *data, int silent,
+	       struct inode_operations *fs_dir_inode_ops);
+extern int fat_statfs(struct super_block *sb, struct statfs *buf);
+extern void fat_write_inode(struct inode *inode, int wait);
+extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
+
+/* fat/misc.c */
+extern void fat_fs_panic(struct super_block *s, const char *msg);
+extern int fat_is_binary(char conversion, char *extension);
 extern void lock_fat(struct super_block *sb);
 extern void unlock_fat(struct super_block *sb);
+extern void fat_clusters_flush(struct super_block *sb);
 extern int fat_add_cluster(struct inode *inode);
 extern struct buffer_head *fat_extend_dir(struct inode *inode);
-extern int date_dos2unix(__u16 time, __u16 date);
-extern void fat_fs_panic(struct super_block *s,const char *msg);
-extern void fat_lock_creation(void);
-extern void fat_unlock_creation(void);
-extern void fat_date_unix2dos(int unix_date,__u16 *time, __u16 *date);
-extern int fat__get_entry(struct inode *dir,loff_t *pos,struct buffer_head **bh,
-			 struct msdos_dir_entry **de,int *ino);
-static __inline__ int fat_get_entry(struct inode *dir,loff_t *pos,
-		struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
+extern int date_dos2unix(unsigned short time, unsigned short date);
+extern void fat_date_unix2dos(int unix_date, unsigned short *time,
+			      unsigned short *date);
+extern int fat__get_entry(struct inode *dir, loff_t *pos, struct buffer_head **bh,
+			  struct msdos_dir_entry **de, int *ino);
+static __inline__ int fat_get_entry(struct inode *dir, loff_t *pos,
+				    struct buffer_head **bh,
+				    struct msdos_dir_entry **de, int *ino)
 {
 	/* Fast stuff first */
 	if (*bh && *de &&
@@ -222,103 +323,33 @@
 	}
 	return fat__get_entry(dir,pos,bh,de,ino);
 }
-extern int fat_scan(struct inode *dir,const char *name,struct buffer_head **res_bh,
-		    struct msdos_dir_entry **res_de,int *ino);
-extern int fat_parent_ino(struct inode *dir,int locked);
 extern int fat_subdirs(struct inode *dir);
-void fat_clusters_flush(struct super_block *sb);
-
-/* fat.c */
-extern int fat_access(struct super_block *sb,int nr,int new_value);
-extern int fat_free(struct inode *inode,int skip);
-void fat_cache_inval_inode(struct inode *inode);
-void fat_cache_inval_dev(kdev_t device);
-extern void fat_cache_init(void);
-void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu);
-void fat_cache_add(struct inode *inode,int f_clu,int d_clu);
-int fat_get_cluster(struct inode *inode,int cluster);
+extern int fat_scan(struct inode *dir, const char *name,
+		    struct buffer_head **res_bh,
+		    struct msdos_dir_entry **res_de, int *ino);
 
-/* inode.c */
-extern void fat_hash_init(void);
-extern int fat_bmap(struct inode *inode,int block);
-extern int fat_get_block(struct inode *, long, struct buffer_head *, int);
-extern int fat_notify_change(struct dentry *, struct iattr *);
-extern void fat_clear_inode(struct inode *inode);
-extern void fat_delete_inode(struct inode *inode);
-extern void fat_put_super(struct super_block *sb);
-extern void fat_attach(struct inode *inode, int ino);
-extern void fat_detach(struct inode *inode);
-extern struct inode *fat_iget(struct super_block*,int);
-extern struct inode *fat_build_inode(struct super_block*,struct msdos_dir_entry*,int,int*);
-extern struct super_block *fat_read_super(struct super_block *s, void *data, int silent, struct inode_operations *dir_ops);
+/* msdos/namei.c  - these are for Umsdos */
 extern void msdos_put_super(struct super_block *sb);
-extern int fat_statfs(struct super_block *sb,struct statfs *buf);
-extern void fat_write_inode(struct inode *inode, int);
-
-/* dir.c */
-extern struct file_operations fat_dir_operations;
-extern int fat_search_long(struct inode *dir, const char *name, int len,
-			   int anycase, loff_t *spos, loff_t *lpos);
-extern int fat_readdir(struct file *filp,
-		       void *dirent, filldir_t);
-extern int fat_dir_ioctl(struct inode * inode, struct file * filp,
-			 unsigned int cmd, unsigned long arg);
-int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
-		  struct msdos_dir_entry **de, int *ino);
-int fat_dir_empty(struct inode *dir);
-int fat_new_dir(struct inode *inode, struct inode *parent, int is_vfat);
-
-/* file.c */
-extern struct inode_operations fat_file_inode_operations;
-extern struct inode_operations fat_file_inode_operations_1024;
-extern struct inode_operations fat_file_inode_operations_readpage;
-extern struct file_operations fat_file_operations;
-extern ssize_t fat_file_read(struct file *, char *, size_t, loff_t *);
-extern ssize_t fat_file_write(struct file *, const char *, size_t, loff_t *);
-extern void fat_truncate(struct inode *inode);
-
-/* msdos.c */
-extern struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent);
-
-/* msdos.c - these are for Umsdos */
-extern void msdos_read_inode(struct inode *inode);
-extern struct dentry *msdos_lookup(struct inode *dir,struct dentry *);
-extern int msdos_create(struct inode *dir,struct dentry *dentry,int mode);
-extern int msdos_rmdir(struct inode *dir,struct dentry *dentry);
-extern int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode);
-extern int msdos_unlink(struct inode *dir,struct dentry *dentry);
-extern int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
-			struct inode *new_dir,struct dentry *new_dentry);
-
-/* nls.c */
-extern struct fat_nls_table *fat_load_nls(int codepage);
-
-/* tables.c */
-extern unsigned char fat_uni2esc[];
-extern unsigned char fat_esc2uni[];
-
-/* fatfs_syms.c */
-extern void cleanup_fat_fs(void);
-
-/* nls.c */
-extern int fat_register_nls(struct fat_nls_table * fmt);
-extern int fat_unregister_nls(struct fat_nls_table * fmt);
-extern struct fat_nls_table *fat_find_nls(int codepage);
-extern struct fat_nls_table *fat_load_nls(int codepage);
-extern void fat_unload_nls(int codepage);
-extern int init_fat_nls(void);
+extern struct dentry *msdos_lookup(struct inode *dir, struct dentry *);
+extern int msdos_create(struct inode *dir, struct dentry *dentry, int mode);
+extern int msdos_rmdir(struct inode *dir, struct dentry *dentry);
+extern int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+extern int msdos_unlink(struct inode *dir, struct dentry *dentry);
+extern int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
+			struct inode *new_dir, struct dentry *new_dentry);
+extern struct super_block *msdos_read_super(struct super_block *sb,
+					    void *data, int silent);
 
 /* vfat/namei.c - these are for dmsdos */
-extern int vfat_create(struct inode *dir,struct dentry *dentry,int mode);
-extern int vfat_unlink(struct inode *dir,struct dentry *dentry);
-extern int vfat_mkdir(struct inode *dir,struct dentry *dentry,int mode);
-extern int vfat_rmdir(struct inode *dir,struct dentry *dentry);
-extern int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
-		       struct inode *new_dir,struct dentry *new_dentry);
-extern struct super_block *vfat_read_super(struct super_block *sb,void *data,
+extern struct dentry *vfat_lookup(struct inode *dir, struct dentry *);
+extern int vfat_create(struct inode *dir, struct dentry *dentry, int mode);
+extern int vfat_rmdir(struct inode *dir, struct dentry *dentry);
+extern int vfat_unlink(struct inode *dir, struct dentry *dentry);
+extern int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+extern int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
+		       struct inode *new_dir, struct dentry *new_dentry);
+extern struct super_block *vfat_read_super(struct super_block *sb, void *data,
 					   int silent);
-extern void vfat_read_inode(struct inode *inode);
-extern struct dentry *vfat_lookup(struct inode *dir,struct dentry *);
 
 /* vfat/vfatfs_syms.c */
 extern struct file_system_type vfat_fs_type;
diff -u --recursive --new-file v2.4.12/linux/include/linux/msdos_fs_sb.h linux/include/linux/msdos_fs_sb.h
--- v2.4.12/linux/include/linux/msdos_fs_sb.h	Thu May 24 15:36:34 2001
+++ linux/include/linux/msdos_fs_sb.h	Fri Oct 12 13:48:42 2001
@@ -12,6 +12,7 @@
 	unsigned short fs_umask;
 	unsigned short codepage;  /* Codepage for shortname conversions */
 	char *iocharset;          /* Charset used for filename input/display */
+	unsigned short shortname; /* flags for shortname display/create rule */
 	unsigned char name_check; /* r = relaxed, n = normal, s = strict */
 	unsigned char conversion; /* b = binary, t = text, a = auto */
 	unsigned quiet:1,         /* set = fake successful chmods and chowns */
@@ -28,11 +29,6 @@
 		 nocase:1;	  /* Does this need case conversion? 0=need case conversion*/
 };
 
-struct vfat_unicode {
-	unsigned char uni1;
-	unsigned char uni2;
-};
-
 struct msdos_sb_info {
 	unsigned short cluster_size; /* sectors/cluster */
 	unsigned short cluster_bits; /* sectors/cluster */
@@ -45,7 +41,6 @@
 	unsigned long clusters;      /* number of clusters */
 	unsigned long root_cluster;  /* first cluster of the root directory */
 	unsigned long fsinfo_sector; /* FAT32 fsinfo offset from start of disk */
-	wait_queue_head_t fat_wait;
 	struct semaphore fat_lock;
 	int prev_free;               /* previously returned free cluster number */
 	int free_clusters;           /* -1 if undefined */
diff -u --recursive --new-file v2.4.12/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.4.12/linux/include/linux/pci.h	Thu Oct 18 13:48:29 2001
+++ linux/include/linux/pci.h	Thu Oct 18 17:44:20 2001
@@ -353,7 +353,7 @@
 
 	struct pci_driver *driver;	/* which driver has allocated this device */
 	void		*driver_data;	/* data private to the driver */
-	dma_addr_t	dma_mask;	/* Mask of the bits of bus address this
+	u64		dma_mask;	/* Mask of the bits of bus address this
 					   device implements.  Normally this is
 					   0xffffffff.  You only need to change
 					   this if your device has broken DMA
@@ -559,7 +559,8 @@
 int pci_enable_device(struct pci_dev *dev);
 void pci_disable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
-int pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask);
+int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
+int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_assign_resource(struct pci_dev *dev, int i);
 
 /* Power management related routines */
@@ -641,7 +642,8 @@
 static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; }
 static inline void pci_disable_device(struct pci_dev *dev) { }
 static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; }
-static inline int pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask) { return -EIO; }
+static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; }
+static inline int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; }
 static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;}
 static inline int pci_register_driver(struct pci_driver *drv) { return 0;}
 static inline void pci_unregister_driver(struct pci_driver *drv) { }
diff -u --recursive --new-file v2.4.12/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.4.12/linux/include/linux/pci_ids.h	Thu Oct 11 08:02:26 2001
+++ linux/include/linux/pci_ids.h	Tue Oct 16 21:56:29 2001
@@ -1594,6 +1594,17 @@
 #define PCI_DEVICE_ID_INTEL_82801BA_9	0x244b
 #define PCI_DEVICE_ID_INTEL_82801BA_10	0x244c
 #define PCI_DEVICE_ID_INTEL_82801BA_11	0x244e
+#define PCI_DEVICE_ID_INTEL_82801CA_0	0x2480
+#define PCI_DEVICE_ID_INTEL_82801CA_2	0x2482
+#define PCI_DEVICE_ID_INTEL_82801CA_3	0x2483
+#define PCI_DEVICE_ID_INTEL_82801CA_4	0x2484
+#define PCI_DEVICE_ID_INTEL_82801CA_5	0x2485
+#define PCI_DEVICE_ID_INTEL_82801CA_6	0x2486
+#define PCI_DEVICE_ID_INTEL_82801CA_7	0x2487
+#define PCI_DEVICE_ID_INTEL_82801CA_10	0x248a
+#define PCI_DEVICE_ID_INTEL_82801CA_11	0x248b
+#define PCI_DEVICE_ID_INTEL_82801CA_12	0x248c
+#define PCI_DEVICE_ID_INTEL_80310	0x530d
 #define PCI_DEVICE_ID_INTEL_82810_MC1	0x7120
 #define PCI_DEVICE_ID_INTEL_82810_IG1	0x7121
 #define PCI_DEVICE_ID_INTEL_82810_MC3	0x7122
diff -u --recursive --new-file v2.4.12/linux/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h
--- v2.4.12/linux/include/linux/reiserfs_fs.h	Tue Oct  9 17:06:53 2001
+++ linux/include/linux/reiserfs_fs.h	Fri Oct 12 14:20:42 2001
@@ -12,11 +12,12 @@
 #ifndef _LINUX_REISER_FS_H
 #define _LINUX_REISER_FS_H
 
-
 #include <linux/types.h>
 #ifdef __KERNEL__
 #include <linux/slab.h>
 #include <linux/tqueue.h>
+#include <asm/unaligned.h>
+#include <linux/bitops.h>
 #include <asm/hardirq.h>
 #endif
 
@@ -293,11 +294,57 @@
 } __attribute__ ((__packed__));
 
 struct offset_v2 {
-    __u64 k_offset:60;
-    __u64 k_type: 4;
+#ifdef __LITTLE_ENDIAN
+	    /* little endian version */
+	    __u64 k_offset:60;
+	    __u64 k_type: 4;
+#else
+	    /* big endian version */
+	    __u64 k_type: 4;
+	    __u64 k_offset:60;
+#endif
 } __attribute__ ((__packed__));
 
+#ifndef __LITTLE_ENDIAN
+typedef union {
+    struct offset_v2 offset_v2;
+    __u64 linear;
+} __attribute__ ((__packed__)) offset_v2_esafe_overlay;
+
+static inline __u16 offset_v2_k_type( struct offset_v2 *v2 )
+{
+    offset_v2_esafe_overlay tmp = *(offset_v2_esafe_overlay *)v2;
+    tmp.linear = le64_to_cpu( tmp.linear );
+    return tmp.offset_v2.k_type;
+}
+ 
+static inline void set_offset_v2_k_type( struct offset_v2 *v2, int type )
+{
+    offset_v2_esafe_overlay *tmp = (offset_v2_esafe_overlay *)v2;
+    tmp->linear = le64_to_cpu(tmp->linear);
+    tmp->offset_v2.k_type = type;
+    tmp->linear = le64_to_cpu(tmp->linear);
+}
+ 
+static inline loff_t offset_v2_k_offset( struct offset_v2 *v2 )
+{
+    offset_v2_esafe_overlay tmp = *(offset_v2_esafe_overlay *)v2;
+    tmp.linear = le64_to_cpu( tmp.linear );
+    return tmp.offset_v2.k_offset;
+}
 
+static inline void set_offset_v2_k_offset( struct offset_v2 *v2, loff_t offset ){
+    offset_v2_esafe_overlay *tmp = (offset_v2_esafe_overlay *)v2;
+    tmp->linear = le64_to_cpu(tmp->linear);
+    tmp->offset_v2.k_offset = offset;
+    tmp->linear = le64_to_cpu(tmp->linear);
+}
+#else
+# define offset_v2_k_type(v2)           ((v2)->k_type)
+# define set_offset_v2_k_type(v2,val)   (offset_v2_k_type(v2) = (val))
+# define offset_v2_k_offset(v2)         ((v2)->k_offset)
+# define set_offset_v2_k_offset(v2,val) (offset_v2_k_offset(v2) = (val))
+#endif
 
 /* Key of an item determines its location in the S+tree, and
    is composed of 4 components */
@@ -387,8 +434,8 @@
     __u16 ih_entry_count; /* Iff this is a directory item, this field equals the number of directory
 				      entries in the directory item. */
   } __attribute__ ((__packed__)) u;
-  __u16 ih_item_len;           /* total size of the item body                  */
-  __u16 ih_item_location;      /* an offset to the item body within the block  */
+  __u16 ih_item_len;           /* total size of the item body */
+  __u16 ih_item_location;      /* an offset to the item body within the block */
 				/* I thought we were going to use this
                                    for having lots of item types? Why
                                    don't you use this for item type
@@ -423,11 +470,19 @@
 
 
 // FIXME: now would that work for other than i386 archs
-#define unreachable_item(ih) (ih->ih_version & (1 << 15))
+#define unreachable_item(ih) (ih_version(ih) & (1 << 15))
 
 #define get_ih_free_space(ih) (ih_version (ih) == ITEM_VERSION_2 ? 0 : ih_free_space (ih))
 #define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == ITEM_VERSION_2) ? 0 : (val)))
 
+/* these operate on indirect items, where you've got an array of ints
+** at a possibly unaligned location.  These are a noop on ia32
+** 
+** p is the array of __u32, i is the index into the array, v is the value
+** to store there.
+*/
+#define get_block_num(p, i) le32_to_cpu(get_unaligned((p) + (i)))
+#define put_block_num(p, i, v) put_unaligned(cpu_to_le32(v), (p) + (i))
 
 //
 // there are 5 item types currently
@@ -490,8 +545,9 @@
 //
 static inline loff_t le_key_k_offset (int version, struct key * key)
 {
-    return (version == ITEM_VERSION_1) ? key->u.k_offset_v1.k_offset :
-	le64_to_cpu (key->u.k_offset_v2.k_offset);
+    return (version == ITEM_VERSION_1) ?
+        le32_to_cpu( key->u.k_offset_v1.k_offset ) :
+	offset_v2_k_offset( &(key->u.k_offset_v2) );
 }
 static inline loff_t le_ih_k_offset (struct item_head * ih)
 {
@@ -501,8 +557,9 @@
 
 static inline loff_t le_key_k_type (int version, struct key * key)
 {
-    return (version == ITEM_VERSION_1) ? uniqueness2type (key->u.k_offset_v1.k_uniqueness) :
-	le16_to_cpu (key->u.k_offset_v2.k_type);
+    return (version == ITEM_VERSION_1) ?
+        uniqueness2type( le32_to_cpu( key->u.k_offset_v1.k_uniqueness)) :
+	offset_v2_k_type( &(key->u.k_offset_v2) );
 }
 static inline loff_t le_ih_k_type (struct item_head * ih)
 {
@@ -512,8 +569,9 @@
 
 static inline void set_le_key_k_offset (int version, struct key * key, loff_t offset)
 {
-    (version == ITEM_VERSION_1) ? (key->u.k_offset_v1.k_offset = offset) :
-	(key->u.k_offset_v2.k_offset = cpu_to_le64 (offset));
+    (version == ITEM_VERSION_1) ?
+        (key->u.k_offset_v1.k_offset = cpu_to_le32 (offset)) : /* jdm check */
+	(set_offset_v2_k_offset( &(key->u.k_offset_v2), offset ));
 }
 static inline void set_le_ih_k_offset (struct item_head * ih, loff_t offset)
 {
@@ -524,8 +582,9 @@
 
 static inline void set_le_key_k_type (int version, struct key * key, int type)
 {
-    (version == ITEM_VERSION_1) ? (key->u.k_offset_v1.k_uniqueness = type2uniqueness (type)) :
-	(key->u.k_offset_v2.k_type = cpu_to_le16 (type));
+    (version == ITEM_VERSION_1) ?
+        (key->u.k_offset_v1.k_uniqueness = cpu_to_le32(type2uniqueness(type))):
+	(set_offset_v2_k_type( &(key->u.k_offset_v2), type ));
 }
 static inline void set_le_ih_k_type (struct item_head * ih, int type)
 {
@@ -553,26 +612,30 @@
 //
 static inline loff_t cpu_key_k_offset (struct cpu_key * key)
 {
-    return (key->version == ITEM_VERSION_1) ? key->on_disk_key.u.k_offset_v1.k_offset :
+    return (key->version == ITEM_VERSION_1) ?
+        key->on_disk_key.u.k_offset_v1.k_offset :
 	key->on_disk_key.u.k_offset_v2.k_offset;
 }
 
 static inline loff_t cpu_key_k_type (struct cpu_key * key)
 {
-    return (key->version == ITEM_VERSION_1) ? uniqueness2type (key->on_disk_key.u.k_offset_v1.k_uniqueness) :
+    return (key->version == ITEM_VERSION_1) ?
+        uniqueness2type (key->on_disk_key.u.k_offset_v1.k_uniqueness) :
 	key->on_disk_key.u.k_offset_v2.k_type;
 }
 
 static inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset)
 {
-    (key->version == ITEM_VERSION_1) ? (key->on_disk_key.u.k_offset_v1.k_offset = offset) :
+    (key->version == ITEM_VERSION_1) ?
+        (key->on_disk_key.u.k_offset_v1.k_offset = offset) :
 	(key->on_disk_key.u.k_offset_v2.k_offset = offset);
 }
 
 
 static inline void set_cpu_key_k_type (struct cpu_key * key, int type)
 {
-    (key->version == ITEM_VERSION_1) ? (key->on_disk_key.u.k_offset_v1.k_uniqueness = type2uniqueness (type)) :
+    (key->version == ITEM_VERSION_1) ?
+        (key->on_disk_key.u.k_offset_v1.k_uniqueness = type2uniqueness (type)):
 	(key->on_disk_key.u.k_offset_v2.k_type = type);
 }
 
@@ -638,7 +701,17 @@
   struct key  blk_right_delim_key; /* kept only for compatibility */
 };
 
-#define BLKH_SIZE (sizeof(struct block_head))
+#define BLKH_SIZE                     (sizeof(struct block_head))
+#define blkh_level(p_blkh)            (le16_to_cpu((p_blkh)->blk_level))
+#define blkh_nr_item(p_blkh)          (le16_to_cpu((p_blkh)->blk_nr_item))
+#define blkh_free_space(p_blkh)       (le16_to_cpu((p_blkh)->blk_free_space))
+#define blkh_reserved(p_blkh)         (le16_to_cpu((p_blkh)->blk_reserved))
+#define set_blkh_level(p_blkh,val)    ((p_blkh)->blk_level = cpu_to_le16(val))
+#define set_blkh_nr_item(p_blkh,val)  ((p_blkh)->blk_nr_item = cpu_to_le16(val))
+#define set_blkh_free_space(p_blkh,val) ((p_blkh)->blk_free_space = cpu_to_le16(val))
+#define set_blkh_reserved(p_blkh,val) ((p_blkh)->blk_reserved = cpu_to_le16(val))
+#define blkh_right_delim_key(p_blkh)  ((p_blkh)->blk_right_delim_key)
+#define set_blkh_right_delim_key(p_blkh,val)  ((p_blkh)->blk_right_delim_key = val)
 
 /*
  * values for blk_level field of the struct block_head
@@ -652,25 +725,26 @@
 #define DISK_LEAF_NODE_LEVEL  1 /* Leaf node level.*/
 
 /* Given the buffer head of a formatted node, resolve to the block head of that node. */
-#define B_BLK_HEAD(p_s_bh)  ((struct block_head *)((p_s_bh)->b_data))
+#define B_BLK_HEAD(p_s_bh)            ((struct block_head *)((p_s_bh)->b_data))
 /* Number of items that are in buffer. */
-#define B_NR_ITEMS(p_s_bh)	  	(le16_to_cpu ( B_BLK_HEAD(p_s_bh)->blk_nr_item ))
-#define B_LEVEL(bh)			(le16_to_cpu ( B_BLK_HEAD(bh)->blk_level ))
-#define B_FREE_SPACE(bh)		(le16_to_cpu ( B_BLK_HEAD(bh)->blk_free_space ))
-
-#define PUT_B_NR_ITEMS(p_s_bh)	  	do { B_BLK_HEAD(p_s_bh)->blk_nr_item = cpu_to_le16(val); } while (0)
-#define PUT_B_LEVEL(bh, val)		do { B_BLK_HEAD(bh)->blk_level = cpu_to_le16(val); } while (0)
-#define PUT_B_FREE_SPACE(bh)		do { B_BLK_HEAD(bh)->blk_free_space = cpu_to_le16(val); } while (0)
+#define B_NR_ITEMS(p_s_bh)            (blkh_nr_item(B_BLK_HEAD(p_s_bh)))
+#define B_LEVEL(p_s_bh)               (blkh_level(B_BLK_HEAD(p_s_bh)))
+#define B_FREE_SPACE(p_s_bh)          (blkh_free_space(B_BLK_HEAD(p_s_bh)))
+
+#define PUT_B_NR_ITEMS(p_s_bh,val)    do { set_blkh_nr_item(B_BLK_HEAD(p_s_bh),val); } while (0)
+#define PUT_B_LEVEL(p_s_bh,val)       do { set_blkh_level(B_BLK_HEAD(p_s_bh),val); } while (0)
+#define PUT_B_FREE_SPACE(p_s_bh,val)  do { set_blkh_free_space(B_BLK_HEAD(p_s_bh),val); } while (0)
+
 
-/* Get right delimiting key. */
-#define B_PRIGHT_DELIM_KEY(p_s_bh)	( &(B_BLK_HEAD(p_s_bh)->blk_right_delim_key) )
+/* Get right delimiting key. -- little endian */
+#define B_PRIGHT_DELIM_KEY(p_s_bh)   (&(blk_right_delim_key(B_BLK_HEAD(p_s_bh))
 
 /* Does the buffer contain a disk leaf. */
-#define B_IS_ITEMS_LEVEL(p_s_bh)   	( B_BLK_HEAD(p_s_bh)->blk_level == DISK_LEAF_NODE_LEVEL )
+#define B_IS_ITEMS_LEVEL(p_s_bh)     (B_LEVEL(p_s_bh) == DISK_LEAF_NODE_LEVEL)
 
 /* Does the buffer contain a disk internal node */
-#define B_IS_KEYS_LEVEL(p_s_bh) 	( B_BLK_HEAD(p_s_bh)->blk_level > DISK_LEAF_NODE_LEVEL &&\
-					  B_BLK_HEAD(p_s_bh)->blk_level <= MAX_HEIGHT )
+#define B_IS_KEYS_LEVEL(p_s_bh)      (B_LEVEL(p_s_bh) > DISK_LEAF_NODE_LEVEL \
+                                            && B_LEVEL(p_s_bh) <= MAX_HEIGHT)
 
 
 
@@ -709,8 +783,32 @@
 				   policy.  Someday.  -Hans */
 } __attribute__ ((__packed__));
 
-#define SD_V1_SIZE (sizeof(struct stat_data_v1))
-
+#define SD_V1_SIZE              (sizeof(struct stat_data_v1))
+#define stat_data_v1(ih)        (ih_version (ih) == ITEM_VERSION_1)
+#define sd_v1_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
+#define set_sd_v1_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
+#define sd_v1_nlink(sdp)        (le16_to_cpu((sdp)->sd_nlink))
+#define set_sd_v1_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le16(v))
+#define sd_v1_uid(sdp)          (le16_to_cpu((sdp)->sd_uid))
+#define set_sd_v1_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le16(v))
+#define sd_v1_gid(sdp)          (le16_to_cpu((sdp)->sd_gid))
+#define set_sd_v1_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le16(v))
+#define sd_v1_size(sdp)         (le32_to_cpu((sdp)->sd_size))
+#define set_sd_v1_size(sdp,v)   ((sdp)->sd_size = cpu_to_le32(v))
+#define sd_v1_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
+#define set_sd_v1_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
+#define sd_v1_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
+#define set_sd_v1_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
+#define sd_v1_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
+#define set_sd_v1_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
+#define sd_v1_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
+#define set_sd_v1_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
+#define sd_v1_blocks(sdp)       (le32_to_cpu((sdp)->u.sd_blocks))
+#define set_sd_v1_blocks(sdp,v) ((sdp)->u.sd_blocks = cpu_to_le32(v))
+#define sd_v1_first_direct_byte(sdp) \
+                                (le32_to_cpu((sdp)->sd_first_direct_byte))
+#define set_sd_v1_first_direct_byte(sdp,v) \
+                                ((sdp)->sd_first_direct_byte = cpu_to_le32(v))
 
 /* Stat Data on disk (reiserfs version of UFS disk inode minus the
    address blocks) */
@@ -743,8 +841,32 @@
 // this is 40 bytes long
 //
 #define SD_SIZE (sizeof(struct stat_data))
-
-#define stat_data_v1(ih) (ih_version (ih) == ITEM_VERSION_1)
+#define SD_V2_SIZE              SD_SIZE
+#define stat_data_v2(ih)        (ih_version (ih) == ITEM_VERSION_2)
+#define sd_v2_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
+#define set_sd_v2_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
+/* sd_reserved */
+/* set_sd_reserved */
+#define sd_v2_nlink(sdp)        (le32_to_cpu((sdp)->sd_nlink))
+#define set_sd_v2_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le32(v))
+#define sd_v2_size(sdp)         (le64_to_cpu((sdp)->sd_size))
+#define set_sd_v2_size(sdp,v)   ((sdp)->sd_size = cpu_to_le64(v))
+#define sd_v2_uid(sdp)          (le32_to_cpu((sdp)->sd_uid))
+#define set_sd_v2_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le32(v))
+#define sd_v2_gid(sdp)          (le32_to_cpu((sdp)->sd_gid))
+#define set_sd_v2_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le32(v))
+#define sd_v2_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
+#define set_sd_v2_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
+#define sd_v2_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
+#define set_sd_v2_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
+#define sd_v2_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
+#define set_sd_v2_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
+#define sd_v2_blocks(sdp)       (le32_to_cpu((sdp)->sd_blocks))
+#define set_sd_v2_blocks(sdp,v) ((sdp)->sd_blocks = cpu_to_le32(v))
+#define sd_v2_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
+#define set_sd_v2_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
+#define sd_v2_generation(sdp)   (le32_to_cpu((sdp)->u.sd_generation))
+#define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v))
 
 
 /***************************************************************************/
@@ -793,7 +915,18 @@
   __u16 deh_state;		/* whether 1) entry contains stat data (for future), and 2) whether
 					   entry is hidden (unlinked) */
 } __attribute__ ((__packed__));
-#define DEH_SIZE sizeof(struct reiserfs_de_head)
+#define DEH_SIZE                  sizeof(struct reiserfs_de_head)
+#define deh_offset(p_deh)         (le32_to_cpu((p_deh)->deh_offset))
+#define deh_dir_id(p_deh)         (le32_to_cpu((p_deh)->deh_dir_id))
+#define deh_objectid(p_deh)       (le32_to_cpu((p_deh)->deh_objectid))
+#define deh_location(p_deh)       (le16_to_cpu((p_deh)->deh_location))
+#define deh_state(p_deh)          (le16_to_cpu((p_deh)->deh_state))
+
+#define put_deh_offset(p_deh,v)   ((p_deh)->deh_offset = cpu_to_le32((v)))
+#define put_deh_dir_id(p_deh,v)   ((p_deh)->deh_dir_id = cpu_to_le32((v)))
+#define put_deh_objectid(p_deh,v) ((p_deh)->deh_objectid = cpu_to_le32((v)))
+#define put_deh_location(p_deh,v) ((p_deh)->deh_location = cpu_to_le16((v)))
+#define put_deh_state(p_deh,v)    ((p_deh)->deh_state = cpu_to_le16((v)))
 
 /* empty directory contains two entries "." and ".." and their headers */
 #define EMPTY_DIR_SIZE \
@@ -805,34 +938,31 @@
 #define DEH_Statdata 0			/* not used now */
 #define DEH_Visible 2
 
-/* bitops which deals with unaligned addrs; 
-   needed for alpha port. --zam */
-#ifdef __alpha__
-#   define ADDR_UNALIGNED_BITS  (5)
+/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */
+#if BITS_PER_LONG == 64 || defined(__s390__) || defined(__hppa__)
+#   define ADDR_UNALIGNED_BITS  (3)
 #endif
 
+/* These are only used to manipulate deh_state.
+ * Because of this, we'll use the ext2_ bit routines,
+ * since they are little endian */
 #ifdef ADDR_UNALIGNED_BITS
 
 #   define aligned_address(addr)           ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1)))
 #   define unaligned_offset(addr)          (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3)
 
-#   define set_bit_unaligned(nr, addr)     set_bit((nr) + unaligned_offset(addr), aligned_address(addr))
-#   define clear_bit_unaligned(nr, addr)   clear_bit((nr) + unaligned_offset(addr), aligned_address(addr))
-#   define test_bit_unaligned(nr, addr)    test_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define set_bit_unaligned(nr, addr)     ext2_set_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define clear_bit_unaligned(nr, addr)   ext2_clear_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define test_bit_unaligned(nr, addr)    ext2_test_bit((nr) + unaligned_offset(addr), aligned_address(addr))
 
 #else
 
-#   define set_bit_unaligned(nr, addr)     set_bit(nr, addr)
-#   define clear_bit_unaligned(nr, addr)   clear_bit(nr, addr)
-#   define test_bit_unaligned(nr, addr)    test_bit(nr, addr)
+#   define set_bit_unaligned(nr, addr)     ext2_set_bit(nr, addr)
+#   define clear_bit_unaligned(nr, addr)   ext2_clear_bit(nr, addr)
+#   define test_bit_unaligned(nr, addr)    ext2_test_bit(nr, addr)
 
 #endif
 
-#define deh_dir_id(deh) (__le32_to_cpu ((deh)->deh_dir_id))
-#define deh_objectid(deh) (__le32_to_cpu ((deh)->deh_objectid))
-#define deh_offset(deh) (__le32_to_cpu ((deh)->deh_offset))
-
-
 #define mark_de_with_sd(deh)        set_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
 #define mark_de_without_sd(deh)     clear_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
 #define mark_de_visible(deh)	    set_bit_unaligned (DEH_Visible, &((deh)->deh_state))
@@ -844,7 +974,9 @@
 
 /* compose directory item containing "." and ".." entries (entries are
    not aligned to 4 byte boundary) */
-static inline void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
+/* the last four params are LE */
+static inline void make_empty_dir_item_v1 (char * body,
+                                           __u32 dirid, __u32 objid,
 					   __u32 par_dirid, __u32 par_objid)
 {
     struct reiserfs_de_head * deh;
@@ -853,29 +985,32 @@
     deh = (struct reiserfs_de_head *)body;
     
     /* direntry header of "." */
-    deh[0].deh_offset = cpu_to_le32 (DOT_OFFSET);
-    deh[0].deh_dir_id = cpu_to_le32 (dirid);
-    deh[0].deh_objectid = cpu_to_le32 (objid);
-    deh[0].deh_location = cpu_to_le16 (EMPTY_DIR_SIZE_V1 - strlen ("."));
-    deh[0].deh_state = 0;
+    put_deh_offset( &(deh[0]), DOT_OFFSET );
+    /* these two are from make_le_item_head, and are are LE */
+    deh[0].deh_dir_id = dirid;
+    deh[0].deh_objectid = objid;
+    deh[0].deh_state = 0; /* Endian safe if 0 */
+    put_deh_location( &(deh[0]), EMPTY_DIR_SIZE_V1 - strlen( "." ));
     mark_de_visible(&(deh[0]));
   
     /* direntry header of ".." */
-    deh[1].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET);
+    put_deh_offset( &(deh[1]), DOT_DOT_OFFSET);
     /* key of ".." for the root directory */
-    deh[1].deh_dir_id = cpu_to_le32 (par_dirid);
-    deh[1].deh_objectid = cpu_to_le32 (par_objid);
-    deh[1].deh_location = cpu_to_le16 (le16_to_cpu (deh[0].deh_location) - strlen (".."));
-    deh[1].deh_state = 0;
+    /* these two are from the inode, and are are LE */
+    deh[1].deh_dir_id = par_dirid;
+    deh[1].deh_objectid = par_objid;
+    deh[1].deh_state = 0; /* Endian safe if 0 */
+    put_deh_location( &(deh[1]), deh_location( &(deh[0]) ) - strlen( ".." ) );
     mark_de_visible(&(deh[1]));
 
     /* copy ".." and "." */
-    memcpy (body + deh[0].deh_location, ".", 1);
-    memcpy (body + deh[1].deh_location, "..", 2);
+    memcpy (body + deh_location( &(deh[0]) ), ".", 1);
+    memcpy (body + deh_location( &(deh[1]) ), "..", 2);
 }
 
 /* compose directory item containing "." and ".." entries */
-static inline void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
+static inline void make_empty_dir_item (char * body,
+                                        __u32 dirid, __u32 objid,
 					__u32 par_dirid, __u32 par_objid)
 {
     struct reiserfs_de_head * deh;
@@ -884,31 +1019,33 @@
     deh = (struct reiserfs_de_head *)body;
     
     /* direntry header of "." */
-    deh[0].deh_offset = cpu_to_le32 (DOT_OFFSET);
-    deh[0].deh_dir_id = cpu_to_le32 (dirid);
-    deh[0].deh_objectid = cpu_to_le32 (objid);
-    deh[0].deh_location = cpu_to_le16 (EMPTY_DIR_SIZE - ROUND_UP (strlen (".")));
-    deh[0].deh_state = 0;
+    put_deh_offset( &(deh[0]), DOT_OFFSET );
+    /* these two are from make_le_item_head, and are are LE */
+    deh[0].deh_dir_id = dirid;
+    deh[0].deh_objectid = objid;
+    deh[0].deh_state = 0; /* Endian safe if 0 */
+    put_deh_location( &(deh[0]), EMPTY_DIR_SIZE - ROUND_UP( strlen( "." ) ) );
     mark_de_visible(&(deh[0]));
   
     /* direntry header of ".." */
-    deh[1].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET);
+    put_deh_offset( &(deh[1]), DOT_DOT_OFFSET );
     /* key of ".." for the root directory */
-    deh[1].deh_dir_id = cpu_to_le32 (par_dirid);
-    deh[1].deh_objectid = cpu_to_le32 (par_objid);
-    deh[1].deh_location = cpu_to_le16 (le16_to_cpu (deh[0].deh_location) - ROUND_UP (strlen ("..")));
-    deh[1].deh_state = 0;
+    /* these two are from the inode, and are are LE */
+    deh[1].deh_dir_id = par_dirid;
+    deh[1].deh_objectid = par_objid;
+    deh[1].deh_state = 0; /* Endian safe if 0 */
+    put_deh_location( &(deh[1]), deh_location( &(deh[0])) - ROUND_UP( strlen( ".." ) ) );
     mark_de_visible(&(deh[1]));
 
     /* copy ".." and "." */
-    memcpy (body + deh[0].deh_location, ".", 1);
-    memcpy (body + deh[1].deh_location, "..", 2);
+    memcpy (body + deh_location( &(deh[0]) ), ".", 1);
+    memcpy (body + deh_location( &(deh[1]) ), "..", 2);
 }
 
 
 /* array of the entry headers */
  /* get item body */
-#define B_I_PITEM(bh,ih) ( (bh)->b_data + (ih)->ih_item_location )
+#define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih) )
 #define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih)))
 
 /* length of the directory entry in directory item. This define
@@ -919,7 +1056,7 @@
    See picture above.*/
 /*
 #define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \
-((i) ? (((deh)-1)->deh_location - (deh)->deh_location) : ((ih)->ih_item_len) - (deh)->deh_location)
+((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh))))
 */
 static inline int entry_length (struct buffer_head * bh, struct item_head * ih,
 				int pos_in_item)
@@ -928,18 +1065,19 @@
 
     deh = B_I_DEH (bh, ih) + pos_in_item;
     if (pos_in_item)
-	return (le16_to_cpu ((deh - 1)->deh_location) - le16_to_cpu (deh->deh_location));
-    return (le16_to_cpu (ih->ih_item_len) - le16_to_cpu (deh->deh_location));
+	return deh_location(deh-1) - deh_location(deh);
+
+    return ih_item_len(ih) - deh_location(deh);
 }
 
 
 
 /* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */
-#define I_ENTRY_COUNT(ih) ((ih)->u.ih_entry_count)
+#define I_ENTRY_COUNT(ih) (ih_entry_count((ih)))
 
 
 /* name by bh, ih and entry_num */
-#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih->ih_item_location + (B_I_DEH(bh,ih)+(entry_num))->deh_location))
+#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num))))
 
 // two entries per block (at least)
 //#define REISERFS_MAX_NAME_LEN(block_size) 
@@ -976,7 +1114,7 @@
 /* these defines are useful when a particular member of a reiserfs_dir_entry is needed */
 
 /* pointer to file name, stored in entry */
-#define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + (deh)->deh_location)
+#define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + deh_location(deh))
 
 /* length of name */
 #define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \
@@ -1014,14 +1152,18 @@
 };
 
 #define DC_SIZE (sizeof(struct disk_child))
+#define dc_block_number(dc_p)	(le32_to_cpu((dc_p)->dc_block_number))
+#define dc_size(dc_p)		(le16_to_cpu((dc_p)->dc_size))
+#define put_dc_block_number(dc_p, val)   do { (dc_p)->dc_block_number = cpu_to_le32(val); } while(0)
+#define put_dc_size(dc_p, val)   do { (dc_p)->dc_size = cpu_to_le16(val); } while(0)
 
 /* Get disk child by buffer header and position in the tree node. */
 #define B_N_CHILD(p_s_bh,n_pos)  ((struct disk_child *)\
 ((p_s_bh)->b_data+BLKH_SIZE+B_NR_ITEMS(p_s_bh)*KEY_SIZE+DC_SIZE*(n_pos)))
 
 /* Get disk child number by buffer header and position in the tree node. */
-#define B_N_CHILD_NUM(p_s_bh,n_pos) (le32_to_cpu (B_N_CHILD(p_s_bh,n_pos)->dc_block_number))
-#define PUT_B_N_CHILD_NUM(p_s_bh,n_pos, val) do { B_N_CHILD(p_s_bh,n_pos)->dc_block_number = cpu_to_le32(val); } while (0)
+#define B_N_CHILD_NUM(p_s_bh,n_pos) (dc_block_number(B_N_CHILD(p_s_bh,n_pos)))
+#define PUT_B_N_CHILD_NUM(p_s_bh,n_pos, val) (put_dc_block_number(B_N_CHILD(p_s_bh,n_pos), val ))
 
  /* maximal value of field child_size in structure disk_child */ 
  /* child size is the combined size of all items and their headers */
@@ -1459,10 +1601,10 @@
 
 
 /* number of blocks pointed to by the indirect item */
-#define I_UNFM_NUM(p_s_ih)	( (p_s_ih)->ih_item_len / UNFM_P_SIZE )
+#define I_UNFM_NUM(p_s_ih)	( ih_item_len(p_s_ih) / UNFM_P_SIZE )
 
 /* the used space within the unformatted node corresponding to pos within the item pointed to by ih */
-#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - (ih)->u.ih_free_space : (size))
+#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size))
 
 /* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */
 
@@ -1477,16 +1619,16 @@
 #define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) )
 
 /* get item body */
-#define B_N_PITEM(bh,item_num) ( (bh)->b_data + B_N_PITEM_HEAD((bh),(item_num))->ih_item_location)
+#define B_N_PITEM(bh,item_num) ( (bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(item_num))))
 
 /* get the stat data by the buffer header and the item order */
 #define B_N_STAT_DATA(bh,nr) \
-( (struct stat_data *)((bh)->b_data+B_N_PITEM_HEAD((bh),(nr))->ih_item_location ) )
+( (struct stat_data *)((bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(nr))) ) )
 
-                 /* following defines use reiserfs buffer header and item header */
+    /* following defines use reiserfs buffer header and item header */
 
 /* get stat-data */
-#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + (ih)->ih_item_location) )
+#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + ih_location(ih)) )
 
 // this is 3976 for size==4096
 #define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE)
@@ -1494,7 +1636,7 @@
 /* indirect items consist of entries which contain blocknrs, pos
    indicates which entry, and B_I_POS_UNFM_POINTER resolves to the
    blocknr contained by the entry pos points to */
-#define B_I_POS_UNFM_POINTER(bh,ih,pos) (*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)))
+#define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)))
 #define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0)
 
 /* Reiserfs buffer cache statistics. */
@@ -1596,6 +1738,8 @@
 */
 #define JOURNAL_BUFFER(j,n) ((j)->j_ap_blocks[((j)->j_start + (n)) % JOURNAL_BLOCK_COUNT])
 
+void reiserfs_commit_for_inode(struct inode *) ;
+void reiserfs_update_inode_transaction(struct inode *) ;
 void reiserfs_wait_on_write_block(struct super_block *s) ;
 void reiserfs_block_writes(struct reiserfs_transaction_handle *th) ;
 void reiserfs_allow_writes(struct super_block *s) ;
@@ -1692,7 +1836,7 @@
 {
     int type;
     
-    type = le16_to_cpu (key->u.k_offset_v2.k_type);
+    type = offset_v2_k_type( &(key->u.k_offset_v2));
     if (type != TYPE_DIRECT && type != TYPE_INDIRECT && type != TYPE_DIRENTRY)
 	return ITEM_VERSION_1;
 
@@ -1943,9 +2087,9 @@
 #endif
 
 /* hashes.c */
-__u32 keyed_hash (const char *msg, int len);
-__u32 yura_hash (const char *msg, int len);
-__u32 r5_hash (const char *msg, int len);
+__u32 keyed_hash (const signed char *msg, int len);
+__u32 yura_hash (const signed char *msg, int len);
+__u32 r5_hash (const signed char *msg, int len);
 
 /* version.c */
 char *reiserfs_get_version_string(void) ;
diff -u --recursive --new-file v2.4.12/linux/include/linux/reiserfs_fs_i.h linux/include/linux/reiserfs_fs_i.h
--- v2.4.12/linux/include/linux/reiserfs_fs_i.h	Thu Oct 18 13:47:37 2001
+++ linux/include/linux/reiserfs_fs_i.h	Thu Oct 18 17:43:37 2001
@@ -40,6 +40,12 @@
                                    is a comment you should make.... -Hans */
   //nopack-attribute
   int nopack;
+  
+  /* we use these for fsync or O_SYNC to decide which transaction needs
+  ** to be committed in order for this inode to be properly flushed
+  */
+  unsigned long i_trans_id ;
+  unsigned long i_trans_index ;
 };
 
 
diff -u --recursive --new-file v2.4.12/linux/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h
--- v2.4.12/linux/include/linux/reiserfs_fs_sb.h	Thu Oct 18 13:47:38 2001
+++ linux/include/linux/reiserfs_fs_sb.h	Thu Oct 18 17:43:37 2001
@@ -65,6 +65,57 @@
 } __attribute__ ((__packed__));
 
 #define SB_SIZE (sizeof(struct reiserfs_super_block))
+/* struct reiserfs_super_block accessors/mutators
+ * since this is a disk structure, it will always be in 
+ * little endian format. */
+#define sb_block_count(sbp)           (le32_to_cpu((sbp)->s_block_count))
+#define set_sb_block_count(sbp,v)     ((sbp)->s_block_count = cpu_to_le32(v))
+#define sb_free_blocks(sbp)           (le32_to_cpu((sbp)->s_free_blocks))
+#define set_sb_free_blocks(sbp,v)     ((sbp)->s_free_blocks = cpu_to_le32(v))
+#define sb_root_block(sbp)            (le32_to_cpu((sbp)->s_root_block))
+#define set_sb_root_block(sbp,v)      ((sbp)->s_root_block = cpu_to_le32(v))
+#define sb_journal_block(sbp)         (le32_to_cpu((sbp)->s_journal_block))
+#define set_sb_journal_block(sbp,v)   ((sbp)->s_journal_block = cpu_to_le32(v))
+#define sb_journal_dev(sbp)           (le32_to_cpu((sbp)->s_journal_dev))
+#define set_sb_journal_dev(sbp,v)     ((sbp)->s_journal_dev = cpu_to_le32(v))
+#define sb_orig_journal_size(sbp)   (le32_to_cpu((sbp)->s_orig_journal_size))
+#define set_sb_orig_journal_size(sbp,v) \
+                            ((sbp)->s_orig_journal_size = cpu_to_le32(v))
+#define sb_journal_trans_max(sbp)     (le32_to_cpu((sbp)->s_journal_trans_max))
+#define set_journal_trans_max(sbp,v) \
+                            ((sbp)->s_journal_trans_max = cpu_to_le32(v))
+#define sb_journal_block_count(sbp)  (le32_to_cpu((sbp)->journal_block_count))
+#define sb_set_journal_block_count(sbp,v) \
+                            ((sbp)->s_journal_block_count = cpu_to_le32(v))
+#define sb_journal_max_batch(sbp)     (le32_to_cpu((sbp)->s_journal_max_batch))
+#define set_sb_journal_max_batch(sbp,v) \
+                            ((sbp)->s_journal_max_batch = cpu_to_le32(v))
+#define sb_jourmal_max_commit_age(sbp) \
+                            (le32_to_cpu((sbp)->s_journal_max_commit_age))
+#define set_sb_journal_max_commit_age(sbp,v) \
+                            ((sbp)->s_journal_max_commit_age = cpu_to_le32(v))
+#define sb_jourmal_max_trans_age(sbp) \
+                            (le32_to_cpu((sbp)->s_journal_max_trans_age))
+#define set_sb_journal_max_trans_age(sbp,v) \
+                            ((sbp)->s_journal_max_trans_age = cpu_to_le32(v))
+#define sb_blocksize(sbp)             (le16_to_cpu((sbp)->s_blocksize))
+#define set_sb_blocksize(sbp,v)       ((sbp)->s_blocksize = cpu_to_le16(v))
+#define sb_oid_maxsize(sbp)           (le16_to_cpu((sbp)->s_oid_maxsize))
+#define set_sb_oid_maxsize(sbp,v)     ((sbp)->s_oid_maxsize = cpu_to_le16(v))
+#define sb_oid_cursize(sbp)           (le16_to_cpu((sbp)->s_oid_cursize))
+#define set_sb_oid_cursize(sbp,v)     ((sbp)->s_oid_cursize = cpu_to_le16(v))
+#define sb_state(sbp)                 (le16_to_cpu((sbp)->s_state))
+#define set_sb_state(sbp,v)           ((sbp)->s_state = cpu_to_le16(v))
+#define sb_hash_function_code(sbp) \
+                            (le32_to_cpu((sbp)->s_hash_function_code))
+#define set_sb_hash_function_code(sbp,v) \
+                            ((sbp)->s_hash_function_code = cpu_to_le32(v))
+#define sb_tree_height(sbp)           (le16_to_cpu((sbp)->s_tree_height))
+#define set_sb_tree_height(sbp,v)     ((sbp)->s_tree_height = cpu_to_le16(v))
+#define sb_bmap_nr(sbp)               (le16_to_cpu((sbp)->s_bmap_nr))
+#define set_sb_bmap_nr(sbp,v)         ((sbp)->s_bmap_nr = cpu_to_le16(v))
+#define sb_version(sbp)               (le16_to_cpu((sbp)->s_version))
+#define set_sb_version(sbp,v)         ((sbp)->s_version = cpu_to_le16(v))
 
 /* this is the super from 3.5.X, where X >= 10 */
 struct reiserfs_super_block_v1
@@ -180,7 +231,6 @@
   unsigned long t_trans_id ;    /* sanity check, equals the current trans id */
   struct super_block *t_super ; /* super for this FS when journal_begin was 
                                    called. saves calls to reiserfs_get_super */
-
 } ;
 
 /*
@@ -262,7 +312,7 @@
 #define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick.  magic string to find desc blocks in the journal */
 
 
-typedef __u32 (*hashf_t) (const char *, int);
+typedef __u32 (*hashf_t) (const signed char *, int);
 
 /* reiserfs union of in-core super block data */
 struct reiserfs_sb_info
@@ -377,25 +427,22 @@
 
 
 // on-disk super block fields converted to cpu form
-#define SB_DISK_SUPER_BLOCK(s) ((s)->u.reiserfs_sb.s_rs)
-#define SB_BLOCK_COUNT(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_block_count))
-#define SB_FREE_BLOCKS(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_free_blocks))
-#define SB_REISERFS_MAGIC(s) (SB_DISK_SUPER_BLOCK(s)->s_magic)
-#define SB_ROOT_BLOCK(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_root_block))
-#define SB_TREE_HEIGHT(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_tree_height))
-#define SB_REISERFS_STATE(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_state))
-#define SB_VERSION(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_version))
-#define SB_BMAP_NR(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_bmap_nr))
-
-#define PUT_SB_BLOCK_COUNT(s, val)    do { SB_DISK_SUPER_BLOCK(s)->s_block_count = cpu_to_le32(val); } while (0)
-#define PUT_SB_FREE_BLOCKS(s, val)    do { SB_DISK_SUPER_BLOCK(s)->s_free_blocks = cpu_to_le32(val); } while (0)
-#define PUT_SB_ROOT_BLOCK(s, val)     do { SB_DISK_SUPER_BLOCK(s)->s_root_block = cpu_to_le32(val); } while (0)
-#define PUT_SB_TREE_HEIGHT(s, val)    do { SB_DISK_SUPER_BLOCK(s)->s_tree_height = cpu_to_le16(val); } while (0)
-#define PUT_SB_REISERFS_STATE(s, val) do { SB_DISK_SUPER_BLOCK(s)->s_state = cpu_to_le16(val); } while (0) 
-#define PUT_SB_VERSION(s, val)        do { SB_DISK_SUPER_BLOCK(s)->s_version = cpu_to_le16(val); } while (0)
-#define PUT_SB_BMAP_NR(s, val)           do { SB_DISK_SUPER_BLOCK(s)->s_bmap_nr = cpu_to_le16 (val); } while (0)
+#define SB_DISK_SUPER_BLOCK(s)        ((s)->u.reiserfs_sb.s_rs)
+#define SB_BLOCK_COUNT(s)             sb_block_count (SB_DISK_SUPER_BLOCK(s))
+#define SB_FREE_BLOCKS(s)             sb_free_blocks (SB_DISK_SUPER_BLOCK(s))
+#define SB_REISERFS_MAGIC(s)          (SB_DISK_SUPER_BLOCK(s)->s_magic)
+#define SB_ROOT_BLOCK(s)              sb_root_block (SB_DISK_SUPER_BLOCK(s))
+#define SB_TREE_HEIGHT(s)             sb_tree_height (SB_DISK_SUPER_BLOCK(s))
+#define SB_REISERFS_STATE(s)          sb_state (SB_DISK_SUPER_BLOCK(s))
+#define SB_VERSION(s)                 sb_version (SB_DISK_SUPER_BLOCK(s))
+#define SB_BMAP_NR(s)                 sb_bmap_nr(SB_DISK_SUPER_BLOCK(s))
+
+#define PUT_SB_BLOCK_COUNT(s, val)    do { set_sb_block_count( SB_DISK_SUPER_BLOCK(s), val); } while (0)
+#define PUT_SB_FREE_BLOCKS(s, val)    do { set_sb_free_blocks( SB_DISK_SUPER_BLOCK(s), val); } while (0)
+#define PUT_SB_ROOT_BLOCK(s, val)     do { set_sb_root_block( SB_DISK_SUPER_BLOCK(s), val); } while (0)
+#define PUT_SB_TREE_HEIGHT(s, val)    do { set_sb_tree_height( SB_DISK_SUPER_BLOCK(s), val); } while (0)
+#define PUT_SB_REISERFS_STATE(s, val) do { set_sb_state( SB_DISK_SUPER_BLOCK(s), val); } while (0) 
+#define PUT_SB_VERSION(s, val)        do { set_sb_version( SB_DISK_SUPER_BLOCK(s), val); } while (0)
+#define PUT_SB_BMAP_NR(s, val)        do { set_sb_bmap_nr( SB_DISK_SUPER_BLOCK(s), val); } while (0)
 
 #endif	/* _LINUX_REISER_FS_SB */
-
-
-
diff -u --recursive --new-file v2.4.12/linux/include/linux/sonypi.h linux/include/linux/sonypi.h
--- v2.4.12/linux/include/linux/sonypi.h	Sun Sep 23 11:41:01 2001
+++ linux/include/linux/sonypi.h	Thu Oct 11 11:17:22 2001
@@ -67,9 +67,12 @@
 #define SONYPI_EVENT_FNKEY_S			29
 #define SONYPI_EVENT_FNKEY_B			30
 #define SONYPI_EVENT_BLUETOOTH_PRESSED		31
-#define SONYPI_EVENT_PKEY_P1                    32
-#define SONYPI_EVENT_PKEY_P2                    33
-#define SONYPI_EVENT_PKEY_P3                    34
+#define SONYPI_EVENT_PKEY_P1			32
+#define SONYPI_EVENT_PKEY_P2			33
+#define SONYPI_EVENT_PKEY_P3			34
+#define SONYPI_EVENT_BACK_PRESSED		35
+#define SONYPI_EVENT_LID_CLOSED			36
+#define SONYPI_EVENT_LID_OPENED			37
 
 
 /* brightness etc. ioctls */
diff -u --recursive --new-file v2.4.12/linux/include/linux/spinlock.h linux/include/linux/spinlock.h
--- v2.4.12/linux/include/linux/spinlock.h	Thu Oct 18 13:47:37 2001
+++ linux/include/linux/spinlock.h	Thu Oct 18 17:43:37 2001
@@ -30,6 +30,10 @@
 #define write_unlock_irqrestore(lock, flags)	do { write_unlock(lock); local_irq_restore(flags); } while (0)
 #define write_unlock_irq(lock)			do { write_unlock(lock); local_irq_enable();       } while (0)
 #define write_unlock_bh(lock)			do { write_unlock(lock); local_bh_enable();        } while (0)
+#define spin_trylock_bh(lock)			({ int __r; local_bh_disable();\
+						__r = spin_trylock(lock);      \
+						if (!__r) local_bh_enable();   \
+						__r; })
 
 #ifdef CONFIG_SMP
 #include <asm/spinlock.h>
diff -u --recursive --new-file v2.4.12/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.4.12/linux/include/linux/swap.h	Thu Oct 18 13:47:37 2001
+++ linux/include/linux/swap.h	Thu Oct 18 17:43:37 2001
@@ -110,7 +110,7 @@
 
 /* linux/mm/vmscan.c */
 extern wait_queue_head_t kswapd_wait;
-extern int FASTCALL(try_to_free_pages(zone_t *, unsigned int, unsigned int));
+extern int FASTCALL(try_to_free_pages(unsigned int, unsigned int));
 
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, struct page *);
diff -u --recursive --new-file v2.4.12/linux/include/linux/udf_fs.h linux/include/linux/udf_fs.h
--- v2.4.12/linux/include/linux/udf_fs.h	Tue Jul  3 17:08:22 2001
+++ linux/include/linux/udf_fs.h	Thu Oct 11 08:59:24 2001
@@ -37,8 +37,8 @@
 #define UDF_PREALLOCATE
 #define UDF_DEFAULT_PREALLOC_BLOCKS	8
 
-#define UDFFS_DATE			"2001/06/13"
-#define UDFFS_VERSION			"0.9.4.1"
+#define UDFFS_DATE			"2001/10/10"
+#define UDFFS_VERSION			"0.9.5"
 
 #if !defined(UDFFS_RW)
 
diff -u --recursive --new-file v2.4.12/linux/include/linux/udf_fs_sb.h linux/include/linux/udf_fs_sb.h
--- v2.4.12/linux/include/linux/udf_fs_sb.h	Thu Oct 18 13:47:34 2001
+++ linux/include/linux/udf_fs_sb.h	Thu Oct 11 08:59:24 2001
@@ -18,10 +18,6 @@
 #if !defined(_LINUX_UDF_FS_SB_H)
 #define _LINUX_UDF_FS_SB_H
 
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
 #pragma pack(1)
 
 #define UDF_MAX_BLOCK_LOADED	8
@@ -89,7 +85,7 @@
 	__u16			s_partition;
 
 	/* Sector headers */
-	__u32			s_session;
+	__s32			s_session;
 	__u32			s_anchor[4];
 	__u32			s_lastblock;
 
diff -u --recursive --new-file v2.4.12/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h
--- v2.4.12/linux/include/linux/ufs_fs.h	Thu Oct 18 13:47:37 2001
+++ linux/include/linux/ufs_fs.h	Sat Oct 20 19:14:42 2001
@@ -532,6 +532,14 @@
 /* dir.c */
 extern struct inode_operations ufs_dir_inode_operations;
 extern int ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *, struct buffer_head *, unsigned long);
+extern int ufs_add_link (struct dentry *, struct inode *);
+extern ino_t ufs_inode_by_name(struct inode *, struct dentry *);
+extern int ufs_make_empty(struct inode *, struct inode *);
+extern struct ufs_dir_entry * ufs_find_entry (struct dentry *, struct buffer_head **);
+extern int ufs_delete_entry (struct inode *, struct ufs_dir_entry *, struct buffer_head *);
+extern int ufs_empty_dir (struct inode *);
+extern struct ufs_dir_entry * ufs_dotdot (struct inode *, struct buffer_head **);
+extern void ufs_set_link(struct inode *, struct ufs_dir_entry *, struct buffer_head *, struct inode *);
 
 /* file.c */
 extern struct inode_operations ufs_file_inode_operations;
@@ -541,7 +549,7 @@
 
 /* ialloc.c */
 extern void ufs_free_inode (struct inode *inode);
-extern struct inode * ufs_new_inode (const struct inode *, int, int *);
+extern struct inode * ufs_new_inode (const struct inode *, int);
 
 /* inode.c */
 extern int ufs_frag_map (struct inode *, int);
diff -u --recursive --new-file v2.4.12/linux/include/linux/usb.h linux/include/linux/usb.h
--- v2.4.12/linux/include/linux/usb.h	Thu Oct 18 13:49:59 2001
+++ linux/include/linux/usb.h	Sat Oct 20 19:13:11 2001
@@ -855,7 +855,7 @@
 
 extern struct list_head usb_driver_list;
 extern struct list_head usb_bus_list;
-extern rwlock_t usb_bus_list_lock;
+extern struct semaphore usb_bus_list_lock;
 
 /*
  * USB device fs stuff
diff -u --recursive --new-file v2.4.12/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.4.12/linux/include/linux/videodev.h	Sun Aug 12 13:28:01 2001
+++ linux/include/linux/videodev.h	Thu Oct 11 11:17:22 2001
@@ -185,7 +185,7 @@
 {
 	__u32 	x,y;			/* Offsets into image */
 	__u32	width, height;		/* Area to capture */
-	__u16	decimation;		/* Decimation divder */
+	__u16	decimation;		/* Decimation divider */
 	__u16	flags;			/* Flags for capture */
 #define VIDEO_CAPTURE_ODD		0	/* Temporal */
 #define VIDEO_CAPTURE_EVEN		1
@@ -377,15 +377,5 @@
 #define VID_HARDWARE_PWC	31	/* Philips webcams */
 #define VID_HARDWARE_MEYE	32	/* Sony Vaio MotionEye cameras */
 #define VID_HARDWARE_CPIA2	33
-
-/*
- *	Initialiser list
- */
- 
-struct video_init
-{
-	char *name;
-	int (*init)(struct video_init *);
-};
 
 #endif
diff -u --recursive --new-file v2.4.12/linux/include/linux/vt_buffer.h linux/include/linux/vt_buffer.h
--- v2.4.12/linux/include/linux/vt_buffer.h	Thu Oct 18 13:49:26 2001
+++ linux/include/linux/vt_buffer.h	Thu Oct 18 17:45:36 2001
@@ -26,9 +26,6 @@
 #define scr_memmovew(d, s, c) memmove(d, s, c)
 #define VT_BUF_HAVE_MEMCPYW
 #define VT_BUF_HAVE_MEMMOVEW
-#define scr_memcpyw_from(d, s, c) memcpy(d, s, c)
-#define scr_memcpyw_to(d, s, c) memcpy(d, s, c)
-#define VT_BUF_HAVE_MEMCPYF
 #endif
 
 #ifndef VT_BUF_HAVE_MEMSETW
@@ -61,22 +58,6 @@
 		while (count--)
 			scr_writew(scr_readw(--s), --d);
 	}
-}
-#endif
-
-#ifndef VT_BUF_HAVE_MEMCPYF
-static inline void scr_memcpyw_from(u16 *d, const u16 *s, unsigned int count)
-{
-	count /= 2;
-	while (count--)
-		*d++ = scr_readw(s++);
-}
-
-static inline void scr_memcpyw_to(u16 *d, const u16 *s, unsigned int count)
-{
-	count /= 2;
-	while (count--)
-		scr_writew(*s++, d++);
 }
 #endif
 
diff -u --recursive --new-file v2.4.12/linux/include/linux/wireless.h linux/include/linux/wireless.h
--- v2.4.12/linux/include/linux/wireless.h	Thu Oct 18 13:47:51 2001
+++ linux/include/linux/wireless.h	Thu Oct 18 17:43:48 2001
@@ -1,7 +1,7 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	11	28.3.01
+ * Version :	12	5.10.01
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  */
@@ -63,7 +63,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	11
+#define WIRELESS_EXT	12
 
 /*
  * Changes :
@@ -116,6 +116,13 @@
  * ----------
  *	- Add WE version in range (help backward/forward compatibility)
  *	- Add retry ioctls (work like PM)
+ *
+ * V11 to V12
+ * ----------
+ *	- Add SIOCSIWSTATS to get /proc/net/wireless programatically
+ *	- Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
+ *	- Add new statistics (frag, retry, beacon)
+ *	- Add average quality (for user space calibration)
  */
 
 /* -------------------------- IOCTL LIST -------------------------- */
@@ -137,6 +144,8 @@
 #define SIOCGIWRANGE	0x8B0B		/* Get range of parameters */
 #define SIOCSIWPRIV	0x8B0C		/* Unused */
 #define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
+#define SIOCSIWSTATS	0x8B0E		/* Unused */
+#define SIOCGIWSTATS	0x8B0F		/* Get /proc/net/wireless stats */
 
 /* Mobile IP support */
 #define SIOCSIWSPY	0x8B10		/* set spy addresses */
@@ -177,11 +186,33 @@
 #define SIOCSIWPOWER	0x8B2C		/* set Power Management settings */
 #define SIOCGIWPOWER	0x8B2D		/* get Power Management settings */
 
+/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
+
+/* These 16 ioctl are wireless device private.
+ * Each driver is free to use them for whatever purpose it chooses,
+ * however the driver *must* export the description of those ioctls
+ * with SIOCGIWPRIV and *must* use arguments as defined below.
+ * If you don't follow those rules, DaveM is going to hate you (reason :
+ * it make mixed 32/64bit operation impossible).
+ */
+#define SIOCIWFIRSTPRIV	0x8BE0
+#define SIOCIWLASTPRIV	0x8BFF
+/* Previously, we were using SIOCDEVPRIVATE, but we now have our
+ * separate range because of collisions with other tools such as
+ * 'mii-tool'.
+ * We now have 32 commands, so a bit more space ;-).
+ * Also, all 'odd' commands are only usable by root and don't return the
+ * content of ifr/iwr to user (but you are not obliged to use the set/get
+ * convention, just use every other two command).
+ * And I repeat : you are not obliged to use them with iwspy, but you
+ * must be compliant with it.
+ */
+
 /* ------------------------- IOCTL STUFF ------------------------- */
 
 /* The first and the last (range) */
 #define SIOCIWFIRST	0x8B00
-#define SIOCIWLAST	0x8B30
+#define SIOCIWLAST	SIOCIWLASTPRIV		/* 0x8BFF */
 
 /* Even : get (world access), odd : set (root access) */
 #define IW_IS_SET(cmd)	(!((cmd) & 0x1))
@@ -191,7 +222,7 @@
 /*
  * The following is used with SIOCGIWPRIV. It allow a driver to define
  * the interface (name, type of data) for its private ioctl.
- * Privates ioctl are SIOCDEVPRIVATE -> SIOCDEVPRIVATE + 0xF
+ * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV
  */
 
 #define IW_PRIV_TYPE_MASK	0x7000	/* Type of arguments */
@@ -334,23 +365,38 @@
  */
 struct	iw_quality
 {
-	__u8		qual;		/* link quality (%retries, SNR or better...) */
-	__u8		level;		/* signal level */
-	__u8		noise;		/* noise level */
+	__u8		qual;		/* link quality (%retries, SNR,
+					   %missed beacons or better...) */
+	__u8		level;		/* signal level (dBm) */
+	__u8		noise;		/* noise level (dBm) */
 	__u8		updated;	/* Flags to know if updated */
 };
 
 /*
  *	Packet discarded in the wireless adapter due to
  *	"wireless" specific problems...
+ *	Note : the list of counter and statistics in net_device_stats
+ *	is already pretty exhaustive, and you should use that first.
+ *	This is only additional stats...
  */
 struct	iw_discarded
 {
-	__u32		nwid;		/* Wrong nwid */
-	__u32		code;		/* Unable to code/decode */
+	__u32		nwid;		/* Rx : Wrong nwid/essid */
+	__u32		code;		/* Rx : Unable to code/decode (WEP) */
+	__u32		fragment;	/* Rx : Can't perform MAC reassembly */
+	__u32		retries;	/* Tx : Max MAC retries num reached */
 	__u32		misc;		/* Others cases */
 };
 
+/*
+ *	Packet/Time period missed in the wireless adapter due to
+ *	"wireless" specific problems...
+ */
+struct	iw_missed
+{
+	__u32		beacon;		/* Missed beacons/superframe */
+};
+
 /* ------------------------ WIRELESS STATS ------------------------ */
 /*
  * Wireless statistics (used for /proc/net/wireless)
@@ -363,6 +409,7 @@
 	struct iw_quality	qual;		/* Quality of the link
 						 * (instant/mean/max) */
 	struct iw_discarded	discard;	/* Packet discarded counts */
+	struct iw_missed	miss;		/* Packet missed counts */
 };
 
 /* ------------------------ IOCTL REQUEST ------------------------ */
@@ -493,6 +540,19 @@
 	__s32		max_retry;	/* Maximal number of retries */
 	__s32		min_r_time;	/* Minimal retry lifetime */
 	__s32		max_r_time;	/* Maximal retry lifetime */
+
+	/* Average quality of link & SNR */
+	struct iw_quality	avg_qual;	/* Quality of the link */
+	/* This should contain the average/typical values of the quality
+	 * indicator. This should be the threshold between a "good" and
+	 * a "bad" link (example : monitor going from green to orange).
+	 * Currently, user space apps like quality monitors don't have any
+	 * way to calibrate the measurement. With this, they can split
+	 * the range between 0 and max_qual in different quality level
+	 * (using a geometric subdivision centered on the average).
+	 * I expect that people doing the user space apps will feedback
+	 * us on which value we need to put in each driver...
+	 */
 };
 
 /*
diff -u --recursive --new-file v2.4.12/linux/include/net/route.h linux/include/net/route.h
--- v2.4.12/linux/include/net/route.h	Thu Oct 18 13:48:05 2001
+++ linux/include/net/route.h	Thu Oct 18 17:44:34 2001
@@ -37,9 +37,12 @@
 #endif
 
 #define RTO_ONLINK	0x01
-#define RTO_TPROXY	0x80000000
 
 #define RTO_CONN	0
+/* RTO_CONN is not used (being alias for 0), but preserved not to break
+ * some modules referring to it. */
+
+#define RT_CONN_FLAGS(sk)   (RT_TOS(sk->protinfo.af_inet.tos) | sk->localroute)
 
 struct rt_key
 {
diff -u --recursive --new-file v2.4.12/linux/include/pcmcia/cs_types.h linux/include/pcmcia/cs_types.h
--- v2.4.12/linux/include/pcmcia/cs_types.h	Fri Feb 16 16:02:37 2001
+++ linux/include/pcmcia/cs_types.h	Thu Oct 11 09:43:29 2001
@@ -36,8 +36,13 @@
 #include <sys/types.h>
 #endif
 
-typedef u_short	socket_t;
+#ifdef __arm__
+typedef u_int   ioaddr_t;
+#else
 typedef u_short	ioaddr_t;
+#endif
+
+typedef u_short	socket_t;
 typedef u_int	event_t;
 typedef u_char	cisdata_t;
 typedef u_short	page_t;
diff -u --recursive --new-file v2.4.12/linux/include/pcmcia/ss.h linux/include/pcmcia/ss.h
--- v2.4.12/linux/include/pcmcia/ss.h	Fri Feb 16 16:02:37 2001
+++ linux/include/pcmcia/ss.h	Thu Oct 11 09:43:29 2001
@@ -30,6 +30,8 @@
 #ifndef _LINUX_SS_H
 #define _LINUX_SS_H
 
+#include <pcmcia/cs_types.h>
+
 /* Definitions for card status flags for GetStatus */
 #define SS_WRPROT	0x0001
 #define SS_CARDLOCK	0x0002
@@ -52,6 +54,7 @@
     u_int	features;
     u_int	irq_mask;
     u_int	map_size;
+    ioaddr_t	io_offset;
     u_char	pci_irq;
     struct pci_dev *cb_dev;
     struct bus_operations *bus;
@@ -101,7 +104,7 @@
     u_char	map;
     u_char	flags;
     u_short	speed;
-    u_short	start, stop;
+    ioaddr_t	start, stop;
 } pccard_io_map;
 
 typedef struct pccard_mem_map {
diff -u --recursive --new-file v2.4.12/linux/init/main.c linux/init/main.c
--- v2.4.12/linux/init/main.c	Tue Oct  9 17:06:53 2001
+++ linux/init/main.c	Fri Oct 12 10:17:15 2001
@@ -777,8 +777,12 @@
 		int i, pid;
 
 		pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
-		if (pid>0)
-			while (pid != wait(&i));
+		if (pid > 0) {
+			while (pid != wait(&i)) {
+				current->policy |= SCHED_YIELD;
+				schedule();
+			}
+		}
 		if (MAJOR(real_root_dev) != RAMDISK_MAJOR
 		     || MINOR(real_root_dev) != 0) {
 			error = change_root(real_root_dev,"/initrd");
diff -u --recursive --new-file v2.4.12/linux/ipc/shm.c linux/ipc/shm.c
--- v2.4.12/linux/ipc/shm.c	Sun Sep 23 11:41:01 2001
+++ linux/ipc/shm.c	Wed Oct 17 14:16:39 2001
@@ -348,6 +348,7 @@
 
 static void shm_get_stat (unsigned long *rss, unsigned long *swp) 
 {
+	struct shmem_inode_info *info;
 	int i;
 
 	*rss = 0;
@@ -361,10 +362,11 @@
 		if(shp == NULL)
 			continue;
 		inode = shp->shm_file->f_dentry->d_inode;
-		spin_lock (&inode->u.shmem_i.lock);
+		info = SHMEM_I(inode);
+		spin_lock (&info->lock);
 		*rss += inode->i_mapping->nrpages;
-		*swp += inode->u.shmem_i.swapped;
-		spin_unlock (&inode->u.shmem_i.lock);
+		*swp += info->swapped;
+		spin_unlock (&info->lock);
 	}
 }
 
diff -u --recursive --new-file v2.4.12/linux/kernel/context.c linux/kernel/context.c
--- v2.4.12/linux/kernel/context.c	Sat May 19 17:47:55 2001
+++ linux/kernel/context.c	Thu Oct 11 11:17:22 2001
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/unistd.h>
 #include <linux/signal.h>
+#include <linux/completion.h>
 
 static DECLARE_TASK_QUEUE(tq_context);
 static DECLARE_WAIT_QUEUE_HEAD(context_task_wq);
@@ -63,7 +64,7 @@
 	return ret;
 }
 
-static int context_thread(void *dummy)
+static int context_thread(void *startup)
 {
 	struct task_struct *curtask = current;
 	DECLARE_WAITQUEUE(wait, curtask);
@@ -79,6 +80,8 @@
 	recalc_sigpending(curtask);
 	spin_unlock_irq(&curtask->sigmask_lock);
 
+	complete((struct completion *)startup);
+
 	/* Install a handler so SIGCLD is delivered */
 	sa.sa.sa_handler = SIG_IGN;
 	sa.sa.sa_flags = 0;
@@ -150,7 +153,10 @@
 	
 int start_context_thread(void)
 {
-	kernel_thread(context_thread, NULL, CLONE_FS | CLONE_FILES);
+	static struct completion startup __initdata = COMPLETION_INITIALIZER(startup);
+
+	kernel_thread(context_thread, &startup, CLONE_FS | CLONE_FILES);
+	wait_for_completion(&startup);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.12/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.4.12/linux/kernel/ksyms.c	Tue Oct  9 17:06:53 2001
+++ linux/kernel/ksyms.c	Wed Oct 17 14:32:50 2001
@@ -59,7 +59,7 @@
 
 extern void *sys_call_table;
 
-extern int sys_tz;
+extern struct timezone sys_tz;
 extern int request_dma(unsigned int dmanr, char * deviceID);
 extern void free_dma(unsigned int dmanr);
 extern spinlock_t dma_spin_lock;
@@ -223,6 +223,7 @@
 EXPORT_SYMBOL(posix_test_lock);
 EXPORT_SYMBOL(posix_block_lock);
 EXPORT_SYMBOL(posix_unblock_lock);
+EXPORT_SYMBOL(posix_locks_deadlock);
 EXPORT_SYMBOL(locks_mandatory_area);
 EXPORT_SYMBOL(dput);
 EXPORT_SYMBOL(have_submounts);
diff -u --recursive --new-file v2.4.12/linux/kernel/sched.c linux/kernel/sched.c
--- v2.4.12/linux/kernel/sched.c	Tue Oct  9 17:06:53 2001
+++ linux/kernel/sched.c	Wed Oct 17 14:14:37 2001
@@ -1297,6 +1297,7 @@
 
 	current->session = 1;
 	current->pgrp = 1;
+	current->tty = NULL;
 
 	/* Become as one with the init task */
 
diff -u --recursive --new-file v2.4.12/linux/lib/vsprintf.c linux/lib/vsprintf.c
--- v2.4.12/linux/lib/vsprintf.c	Sun Sep 23 11:41:01 2001
+++ linux/lib/vsprintf.c	Thu Oct 11 11:17:22 2001
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
+#include <linux/kernel.h>
 
 #include <asm/div64.h>
 
@@ -519,36 +520,44 @@
 	int num = 0;
 	int qualifier;
 	int base;
-	unsigned int field_width;
+	int field_width = -1;
 	int is_sign = 0;
 
-	for (; *fmt; fmt++) {
+	while(*fmt && *str) {
 		/* skip any white space in format */
+		/* white space in format matchs any amount of
+		 * white space, including none, in the input.
+		 */
 		if (isspace(*fmt)) {
-			continue;
+			while (isspace(*fmt))
+				++fmt;
+			while (isspace(*str))
+				++str;
 		}
 
 		/* anything that is not a conversion must match exactly */
-		if (*fmt != '%') {
+		if (*fmt != '%' && *fmt) {
 			if (*fmt++ != *str++)
-				return num;
+				break;
 			continue;
 		}
+
+		if (!*fmt)
+			break;
 		++fmt;
 		
 		/* skip this conversion.
 		 * advance both strings to next white space
 		 */
 		if (*fmt == '*') {
-			while (!isspace(*fmt))
+			while (!isspace(*fmt) && *fmt)
 				fmt++;
-			while(!isspace(*str))
+			while (!isspace(*str) && *str)
 				str++;
 			continue;
 		}
 
 		/* get field width */
-		field_width = 0xffffffffUL;
 		if (isdigit(*fmt))
 			field_width = skip_atoi(&fmt);
 
@@ -561,25 +570,32 @@
 		base = 10;
 		is_sign = 0;
 
-		switch(*fmt) {
+		if (!*fmt || !*str)
+			break;
+
+		switch(*fmt++) {
 		case 'c':
 		{
 			char *s = (char *) va_arg(args,char*);
+			if (field_width == -1)
+				field_width = 1;
 			do {
 				*s++ = *str++;
-			} while(field_width-- > 0);
+			} while(field_width-- > 0 && *str);
 			num++;
 		}
 		continue;
 		case 's':
 		{
 			char *s = (char *) va_arg(args, char *);
+			if(field_width == -1)
+				field_width = INT_MAX;
 			/* first, skip leading white space in buffer */
 			while (isspace(*str))
 				str++;
 
 			/* now copy until next white space */
-			while (!isspace(*str) && field_width--) {
+			while (*str && !isspace(*str) && field_width--) {
 				*s++ = *str++;
 			}
 			*s = '\0';
@@ -620,6 +636,9 @@
 		 */
 		while (isspace(*str))
 			str++;
+
+		if (!*str || !isdigit(*str))
+			break;
 
 		switch(qualifier) {
 		case 'h':
diff -u --recursive --new-file v2.4.12/linux/mm/filemap.c linux/mm/filemap.c
--- v2.4.12/linux/mm/filemap.c	Tue Oct  9 17:06:53 2001
+++ linux/mm/filemap.c	Wed Oct 17 10:21:37 2001
@@ -667,8 +667,7 @@
 static int FASTCALL(page_cache_read(struct file * file, unsigned long offset));
 static int page_cache_read(struct file * file, unsigned long offset)
 {
-	struct inode *inode = file->f_dentry->d_inode;
-	struct address_space *mapping = inode->i_mapping;
+	struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
 	struct page **hash = page_hash(mapping, offset);
 	struct page *page; 
 
@@ -1521,6 +1520,53 @@
 	return retval;
 }
 
+static ssize_t do_readahead(struct file *file, unsigned long index, unsigned long nr)
+{
+	struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
+	unsigned long max;
+
+	if (!mapping || !mapping->a_ops || !mapping->a_ops->readpage)
+		return -EINVAL;
+
+	/* Limit it to the size of the file.. */
+	max = (mapping->host->i_size + ~PAGE_CACHE_MASK) >> PAGE_CACHE_SHIFT;
+	if (index > max)
+		return 0;
+	max -= index;
+	if (nr > max)
+		nr = max;
+
+	/* And limit it to a sane percentage of the inactive list.. */
+	max = nr_inactive_pages / 2;
+	if (nr > max)
+		nr = max;
+
+	while (nr) {
+		page_cache_read(file, index);
+		index++;
+		nr--;
+	}
+	return 0;
+}
+
+asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count)
+{
+	ssize_t ret;
+	struct file *file;
+
+	ret = -EBADF;
+	file = fget(fd);
+	if (file) {
+		if (file->f_mode & FMODE_READ) {
+			unsigned long start = offset >> PAGE_CACHE_SHIFT;
+			unsigned long len = (count + ((long)offset & ~PAGE_CACHE_MASK)) >> PAGE_CACHE_SHIFT;
+			ret = do_readahead(file, start, len);
+		}
+		fput(file);
+	}
+	return ret;
+}
+
 /*
  * Read-ahead and flush behind for MADV_SEQUENTIAL areas.  Since we are
  * sure this is sequential access, we don't need a flexible read-ahead
@@ -1589,12 +1635,13 @@
 {
 	int error;
 	struct file *file = area->vm_file;
-	struct inode *inode = file->f_dentry->d_inode;
-	struct address_space *mapping = inode->i_mapping;
+	struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
+	struct inode *inode = mapping->host;
 	struct page *page, **hash, *old_page;
-	unsigned long size, pgoff;
+	unsigned long size, pgoff, endoff;
 
 	pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
+	endoff = ((area->vm_end - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
 
 retry_all:
 	/*
@@ -1605,6 +1652,10 @@
 	if ((pgoff >= size) && (area->vm_mm == current->mm))
 		return NULL;
 
+	/* The "size" of the file, as far as mmap is concerned, isn't bigger than the mapping */
+	if (size > endoff)
+		size = endoff;
+
 	/*
 	 * Do we have something in the page cache already?
 	 */
@@ -1851,15 +1902,14 @@
 
 int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
 {
-	struct inode *inode = file->f_dentry->d_inode;
+	struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
+	struct inode *inode = mapping->host;
 
 	if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) {
-		if (!inode->i_mapping->a_ops->writepage)
+		if (!mapping->a_ops->writepage)
 			return -EINVAL;
 	}
-	if (!inode->i_sb || !S_ISREG(inode->i_mode))
-		return -EACCES;
-	if (!inode->i_mapping->a_ops->readpage)
+	if (!mapping->a_ops->readpage)
 		return -ENOEXEC;
 	UPDATE_ATIME(inode);
 	vma->vm_ops = &generic_file_vm_ops;
@@ -2309,7 +2359,7 @@
 	unsigned long pgoff)
 {
 	unsigned char present = 0;
-	struct address_space * as = &vma->vm_file->f_dentry->d_inode->i_data;
+	struct address_space * as = vma->vm_file->f_dentry->d_inode->i_mapping;
 	struct page * page, ** hash = page_hash(as, pgoff);
 
 	spin_lock(&pagecache_lock);
diff -u --recursive --new-file v2.4.12/linux/mm/memory.c linux/mm/memory.c
--- v2.4.12/linux/mm/memory.c	Tue Oct  9 17:06:53 2001
+++ linux/mm/memory.c	Mon Oct 15 12:09:50 2001
@@ -1122,10 +1122,8 @@
 	spin_unlock(&mm->page_table_lock);
 	page = lookup_swap_cache(entry);
 	if (!page) {
-		lock_kernel();
 		swapin_readahead(entry);
 		page = read_swap_cache_async(entry);
-		unlock_kernel();
 		if (!page) {
 			spin_lock(&mm->page_table_lock);
 			/*
diff -u --recursive --new-file v2.4.12/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.4.12/linux/mm/page_alloc.c	Tue Oct  9 17:06:53 2001
+++ linux/mm/page_alloc.c	Thu Oct 18 12:47:09 2001
@@ -242,7 +242,7 @@
 	current->allocation_order = order;
 	current->flags |= PF_MEMALLOC | PF_FREE_PAGES;
 
-	__freed = try_to_free_pages(classzone, gfp_mask, order);
+	__freed = try_to_free_pages(gfp_mask, order);
 
 	current->flags &= ~(PF_MEMALLOC | PF_FREE_PAGES);
 
@@ -394,7 +394,7 @@
 	}
 
 	/* Don't let big-order allocations loop */
-	if (order)
+	if (order > 1)
 		return NULL;
 
 	/* Yield for kswapd, and try again */
diff -u --recursive --new-file v2.4.12/linux/mm/shmem.c linux/mm/shmem.c
--- v2.4.12/linux/mm/shmem.c	Thu Oct 11 08:02:26 2001
+++ linux/mm/shmem.c	Wed Oct 17 14:19:20 2001
@@ -386,10 +386,10 @@
 	spin_unlock (&info->lock);
 	return 0;
 found:
+	delete_from_swap_cache(page);
 	add_to_page_cache(page, info->inode->i_mapping, offset + idx);
 	SetPageDirty(page);
 	SetPageUptodate(page);
-	UnlockPage(page);
 	info->swapped--;
 	spin_unlock(&info->lock);
 	return 1;
@@ -531,10 +531,8 @@
 		if (!page) {
 			swp_entry_t swap = *entry;
 			spin_unlock (&info->lock);
-			lock_kernel();
 			swapin_readahead(*entry);
 			page = read_swap_cache_async(*entry);
-			unlock_kernel();
 			if (!page) {
 				if (entry->val != swap.val)
 					goto repeat;
@@ -1237,45 +1235,54 @@
 
 static int shmem_parse_options(char *options, int *mode, unsigned long * blocks, unsigned long *inodes)
 {
-	char *this_char, *value;
+	char *this_char, *value, *rest;
 
 	this_char = NULL;
 	if ( options )
 		this_char = strtok(options,",");
 	for ( ; this_char; this_char = strtok(NULL,",")) {
-		if ((value = strchr(this_char,'=')) != NULL)
+		if ((value = strchr(this_char,'=')) != NULL) {
 			*value++ = 0;
+		} else {
+			printk(KERN_ERR 
+			    "shmem_parse_options: No value for option '%s'\n", 
+			    this_char);
+			return 1;
+		}
+
 		if (!strcmp(this_char,"size")) {
 			unsigned long long size;
-			if (!value || !*value || !blocks)
-				return 1;
-			size = memparse(value,&value);
-			if (*value)
-				return 1;
+			size = memparse(value,&rest);
+			if (*rest)
+				goto bad_val;
 			*blocks = size >> PAGE_CACHE_SHIFT;
 		} else if (!strcmp(this_char,"nr_blocks")) {
-			if (!value || !*value || !blocks)
-				return 1;
-			*blocks = memparse(value,&value);
-			if (*value)
-				return 1;
+			*blocks = memparse(value,&rest);
+			if (*rest)
+				goto bad_val;
 		} else if (!strcmp(this_char,"nr_inodes")) {
-			if (!value || !*value || !inodes)
-				return 1;
-			*inodes = memparse(value,&value);
-			if (*value)
-				return 1;
+			*inodes = memparse(value,&rest);
+			if (*rest)
+				goto bad_val;
 		} else if (!strcmp(this_char,"mode")) {
-			if (!value || !*value || !mode)
-				return 1;
-			*mode = simple_strtoul(value,&value,8);
-			if (*value)
-				return 1;
-		}
-		else
+			if (!mode)
+				continue;
+			*mode = simple_strtoul(value,&rest,8);
+			if (*rest)
+				goto bad_val;
+		} else {
+			printk(KERN_ERR "shmem_parse_options: Bad option %s\n",
+			       this_char);
 			return 1;
+		}
 	}
 	return 0;
+
+bad_val:
+	printk(KERN_ERR "shmem_parse_options: Bad value '%s' for option '%s'\n", 
+	       value, this_char);
+	return 1;
+
 }
 
 static int shmem_remount_fs (struct super_block *sb, int *flags, char *data)
diff -u --recursive --new-file v2.4.12/linux/mm/swap.c linux/mm/swap.c
--- v2.4.12/linux/mm/swap.c	Sun Sep 23 11:41:01 2001
+++ linux/mm/swap.c	Wed Oct 17 09:47:36 2001
@@ -130,11 +130,15 @@
  */
 void __init swap_setup(void)
 {
-	/* Use a smaller cluster for memory <16MB or <32MB */
-	if (num_physpages < ((16 * 1024 * 1024) >> PAGE_SHIFT))
+	unsigned long megs = num_physpages >> (20 - PAGE_SHIFT);
+
+	/* Use a smaller cluster for small-memory machines */
+	if (megs < 16)
 		page_cluster = 2;
-	else if (num_physpages < ((32 * 1024 * 1024) >> PAGE_SHIFT))
-		page_cluster = 3;
 	else
-		page_cluster = 4;
+		page_cluster = 3;
+	/*
+	 * Right now other parts of the system means that we
+	 * _really_ don't want to cluster much more
+	 */
 }
diff -u --recursive --new-file v2.4.12/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.4.12/linux/mm/swapfile.c	Tue Oct  9 17:06:53 2001
+++ linux/mm/swapfile.c	Mon Oct 15 12:09:50 2001
@@ -209,7 +209,7 @@
  * share this swap entry, so be cautious and let do_wp_page work out
  * what to do if a write is requested later.
  */
-/* BKL, mmlist_lock and vma->vm_mm->page_table_lock are held */
+/* mmlist_lock and vma->vm_mm->page_table_lock are held */
 static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address,
 	pte_t *dir, swp_entry_t entry, struct page* page)
 {
@@ -225,7 +225,7 @@
 	++vma->vm_mm->rss;
 }
 
-/* BKL, mmlist_lock and vma->vm_mm->page_table_lock are held */
+/* mmlist_lock and vma->vm_mm->page_table_lock are held */
 static inline void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir,
 	unsigned long address, unsigned long size, unsigned long offset,
 	swp_entry_t entry, struct page* page)
@@ -253,7 +253,7 @@
 	} while (address && (address < end));
 }
 
-/* BKL, mmlist_lock and vma->vm_mm->page_table_lock are held */
+/* mmlist_lock and vma->vm_mm->page_table_lock are held */
 static inline void unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,
 	unsigned long address, unsigned long size,
 	swp_entry_t entry, struct page* page)
@@ -284,7 +284,7 @@
 	} while (address && (address < end));
 }
 
-/* BKL, mmlist_lock and vma->vm_mm->page_table_lock are held */
+/* mmlist_lock and vma->vm_mm->page_table_lock are held */
 static void unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
 			swp_entry_t entry, struct page* page)
 {
@@ -424,10 +424,6 @@
 
 		/*
 		 * Don't hold on to start_mm if it looks like exiting.
-		 * Can mmput ever block? if so, then we cannot risk
-		 * it between deleting the page from the swap cache,
-		 * and completing the search through mms (and cannot
-		 * use it to avoid the long hold on mmlist_lock there).
 		 */
 		if (atomic_read(&start_mm->mm_users) == 1) {
 			mmput(start_mm);
@@ -436,18 +432,15 @@
 		}
 
 		/*
-		 * Wait for and lock page.  Remove it from swap cache
-		 * so try_to_swap_out won't bump swap count.  Mark dirty
-		 * so try_to_swap_out will preserve it without us having
-		 * to mark any present ptes as dirty: so we can skip
-		 * searching processes once swap count has all gone.
+		 * Wait for and lock page.  When do_swap_page races with
+		 * try_to_unuse, do_swap_page can handle the fault much
+		 * faster than try_to_unuse can locate the entry.  This
+		 * apparently redundant "wait_on_page" lets try_to_unuse
+		 * defer to do_swap_page in such a case - in some tests,
+		 * do_swap_page and try_to_unuse repeatedly compete.
 		 */
+		wait_on_page(page);
 		lock_page(page);
-		if (PageSwapCache(page))
-			delete_from_swap_cache(page);
-		SetPageDirty(page);
-		UnlockPage(page);
-		flush_page_to_ram(page);
 
 		/*
 		 * Remove all references to entry, without blocking.
@@ -455,20 +448,22 @@
 		 * to search, but use it as a reminder to search shmem.
 		 */
 		swcount = *swap_map;
-		if (swcount) {
+		if (swcount > 1) {
+			flush_page_to_ram(page);
 			if (start_mm == &init_mm)
 				shmem_unuse(entry, page);
 			else
 				unuse_process(start_mm, entry, page);
 		}
-		if (*swap_map) {
+		if (*swap_map > 1) {
 			int set_start_mm = (*swap_map >= swcount);
 			struct list_head *p = &start_mm->mmlist;
 			struct mm_struct *new_start_mm = start_mm;
 			struct mm_struct *mm;
 
 			spin_lock(&mmlist_lock);
-			while (*swap_map && (p = p->next) != &start_mm->mmlist) {
+			while (*swap_map > 1 &&
+					(p = p->next) != &start_mm->mmlist) {
 				mm = list_entry(p, struct mm_struct, mmlist);
 				swcount = *swap_map;
 				if (mm == &init_mm) {
@@ -486,7 +481,6 @@
 			mmput(start_mm);
 			start_mm = new_start_mm;
 		}
-		page_cache_release(page);
 
 		/*
 		 * How could swap count reach 0x7fff when the maximum
@@ -505,23 +499,52 @@
 			swap_list_lock();
 			swap_device_lock(si);
 			nr_swap_pages++;
-			*swap_map = 0;
+			*swap_map = 1;
 			swap_device_unlock(si);
 			swap_list_unlock();
 			reset_overflow = 1;
 		}
 
 		/*
+		 * If a reference remains (rare), we would like to leave
+		 * the page in the swap cache; but try_to_swap_out could
+		 * then re-duplicate the entry once we drop page lock,
+		 * so we might loop indefinitely; also, that page could
+		 * not be swapped out to other storage meanwhile.  So:
+		 * delete from cache even if there's another reference,
+		 * after ensuring that the data has been saved to disk -
+		 * since if the reference remains (rarer), it will be
+		 * read from disk into another page.  Splitting into two
+		 * pages would be incorrect if swap supported "shared
+		 * private" pages, but they are handled by tmpfs files.
+		 * Note shmem_unuse already deleted its from swap cache.
+		 */
+		swcount = *swap_map;
+		if ((swcount > 0) != PageSwapCache(page))
+			BUG();
+		if ((swcount > 1) && PageDirty(page)) {
+			rw_swap_page(WRITE, page);
+			lock_page(page);
+		}
+		if (PageSwapCache(page))
+			delete_from_swap_cache(page);
+
+		/*
+		 * So we could skip searching mms once swap count went
+		 * to 1, we did not mark any present ptes as dirty: must
+		 * mark page dirty so try_to_swap_out will preserve it.
+		 */
+		SetPageDirty(page);
+		UnlockPage(page);
+		page_cache_release(page);
+
+		/*
 		 * Make sure that we aren't completely killing
 		 * interactive performance.  Interruptible check on
 		 * signal_pending() would be nice, but changes the spec?
 		 */
 		if (current->need_resched)
 			schedule();
-		else {
-			unlock_kernel();
-			lock_kernel();
-		}
 	}
 
 	mmput(start_mm);
@@ -577,7 +600,9 @@
 	total_swap_pages -= p->pages;
 	p->flags = SWP_USED;
 	swap_list_unlock();
+	unlock_kernel();
 	err = try_to_unuse(type);
+	lock_kernel();
 	if (err) {
 		/* re-insert swap space back into swap_list */
 		swap_list_lock();
diff -u --recursive --new-file v2.4.12/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.4.12/linux/mm/vmscan.c	Tue Oct  9 17:06:53 2001
+++ linux/mm/vmscan.c	Thu Oct 18 17:41:41 2001
@@ -33,6 +33,8 @@
  */
 #define DEF_PRIORITY (6)
 
+#define page_zone_plenty(page) ((page)->zone->free_pages > (page)->zone->pages_high)
+
 /*
  * The swap-out function returns 1 if it successfully
  * scanned all the pages it was asked to (`count').
@@ -43,11 +45,10 @@
  */
 
 /* mm->page_table_lock is held. mmap_sem is not held */
-static inline int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, struct page *page, zone_t * classzone)
+static inline int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, struct page *page)
 {
 	pte_t pte;
 	swp_entry_t entry;
-	int right_classzone;
 
 	/* Don't look at this pte if it's been accessed recently. */
 	if (ptep_test_and_clear_young(page_table)) {
@@ -55,12 +56,12 @@
 		return 0;
 	}
 
-	if (TryLockPage(page))
+	/* Don't bother replenishing zones that have tons of memory */
+	if (page_zone_plenty(page))
 		return 0;
 
-	right_classzone = 1;
-	if (!memclass(page->zone, classzone))
-		right_classzone = 0;
+	if (TryLockPage(page))
+		return 0;
 
 	/* From this point on, the odds are that we're going to
 	 * nuke this pte, so read and clear the pte.  This hook
@@ -89,7 +90,7 @@
 		{
 			int freeable = page_count(page) - !!page->buffers <= 2;
 			page_cache_release(page);
-			return freeable & right_classzone;
+			return freeable;
 		}
 	}
 
@@ -145,7 +146,7 @@
 }
 
 /* mm->page_table_lock is held. mmap_sem is not held */
-static inline int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int count, zone_t * classzone)
+static inline int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int count)
 {
 	pte_t * pte;
 	unsigned long pmd_end;
@@ -169,7 +170,7 @@
 			struct page *page = pte_page(*pte);
 
 			if (VALID_PAGE(page) && !PageReserved(page)) {
-				count -= try_to_swap_out(mm, vma, address, pte, page, classzone);
+				count -= try_to_swap_out(mm, vma, address, pte, page);
 				if (!count) {
 					address += PAGE_SIZE;
 					break;
@@ -184,7 +185,7 @@
 }
 
 /* mm->page_table_lock is held. mmap_sem is not held */
-static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int count, zone_t * classzone)
+static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int count)
 {
 	pmd_t * pmd;
 	unsigned long pgd_end;
@@ -204,7 +205,7 @@
 		end = pgd_end;
 	
 	do {
-		count = swap_out_pmd(mm, vma, pmd, address, end, count, classzone);
+		count = swap_out_pmd(mm, vma, pmd, address, end, count);
 		if (!count)
 			break;
 		address = (address + PMD_SIZE) & PMD_MASK;
@@ -214,7 +215,7 @@
 }
 
 /* mm->page_table_lock is held. mmap_sem is not held */
-static inline int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int count, zone_t * classzone)
+static inline int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int count)
 {
 	pgd_t *pgdir;
 	unsigned long end;
@@ -229,7 +230,7 @@
 	if (address >= end)
 		BUG();
 	do {
-		count = swap_out_pgd(mm, vma, pgdir, address, end, count, classzone);
+		count = swap_out_pgd(mm, vma, pgdir, address, end, count);
 		if (!count)
 			break;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
@@ -244,7 +245,7 @@
 /*
  * Returns remaining count of pages to be swapped out by followup call.
  */
-static inline int swap_out_mm(struct mm_struct * mm, int count, int * mmcounter, zone_t * classzone)
+static inline int swap_out_mm(struct mm_struct * mm, int count, int * mmcounter)
 {
 	unsigned long address;
 	struct vm_area_struct* vma;
@@ -266,7 +267,7 @@
 			address = vma->vm_start;
 
 		for (;;) {
-			count = swap_out_vma(mm, vma, address, count, classzone);
+			count = swap_out_vma(mm, vma, address, count);
 			vma = vma->vm_next;
 			if (!vma)
 				break;
@@ -283,8 +284,8 @@
 	return count;
 }
 
-static int FASTCALL(swap_out(unsigned int priority, zone_t * classzone, unsigned int gfp_mask, int nr_pages));
-static int swap_out(unsigned int priority, zone_t * classzone, unsigned int gfp_mask, int nr_pages)
+static int FASTCALL(swap_out(unsigned int priority, unsigned int gfp_mask, int nr_pages));
+static int swap_out(unsigned int priority, unsigned int gfp_mask, int nr_pages)
 {
 	int counter;
 	struct mm_struct *mm;
@@ -311,7 +312,7 @@
 		atomic_inc(&mm->mm_users);
 		spin_unlock(&mmlist_lock);
 
-		nr_pages = swap_out_mm(mm, nr_pages, &counter, classzone);
+		nr_pages = swap_out_mm(mm, nr_pages, &counter);
 
 		mmput(mm);
 
@@ -326,8 +327,8 @@
 	return 0;
 }
 
-static int FASTCALL(shrink_cache(int nr_pages, int max_scan, zone_t * classzone, unsigned int gfp_mask));
-static int shrink_cache(int nr_pages, int max_scan, zone_t * classzone, unsigned int gfp_mask)
+static int FASTCALL(shrink_cache(int nr_pages, int max_scan, unsigned int gfp_mask));
+static int shrink_cache(int nr_pages, int max_scan, unsigned int gfp_mask)
 {
 	struct list_head * entry;
 
@@ -345,7 +346,7 @@
 
 		page = list_entry(entry, struct page, lru);
 
-		if (unlikely(!PageInactive(page) && !PageActive(page)))
+		if (unlikely(!PageInactive(page)))
 			BUG();
 
 		list_del(entry);
@@ -354,8 +355,7 @@
 			continue;
 
 		max_scan--;
-
-		if (unlikely(!memclass(page->zone, classzone)))
+		if (unlikely(page_zone_plenty(page)))
 			continue;
 
 		/* Racy check to avoid trylocking when not worthwhile */
@@ -369,7 +369,7 @@
 		if (unlikely(TryLockPage(page)))
 			continue;
 
-		if (PageDirty(page) && is_page_cache_freeable(page)) {
+		if (PageDirty(page) && is_page_cache_freeable(page) && page->mapping) {
 			/*
 			 * It is not critical here to write it only if
 			 * the page is unmapped beause any direct writer
@@ -522,8 +522,8 @@
 	spin_unlock(&pagemap_lru_lock);
 }
 
-static int FASTCALL(shrink_caches(int priority, zone_t * classzone, unsigned int gfp_mask, int nr_pages));
-static int shrink_caches(int priority, zone_t * classzone, unsigned int gfp_mask, int nr_pages)
+static int FASTCALL(shrink_caches(int priority, unsigned int gfp_mask, int nr_pages));
+static int shrink_caches(int priority, unsigned int gfp_mask, int nr_pages)
 {
 	int max_scan;
 	int chunk_size = nr_pages;
@@ -537,9 +537,9 @@
 	/* try to keep the active list 2/3 of the size of the cache */
 	ratio = (unsigned long) nr_pages * nr_active_pages / ((nr_inactive_pages + 1) * 2);
 	refill_inactive(ratio);
-  
+
 	max_scan = nr_inactive_pages / priority;
-	nr_pages = shrink_cache(nr_pages, max_scan, classzone, gfp_mask);
+	nr_pages = shrink_cache(nr_pages, max_scan, gfp_mask);
 	if (nr_pages <= 0)
 		return 0;
 
@@ -552,18 +552,18 @@
 	return nr_pages;
 }
 
-int try_to_free_pages(zone_t * classzone, unsigned int gfp_mask, unsigned int order)
+int try_to_free_pages(unsigned int gfp_mask, unsigned int order)
 {
 	int ret = 0;
 	int priority = DEF_PRIORITY;
 	int nr_pages = SWAP_CLUSTER_MAX;
 
 	do {
-		nr_pages = shrink_caches(priority, classzone, gfp_mask, nr_pages);
+		nr_pages = shrink_caches(priority, gfp_mask, nr_pages);
 		if (nr_pages <= 0)
 			return 1;
 
-		ret |= swap_out(priority, classzone, gfp_mask, SWAP_CLUSTER_MAX << 2);
+		ret |= swap_out(priority, gfp_mask, SWAP_CLUSTER_MAX << 2);
 	} while (--priority);
 
 	return ret;
@@ -595,7 +595,7 @@
 			schedule();
 		if (!zone->need_balance)
 			continue;
-		if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) {
+		if (!try_to_free_pages(GFP_KSWAPD, 0)) {
 			zone->need_balance = 0;
 			__set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(HZ);
diff -u --recursive --new-file v2.4.12/linux/net/ax25/ax25_ip.c linux/net/ax25/ax25_ip.c
--- v2.4.12/linux/net/ax25/ax25_ip.c	Tue Jul  3 17:08:22 2001
+++ linux/net/ax25/ax25_ip.c	Fri Oct 12 14:22:49 2001
@@ -56,9 +56,14 @@
 
 int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
 {
-  	/* header is an AX.25 UI frame from us to them */
- 	unsigned char *buff = skb_push(skb, AX25_HEADER_LEN);
+	unsigned char *buff;
+
+	/* they sometimes come back to us... */
+	if (type == ETH_P_AX25)
+		return 0;
 
+  	/* header is an AX.25 UI frame from us to them */
+ 	buff = skb_push(skb, AX25_HEADER_LEN);
   	*buff++ = 0x00;	/* KISS DATA */
 
 	if (daddr != NULL)
@@ -90,7 +95,7 @@
   			*buff++ = AX25_P_ARP;
   			break;
   		default:
-  			printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%x2.2\n", type);
+  			printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type);
   			*buff++ = 0;
   			break;
  	}
diff -u --recursive --new-file v2.4.12/linux/net/bridge/br.c linux/net/bridge/br.c
--- v2.4.12/linux/net/bridge/br.c	Tue Oct  9 17:06:53 2001
+++ linux/net/bridge/br.c	Wed Oct 17 14:16:39 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br.c,v 1.45 2000/10/22 18:26:07 davem Exp $
+ *	$Id: br.c,v 1.46 2001/10/02 02:22:36 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
diff -u --recursive --new-file v2.4.12/linux/net/core/dev.c linux/net/core/dev.c
--- v2.4.12/linux/net/core/dev.c	Tue Oct  9 17:06:53 2001
+++ linux/net/core/dev.c	Fri Oct 12 14:21:18 2001
@@ -1804,7 +1804,7 @@
 
 	if (stats != (struct iw_statistics *) NULL) {
 		size = sprintf(buffer,
-			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d\n",
+			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d %6d %6d   %6d\n",
 			       dev->name,
 			       stats->status,
 			       stats->qual.qual,
@@ -1815,7 +1815,10 @@
 			       stats->qual.updated & 4 ? '.' : ' ',
 			       stats->discard.nwid,
 			       stats->discard.code,
-			       stats->discard.misc);
+			       stats->discard.fragment,
+			       stats->discard.retries,
+			       stats->discard.misc,
+			       stats->miss.beacon);
 		stats->qual.updated = 0;
 	}
 	else
@@ -1839,8 +1842,8 @@
 	struct net_device *	dev;
 
 	size = sprintf(buffer,
-		       "Inter-| sta-|   Quality        |   Discarded packets\n"
-		       " face | tus | link level noise |  nwid  crypt   misc\n"
+		       "Inter-| sta-|   Quality        |   Discarded packets               | Missed\n"
+		       " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon\n"
 			);
 	
 	pos += size;
@@ -1871,6 +1874,33 @@
 	return len;
 }
 #endif	/* CONFIG_PROC_FS */
+
+/*
+ *	Allow programatic access to /proc/net/wireless even if /proc
+ *	doesn't exist... Also more efficient...
+ */
+static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
+{
+	/* Get stats from the driver */
+	struct iw_statistics *stats = (dev->get_wireless_stats ?
+				       dev->get_wireless_stats(dev) :
+				       (struct iw_statistics *) NULL);
+
+	if (stats != (struct iw_statistics *) NULL) {
+		struct iwreq *	wrq = (struct iwreq *)ifr;
+
+		/* Copy statistics to the user buffer */
+		if(copy_to_user(wrq->u.data.pointer, stats,
+				sizeof(struct iw_statistics)))
+			return -EFAULT;
+
+		/* Check if we need to clear the update flag */
+		if(wrq->u.data.flags != 0)
+			stats->qual.updated = 0;
+		return(0);
+	} else
+		return -EOPNOTSUPP;
+}
 #endif	/* WIRELESS_EXT */
 
 /**
@@ -2169,6 +2199,11 @@
 			dev->name[IFNAMSIZ-1] = 0;
 			notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
 			return 0;
+
+#ifdef WIRELESS_EXT
+		case SIOCGIWSTATS:
+			return dev_iwstats(dev, ifr);
+#endif	/* WIRELESS_EXT */
 
 		/*
 		 *	Unknown or private ioctl
diff -u --recursive --new-file v2.4.12/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.4.12/linux/net/ipv4/ip_output.c	Sun Sep 23 11:41:01 2001
+++ linux/net/ipv4/ip_output.c	Wed Oct 17 14:16:39 2001
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) output module.
  *
- * Version:	$Id: ip_output.c,v 1.98 2001/09/01 00:31:50 davem Exp $
+ * Version:	$Id: ip_output.c,v 1.99 2001/10/15 12:34:50 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -367,7 +367,7 @@
 		 * out.
 		 */
 		if (ip_route_output(&rt, daddr, sk->saddr,
-				    RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute,
+				    RT_CONN_FLAGS(sk),
 				    sk->bound_dev_if))
 			goto no_route;
 		__sk_dst_set(sk, &rt->u.dst);
diff -u --recursive --new-file v2.4.12/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.4.12/linux/net/ipv4/ipconfig.c	Tue Oct  9 17:06:53 2001
+++ linux/net/ipv4/ipconfig.c	Wed Oct 17 14:16:39 2001
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.38 2001/09/25 23:23:07 davem Exp $
+ *  $Id: ipconfig.c,v 1.39 2001/10/13 01:47:31 davem Exp $
  *
  *  Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or
  *  user-supplied information to configure own IP address and routes.
@@ -95,7 +95,7 @@
  */
 
 /* This is used by platforms which might be able to set the ipconfig
- * variabled using firmware environment vars.  If this is set, it will
+ * variables using firmware environment vars.  If this is set, it will
  * ignore such firmware variables.
  */
 int ic_set_manually __initdata = 0;		/* IPconfig parameters set manually */
diff -u --recursive --new-file v2.4.12/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c
--- v2.4.12/linux/net/ipv4/ipip.c	Tue Oct  9 17:06:53 2001
+++ linux/net/ipv4/ipip.c	Wed Oct 17 14:16:39 2001
@@ -1,7 +1,7 @@
 /*
  *	Linux NET3:	IP/IP protocol decoder. 
  *
- *	Version: $Id: ipip.c,v 1.49 2001/09/25 22:35:47 davem Exp $
+ *	Version: $Id: ipip.c,v 1.50 2001/10/02 02:22:36 davem Exp $
  *
  *	Authors:
  *		Sam Lantinga (slouken@cs.ucdavis.edu)  02/01/95
diff -u --recursive --new-file v2.4.12/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.4.12/linux/net/ipv4/route.c	Sun Sep 23 11:41:01 2001
+++ linux/net/ipv4/route.c	Wed Oct 17 14:16:39 2001
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.99 2001/09/18 22:29:09 davem Exp $
+ * Version:	$Id: route.c,v 1.100 2001/10/15 12:34:50 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -2002,9 +2002,7 @@
 		    rth->key.fwmark == key->fwmark &&
 #endif
 		    !((rth->key.tos ^ key->tos) &
-			    (IPTOS_RT_MASK | RTO_ONLINK)) &&
-		    ((key->tos & RTO_TPROXY) ||
-		     !(rth->rt_flags & RTCF_TPROXY))) {
+			    (IPTOS_RT_MASK | RTO_ONLINK))) {
 			rth->u.dst.lastuse = jiffies;
 			dst_hold(&rth->u.dst);
 			rth->u.dst.__use++;
diff -u --recursive --new-file v2.4.12/linux/net/ipv4/syncookies.c linux/net/ipv4/syncookies.c
--- v2.4.12/linux/net/ipv4/syncookies.c	Wed May 16 10:31:27 2001
+++ linux/net/ipv4/syncookies.c	Wed Oct 17 14:16:39 2001
@@ -9,7 +9,7 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  * 
- *  $Id: syncookies.c,v 1.14 2001/05/05 01:01:55 davem Exp $
+ *  $Id: syncookies.c,v 1.15 2001/10/15 12:34:50 davem Exp $
  *
  *  Missing: IPv6 support. 
  */
@@ -178,7 +178,7 @@
 			    opt && 
 			    opt->srr ? opt->faddr : req->af.v4_req.rmt_addr,
 			    req->af.v4_req.loc_addr,
-			    sk->protinfo.af_inet.tos | RTO_CONN,
+			    RT_CONN_FLAGS(sk),
 			    0)) { 
 		tcp_openreq_free(req);
 		goto out; 
diff -u --recursive --new-file v2.4.12/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.4.12/linux/net/ipv4/tcp_ipv4.c	Tue Oct  9 17:06:53 2001
+++ linux/net/ipv4/tcp_ipv4.c	Sun Oct 21 10:36:54 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.231 2001/09/26 23:38:47 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.234 2001/10/18 09:49:08 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -162,6 +162,37 @@
 	local_bh_enable();
 }
 
+static inline void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb, unsigned short snum) 
+{ 
+	sk->num = snum; 
+	if ((sk->bind_next = tb->owners) != NULL)
+		tb->owners->bind_pprev = &sk->bind_next;
+	tb->owners = sk;
+	sk->bind_pprev = &tb->owners;
+	sk->prev = (struct sock *) tb;
+} 
+
+static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
+{ 
+	struct sock *sk2 = tb->owners;
+	int sk_reuse = sk->reuse;
+	
+	for( ; sk2 != NULL; sk2 = sk2->bind_next) {
+		if (sk != sk2 &&
+		    sk->bound_dev_if == sk2->bound_dev_if) {
+			if (!sk_reuse	||
+			    !sk2->reuse	||
+			    sk2->state == TCP_LISTEN) {
+				if (!sk2->rcv_saddr	||
+				    !sk->rcv_saddr	||
+				    (sk2->rcv_saddr == sk->rcv_saddr))
+					break;
+			}
+		}
+	}
+	return sk2 != NULL; 
+} 
+
 /* Obtain a reference to a local port for the given sock,
  * if snum is zero it means select any available local port.
  */
@@ -216,26 +247,9 @@
 		if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
 			goto success;
 		} else {
-			struct sock *sk2 = tb->owners;
-			int sk_reuse = sk->reuse;
-
-			for( ; sk2 != NULL; sk2 = sk2->bind_next) {
-				if (sk != sk2 &&
-				    sk->bound_dev_if == sk2->bound_dev_if) {
-					if (!sk_reuse	||
-					    !sk2->reuse	||
-					    sk2->state == TCP_LISTEN) {
-						if (!sk2->rcv_saddr	||
-						    !sk->rcv_saddr	||
-						    (sk2->rcv_saddr == sk->rcv_saddr))
-							break;
-					}
-				}
-			}
-			/* If we found a conflict, fail. */
-			ret = 1;
-			if (sk2 != NULL)
-				goto fail_unlock;
+			ret = 1; 
+			if (tcp_bind_conflict(sk, tb))
+				goto fail_unlock; 
 		}
 	}
 	ret = 1;
@@ -251,17 +265,10 @@
 		   ((sk->reuse == 0) || (sk->state == TCP_LISTEN)))
 		tb->fastreuse = 0;
 success:
-	sk->num = snum;
-	if (sk->prev == NULL) {
-		if ((sk->bind_next = tb->owners) != NULL)
-			tb->owners->bind_pprev = &sk->bind_next;
-		tb->owners = sk;
-		sk->bind_pprev = &tb->owners;
-		sk->prev = (struct sock *) tb;
-	} else {
-		BUG_TRAP(sk->prev == (struct sock *) tb);
-	}
-	ret = 0;
+	if (sk->prev == NULL)
+		tcp_bind_hash(sk, tb, snum); 
+	BUG_TRAP(sk->prev == (struct sock *) tb);
+ 	ret = 0;
 
 fail_unlock:
 	spin_unlock(&head->lock);
@@ -660,7 +667,7 @@
 	}
 
 	tmp = ip_route_connect(&rt, nexthop, sk->saddr,
-			       RT_TOS(sk->protinfo.af_inet.tos)|RTO_CONN|sk->localroute, sk->bound_dev_if);
+			       RT_CONN_FLAGS(sk), sk->bound_dev_if);
 	if (tmp < 0)
 		return tmp;
 
@@ -676,7 +683,7 @@
 		daddr = rt->rt_dst;
 
 	err = -ENOBUFS;
-	buff = alloc_skb(MAX_TCP_HEADER + 15, GFP_KERNEL);
+	buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
 
 	if (buff == NULL)
 		goto failure;
@@ -1147,8 +1154,7 @@
 				 opt->faddr :
 				 req->af.v4_req.rmt_addr),
 			   req->af.v4_req.loc_addr,
-			   RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute,
-			   sk->bound_dev_if)) {
+			   RT_CONN_FLAGS(sk), sk->bound_dev_if)) {
 		IP_INC_STATS_BH(IpOutNoRoutes);
 		return NULL;
 	}
@@ -1776,8 +1782,7 @@
 		daddr = sk->protinfo.af_inet.opt->faddr;
 
 	err = ip_route_output(&rt, daddr, sk->saddr,
-			      RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute,
-			      sk->bound_dev_if);
+			      RT_CONN_FLAGS(sk), sk->bound_dev_if);
 	if (!err) {
 		__sk_dst_set(sk, &rt->u.dst);
 		sk->route_caps = rt->u.dst.dev->features;
diff -u --recursive --new-file v2.4.12/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.4.12/linux/net/ipv4/udp.c	Sun Sep 23 11:41:01 2001
+++ linux/net/ipv4/udp.c	Wed Oct 17 14:16:39 2001
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.99 2001/09/01 00:31:50 davem Exp $
+ * Version:	$Id: udp.c,v 1.100 2001/10/15 12:34:50 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -724,7 +724,7 @@
 	sk_dst_reset(sk);
 
 	err = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr,
-			       sk->protinfo.af_inet.tos|sk->localroute, sk->bound_dev_if);
+			       RT_CONN_FLAGS(sk), sk->bound_dev_if);
 	if (err)
 		return err;
 	if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) {
diff -u --recursive --new-file v2.4.12/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.4.12/linux/net/ipv6/af_inet6.c	Tue Oct  9 17:06:53 2001
+++ linux/net/ipv6/af_inet6.c	Wed Oct 17 14:16:39 2001
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/af_inet.c
  *
- *	$Id: af_inet6.c,v 1.64 2001/06/13 16:25:03 davem Exp $
+ *	$Id: af_inet6.c,v 1.65 2001/10/02 02:22:36 davem Exp $
  *
  * 	Fixes:
  *	piggy, Karl Knutson	:	Socket protocol table
diff -u --recursive --new-file v2.4.12/linux/net/ipv6/netfilter/ip6t_mac.c linux/net/ipv6/netfilter/ip6t_mac.c
--- v2.4.12/linux/net/ipv6/netfilter/ip6t_mac.c	Tue Jun 20 14:32:27 2000
+++ linux/net/ipv6/netfilter/ip6t_mac.c	Fri Oct 12 15:30:00 2001
@@ -20,7 +20,7 @@
 
     /* Is mac pointer valid? */
     return (skb->mac.raw >= skb->head
-	    && skb->mac.raw < skb->head + skb->len - ETH_HLEN
+	    && (skb->mac.raw + ETH_HLEN) <= skb->data
 	    /* If so, compare... */
 	    && ((memcmp(skb->mac.ethernet->h_source, info->srcaddr, ETH_ALEN)
 		== 0) ^ info->invert));
diff -u --recursive --new-file v2.4.12/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.4.12/linux/net/ipv6/tcp_ipv6.c	Tue Oct  9 17:06:53 2001
+++ linux/net/ipv6/tcp_ipv6.c	Wed Oct 17 14:16:39 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.139 2001/09/26 23:38:47 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.140 2001/10/15 12:34:50 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -339,13 +339,18 @@
 	return tcp_v6_lookup_listener(daddr, hnum, dif);
 }
 
-#define tcp_v6_lookup(sa, sp, da, dp, dif) \
-({	struct sock *___sk; \
-	local_bh_disable(); \
-	___sk = __tcp_v6_lookup((sa),(sp),(da),ntohs(dp),(dif)); \
-	local_bh_enable(); \
-	___sk; \
-})
+__inline__ struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
+				      struct in6_addr *daddr, u16 dport,
+				      int dif)
+{
+	struct sock *sk;
+
+	local_bh_disable();
+	sk = __tcp_v6_lookup(saddr, sport, daddr, ntohs(dport), dif);
+	local_bh_enable();
+
+	return sk;
+}
 
 
 /*
@@ -656,7 +661,7 @@
 	tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
 
 	err = -ENOBUFS;
-	buff = alloc_skb(MAX_TCP_HEADER + 15, GFP_KERNEL);
+	buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
 
 	if (buff == NULL)
 		goto failure;
diff -u --recursive --new-file v2.4.12/linux/net/socket.c linux/net/socket.c
--- v2.4.12/linux/net/socket.c	Tue Oct  9 17:06:53 2001
+++ linux/net/socket.c	Wed Oct 17 14:38:28 2001
@@ -440,10 +440,11 @@
 	struct inode * inode;
 	struct socket * sock;
 
-	inode = new_inode(sock_mnt->mnt_sb);
+	inode = get_empty_inode();
 	if (!inode)
 		return NULL;
 
+	inode->i_sb = sock_mnt->mnt_sb;
 	sock = socki_lookup(inode);
 
 	inode->i_mode = S_IFSOCK|S_IRWXUGO;
diff -u --recursive --new-file v2.4.12/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- v2.4.12/linux/net/sunrpc/sched.c	Tue Oct  9 17:06:53 2001
+++ linux/net/sunrpc/sched.c	Thu Oct 11 08:12:52 2001
@@ -30,7 +30,7 @@
 /*
  * We give RPC the same get_free_pages priority as NFS
  */
-#define GFP_RPC			GFP_NFS
+#define GFP_RPC			GFP_NOFS
 
 static void			__rpc_default_timer(struct rpc_task *task);
 static void			rpciod_killall(void);
@@ -744,7 +744,7 @@
  * for readahead):
  *
  *   sync user requests:	GFP_KERNEL
- *   async requests:		GFP_RPC		(== GFP_NFS)
+ *   async requests:		GFP_RPC		(== GFP_NOFS)
  *   swap requests:		GFP_ATOMIC	(or new GFP_SWAPPER)
  */
 void *
@@ -1067,8 +1067,6 @@
 	spin_unlock_irq(&current->sigmask_lock);
 
 	strcpy(current->comm, "rpciod");
-
-	current->flags |= PF_MEMALLOC;
 
 	dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid);
 	while (rpciod_users) {
diff -u --recursive --new-file v2.4.12/linux/net/sunrpc/stats.c linux/net/sunrpc/stats.c
--- v2.4.12/linux/net/sunrpc/stats.c	Tue Dec  7 10:03:12 1999
+++ linux/net/sunrpc/stats.c	Thu Oct 11 11:17:22 2001
@@ -202,3 +202,4 @@
 	rpc_proc_exit();
 }
 #endif
+MODULE_LICENSE("GPL");
