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

diff -urN linux-2.4.5-pre3/CREDITS linux/CREDITS
--- linux-2.4.5-pre3/CREDITS	Mon Dec  3 22:43:49 2001
+++ linux/CREDITS	Mon Dec  3 22:44:22 2001
@@ -221,6 +221,14 @@
 S: 62-300 Wrzesnia
 S: Poland
 
+N: Fred Barnes
+E: frmb2@ukc.ac.uk
+D: Various parport/ppdev hacks and fixes
+S: Computing Lab, The University
+S: Canterbury, KENT
+S: CT2 7NF
+S: England
+
 N: Paul Barton-Davis
 E: pbd@op.net
 D: Driver for WaveFront soundcards (Turtle Beach Maui, Tropez, Tropez+)
@@ -1663,6 +1671,7 @@
 N: Jamie Lokier
 E: jamie@imbolc.ucc.ie
 D: Reboot-through-BIOS for broken 486 motherboards
+D: Some parport fixes
 S: 11 Goodson Walk
 S: Marston
 S: Oxford
@@ -2883,7 +2892,7 @@
 S: USA
 
 N: Tim Waugh
-E: tim@cyberelk.demon.co.uk
+E: tim@cyberelk.net
 D: Co-architect of the parallel-port sharing system
 S: 17 Curling Vale
 S: GUILDFORD
diff -urN linux-2.4.5-pre3/Documentation/Changes linux/Documentation/Changes
--- linux-2.4.5-pre3/Documentation/Changes	Wed Apr 11 19:02:27 2001
+++ linux/Documentation/Changes	Mon Dec  3 22:44:22 2001
@@ -31,7 +31,7 @@
 Eine deutsche Version dieser Datei finden Sie unter
 <http://www.stefan-winter.de/Changes-2.4.0.txt>.
 
-Last updated: April 6, 2001
+Last updated: May 9, 2001
 
 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu).
 
@@ -71,7 +71,7 @@
 information about their gcc version requirements from another source.
 
 The recommended compiler for the kernel is egcs 1.1.2 (gcc 2.91.66), and it
-should be used when you need absolute stability. You may use gcc 2.95.2
+should be used when you need absolute stability. You may use gcc 2.95.x
 instead if you wish, although it may cause problems. Later versions of gcc
 have not received much testing for Linux kernel compilation, and there are
 almost certainly bugs (mainly, but not exclusively, in the kernel) that
@@ -83,9 +83,9 @@
 be compiled with it.
 
 In addition, please pay attention to compiler optimization.  Anything
-greater than -O2 may not be wise.  Similarly, if you choose to use gcc-2.95
+greater than -O2 may not be wise.  Similarly, if you choose to use gcc-2.95.x
 or derivatives, be sure not to use -fstrict-aliasing (which, depending on
-your version of gcc 2.95, may necessitate using -fno-strict-aliasing).
+your version of gcc 2.95.x, may necessitate using -fno-strict-aliasing).
 
 Make
 ----
@@ -268,15 +268,15 @@
 ------------------------
 o  <ftp://sourceware.cygnus.com/pub/gcc/releases/egcs-1.1.2/egcs-1.1.2.tar.bz2>
 
-gcc 2.95.2
+gcc 2.95.3
 ----------
-o  <ftp://ftp.gnu.org/pub/gnu/gcc/gcc-2.95.2.tar.gz>
+o  <ftp://ftp.gnu.org/pub/gnu/gcc/gcc-2.95.3.tar.gz>
 
 Gnu Make
 ********
 
 Make 3.77
---------
+---------
 o  <ftp://ftp.gnu.org/gnu/make/make-3.77.tar.gz>
 
 Binutils
diff -urN linux-2.4.5-pre3/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt
--- linux-2.4.5-pre3/Documentation/DMA-mapping.txt	Thu Apr 19 08:38:48 2001
+++ linux/Documentation/DMA-mapping.txt	Mon Dec  3 22:44:22 2001
@@ -240,6 +240,7 @@
 
 where dev, size are the same as in the above call and cpu_addr and
 dma_handle are the values pci_alloc_consistent returned to you.
+This function may not be called in interrupt context.
 
 If your driver needs lots of smaller memory regions, you can write
 custom code to subdivide pages returned by pci_alloc_consistent,
@@ -262,7 +263,8 @@
 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.
+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:
 
@@ -270,21 +272,23 @@
 
 flags are SLAB_KERNEL if blocking is permitted (not in_interrupt nor
 holding SMP locks), SLAB_ATOMIC otherwise.  Like pci_alloc_consistent,
-this returns two values, cpu_addr and dma_handle,
+this returns two values, cpu_addr and dma_handle.
 
 Free memory that was allocated from a pci_pool like this:
 
 	pci_pool_free(pool, cpu_addr, dma_handle);
 
 where pool is what you passed to pci_pool_alloc, and cpu_addr and
-dma_handle are the values pci_pool_alloc returned.
+dma_handle are the values pci_pool_alloc returned. This function
+may be called in interrupt context.
 
 Destroy a pci_pool by calling:
 
 	pci_pool_destroy(pool);
 
 Make sure you've called pci_pool_free for all memory allocated
-from a pool before you destroy the pool.
+from a pool before you destroy the pool. This function may not
+be called in interrupt context.
 
 			DMA Direction
 
diff -urN linux-2.4.5-pre3/Documentation/DocBook/kernel-hacking.tmpl linux/Documentation/DocBook/kernel-hacking.tmpl
--- linux-2.4.5-pre3/Documentation/DocBook/kernel-hacking.tmpl	Fri Apr  6 10:42:55 2001
+++ linux/Documentation/DocBook/kernel-hacking.tmpl	Mon Dec  3 22:44:22 2001
@@ -713,7 +713,8 @@
    </para>
    <para>
    Static data structures marked as <type>__initdata</type> must be initialised
-   (as opposed to ordinary static data which is zeroed BSS).
+   (as opposed to ordinary static data which is zeroed BSS) and cannot be 
+   <type>const</type>.
    </para> 
 
   </sect1>
diff -urN linux-2.4.5-pre3/Documentation/DocBook/kernel-locking.tmpl linux/Documentation/DocBook/kernel-locking.tmpl
--- linux-2.4.5-pre3/Documentation/DocBook/kernel-locking.tmpl	Fri Apr  6 10:42:55 2001
+++ linux/Documentation/DocBook/kernel-locking.tmpl	Mon Dec  3 22:44:22 2001
@@ -760,8 +760,11 @@
     </para>
 
     <para>
-      Any atomic operation is defined to act as a memory barrier
-      (ie. as per the <function>mb()</function> macro).  Also,
+      Some atomic operations are defined to act as a memory barrier
+      (ie. as per the <function>mb()</function> macro, but if in
+      doubt, be explicit.
+      <!-- Rusty Russell 2 May 2001, 2.4.4 -->
+      Also,
       spinlock operations act as partial barriers: operations after
       gaining a spinlock will never be moved to precede the
       <function>spin_lock()</function> call, and operations before
diff -urN linux-2.4.5-pre3/Documentation/devices.txt linux/Documentation/devices.txt
--- linux-2.4.5-pre3/Documentation/devices.txt	Mon Dec  3 22:43:49 2001
+++ linux/Documentation/devices.txt	Mon Dec  3 22:44:22 2001
@@ -660,6 +660,12 @@
 
  29 char	Universal frame buffer
 		  0 = /dev/fb0		First frame buffer
+		  1 = /dev/fb1		Second frame buffer
+		    ...
+		 31 = /dev/fb31		32nd frame buffer
+
+		Backward compatibility aliases {2.6}
+
 		 32 = /dev/fb1		Second frame buffer
 		    ...
 		224 = /dev/fb7		Eighth frame buffer
diff -urN linux-2.4.5-pre3/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- linux-2.4.5-pre3/Documentation/ioctl-number.txt	Fri Mar  2 17:50:22 2001
+++ linux/Documentation/ioctl-number.txt	Mon Dec  3 22:44:22 2001
@@ -139,7 +139,7 @@
 'p'	00-3F	linux/mc146818rtc.h
 'p'	40-7F	linux/nvram.h
 'p'	80-9F				user-space parport
-					<mailto:tim@cyberelk.demon.co.uk>
+					<mailto:tim@cyberelk.net>
 'q'	00-1F	linux/videotext.h	conflict!
 'q'	80-FF				Internet PhoneJACK, Internet LineJACK
 					<http://www.quicknet.net>
diff -urN linux-2.4.5-pre3/Documentation/parport.txt linux/Documentation/parport.txt
--- linux-2.4.5-pre3/Documentation/parport.txt	Fri Apr  6 10:42:51 2001
+++ linux/Documentation/parport.txt	Mon Dec  3 22:44:22 2001
@@ -261,4 +261,4 @@
     io=0x378 irq=7 dma=3 (for DMA)
 --
 Philip.Blundell@pobox.com
-tim@cyberelk.demon.co.uk
+tim@cyberelk.net
diff -urN linux-2.4.5-pre3/Documentation/pci.txt linux/Documentation/pci.txt
--- linux-2.4.5-pre3/Documentation/pci.txt	Sun Sep 17 09:45:06 2000
+++ linux/Documentation/pci.txt	Mon Dec  3 22:44:22 2001
@@ -60,8 +60,8 @@
 	remove		Pointer to a function which gets called whenever a device
 			being handled by this driver is removed (either during
 			deregistration of the driver or when it's manually pulled
-			out of a hot-pluggable slot). This function can be called
-			from interrupt context.
+			out of a hot-pluggable slot). This function always gets
+			called from process context, so it can sleep.
 	suspend,	Power management hooks -- called when the device goes to
 	resume		sleep or is resumed.
 
diff -urN linux-2.4.5-pre3/Documentation/rtc.txt linux/Documentation/rtc.txt
--- linux-2.4.5-pre3/Documentation/rtc.txt	Thu Jan  4 12:50:17 2001
+++ linux/Documentation/rtc.txt	Mon Dec  3 22:44:22 2001
@@ -89,7 +89,7 @@
 #include <unistd.h>
 #include <errno.h>
 
-void main(void) {
+int main(void) {
 
 int i, fd, retval, irqcount = 0;
 unsigned long tmp, data;
@@ -277,5 +277,6 @@
 								 irqcount);
 
 close(fd);
+return 0;
 
 } /* end main */
diff -urN linux-2.4.5-pre3/Documentation/sound/cs46xx linux/Documentation/sound/cs46xx
--- linux-2.4.5-pre3/Documentation/sound/cs46xx	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/cs46xx	Mon Dec  3 22:44:22 2001
@@ -0,0 +1,138 @@
+
+Documentation for the Cirrus Logic/Crystal SoundFusion cs46xx/cs4280 audio 
+controller chips (2001/05/11)
+
+The cs46xx audio driver supports the DSP line of Cirrus controllers. 
+Specifically, the cs4610, cs4612, cs4614, cs4622, cs4624, cs4630 and the cs4280
+products.  This driver uses the generic ac97_codec driver for AC97 codec
+support.  
+
+
+Features:
+
+Full Duplex Playback/Capture supported from 8k-48k.
+16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported.
+
+APM/PM - 2.2.x PM is enabled and functional. APM can also
+be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro
+definition.
+
+DMA playback buffer size is configurable from 16k (defaultorder=2) up to 2Meg 
+(defaultorder=11).  DMA capture buffer size is fixed at a single 4k page as
+two 2k fragments.
+
+MMAP seems to work well with QuakeIII, and test XMMS plugin.
+
+Myth2 works, but the polling logic is not fully correct, but is functional.
+
+The 2.4.4-ac6 gameport code in the cs461x joystick driver has been tested 
+with a Microsoft Sidewinder joystick (cs461x.o and sidewinder.o).  This 
+audio driver must be loaded prior to the joystick driver to enable the
+DSP task image supporting the joystick device.
+
+
+Limitations:
+
+SPDIF is currently not supported.
+
+Primary codec support only.  No secondary codec support is implemented.
+
+
+
+NOTES:
+
+Hercules Game Theatre XP - the EGPIO2 pin controls the external Amp,
+and has been tested.
+Module parameter hercules_egpio_disable set to 1, will force a 0 to EGPIODR
+to disable the external amplifier.
+
+VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control
+the external amplifier for the "back" speakers, since we do not
+support the secondary codec then this external amp is not
+turned on.  The primary codec external amplifier is supported but
+note that the AC97 EAPD bit is inverted logic (amp_voyetra()).
+
+DMA buffer size - there are issues with many of the Linux applications
+concerning the optimal buffer size.  Several applications request a 
+certain fragment size and number and then do not verify that the driver
+has the ability to support the requested configuration.  
+SNDCTL_DSP_SETFRAGMENT ioctl is used to request a fragment size and
+number of fragments.  Some applications exit if an error is returned
+on this particular ioctl. Therefore, in alignment with the other OSS audio 
+drivers, no error is returned when a SETFRAGs IOCTL is received, but the 
+values passed from the app are not used in any buffer calculation 
+(ossfragshift/ossmaxfrags are not used).
+Use the "defaultorder=N" module parameter to change the buffer size if
+you have an application that requires a specific number of fragments
+or a specific buffer size (see below).
+
+Debug Interface
+---------------
+There is an ioctl debug interface to allow runtime modification of the 
+debug print levels.  This debug interface code can be disabled from the 
+compilation process with commenting the following define:
+#define CSDEBUG_INTERFACE 1
+There is also a debug print methodolgy to select printf statements from
+different areas of the driver.  A debug print level is also used to allow
+additional printfs to be active.  Comment out the following line in the
+driver to disable compilation of the CS_DBGOUT print statements:
+#define CSDEBUG 1
+ 
+Please see the defintions for cs_debuglevel and cs_debugmask for additional
+information on the debug levels and sections.
+
+There is also a csdbg executable to allow runtime manipulation of these 
+parameters.  for a copy email: twoller@crystal.cirrus.com
+
+
+
+MODULE_PARMS definitions
+------------------------
+MODULE_PARM(defaultorder, "i");
+defaultorder=N
+where N is a value from 1 to 12
+The buffer order determines the size of the dma buffer for the driver.
+under Linux, a smaller buffer allows more responsiveness from many of the 
+applications (e.g. games).  A larger buffer allows some of the apps (esound) 
+to not underrun the dma buffer as easily.  As default, use 32k (order=3)
+rather than 64k as some of the games work more responsively.
+(2^N) * PAGE_SIZE = allocated buffer size
+
+MODULE_PARM(cs_debuglevel, "i");
+MODULE_PARM(cs_debugmask, "i");
+cs_debuglevel=N
+cs_debugmask=0xMMMMMMMM
+where N is a value from 0 (no debug printfs), to 9 (maximum)
+0xMMMMMMMM is a debug mask corresponding to the CS_xxx bits (see driver source).
+
+MODULE_PARM(hercules_egpio_disable, "i");
+hercules_egpio_disable=N
+where N is a 0 (enable egpio), or a 1 (disable egpio support)
+
+MODULE_PARM(initdelay, "i");
+initdelay=N
+This value is used to determine the millescond delay during the initialization
+code prior to powering up the PLL.  On laptops this value can be used to
+assist with errors on resume, mostly with IBM laptops.  Basically, if the 
+system is booted under battery power then the mdelay()/udelay() functions fail to 
+properly delay the required time.  Also, if the system is booted under AC power
+and then the power removed, the mdelay()/udelay() functions will not delay properly.
+ 
+MODULE_PARM(powerdown, "i");
+powerdown=N
+where N is 0 (disable any powerdown of the internal blocks) or 1 (enable powerdown)
+
+
+MODULE_PARM(external_amp, "i");
+external_amp=1
+if N is set to 1, then force enabling the EAPD support in the primary AC97 codec.
+override the detection logic and force the external amp bit in the AC97 0x26 register
+to be reset (0).  EAPD should be 0 for powerup, and 1 for powerdown.  The VTB Santa Cruz
+card has inverted logic, so there is a special function for these cards.
+
+MODULE_PARM(thinkpad, "i");
+thinkpad=1
+if N is set to 1, then force enabling the clkrun functionality.
+Currently, when the part is being used, then clkrun is disabled for the entire system,
+but re-enabled when the driver is released or there is no outstanding open count.
+
diff -urN linux-2.4.5-pre3/Documentation/usb/hotplug.txt linux/Documentation/usb/hotplug.txt
--- linux-2.4.5-pre3/Documentation/usb/hotplug.txt	Tue Jan 16 12:02:51 2001
+++ linux/Documentation/usb/hotplug.txt	Mon Dec  3 22:44:22 2001
@@ -69,7 +69,10 @@
 
 If "usbdevfs" is configured, DEVICE and DEVFS are also passed.  DEVICE is
 the pathname of the device, and is useful for devices with multiple and/or
-alternate interfaces that complicate driver selection.
+alternate interfaces that complicate driver selection.  By design, USB
+hotplugging is independent of "usbdevfs":  you can do most essential parts
+of USB device setup without using that filesystem, and without running a
+user mode daemon to detect changes in system configuration.
 
 Currently available policy agent implementations can load drivers for
 modules, and can invoke driver-specific setup scripts.  The newest ones
@@ -85,14 +88,26 @@
 
 See <linux/usb.h> for full information about such table entries; or look
 at existing drivers.  Each table entry describes one or more criteria to
-be used when matching a driver to a device or class of devices.
+be used when matching a driver to a device or class of devices.  The
+specific criteria are identified by bits set in "match_flags", paired
+with field values.  You can construct the criteria directly, or with
+macros such as these, and use driver_info to store more information.
+
+    USB_DEVICE (vendorId, productId)
+	... matching devices with specified vendor and product ids
+    USB_DEVICE_VER (vendorId, productId, lo, hi)
+	... like USB_DEVICE with lo <= productversion <= hi
+    USB_INTERFACE_INFO (class, subclass, protocol)
+	... matching specified interface class info
+    USB_DEVICE_INFO (class, subclass, protocol)
+	... matching specified device class info
 
 A short example, for a driver that supports several specific USB devices
 and their quirks, might have a MODULE_DEVICE_TABLE like this:
 
     static const struct usb_device_id mydriver_id_table = {
-	{ idVendor: 0x9999, idProduct 0xaaaa, driver_info: QUIRK_X },
-	{ idVendor: 0xbbbb, idProduct 0x8888, driver_info: QUIRK_Y|QUIRK_Z },
+	{ USB_DEVICE (0x9999, 0xaaaa), driver_info: QUIRK_X },
+	{ USB_DEVICE (0xbbbb, 0x8888), driver_info: QUIRK_Y|QUIRK_Z },
 	...
 	{ } /* end with an all-zeroes entry */
     }
diff -urN linux-2.4.5-pre3/MAINTAINERS linux/MAINTAINERS
--- linux-2.4.5-pre3/MAINTAINERS	Mon Dec  3 22:43:49 2001
+++ linux/MAINTAINERS	Mon Dec  3 22:44:22 2001
@@ -409,6 +409,12 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
+P:	Tobias Ringstrom
+M:	tori@unhappy.mine.nu
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+
 DOUBLETALK DRIVER
 P:	James R. Van Zandt
 M:	jrv@vanzandt.mv.com
@@ -995,7 +1001,7 @@
 P:	Phil Blundell
 M:	Philip.Blundell@pobox.com
 P:	Tim Waugh
-M:	tim@cyberelk.demon.co.uk
+M:	tim@cyberelk.net
 P:	David Campbell
 M:	campbell@torque.net
 P:	Andrea Arcangeli
@@ -1006,7 +1012,7 @@
 
 PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES
 P:	Tim Waugh
-M:	tim@cyberelk.demon.co.uk
+M:	tim@cyberelk.net
 L:	linux-parport@torque.net
 W:	http://www.torque.net/linux-pp.html
 S:	Maintained
diff -urN linux-2.4.5-pre3/Makefile linux/Makefile
--- linux-2.4.5-pre3/Makefile	Mon Dec  3 22:43:49 2001
+++ linux/Makefile	Mon Dec  3 22:44:22 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 5
-EXTRAVERSION =-pre3
+EXTRAVERSION =-pre4
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -118,11 +118,7 @@
 
 CORE_FILES	=kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o
 NETWORKS	=net/network.o
-DRIVERS		=drivers/block/block.o \
-		 drivers/char/char.o \
-		 drivers/misc/misc.o \
-		 drivers/net/net.o \
-		 drivers/media/media.o
+
 LIBS		=$(TOPDIR)/lib/lib.a
 SUBDIRS		=kernel drivers mm fs net ipc lib
 
@@ -132,6 +128,11 @@
 DRIVERS-  :=
 
 DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o
+DRIVERS-y += drivers/char/char.o \
+	drivers/block/block.o \
+	drivers/misc/misc.o \
+	drivers/net/net.o \
+	drivers/media/media.o
 DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o
 DRIVERS-$(CONFIG_DRM) += drivers/char/drm/drm.o
 DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a
@@ -177,7 +178,7 @@
 DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
 DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
 
-DRIVERS += $(DRIVERS-y)
+DRIVERS := $(DRIVERS-y)
 
 
 # files removed with 'make clean'
diff -urN linux-2.4.5-pre3/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c
--- linux-2.4.5-pre3/arch/alpha/kernel/pci.c	Fri Mar  2 11:12:07 2001
+++ linux/arch/alpha/kernel/pci.c	Mon Dec  3 22:44:22 2001
@@ -156,7 +156,7 @@
 	else if	(res->flags & IORESOURCE_MEM) {
 		/* Make sure we start at our min on all hoses */
 		if (start - hose->mem_space->start < PCIBIOS_MIN_MEM)
-			start = PCIBIOS_MIN_MEM + hose->io_space->start;
+			start = PCIBIOS_MIN_MEM + hose->mem_space->start;
 
 		/*
 		 * The following holds at least for the Low Cost
diff -urN linux-2.4.5-pre3/arch/alpha/kernel/sys_miata.c linux/arch/alpha/kernel/sys_miata.c
--- linux-2.4.5-pre3/arch/alpha/kernel/sys_miata.c	Fri Oct 27 10:55:01 2000
+++ linux/arch/alpha/kernel/sys_miata.c	Mon Dec  3 22:44:22 2001
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/reboot.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
@@ -223,11 +224,21 @@
 static void
 miata_kill_arch(int mode)
 {
-	/* Who said DEC engineers have no sense of humor? ;-)  */
-	if (alpha_using_srm) {
-		*(vuip) PYXIS_RESET = 0x0000dead;
-		mb();
+	switch(mode) {
+	case LINUX_REBOOT_CMD_RESTART:
+		/* Who said DEC engineers have no sense of humor? ;-)  */ 
+		if (alpha_using_srm) {
+			*(vuip) PYXIS_RESET = 0x0000dead; 
+			mb(); 
+		}
+		break;
+	case LINUX_REBOOT_CMD_HALT:
+		break;
+	case LINUX_REBOOT_CMD_POWER_OFF:
+		break;
 	}
+
+	halt();
 }
 
 
diff -urN linux-2.4.5-pre3/arch/arm/def-configs/clps7500 linux/arch/arm/def-configs/clps7500
--- linux-2.4.5-pre3/arch/arm/def-configs/clps7500	Mon Sep 18 15:15:24 2000
+++ linux/arch/arm/def-configs/clps7500	Mon Dec  3 22:44:22 2001
@@ -2,7 +2,9 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_ARM=y
+# CONFIG_EISA is not set
 # CONFIG_SBUS is not set
+# CONFIG_MCA is not set
 CONFIG_UID16=y
 
 #
@@ -23,6 +25,7 @@
 CONFIG_ARCH_CLPS7500=y
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_FTVPCI is not set
 # CONFIG_ARCH_TBOX is not set
 # CONFIG_ARCH_SHARK is not set
@@ -30,22 +33,51 @@
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_CLPS711X is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Footbridge Implementations
+#
+
+#
+# SA11x0 Implementations
+#
+
+#
+# CLPS711X/EP721X Implementations
+#
 # CONFIG_ARCH_ACORN is not set
 # CONFIG_FOOTBRIDGE is not set
 # CONFIG_FOOTBRIDGE_HOST is not set
 # CONFIG_FOOTBRIDGE_ADDIN is not set
 CONFIG_CPU_32=y
 # CONFIG_CPU_26 is not set
+
+#
+# Processor Type
+#
 CONFIG_CPU_32v3=y
-CONFIG_CPU_ARM7=y
+# CONFIG_CPU_32v4 is not set
+# CONFIG_CPU_ARM610 is not set
+CONFIG_CPU_ARM710=y
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+# CONFIG_CPU_SA1100 is not set
 # CONFIG_DISCONTIGMEM is not set
-# CONFIG_PCI is not set
-# CONFIG_ISA is not set
-# CONFIG_ISA_DMA is not set
 
 #
 # General setup
 #
+CONFIG_ANGELBOOT=y
+# CONFIG_PCI is not set
+CONFIG_ISA=y
+# CONFIG_ISA_DMA is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
 CONFIG_NET=y
@@ -60,7 +92,7 @@
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 # CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="root=/dev/nfs rw"
+CONFIG_CMDLINE="mem=16M root=nfs"
 # CONFIG_ALIGNMENT_TRAP is not set
 
 #
@@ -81,34 +113,35 @@
 # Memory Technology Devices (MTD)
 #
 CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
 # CONFIG_MTD_DOC1000 is not set
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOCPROBE is not set
+
+#
+# RAM/ROM Device Drivers
+#
 # CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_PMC551_BUGFIX is not set
+# CONFIG_MTD_PMC551_DEBUG is not set
 # CONFIG_MTD_MTDRAM is not set
 
 #
-# MTD drivers for mapped chips
+# Linearly Mapped Flash Device Drivers
 #
 # CONFIG_MTD_CFI is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-# CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_JEDEC is not set
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
-# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_JEDEC is not set
 
 #
 # Drivers for chip mappings
 #
-# CONFIG_MTD_MIXMEM is not set
-# CONFIG_MTD_NORA is not set
-# CONFIG_MTD_OCTAGON is not set
-# CONFIG_MTD_PNC2000 is not set
-# CONFIG_MTD_RPXLITE is not set
-# CONFIG_MTD_VMAX is not set
 
 #
 # User modules and translation layers for MTD devices
@@ -122,7 +155,6 @@
 # Plug and Play configuration
 #
 # CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
 
 #
 # Block devices
@@ -130,20 +162,12 @@
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
+CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
-CONFIG_BLK_DEV_FLD7500=y
+# CONFIG_BLK_DEV_FLD7500 is not set
 
 #
 # Networking options
@@ -159,10 +183,8 @@
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IP_PNP_RARP is not set
-# CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -179,6 +201,7 @@
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
@@ -201,6 +224,7 @@
 CONFIG_DUMMY=y
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 # CONFIG_NET_SB1000 is not set
 
 #
@@ -213,16 +237,19 @@
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
 # CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
+CONFIG_NET_PCI=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+CONFIG_CS89x0=y
+# CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
 
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_YELLOWFIN is not set
-# CONFIG_ACENIC is not set
-# CONFIG_SK98LIN is not set
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -283,10 +310,6 @@
 # I2O device support
 #
 # CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
 
 #
 # ISDN subsystem
@@ -294,6 +317,11 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -305,7 +333,7 @@
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
 CONFIG_PRINTER=y
-CONFIG_LP_CONSOLE=y
+# CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
 
 #
@@ -322,16 +350,38 @@
 #
 # Mice
 #
-# CONFIG_BUSMOUSE is not set
+CONFIG_BUSMOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_LOGIBUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
 CONFIG_MOUSE=y
-CONFIG_PSMOUSE=y
+# CONFIG_PSMOUSE is not set
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
 
 #
 # Joysticks
 #
-# CONFIG_JOYSTICK is not set
+
+#
+# Game port support
+#
+
+#
+# Gameport joysticks
+#
+
+#
+# Serial port support
+#
+
+#
+# Serial port joysticks
+#
+
+#
+# Parallel port joysticks
+#
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -341,11 +391,6 @@
 CONFIG_CLPS7500_FLASH=y
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-
-#
-# Video For Linux
-#
-# CONFIG_VIDEO_DEV is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -353,45 +398,38 @@
 # CONFIG_DRM is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # File systems
 #
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
 CONFIG_MINIX_FS=y
 # CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS is not set
+CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
-# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
@@ -401,21 +439,10 @@
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
 # CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
 
 #
 # Partition Types
@@ -430,11 +457,14 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
 # Console drivers
 #
+CONFIG_PC_KEYB=y
+CONFIG_PC_KEYMAP=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 
@@ -445,15 +475,14 @@
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FB_ACORN=y
 # CONFIG_CHRONTEL_7003 is not set
-# CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_VIRTUAL is not set
 CONFIG_FBCON_ADVANCED=y
-# CONFIG_FBCON_MFB is not set
-# CONFIG_FBCON_CFB2 is not set
-# CONFIG_FBCON_CFB4 is not set
+CONFIG_FBCON_MFB=y
+CONFIG_FBCON_CFB2=y
+CONFIG_FBCON_CFB4=y
 CONFIG_FBCON_CFB8=y
-# CONFIG_FBCON_CFB16 is not set
-# CONFIG_FBCON_CFB24 is not set
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB24=y
 # CONFIG_FBCON_CFB32 is not set
 # CONFIG_FBCON_AFB is not set
 # CONFIG_FBCON_ILBM is not set
@@ -487,4 +516,4 @@
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_INFO is not set
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_DEBUG_LL is not set
+CONFIG_DEBUG_LL=y
diff -urN linux-2.4.5-pre3/arch/arm/def-configs/integrator linux/arch/arm/def-configs/integrator
--- linux-2.4.5-pre3/arch/arm/def-configs/integrator	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/def-configs/integrator	Mon Dec  3 22:44:22 2001
@@ -25,6 +25,7 @@
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 CONFIG_ARCH_INTEGRATOR=y
 # CONFIG_ARCH_RPC is not set
@@ -56,18 +57,28 @@
 #
 # Processor Type
 #
+# CONFIG_CPU_32v3 is not set
 CONFIG_CPU_32v4=y
-CONFIG_CPU_ARM720=y
-CONFIG_CPU_ARM920=y
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+CONFIG_CPU_ARM720T=y
+CONFIG_CPU_ARM920T=y
 CONFIG_CPU_ARM920_CPU_IDLE=y
 CONFIG_CPU_ARM920_I_CACHE_ON=y
 CONFIG_CPU_ARM920_D_CACHE_ON=y
 # CONFIG_CPU_ARM920_WRITETHROUGH is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+# CONFIG_CPU_SA1100 is not set
 # CONFIG_DISCONTIGMEM is not set
 
 #
 # General setup
 #
+
+#
+# Please ensure that you have read the help on the next option
+#
 # CONFIG_ANGELBOOT is not set
 CONFIG_PCI_INTEGRATOR=y
 CONFIG_PCI=y
@@ -103,23 +114,32 @@
 # Memory Technology Devices (MTD)
 #
 CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
 # CONFIG_MTD_DOC1000 is not set
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOCPROBE is not set
+
+#
+# RAM/ROM Device Drivers
+#
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PMC551 is not set
 # CONFIG_MTD_MTDRAM is not set
 
 #
-# MTD drivers for mapped chips
+# Linearly Mapped Flash Device Drivers
 #
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_JEDEC is not set
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
+# CONFIG_MTD_JEDEC is not set
 # CONFIG_MTD_PHYSMAP is not set
 
 #
@@ -347,6 +367,8 @@
 CONFIG_SERIAL_AMBA=y
 CONFIG_SERIAL_INTEGRATOR=y
 CONFIG_SERIAL_AMBA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
 
@@ -403,6 +425,8 @@
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
@@ -457,8 +481,6 @@
 # CONFIG_NCPFS_NFS_NS is not set
 # CONFIG_NCPFS_OS2_NS is not set
 # CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 
@@ -475,6 +497,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
@@ -503,7 +526,7 @@
 #
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
+# CONFIG_NO_FRAME_POINTER is not set
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.5-pre3/arch/arm/defconfig linux/arch/arm/defconfig
--- linux-2.4.5-pre3/arch/arm/defconfig	Mon Jun 19 17:59:33 2000
+++ linux/arch/arm/defconfig	Mon Dec  3 22:44:22 2001
@@ -2,50 +2,80 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
 CONFIG_UID16=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
 
 #
-# System and processor type
+# Loadable module support
 #
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
-# CONFIG_ARCH_RPC is not set
+# CONFIG_MODULES is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
-CONFIG_FOOTBRIDGE=y
-CONFIG_HOST_FOOTBRIDGE=y
-# CONFIG_ADDIN_FOOTBRIDGE is not set
-CONFIG_ARCH_EBSA285=y
-# CONFIG_ARCH_CATS is not set
-CONFIG_ARCH_NETWINDER=y
-# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+CONFIG_ARCH_INTEGRATOR=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_CLPS711X is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Footbridge Implementations
+#
+
+#
+# SA11x0 Implementations
+#
+
+#
+# CLPS711X/EP721X Implementations
+#
 # CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
 CONFIG_CPU_32=y
 # CONFIG_CPU_26 is not set
-CONFIG_CPU_32v4=y
-CONFIG_CPU_SA110=y
-CONFIG_PCI=y
-CONFIG_PCI_NAMES=y
-CONFIG_ISA=y
-CONFIG_ISA_DMA=y
-# CONFIG_SBUS is not set
-# CONFIG_PCMCIA is not set
-# CONFIG_ALIGNMENT_TRAP is not set
 
 #
-# Loadable module support
+# Processor Type
 #
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ARM720=y
+CONFIG_CPU_ARM920=y
+CONFIG_CPU_ARM920_CPU_IDLE=y
+CONFIG_CPU_ARM920_I_CACHE_ON=y
+CONFIG_CPU_ARM920_D_CACHE_ON=y
+# CONFIG_CPU_ARM920_WRITETHROUGH is not set
+# CONFIG_DISCONTIGMEM is not set
 
 #
 # General setup
 #
+# CONFIG_ANGELBOOT is not set
+CONFIG_PCI_INTEGRATOR=y
+CONFIG_PCI=y
+# CONFIG_ISA is not set
+# CONFIG_ISA_DMA is not set
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
@@ -56,296 +86,86 @@
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
 # CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="root=1f04 mem=32M"
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
 
 #
 # Parallel port support
 #
-CONFIG_PARPORT=y
-CONFIG_PARPORT_PC=y
-CONFIG_PARPORT_PC_FIFO=y
-# CONFIG_PARPORT_PC_SUPERIO is not set
-# CONFIG_PARPORT_ARC is not set
-# CONFIG_PARPORT_AMIGA is not set
-# CONFIG_PARPORT_MFC3 is not set
-# CONFIG_PARPORT_ATARI is not set
-# CONFIG_PARPORT_SUNBPP is not set
-# CONFIG_PARPORT_OTHER is not set
-CONFIG_PARPORT_1284=y
-CONFIG_CMDLINE="root=/dev/hda1 ro mem=32M parport=0x378,7 ide0=autotune"
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-# CONFIG_LEDS_CPU is not set
+# CONFIG_PARPORT is not set
 
 #
-# IEEE 1394 (FireWire) support
+# Memory Technology Devices (MTD)
 #
-# CONFIG_IEEE1394 is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_MTDRAM is not set
 
 #
-# I2O device support
+# MTD drivers for mapped chips
 #
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_JEDEC is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_PHYSMAP is not set
+
+#
+# Drivers for chip mappings
+#
+# CONFIG_MTD_MIXMEM is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_OCTAGON is not set
+# CONFIG_MTD_PNC2000 is not set
+# CONFIG_MTD_RPXLITE is not set
+# CONFIG_MTD_VMAX is not set
+
+#
+# User modules and translation layers for MTD devices
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+CONFIG_MTD_ARM=y
 
 #
 # Plug and Play configuration
 #
-CONFIG_PNP=y
-CONFIG_ISAPNP=y
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
 
 #
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE=m
-CONFIG_PARIDE_PARPORT=y
-
-#
-# Parallel IDE high-level drivers
-#
-CONFIG_PARIDE_PD=m
-CONFIG_PARIDE_PCD=m
-CONFIG_PARIDE_PF=m
-CONFIG_PARIDE_PT=m
-CONFIG_PARIDE_PG=m
-
-#
-# Parallel IDE protocol modules
-#
-CONFIG_PARIDE_ATEN=m
-CONFIG_PARIDE_BPCK=m
-CONFIG_PARIDE_COMM=m
-CONFIG_PARIDE_DSTR=m
-CONFIG_PARIDE_FIT2=m
-CONFIG_PARIDE_FIT3=m
-CONFIG_PARIDE_EPAT=m
-CONFIG_PARIDE_EPIA=m
-CONFIG_PARIDE_FRIQ=m
-CONFIG_PARIDE_FRPW=m
-CONFIG_PARIDE_KBIC=m
-CONFIG_PARIDE_KTTI=m
-CONFIG_PARIDE_ON20=m
-CONFIG_PARIDE_ON26=m
+# CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=m
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=m
-CONFIG_MD_STRIPED=m
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
 
 #
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_PRINTER=m
-# CONFIG_LP_CONSOLE is not set
-# CONFIG_PPDEV is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=y
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
-
-#
-# Joysticks
-#
-# CONFIG_JOYSTICK is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-# CONFIG_WDT is not set
-CONFIG_SOFT_WATCHDOG=y
-# CONFIG_PCWATCHDOG is not set
-# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_MIXCOMWD is not set
-# CONFIG_21285_WATCHDOG is not set
-CONFIG_977_WATCHDOG=m
-CONFIG_DS1620=y
-CONFIG_NWBUTTON=y
-CONFIG_NWBUTTON_REBOOT=y
-CONFIG_NWFLASH=m
-# CONFIG_NVRAM is not set
-CONFIG_RTC=y
-
-#
-# Video For Linux
-#
-CONFIG_VIDEO_DEV=y
-# CONFIG_I2C_PARPORT is not set
-
-#
-# Radio Adapters
-#
-# CONFIG_RADIO_CADET is not set
-# CONFIG_RADIO_RTRACK is not set
-# CONFIG_RADIO_RTRACK2 is not set
-# CONFIG_RADIO_AZTECH is not set
-# CONFIG_RADIO_GEMTEK is not set
-# CONFIG_RADIO_MIROPCM20 is not set
-# CONFIG_RADIO_SF16FMI is not set
-# CONFIG_RADIO_TERRATEC is not set
-# CONFIG_RADIO_TRUST is not set
-# CONFIG_RADIO_TYPHOON is not set
-# CONFIG_RADIO_ZOLTRIX is not set
-
-#
-# Video Adapters
-#
-# CONFIG_VIDEO_PMS is not set
-# CONFIG_VIDEO_BWQCAM is not set
-# CONFIG_VIDEO_CQCAM is not set
-# CONFIG_VIDEO_SAA5249 is not set
-# CONFIG_TUNER_3036 is not set
-# CONFIG_VIDEO_STRADIS is not set
-# CONFIG_VIDEO_ZORAN is not set
-# CONFIG_VIDEO_BUZ is not set
-# CONFIG_VIDEO_ZR36120 is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_DRM is not set
-# CONFIG_DRM_TDFX is not set
-# CONFIG_AGP is not set
-
-#
-# USB support
-#
-CONFIG_USB=m
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-CONFIG_USB_OHCI=m
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-
-#
-# USB Devices
-#
-CONFIG_USB_PRINTER=m
-# CONFIG_USB_SCANNER is not set
-CONFIG_USB_AUDIO=m
-CONFIG_USB_ACM=m
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_CPIA is not set
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_USS720 is not set
-# CONFIG_USB_DABUSB is not set
-# CONFIG_USB_PLUSB is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_DSBR is not set
-
-#
-# USB HID
-#
-# CONFIG_USB_HID is not set
-CONFIG_USB_KBD=m
-CONFIG_USB_MOUSE=m
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_WMFORCE is not set
-CONFIG_INPUT_KEYBDEV=m
-CONFIG_INPUT_MOUSEDEV=m
-CONFIG_INPUT_MOUSEDEV_MIX=y
-# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-CONFIG_FB=y
-
-#
-# Frame-buffer support
-#
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_RIVA is not set
-# CONFIG_FB_CLGEN is not set
-# CONFIG_FB_PM2 is not set
-CONFIG_FB_CYBER2000=y
-# CONFIG_FB_MATROX is not set
-# CONFIG_FB_ATY is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_3DFX is not set
-# CONFIG_FB_VIRTUAL is not set
-CONFIG_FBCON_ADVANCED=y
-# CONFIG_FBCON_MFB is not set
-# CONFIG_FBCON_CFB2 is not set
-# CONFIG_FBCON_CFB4 is not set
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
-CONFIG_FBCON_CFB24=y
-# CONFIG_FBCON_CFB32 is not set
-# CONFIG_FBCON_AFB is not set
-# CONFIG_FBCON_ILBM is not set
-# CONFIG_FBCON_IPLAN2P2 is not set
-# CONFIG_FBCON_IPLAN2P4 is not set
-# CONFIG_FBCON_IPLAN2P8 is not set
-# CONFIG_FBCON_MAC is not set
-# CONFIG_FBCON_VGA_PLANES is not set
-CONFIG_FBCON_VGA=y
-# CONFIG_FBCON_HGA is not set
-# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-CONFIG_FBCON_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-CONFIG_FONT_ACORN_8x8=y
-
-#
 # Networking options
 #
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
+# CONFIG_PACKET is not set
 # CONFIG_NETLINK is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -356,16 +176,10 @@
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IP_PNP_RARP is not set
-# CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-CONFIG_IP_ALIAS=y
+# CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
-
-#
-# (it is safe to leave these untouched)
-#
-CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
@@ -376,10 +190,11 @@
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
@@ -391,16 +206,6 @@
 # CONFIG_NET_SCHED is not set
 
 #
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
 # Network device support
 #
 CONFIG_NETDEVICES=y
@@ -412,68 +217,59 @@
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 # CONFIG_NET_SB1000 is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
-# CONFIG_ARM_AM79C961A is not set
-CONFIG_NET_VENDOR_3COM=y
-# CONFIG_EL1 is not set
-# CONFIG_EL2 is not set
-# CONFIG_ELPLUS is not set
-# CONFIG_EL16 is not set
-# CONFIG_EL3 is not set
-# CONFIG_3C515 is not set
-CONFIG_VORTEX=y
+# CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
+CONFIG_TULIP=y
 # CONFIG_DE4X5 is not set
-CONFIG_TULIP=m
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
-# CONFIG_EEPRO100 is not set
+CONFIG_EEPRO100=y
+CONFIG_EEPRO100_PM=y
 # CONFIG_LNE390 is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
 # CONFIG_NE3210 is not set
-CONFIG_NE2K_PCI=y
-# CONFIG_RTL8129 is not set
+# CONFIG_ES3210 is not set
 # CONFIG_8139TOO is not set
+# CONFIG_RTL8129 is not set
 # CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_ES3210 is not set
-# CONFIG_EPIC100 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_HAPPYMEAL is not set
 # CONFIG_NET_POCKET is not set
 
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_YELLOWFIN is not set
 # CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-# CONFIG_PPP_SYNC_TTY is not set
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_SLIP=m
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_SMART=y
-CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
 
 #
 # Wireless LAN (non-hamradio)
@@ -494,71 +290,21 @@
 # CONFIG_WAN is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# Amateur Radio support
 #
-CONFIG_IDE=y
+# CONFIG_HAMRADIO is not set
 
 #
-# IDE, ATA and ATAPI Block devices
+# IrDA (infrared) support
 #
-CONFIG_BLK_DEV_IDE=y
+# CONFIG_IRDA is not set
 
 #
-# Please see Documentation/ide.txt for help/info on IDE drives
+# ATA/IDE/MFM/RLL support
 #
-# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_IDEDISK_MULTI_MODE=y
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_OFFBOARD=y
-CONFIG_IDEDMA_PCI_AUTO=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
-# CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD7409 is not set
-# CONFIG_AMD7409_OVERRIDE is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_CMD64X_RAID is not set
-CONFIG_BLK_DEV_CY82C693=y
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_HPT34X_AUTODMA is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_HPT366_FIP is not set
-# CONFIG_HPT366_MODE3 is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_PDC202XX=y
-# CONFIG_PDC202XX_BURST is not set
-# CONFIG_PDC202XX_MASTER is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-CONFIG_BLK_DEV_SL82C105=y
-# CONFIG_IDE_CHIPSETS is not set
-CONFIG_IDEDMA_AUTO=y
-CONFIG_BLK_DEV_IDE_MODES=y
 
 #
 # SCSI support
@@ -566,72 +312,115 @@
 # CONFIG_SCSI is not set
 
 #
-# Sound
+# IEEE 1394 (FireWire) support
 #
-CONFIG_SOUND=m
-# CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_ES1370 is not set
-# CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_ESSSOLO1 is not set
-# CONFIG_SOUND_MAESTRO is not set
-# CONFIG_SOUND_SONICVIBES is not set
-# CONFIG_SOUND_TRIDENT is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-CONFIG_SOUND_OSS=m
-# CONFIG_SOUND_TRACEINIT is not set
-# CONFIG_SOUND_DMAP is not set
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_ADLIB is not set
-# CONFIG_SOUND_ACI_MIXER is not set
-# CONFIG_SOUND_CS4232 is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_NM256 is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_PAS is not set
-# CONFIG_PAS_JOYSTICK is not set
-# CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_SOFTOSS is not set
-CONFIG_SOUND_SB=m
-# CONFIG_SOUND_AWE32_SYNTH is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_UART6850 is not set
-# CONFIG_SOUND_AEDSP16 is not set
-# CONFIG_SOUND_VIDC is not set
-CONFIG_SOUND_WAVEARTIST=m
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SERIAL_AMBA=y
+CONFIG_SERIAL_INTEGRATOR=y
+CONFIG_SERIAL_AMBA_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
 
 #
 # File systems
 #
 # CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
-CONFIG_ADFS_FS=y
+# CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
+# CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
 # CONFIG_CRAMFS is not set
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
@@ -639,77 +428,77 @@
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+CONFIG_ROMFS_FS=y
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
-CONFIG_NFSD=m
+# CONFIG_NFSD is not set
 # CONFIG_NFSD_V3 is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
 
 #
 # Partition Types
 #
 CONFIG_PARTITION_ADVANCED=y
-CONFIG_ACORN_PARTITION=y
-# CONFIG_ACORN_PARTITION_ICS is not set
-CONFIG_ACORN_PARTITION_ADFS=y
-# CONFIG_ACORN_PARTITION_POWERTEC is not set
-# CONFIG_ACORN_PARTITION_RISCIX is not set
+# CONFIG_ACORN_PARTITION is not set
 # CONFIG_OSF_PARTITION is not set
 # CONFIG_AMIGA_PARTITION is not set
 # CONFIG_ATARI_PARTITION is not set
 # CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_MSDOS_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
-CONFIG_NLS=y
+# CONFIG_NLS is not set
 
 #
-# Native Language Support
+# Console drivers
+#
+CONFIG_KMI_KEYB=y
+CONFIG_PC_KEYMAP=y
+CONFIG_VGA_CONSOLE=y
+# CONFIG_FB is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
 #
-CONFIG_NLS_CODEPAGE_437=m
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_CODEPAGE_852=m
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-CONFIG_NLS_ISO8859_1=m
-CONFIG_NLS_ISO8859_2=m
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-CONFIG_NLS_ISO8859_15=m
-# CONFIG_NLS_KOI8_R is not set
+# CONFIG_USB is not set
 
 #
 # Kernel hacking
@@ -719,4 +508,4 @@
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_DEBUG_LL is not set
+CONFIG_DEBUG_LL=y
diff -urN linux-2.4.5-pre3/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c
--- linux-2.4.5-pre3/arch/arm/kernel/setup.c	Fri Apr 27 14:10:31 2001
+++ linux/arch/arm/kernel/setup.c	Mon Dec  3 22:44:22 2001
@@ -51,7 +51,6 @@
 extern void paging_init(struct meminfo *, struct machine_desc *desc);
 extern void bootmem_init(struct meminfo *);
 extern void reboot_setup(char *str);
-extern unsigned long memparse(char *ptr, char **retptr);
 extern int root_mountflags;
 extern int _stext, _text, _etext, _edata, _end;
 
diff -urN linux-2.4.5-pre3/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile
--- linux-2.4.5-pre3/arch/arm/lib/Makefile	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/lib/Makefile	Mon Dec  3 22:44:22 2001
@@ -48,3 +48,7 @@
 endif
 
 include $(TOPDIR)/Rules.make
+
+csumpartialcopy.o: csumpartialcopygeneric.S
+csumpartialcopyuser.o: csumpartialcopygeneric.S
+
diff -urN linux-2.4.5-pre3/arch/arm/lib/csumpartial.S linux/arch/arm/lib/csumpartial.S
--- linux-2.4.5-pre3/arch/arm/lib/csumpartial.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/csumpartial.S	Mon Dec  3 22:44:22 2001
@@ -12,57 +12,119 @@
 
 		.text
 
-/* Function: __u32 csum_partial(const char *src, int len, __u32)
+/*
+ * Function: __u32 csum_partial(const char *src, int len, __u32 sum)
  * Params  : r0 = buffer, r1 = len, r2 = checksum
  * Returns : r0 = new checksum
  */
 
+buf	.req	r0
+len	.req	r1
+sum	.req	r2
+td0	.req	r3
+td1	.req	r4	@ save before use
+td2	.req	r5	@ save before use
+td3	.req	lr
+
+.zero:		mov	r0, sum
+		add	sp, sp, #4
+		ldr	pc, [sp], #4
+
+		/*
+		 * Handle 0 to 7 bytes, with any alignment of source and
+		 * destination pointers.  Note that when we get here, C = 0
+		 */
+.less8:		teq	len, #0			@ check for zero count
+		beq	.zero
+
+		/* we must have at least one byte. */
+		tst	buf, #1			@ odd address?
+		ldrneb	td0, [buf], #1
+		subne	len, len, #1
+		adcnes	sum, sum, td0, lsl #8
+
+.less4:		tst	len, #6
+		beq	.less8_byte
+
+		/* we are now half-word aligned */
+
+.less8_wordlp:
+#ifdef __ARM_ARCH_4__
+		ldrh	td0, [buf], #2
+		sub	len, len, #2
+#else
+		ldrb	td0, [buf], #1
+		ldrb	td3, [buf], #1
+		sub	len, len, #2
+		orr	td0, td0, td3, lsl #8
+#endif
+		adcs	sum, sum, td0
+		tst	len, #6
+		bne	.less8_wordlp
+
+.less8_byte:	tst	len, #1			@ odd number of bytes
+		ldrneb	td0, [buf], #1		@ include last byte
+		adcnes	sum, sum, td0		@ update checksum
+
+.done:		adc	r0, sum, #0		@ collect up the last carry
+		ldr	td0, [sp], #4
+		tst	td0, #1			@ check buffer alignment
+		movne	td0, r0, lsl #8		@ rotate checksum by 8 bits
+		orrne	r0, td0, r0, lsr #24
+		ldr	pc, [sp], #4		@ return
+
+.not_aligned:	tst	buf, #1			@ odd address
+		ldrneb	td0, [buf], #1		@ make even
+		subne	len, len, #1
+		adcnes	sum, sum, td0, lsl #8	@ update checksum
+
+		tst	buf, #2			@ 32-bit aligned?
+#ifdef __ARM_ARCH_4__
+		ldrneh	td0, [buf], #2		@ make 32-bit aligned
+		subne	len, len, #2
+#else
+		ldrneb	td0, [buf], #1
+		ldrneb	ip, [buf], #1
+		subne	len, len, #2
+		orrne	td0, td0, ip, lsl #8
+#endif
+		adcnes	sum, sum, td0		@ update checksum
+		mov	pc, lr
+
 ENTRY(csum_partial)
-		tst	r0, #2
-		beq	1f
-		subs	r1, r1, #2
-		addmi	r1, r1, #2
-		bmi	3f
-		bic	r0, r0, #3
-		ldr	r3, [r0], #4
-		adds	r2, r2, r3, lsr #16
-		adcs	r2, r2, #0
-1:		adds	r2, r2, #0
-		bics	ip, r1, #31
+		stmfd	sp!, {buf, lr}
+		cmp	len, #8			@ Ensure that we have at least
+		blo	.less8			@ 8 bytes to copy.
+
+		adds	sum, sum, #0		@ C = 0
+		tst	buf, #3			@ Test destination alignment
+		blne	.not_aligned		@ aligh destination, return here
+
+1:		bics	ip, len, #31
 		beq	3f
-		stmfd	sp!, {r4 - r6}
-2:		ldmia	r0!, {r3 - r6}
-		adcs	r2, r2, r3
-		adcs	r2, r2, r4
-		adcs	r2, r2, r5
-		adcs	r2, r2, r6
-		ldmia	r0!, {r3 - r6}
-		adcs	r2, r2, r3
-		adcs	r2, r2, r4
-		adcs	r2, r2, r5
-		adcs	r2, r2, r6
+
+		stmfd	sp!, {r4 - r5}
+2:		ldmia	buf!, {td0, td1, td2, td3}
+		adcs	sum, sum, td0
+		adcs	sum, sum, td1
+		adcs	sum, sum, td2
+		adcs	sum, sum, td3
+		ldmia	buf!, {td0, td1, td2, td3}
+		adcs	sum, sum, td0
+		adcs	sum, sum, td1
+		adcs	sum, sum, td2
+		adcs	sum, sum, td3
 		sub	ip, ip, #32
 		teq	ip, #0
 		bne	2b
-		adcs	r2, r2, #0
-		ldmfd	sp!, {r4 - r6}
-3:		ands	ip, r1, #0x1c
-		beq	5f
-4:		ldr	r3, [r0], #4
-		sub	ip, ip, #4
-		adcs	r2, r2, r3
-		teq	ip, #0
-		bne	4b
-		adcs	r2, r2, #0
-5:		ands	ip, r1, #3
-		moveq	r0, r2
-		RETINSTR(moveq,pc,lr)
-		mov	ip, ip, lsl #3
-		ldr	r3, [r0]
-		rsb	ip, ip, #32
-		mov	r3, r3, lsl ip
-		adds	r2, r2, r3, lsr ip
-		adc	r0, r2, #0
-		RETINSTR(mov,pc,lr)
+		ldmfd	sp!, {r4 - r5}
 
+3:		tst	len, #0x1c		@ should not change C
+		beq	.less4
 
+4:		ldr	td0, [buf], #4
+		sub	len, len, #4
+		adcs	sum, sum, td0
+		tst	len, #0x1c
+		bne	4b
+		b	.less4
diff -urN linux-2.4.5-pre3/arch/arm/lib/csumpartialcopy.S linux/arch/arm/lib/csumpartialcopy.S
--- linux-2.4.5-pre3/arch/arm/lib/csumpartialcopy.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/csumpartialcopy.S	Mon Dec  3 22:44:22 2001
@@ -18,11 +18,11 @@
  */
 
 		.macro	save_regs
-		stmfd	sp!, {r4 - r8, fp, ip, lr, pc}
+		stmfd	sp!, {r1, r4 - r8, fp, ip, lr, pc}
 		.endm
 
 		.macro	load_regs,flags
-		LOADREGS(\flags,fp,{r4 - r8, fp, sp, pc})
+		LOADREGS(\flags,fp,{r1, r4 - r8, fp, sp, pc})
 		.endm
 
 		.macro	load1b, reg1
@@ -47,250 +47,6 @@
 		ldmia	r0!, {\reg1, \reg2, \reg3, \reg4}
 		.endm
 
-ENTRY(csum_partial_copy_nocheck)
-		mov	ip, sp
-		save_regs
-		sub	fp, ip, #4
-		cmp	r2, #4
-		blt	.too_small
-		tst	r1, #2			@ Test destination alignment
-		beq	.dst_aligned
-		load2b	ip, r8
-		subs	r2, r2, #2		@ We do not know if SRC is aligned...
-		orr	ip, ip, r8, lsl #8
-		adds	r3, r3, ip
-		adcs	r3, r3, #0
-		strb	ip, [r1], #1
-		mov	ip, ip, lsr #8
-		strb	ip, [r1], #1		@ Destination now aligned
-.dst_aligned:	tst	r0, #3
-		bne	.src_not_aligned
-		adds	r3, r3, #0
-		bics	ip, r2, #15		@ Routine for src & dst aligned
-		beq	2f
-1:		load4l	r4, r5, r6, r7
-		stmia	r1!, {r4, r5, r6, r7}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		adcs	r3, r3, r6
-		adcs	r3, r3, r7
-		sub	ip, ip, #16
-		teq	ip, #0
-		bne	1b
-2:		ands	ip, r2, #12
-		beq	4f
-		tst	ip, #8
-		beq	3f
-		load2l	r4, r5
-		stmia	r1!, {r4, r5}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		tst	ip, #4
-		beq	4f
-3:		load1l	r4
-		str	r4, [r1], #4
-		adcs	r3, r3, r4
-4:		ands	r2, r2, #3
-		adceq	r0, r3, #0
-		load_regs	eqea
-		load1l	r4
-		tst	r2, #2
-		beq	.exit
-		adcs	r3, r3, r4, lsl #16
-		strb	r4, [r1], #1
-		mov	r4, r4, lsr #8
-		strb	r4, [r1], #1
-		mov	r4, r4, lsr #8
-.exit:		tst	r2, #1
-		strneb	r4, [r1], #1
-		andne	r4, r4, #255
-		adcnes	r3, r3, r4
-		adcs	r0, r3, #0
-		load_regs	ea
+#define FN_ENTRY	ENTRY(csum_partial_copy_nocheck)
 
-.too_small:	teq	r2, #0
-		load_regs	eqea
-		cmp	r2, #2
-		blt	.too_small1
-		load2b	ip, r8
-		orr	ip, ip, r8, lsl #8
-		adds	r3, r3, ip
-		strb	ip, [r1], #1
-		strb	r8, [r1], #1
-		tst	r2, #1
-.too_small1:				@ C = 0
-		beq	.csum_exit
-		load1b	ip
-		strb	ip, [r1], #1
-		adcs	r3, r3, ip
-.csum_exit:	adc	r0, r3, #0
-		load_regs	ea
-
-.src_not_aligned:
-		cmp	r2, #4
-		blt	.too_small
-		and	ip, r0, #3
-		bic	r0, r0, #3
-		load1l	r4
-		cmp	ip, #2
-		beq	.src2_aligned
-		bhi	.src3_aligned
-		mov	r4, r4, lsr #8
-		adds	r3, r3, #0
-		bics	ip, r2, #15
-		beq	2f
-1:		load4l	r5, r6, r7, r8
-		orr	r4, r4, r5, lsl #24
-		mov	r5, r5, lsr #8
-		orr	r5, r5, r6, lsl #24
-		mov	r6, r6, lsr #8
-		orr	r6, r6, r7, lsl #24
-		mov	r7, r7, lsr #8
-		orr	r7, r7, r8, lsl #24
-		stmia	r1!, {r4, r5, r6, r7}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		adcs	r3, r3, r6
-		adcs	r3, r3, r7
-		mov	r4, r8, lsr #8
-		sub	ip, ip, #16
-		teq	ip, #0
-		bne	1b
-2:		ands	ip, r2, #12
-		beq	4f
-		tst	ip, #8
-		beq	3f
-		load2l	r5, r6
-		orr	r4, r4, r5, lsl #24
-		mov	r5, r5, lsr #8
-		orr	r5, r5, r6, lsl #24
-		stmia	r1!, {r4, r5}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		mov	r4, r6, lsr #8
-		tst	ip, #4
-		beq	4f
-3:		load1l	r5
-		orr	r4, r4, r5, lsl #24
-		str	r4, [r1], #4
-		adcs	r3, r3, r4
-		mov	r4, r5, lsr #8
-4:		ands	r2, r2, #3
-		adceq	r0, r3, #0
-		load_regs	eqea
-		tst	r2, #2
-		beq	.exit
-		adcs	r3, r3, r4, lsl #16
-		strb	r4, [r1], #1
-		mov	r4, r4, lsr #8
-		strb	r4, [r1], #1
-		mov	r4, r4, lsr #8
-		b	.exit
-
-.src2_aligned:	mov	r4, r4, lsr #16
-		adds	r3, r3, #0
-		bics	ip, r2, #15
-		beq	2f
-1:		load4l	r5, r6, r7, r8
-		orr	r4, r4, r5, lsl #16
-		mov	r5, r5, lsr #16
-		orr	r5, r5, r6, lsl #16
-		mov	r6, r6, lsr #16
-		orr	r6, r6, r7, lsl #16
-		mov	r7, r7, lsr #16
-		orr	r7, r7, r8, lsl #16
-		stmia	r1!, {r4, r5, r6, r7}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		adcs	r3, r3, r6
-		adcs	r3, r3, r7
-		mov	r4, r8, lsr #16
-		sub	ip, ip, #16
-		teq	ip, #0
-		bne	1b
-2:		ands	ip, r2, #12
-		beq	4f
-		tst	ip, #8
-		beq	3f
-		load2l	r5, r6
-		orr	r4, r4, r5, lsl #16
-		mov	r5, r5, lsr #16
-		orr	r5, r5, r6, lsl #16
-		stmia	r1!, {r4, r5}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		mov	r4, r6, lsr #16
-		tst	ip, #4
-		beq	4f
-3:		load1l	r5
-		orr	r4, r4, r5, lsl #16
-		str	r4, [r1], #4
-		adcs	r3, r3, r4
-		mov	r4, r5, lsr #16
-4:		ands	r2, r2, #3
-		adceq	r0, r3, #0
-		load_regs	eqea
-		tst	r2, #2
-		beq	.exit
-		adcs	r3, r3, r4, lsl #16
-		strb	r4, [r1], #1
-		mov	r4, r4, lsr #8
-		strb	r4, [r1], #1
-		tst	r2, #1
-		adceq	r0, r3, #0
-		load_regs	eqea
-		load1b	r4
-		b	.exit
-
-.src3_aligned:	mov	r4, r4, lsr #24
-		adds	r3, r3, #0
-		bics	ip, r2, #15
-		beq	2f
-1:		load4l	r5, r6, r7, r8
-		orr	r4, r4, r5, lsl #8
-		mov	r5, r5, lsr #24
-		orr	r5, r5, r6, lsl #8
-		mov	r6, r6, lsr #24
-		orr	r6, r6, r7, lsl #8
-		mov	r7, r7, lsr #24
-		orr	r7, r7, r8, lsl #8
-		stmia	r1!, {r4, r5, r6, r7}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		adcs	r3, r3, r6
-		adcs	r3, r3, r7
-		mov	r4, r8, lsr #24
-		sub	ip, ip, #16
-		teq	ip, #0
-		bne	1b
-2:		ands	ip, r2, #12
-		beq	4f
-		tst	ip, #8
-		beq	3f
-		load2l	r5, r6
-		orr	r4, r4, r5, lsl #8
-		mov	r5, r5, lsr #24
-		orr	r5, r5, r6, lsl #8
-		stmia	r1!, {r4, r5}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		mov	r4, r6, lsr #24
-		tst	ip, #4
-		beq	4f
-3:		load1l	r5
-		orr	r4, r4, r5, lsl #8
-		str	r4, [r1], #4
-		adcs	r3, r3, r4
-		mov	r4, r5, lsr #24
-4:		ands	r2, r2, #3
-		adceq	r0, r3, #0
-		load_regs	eqea
-		tst	r2, #2
-		beq	.exit
-		adcs	r3, r3, r4, lsl #16
-		strb	r4, [r1], #1
-		load1l	r4
-		strb	r4, [r1], #1
-		adcs	r3, r3, r4, lsl #24
-		mov	r4, r4, lsr #8
-		b	.exit
+#include "csumpartialcopygeneric.S"
diff -urN linux-2.4.5-pre3/arch/arm/lib/csumpartialcopygeneric.S linux/arch/arm/lib/csumpartialcopygeneric.S
--- linux-2.4.5-pre3/arch/arm/lib/csumpartialcopygeneric.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/csumpartialcopygeneric.S	Mon Dec  3 22:44:22 2001
@@ -0,0 +1,327 @@
+/*
+ *  linux/arch/arm/lib/csumpartialcopygeneric.S
+ *
+ *  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
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * unsigned int
+ * csum_partial_copy_xxx(const char *src, char *dst, int len, int sum, )
+ *  r0 = src, r1 = dst, r2 = len, r3 = sum
+ *  Returns : r0 = checksum
+ *
+ * Note that 'tst' and 'teq' preserve the carry flag.
+ */
+
+src	.req	r0
+dst	.req	r1
+len	.req	r2
+sum	.req	r3
+
+.zero:		mov	r0, sum
+		load_regs	ea
+
+		/*
+		 * Align an unaligned destination pointer.  We know that
+		 * we have >= 8 bytes here, so we don't need to check
+		 * the length.  Note that the source pointer hasn't been
+		 * aligned yet.
+		 */
+.dst_unaligned:	tst	dst, #1
+		beq	.dst_16bit
+
+		load1b	ip
+		sub	len, len, #1
+		adcs	sum, sum, ip, lsl #8	@ update checksum
+		strb	ip, [dst], #1
+		tst	dst, #2
+		moveq	pc, lr			@ dst is now 32bit aligned
+
+.dst_16bit:	load2b	r8, ip
+		sub	len, len, #2
+		adcs	sum, sum, r8
+		strb	r8, [dst], #1
+		adcs	sum, sum, ip, lsl #8
+		strb	ip, [dst], #1
+		mov	pc, lr			@ dst is now 32bit aligned
+
+		/*
+		 * Handle 0 to 7 bytes, with any alignment of source and
+		 * destination pointers.  Note that when we get here, C = 0
+		 */
+.less8:		teq	len, #0			@ check for zero count
+		beq	.zero
+
+		/* we must have at least one byte. */
+		tst	dst, #1			@ dst 16-bit aligned
+		beq	.less8_aligned
+
+		/* Align dst */
+		load1b	ip
+		sub	len, len, #1
+		adcs	sum, sum, ip, lsl #8	@ update checksum
+		strb	ip, [dst], #1
+		tst	len, #6
+		beq	.less8_byteonly
+
+1:		load2b	r8, ip
+		sub	len, len, #2
+		adcs	sum, sum, r8
+		strb	r8, [dst], #1
+		adcs	sum, sum, ip, lsl #8
+		strb	ip, [dst], #1
+.less8_aligned:	tst	len, #6
+		bne	1b
+.less8_byteonly:
+		tst	len, #1
+		beq	.done
+		load1b	r8
+		adcs	sum, sum, r8		@ update checksum
+		strb	r8, [dst], #1
+		b	.done
+
+FN_ENTRY
+		mov	ip, sp
+		save_regs
+		sub	fp, ip, #4
+
+		cmp	len, #8			@ Ensure that we have at least
+		blo	.less8			@ 8 bytes to copy.
+
+		adds	sum, sum, #0		@ C = 0
+		tst	dst, #3			@ Test destination alignment
+		blne	.dst_unaligned		@ align destination, return here
+
+		/*
+		 * Ok, the dst pointer is now 32bit aligned, and we know
+		 * that we must have more than 4 bytes to copy.  Note
+		 * that C contains the carry from the dst alignment above.
+		 */
+
+		tst	src, #3			@ Test source alignment
+		bne	.src_not_aligned
+
+		/* Routine for src & dst aligned */
+
+		bics	ip, len, #15
+		beq	2f
+
+1:		load4l	r4, r5, r6, r7
+		stmia	dst!, {r4, r5, r6, r7}
+		adcs	sum, sum, r4
+		adcs	sum, sum, r5
+		adcs	sum, sum, r6
+		adcs	sum, sum, r7
+		sub	ip, ip, #16
+		teq	ip, #0
+		bne	1b
+
+2:		ands	ip, len, #12
+		beq	4f
+		tst	ip, #8
+		beq	3f
+		load2l	r4, r5
+		stmia	dst!, {r4, r5}
+		adcs	sum, sum, r4
+		adcs	sum, sum, r5
+		tst	ip, #4
+		beq	4f
+
+3:		load1l	r4
+		str	r4, [dst], #4
+		adcs	sum, sum, r4
+
+4:		ands	len, len, #3
+		beq	.done
+		load1l	r4
+		tst	len, #2
+		beq	.exit
+		adcs	sum, sum, r4, lsl #16
+		strb	r4, [dst], #1
+		mov	r4, r4, lsr #8
+		strb	r4, [dst], #1
+		mov	r4, r4, lsr #8
+.exit:		tst	len, #1
+		strneb	r4, [dst], #1
+		andne	r4, r4, #255
+		adcnes	sum, sum, r4
+
+		/*
+		 * If the dst pointer was not 16-bit aligned, we
+		 * need to rotate the checksum here to get around
+		 * the inefficient byte manipulations in the
+		 * architecture independent code.
+		 */
+.done:		adc	r0, sum, #0
+		ldr	sum, [sp, #0]		@ dst
+		tst	sum, #1
+		movne	sum, r0, lsl #8
+		orrne	r0, sum, r0, lsr #24
+		load_regs	ea
+
+.src_not_aligned:
+		adc	sum, sum, #0		@ include C from dst alignment
+		and	ip, src, #3
+		bic	src, src, #3
+		load1l	r4
+		cmp	ip, #2
+		beq	.src2_aligned
+		bhi	.src3_aligned
+		mov	r4, r4, lsr #8		@ C = 0
+		bics	ip, len, #15
+		beq	2f
+1:		load4l	r5, r6, r7, r8
+		orr	r4, r4, r5, lsl #24
+		mov	r5, r5, lsr #8
+		orr	r5, r5, r6, lsl #24
+		mov	r6, r6, lsr #8
+		orr	r6, r6, r7, lsl #24
+		mov	r7, r7, lsr #8
+		orr	r7, r7, r8, lsl #24
+		stmia	dst!, {r4, r5, r6, r7}
+		adcs	sum, sum, r4
+		adcs	sum, sum, r5
+		adcs	sum, sum, r6
+		adcs	sum, sum, r7
+		mov	r4, r8, lsr #8
+		sub	ip, ip, #16
+		teq	ip, #0
+		bne	1b
+2:		ands	ip, len, #12
+		beq	4f
+		tst	ip, #8
+		beq	3f
+		load2l	r5, r6
+		orr	r4, r4, r5, lsl #24
+		mov	r5, r5, lsr #8
+		orr	r5, r5, r6, lsl #24
+		stmia	dst!, {r4, r5}
+		adcs	sum, sum, r4
+		adcs	sum, sum, r5
+		mov	r4, r6, lsr #8
+		tst	ip, #4
+		beq	4f
+3:		load1l	r5
+		orr	r4, r4, r5, lsl #24
+		str	r4, [dst], #4
+		adcs	sum, sum, r4
+		mov	r4, r5, lsr #8
+4:		ands	len, len, #3
+		beq	.done
+		tst	len, #2
+		beq	.exit
+		adcs	sum, sum, r4, lsl #16
+		strb	r4, [dst], #1
+		mov	r4, r4, lsr #8
+		strb	r4, [dst], #1
+		mov	r4, r4, lsr #8
+		b	.exit
+
+.src2_aligned:	mov	r4, r4, lsr #16
+		adds	sum, sum, #0
+		bics	ip, len, #15
+		beq	2f
+1:		load4l	r5, r6, r7, r8
+		orr	r4, r4, r5, lsl #16
+		mov	r5, r5, lsr #16
+		orr	r5, r5, r6, lsl #16
+		mov	r6, r6, lsr #16
+		orr	r6, r6, r7, lsl #16
+		mov	r7, r7, lsr #16
+		orr	r7, r7, r8, lsl #16
+		stmia	dst!, {r4, r5, r6, r7}
+		adcs	sum, sum, r4
+		adcs	sum, sum, r5
+		adcs	sum, sum, r6
+		adcs	sum, sum, r7
+		mov	r4, r8, lsr #16
+		sub	ip, ip, #16
+		teq	ip, #0
+		bne	1b
+2:		ands	ip, len, #12
+		beq	4f
+		tst	ip, #8
+		beq	3f
+		load2l	r5, r6
+		orr	r4, r4, r5, lsl #16
+		mov	r5, r5, lsr #16
+		orr	r5, r5, r6, lsl #16
+		stmia	dst!, {r4, r5}
+		adcs	sum, sum, r4
+		adcs	sum, sum, r5
+		mov	r4, r6, lsr #16
+		tst	ip, #4
+		beq	4f
+3:		load1l	r5
+		orr	r4, r4, r5, lsl #16
+		str	r4, [dst], #4
+		adcs	sum, sum, r4
+		mov	r4, r5, lsr #16
+4:		ands	len, len, #3
+		beq	.done
+		tst	len, #2
+		beq	.exit
+		adcs	sum, sum, r4, lsl #16
+		strb	r4, [dst], #1
+		mov	r4, r4, lsr #8
+		strb	r4, [dst], #1
+		tst	len, #1
+		beq	.done
+		load1b	r4
+		b	.exit
+
+.src3_aligned:	mov	r4, r4, lsr #24
+		adds	sum, sum, #0
+		bics	ip, len, #15
+		beq	2f
+1:		load4l	r5, r6, r7, r8
+		orr	r4, r4, r5, lsl #8
+		mov	r5, r5, lsr #24
+		orr	r5, r5, r6, lsl #8
+		mov	r6, r6, lsr #24
+		orr	r6, r6, r7, lsl #8
+		mov	r7, r7, lsr #24
+		orr	r7, r7, r8, lsl #8
+		stmia	dst!, {r4, r5, r6, r7}
+		adcs	sum, sum, r4
+		adcs	sum, sum, r5
+		adcs	sum, sum, r6
+		adcs	sum, sum, r7
+		mov	r4, r8, lsr #24
+		sub	ip, ip, #16
+		teq	ip, #0
+		bne	1b
+2:		ands	ip, len, #12
+		beq	4f
+		tst	ip, #8
+		beq	3f
+		load2l	r5, r6
+		orr	r4, r4, r5, lsl #8
+		mov	r5, r5, lsr #24
+		orr	r5, r5, r6, lsl #8
+		stmia	dst!, {r4, r5}
+		adcs	sum, sum, r4
+		adcs	sum, sum, r5
+		mov	r4, r6, lsr #24
+		tst	ip, #4
+		beq	4f
+3:		load1l	r5
+		orr	r4, r4, r5, lsl #8
+		str	r4, [dst], #4
+		adcs	sum, sum, r4
+		mov	r4, r5, lsr #24
+4:		ands	len, len, #3
+		beq	.done
+		tst	len, #2
+		beq	.exit
+		adcs	sum, sum, r4, lsl #16
+		strb	r4, [dst], #1
+		load1l	r4
+		strb	r4, [dst], #1
+		adcs	sum, sum, r4, lsl #24
+		mov	r4, r4, lsr #8
+		b	.exit
diff -urN linux-2.4.5-pre3/arch/arm/lib/csumpartialcopyuser.S linux/arch/arm/lib/csumpartialcopyuser.S
--- linux-2.4.5-pre3/arch/arm/lib/csumpartialcopyuser.S	Tue Mar  6 19:44:35 2001
+++ linux/arch/arm/lib/csumpartialcopyuser.S	Mon Dec  3 22:44:22 2001
@@ -15,10 +15,6 @@
 
 		.text
 
-/* Function: __u32 csum_partial_copy_from_user (const char *src, char *dst, int len, __u32 sum, int *err_ptr)
- * Params  : r0 = src, r1 = dst, r2 = len, r3 = sum, [sp, #0] = &err
- * Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT
- */
 #if defined(CONFIG_CPU_32)
 
 		.macro	save_regs
@@ -152,253 +148,16 @@
 #error Unknown CPU architecture
 #endif
 
-ENTRY(csum_partial_copy_from_user)
-		mov	ip, sp
-		save_regs
-		sub	fp, ip, #4
-		cmp	r2, #4
-		blt	.too_small
-		tst	r1, #2			@ Test destination alignment
-		beq	.dst_aligned
-		load2b	ip, r8
-		subs	r2, r2, #2		@ We do not know if SRC is aligned...
-		orr	ip, ip, r8, lsl #8
-		adds	r3, r3, ip
-		adcs	r3, r3, #0
-		strb	ip, [r1], #1
-		mov	ip, ip, lsr #8
-		strb	ip, [r1], #1		@ Destination now aligned
-.dst_aligned:	tst	r0, #3
-		bne	.src_not_aligned
-		adds	r3, r3, #0
-		bics	ip, r2, #15		@ Routine for src & dst aligned
-		beq	2f
-1:		load4l	r4, r5, r6, r7
-		stmia	r1!, {r4, r5, r6, r7}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		adcs	r3, r3, r6
-		adcs	r3, r3, r7
-		sub	ip, ip, #16
-		teq	ip, #0
-		bne	1b
-2:		ands	ip, r2, #12
-		beq	4f
-		tst	ip, #8
-		beq	3f
-		load2l	r4, r5
-		stmia	r1!, {r4, r5}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		tst	ip, #4
-		beq	4f
-3:		load1l	r4
-		str	r4, [r1], #4
-		adcs	r3, r3, r4
-4:		ands	r2, r2, #3
-		adceq	r0, r3, #0
-		load_regs	eqea
-		load1l	r4
-		tst	r2, #2
-		beq	.exit
-		adcs	r3, r3, r4, lsl #16
-		strb	r4, [r1], #1
-		mov	r4, r4, lsr #8
-		strb	r4, [r1], #1
-		mov	r4, r4, lsr #8
-.exit:		tst	r2, #1
-		strneb	r4, [r1], #1
-		andne	r4, r4, #255
-		adcnes	r3, r3, r4
-		adcs	r0, r3, #0
-		load_regs	ea
-
-.too_small:	teq	r2, #0
-		load_regs	eqea
-		cmp	r2, #2
-		blt	.too_small1
-		load2b	ip, r8
-		orr	ip, ip, r8, lsl #8
-		adds	r3, r3, ip
-		strb	ip, [r1], #1
-		strb	r8, [r1], #1
-		tst	r2, #1
-.too_small1:				@ C = 0
-		beq	.csum_exit
-		load1b	ip
-		strb	ip, [r1], #1
-		adcs	r3, r3, ip
-.csum_exit:	adc	r0, r3, #0
-		load_regs	ea
-
-.src_not_aligned:
-		cmp	r2, #4
-		blt	.too_small
-		and	ip, r0, #3
-		bic	r0, r0, #3
-		load1l	r4
-		cmp	ip, #2
-		beq	.src2_aligned
-		bhi	.src3_aligned
-		mov	r4, r4, lsr #8
-		adds	r3, r3, #0
-		bics	ip, r2, #15
-		beq	2f
-1:		load4l	r5, r6, r7, r8
-		orr	r4, r4, r5, lsl #24
-		mov	r5, r5, lsr #8
-		orr	r5, r5, r6, lsl #24
-		mov	r6, r6, lsr #8
-		orr	r6, r6, r7, lsl #24
-		mov	r7, r7, lsr #8
-		orr	r7, r7, r8, lsl #24
-		stmia	r1!, {r4, r5, r6, r7}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		adcs	r3, r3, r6
-		adcs	r3, r3, r7
-		mov	r4, r8, lsr #8
-		sub	ip, ip, #16
-		teq	ip, #0
-		bne	1b
-2:		ands	ip, r2, #12
-		beq	4f
-		tst	ip, #8
-		beq	3f
-		load2l	r5, r6
-		orr	r4, r4, r5, lsl #24
-		mov	r5, r5, lsr #8
-		orr	r5, r5, r6, lsl #24
-		stmia	r1!, {r4, r5}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		mov	r4, r6, lsr #8
-		tst	ip, #4
-		beq	4f
-3:		load1l	r5
-		orr	r4, r4, r5, lsl #24
-		str	r4, [r1], #4
-		adcs	r3, r3, r4
-		mov	r4, r5, lsr #8
-4:		ands	r2, r2, #3
-		adceq	r0, r3, #0
-		load_regs	eqea
-		tst	r2, #2
-		beq	.exit
-		adcs	r3, r3, r4, lsl #16
-		strb	r4, [r1], #1
-		mov	r4, r4, lsr #8
-		strb	r4, [r1], #1
-		mov	r4, r4, lsr #8
-		b	.exit
-
-.src2_aligned:	mov	r4, r4, lsr #16
-		adds	r3, r3, #0
-		bics	ip, r2, #15
-		beq	2f
-1:		load4l	r5, r6, r7, r8
-		orr	r4, r4, r5, lsl #16
-		mov	r5, r5, lsr #16
-		orr	r5, r5, r6, lsl #16
-		mov	r6, r6, lsr #16
-		orr	r6, r6, r7, lsl #16
-		mov	r7, r7, lsr #16
-		orr	r7, r7, r8, lsl #16
-		stmia	r1!, {r4, r5, r6, r7}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		adcs	r3, r3, r6
-		adcs	r3, r3, r7
-		mov	r4, r8, lsr #16
-		sub	ip, ip, #16
-		teq	ip, #0
-		bne	1b
-2:		ands	ip, r2, #12
-		beq	4f
-		tst	ip, #8
-		beq	3f
-		load2l	r5, r6
-		orr	r4, r4, r5, lsl #16
-		mov	r5, r5, lsr #16
-		orr	r5, r5, r6, lsl #16
-		stmia	r1!, {r4, r5}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		mov	r4, r6, lsr #16
-		tst	ip, #4
-		beq	4f
-3:		load1l	r5
-		orr	r4, r4, r5, lsl #16
-		str	r4, [r1], #4
-		adcs	r3, r3, r4
-		mov	r4, r5, lsr #16
-4:		ands	r2, r2, #3
-		adceq	r0, r3, #0
-		load_regs	eqea
-		tst	r2, #2
-		beq	.exit
-		adcs	r3, r3, r4, lsl #16
-		strb	r4, [r1], #1
-		mov	r4, r4, lsr #8
-		strb	r4, [r1], #1
-		tst	r2, #1
-		adceq	r0, r3, #0
-		load_regs	eqea
-		load1b	r4
-		b	.exit
-
-.src3_aligned:	mov	r4, r4, lsr #24
-		adds	r3, r3, #0
-		bics	ip, r2, #15
-		beq	2f
-1:		load4l	r5, r6, r7, r8
-		orr	r4, r4, r5, lsl #8
-		mov	r5, r5, lsr #24
-		orr	r5, r5, r6, lsl #8
-		mov	r6, r6, lsr #24
-		orr	r6, r6, r7, lsl #8
-		mov	r7, r7, lsr #24
-		orr	r7, r7, r8, lsl #8
-		stmia	r1!, {r4, r5, r6, r7}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		adcs	r3, r3, r6
-		adcs	r3, r3, r7
-		mov	r4, r8, lsr #24
-		sub	ip, ip, #16
-		teq	ip, #0
-		bne	1b
-2:		ands	ip, r2, #12
-		beq	4f
-		tst	ip, #8
-		beq	3f
-		load2l	r5, r6
-		orr	r4, r4, r5, lsl #8
-		mov	r5, r5, lsr #24
-		orr	r5, r5, r6, lsl #8
-		stmia	r1!, {r4, r5}
-		adcs	r3, r3, r4
-		adcs	r3, r3, r5
-		mov	r4, r6, lsr #24
-		tst	ip, #4
-		beq	4f
-3:		load1l	r5
-		orr	r4, r4, r5, lsl #8
-		str	r4, [r1], #4
-		adcs	r3, r3, r4
-		mov	r4, r5, lsr #24
-4:		ands	r2, r2, #3
-		adceq	r0, r3, #0
-		load_regs	eqea
-		tst	r2, #2
-		beq	.exit
-		adcs	r3, r3, r4, lsl #16
-		strb	r4, [r1], #1
-		load1l	r4
-		strb	r4, [r1], #1
-		adcs	r3, r3, r4, lsl #24
-		mov	r4, r4, lsr #8
-		b	.exit
+/*
+ * unsigned int
+ * csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *err_ptr)
+ *  r0 = src, r1 = dst, r2 = len, r3 = sum, [sp] = *err_ptr
+ *  Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT
+ */
+
+#define FN_ENTRY	ENTRY(csum_partial_copy_from_user)
+
+#include "csumpartialcopygeneric.S"
 
 /*
  * FIXME: minor buglet here
@@ -411,13 +170,13 @@
 #endif
 		.align	4
 6001:		mov	r4, #-EFAULT
-		ldr	r5, [fp, #4]
+		ldr	r5, [fp, #4]		@ *err_ptr
 		str	r4, [r5]
-		ldmia	sp, {r1, r2}		@ retrieve original arguments
+		ldmia	sp, {r1, r2}		@ retrieve dst, len
 		add	r2, r2, r1
-		mov	r3, #0			@ zero the buffer
+		mov	r0, #0			@ zero the buffer
 6002:		teq	r2, r1
-		strneb	r3, [r1], #1
+		strneb	r0, [r1], #1
 		bne	6002b
 		load_regs	ea
 #if defined(CONFIG_CPU_32)
diff -urN linux-2.4.5-pre3/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c
--- linux-2.4.5-pre3/arch/arm/mm/fault-armv.c	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/mm/fault-armv.c	Mon Dec  3 22:44:22 2001
@@ -132,7 +132,7 @@
 
 #define get8_unaligned_check(val,addr,err)		\
 	__asm__(					\
-	"1:	ldrb	%1, [%2]\n"			\
+	"1:	ldrb	%1, [%2], #1\n"			\
 	"2:\n"						\
 	"	.section .fixup,\"ax\"\n"		\
 	"	.align	2\n"				\
@@ -148,7 +148,7 @@
 
 #define get8t_unaligned_check(val,addr,err)		\
 	__asm__(					\
-	"1:	ldrbt	%1, [%2]\n"			\
+	"1:	ldrbt	%1, [%2], #1\n"			\
 	"2:\n"						\
 	"	.section .fixup,\"ax\"\n"		\
 	"	.align	2\n"				\
diff -urN linux-2.4.5-pre3/arch/arm/vmlinux-armv.lds.in linux/arch/arm/vmlinux-armv.lds.in
--- linux-2.4.5-pre3/arch/arm/vmlinux-armv.lds.in	Tue Mar  6 19:44:35 2001
+++ linux/arch/arm/vmlinux-armv.lds.in	Mon Dec  3 22:44:22 2001
@@ -44,11 +44,12 @@
 			*(.rodata)
 			*(.glue_7)
 			*(.glue_7t)
-			*(.kstrtab)
 		*(.got)			/* Global offset table		*/
 
 		_etext = .;		/* End of text section		*/
 	}
+
+	.kstrtab : { *(.kstrtab) }
 
 	. = ALIGN(16);
 	__ex_table : {			/* Exception table		*/
diff -urN linux-2.4.5-pre3/arch/cris/drivers/gpio.c linux/arch/cris/drivers/gpio.c
--- linux-2.4.5-pre3/arch/cris/drivers/gpio.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/gpio.c	Mon Dec  3 22:44:22 2001
@@ -1,4 +1,4 @@
-/* $Id: gpio.c,v 1.4 2001/02/27 13:52:48 bjornw Exp $
+/* $Id: gpio.c,v 1.7 2001/04/04 13:30:08 matsfg Exp $
  *
  * Etrax general port I/O device
  *
@@ -9,6 +9,15 @@
  *             Johan Adolfsson  (read/set directions)
  *
  * $Log: gpio.c,v $
+ * Revision 1.7  2001/04/04 13:30:08  matsfg
+ * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping
+ *
+ * Revision 1.6  2001/03/26 16:03:06  bjornw
+ * Needs linux/config.h
+ *
+ * Revision 1.5  2001/03/26 14:22:03  bjornw
+ * Namechange of some config options
+ *
  * Revision 1.4  2001/02/27 13:52:48  bjornw
  * malloc.h -> slab.h
  *
@@ -25,6 +34,7 @@
  */
 
 #include <linux/config.h>
+
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -78,25 +88,25 @@
 	&port_pa_data_shadow, &port_pb_data_shadow };
 
 /* What direction bits that are user changeable 1=changeable*/
-#ifndef CONFIG_PA_CHANGEABLE_DIR
-#define CONFIG_PA_CHANGEABLE_DIR 0x00
+#ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR
+#define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00
 #endif
-#ifndef CONFIG_PB_CHANGEABLE_DIR
-#define CONFIG_PB_CHANGEABLE_DIR 0x00
+#ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR
+#define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00
 #endif
 
-#ifndef CONFIG_PA_CHANGEABLE_BITS
-#define CONFIG_PA_CHANGEABLE_BITS 0xFF
+#ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS
+#define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF
 #endif
-#ifndef CONFIG_PB_CHANGEABLE_BITS
-#define CONFIG_PB_CHANGEABLE_BITS 0xFF
+#ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS
+#define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF
 #endif
 
 
-static unsigned char changeable_dir[2] = { CONFIG_PA_CHANGEABLE_DIR,
-                                           CONFIG_PB_CHANGEABLE_DIR };
-static unsigned char changeable_bits[2] = { CONFIG_PA_CHANGEABLE_BITS,
-                                            CONFIG_PB_CHANGEABLE_BITS };
+static unsigned char changeable_dir[2] = { CONFIG_ETRAX_PA_CHANGEABLE_DIR,
+                                           CONFIG_ETRAX_PB_CHANGEABLE_DIR };
+static unsigned char changeable_bits[2] = { CONFIG_ETRAX_PA_CHANGEABLE_BITS,
+                                            CONFIG_ETRAX_PB_CHANGEABLE_BITS };
 
 static volatile unsigned char *dir[2] = { R_PORT_PA_DIR, R_PORT_PB_DIR };
 
@@ -240,7 +250,7 @@
 		default:
 			if(priv->minor == LEDS)
 				return gpio_leds_ioctl(cmd, arg);
-			else
+                        else
 				return -EINVAL;
 	}
 	
@@ -252,7 +262,12 @@
 {
 	unsigned char green;
 	unsigned char red;
-
+        static int initialized = 0;
+        if(!initialized)
+        {
+          initialized = 1;
+          init_ioremap();
+        }
 	switch (_IOC_NR(cmd)) {
 		case IO_LEDACTIVE_SET:
 			green = ((unsigned char) arg) & 1;
@@ -260,6 +275,11 @@
 			LED_ACTIVE_SET_G(green);
 			LED_ACTIVE_SET_R(red);
 			break;
+                case IO_LED_SETBIT:                 
+                        LED_BIT_SET(arg);
+                       break;
+                case IO_LED_CLRBIT:
+                        LED_BIT_CLR(arg);
 		default:
 			return -EINVAL;
 	}
diff -urN linux-2.4.5-pre3/arch/cris/drivers/i2c.c linux/arch/cris/drivers/i2c.c
--- linux-2.4.5-pre3/arch/cris/drivers/i2c.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/i2c.c	Mon Dec  3 22:44:22 2001
@@ -12,6 +12,12 @@
 *!                                 don't use PB_I2C if DS1302 uses same bits,
 *!                                 use PB.
 *! $Log: i2c.c,v $
+*! Revision 1.7  2001/04/04 13:11:36  markusl
+*! Updated according to review remarks
+*!
+*! Revision 1.6  2001/03/19 12:43:00  markusl
+*! Made some symbols unstatic (used by the eeprom driver)
+*!
 *! Revision 1.5  2001/02/27 13:52:48  bjornw
 *! malloc.h -> slab.h
 *!
@@ -37,7 +43,7 @@
 *! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
-/* $Id: i2c.c,v 1.5 2001/02/27 13:52:48 bjornw Exp $ */
+/* $Id: i2c.c,v 1.7 2001/04/04 13:11:36 markusl Exp $ */
 /****************** INCLUDE FILES SECTION ***********************************/
 
 #include <linux/module.h>
@@ -144,50 +150,50 @@
 
 /* generate i2c start condition */
 
-static void
+void
 i2c_start(void)
 {
-	//
-	// SCL=1 SDA=1
-	//
+	/*
+	 * SCL=1 SDA=1
+	 */
 	i2c_dir_out();
 	i2c_delay(CLOCK_HIGH_TIME/6);
 	i2c_data(I2C_DATA_HIGH);
 	i2c_clk(I2C_CLOCK_HIGH);
 	i2c_delay(CLOCK_HIGH_TIME);
-	//
-	// SCL=1 SDA=0
-	//
+	/*
+	 * SCL=1 SDA=0
+	 */
 	i2c_data(I2C_DATA_LOW);
 	i2c_delay(START_CONDITION_HOLD_TIME);
-	//
-	// SCL=0 SDA=0
-	//
+	/*
+	 * SCL=0 SDA=0
+	 */
 	i2c_clk(I2C_CLOCK_LOW);
 	i2c_delay(CLOCK_LOW_TIME);
 }
 
 /* generate i2c stop condition */
 
-static void
+void
 i2c_stop(void)
 {
 	i2c_dir_out();
 
-	//
-	// SCL=0 SDA=0
-	//
+	/*
+	 * SCL=0 SDA=0
+	 */
 	i2c_clk(I2C_CLOCK_LOW);
 	i2c_data(I2C_DATA_LOW);
 	i2c_delay(CLOCK_LOW_TIME*2);
-	//
-	// SCL=1 SDA=0
-	//
+	/*
+	 * SCL=1 SDA=0
+	 */
 	i2c_clk(I2C_CLOCK_HIGH);
 	i2c_delay(CLOCK_HIGH_TIME*2);
-	//
-	// SCL=1 SDA=1
-	//
+	/*
+	 * SCL=1 SDA=1
+	 */
 	i2c_data(I2C_DATA_HIGH);
 	i2c_delay(STOP_CONDITION_HOLD_TIME);
 
@@ -196,7 +202,7 @@
 
 /* write a byte to the i2c interface */
 
-static void
+void
 i2c_outbyte(unsigned char x)
 {
 	int i;
@@ -219,78 +225,75 @@
 	i2c_data(I2C_DATA_LOW);
 	i2c_delay(CLOCK_LOW_TIME/2);
 
-	//
-	// enable input
-	//
+	/*
+	 * enable input
+	 */
 	i2c_dir_in();
 }
 
 /* read a byte from the i2c interface */
 
-static unsigned char
+unsigned char
 i2c_inbyte(void)
 {
 	unsigned char aBitByte = 0;
 	int i;
 	int iaa;
-	//int dd= 0;
 
-	//
-	// enable output
-	//
+	/*
+	 * enable output
+	 */
 	i2c_dir_out();
-	//
-	// Release data bus by setting
-	// data high
-	//
+	/*
+	 * Release data bus by setting
+	 * data high
+	 */
 	i2c_data(I2C_DATA_HIGH);
-	//
-	// enable input
-	//
+	/*
+	 * enable input
+	 */
 	i2c_dir_in();
-	//
-	// Use PORT PB instead of I2C
-	// for input. (I2C not working)
-	//
+	/*
+	 * Use PORT PB instead of I2C
+	 * for input. (I2C not working)
+	 */
 	i2c_clk(1);
 	i2c_data(1);
-/*	*R_PORT_PB_DATA = *R_PORT_PB_READ | 0x03;*/
-	//
-	// get bits
-	//
+	/*
+	 * get bits
+	 */
 	for (i = 0; i < 8; i++) {
 		i2c_delay(CLOCK_LOW_TIME/2);
-		//
-		// low clock period
-		//
+		/*
+		 * low clock period
+		 */
 		i2c_clk(I2C_CLOCK_HIGH);
-		//
-		// switch off I2C
-		//
+		/*
+		 * switch off I2C
+		 */
 		i2c_data(1);
 		i2c_disable();
 		i2c_dir_in();
-		//
-		// wait before getting bit
-		//
+		/*
+		 * wait before getting bit
+		 */
 		i2c_delay(CLOCK_HIGH_TIME/2);
 		aBitByte = (aBitByte << 1);
 		iaa = i2c_getbit();
 		aBitByte = aBitByte | iaa ;
-		//if (iaa > 0) dd++;
-		//
-		// wait
-		//
+		/*
+		 * wait
+		 */
 		i2c_delay(CLOCK_HIGH_TIME/2);
-		//
-		// end clock puls
-		//
+		/*
+		 * end clock puls
+		 */
 		i2c_enable();
 		i2c_dir_out();
 		i2c_clk(I2C_CLOCK_LOW);
-		//
-		// low clock period
-		//
+		/*
+		 * low clock period
+		 */
 		i2c_delay(CLOCK_LOW_TIME/2);
 	}
 	i2c_dir_out();
@@ -305,49 +308,47 @@
 *#
 *#--------------------------------------------------------------------------*/
 
-static int
+int
 i2c_getack(void)
 {
 	int ack = 1;
-	//
-	// enable output
-	//
+	/*
+	 * enable output
+	 */
 	i2c_dir_out();
-	//
-	// Release data bus by setting
-	// data high
-	//
+	/*
+	 * Release data bus by setting
+	 * data high
+	 */
 	i2c_data(I2C_DATA_HIGH);
-	//
-	// enable input
-	//
+	/*
+	 * enable input
+	 */
 	i2c_dir_in();
 	i2c_delay(CLOCK_HIGH_TIME/4);
-	//
-	// generate ACK clock pulse
-	//
+	/*
+	 * generate ACK clock pulse
+	 */
 	i2c_clk(I2C_CLOCK_HIGH);
-	//
-	// Use PORT PB instead of I2C
-	// for input. (I2C not working)
-	//
+	/*
+	 * Use PORT PB instead of I2C
+	 * for input. (I2C not working)
+	 */
 	i2c_clk(1);
 	i2c_data(1);
-  
-/*	*R_PORT_PB_DATA = *R_PORT_PB_READ | 0x03;*/
-	//
-	// switch off I2C
-	//
+	/*
+	 * switch off I2C
+	 */
 	i2c_data(1);
 	i2c_disable();
 	i2c_dir_in();
-	//
-	// now wait for ack
-	//
+	/*
+	 * now wait for ack
+	 */
 	i2c_delay(CLOCK_HIGH_TIME/2);
-	//
-	// check for ack
-	//
+	/*
+	 * check for ack
+	 */
 	if(i2c_getbit())
 		ack = 0;
 	i2c_delay(CLOCK_HIGH_TIME/2);
@@ -357,20 +358,20 @@
 		i2c_delay(CLOCK_HIGH_TIME/2);
 	}
 
-	//
-	// end clock pulse
-	//
+	/*
+	 * end clock pulse
+	 */
 	i2c_enable();
 	i2c_dir_out();
 	i2c_clk(I2C_CLOCK_LOW);
 	i2c_delay(CLOCK_HIGH_TIME/4);
-	//
-	// enable output
-	//
+	/*
+	 * enable output
+	 */
 	i2c_dir_out();
-	//
-	// remove ACK clock pulse
-	//
+	/*
+	 * remove ACK clock pulse
+	 */
 	i2c_data(I2C_DATA_HIGH);
 	i2c_delay(CLOCK_LOW_TIME/2);
 	return ack;
@@ -383,32 +384,32 @@
 *# DESCRIPTION  : Send ACK on received data
 *#
 *#--------------------------------------------------------------------------*/
-static void
+void
 i2c_sendack(void)
 {
-	//
-	// enable output
-	//
+	/*
+	 * enable output
+	 */
 	i2c_delay(CLOCK_LOW_TIME);
 	i2c_dir_out();
-	//
-	// set ack pulse high
-	//
+	/*
+	 * set ack pulse high
+	 */
 	i2c_data(I2C_DATA_LOW);
-	//
-	// generate clock pulse
-	//
+	/*
+	 * generate clock pulse
+	 */
 	i2c_delay(CLOCK_HIGH_TIME/6);
 	i2c_clk(I2C_CLOCK_HIGH);
 	i2c_delay(CLOCK_HIGH_TIME);
 	i2c_clk(I2C_CLOCK_LOW);
 	i2c_delay(CLOCK_LOW_TIME/6);
-	//
-	// reset data out
-	//
+	/*
+	 * reset data out
+	 */
 	i2c_data(I2C_DATA_HIGH);
 	i2c_delay(CLOCK_LOW_TIME);
-	//
+	
 	i2c_dir_in();
 }
 
@@ -424,20 +425,22 @@
 	     unsigned char theValue)
 {
 	int error, cntr = 3;
+	unsigned long flags;
 		
 	do {
 		error = 0;
-		//
-		// we don't like to be interrupted
-		//
+		/*
+		 * we don't like to be interrupted
+		 */
+		save_flags(flags);
 		cli();
-		//
-		// generate start condition
-		//
+		/*
+		 * generate start condition
+		 */
 		i2c_start();
-		//
-		// dummy preamble
-		//
+		/*
+		 * dummy preamble
+		 */
 		i2c_outbyte(0x01);
 		i2c_data(I2C_DATA_HIGH);
 		i2c_clk(I2C_CLOCK_HIGH);
@@ -452,42 +455,42 @@
 		i2c_delay(CLOCK_LOW_TIME);
 
 		i2c_start();
-		//
-		// send slave address
-		//
+		/*
+		 * send slave address
+		 */
 		i2c_outbyte(theSlave);
-		//
-		// wait for ack
-		//
+		/*
+		 * wait for ack
+		 */
 		if(!i2c_getack())
 			error = 1;
-		//
-		// now select register
-		//
+		/*
+		 * now select register
+		 */
 		i2c_dir_out();
 		i2c_outbyte(theReg);
-		//
-		// now it's time to wait for ack
-		//
+		/*
+		 * now it's time to wait for ack
+		 */
 		if(!i2c_getack())
 			error |= 2;
-		//
-		// send register register data
-		//
+		/*
+		 * send register register data
+		 */
 		i2c_outbyte(theValue);
-		//
-		// now it's time to wait for ack
-		//
+		/*
+		 * now it's time to wait for ack
+		 */
 		if(!i2c_getack())
 			error |= 4;
-		//
-		// end byte stream
-		//
+		/*
+		 * end byte stream
+		 */
 		i2c_stop();
-		//
-		// enable interrupt again
-		//
-		sti();
+		/*
+		 * enable interrupt again
+		 */
+		restore_flags(flags);
 		
 	} while(error && cntr--);
 	
@@ -508,20 +511,22 @@
 {
 	unsigned char b = 0;
 	int error, cntr = 3;
+	unsigned long flags;
 		
 	do {
 		error = 0;
-		//
-		// we don't like to be interrupted
-		//
+		/*
+		 * we don't like to be interrupted
+		 */
+		save_flags(flags);
 		cli();
-		//
-		// generate start condition
-		//
+		/*
+		 * generate start condition
+		 */
 		i2c_start();
-		//
-		// dummy preamble
-		//
+		/*
+		 * dummy preamble
+		 */
 		i2c_outbyte(0x01);
 		i2c_data(I2C_DATA_HIGH);
 		i2c_clk(I2C_CLOCK_HIGH);
@@ -537,55 +542,56 @@
     
 		i2c_start();
     
-		//
-		// send slave address
-		//
+		/*
+		 * send slave address
+		 */
 		i2c_outbyte(theSlave);
-		//
-		// wait for ack
-		//
+		/*
+		 * wait for ack
+		 */
 		if(!i2c_getack())
 			error = 1;
-		//
-		// now select register
-		//
+		/*
+		 * now select register
+		 */
 		i2c_dir_out();
 		i2c_outbyte(theReg);
-		//
-		// now it's time to wait for ack
-		//
+		/*
+		 * now it's time to wait for ack
+		 */
 		if(!i2c_getack())
 			error = 1;
-		//
-		// repeat start condition
-		//
+		/*
+		 * repeat start condition
+		 */
 		i2c_delay(CLOCK_LOW_TIME);
 		i2c_start();
-		//
-		// send slave address
-		//
+		/*
+		 * send slave address
+		 */
 		i2c_outbyte(theSlave | 0x01);
-		//
-		// wait for ack
-		//
+		/*
+		 * wait for ack
+		 */
 		if(!i2c_getack())
 			error = 1;
-		//
-		// fetch register
-		//
+		/*
+		 * fetch register
+		 */
 		b = i2c_inbyte();
-		//
-		// send Ack
-		//
+		/*
+		 * send Ack
+		 */
 		i2c_sendack();
-		//
-		// end sequence
-		//
+		/*
+		 * end sequence
+		 */
 		i2c_stop();
-		//
-		// enable interrupt again
-		//
-		sti();	
+		/*
+		 * enable interrupt again
+		 */
+		restore_flags(flags);
+		
 	} while(error && cntr--);
 
 	return b;
@@ -616,7 +622,7 @@
 
 	switch (_IOC_NR(cmd)) {
 		case I2C_WRITEREG:
-			// write to an i2c slave
+			/* write to an i2c slave */
 			D(printk("i2cw %d %d %d\n", 
 				 I2C_ARGSLAVE(arg),
 				 I2C_ARGREG(arg),
@@ -628,7 +634,7 @@
 		case I2C_READREG:
 		{
 			unsigned char val;
-			// read from an i2c slave
+			/* read from an i2c slave */
 			D(printk("i2cr %d %d ", 
 				I2C_ARGSLAVE(arg),
 				I2C_ARGREG(arg)));
@@ -682,6 +688,8 @@
 	}
 
 	printk("I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n");
+	
+	return 0;
 }
 
 /* this makes sure that i2c_init is called during boot */
diff -urN linux-2.4.5-pre3/arch/cris/drivers/i2c.h linux/arch/cris/drivers/i2c.h
--- linux-2.4.5-pre3/arch/cris/drivers/i2c.h	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/i2c.h	Mon Dec  3 22:44:22 2001
@@ -1,16 +1,16 @@
-/* $Id: i2c.h,v 1.2 2001/01/18 15:49:30 bjornw Exp $ */
+/* $Id: i2c.h,v 1.3 2001/03/19 12:43:01 markusl Exp $ */
 
 /* High level I2C actions */
 int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue);
 unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg);
 
 /* Low level I2C */
-static void i2c_start(void);
-static void i2c_stop(void);
-static void i2c_outbyte(unsigned char x);
-static unsigned char i2c_inbyte(void);
-static int i2c_getack(void);
-static void i2c_sendack(void);
+void i2c_start(void);
+void i2c_stop(void);
+void i2c_outbyte(unsigned char x);
+unsigned char i2c_inbyte(void);
+int i2c_getack(void);
+void i2c_sendack(void);
 
 
 
diff -urN linux-2.4.5-pre3/arch/i386/kernel/bluesmoke.c linux/arch/i386/kernel/bluesmoke.c
--- linux-2.4.5-pre3/arch/i386/kernel/bluesmoke.c	Wed Apr 11 19:02:27 2001
+++ linux/arch/i386/kernel/bluesmoke.c	Mon Dec  3 22:44:22 2001
@@ -1,16 +1,18 @@
-/*
- *	Machine Check Handler For PII/PIII
- */
 
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <asm/processor.h> 
 #include <asm/msr.h>
 
+/*
+ *	Machine Check Handler For PII/PIII
+ */
+
 static int banks;
 
-void do_machine_check(struct pt_regs * regs, long error_code)
+static void intel_machine_check(struct pt_regs * regs, long error_code)
 {
 	int recover=1;
 	u32 alow, ahigh, high, low;
@@ -62,28 +64,101 @@
 	wrmsr(0x17a,mcgstl, mcgsth);
 }
 
+/*
+ *	Machine check handler for Pentium class Intel
+ */
+ 
+static void pentium_machine_check(struct pt_regs * regs, long error_code)
+{
+	u32 loaddr, hi, lotype;
+	rdmsr(0x0, loaddr, hi);
+	rdmsr(0x1, lotype, hi);
+	printk(KERN_EMERG "CPU#%d: Machine Check Exception:  0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype);
+	if(lotype&(1<<5))
+		printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id());
+}
 
 /*
- *	This has to be run for each processor
+ *	Machine check handler for WinChip C6
+ */
+ 
+static void winchip_machine_check(struct pt_regs * regs, long error_code)
+{
+	printk(KERN_EMERG "CPU#%d: Machine Check Exception.\n", smp_processor_id());
+}
+
+/*
+ *	Handle unconfigured int18 (should never happen)
  */
+
+static void unexpected_machine_check(struct pt_regs * regs, long error_code)
+{	
+	printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id());
+}
+
+/*
+ *	Call the installed machine check handler for this CPU setup.
+ */ 
  
-void mcheck_init(struct cpuinfo_x86 *c)
+static void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
+
+void do_machine_check(struct pt_regs * regs, long error_code)
+{
+	machine_check_vector(regs, error_code);
+}
+
+/*
+ *	Set up machine check reporting for Intel processors
+ */
+
+void __init intel_mcheck_init(struct cpuinfo_x86 *c)
 {
 	u32 l, h;
 	int i;
 	static int done;
-
-	if( c->x86_vendor != X86_VENDOR_INTEL )
-		return;
 	
+	/*
+	 *	Check for MCE support
+	 */
+
 	if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) )
+		return;	
+	
+	/*
+	 *	Pentium machine check
+	 */
+	
+	if(c->x86 == 5)
+	{
+		machine_check_vector = pentium_machine_check;
+		wmb();
+		/* Read registers before enabling */
+		rdmsr(0x0, l, h);
+		rdmsr(0x1, 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");
+		printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id());
 		return;
-		
+	}
+	
+
+	/*
+	 *	Check for PPro style MCA
+	 */
+	 		
 	if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) )
 		return;
 		
 	/* Ok machine check is available */
 	
+	machine_check_vector = intel_machine_check;
+	wmb();
+	
 	if(done==0)
 		printk(KERN_INFO "Intel machine check architecture supported.\n");
 	rdmsr(0x179, l, h);
@@ -104,4 +179,53 @@
 		"movl %%eax, %%cr4\n\t" : : : "eax");
 	printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id());
 	done=1;
+}
+
+/*
+ *	Set up machine check reporting on the Winchip C6 series
+ */
+ 
+static void winchip_mcheck_init(struct cpuinfo_x86 *c)
+{
+	u32 lo, hi;
+	/* Not supported on C3 */
+	if(c->x86 != 5)
+		return;
+	/* Winchip C6 */
+	machine_check_vector = winchip_machine_check;
+	wmb();
+	rdmsr(0x107, lo, hi);
+	lo|= (1<<2);	/* Enable EIERRINT (int 18 MCE) */
+	lo&= ~(1<<4);	/* Enable MCE */
+	wrmsr(0x107, lo, hi);
+	__asm__ __volatile__ (
+		"movl %%cr4, %%eax\n\t"
+		"orl $0x40, %%eax\n\t"
+		"movl %%eax, %%cr4\n\t" : : : "eax");
+	printk(KERN_INFO "Winchip machine check reporting enabled on CPU#%d.\n", smp_processor_id());
+}
+
+
+/*
+ *	This has to be run for each processor
+ */
+
+void __init mcheck_init(struct cpuinfo_x86 *c)
+{
+	switch(c->x86_vendor)
+	{
+		case X86_VENDOR_AMD:
+			/*
+			 *	AMD K7 machine check is Intel like
+			 */
+			if(c->x86 == 6)
+				intel_mcheck_init(c);
+			break;
+		case X86_VENDOR_INTEL:
+			intel_mcheck_init(c);
+			break;
+		case X86_VENDOR_CENTAUR:
+			winchip_mcheck_init(c);
+			break;
+	}
 }
diff -urN linux-2.4.5-pre3/arch/i386/kernel/pci-i386.c linux/arch/i386/kernel/pci-i386.c
--- linux-2.4.5-pre3/arch/i386/kernel/pci-i386.c	Mon Aug  7 14:31:40 2000
+++ linux/arch/i386/kernel/pci-i386.c	Mon Dec  3 22:44:22 2001
@@ -350,3 +350,35 @@
 	printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
 	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
 }
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state, int write_combine)
+{
+	unsigned long prot;
+
+	/* I/O space cannot be accessed via normal processor loads and
+	 * stores on this platform.
+	 */
+	if (mmap_state == pci_mmap_io)
+		return -EINVAL;
+
+	/* Leave vm_pgoff as-is, the PCI space address is the physical
+	 * address on this platform.
+	 */
+	vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
+
+	prot = pgprot_val(vma->vm_page_prot);
+	if (boot_cpu_data.x86 > 3)
+		prot |= _PAGE_PCD | _PAGE_PWT;
+	vma->vm_page_prot = __pgprot(prot);
+
+	/* Write-combine setting is ignored, it is changed via the mtrr
+	 * interfaces on this platform.
+	 */
+	if (remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+			     vma->vm_end - vma->vm_start,
+			     vma->vm_page_prot))
+		return -EAGAIN;
+
+	return 0;
+}
diff -urN linux-2.4.5-pre3/arch/m68k/lib/semaphore.S linux/arch/m68k/lib/semaphore.S
--- linux-2.4.5-pre3/arch/m68k/lib/semaphore.S	Wed Jan 26 12:44:20 2000
+++ linux/arch/m68k/lib/semaphore.S	Mon Dec  3 22:44:22 2001
@@ -51,49 +51,3 @@
 	moveml (%sp)+,%a0/%d0/%d1
 	rts
 
-ENTRY(__down_read_failed)
-	moveml %a0/%d0/%d1,-(%sp)
-	jcc 3f
-1:	movel %a1,-(%sp)
-	jbsr SYMBOL_NAME(down_read_failed_biased)
-	movel (%sp)+,%a1
-2:	moveml (%sp)+,%a0/%d0/%d1
-	rts
-
-3:	movel %a1,-(%sp)
-	jbsr SYMBOL_NAME(down_read_failed)
-	movel (%sp)+,%a1
-	subql #1,%a1@
-	jpl 2b
-	jcc 3b
-	jra 1b
-
-ENTRY(__down_write_failed)
-	moveml %a0/%d0/%d1,-(%sp)
-	jcc 3f
-1:	movel %a1,-(%sp)
-	jbsr SYMBOL_NAME(down_write_failed_biased)
-	movel (%sp)+,%a1
-2:	moveml (%sp)+,%a0/%d0/%d1
-	rts
-
-3:	movel %a1,-(%sp)
-	jbsr SYMBOL_NAME(down_write_failed)
-	movel (%sp)+,%a1
-	subl #RW_LOCK_BIAS,%a1@
-	jpl 2b
-	jcc 3b
-	jra 1b
-
-ENTRY(__rwsem_wake)
-	moveml %a0/%d0/%d1,-(%sp)
-	jeq 1f
-	movel %a1,-(%sp)
-	jbsr SYMBOL_NAME(rwsem_wake_readers)
-	jra 2f
-1:	movel %a1,-(%sp)
-	jbsr rwsem_wake_writer
-2:	movel (%sp)+,%a1
-	moveml (%sp)+,%a0/%d0/%d1
-	rts
-
diff -urN linux-2.4.5-pre3/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- linux-2.4.5-pre3/arch/m68k/mm/memory.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/m68k/mm/memory.c	Mon Dec  3 22:44:22 2001
@@ -246,6 +246,10 @@
 		voff -= m68k_memory[i].size;
 	} while (++i < m68k_num_memory);
 
+	/* As a special case allow `__pa(high_memory)'.  */
+	if (voff == 0)
+		return m68k_memory[i-1].addr + m68k_memory[i-1].size;
+
 	return mm_vtop_fallback(vaddr);
 }
 #endif
diff -urN linux-2.4.5-pre3/arch/ppc/Makefile linux/arch/ppc/Makefile
--- linux-2.4.5-pre3/arch/ppc/Makefile	Mon Dec  3 22:43:49 2001
+++ linux/arch/ppc/Makefile	Mon Dec  3 22:44:22 2001
@@ -141,48 +141,9 @@
 	@$(MAKECHRPBOOT) $@
 endif
 
-.PHONY: clean_config
-clean_config:
+%_config: arch/ppc/configs/%_defconfig
 	rm -f .config arch/ppc/defconfig
-
-gemini_config: clean_config
-	cp -f arch/ppc/configs/gemini_defconfig arch/ppc/defconfig
-
-pmac_config: clean_config
-	cp -f arch/ppc/configs/pmac_defconfig arch/ppc/defconfig
-
-prep_config: clean_config
-	cp -f arch/ppc/configs/prep_defconfig arch/ppc/defconfig
-
-chrp_config: clean_config
-	cp -f arch/ppc/configs/chrp_defconfig arch/ppc/defconfig
-
-common_config: clean_config
-	cp -f arch/ppc/configs/common_defconfig arch/ppc/defconfig
-
-mbx_config: clean_config
-	cp -f arch/ppc/configs/mbx_defconfig arch/ppc/defconfig
-
-apus_config: clean_config
-	cp -f arch/ppc/configs/apus_defconfig arch/ppc/defconfig
-
-oak_config: clean_config
-	cp -f arch/ppc/configs/oak_defconfig arch/ppc/defconfig
-
-walnut_config: clean_config
-	cp -f arch/ppc/configs/walnut_defconfig arch/ppc/defconfig
-
-rpxlite_config: clean_config
-	cp -f arch/ppc/configs/rpxlite_defconfig arch/ppc/defconfig
-
-rpxcllf_config: clean_config
-	cp -f arch/ppc/configs/rpxcllf_defconfig arch/ppc/defconfig
-
-bseip_config: clean_config
-	cp -f arch/ppc/configs/bseip_defconfig arch/ppc/defconfig
-
-est8260_config: clean_config
-	cp -f arch/ppc/configs/est8260_defconfig arch/ppc/defconfig
+	cp -f arch/ppc/configs/$(@:config=defconfig) arch/ppc/defconfig
 
 archclean:
 	rm -f arch/ppc/kernel/{mk_defs,ppc_defs.h,find_name,checks}
diff -urN linux-2.4.5-pre3/arch/ppc/amiga/Makefile linux/arch/ppc/amiga/Makefile
--- linux-2.4.5-pre3/arch/ppc/amiga/Makefile	Fri Dec 29 14:07:20 2000
+++ linux/arch/ppc/amiga/Makefile	Mon Dec  3 22:44:22 2001
@@ -14,6 +14,6 @@
 obj-y		:= config.o amiints.o cia.o time.o bootinfo.o amisound.o \
 			chipram.o amiga_ksyms.o
 
-obj-$(CONFIG_AMIGA_PCMCIA) += pcmia.o
+obj-$(CONFIG_AMIGA_PCMCIA) += pcmcia.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.5-pre3/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c
--- linux-2.4.5-pre3/arch/ppc/amiga/amiints.c	Fri Feb 16 16:02:34 2001
+++ linux/arch/ppc/amiga/amiints.c	Mon Dec  3 22:44:22 2001
@@ -255,9 +255,10 @@
 		return;
 	}
 
-	if (irq >= IRQ_AMIGA_AUTO)
+	if (irq >= IRQ_AMIGA_AUTO) {
 		sys_free_irq(irq - IRQ_AMIGA_AUTO, dev_id);
-
+		return;
+	}
 	if (irq >= IRQ_AMIGA_CIAA) {
 		cia_free_irq(irq, dev_id);
 		return;
@@ -295,7 +296,10 @@
 		return;
 	}
 
-	if (--ami_ablecount[irq])
+	ami_ablecount[irq]--;
+	if (ami_ablecount[irq]<0)
+		ami_ablecount[irq]=0;
+	else if (ami_ablecount[irq])
 		return;
 
 	/* No action for auto-vector interrupts */
@@ -347,64 +351,16 @@
 	ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp);
 }
 
-void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server)
+void amiga_do_irq_list(int irq, struct pt_regs *fp)
 {
-	irq_node_t *node, *slow_nodes;
-	unsigned short intena;
-	unsigned long flags;
+	irq_node_t *node;
 
 	kstat.irqs[0][SYS_IRQS + irq]++;
-	if (server->count++)
-		server->reentrance = 1;
 
-	intena = ami_intena_vals[irq];
-	custom.intreq = intena;
-
-	/* serve first fast handlers - there can only be one of these */
-	node = ami_irq_list[irq];
-
-	/*
-	 * Timer interrupts show up like this
-	 */
-	if (!node) {
-		server->count--;
-		return;
-	}
+	custom.intreq = ami_intena_vals[irq];
 
-	if (node && (node->flags & SA_INTERRUPT)) {
-		save_flags(flags);
-		cli();
+	for (node = ami_irq_list[irq]; node; node = node->next)
 		node->handler(irq, node->dev_id, fp);
-		restore_flags(flags);
-
-		server->count--;
-		return;
-	}
-
-	/*
-	 * Disable the interrupt source in question and reenable all
-	 * other interrupts. No interrupt handler should ever touch
-	 * the intena flags directly!
-	 */
-	custom.intena = intena;
-	save_flags(flags);
-	sti();
-
-	slow_nodes = node;
-	for (;;) {
-		for (; node; node = node->next)
-			node->handler(irq, node->dev_id, fp);
-
-		if (!server->reentrance) {
-			server->count--;
-			restore_flags(flags);
-			custom.intena = IF_SETCLR | intena;
-			return;
-		}
-
-		server->reentrance = 0;
-		node = slow_nodes;
-	}
 }
 
 /*
@@ -437,7 +393,6 @@
 static void ami_int3(int irq, void *dev_id, struct pt_regs *fp)
 {
 	unsigned short ints = custom.intreqr & custom.intenar;
-	static struct irq_server server = {0, 0};
 
 	/* if a blitter interrupt */
 	if (ints & IF_BLIT) {
@@ -453,7 +408,7 @@
 
 	/* if a vertical blank interrupt */
 	if (ints & IF_VERTB)
-		amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server);
+		amiga_do_irq_list(IRQ_AMIGA_VERTB, fp);
 }
 
 static void ami_int4(int irq, void *dev_id, struct pt_regs *fp)
@@ -512,7 +467,7 @@
    and executes them in a loop. Having ami_badint at the end of the chain
    is a bad idea. */
 void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-	NULL, ami_int1, NULL, NULL /* FB expects to replace ami_int3*/,
+	NULL, ami_int1, NULL, ami_int3,
 	ami_int4, ami_int5, NULL, ami_int7
 };
 #else
diff -urN linux-2.4.5-pre3/arch/ppc/amiga/chipram.c linux/arch/ppc/amiga/chipram.c
--- linux-2.4.5-pre3/arch/ppc/amiga/chipram.c	Tue Jul 11 11:18:53 2000
+++ linux/arch/ppc/amiga/chipram.c	Mon Dec  3 22:44:22 2001
@@ -1,183 +1 @@
-/*
-**  linux/amiga/chipram.c
-**
-**      Modified 03-May-94 by Geert Uytterhoeven <geert@linux-m68k.org>
-**          - 64-bit aligned allocations for full AGA compatibility
-*/
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/zorro.h>
-#include <asm/amigahw.h>
-
-struct chip_desc {
-	unsigned first   :  1;
-	unsigned last    :  1;
-	unsigned alloced :  1;
-	unsigned length  : 24;
-	long pad;					/* We suppose this makes this struct 64 bits long!! */
-};
-
-#define DP(ptr) ((struct chip_desc *)(ptr))
-
-u_long amiga_chip_size;
-static unsigned long chipavail;
-
-static struct resource chipram = { "Chip RAM", 0 };
-
-unsigned long amiga_chip_avail( void )
-{
-#ifdef DEBUG
-	printk("chip_avail : %ld bytes\n",chipavail);
-#endif
-	return chipavail;
-}
-
-
-void __init amiga_chip_init (void)
-{
-  struct chip_desc *dp;
-
-  if (!AMIGAHW_PRESENT(CHIP_RAM))
-    return;
-
-#ifndef CONFIG_APUS_FAST_EXCEPT
-  /*
-   * Remove the first 4 pages where PPC exception handlers will
-   * be located.
-   */
-  amiga_chip_size -= 0x4000;
-#endif
-  chipram.end = amiga_chip_size-1;
-  request_resource(&iomem_resource, &chipram);
-
-  /* initialize start boundary */
-
-  dp = DP(chipaddr);
-  dp->first = 1;
-
-  dp->alloced = 0;
-  dp->length = amiga_chip_size - 2*sizeof(*dp);
-
-  /* initialize end boundary */
-  dp = DP(chipaddr + amiga_chip_size) - 1;
-  dp->last = 1;
-  
-  dp->alloced = 0;
-  dp->length = amiga_chip_size - 2*sizeof(*dp);
-  chipavail = dp->length;  /*MILAN*/
-
-#ifdef DEBUG
-  printk ("chipram end boundary is %p, length is %d\n", dp,
-	  dp->length);
-#endif
-}
-
-void *amiga_chip_alloc(long size, const char *name)
-{
-	/* last chunk */
-	struct chip_desc *dp;
-	void *ptr;
-
-	/* round off */
-	size = (size + 7) & ~7;
-
-#ifdef DEBUG
-   printk("amiga_chip_alloc: allocate %ld bytes\n", size);
-#endif
-
-	/*
-	 * get pointer to descriptor for last chunk by 
-	 * going backwards from end chunk
-	 */
-	dp = DP(chipaddr + amiga_chip_size) - 1;
-	dp = DP((unsigned long)dp - dp->length) - 1;
-	
-	while ((dp->alloced || dp->length < size)
-	       && !dp->first)
-		dp = DP ((unsigned long)dp - dp[-1].length) - 2;
-
-	if (dp->alloced || dp->length < size) {
-		printk ("no chipmem available for %ld allocation\n", size);
-		return NULL;
-	}
-
-	if (dp->length < (size + 2*sizeof(*dp))) {
-		/* length too small to split; allocate the whole thing */
-		dp->alloced = 1;
-		ptr = (void *)(dp+1);
-		dp = DP((unsigned long)ptr + dp->length);
-		dp->alloced = 1;
-#ifdef DEBUG
-		printk ("amiga_chip_alloc: no split\n");
-#endif
-	} else {
-		/* split the extent; use the end part */
-		long newsize = dp->length - (2*sizeof(*dp) + size);
-
-#ifdef DEBUG
-		printk ("amiga_chip_alloc: splitting %d to %ld\n", dp->length,
-			newsize);
-#endif
-		dp->length = newsize;
-		dp = DP((unsigned long)(dp+1) + newsize);
-		dp->first = dp->last = 0;
-		dp->alloced = 0;
-		dp->length = newsize;
-		dp++;
-		dp->first = dp->last = 0;
-		dp->alloced = 1;
-		dp->length = size;
-		ptr = (void *)(dp+1);
-		dp = DP((unsigned long)ptr + size);
-		dp->alloced = 1;
-		dp->length = size;
-	}
-
-#ifdef DEBUG
-	printk ("amiga_chip_alloc: returning %p\n", ptr);
-#endif
-
-	if ((unsigned long)ptr & 7)
-		panic("amiga_chip_alloc: alignment violation\n");
-
-    chipavail -= size + (2*sizeof(*dp)); /*MILAN*/
-
-    if (!request_mem_region(ZTWO_PADDR(ptr), size, name))
-	printk(KERN_WARNING "amiga_chip_alloc: region of size %ld at 0x%08lx "
-	       "is busy\n", size, ZTWO_PADDR(ptr));
-
-    return ptr;
-}
-
-void amiga_chip_free (void *ptr)
-{
-	struct chip_desc *sdp = DP(ptr) - 1, *dp2;
-	struct chip_desc *edp = DP((unsigned long)ptr + sdp->length);
-
-    chipavail += sdp->length + (2* sizeof(sdp)); /*MILAN*/
-#ifdef DEBUG
-   printk("chip_free: free %ld bytes at %p\n",sdp->length,ptr);
-#endif
-	/* deallocate the chunk */
-	sdp->alloced = edp->alloced = 0;
-	release_mem_region(ZTWO_PADDR(ptr), sdp->length);
-
-	/* check if we should merge with the previous chunk */
-	if (!sdp->first && !sdp[-1].alloced) {
-		dp2 = DP((unsigned long)sdp - sdp[-1].length) - 2;
-		dp2->length += sdp->length + 2*sizeof(*sdp);
-		edp->length = dp2->length;
-		sdp = dp2;
-	}
-
-	/* check if we should merge with the following chunk */
-	if (!edp->last && !edp[1].alloced) {
-		dp2 = DP((unsigned long)edp + edp[1].length) + 2;
-		dp2->length += edp->length + 2*sizeof(*sdp);
-		sdp->length = dp2->length;
-		edp = dp2;
-	}
-}
+#include "../../m68k/amiga/chipram.c"
diff -urN linux-2.4.5-pre3/arch/ppc/amiga/cia.c linux/arch/ppc/amiga/cia.c
--- linux-2.4.5-pre3/arch/ppc/amiga/cia.c	Wed Feb  9 19:43:47 2000
+++ linux/arch/ppc/amiga/cia.c	Mon Dec  3 22:44:22 2001
@@ -27,18 +27,17 @@
 	u_short int_mask;
 	int handler_irq, cia_irq, server_irq;
 	char *name;
-	struct irq_server server;
 	irq_handler_t irq_list[CIA_IRQS];
 } ciaa_base = {
 	&ciaa, 0, 0, IF_PORTS,
 	IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA,
 	IRQ_AMIGA_PORTS,
-	"CIAA handler", {0, 0}
+	"CIAA handler"
 }, ciab_base = {
 	&ciab, 0, 0, IF_EXTER,
 	IRQ_AMIGA_AUTO_6, IRQ_AMIGA_CIAB,
 	IRQ_AMIGA_EXTER,
-	"CIAB handler", {0, 0}
+	"CIAB handler"
 };
 
 #define CIA_SET_BASE_ADJUST_IRQ(base, irq)	\
@@ -197,7 +196,7 @@
 		}
 		ints >>= 1;
 	}
-	amiga_do_irq_list(base->server_irq, fp, &base->server);
+	amiga_do_irq_list(base->server_irq, fp);
 }
 
 void __init cia_init_IRQ(struct ciabase *base)
diff -urN linux-2.4.5-pre3/arch/ppc/amiga/config.c linux/arch/ppc/amiga/config.c
--- linux-2.4.5-pre3/arch/ppc/amiga/config.c	Mon Nov 27 17:57:34 2000
+++ linux/arch/ppc/amiga/config.c	Mon Dec  3 22:44:22 2001
@@ -1,12 +1,5 @@
 #define m68k_debug_device debug_device
 
-#include <linux/init.h>
-
-/* machine dependent "kbd-reset" setup function */
-void (*mach_kbd_reset_setup) (char *, int) __initdata = 0;
-
-#include <asm/io.h>
-
 /*
  *  linux/arch/m68k/amiga/config.c
  *
@@ -28,6 +21,10 @@
 #include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
+#include <linux/init.h>
+#ifdef CONFIG_ZORRO
+#include <linux/zorro.h>
+#endif
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
@@ -36,10 +33,12 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/irq.h>
+#include <asm/keyboard.h>
 #include <asm/machdep.h>
-#include <linux/zorro.h>
+#include <asm/io.h>
 
 unsigned long powerup_PCI_present;
+unsigned long powerup_BPPCPLUS_present;
 unsigned long amiga_model;
 unsigned long amiga_eclock;
 unsigned long amiga_masterclock;
@@ -121,7 +120,7 @@
 };
 
 #ifdef CONFIG_MAGIC_SYSRQ
-static char amiga_sysrq_xlate[128] =
+char amiga_sysrq_xlate[128] =
 	"\0001234567890-=\\\000\000"					/* 0x00 - 0x0f */
 	"qwertyuiop[]\000123"							/* 0x10 - 0x1f */
 	"asdfghjkl;'\000\000456"						/* 0x20 - 0x2f */
@@ -139,16 +138,18 @@
      *  Motherboard Resources present in all Amiga models
      */
 
-static struct resource mb_res[] = {
-    { "Ranger Memory", 0x00c00000, 0x00c7ffff },
-    { "CIA B", 0x00bfd000, 0x00bfdfff },
-    { "CIA A", 0x00bfe000, 0x00bfefff },
-    { "Custom I/O", 0x00dff000, 0x00dfffff },
-    { "Kickstart ROM", 0x00f80000, 0x00ffffff }
+static struct {
+    struct resource _ciab, _ciaa, _custom, _kickstart;
+} mb_resources = {
+//    { "Ranger Memory", 0x00c00000, 0x00c7ffff },
+    _ciab:	{ "CIA B", 0x00bfd000, 0x00bfdfff },
+    _ciaa:	{ "CIA A", 0x00bfe000, 0x00bfefff },
+    _custom:	{ "Custom I/O", 0x00dff000, 0x00dfffff },
+    _kickstart:	{ "Kickstart ROM", 0x00f80000, 0x00ffffff }
 };
 
 static struct resource rtc_resource = {
-    "A2000 RTC", 0x00dc0000, 0x00dcffff
+    NULL, 0x00dc0000, 0x00dcffff
 };
 
 static struct resource ram_resource[NUM_MEMINFO];
@@ -194,6 +195,7 @@
 	    break;
 
 	case BI_AMIGA_AUTOCON:
+#ifdef CONFIG_ZORRO
 	    if (zorro_num_autocon < ZORRO_NUM_AUTO) {
 		const struct ConfigDev *cd = (struct ConfigDev *)data;
 		struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++];
@@ -204,12 +206,21 @@
 		dev->resource.end = dev->resource.start+cd->cd_BoardSize-1;
 	    } else
 		printk("amiga_parse_bootinfo: too many AutoConfig devices\n");
+#endif /* CONFIG_ZORRO */
 	    break;
 
 	case BI_AMIGA_SERPER:
 	    /* serial port period: ignored here */
 	    break;
 
+	case BI_AMIGA_PUP_BRIDGE:
+	    powerup_PCI_present = *(const unsigned short *)data;
+	    break;
+
+	case BI_AMIGA_BPPC_SCSI:
+	    powerup_BPPCPLUS_present = *(const unsigned short *)data;
+	    break;
+
 	default:
 	    unknown = 1;
     }
@@ -392,11 +403,8 @@
 
   /* Some APUS boxes may have PCI memory, but ... */
   iomem_resource.name = "Memory";
-  request_resource(&iomem_resource, &ranger_resource);
-  request_resource(&iomem_resource, &ciab_resource);
-  request_resource(&iomem_resource, &ciaa_resource);
-  request_resource(&iomem_resource, &custom_chips_resource);
-  request_resource(&iomem_resource, &kickstart_resource);
+  for (i = 0; i < 4; i++)
+    request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]);
 
   mach_sched_init      = amiga_sched_init;
   mach_keyb_init       = amiga_keyb_init;
@@ -415,11 +423,12 @@
   mach_gettimeoffset   = amiga_gettimeoffset;
   if (AMIGAHW_PRESENT(A3000_CLK)){
     mach_gettod  = a3000_gettod;
-    rtc_resource.name[1] = '3';
+    rtc_resource.name = "A3000 RTC";
     request_resource(&iomem_resource, &rtc_resource);
   }
   else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */
     mach_gettod  = a2000_gettod;
+    rtc_resource.name = "A2000 RTC";
     request_resource(&iomem_resource, &rtc_resource);
   }
 
@@ -439,14 +448,10 @@
   mach_floppy_setup    = amiga_floppy_setup;
 #endif
   mach_reset           = amiga_reset;
+#ifdef CONFIG_DUMMY_CONSOLE
   conswitchp           = &dummy_con;
-  kd_mksound           = amiga_mksound;
-#ifdef CONFIG_MAGIC_SYSRQ
-  mach_sysrq_key = 0x5f;	     /* HELP */
-  mach_sysrq_shift_state = 0x03; /* SHIFT+ALTGR */
-  mach_sysrq_shift_mask = 0xff;  /* all modifiers except CapsLock */
-  mach_sysrq_xlate = amiga_sysrq_xlate;
 #endif
+  kd_mksound           = amiga_mksound;
 #ifdef CONFIG_HEARTBEAT
   mach_heartbeat = amiga_heartbeat;
 #endif
@@ -500,11 +505,14 @@
 static unsigned short jiffy_ticks;
 
 static void __init amiga_sched_init(void (*timer_routine)(int, void *,
-					struct pt_regs *))
+							  struct pt_regs *))
 {
+	static struct resource sched_res = {
+	    "timer", 0x00bfd400, 0x00bfd5ff,
+	};
 	jiffy_ticks = (amiga_eclock+HZ/2)/HZ;
 
-	if (!request_mem_region(CIAB_PHYSADDR+0x400, 0x200, "timer"))
+	if (request_resource(&mb_resources._ciab, &sched_res))
 	    printk("Cannot allocate ciab.ta{lo,hi}\n");
 	ciab.cra &= 0xC0;   /* turn off timer A, continuous mode, from Eclk */
 	ciab.talo = jiffy_ticks % 256;
@@ -612,6 +620,8 @@
 			t->wday = tod->weekday;
 			t->mon  = tod->month1  * 10 + tod->month2 - 1;
 			t->year = tod->year1   * 10 + tod->year2;
+			if (t->year <= 69)
+				t->year += 100;
 		} else {
 			tod->second1 = t->sec / 10;
 			tod->second2 = t->sec % 10;
@@ -625,6 +635,8 @@
 				tod->weekday = t->wday;
 			tod->month1  = (t->mon + 1) / 10;
 			tod->month2  = (t->mon + 1) % 10;
+			if (t->year >= 100)
+				t->year -= 100;
 			tod->year1   = t->year / 10;
 			tod->year2   = t->year % 10;
 		}
@@ -646,6 +658,8 @@
 			t->wday = tod->weekday;
 			t->mon  = tod->month1      * 10 + tod->month2 - 1;
 			t->year = tod->year1       * 10 + tod->year2;
+			if (t->year <= 69)
+				t->year += 100;
 
 			if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){
 				if (!(tod->hour1 & TOD2000_HOUR1_PM) && t->hour == 12)
@@ -672,6 +686,8 @@
 				tod->weekday = t->wday;
 			tod->month1  = (t->mon + 1) / 10;
 			tod->month2  = (t->mon + 1) % 10;
+			if (t->year >= 100)
+				t->year -= 100;
 			tod->year1   = t->year / 10;
 			tod->year2   = t->year % 10;
 		}
@@ -796,7 +812,9 @@
 
 static void amiga_savekmsg_init(void)
 {
-    savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM, "Debug");
+    static struct resource debug_res = { "Debug" };
+
+    savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res);
     savekmsg->magic1 = SAVEKMSG_MAGIC1;
     savekmsg->magic2 = SAVEKMSG_MAGIC2;
     savekmsg->magicptr = virt_to_phys(savekmsg);
diff -urN linux-2.4.5-pre3/arch/ppc/chrpboot/crt0.S linux/arch/ppc/chrpboot/crt0.S
--- linux-2.4.5-pre3/arch/ppc/chrpboot/crt0.S	Mon Jan 12 15:18:13 1998
+++ linux/arch/ppc/chrpboot/crt0.S	Mon Dec  3 22:44:22 2001
@@ -15,6 +15,8 @@
 1:	dcbf	0,9
 	icbi	0,9
 	addi	9,9,0x20
-	cmplwi	0,9,8
+	cmplw	0,9,8
 	blt	1b
+	sync
+	isync
 	b	start
diff -urN linux-2.4.5-pre3/arch/ppc/config.in linux/arch/ppc/config.in
--- linux-2.4.5-pre3/arch/ppc/config.in	Mon Dec  3 22:43:49 2001
+++ linux/arch/ppc/config.in	Mon Dec  3 22:44:22 2001
@@ -127,15 +127,18 @@
 # Yes MCA RS/6000s exist but Linux-PPC does not currently support any
 define_bool CONFIG_MCA n
 
-if [ "$CONFIG_APUS" = "y" -o "$CONFIG_4xx" = "y" -o \
-     "$CONFIG_8260" = "y" ]; then
+if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8260" = "y" ]; then
   define_bool CONFIG_PCI n
 else
   if [ "$CONFIG_8xx" = "y" ]; then
      bool 'QSpan PCI' CONFIG_PCI_QSPAN
      define_bool CONFIG_PCI $CONFIG_PCI_QSPAN
   else
-     define_bool CONFIG_PCI y
+     if [ "$CONFIG_APUS" = "y" ]; then
+       bool 'PCI for Permedia2' CONFIG_PCI
+     else
+       define_bool CONFIG_PCI y
+     fi
   fi
 fi
 
@@ -165,7 +168,11 @@
 source drivers/parport/Config.in
 
 if [ "$CONFIG_4xx" != "y" -a "$CONFIG_8xx" != "y" ]; then
-  tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
+  if [ "$CONFIG_APUS" != "y" ]; then
+    tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
+  else
+    bool 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
+  fi
 fi
 
 if [ "$CONFIG_ALL_PPC" = "y" ]; then
@@ -186,12 +193,26 @@
   define_bool CONFIG_AMIGAMOUSE y
   define_bool CONFIG_ABSTRACT_CONSOLE y
   define_bool CONFIG_FB y
+  define_bool CONFIG_MOUSE y
+  define_bool CONFIG_BUSMOUSE y
+  define_bool CONFIG_APUS_FAST_EXCEPT y
+
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    bool 'Amiga 1200/600 PCMCIA support' CONFIG_AMIGA_PCMCIA
+  fi
+
   tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
-  tristate 'Parallel printer support' CONFIG_M68K_PRINTER
   tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
   dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
   dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
   tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
+  fi
+  if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
+    tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL
+    tristate 'PCMCIA NE2000 support' CONFIG_APNE
+  fi
   if [ "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o "$CONFIG_GVPIOEXT" = "y" -o \
        "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then
     bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
diff -urN linux-2.4.5-pre3/arch/ppc/configs/apus_defconfig linux/arch/ppc/configs/apus_defconfig
--- linux-2.4.5-pre3/arch/ppc/configs/apus_defconfig	Mon Dec  3 22:43:49 2001
+++ linux/arch/ppc/configs/apus_defconfig	Mon Dec  3 22:44:22 2001
@@ -13,7 +13,9 @@
 #
 # Loadable module support
 #
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
 
 #
 # Platform support
@@ -28,7 +30,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_GEMINI is not set
 CONFIG_APUS=y
-CONFIG_PPC601_SYNC_FIX=y
+# CONFIG_PPC601_SYNC_FIX is not set
 # CONFIG_SMP is not set
 # CONFIG_ALTIVEC is not set
 CONFIG_MACH_SPECIFIC=y
@@ -41,7 +43,7 @@
 # CONFIG_EISA is not set
 # CONFIG_SBUS is not set
 # CONFIG_MCA is not set
-# CONFIG_PCI is not set
+CONFIG_PCI=y
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
@@ -49,32 +51,42 @@
 CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_HOTPLUG=y
-
-#
-# PCMCIA/CardBus support
-#
+CONFIG_BINFMT_MISC=m
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
 
 #
 # Parallel port support
 #
-# CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+CONFIG_PARPORT_AMIGA=m
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
+CONFIG_GEN_RTC=y
 CONFIG_FB_CONSOLE=y
 CONFIG_AMIGA=y
 CONFIG_ZORRO=y
 CONFIG_AMIGAMOUSE=y
 CONFIG_ABSTRACT_CONSOLE=y
 CONFIG_FB=y
+CONFIG_MOUSE=y
+CONFIG_BUSMOUSE=y
+CONFIG_APUS_FAST_EXCEPT=y
+CONFIG_AMIGA_PCMCIA=y
 CONFIG_AMIGA_BUILTIN_SERIAL=y
-# CONFIG_M68K_PRINTER is not set
 CONFIG_GVPIOEXT=y
-# CONFIG_GVPIOEXT_LP is not set
-CONFIG_GVPIOEXT_PLIP=y
+CONFIG_GVPIOEXT_LP=m
+CONFIG_GVPIOEXT_PLIP=m
 CONFIG_MULTIFACE_III_TTY=y
-# CONFIG_SERIAL_CONSOLE is not set
+CONFIG_A2232=y
+CONFIG_WHIPPET_SERIAL=y
+CONFIG_APNE=y
+CONFIG_SERIAL_CONSOLE=y
 CONFIG_HEARTBEAT=y
 CONFIG_PROC_HARDWARE=y
 CONFIG_ZORRO_NAMES=y
@@ -95,14 +107,14 @@
 #
 # CONFIG_BLK_DEV_FD is not set
 CONFIG_AMIGA_FLOPPY=y
-CONFIG_AMIGA_Z2RAM=y
+CONFIG_AMIGA_Z2RAM=m
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
@@ -110,21 +122,25 @@
 #
 # Multi-device support (RAID and LVM)
 #
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_LVM is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+CONFIG_BLK_DEV_LVM=m
 
 #
 # Networking options
 #
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+CONFIG_NETLINK_DEV=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -133,9 +149,42 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_UNCLEAN=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_MIRROR=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 # CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
+CONFIG_KHTTPD=m
 # CONFIG_ATM is not set
 
 #
@@ -187,9 +236,9 @@
 # CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=m
 
 #
 # IDE chipset support/bugfixes
@@ -197,6 +246,9 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_GAYLE=y
 CONFIG_BLK_DEV_IDEDOUBLER=y
 CONFIG_BLK_DEV_BUDDHA=y
@@ -215,24 +267,25 @@
 #
 CONFIG_BLK_DEV_SD=y
 CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_SR_EXTRA_DEVS=2
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_SR_EXTRA_DEVS=4
+CONFIG_CHR_DEV_SG=m
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
 # CONFIG_SCSI_DEBUG_QUEUES is not set
 # CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
 
 #
 # SCSI low-level drivers
 #
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AHA152X is not set
@@ -245,6 +298,7 @@
 # CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_DTC3280 is not set
 # CONFIG_SCSI_EATA is not set
@@ -255,20 +309,47 @@
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
 # CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
+CONFIG_A3000_SCSI=y
+CONFIG_A4000T_SCSI=y
+CONFIG_A2091_SCSI=y
+CONFIG_GVP11_SCSI=y
+CONFIG_CYBERSTORM_SCSI=y
+CONFIG_CYBERSTORMII_SCSI=y
+CONFIG_BLZ2060_SCSI=y
+CONFIG_BLZ1230_SCSI=y
+CONFIG_FASTLANE_SCSI=y
+CONFIG_A4091_SCSI=y
+CONFIG_WARPENGINE_SCSI=y
+CONFIG_BLZ603EPLUS_SCSI=y
+CONFIG_OKTAGON_SCSI=y
+CONFIG_CYBERSTORMIII_SCSI=y
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
 
 #
 # Network device support
@@ -279,10 +360,11 @@
 # ARCnet devices
 #
 # CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
+CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
+CONFIG_TUN=m
+# CONFIG_ETHERTAP is not set
 # CONFIG_NET_SB1000 is not set
 
 #
@@ -295,7 +377,7 @@
 # CONFIG_NCR885E is not set
 # CONFIG_OAKNET is not set
 CONFIG_ARIADNE=y
-# CONFIG_NE2K_ZORRO is not set
+CONFIG_NE2K_ZORRO=y
 CONFIG_A2065=y
 CONFIG_HYDRA=y
 # CONFIG_NET_VENDOR_3COM is not set
@@ -304,6 +386,7 @@
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
 # CONFIG_NET_ISA is not set
 # CONFIG_NET_PCI is not set
 # CONFIG_NET_POCKET is not set
@@ -317,18 +400,19 @@
 # CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
+CONFIG_PLIP=m
 CONFIG_PPP=y
 CONFIG_PPP_MULTILINK=y
-# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_FILTER=y
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=y
 CONFIG_PPP_DEFLATE=y
 CONFIG_PPP_BSDCOMP=y
-# CONFIG_PPPOE is not set
+CONFIG_PPPOE=y
 CONFIG_SLIP=y
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
-# CONFIG_SLIP_MODE_SLIP6 is not set
+CONFIG_SLIP_MODE_SLIP6=y
 
 #
 # Wireless LAN (non-hamradio)
@@ -378,10 +462,13 @@
 #
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_RIVA is not set
 CONFIG_FB_CLGEN=y
 CONFIG_FB_PM2=y
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
+# CONFIG_FB_PM2_PCI is not set
 CONFIG_FB_PM2_CVPPC=y
-# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_CYBER2000=y
 CONFIG_FB_AMIGA=y
 CONFIG_FB_AMIGA_OCS=y
 CONFIG_FB_AMIGA_ECS=y
@@ -389,7 +476,7 @@
 CONFIG_FB_CYBER=y
 CONFIG_FB_VIRGE=y
 CONFIG_FB_RETINAZ3=y
-# CONFIG_FB_FM2 is not set
+CONFIG_FB_FM2=y
 # CONFIG_FB_OF is not set
 # CONFIG_FB_CONTROL is not set
 # CONFIG_FB_PLATINUM is not set
@@ -399,25 +486,49 @@
 # CONFIG_FB_S3TRIO is not set
 # CONFIG_FB_VGA16 is not set
 # CONFIG_FB_E1355 is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_SIS is not set
 # CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
-CONFIG_FBCON_MFB=y
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
 CONFIG_FBCON_CFB8=y
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
 CONFIG_FBCON_AFB=y
 CONFIG_FBCON_ILBM=y
-CONFIG_FBCON_FONTWIDTH8_ONLY=y
-# CONFIG_FBCON_FONTS is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FBCON_FONTS=y
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
+CONFIG_FONT_SUN8x16=y
+CONFIG_FONT_SUN12x22=y
+CONFIG_FONT_6x11=y
 CONFIG_FONT_PEARL_8x8=y
+CONFIG_FONT_ACORN_8x8=y
 
 #
 # Input core support
 #
-# CONFIG_INPUT is not set
+CONFIG_INPUT=m
+CONFIG_INPUT_KEYBDEV=m
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=m
 
 #
 # Macintosh device drivers
@@ -428,11 +539,14 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_UNIX98_PTYS is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
 
 #
 # I2C support
@@ -442,8 +556,14 @@
 #
 # Mice
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
+CONFIG_BUSMOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_LOGIBUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_MOUSE=y
+# CONFIG_PSMOUSE is not set
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
 
 #
 # Joysticks
@@ -482,8 +602,8 @@
 # File systems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
 # CONFIG_ADFS_FS is not set
@@ -497,11 +617,11 @@
 CONFIG_VFAT_FS=y
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
-# CONFIG_CRAMFS is not set
+CONFIG_CRAMFS=y
 CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=m
 CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+CONFIG_JOLIET=y
 CONFIG_MINIX_FS=y
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
@@ -510,10 +630,10 @@
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS is not set
+CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
+CONFIG_ROMFS_FS=y
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_SYSV_FS_WRITE is not set
@@ -525,15 +645,17 @@
 #
 # Network File Systems
 #
-# CONFIG_CODA_FS is not set
+CONFIG_CODA_FS=m
 CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
+CONFIG_NFS_V3=y
 # CONFIG_ROOT_NFS is not set
-# CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_SMB_FS is not set
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_NCPFS_PACKET_SIGNING is not set
 # CONFIG_NCPFS_IOCTL_LOCKING is not set
@@ -547,56 +669,116 @@
 #
 # Partition Types
 #
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
 CONFIG_AMIGA_PARTITION=y
-# CONFIG_SMB_NLS is not set
+CONFIG_ATARI_PARTITION=y
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+# CONFIG_MINIX_SUBPARTITION is not set
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_SMB_NLS=y
 CONFIG_NLS=y
 
 #
 # Native Language Support
 #
 CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-CONFIG_NLS_ISO8859_1=y
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
 
 #
 # Sound
 #
-# CONFIG_SOUND is not set
+CONFIG_SOUND=y
+CONFIG_DMASOUND_PAULA=m
+CONFIG_DMASOUND=m
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+CONFIG_SOUND_OSS=m
+CONFIG_SOUND_TRACEINIT=y
+CONFIG_SOUND_DMAP=y
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+CONFIG_SOUND_VMIDI=m
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_YMFPCI is not set
+# CONFIG_SOUND_YMFPCI_LEGACY is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+# CONFIG_SOUND_TVMIXER is not set
 
 #
 # USB support
@@ -606,6 +788,6 @@
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
 # CONFIG_XMON is not set
diff -urN linux-2.4.5-pre3/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- linux-2.4.5-pre3/arch/ppc/kernel/Makefile	Mon Dec  3 22:43:49 2001
+++ linux/arch/ppc/kernel/Makefile	Mon Dec  3 22:44:22 2001
@@ -57,6 +57,9 @@
 obj-$(CONFIG_MATH_EMULATION)	+= softemu8xx.o
 obj-$(CONFIG_MBX)		+= i8259.o
 obj-$(CONFIG_APUS)		+= apus_setup.o
+ifeq ($(CONFIG_APUS),y)
+obj-$(CONFIG_PCI)		+= apus_pci.o
+endif
 obj-$(CONFIG_ALL_PPC)		+= pmac_pic.o pmac_setup.o pmac_time.o prom.o \
 					feature.o pmac_pci.o chrp_setup.o \
 					chrp_time.o chrp_pci.o 	open_pic.o \
diff -urN linux-2.4.5-pre3/arch/ppc/kernel/apus_pci.c linux/arch/ppc/kernel/apus_pci.c
--- linux-2.4.5-pre3/arch/ppc/kernel/apus_pci.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/apus_pci.c	Mon Dec  3 22:44:22 2001
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) Michel Dänzer <michdaen@iiic.ethz.ch>
+ *
+ * APUS PCI routines.
+ *
+ * Currently, only B/CVisionPPC cards (Permedia2) are supported.
+ *
+ * Thanks to Geert Uytterhoeven for the idea:
+ * Read values from given config space(s) for the first devices, -1 otherwise
+ *
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_AMIGA
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+
+#include <asm/init.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#include "apus_pci.h"
+
+
+/* These definitions are mostly adapted from pm2fb.c */
+
+#undef APUS_PCI_MASTER_DEBUG
+#ifdef APUS_PCI_MASTER_DEBUG
+#define DPRINTK(a,b...)	printk(KERN_DEBUG "apus_pci: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
+#endif 
+
+/*
+ * The _DEFINITIVE_ memory mapping/unmapping functions.
+ * This is due to the fact that they're changing soooo often...
+ */
+#define DEFW()		wmb()
+#define DEFR()		rmb()
+#define DEFRW()		mb()
+
+#define DEVNO(d)	((d)>>3)
+#define FNNO(d)		((d)&7)
+
+
+extern unsigned long powerup_PCI_present;
+
+static struct pci_controller *apus_hose;
+
+
+__apus
+void *pci_io_base(unsigned int bus)
+{
+	return 0;
+}
+
+
+#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
+#define cfg_write(val, addr, type, op)	op((val), (type *)(addr)); DEFW()
+#define cfg_read_bad	*val = ~0;
+#define cfg_write_bad	;
+#define cfg_read_val(val)	*val
+#define cfg_write_val(val)	val
+
+#define APUS_PCI_OP(rw, size, type, op, mask)					\
+__apus int									\
+apus_pcibios_##rw##_config_##size(struct pci_dev *dev, int offset, type val)	\
+{										\
+	int fnno = FNNO(dev->devfn);						\
+	int devno = DEVNO(dev->devfn);						\
+										\
+	if (dev->bus->number > 0 || devno != 1) {				\
+		cfg_##rw##_bad;							\
+		return PCIBIOS_DEVICE_NOT_FOUND;				\
+	}									\
+	/* base address + function offset + offset ^ endianness conversion */	\
+	cfg_##rw(val, apus_hose->cfg_data + (fnno<<5) + (offset ^ mask),	\
+		 type, op);							\
+										\
+	DPRINTK(#op " b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, v: 0x%x\n",		\
+		dev->bus->number, dev->devfn>>3, dev->devfn&7,			\
+		offset, cfg_##rw##_val(val));					\
+	return PCIBIOS_SUCCESSFUL;						\
+}
+
+APUS_PCI_OP(read, byte, u8 *, readb, 3)
+APUS_PCI_OP(read, word, u16 *, readw, 2)
+APUS_PCI_OP(read, dword, u32 *, readl, 0)
+APUS_PCI_OP(write, byte, u8, writeb, 3)
+APUS_PCI_OP(write, word, u16, writew, 2)
+APUS_PCI_OP(write, dword, u32, writel, 0)
+
+
+static struct pci_ops apus_pci_ops = {
+	apus_pcibios_read_config_byte,
+	apus_pcibios_read_config_word,
+	apus_pcibios_read_config_dword,
+	apus_pcibios_write_config_byte,
+	apus_pcibios_write_config_word,
+	apus_pcibios_write_config_dword
+};
+
+static struct resource pci_mem = { "B/CVisionPPC PCI mem", CVPPC_FB_APERTURE_ONE, CVPPC_PCI_CONFIG, IORESOURCE_MEM };
+
+void __init
+apus_pcibios_fixup(void)
+{
+/*	struct pci_dev *dev = pci_find_slot(0, 1<<3);
+	unsigned int reg, val, offset;*/
+
+	/* FIXME: interrupt? */
+	/*dev->interrupt = xxx;*/
+
+        request_resource(&iomem_resource, &pci_mem);
+    	printk("%s: PCI mem resource requested\n", __FUNCTION__);
+}
+
+static void __init apus_pcibios_fixup_bus(struct pci_bus *bus)
+{
+        bus->resource[1] = &pci_mem;
+}
+
+
+/* 
+ * This is from pm2fb.c again
+ * 
+ * Check if PCI (B/CVisionPPC) is available, initialize it and set up
+ * the pcibios_* pointers
+ */
+
+
+void __init
+apus_setup_pci_ptrs(void)
+{
+	if (!powerup_PCI_present) {
+		DPRINTK("no PCI bridge detected\n");
+		return;
+	}
+	DPRINTK("Phase5 B/CVisionPPC PCI bridge detected.\n");
+
+	apus_hose = pcibios_alloc_controller();
+	if (!apus_hose) {
+		printk("apus_pci: Can't allocate PCI controller structure\n");
+		return;
+	}
+
+	if (!(apus_hose->cfg_data = ioremap(CVPPC_PCI_CONFIG, 256))) {
+		printk("apus_pci: unable to map PCI config region\n");
+		return;
+	}
+
+	if (!(apus_hose->cfg_addr = ioremap(CSPPC_PCI_BRIDGE, 256))) {
+		printk("apus_pci: unable to map PCI bridge\n");
+		return;
+	}
+
+	writel(CSPPCF_BRIDGE_BIG_ENDIAN, apus_hose->cfg_addr + CSPPC_BRIDGE_ENDIAN);
+	DEFW();
+
+	writel(CVPPC_REGS_REGION,  apus_hose->cfg_data+ PCI_BASE_ADDRESS_0);
+	DEFW();
+	writel(CVPPC_FB_APERTURE_ONE, apus_hose->cfg_data + PCI_BASE_ADDRESS_1);
+	DEFW();
+	writel(CVPPC_FB_APERTURE_TWO, apus_hose->cfg_data + PCI_BASE_ADDRESS_2);
+	DEFW();
+	writel(CVPPC_ROM_ADDRESS, apus_hose->cfg_data + PCI_ROM_ADDRESS);
+	DEFW();
+
+	writel(0xef000000 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+		PCI_COMMAND_MASTER, apus_hose->cfg_data + PCI_COMMAND);
+	DEFW();
+
+	apus_hose->first_busno = 0;
+	apus_hose->last_busno = 0;
+	apus_hose->ops = &apus_pci_ops;
+	ppc_md.pcibios_fixup = apus_pcibios_fixup;
+	ppc_md.pcibios_fixup_bus = apus_pcibios_fixup_bus;
+
+	return;
+}
+
+#endif /* CONFIG_AMIGA */
diff -urN linux-2.4.5-pre3/arch/ppc/kernel/apus_pci.h linux/arch/ppc/kernel/apus_pci.h
--- linux-2.4.5-pre3/arch/ppc/kernel/apus_pci.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/apus_pci.h	Mon Dec  3 22:44:22 2001
@@ -0,0 +1,39 @@
+/*
+ * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer
+ * driver.
+ *
+ * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ * --------------------------------------------------------------------------
+ * $Id: cvisionppc.h,v 1.9 1999/03/12 09:45:06 illo Exp $
+ * --------------------------------------------------------------------------
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef APUS_PCI_H
+#define APUS_PCI_H
+
+
+#include "pci.h"
+
+
+#define CSPPC_PCI_BRIDGE		0xfffe0000
+#define CSPPC_BRIDGE_ENDIAN		0x0000
+#define CSPPC_BRIDGE_INT		0x0010
+
+#define	CVPPC_PCI_CONFIG		0xfffc0000
+#define CVPPC_ROM_ADDRESS		0xe2000001
+#define CVPPC_REGS_REGION		0xef000000
+#define CVPPC_FB_APERTURE_ONE		0xe0000000
+#define CVPPC_FB_APERTURE_TWO		0xe1000000
+#define CVPPC_FB_SIZE			0x00800000
+
+/* CVPPC_BRIDGE_ENDIAN */
+#define CSPPCF_BRIDGE_BIG_ENDIAN	0x02
+
+/* CVPPC_BRIDGE_INT */
+#define CSPPCF_BRIDGE_ACTIVE_INT2	0x01
+
+
+#endif	/* APUS_PCI_H */
diff -urN linux-2.4.5-pre3/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- linux-2.4.5-pre3/arch/ppc/kernel/pci.c	Mon Dec  3 22:43:49 2001
+++ linux/arch/ppc/kernel/pci.c	Mon Dec  3 22:44:22 2001
@@ -385,6 +385,8 @@
 	return 0;
 }
 
+static int next_controller_index;
+
 struct pci_controller * __init
 pcibios_alloc_controller(void)
 {
@@ -396,6 +398,8 @@
 	*hose_tail = hose;
 	hose_tail = &hose->next;
 
+	hose->index = next_controller_index++;
+
 	return hose;
 }
 
@@ -896,6 +900,144 @@
 	return res->start;
 #endif	
 }
+
+/*
+ * Return the index of the PCI controller for device pdev.
+ */
+int pci_controller_num(struct pci_dev *dev)
+{
+	struct pci_controller *hose = (struct pci_controller *) dev->sysdata;
+
+	return hose->index;
+}
+
+/*
+ * Platform support for /proc/bus/pci/X/Y mmap()s,
+ * modelled on the sparc64 implementation by Dave Miller.
+ *  -- paulus.
+ */
+
+/*
+ * Adjust vm_pgoff of VMA such that it is the physical page offset
+ * corresponding to the 32-bit pci bus offset for DEV requested by the user.
+ *
+ * Basically, the user finds the base address for his device which he wishes
+ * to mmap.  They read the 32-bit value from the config space base register,
+ * add whatever PAGE_SIZE multiple offset they wish, and feed this into the
+ * offset parameter of mmap on /proc/bus/pci/XXX for that device.
+ *
+ * Returns negative error code on failure, zero on success.
+ */
+static __inline__ int
+__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
+		       enum pci_mmap_state mmap_state)
+{
+	struct pci_controller *hose = (struct pci_controller *) dev->sysdata;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long io_offset = 0;
+	int i, res_bit;
+
+	if (hose == 0)
+		return -EINVAL;		/* should never happen */
+
+	/* If memory, add on the PCI bridge address offset */
+	if (mmap_state == pci_mmap_mem) {
+		offset += hose->pci_mem_offset;
+		res_bit = IORESOURCE_MEM;
+	} else {
+		io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
+		offset += io_offset;
+		res_bit = IORESOURCE_IO;
+	}
+
+	/*
+	 * Check that the offset requested corresponds to one of the
+	 * resources of the device.
+	 */
+	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+		struct resource *rp = &dev->resource[i];
+		int flags = rp->flags;
+
+		/* treat ROM as memory (should be already) */
+		if (i == PCI_ROM_RESOURCE)
+			flags |= IORESOURCE_MEM;
+
+		/* Active and same type? */
+		if ((flags & res_bit) == 0)
+			continue;
+
+		/* In the range of this resource? */
+		if (offset < (rp->start & PAGE_MASK) || offset > rp->end)
+			continue;
+
+		/* found it! construct the final physical address */
+		if (mmap_state == pci_mmap_io)
+			offset += hose->io_base_phys - io_offset;
+
+		vma->vm_pgoff = offset >> PAGE_SHIFT;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
+ * mapping.
+ */
+static __inline__ void
+__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
+		     enum pci_mmap_state mmap_state)
+{
+	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+}
+
+/*
+ * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
+ * device mapping.
+ */
+static __inline__ void
+__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
+		      enum pci_mmap_state mmap_state, int write_combine)
+{
+	int prot = pgprot_val(vma->vm_page_prot);
+
+	/* XXX would be nice to have a way to ask for write-through */
+	prot |= _PAGE_NO_CACHE;
+	if (!write_combine)
+		prot |= _PAGE_GUARDED;
+	vma->vm_page_prot = __pgprot(prot);
+}
+
+/*
+ * Perform the actual remap of the pages for a PCI device mapping, as
+ * appropriate for this architecture.  The region in the process to map
+ * is described by vm_start and vm_end members of VMA, the base physical
+ * address is found in vm_pgoff.
+ * The pci device structure is provided so that architectures may make mapping
+ * decisions on a per-device or per-bus basis.
+ *
+ * Returns a negative error code on failure, zero on success.
+ */
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state,
+			int write_combine)
+{
+	int ret;
+
+	ret = __pci_mmap_make_offset(dev, vma, mmap_state);
+	if (ret < 0)
+		return ret;
+
+	__pci_mmap_set_flags(dev, vma, mmap_state);
+	__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
+
+	ret = remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
+
+	return ret;
+}
+
 
 /* Obsolete functions. Should be removed once the symbios driver
  * is fixed
diff -urN linux-2.4.5-pre3/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c
--- linux-2.4.5-pre3/arch/sparc64/kernel/pci_common.c	Mon Dec  3 22:43:49 2001
+++ linux/arch/sparc64/kernel/pci_common.c	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.17 2001/05/15 12:32:52 davem Exp $
+/* $Id: pci_common.c,v 1.18 2001/05/18 23:06:35 davem Exp $
  * pci_common.c: PCI controller common support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -500,15 +500,21 @@
 
 static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt)
 {
+	struct linux_prom_pci_intmap bridge_local_intmap[PROM_PCIIMAP_MAX], *intmap;
+	struct linux_prom_pci_intmask bridge_local_intmask, *intmask;
 	struct pcidev_cookie *dev_pcp = pdev->sysdata;
 	struct pci_pbm_info *pbm = dev_pcp->pbm;
 	struct linux_prom_pci_registers *pregs = dev_pcp->prom_regs;
 	unsigned int hi, mid, lo, irq;
-	int i;
+	int i, num_intmap;
 
 	if (pbm->num_pbm_intmap == 0)
 		return 0;
 
+	intmap = &pbm->pbm_intmap[0];
+	intmask = &pbm->pbm_intmask;
+	num_intmap = pbm->num_pbm_intmap;
+
 	/* If we are underneath a PCI bridge, use PROM register
 	 * property of the parent bridge which is closest to
 	 * the PBM.
@@ -516,7 +522,7 @@
 	if (pdev->bus->number != pbm->pci_first_busno) {
 		struct pcidev_cookie *bus_pcp;
 		struct pci_dev *pwalk;
-		int offset;
+		int offset, plen;
 
 		pwalk = pdev->bus->self;
 		while (pwalk->bus &&
@@ -524,6 +530,27 @@
 			pwalk = pwalk->bus->self;
 
 		bus_pcp = pwalk->sysdata;
+
+		/* But if the PCI bridge has it's own interrupt map
+		 * and mask properties, use that and the device regs.
+		 */
+		plen = prom_getproperty(bus_pcp->prom_node, "interrupt-map",
+					(char *) &bridge_local_intmap[0],
+					sizeof(bridge_local_intmap));
+		if (plen != -1) {
+			intmap = &bridge_local_intmap[0];
+			num_intmap = plen / sizeof(struct linux_prom_pci_intmap);
+			plen = prom_getproperty(bus_pcp->prom_node, "interrupt-map-mask",
+						(char *) &bridge_local_intmask,
+						sizeof(bridge_local_intmask));
+			if (plen == -1) {
+				prom_printf("pbm_intmap_match: Bridge has intmap but "
+					    "no intmask.\n");
+				prom_halt();
+			}
+			goto check_intmap;
+		}
+
 		pregs = bus_pcp->prom_regs;
 
 		offset = prom_getint(dev_pcp->prom_node,
@@ -544,17 +571,18 @@
 		}
 	}
 
-	hi   = pregs->phys_hi & pbm->pbm_intmask.phys_hi;
-	mid  = pregs->phys_mid & pbm->pbm_intmask.phys_mid;
-	lo   = pregs->phys_lo & pbm->pbm_intmask.phys_lo;
-	irq  = *interrupt & pbm->pbm_intmask.interrupt;
-
-	for (i = 0; i < pbm->num_pbm_intmap; i++) {
-		if (pbm->pbm_intmap[i].phys_hi  == hi	&&
-		    pbm->pbm_intmap[i].phys_mid == mid	&&
-		    pbm->pbm_intmap[i].phys_lo  == lo	&&
-		    pbm->pbm_intmap[i].interrupt == irq) {
-			*interrupt = pbm->pbm_intmap[i].cinterrupt;
+check_intmap:
+	hi   = pregs->phys_hi & intmask->phys_hi;
+	mid  = pregs->phys_mid & intmask->phys_mid;
+	lo   = pregs->phys_lo & intmask->phys_lo;
+	irq  = *interrupt & intmask->interrupt;
+
+	for (i = 0; i < num_intmap; i++) {
+		if (intmap[i].phys_hi  == hi	&&
+		    intmap[i].phys_mid == mid	&&
+		    intmap[i].phys_lo  == lo	&&
+		    intmap[i].interrupt == irq) {
+			*interrupt = intmap[i].cinterrupt;
 			return 1;
 		}
 	}
diff -urN linux-2.4.5-pre3/drivers/block/genhd.c linux/drivers/block/genhd.c
--- linux-2.4.5-pre3/drivers/block/genhd.c	Mon Dec  3 22:43:49 2001
+++ linux/drivers/block/genhd.c	Mon Dec  3 22:44:23 2001
@@ -29,7 +29,7 @@
 extern int cpqarray_init(void);
 extern void ieee1394_init(void);
 
-void __init device_init(void)
+int __init device_init(void)
 {
 	blk_dev_init();
 	sti();
@@ -58,4 +58,7 @@
 #ifdef CONFIG_VT
 	console_map_init();
 #endif
+	return 0;
 }
+
+__initcall(device_init);
diff -urN linux-2.4.5-pre3/drivers/block/swim_iop.c linux/drivers/block/swim_iop.c
--- linux-2.4.5-pre3/drivers/block/swim_iop.c	Wed Feb 16 10:56:45 2000
+++ linux/drivers/block/swim_iop.c	Mon Dec  3 22:44:23 2001
@@ -363,7 +363,7 @@
 				   sizeof(struct floppy_struct));
 		return err;
 	}
-	return -ENOIOCTLCMD;
+	return -ENOTTY;
 }
 
 static int floppy_open(struct inode *inode, struct file *filp)
diff -urN linux-2.4.5-pre3/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c
--- linux-2.4.5-pre3/drivers/char/acquirewdt.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/acquirewdt.c	Mon Dec  3 22:44:23 2001
@@ -110,7 +110,7 @@
 	  break;
 
 	default:
-	  return -ENOIOCTLCMD;
+	  return -ENOTTY;
 	}
 	return 0;
 }
diff -urN linux-2.4.5-pre3/drivers/char/advantechwdt.c linux/drivers/char/advantechwdt.c
--- linux-2.4.5-pre3/drivers/char/advantechwdt.c	Tue Mar  6 19:44:34 2001
+++ linux/drivers/char/advantechwdt.c	Mon Dec  3 22:44:23 2001
@@ -120,7 +120,7 @@
 	  break;
 
 	default:
-	  return -ENOIOCTLCMD;
+	  return -ENOTTY;
 	}
 	return 0;
 }
diff -urN linux-2.4.5-pre3/drivers/char/mem.c linux/drivers/char/mem.c
--- linux-2.4.5-pre3/drivers/char/mem.c	Mon Dec  3 22:43:49 2001
+++ linux/drivers/char/mem.c	Mon Dec  3 22:44:23 2001
@@ -29,9 +29,6 @@
 #ifdef CONFIG_I2C
 extern int i2c_init_all(void);
 #endif
-#ifdef CONFIG_VIDEO_DEV
-extern int videodev_init(void);
-#endif
 #ifdef CONFIG_FB
 extern void fbmem_init(void);
 #endif
@@ -647,9 +644,6 @@
 #endif
 #if defined(CONFIG_ADB)
 	adbdev_init();
-#endif
-#ifdef CONFIG_VIDEO_DEV
-	videodev_init();
 #endif
 	return 0;
 }
diff -urN linux-2.4.5-pre3/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- linux-2.4.5-pre3/drivers/char/ppdev.c	Mon Oct 16 12:58:51 2000
+++ linux/drivers/char/ppdev.c	Mon Dec  3 22:44:23 2001
@@ -35,17 +35,25 @@
  *   WCTLONIRQ	on interrupt, set control lines
  *   CLRIRQ	clear (and return) interrupt count
  *   SETTIME	sets device timeout (struct timeval)
- *   GETTIME    gets device timeout (struct timeval)
+ *   GETTIME	gets device timeout (struct timeval)
+ *   GETMODES	gets hardware supported modes (unsigned int)
+ *   GETMODE	gets the current IEEE1284 mode
+ *   GETPHASE   gets the current IEEE1284 phase
+ *   GETFLAGS   gets current (user-visible) flags
+ *   SETFLAGS   sets current (user-visible) flags
  * read/write	read or write in current IEEE 1284 protocol
  * select	wait for interrupt (in readfds)
  *
  * Changes:
- * Added SETTIME/GETTIME ioctl, Fred Barnes 1999.
+ * Added SETTIME/GETTIME ioctl, Fred Barnes, 1999.
  *
  * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 2000/08/25
  * - On error, copy_from_user and copy_to_user do not return -EFAULT,
  *   They return the positive number of bytes *not* copied due to address
  *   space errors.
+ *
+ * Added GETMODES/GETMODE/GETPHASE ioctls, Fred Barnes <frmb2@ukc.ac.uk>, 03/01/2001.
+ * Added GETFLAGS/SETFLAGS ioctls, Fred Barnes, 04/2001
  */
 
 #include <linux/module.h>
@@ -84,7 +92,7 @@
 
 /* Other constants */
 #define PP_INTERRUPT_TIMEOUT (10 * HZ) /* 10s */
-#define PP_BUFFER_SIZE 256
+#define PP_BUFFER_SIZE 1024
 #define PARDEVICE_MAX 8
 
 /* ROUND_UP macro from fs/select.c */
@@ -109,6 +117,8 @@
 	char * kbuffer;
 	ssize_t bytes_read = 0;
 	ssize_t got = 0;
+	struct parport *pport;
+	int mode;
 
 	if (!(pp->flags & PP_CLAIMED)) {
 		/* Don't have the port claimed */
@@ -118,18 +128,40 @@
 	}
 
 	kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL);
-	if (!kbuffer)
+	if (!kbuffer) {
 		return -ENOMEM;
+	}
+	pport = pp->pdev->port;
+	mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
 
 	while (bytes_read < count) {
 		ssize_t need = min(count - bytes_read, PP_BUFFER_SIZE);
 
-		got = parport_read (pp->pdev->port, kbuffer, need);
+		if (mode == IEEE1284_MODE_EPP) {
+			/* various specials for EPP mode */
+			int flags = 0;
+			size_t (*fn)(struct parport *, void *, size_t, int);
+
+			if (pp->flags & PP_W91284PIC) {
+				flags |= PARPORT_W91284PIC;
+			}
+			if (pp->flags & PP_FASTREAD) {
+				flags |= PARPORT_EPP_FAST;
+			}
+			if (pport->ieee1284.mode & IEEE1284_ADDR) {
+				fn = pport->ops->epp_read_addr;
+			} else {
+				fn = pport->ops->epp_read_data;
+			}
+			got = (*fn)(pport, kbuffer, need, flags);
+		} else {
+			got = parport_read (pport, kbuffer, need);
+		}
 
 		if (got <= 0) {
-			if (!bytes_read)
+			if (!bytes_read) {
 				bytes_read = got;
-
+			}
 			break;
 		}
 
@@ -141,13 +173,15 @@
 		bytes_read += got;
 
 		if (signal_pending (current)) {
-			if (!bytes_read)
+			if (!bytes_read) {
 				bytes_read = -EINTR;
+			}
 			break;
 		}
 
-		if (current->need_resched)
+		if (current->need_resched) {
 			schedule ();
+		}
 	}
 
 	kfree (kbuffer);
@@ -163,6 +197,8 @@
 	char * kbuffer;
 	ssize_t bytes_written = 0;
 	ssize_t wrote;
+	int mode;
+	struct parport *pport;
 
 	if (!(pp->flags & PP_CLAIMED)) {
 		/* Don't have the port claimed */
@@ -172,8 +208,11 @@
 	}
 
 	kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL);
-	if (!kbuffer)
+	if (!kbuffer) {
 		return -ENOMEM;
+	}
+	pport = pp->pdev->port;
+	mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
 
 	while (bytes_written < count) {
 		ssize_t n = min(count - bytes_written, PP_BUFFER_SIZE);
@@ -183,24 +222,38 @@
 			break;
 		}
 
-		wrote = parport_write (pp->pdev->port, kbuffer, n);
+		if ((pp->flags & PP_FASTWRITE) && (mode == IEEE1284_MODE_EPP)) {
+			/* do a fast EPP write */
+			if (pport->ieee1284.mode & IEEE1284_ADDR) {
+				wrote = pport->ops->epp_write_addr (pport,
+					kbuffer, n, PARPORT_EPP_FAST);
+			} else {
+				wrote = pport->ops->epp_write_data (pport,
+					kbuffer, n, PARPORT_EPP_FAST);
+			}
+		} else {
+			wrote = parport_write (pp->pdev->port, kbuffer, n);
+		}
 
 		if (wrote <= 0) {
-			if (!bytes_written)
+			if (!bytes_written) {
 				bytes_written = wrote;
+			}
 			break;
 		}
 
 		bytes_written += wrote;
 
 		if (signal_pending (current)) {
-			if (!bytes_written)
+			if (!bytes_written) {
 				bytes_written = -EINTR;
+			}
 			break;
 		}
 
-		if (current->need_resched)
+		if (current->need_resched) {
 			schedule ();
+		}
 	}
 
 	kfree (kbuffer);
@@ -276,7 +329,9 @@
 	struct parport * port;
 
 	/* First handle the cases that don't take arguments. */
-	if (cmd == PPCLAIM) {
+	switch (cmd) {
+	case PPCLAIM:
+	    {
 		struct ieee1284_info *info;
 
 		if (pp->flags & PP_CLAIMED) {
@@ -288,8 +343,9 @@
 		/* Deferred device registration. */
 		if (!pp->pdev) {
 			int err = register_device (minor, pp);
-			if (err)
+			if (err) {
 				return err;
+			}
 		}
 
 		parport_claim_or_block (pp->pdev);
@@ -307,9 +363,8 @@
 		info->phase = pp->state.phase;
 
 		return 0;
-	}
-
-	if (cmd == PPEXCL) {
+	    }
+	case PPEXCL:
 		if (pp->pdev) {
 			printk (KERN_DEBUG CHRDEV "%x: too late for PPEXCL; "
 				"already registered\n", minor);
@@ -324,9 +379,8 @@
 		 * when we finally do the registration. */
 		pp->flags |= PP_EXCL;
 		return 0;
-	}
-
-	if (cmd == PPSETMODE) {
+	case PPSETMODE:
+	    {
 		int mode;
 		if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
 			return -EFAULT;
@@ -340,20 +394,82 @@
 		}
 
 		return 0;
-	}
+	    }
+	case PPGETMODE:
+	    {
+		int mode;
 
-	if (cmd == PPSETPHASE) {
+		if (pp->flags & PP_CLAIMED) {
+			mode = pp->pdev->port->ieee1284.mode;
+		} else {
+			mode = pp->state.mode;
+		}
+		if (copy_to_user ((int *)arg, &mode, sizeof (mode))) {
+			return -EFAULT;
+		}
+		return 0;
+	    }
+	case PPSETPHASE:
+	    {
 		int phase;
-		if (copy_from_user (&phase, (int *) arg, sizeof (phase)))
+		if (copy_from_user (&phase, (int *) arg, sizeof (phase))) {
 			return -EFAULT;
+		}
 		/* FIXME: validate phase */
 		pp->state.phase = phase;
 
-		if (pp->flags & PP_CLAIMED)
+		if (pp->flags & PP_CLAIMED) {
 			pp->pdev->port->ieee1284.phase = phase;
+		}
 
 		return 0;
-	}
+	    }
+	case PPGETPHASE:
+	    {
+		int phase;
+
+		if (pp->flags & PP_CLAIMED) {
+			phase = pp->pdev->port->ieee1284.phase;
+		} else {
+			phase = pp->state.phase;
+		}
+		if (copy_to_user ((int *)arg, &phase, sizeof (phase))) {
+			return -EFAULT;
+		}
+		return 0;
+	    }
+	case PPGETMODES:
+	    {
+		unsigned int modes;
+
+		modes = pp->pdev->port->modes;
+		if (copy_to_user ((unsigned int *)arg, &modes, sizeof (port->modes))) {
+			return -EFAULT;
+		}
+		return 0;
+	    }
+	case PPSETFLAGS:
+	    {
+		int uflags;
+
+		if (copy_from_user (&uflags, (int *)arg, sizeof (uflags))) {
+			return -EFAULT;
+		}
+		pp->flags &= ~PP_FLAGMASK;
+		pp->flags |= (uflags & PP_FLAGMASK);
+		return 0;
+	    }
+	case PPGETFLAGS:
+	    {
+		int uflags;
+
+		uflags = pp->flags & PP_FLAGMASK;
+		if (copy_to_user ((int *)arg, &uflags, sizeof (uflags))) {
+			return -EFAULT;
+		}
+		return 0;
+	    }
+	}	/* end switch() */
 
 	/* Everything else requires the port to be claimed, so check
 	 * that now. */
@@ -537,13 +653,28 @@
 {
 	unsigned int minor = MINOR (inode->i_rdev);
 	struct pp_struct *pp = file->private_data;
+	int compat_negot;
 
 	lock_kernel();
-	if (pp->pdev && pp->pdev->port->ieee1284.mode != IEEE1284_MODE_COMPAT) {
-		if (!(pp->flags & PP_CLAIMED)) {
-			parport_claim_or_block (pp->pdev);
-			pp->flags |= PP_CLAIMED;
-		}
+	compat_negot = 0;
+	if (!(pp->flags & PP_CLAIMED) && pp->pdev &&
+	    (pp->state.mode != IEEE1284_MODE_COMPAT)) {
+	    	struct ieee1284_info *info;
+
+		/* parport released, but not in compatability mode */
+		parport_claim_or_block (pp->pdev);
+		pp->flags |= PP_CLAIMED;
+		info = &pp->pdev->port->ieee1284;
+		pp->saved_state.mode = info->mode;
+		pp->saved_state.phase = info->phase;
+		info->mode = pp->state.mode;
+		info->phase = pp->state.phase;
+		compat_negot = 1;
+	} else if ((pp->flags & PP_CLAIMED) && pp->pdev &&
+	    (pp->pdev->port->ieee1284.mode != IEEE1284_MODE_COMPAT)) {
+		compat_negot = 2;
+	}
+	if (compat_negot) {
 		parport_negotiate (pp->pdev->port, IEEE1284_MODE_COMPAT);
 		printk (KERN_DEBUG CHRDEV
 			"%x: negotiated back to compatibility mode because "
@@ -551,9 +682,18 @@
 	}
 
 	if (pp->flags & PP_CLAIMED) {
+		struct ieee1284_info *info;
+
+		info = &pp->pdev->port->ieee1284;
+		pp->state.mode = info->mode;
+		pp->state.phase = info->phase;
+		info->mode = pp->saved_state.mode;
+		info->phase = pp->saved_state.phase;
 		parport_release (pp->pdev);
-		printk (KERN_DEBUG CHRDEV "%x: released pardevice because "
-			"user-space forgot\n", minor);
+		if (compat_negot != 1) {
+			printk (KERN_DEBUG CHRDEV "%x: released pardevice "
+				"because user-space forgot\n", minor);
+		}
 	}
 
 	if (pp->pdev) {
diff -urN linux-2.4.5-pre3/drivers/char/sbc60xxwdt.c linux/drivers/char/sbc60xxwdt.c
--- linux-2.4.5-pre3/drivers/char/sbc60xxwdt.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/sbc60xxwdt.c	Mon Dec  3 22:44:23 2001
@@ -241,7 +241,7 @@
 	switch(cmd)
 	{
 		default:
-			return -ENOIOCTLCMD;
+			return -ENOTTY;
 		case WDIOC_GETSUPPORT:
 			return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0;
 		case WDIOC_KEEPALIVE:
diff -urN linux-2.4.5-pre3/drivers/char/serial.c linux/drivers/char/serial.c
--- linux-2.4.5-pre3/drivers/char/serial.c	Fri Apr 13 20:26:07 2001
+++ linux/drivers/char/serial.c	Mon Dec  3 22:44:23 2001
@@ -565,9 +565,12 @@
 
 	icount = &info->state->icount;
 	do {
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			tty->flip.tqueue.routine((void *) tty);
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				return;		// if TTY_DONT_FLIP is set
+		}
 		ch = serial_inp(info, UART_RX);
-		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-			goto ignore_char;
 		*tty->flip.char_buf_ptr = ch;
 		icount->rx++;
 		
diff -urN linux-2.4.5-pre3/drivers/char/softdog.c linux/drivers/char/softdog.c
--- linux-2.4.5-pre3/drivers/char/softdog.c	Tue Feb 13 14:13:43 2001
+++ linux/drivers/char/softdog.c	Mon Dec  3 22:44:23 2001
@@ -132,7 +132,7 @@
 	};
 	switch (cmd) {
 		default:
-			return -ENOIOCTLCMD;
+			return -ENOTTY;
 		case WDIOC_GETSUPPORT:
 			if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
 				return -EFAULT;
diff -urN linux-2.4.5-pre3/drivers/char/wdt.c linux/drivers/char/wdt.c
--- linux-2.4.5-pre3/drivers/char/wdt.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/wdt.c	Mon Dec  3 22:44:23 2001
@@ -311,7 +311,7 @@
 	switch(cmd)
 	{
 		default:
-			return -ENOIOCTLCMD;
+			return -ENOTTY;
 		case WDIOC_GETSUPPORT:
 			return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0;
 
diff -urN linux-2.4.5-pre3/drivers/char/wdt285.c linux/drivers/char/wdt285.c
--- linux-2.4.5-pre3/drivers/char/wdt285.c	Mon Oct 16 12:58:51 2000
+++ linux/drivers/char/wdt285.c	Mon Dec  3 22:44:23 2001
@@ -136,7 +136,7 @@
 	switch(cmd)
 	{
 		default:
-			return -ENOIOCTLCMD;
+			return -ENOTTY;
 		case WDIOC_GETSUPPORT:
 			i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct watchdog_info));
 			if (i)
diff -urN linux-2.4.5-pre3/drivers/char/wdt_pci.c linux/drivers/char/wdt_pci.c
--- linux-2.4.5-pre3/drivers/char/wdt_pci.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/wdt_pci.c	Mon Dec  3 22:44:23 2001
@@ -327,7 +327,7 @@
 	switch(cmd)
 	{
 		default:
-			return -ENOIOCTLCMD;
+			return -ENOTTY;
 		case WDIOC_GETSUPPORT:
 			return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0;
 
diff -urN linux-2.4.5-pre3/drivers/ide/alim15x3.c linux/drivers/ide/alim15x3.c
--- linux-2.4.5-pre3/drivers/ide/alim15x3.c	Fri Apr 27 14:15:01 2001
+++ linux/drivers/ide/alim15x3.c	Mon Dec  3 22:44:23 2001
@@ -233,8 +233,8 @@
 }
 #endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-static byte m5229_revision	= 0;
-static byte chip_is_1543c_e	= 0;
+static byte m5229_revision;
+static byte chip_is_1543c_e;
 
 byte ali_proc = 0;
 static struct pci_dev *isa_dev;
@@ -689,7 +689,8 @@
 		 * M1543C or newer for DMAing
 		 */
 		hwif->dmaproc = &ali15x3_dmaproc;
-		hwif->autodma = 1;
+		if (!noautodma)
+			hwif->autodma = 1;
 	}
 }
 
diff -urN linux-2.4.5-pre3/drivers/ide/amd7409.c linux/drivers/ide/amd7409.c
--- linux-2.4.5-pre3/drivers/ide/amd7409.c	Tue Nov  7 11:02:24 2000
+++ linux/drivers/ide/amd7409.c	Mon Dec  3 22:44:23 2001
@@ -455,7 +455,8 @@
 
 	if (hwif->dma_base) {
 		hwif->dmaproc = &amd7409_dmaproc;
-		hwif->autodma = 1;
+		if (!noautodma)
+			hwif->autodma = 1;
 	} else {
 		hwif->autodma = 0;
 		hwif->drives[0].autotune = 1;
diff -urN linux-2.4.5-pre3/drivers/ide/cy82c693.c linux/drivers/ide/cy82c693.c
--- linux-2.4.5-pre3/drivers/ide/cy82c693.c	Tue Jun 20 07:52:36 2000
+++ linux/drivers/ide/cy82c693.c	Mon Dec  3 22:44:23 2001
@@ -442,7 +442,8 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
 		hwif->dmaproc = &cy82c693_dmaproc;
-		hwif->autodma = 1;
+		if (!noautodma)
+			hwif->autodma = 1;
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 }
diff -urN linux-2.4.5-pre3/drivers/ide/hpt34x.c linux/drivers/ide/hpt34x.c
--- linux-2.4.5-pre3/drivers/ide/hpt34x.c	Tue Jun 20 07:52:36 2000
+++ linux/drivers/ide/hpt34x.c	Mon Dec  3 22:44:23 2001
@@ -419,7 +419,11 @@
 		unsigned short pcicmd = 0;
 
 		pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
-		hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
+		if (!noautodma)
+			hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
+		else
+			hwif->autodma = 0;
+
 		hwif->dmaproc = &hpt34x_dmaproc;
 	} else {
 		hwif->drives[0].autotune = 1;
diff -urN linux-2.4.5-pre3/drivers/ide/hpt366.c linux/drivers/ide/hpt366.c
--- linux-2.4.5-pre3/drivers/ide/hpt366.c	Sat Jan 27 08:45:58 2001
+++ linux/drivers/ide/hpt366.c	Mon Dec  3 22:44:23 2001
@@ -223,8 +223,8 @@
 byte hpt366_proc = 0;
 
 extern char *ide_xfer_verbose (byte xfer_rate);
-byte hpt363_shared_irq = 0;
-byte hpt363_shared_pin = 0;
+byte hpt363_shared_irq;
+byte hpt363_shared_pin;
 
 static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
 {
@@ -706,7 +706,10 @@
 		} else {
 			hwif->dmaproc = &hpt366_dmaproc;
 		}
-		hwif->autodma = 1;
+		if (!noautodma)
+			hwif->autodma = 1;
+		else
+			hwif->autodma = 0;
 	} else {
 		hwif->autodma = 0;
 		hwif->drives[0].autotune = 1;
diff -urN linux-2.4.5-pre3/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c
--- linux-2.4.5-pre3/drivers/ide/ide-pci.c	Mon Dec  3 22:43:49 2001
+++ linux/drivers/ide/ide-pci.c	Mon Dec  3 22:44:23 2001
@@ -708,7 +708,8 @@
 				/*
  	 			 * Set up BM-DMA capability (PnP BIOS should have done this)
  	 			 */
-				hwif->autodma = 0;	/* default DMA off if we had to configure it here */
+		    		if (!IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530)
+					hwif->autodma = 0;	/* default DMA off if we had to configure it here */
 				(void) pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER);
 				if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
 					printk("%s: %s error updating PCICMD\n", hwif->name, d->name);
diff -urN linux-2.4.5-pre3/drivers/ide/sis5513.c linux/drivers/ide/sis5513.c
--- linux-2.4.5-pre3/drivers/ide/sis5513.c	Tue Jan  2 16:58:45 2001
+++ linux/drivers/ide/sis5513.c	Mon Dec  3 22:44:23 2001
@@ -629,7 +629,8 @@
 			case PCI_DEVICE_ID_SI_5600:
 			case PCI_DEVICE_ID_SI_5597:
 			case PCI_DEVICE_ID_SI_5591:
-				hwif->autodma = 1;
+				if (!noautodma)
+					hwif->autodma = 1;
 				hwif->dmaproc = &sis5513_dmaproc;
 				break;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
diff -urN linux-2.4.5-pre3/drivers/ide/slc90e66.c linux/drivers/ide/slc90e66.c
--- linux-2.4.5-pre3/drivers/ide/slc90e66.c	Tue Mar  6 19:44:34 2001
+++ linux/drivers/ide/slc90e66.c	Mon Dec  3 22:44:23 2001
@@ -372,10 +372,10 @@
 	if (!hwif->dma_base)
 		return;
 
-#ifndef CONFIG_BLK_DEV_IDEDMA
 	hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-	hwif->autodma = 1;
+#ifdef CONFIG_BLK_DEV_IDEDMA 
+	if (!noautodma)
+		hwif->autodma = 1;
 	hwif->dmaproc = &slc90e66_dmaproc;
 	hwif->speedproc = &slc90e66_tune_chipset;
 #endif /* !CONFIG_BLK_DEV_IDEDMA */
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/avmcard.h linux/drivers/isdn/avmb1/avmcard.h
--- linux-2.4.5-pre3/drivers/isdn/avmb1/avmcard.h	Thu Apr 19 22:30:16 2001
+++ linux/drivers/isdn/avmb1/avmcard.h	Mon Dec  3 22:44:23 2001
@@ -1,60 +1,8 @@
 /*
- * $Id: avmcard.h,v 1.8.6.1 2001/04/20 02:41:59 keil Exp $
+ * $Id: avmcard.h,v 1.8.6.3 2001/05/17 21:15:33 kai Exp $
  *
  * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  *
- * $Log: avmcard.h,v $
- * Revision 1.8.6.1  2001/04/20 02:41:59  keil
- * changes from mainstream
- *
- * Revision 1.8  2000/10/10 17:44:19  kai
- * changes from/for 2.2.18
- *
- * Revision 1.7  2000/01/25 14:33:38  calle
- * - Added Support AVM B1 PCI V4.0 (tested with prototype)
- *   - splitted up t1pci.c into b1dma.c for common function with b1pciv4
- *   - support for revision register
- *
- * Revision 1.6  1999/11/05 16:38:01  calle
- * Cleanups before kernel 2.4:
- * - Changed all messages to use card->name or driver->name instead of
- *   constant string.
- * - Moved some data from struct avmcard into new struct avmctrl_info.
- *   Changed all lowlevel capi driver to match the new structur.
- *
- * Revision 1.5  1999/09/07 09:02:53  calle
- * SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
- * DATA_B3_IND is always directly after the CAPI message. The "Data" member
- * ist never used inside the kernel.
- *
- * Revision 1.4  1999/08/04 10:10:08  calle
- * Bugfix: corrected /proc functions, added structure for new AVM cards.
- *
- * Revision 1.3  1999/07/23 08:41:47  calle
- * prepared for new AVM cards.
- *
- * Revision 1.2  1999/07/05 15:09:45  calle
- * - renamed "appl_release" to "appl_released".
- * - version und profile data now cleared on controller reset
- * - extended /proc interface, to allow driver and controller specific
- *   informations to include by driver hackers.
- *
- * Revision 1.1  1999/07/01 15:26:22  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
  */
 
 #ifndef _AVMCARD_H_
@@ -62,7 +10,6 @@
 
 #define	AVMB1_PORTLEN		0x1f
 #define AVM_MAXVERSION		8
-#define AVM_NAPPS		30
 #define AVM_NCCI_PER_CHANNEL	4
 
 /*
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/b1.c	Thu Apr 19 22:30:16 2001
+++ linux/drivers/isdn/avmb1/b1.c	Mon Dec  3 22:44:23 2001
@@ -120,6 +120,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/capi.h>
+#include <linux/kernelcapi.h>
 #include <asm/io.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
@@ -129,7 +130,7 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.20.6.4 $";
+static char *revision = "$Revision: 1.20.6.6 $";
 
 /* ------------------------------------------------------------- */
 
@@ -374,7 +375,7 @@
 	cli();
 	b1_setinterrupt(port, card->irq, card->cardtype);
 	b1_put_byte(port, SEND_INIT);
-	b1_put_word(port, AVM_NAPPS);
+	b1_put_word(port, CAPI_MAXAPPL);
 	b1_put_word(port, AVM_NCCI_PER_CHANNEL*2);
 	b1_put_word(port, ctrl->cnr - 1);
 	restore_flags(flags);
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/b1dma.c	Thu Apr 19 22:30:16 2001
+++ linux/drivers/isdn/avmb1/b1dma.c	Mon Dec  3 22:44:23 2001
@@ -65,6 +65,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/capi.h>
+#include <linux/kernelcapi.h>
 #include <asm/io.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
@@ -74,7 +75,7 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.11.6.4 $";
+static char *revision = "$Revision: 1.11.6.6 $";
 
 /* ------------------------------------------------------------- */
 
@@ -731,7 +732,7 @@
 	_put_byte(&p, 0);
 	_put_byte(&p, 0);
 	_put_byte(&p, SEND_INIT);
-	_put_word(&p, AVM_NAPPS);
+	_put_word(&p, CAPI_MAXAPPL);
 	_put_word(&p, AVM_NCCI_PER_CHANNEL*30);
 	_put_word(&p, card->cardnr - 1);
 	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/b1isa.c linux/drivers/isdn/avmb1/b1isa.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/b1isa.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/b1isa.c	Mon Dec  3 22:44:23 2001
@@ -95,7 +95,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.10.6.4 $";
+static char *revision = "$Revision: 1.10.6.5 $";
 
 /* ------------------------------------------------------------- */
 
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/b1pci.c	Thu Apr 19 22:30:16 2001
+++ linux/drivers/isdn/avmb1/b1pci.c	Mon Dec  3 22:44:23 2001
@@ -125,7 +125,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.29.6.3 $";
+static char *revision = "$Revision: 1.29.6.4 $";
 
 /* ------------------------------------------------------------- */
 
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/b1pcmcia.c linux/drivers/isdn/avmb1/b1pcmcia.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/b1pcmcia.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/b1pcmcia.c	Mon Dec  3 22:44:23 2001
@@ -102,7 +102,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.12.6.3 $";
+static char *revision = "$Revision: 1.12.6.4 $";
 
 /* ------------------------------------------------------------- */
 
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/c4.c	Thu Apr 19 22:30:16 2001
+++ linux/drivers/isdn/avmb1/c4.c	Mon Dec  3 22:44:23 2001
@@ -112,6 +112,7 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/capi.h>
+#include <linux/kernelcapi.h>
 #include <linux/init.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -121,7 +122,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.20.6.6 $";
+static char *revision = "$Revision: 1.20.6.8 $";
 
 #undef CONFIG_C4_DEBUG
 #undef CONFIG_C4_POLLDEBUG
@@ -851,7 +852,7 @@
 	_put_byte(&p, 0);
 	_put_byte(&p, 0);
 	_put_byte(&p, SEND_INIT);
-	_put_word(&p, AVM_NAPPS);
+	_put_word(&p, CAPI_MAXAPPL);
 	_put_word(&p, AVM_NCCI_PER_CHANNEL*30);
 	_put_word(&p, card->cardnr - 1);
 	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/capi.c	Wed Apr 18 11:49:13 2001
+++ linux/drivers/isdn/avmb1/capi.c	Mon Dec  3 22:44:23 2001
@@ -1,238 +1,10 @@
 /*
- * $Id: capi.c,v 1.44.6.9 2001/04/08 17:51:42 kai Exp $
+ * $Id: capi.c,v 1.44.6.11 2001/05/17 20:41:51 kai Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
  * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
- * $Log: capi.c,v $
- * Revision 1.44.6.9  2001/04/08 17:51:42  kai
- * merge various fixes from HEAD (found by the CHECKER project)
- *
- * Revision 1.44.6.8  2001/03/21 08:52:21  kai
- * merge from main branch: fix buffer for revision string (calle)
- *
- * Revision 1.44.6.7  2001/03/15 15:11:24  kai
- * *** empty log message ***
- *
- * Revision 1.44.6.6  2001/03/13 16:17:07  kai
- * spelling fixes from 2.4.3-pre
- *
- * Revision 1.44.6.5  2001/02/13 11:43:29  kai
- * more compatility changes for 2.2.19
- *
- * Revision 1.44.6.4  2001/02/10 14:41:20  kai
- * Changes from kernel tree
- *
- * Revision 1.44.6.3  2000/12/17 22:45:08  kai
- * That's hopefully it for test13-4
- *
- * Revision 1.44.6.2  2000/12/14 23:04:12  kai
- * Makefile changes and the like for 2.4.0-test13-pre1
- * No compatiblity code for older kernels yet, but note the branch
- *
- * Revision 1.45  2000/12/02 19:47:29  kai
- * Change the Makefiles to new style.
- * There may be problems there that I missed, so this shouldn't go into
- * an offical kernel any time soon.
- * However, if I didn't commit it, we wouldn't find the bugs...
- *
- * Revision 1.44  2000/11/25 17:00:59  kai
- * compatibility cleanup - final part for the time being
- *
- * Revision 1.43  2000/11/23 20:45:14  kai
- * fixed module_init/exit stuff
- * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
- *
- * Revision 1.42  2000/11/19 17:03:55  kai
- * compatibility cleanup - part 5
- *
- * Revision 1.41  2000/11/01 14:05:02  calle
- * - use module_init/module_exit from linux/init.h.
- * - all static struct variables are initialized with "membername:" now.
- * - avm_cs.c, let it work with newer pcmcia-cs.
- *
- * Revision 1.40  2000/10/24 15:15:04  calle
- * Workaround: pppd calls restoretty before reseting the ldisc and
- *   ldisc "ppp_sync" didn't support this. So we call n_tty_ioctl
- *   in the driver ioctl function. (remember: driver ioctl function is
- *   only called if ldisc ioctl function did not handle the call)
- *
- * Revision 1.39  2000/07/24 13:42:50  calle
- * - lock_kernel/unlock_kernel for _release functions. (from 2.4)
- *
- * Revision 1.38  2000/07/24 08:49:09  calle
- * - Bugfix: capiminor_del_all_ack completely wrong :-(
- *
- * Revision 1.37  2000/07/20 10:22:27  calle
- * - Made procfs function cleaner and removed variable "begin".
- *
- * Revision 1.36  2000/06/29 13:59:35  calle
- * - call to devfs_register was wrong
- *
- * Revision 1.35  2000/06/19 15:11:24  keil
- * avoid use of freed structs
- * changes from 2.4.0-ac21
- *
- * Revision 1.34  2000/06/18 16:09:54  keil
- * more changes for 2.4
- *
- * Revision 1.33  2000/05/18 16:35:43  calle
- * Uaaahh. Bad memory leak fixed.
- *
- * Revision 1.32  2000/04/21 12:38:42  calle
- * Bugfix: error in proc_ functions, begin-off => off-begin
- *
- * Revision 1.31  2000/04/03 13:29:24  calle
- * make Tim Waugh happy (module unload races in 2.3.99-pre3).
- * no real problem there, but now it is much cleaner ...
- *
- * Revision 1.30  2000/03/19 12:31:36  calle
- * PPP over CAPI raw driver disabled for now, ppp_generic has been changed.
- *
- * Revision 1.29  2000/03/13 17:48:13  calle
- * removed unused variable.
- *
- * Revision 1.28  2000/03/08 17:06:33  calle
- * - changes for devfs and 2.3.49
- * - capifs now configurable (no need with devfs)
- * - New Middleware ioctl CAPI_NCCI_GETUNIT
- * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
- *
- * Revision 1.27  2000/03/06 18:00:23  calle
- * - Middleware extention now working with 2.3.49 (capifs).
- * - Fixed typos in debug section of capi.c
- * - Bugfix: Makefile corrected for b1pcmcia.c
- *
- * Revision 1.26  2000/03/03 16:48:38  calle
- * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
- *   It is now possible to create a connection with a CAPI2.0 applikation
- *   and than to handle the data connection from /dev/capi/ (capifs) and also
- *   using async or sync PPP on this connection.
- *   The two major device number 190 and 191 are not confirmed yet,
- *   but I want to save the code in cvs, before I go on.
- *
- * Revision 1.25  2000/03/03 16:37:11  kai
- * incorporated some cosmetic changes from the official kernel tree back
- * into CVS
- *
- * Revision 1.24  2000/03/03 15:50:42  calle
- * - kernel CAPI:
- *   - Changed parameter "param" in capi_signal from __u32 to void *.
- *   - rewrote notifier handling in kcapi.c
- *   - new notifier NCCI_UP and NCCI_DOWN
- * - User CAPI:
- *   - /dev/capi20 is now a cloning device.
- *   - middleware extentions prepared.
- * - capidrv.c
- *   - locking of list operations and module count updates.
- *
- * Revision 1.23  2000/02/26 01:00:53  keil
- * changes from 2.3.47
- *
- * Revision 1.22  1999/11/13 21:27:16  keil
- * remove KERNELVERSION
- *
- * Revision 1.21  1999/09/10 17:24:18  calle
- * Changes for proposed standard for CAPI2.0:
- * - AK148 "Linux Exention"
- *
- * Revision 1.20  1999/09/07 09:02:53  calle
- * SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
- * DATA_B3_IND is always directly after the CAPI message. The "Data" member
- * ist never used inside the kernel.
- *
- * Revision 1.19  1999/07/09 15:05:42  keil
- * compat.h is now isdn_compat.h
- *
- * Revision 1.18  1999/07/06 07:42:01  calle
- * - changes in /proc interface
- * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb.
- *
- * Revision 1.17  1999/07/01 15:26:30  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
- * Revision 1.16  1999/07/01 08:22:57  keil
- * compatibility macros now in <linux/isdn_compat.h>
- *
- * Revision 1.15  1999/06/21 15:24:11  calle
- * extend information in /proc.
- *
- * Revision 1.14  1999/06/10 16:51:03  calle
- * Bugfix: open/release of control device was not handled correct.
- *
- * Revision 1.13  1998/08/28 04:32:25  calle
- * Added patch send by Michael.Mueller4@post.rwth-aachen.de, to get AVM B1
- * driver running with 2.1.118.
- *
- * Revision 1.12  1998/05/26 22:39:34  he
- * sync'ed with 2.1.102 where appropriate (CAPABILITY changes)
- * concap typo
- * cleared dev.tbusy in isdn_net BCONN status callback
- *
- * Revision 1.11  1998/03/09 17:46:37  he
- * merged in 2.1.89 changes
- *
- * Revision 1.10  1998/02/13 07:09:13  calle
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.9  1998/01/31 11:14:44  calle
- * merged changes to 2.0 tree, prepare 2.1.82 to work.
- *
- * Revision 1.8  1997/11/04 06:12:08  calle
- * capi.c: new read/write in file_ops since 2.1.60
- * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
- * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
- * compat.h: added #define LinuxVersionCode
- *
- * Revision 1.7  1997/10/11 10:29:34  calle
- * llseek() parameters changed in 2.1.56.
- *
- * Revision 1.6  1997/10/01 09:21:15  fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 1.5  1997/08/21 23:11:55  fritz
- * Added changes for kernels >= 2.1.45
- *
- * Revision 1.4  1997/05/27 15:17:50  fritz
- * Added changes for recent 2.1.x kernels:
- *   changed return type of isdn_close
- *   queue_task_* -> queue_task
- *   clear/set_bit -> test_and_... where apropriate.
- *   changed type of hard_header_cache parameter.
- *
- * Revision 1.3  1997/05/18 09:24:14  calle
- * added verbose disconnect reason reporting to avmb1.
- * some fixes in capi20 interface.
- * changed info messages for B1-PCI
- *
- * Revision 1.2  1997/03/05 21:17:59  fritz
- * Added capi_poll for compiling under 2.1.27
- *
- * Revision 1.1  1997/03/04 21:50:29  calle
- * Frirst version in isdn4linux
- *
- * Revision 2.2  1997/02/12 09:31:39  calle
- * new version
- *
- * Revision 1.1  1997/01/31 10:32:20  calle
- * Initial revision
- *
  */
 
 #include <linux/config.h>
@@ -271,7 +43,7 @@
 #include "capifs.h"
 #endif
 
-static char *revision = "$Revision: 1.44.6.9 $";
+static char *revision = "$Revision: 1.44.6.11 $";
 
 MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
 
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/capidev.h linux/drivers/isdn/avmb1/capidev.h
--- linux-2.4.5-pre3/drivers/isdn/avmb1/capidev.h	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/avmb1/capidev.h	Mon Dec  3 22:44:23 2001
@@ -1,55 +1,9 @@
 /*
- * $Id: capidev.h,v 1.6 2000/11/25 17:00:59 kai Exp $
+ * $Id: capidev.h,v 1.6.6.1 2001/05/17 20:41:51 kai Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
  * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
- *
- * $Log: capidev.h,v $
- * Revision 1.6  2000/11/25 17:00:59  kai
- * compatibility cleanup - final part for the time being
- *
- * Revision 1.5  2000/03/03 15:50:42  calle
- * - kernel CAPI:
- *   - Changed parameter "param" in capi_signal from __u32 to void *.
- *   - rewrote notifier handling in kcapi.c
- *   - new notifier NCCI_UP and NCCI_DOWN
- * - User CAPI:
- *   - /dev/capi20 is now a cloning device.
- *   - middleware extentions prepared.
- * - capidrv.c
- *   - locking of list operations and module count updates.
- *
- * Revision 1.4  1999/07/01 15:26:32  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
- * Revision 1.3  1999/07/01 08:22:58  keil
- * compatibility macros now in <linux/isdn_compat.h>
- *
- * Revision 1.2  1999/06/21 15:24:13  calle
- * extend information in /proc.
- *
- * Revision 1.1  1997/03/04 21:50:30  calle
- * Frirst version in isdn4linux
- *
- * Revision 2.2  1997/02/12 09:31:39  calle
- * new version
- *
- * Revision 1.1  1997/01/31 10:32:20  calle
- * Initial revision
  *
  */
 
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/capidrv.c	Wed Apr 18 11:49:13 2001
+++ linux/drivers/isdn/avmb1/capidrv.c	Mon Dec  3 22:44:23 2001
@@ -1,211 +1,10 @@
 /*
- * $Id: capidrv.c,v 1.39.6.5 2001/04/08 17:51:42 kai Exp $
+ * $Id: capidrv.c,v 1.39.6.6 2001/05/17 20:41:51 kai Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  *
- * $Log: capidrv.c,v $
- * Revision 1.39.6.5  2001/04/08 17:51:42  kai
- * merge various fixes from HEAD (found by the CHECKER project)
- *
- * Revision 1.39.6.4  2001/03/21 08:52:21  kai
- * merge from main branch: fix buffer for revision string (calle)
- *
- * Revision 1.39.6.3  2001/03/13 16:17:07  kai
- * spelling fixes from 2.4.3-pre
- *
- * Revision 1.39.6.2  2001/02/13 11:43:29  kai
- * more compatility changes for 2.2.19
- *
- * Revision 1.39.6.1  2001/02/10 14:41:20  kai
- * Changes from kernel tree
- *
- * Revision 1.39  2000/11/23 20:45:14  kai
- * fixed module_init/exit stuff
- * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
- *
- * Revision 1.38  2000/11/14 08:43:07  calle
- * Bugfix for v110. Connectparamters where setup for sync ...
- *
- * Revision 1.37  2000/11/01 14:05:02  calle
- * - use module_init/module_exit from linux/init.h.
- * - all static struct variables are initialized with "membername:" now.
- * - avm_cs.c, let it work with newer pcmcia-cs.
- *
- * Revision 1.36  2000/06/26 15:13:41  keil
- * features should be or'ed
- *
- * Revision 1.35  2000/06/19 15:11:25  keil
- * avoid use of freed structs
- * changes from 2.4.0-ac21
- *
- * Revision 1.34  2000/06/19 13:13:55  calle
- * Added Modemsupport!
- *
- * Revision 1.33  2000/05/06 00:52:36  kai
- * merged changes from kernel tree
- * fixed timer and net_device->name breakage
- *
- * Revision 1.32  2000/04/07 15:19:58  calle
- * remove warnings
- *
- * Revision 1.31  2000/04/06 15:01:25  calle
- * Bugfix: crash in capidrv.c when reseting a capi controller.
- * - changed code order on remove of controller.
- * - using tq_schedule for notifier in kcapi.c.
- * - now using spin_lock_irqsave() and spin_unlock_irqrestore().
- * strange: sometimes even MP hang on unload of isdn.o ...
- *
- * Revision 1.30  2000/03/03 15:50:42  calle
- * - kernel CAPI:
- *   - Changed parameter "param" in capi_signal from __u32 to void *.
- *   - rewrote notifier handling in kcapi.c
- *   - new notifier NCCI_UP and NCCI_DOWN
- * - User CAPI:
- *   - /dev/capi20 is now a cloning device.
- *   - middleware extentions prepared.
- * - capidrv.c
- *   - locking of list operations and module count updates.
- *
- * Revision 1.29  1999/12/06 17:13:06  calle
- * Added controller watchdog.
- *
- * Revision 1.28  1999/11/05 16:22:37  calle
- * Bugfix: Missing break in switch on ISDN_CMD_HANGUP.
- *
- * Revision 1.27  1999/09/16 15:13:04  calle
- * forgot to change paramter type of contr for lower_callback ...
- *
- * Revision 1.26  1999/08/06 07:41:16  calle
- * Added the "vbox patch". if (si1 == 1) si2 = 0;
- *
- * Revision 1.25  1999/08/04 10:10:11  calle
- * Bugfix: corrected /proc functions, added structure for new AVM cards.
- *
- * Revision 1.24  1999/07/20 06:48:02  calle
- * Bugfix: firmware version check for D2 trace was too restrictiv.
- *
- * Revision 1.23  1999/07/09 15:05:44  keil
- * compat.h is now isdn_compat.h
- *
- * Revision 1.22  1999/07/06 07:24:14  calle
- * Bugfix: call to kfree_skb in capidrv_signal was too early,
- *         thanks to Lars Heete <hel@admin.de>.
- *
- * Revision 1.21  1999/07/01 15:26:34  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
- * Revision 1.20  1999/07/01 08:22:59  keil
- * compatibility macros now in <linux/isdn_compat.h>
- *
- * Revision 1.19  1999/06/29 16:16:54  calle
- * Let ISDN_CMD_UNLOAD work with open isdn devices without crash again.
- * Also right unlocking (ISDN_CMD_UNLOCK) is done now.
- * isdnlog should check returncode of read(2) calls.
- *
- * Revision 1.18  1999/06/21 15:24:15  calle
- * extend information in /proc.
- *
- * Revision 1.17  1999/06/10 16:53:55  calle
- * Removing of module b1pci will now remove card from lower level.
- *
- * Revision 1.16  1999/05/31 11:50:33  calle
- * Bugfix: In if_sendbuf, skb_push'ed DATA_B3 header was not skb_pull'ed
- *         on failure, result in data block with DATA_B3 header transmitted
- *
- * Revision 1.15  1999/05/25 21:26:16  calle
- * Include CAPI-Channelallocation (leased lines) from the 2.0 tree.
- *
- * Revision 1.14  1999/05/22 07:55:06  calle
- * Added *V110* to AVM B1 driver.
- *
- * Revision 1.13  1998/06/26 15:12:55  fritz
- * Added handling of STAT_ICALL with incomplete CPN.
- * Added AT&L for ttyI emulator.
- * Added more locking stuff in tty_write.
- *
- * Revision 1.12  1998/03/29 16:06:03  calle
- * changes from 2.0 tree merged.
- *
- * Revision 1.3.2.10  1998/03/20 14:38:24  calle
- * capidrv: prepared state machines for suspend/resume/hold
- * capidrv: fix bug in state machine if B1/T1 is out of nccis
- * b1capi: changed some errno returns.
- * b1capi: detect if you try to add same T1 to different io address.
- * b1capi: change number of nccis depending on number of channels.
- * b1lli: cosmetics
- *
- * Revision 1.3.2.9  1998/03/20 09:01:12  calle
- * Changes capi_register handling to get full support for 30 bchannels.
- *
- * Revision 1.3.2.8  1998/03/18 17:51:28  calle
- * added controller number to error messages
- *
- * Revision 1.3.2.7  1998/02/27 15:40:47  calle
- * T1 running with slow link. bugfix in capi_release.
- *
- * Revision 1.11  1998/02/13 07:09:15  calle
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.10  1998/02/02 19:52:23  calle
- * Fixed vbox (audio) acceptb.
- *
- * Revision 1.9  1998/01/31 11:14:45  calle
- * merged changes to 2.0 tree, prepare 2.1.82 to work.
- *
- * Revision 1.8  1997/11/04 06:12:09  calle
- * capi.c: new read/write in file_ops since 2.1.60
- * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
- * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
- * compat.h: added #define LinuxVersionCode
- *
- * Revision 1.7  1997/10/11 10:36:34  calle
- * Added isdnlog support. patch to isdnlog needed.
- *
- * Revision 1.6  1997/10/11 10:25:55  calle
- * New interface for lowlevel drivers. BSENT with nr. of bytes sent,
- * allow sending without ACK.
- *
- * Revision 1.5  1997/10/01 09:21:16  fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 1.4  1997/07/13 12:22:43  calle
- * bug fix for more than one controller in connect_req.
- * debugoutput now with contrnr.
- *
- * Revision 1.3  1997/05/18 09:24:15  calle
- * added verbose disconnect reason reporting to avmb1.
- * some fixes in capi20 interface.
- * changed info messages for B1-PCI
- *
- * Revision 1.2  1997/03/05 21:19:59  fritz
- * Removed include of config.h (mkdep stated this is unneded).
- *
- * Revision 1.1  1997/03/04 21:50:31  calle
- * Frirst version in isdn4linux
- *
- * Revision 2.2  1997/02/12 09:31:39  calle
- * new version
- *
- * Revision 1.1  1997/01/31 10:32:20  calle
- * Initial revision
- *
  */
 
 #include <linux/module.h>
@@ -234,7 +33,7 @@
 #include "capicmd.h"
 #include "capidrv.h"
 
-static char *revision = "$Revision: 1.39.6.5 $";
+static char *revision = "$Revision: 1.39.6.6 $";
 static int debugmode = 0;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/capidrv.h linux/drivers/isdn/avmb1/capidrv.h
--- linux-2.4.5-pre3/drivers/isdn/avmb1/capidrv.h	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/avmb1/capidrv.h	Mon Dec  3 22:44:23 2001
@@ -1,30 +1,9 @@
 /*
- * $Id: capidrv.h,v 1.2 1998/03/29 16:06:06 calle Exp $
+ * $Id: capidrv.h,v 1.2.8.1 2001/05/17 20:41:51 kai Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
- *
- * $Log: capidrv.h,v $
- * Revision 1.2  1998/03/29 16:06:06  calle
- * changes from 2.0 tree merged.
- *
- * Revision 1.1.2.1  1998/03/20 14:38:28  calle
- * capidrv: prepared state machines for suspend/resume/hold
- * capidrv: fix bug in state machine if B1/T1 is out of nccis
- * b1capi: changed some errno returns.
- * b1capi: detect if you try to add same T1 to different io address.
- * b1capi: change number of nccis depending on number of channels.
- * b1lli: cosmetics
- *
- * Revision 1.1  1997/03/04 21:50:33  calle
- * Frirst version in isdn4linux
- *
- * Revision 2.2  1997/02/12 09:31:39  calle
- * new version
- *
- * Revision 1.1  1997/01/31 10:32:20  calle
- * Initial revision
  *
  */
 #ifndef __CAPIDRV_H__
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/capifs.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/capifs.c	Mon Dec  3 22:44:23 2001
@@ -105,7 +105,7 @@
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.de>");
 
-static char *revision = "$Revision: 1.14.6.5 $";
+static char *revision = "$Revision: 1.14.6.6 $";
 
 struct capifs_ncci {
 	struct inode *inode;
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/capiutil.c linux/drivers/isdn/avmb1/capiutil.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/capiutil.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/capiutil.c	Mon Dec  3 22:44:23 2001
@@ -1,93 +1,10 @@
 /*
- * $Id: capiutil.c,v 1.13.6.2 2001/03/15 15:11:24 kai Exp $
+ * $Id: capiutil.c,v 1.13.6.3 2001/05/17 20:41:51 kai Exp $
  *
  * CAPI 2.0 convert capi message to capi message struct
  *
  * From CAPI 2.0 Development Kit AVM 1995 (msg.c)
  * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
- *
- * $Log: capiutil.c,v $
- * Revision 1.13.6.2  2001/03/15 15:11:24  kai
- * *** empty log message ***
- *
- * Revision 1.13.6.1  2001/02/13 11:43:29  kai
- * more compatility changes for 2.2.19
- *
- * Revision 1.13  2000/11/23 20:45:14  kai
- * fixed module_init/exit stuff
- * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
- *
- * Revision 1.12  2000/11/01 14:05:02  calle
- * - use module_init/module_exit from linux/init.h.
- * - all static struct variables are initialized with "membername:" now.
- * - avm_cs.c, let it work with newer pcmcia-cs.
- *
- * Revision 1.11  2000/03/03 15:50:42  calle
- * - kernel CAPI:
- *   - Changed parameter "param" in capi_signal from __u32 to void *.
- *   - rewrote notifier handling in kcapi.c
- *   - new notifier NCCI_UP and NCCI_DOWN
- * - User CAPI:
- *   - /dev/capi20 is now a cloning device.
- *   - middleware extentions prepared.
- * - capidrv.c
- *   - locking of list operations and module count updates.
- *
- * Revision 1.10  1999/08/31 11:19:54  paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.9  1999/07/09 15:05:46  keil
- * compat.h is now isdn_compat.h
- *
- * Revision 1.8  1999/07/01 15:26:37  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
- * Revision 1.7  1999/07/01 08:23:01  keil
- * compatibility macros now in <linux/isdn_compat.h>
- *
- * Revision 1.6  1997/11/04 06:12:12  calle
- * capi.c: new read/write in file_ops since 2.1.60
- * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
- * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
- * compat.h: added #define LinuxVersionCode
- *
- * Revision 1.5  1997/10/01 09:21:19  fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 1.4  1997/08/10 07:43:55  calle
- * forgot to export symbol capi_info2str for 2.1.x
- *
- * Revision 1.3  1997/05/18 09:24:18  calle
- * added verbose disconnect reason reporting to avmb1.
- * some fixes in capi20 interface.
- * changed info messages for B1-PCI
- *
- * Revision 1.2  1997/03/05 21:22:13  fritz
- * Fix: Symbols have to be exported unconditionally.
- *
- * Revision 1.1  1997/03/04 21:50:34  calle
- * Frirst version in isdn4linux
- *
- * Revision 2.2  1997/02/12 09:31:39  calle
- * new version
- *
- * Revision 1.1  1997/01/31 10:32:20  calle
- * Initial revision
  *
  */
 #include <linux/module.h>
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/kcapi.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/kcapi.c	Mon Dec  3 22:44:23 2001
@@ -148,7 +148,7 @@
 #include <linux/b1lli.h>
 #endif
 
-static char *revision = "$Revision: 1.21.6.5 $";
+static char *revision = "$Revision: 1.21.6.6 $";
 
 /* ------------------------------------------------------------- */
 
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/t1isa.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/t1isa.c	Mon Dec  3 22:44:23 2001
@@ -109,6 +109,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/capi.h>
+#include <linux/kernelcapi.h>
 #include <linux/init.h>
 #include <asm/io.h>
 #include "capicmd.h"
@@ -116,7 +117,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.16.6.4 $";
+static char *revision = "$Revision: 1.16.6.6 $";
 
 /* ------------------------------------------------------------- */
 
@@ -410,7 +411,7 @@
 	cli();
 	b1_setinterrupt(port, card->irq, card->cardtype);
 	b1_put_byte(port, SEND_INIT);
-	b1_put_word(port, AVM_NAPPS);
+	b1_put_word(port, CAPI_MAXAPPL);
 	b1_put_word(port, AVM_NCCI_PER_CHANNEL*30);
 	b1_put_word(port, ctrl->cnr - 1);
 	restore_flags(flags);
diff -urN linux-2.4.5-pre3/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c
--- linux-2.4.5-pre3/drivers/isdn/avmb1/t1pci.c	Wed Apr 18 11:49:13 2001
+++ linux/drivers/isdn/avmb1/t1pci.c	Mon Dec  3 22:44:23 2001
@@ -94,7 +94,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.13.6.3 $";
+static char *revision = "$Revision: 1.13.6.5 $";
 
 #undef CONFIG_T1PCI_DEBUG
 #undef CONFIG_T1PCI_POLLDEBUG
diff -urN linux-2.4.5-pre3/drivers/isdn/eicon/bri.c linux/drivers/isdn/eicon/bri.c
--- linux-2.4.5-pre3/drivers/isdn/eicon/bri.c	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/eicon/bri.c	Mon Dec  3 22:44:23 2001
@@ -21,8 +21,7 @@
  *
  */
 
-#include <sys/types.h>
-
+#include "eicon.h"
 #include "sys.h"
 #include "idi.h"
 #include "divas.h"
@@ -33,9 +32,6 @@
 #include "adapter.h"
 #include "uxio.h"
 
-#define PCI_COMMAND	0x04
-#define PCI_STATUS	0x06
-#define PCI_LATENCY	0x0D
 #define PCI_BADDR0	0x10
 #define PCI_BADDR1	0x14
 #define PCI_BADDR2	0x18
diff -urN linux-2.4.5-pre3/drivers/isdn/eicon/common.c linux/drivers/isdn/eicon/common.c
--- linux-2.4.5-pre3/drivers/isdn/eicon/common.c	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/eicon/common.c	Mon Dec  3 22:44:23 2001
@@ -22,6 +22,7 @@
  */
 
 
+#include "eicon.h"
 #include "sys.h"
 #include "idi.h"
 #include "constant.h"
@@ -30,19 +31,14 @@
 #include "pr_pc.h"
 
 #include "uxio.h"
-#include <sys/types.h>
-
-#define MAX_ADDR_LEN
 
 #define DIVAS_LOAD_CMD		0x02
 #define DIVAS_START_CMD		0x03
 #define DIVAS_IRQ_RESET		0xC18
 #define DIVAS_IRQ_RESET_VAL	0xFE
 
-#define	PCI_COMMAND	0x04
-#define	PCI_STATUS	0x06
-#define	PCI_LATENCY	0x0D
-#define PCI_INTERRUPT	0x3C
+#define	PCI_LATENCY	PCI_LATENCY_TIMER
+#define PCI_INTERRUPT	PCI_INTERRUPT_LINE
 
 #define TEST_INT_DIVAS		0x11
 #define TEST_INT_DIVAS_BRI	0x12
@@ -93,7 +89,7 @@
         }
 
         if (tablelength > 0)
-          bcopy((caddr_t)DIDD_Table, (caddr_t)table, tablelength);
+          bcopy((void *)DIDD_Table, (void *)table, tablelength);
 
 	return;
 }
@@ -103,7 +99,7 @@
         if (tablelength > sizeof(DIDD_Table))
           tablelength = sizeof(DIDD_Table);
 
-	bcopy((caddr_t)table, (caddr_t)DIDD_Table, tablelength);
+	bcopy((void *)table, (void *)DIDD_Table, tablelength);
 
 	return;
 }
@@ -573,7 +569,7 @@
 
 		b = card->cfg.irq;
 
-		UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT, &b);
+		UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT_LINE, &b);
 
 		if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q)
 		{
diff -urN linux-2.4.5-pre3/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h
--- linux-2.4.5-pre3/drivers/isdn/eicon/eicon.h	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/eicon/eicon.h	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.23.6.2 2001/02/13 11:43:30 kai Exp $
+/* $Id: eicon.h,v 1.23.6.3 2001/05/17 21:15:33 kai Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  *
@@ -147,9 +147,11 @@
 #include <linux/wait.h>
 #include <linux/delay.h>
 #include <linux/ctype.h>
+#include <linux/pci.h>
 
 #include <linux/isdn.h>
 #include <linux/isdnif.h>
+
 
 typedef struct {
   __u16 length __attribute__ ((packed)); /* length of data/parameter field */
diff -urN linux-2.4.5-pre3/drivers/isdn/eicon/kprintf.c linux/drivers/isdn/eicon/kprintf.c
--- linux-2.4.5-pre3/drivers/isdn/eicon/kprintf.c	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/eicon/kprintf.c	Mon Dec  3 22:44:23 2001
@@ -27,13 +27,11 @@
  */
 
 
+#include "eicon.h"
 #include "sys.h"
 #include <stdarg.h>
 #undef MAX
 #undef MIN
-
-#include <sys/types.h>
-#include <sys/param.h>
 
 #include "divas.h"
 #include "divalog.h"
diff -urN linux-2.4.5-pre3/drivers/isdn/hysdn/boardergo.c linux/drivers/isdn/hysdn/boardergo.c
--- linux-2.4.5-pre3/drivers/isdn/hysdn/boardergo.c	Wed Apr 18 11:49:14 2001
+++ linux/drivers/isdn/hysdn/boardergo.c	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: boardergo.c,v 1.5.6.3 2001/03/13 16:17:09 kai Exp $
+/* $Id: boardergo.c,v 1.5.6.4 2001/04/20 02:42:00 keil Exp $
 
  * Linux driver for HYSDN cards, specific routines for ergo type boards.
  *
diff -urN linux-2.4.5-pre3/drivers/isdn/hysdn/hycapi.c linux/drivers/isdn/hysdn/hycapi.c
--- linux-2.4.5-pre3/drivers/isdn/hysdn/hycapi.c	Wed Apr 18 11:49:14 2001
+++ linux/drivers/isdn/hysdn/hycapi.c	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: hycapi.c,v 1.8.6.1 2001/02/16 16:43:30 kai Exp $
+/* $Id: hycapi.c,v 1.8.6.2 2001/04/20 02:42:00 keil Exp $
  *
  * Linux driver for HYSDN cards, CAPI2.0-Interface.
  * written by Ulrich Albrecht (u.albrecht@hypercope.de) for Hypercope GmbH
@@ -41,7 +41,7 @@
 #include "hysdn_defs.h"
 #include <linux/kernelcapi.h>
 
-static char hycapi_revision[]="$Revision: 1.11 $";
+static char hycapi_revision[]="$Revision: 1.8.6.2 $";
 
 unsigned int hycapi_enable = 0xffffffff; 
 MODULE_PARM(hycapi_enable, "i");
diff -urN linux-2.4.5-pre3/drivers/isdn/hysdn/hysdn_defs.h linux/drivers/isdn/hysdn/hysdn_defs.h
--- linux-2.4.5-pre3/drivers/isdn/hysdn/hysdn_defs.h	Wed Apr 18 11:49:14 2001
+++ linux/drivers/isdn/hysdn/hysdn_defs.h	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_defs.h,v 1.5.6.1 2000/11/28 12:02:47 kai Exp $
+/* $Id: hysdn_defs.h,v 1.5.6.2 2001/04/20 02:42:00 keil Exp $
 
  * Linux driver for HYSDN cards, global definitions and exported vars and functions.
  * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
diff -urN linux-2.4.5-pre3/drivers/isdn/hysdn/hysdn_net.c linux/drivers/isdn/hysdn/hysdn_net.c
--- linux-2.4.5-pre3/drivers/isdn/hysdn/hysdn_net.c	Wed Apr 18 11:49:14 2001
+++ linux/drivers/isdn/hysdn/hysdn_net.c	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_net.c,v 1.8.6.1 2001/02/16 16:43:30 kai Exp $
+/* $Id: hysdn_net.c,v 1.8.6.2 2001/04/20 02:42:00 keil Exp $
 
  * Linux driver for HYSDN cards, net (ethernet type) handling routines.
  *
@@ -41,7 +41,7 @@
 MODULE_PARM(hynet_enable, "i");
 
 /* store the actual version for log reporting */
-char *hysdn_net_revision = "$Revision: 1.10 $";
+char *hysdn_net_revision = "$Revision: 1.8.6.2 $";
 
 #define MAX_SKB_BUFFERS 20	/* number of buffers for keeping TX-data */
 
diff -urN linux-2.4.5-pre3/drivers/isdn/hysdn/hysdn_procconf.c linux/drivers/isdn/hysdn/hysdn_procconf.c
--- linux-2.4.5-pre3/drivers/isdn/hysdn/hysdn_procconf.c	Wed Apr 18 11:49:14 2001
+++ linux/drivers/isdn/hysdn/hysdn_procconf.c	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_procconf.c,v 1.8.6.1 2001/03/13 16:17:09 kai Exp $
+/* $Id: hysdn_procconf.c,v 1.8.6.2 2001/04/20 02:42:00 keil Exp $
 
  * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
  * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -31,7 +31,7 @@
 
 #include "hysdn_defs.h"
 
-static char *hysdn_procconf_revision = "$Revision: 1.8.6.1 $";
+static char *hysdn_procconf_revision = "$Revision: 1.8.6.2 $";
 
 #define INFO_OUT_LEN 80		/* length of info line including lf */
 
diff -urN linux-2.4.5-pre3/drivers/isdn/hysdn/hysdn_sched.c linux/drivers/isdn/hysdn/hysdn_sched.c
--- linux-2.4.5-pre3/drivers/isdn/hysdn/hysdn_sched.c	Wed Apr 18 11:49:14 2001
+++ linux/drivers/isdn/hysdn/hysdn_sched.c	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_sched.c,v 1.5.6.1 2001/03/13 16:17:09 kai Exp $
+/* $Id: hysdn_sched.c,v 1.5.6.2 2001/04/20 02:42:00 keil Exp $
 
  * Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc.
  *
diff -urN linux-2.4.5-pre3/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- linux-2.4.5-pre3/drivers/isdn/isdn_common.c	Wed Apr 18 11:49:14 2001
+++ linux/drivers/isdn/isdn_common.c	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.114.6.10 2001/04/08 19:14:00 kai Exp $
+/* $Id: isdn_common.c,v 1.114.6.11 2001/04/20 02:41:58 keil Exp $
 
  * Linux ISDN subsystem, common used functions (linklevel).
  *
@@ -51,7 +51,7 @@
 
 isdn_dev *dev;
 
-static char *isdn_revision = "$Revision: 1.114.6.10 $";
+static char *isdn_revision = "$Revision: 1.114.6.11 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
diff -urN linux-2.4.5-pre3/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- linux-2.4.5-pre3/drivers/isdn/isdn_net.c	Wed Apr 18 11:49:14 2001
+++ linux/drivers/isdn/isdn_net.c	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.140.6.3 2001/02/07 11:31:30 kai Exp $
+/* $Id: isdn_net.c,v 1.140.6.4 2001/04/20 02:41:58 keil Exp $
 
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
@@ -190,7 +190,7 @@
 static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
 static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
 
-char *isdn_net_revision = "$Revision: 1.144 $";
+char *isdn_net_revision = "$Revision: 1.140.6.4 $";
 
  /*
   * Code for raw-networking over ISDN
diff -urN linux-2.4.5-pre3/drivers/isdn/isdn_net.h linux/drivers/isdn/isdn_net.h
--- linux-2.4.5-pre3/drivers/isdn/isdn_net.h	Wed Apr 18 11:49:14 2001
+++ linux/drivers/isdn/isdn_net.h	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.h,v 1.19 2000/06/21 09:54:29 keil Exp $
+/* $Id: isdn_net.h,v 1.19.6.1 2001/04/20 02:41:58 keil Exp $
 
  * header for Linux ISDN subsystem, network related functions (linklevel).
  *
diff -urN linux-2.4.5-pre3/drivers/md/md.c linux/drivers/md/md.c
--- linux-2.4.5-pre3/drivers/md/md.c	Mon Dec  3 22:43:49 2001
+++ linux/drivers/md/md.c	Mon Dec  3 22:44:23 2001
@@ -2997,7 +2997,7 @@
 	int sz = 0;
 	unsigned long max_blocks, resync, res, dt, db, rt;
 
-	resync = mddev->curr_resync - atomic_read(&mddev->recovery_active);
+	resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2;
 	max_blocks = mddev->sb->size;
 
 	/*
@@ -3042,7 +3042,7 @@
 	 */
 	dt = ((jiffies - mddev->resync_mark) / HZ);
 	if (!dt) dt++;
-	db = resync - mddev->resync_mark_cnt;
+	db = resync - (mddev->resync_mark_cnt/2);
 	rt = (dt * ((max_blocks-resync) / (db/100+1)))/100;
 	
 	sz += sprintf(page + sz, " finish=%lu.%lumin", rt / 60, (rt % 60)/6);
@@ -3217,7 +3217,7 @@
 
 void md_done_sync(mddev_t *mddev, int blocks, int ok)
 {
-	/* another "blocks" (1K) blocks have been synced */
+	/* another "blocks" (512byte) blocks have been synced */
 	atomic_sub(blocks, &mddev->recovery_active);
 	wake_up(&mddev->recovery_wait);
 	if (!ok) {
@@ -3230,7 +3230,7 @@
 int md_do_sync(mddev_t *mddev, mdp_disk_t *spare)
 {
 	mddev_t *mddev2;
-	unsigned int max_blocks, currspeed,
+	unsigned int max_sectors, currspeed,
 		j, window, err, serialize;
 	kdev_t read_disk = mddev_to_kdev(mddev);
 	unsigned long mark[SYNC_MARKS];
@@ -3267,7 +3267,7 @@
 
 	mddev->curr_resync = 1;
 
-	max_blocks = mddev->sb->size;
+	max_sectors = mddev->sb->size<<1;
 
 	printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev));
 	printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n",
@@ -3291,23 +3291,23 @@
 	/*
 	 * Tune reconstruction:
 	 */
-	window = MAX_READAHEAD*(PAGE_SIZE/1024);
-	printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n",window,max_blocks);
+	window = MAX_READAHEAD*(PAGE_SIZE/512);
+	printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n",window/2,max_sectors/2);
 
 	atomic_set(&mddev->recovery_active, 0);
 	init_waitqueue_head(&mddev->recovery_wait);
 	last_check = 0;
-	for (j = 0; j < max_blocks;) {
-		int blocks;
+	for (j = 0; j < max_sectors;) {
+		int sectors;
 
-		blocks = mddev->pers->sync_request(mddev, j);
+		sectors = mddev->pers->sync_request(mddev, j);
 
-		if (blocks < 0) {
-			err = blocks;
+		if (sectors < 0) {
+			err = sectors;
 			goto out;
 		}
-		atomic_add(blocks, &mddev->recovery_active);
-		j += blocks;
+		atomic_add(sectors, &mddev->recovery_active);
+		j += sectors;
 		mddev->curr_resync = j;
 
 		if (last_check + window > j)
@@ -3325,7 +3325,7 @@
 			mark_cnt[next] = j - atomic_read(&mddev->recovery_active);
 			last_mark = next;
 		}
-			
+
 
 		if (md_signal_pending(current)) {
 			/*
@@ -3350,7 +3350,7 @@
 		if (md_need_resched(current))
 			schedule();
 
-		currspeed = (j-mddev->resync_mark_cnt)/((jiffies-mddev->resync_mark)/HZ +1) +1;
+		currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
 
 		if (currspeed > sysctl_speed_limit_min) {
 			current->nice = 19;
diff -urN linux-2.4.5-pre3/drivers/md/raid1.c linux/drivers/md/raid1.c
--- linux-2.4.5-pre3/drivers/md/raid1.c	Mon Dec  3 22:43:49 2001
+++ linux/drivers/md/raid1.c	Mon Dec  3 22:44:23 2001
@@ -1198,7 +1198,7 @@
 				raid1_map (mddev, &bh->b_dev, bh->b_size >> 9);
 				if (bh->b_dev == dev) {
 					printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr);
-					md_done_sync(mddev, bh->b_size>>10, 0);
+					md_done_sync(mddev, bh->b_size>>9, 0);
 				} else {
 					printk (REDIRECT_SECTOR,
 						partition_name(bh->b_dev), bh->b_blocknr);
@@ -1305,7 +1305,7 @@
  * issue suitable write requests
  */
 
-static int raid1_sync_request (mddev_t *mddev, unsigned long block_nr)
+static int raid1_sync_request (mddev_t *mddev, unsigned long sector_nr)
 {
 	raid1_conf_t *conf = mddev_to_conf(mddev);
 	struct mirror_info *mirror;
@@ -1315,7 +1315,7 @@
 	int disk;
 
 	spin_lock_irq(&conf->segment_lock);
-	if (!block_nr) {
+	if (!sector_nr) {
 		/* initialize ...*/
 		int buffs;
 		conf->start_active = 0;
@@ -1335,9 +1335,9 @@
 		if (conf->cnt_ready || conf->cnt_active)
 			MD_BUG();
 	}
-	while ((block_nr<<1) >= conf->start_pending) {
+	while (sector_nr >= conf->start_pending) {
 		PRINTK("wait .. sect=%lu start_active=%d ready=%d pending=%d future=%d, cnt_done=%d active=%d ready=%d pending=%d future=%d\n",
-			block_nr<<1, conf->start_active, conf->start_ready, conf->start_pending, conf->start_future,
+			sector_nr, conf->start_active, conf->start_ready, conf->start_pending, conf->start_future,
 			conf->cnt_done, conf->cnt_active, conf->cnt_ready, conf->cnt_pending, conf->cnt_future);
 		wait_event_lock_irq(conf->wait_done,
 					!conf->cnt_active,
@@ -1383,10 +1383,10 @@
 	r1_bh->cmd = SPECIAL;
 	bh = &r1_bh->bh_req;
 
-	bh->b_blocknr = block_nr;
-	bsize = 1024;
+	bh->b_blocknr = sector_nr;
+	bsize = 512;
 	while (!(bh->b_blocknr & 1) && bsize < PAGE_SIZE
-			&& (bh->b_blocknr+2)*(bsize>>10) < mddev->sb->size) {
+			&& (bh->b_blocknr+2)*(bsize>>9) < (mddev->sb->size *2)) {
 		bh->b_blocknr >>= 1;
 		bsize <<= 1;
 	}
@@ -1403,13 +1403,13 @@
 		BUG();
 	bh->b_end_io = end_sync_read;
 	bh->b_private = r1_bh;
-	bh->b_rsector = block_nr<<1;
+	bh->b_rsector = sector_nr;
 	init_waitqueue_head(&bh->b_wait);
 
 	generic_make_request(READ, bh);
 	md_sync_acct(bh->b_dev, bh->b_size/512);
 
-	return (bsize >> 10);
+	return (bsize >> 9);
 
 nomem:
 	raid1_shrink_buffers(conf);
@@ -1444,7 +1444,7 @@
 		int size = bh->b_size;
 		raid1_free_buf(r1_bh);
 		sync_request_done(sect, mddev_to_conf(mddev));
-		md_done_sync(mddev,size>>10, uptodate);
+		md_done_sync(mddev,size>>9, uptodate);
 	}
 }
 
diff -urN linux-2.4.5-pre3/drivers/md/raid5.c linux/drivers/md/raid5.c
--- linux-2.4.5-pre3/drivers/md/raid5.c	Mon Dec  3 22:43:49 2001
+++ linux/drivers/md/raid5.c	Mon Dec  3 22:44:23 2001
@@ -886,7 +886,7 @@
 			}
 		}
 		if (syncing) {
-			md_done_sync(conf->mddev, (sh->size>>10) - sh->sync_redone,0);
+			md_done_sync(conf->mddev, (sh->size>>9) - sh->sync_redone,0);
 			clear_bit(STRIPE_SYNCING, &sh->state);
 			syncing = 0;
 		}			
@@ -1059,7 +1059,7 @@
 		}
 	}
 	if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
-		md_done_sync(conf->mddev, (sh->size>>10) - sh->sync_redone,1);
+		md_done_sync(conf->mddev, (sh->size>>9) - sh->sync_redone,1);
 		clear_bit(STRIPE_SYNCING, &sh->state);
 	}
 	
@@ -1153,13 +1153,13 @@
 	return correct_size;
 }
 
-static int raid5_sync_request (mddev_t *mddev, unsigned long block_nr)
+static int raid5_sync_request (mddev_t *mddev, unsigned long sector_nr)
 {
 	raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
 	struct stripe_head *sh;
 	int sectors_per_chunk = conf->chunk_size >> 9;
-	unsigned long stripe = (block_nr<<1)/sectors_per_chunk;
-	int chunk_offset = (block_nr<<1) % sectors_per_chunk;
+	unsigned long stripe = sector_nr/sectors_per_chunk;
+	int chunk_offset = sector_nr % sectors_per_chunk;
 	int dd_idx, pd_idx;
 	unsigned long first_sector;
 	int raid_disks = conf->raid_disks;
@@ -1167,9 +1167,9 @@
 	int redone = 0;
 	int bufsize;
 
-	sh = get_active_stripe(conf, block_nr<<1, 0, 0);
+	sh = get_active_stripe(conf, sector_nr, 0, 0);
 	bufsize = sh->size;
-	redone = block_nr-(sh->sector>>1);
+	redone = sector_nr - sh->sector;
 	first_sector = raid5_compute_sector(stripe*data_disks*sectors_per_chunk
 		+ chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf);
 	sh->pd_idx = pd_idx;
@@ -1182,7 +1182,7 @@
 	handle_stripe(sh);
 	release_stripe(sh);
 
-	return (bufsize>>10)-redone;
+	return (bufsize>>9)-redone;
 }
 
 /*
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-aimslab.c linux/drivers/media/radio/radio-aimslab.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-aimslab.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-aimslab.c	Mon Dec  3 22:44:23 2001
@@ -42,6 +42,7 @@
 #endif
 
 static int io = CONFIG_RADIO_RTRACK_PORT; 
+static int radio_nr = -1;
 static int users = 0;
 static struct semaphore lock;
 
@@ -345,7 +346,7 @@
 
 	rtrack_radio.priv=&rtrack_unit;
 	
-	if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO)==-1)
+	if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 	{
 		release_region(io, 2);
 		return -EINVAL;
@@ -371,6 +372,7 @@
 MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)");
+MODULE_PARM(radio_nr, "i");
 
 EXPORT_NO_SYMBOLS;
 
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-aztech.c linux/drivers/media/radio/radio-aztech.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-aztech.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-aztech.c	Mon Dec  3 22:44:23 2001
@@ -40,6 +40,7 @@
 #endif
 
 static int io = CONFIG_RADIO_AZTECH_PORT; 
+static int radio_nr = -1;
 static int radio_wait_time = 1000;
 static int users = 0;
 static struct semaphore lock;
@@ -297,7 +298,7 @@
 	init_MUTEX(&lock);
 	aztech_radio.priv=&aztech_unit;
 	
-	if(video_register_device(&aztech_radio, VFL_TYPE_RADIO)==-1)
+	if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 	{
 		release_region(io,2);
 		return -EINVAL;
@@ -312,6 +313,7 @@
 MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
 MODULE_DESCRIPTION("A driver for the Aztech radio card.");
 MODULE_PARM(io, "i");
+MODULE_PARM(radio_nr, "i");
 MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)");
 
 EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-cadet.c linux/drivers/media/radio/radio-cadet.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-cadet.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-cadet.c	Mon Dec  3 22:44:23 2001
@@ -35,6 +35,7 @@
 #define RDS_BUFFER 256
 
 static int io=-1;		/* default to isapnp activation */
+static int radio_nr = -1;
 static int users=0;
 static int curtuner=0;
 static int tunestat=0;
@@ -616,7 +617,7 @@
 	}
 	if (!request_region(io,2,"cadet"))
 		return -EBUSY;
-	if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1) {
+	if(video_register_device(&cadet_radio,VFL_TYPE_RADIO,radio_nr)==-1) {
 		release_region(io,2);
 		return -EINVAL;
 	}
@@ -630,6 +631,7 @@
 MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)");
+MODULE_PARM(radio_nr, "i");
 
 static struct isapnp_device_id id_table[] __devinitdata = {
 	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-gemtek.c linux/drivers/media/radio/radio-gemtek.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-gemtek.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-gemtek.c	Mon Dec  3 22:44:23 2001
@@ -30,6 +30,7 @@
 #endif
 
 static int io = CONFIG_RADIO_GEMTEK_PORT; 
+static int radio_nr = -1;
 static int users = 0;
 static spinlock_t lock;
 
@@ -272,7 +273,7 @@
 
 	gemtek_radio.priv=&gemtek_unit;
 	
-	if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO)==-1)
+	if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 	{
 		release_region(io, 4);
 		return -EINVAL;
@@ -295,6 +296,7 @@
 MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard)).");
+MODULE_PARM(radio_nr, "i");
 
 EXPORT_NO_SYMBOLS;
 
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-maestro.c linux/drivers/media/radio/radio-maestro.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-maestro.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-maestro.c	Mon Dec  3 22:44:23 2001
@@ -61,6 +61,8 @@
 
 #define BITS2FREQ(x)	((x) * FREQ_STEP - FREQ_IF)
 
+static int radio_nr = -1;
+MODULE_PARM(radio_nr, "i");
 
 
 static int radio_open(struct video_device *, int);
@@ -359,7 +361,7 @@
 	init_MUTEX(&radio_unit.lock);
 	
 	if(radio_power_on(&radio_unit)) {
-		if(video_register_device(&maestro_radio, VFL_TYPE_RADIO)==-1) {
+		if(video_register_device(&maestro_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
 			printk("radio-maestro: can't register device!");
 			return 0;
 		}
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-maxiradio.c linux/drivers/media/radio/radio-maxiradio.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-maxiradio.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-maxiradio.c	Mon Dec  3 22:44:23 2001
@@ -56,6 +56,9 @@
 /* TEA5757 pin mappings */
 const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16 ;
 
+static int radio_nr = -1;
+MODULE_PARM(radio_nr, "i");
+
 
 #define FREQ_LO		 50*16000
 #define FREQ_HI		150*16000
@@ -331,7 +334,7 @@
 	init_MUTEX(&radio_unit.lock);
 	maxiradio_radio.priv = &radio_unit;
 
-	if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO)==-1) {
+	if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
 	        printk("radio-maxiradio: can't register device!");
 	        goto err_out_free_region;
 	}
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-miropcm20.c linux/drivers/media/radio/radio-miropcm20.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-miropcm20.c	Fri Apr 13 20:26:07 2001
+++ linux/drivers/media/radio/radio-miropcm20.c	Mon Dec  3 22:44:23 2001
@@ -30,6 +30,8 @@
 #include "../../sound/aci.h"
 
 static int users = 0;
+static int radio_nr = -1;
+MODULE_PARM(radio_nr, "i");
 
 struct pcm20_device
 {
@@ -258,7 +260,7 @@
 
 static int __init pcm20_init(void)
 {
-	if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO)==-1)
+	if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 		return -EINVAL;
 		
 	if(attach_aci_rds()<0) {
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-rtrack2.c linux/drivers/media/radio/radio-rtrack2.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-rtrack2.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-rtrack2.c	Mon Dec  3 22:44:23 2001
@@ -23,6 +23,7 @@
 #endif
 
 static int io = CONFIG_RADIO_RTRACK2_PORT; 
+static int radio_nr = -1;
 static int users = 0;
 static spinlock_t lock;
 
@@ -238,7 +239,7 @@
 	rtrack2_radio.priv=&rtrack2_unit;
 
 	spin_lock_init(&lock);	
-	if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO)==-1)
+	if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 	{
 		release_region(io, 4);
 		return -EINVAL;
@@ -257,6 +258,7 @@
 MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
+MODULE_PARM(radio_nr, "i");
 
 EXPORT_NO_SYMBOLS;
 
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-sf16fmi.c linux/drivers/media/radio/radio-sf16fmi.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-sf16fmi.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-sf16fmi.c	Mon Dec  3 22:44:23 2001
@@ -37,6 +37,7 @@
 #endif
 
 static int io = CONFIG_RADIO_SF16FMI_PORT; 
+static int radio_nr = -1;
 static int users = 0;
 static struct semaphore lock;
 
@@ -304,7 +305,7 @@
 	
 	init_MUTEX(&lock);
 	
-	if(video_register_device(&fmi_radio, VFL_TYPE_RADIO)==-1)
+	if(video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 	{
 		release_region(io, 2);
 		return -EINVAL;
@@ -321,6 +322,7 @@
 MODULE_DESCRIPTION("A driver for the SF16MI radio.");
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)");
+MODULE_PARM(radio_nr, "i");
 
 EXPORT_NO_SYMBOLS;
 
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-terratec.c linux/drivers/media/radio/radio-terratec.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-terratec.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-terratec.c	Mon Dec  3 22:44:23 2001
@@ -50,6 +50,7 @@
 /*******************************************************************/
 
 static int io = CONFIG_RADIO_TERRATEC_PORT; 
+static int radio_nr = -1;
 static int users = 0;
 static spinlock_t lock;
 
@@ -318,7 +319,7 @@
 	
 	spin_lock_init(&lock);
 	
-	if(video_register_device(&terratec_radio, VFL_TYPE_RADIO)==-1)
+	if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 	{
 		release_region(io,2);
 		return -EINVAL;
@@ -339,6 +340,7 @@
 MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
+MODULE_PARM(radio_nr, "i");
 
 EXPORT_NO_SYMBOLS;
 
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-trust.c linux/drivers/media/radio/radio-trust.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-trust.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-trust.c	Mon Dec  3 22:44:23 2001
@@ -31,6 +31,7 @@
 #endif
 
 static int io = CONFIG_RADIO_TRUST_PORT; 
+static int radio_nr = -1;
 static int ioval = 0xf;
 static int users = 0;
 static __u16 curvol;
@@ -303,7 +304,7 @@
 		printk(KERN_ERR "trust: port 0x%x already in use\n", io);
 		return -EBUSY;
 	}
-	if(video_register_device(&trust_radio, VFL_TYPE_RADIO)==-1)
+	if(video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 	{
 		release_region(io, 2);
 		return -EINVAL;
@@ -332,6 +333,7 @@
 MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
+MODULE_PARM(radio_nr, "i");
 
 EXPORT_NO_SYMBOLS;
 
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-typhoon.c linux/drivers/media/radio/radio-typhoon.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-typhoon.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-typhoon.c	Mon Dec  3 22:44:23 2001
@@ -321,10 +321,12 @@
 MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)");
 MODULE_PARM(mutefreq, "i");
 MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
+MODULE_PARM(radio_nr, "i");
 
 EXPORT_NO_SYMBOLS;
 
 static int io = -1;
+static int radio_nr = -1;
 
 #ifdef MODULE
 static unsigned long mutefreq = 0;
@@ -356,7 +358,7 @@
 	}
 
 	typhoon_radio.priv = &typhoon_unit;
-	if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO) == -1)
+	if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO, radio_nr) == -1)
 	{
 		release_region(io, 8);
 		return -EINVAL;
diff -urN linux-2.4.5-pre3/drivers/media/radio/radio-zoltrix.c linux/drivers/media/radio/radio-zoltrix.c
--- linux-2.4.5-pre3/drivers/media/radio/radio-zoltrix.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-zoltrix.c	Mon Dec  3 22:44:23 2001
@@ -39,6 +39,7 @@
 #endif
 
 static int io = CONFIG_RADIO_ZOLTRIX_PORT;
+static int radio_nr = -1;
 static int users = 0;
 
 struct zol_device {
@@ -365,7 +366,7 @@
 		return -EBUSY;
 	}
 
-	if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO) == -1)
+	if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) == -1)
 	{
 		release_region(io, 2);
 		return -EINVAL;
@@ -394,6 +395,7 @@
 MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
+MODULE_PARM(radio_nr, "i");
 
 EXPORT_NO_SYMBOLS;
 
diff -urN linux-2.4.5-pre3/drivers/media/video/adv7175.c linux/drivers/media/video/adv7175.c
--- linux-2.4.5-pre3/drivers/media/video/adv7175.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/video/adv7175.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,478 @@
+#define DEBUGLEVEL 0
+/* 
+    adv7175 - adv7175a video encoder driver version 0.0.3
+
+    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+    Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
+    Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+       - some corrections for Pinnacle Systems Inc. DC10plus card.
+
+    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.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+
+#include <linux/videodev.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c-old.h>
+
+#include <linux/video_encoder.h>
+
+#if (DEBUGLEVEL > 0)
+#define DEBUG(x...)  x		/* Debug driver */
+#else
+#define DEBUG(x...)
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+struct adv7175 {
+	struct i2c_bus *bus;
+	int addr;
+	unsigned char reg[128];
+
+	int norm;
+	int input;
+	int enable;
+	int bright;
+	int contrast;
+	int hue;
+	int sat;
+};
+
+#define   I2C_ADV7175        0xd4
+#define   I2C_ADV7176        0x54
+
+static char adv7175_name[] = "adv7175";
+static char adv7176_name[] = "adv7176";
+static char unknown_name[] = "UNKNOWN";
+
+#if (DEBUGLEVEL > 0)
+static char *inputs[] = { "pass_through", "play_back", "color_bar" };
+static char *norms[] = { "PAL", "NTSC", "SECAM->PAL (may not work!)" };
+#endif
+
+#define I2C_DELAY   10
+
+/* ----------------------------------------------------------------------- */
+
+static int adv7175_write(struct adv7175 *dev, unsigned char subaddr, unsigned char data)
+{
+	int ack;
+
+	LOCK_I2C_BUS(dev->bus);
+
+	i2c_start(dev->bus);
+	i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+	i2c_sendbyte(dev->bus, subaddr, I2C_DELAY);
+	ack = i2c_sendbyte(dev->bus, data, I2C_DELAY);
+	dev->reg[subaddr] = data;
+	i2c_stop(dev->bus);
+	UNLOCK_I2C_BUS(dev->bus);
+	return ack;
+}
+
+static unsigned char adv7175_read(struct adv7175 *dev, unsigned char subaddr)
+{
+	unsigned char data;
+
+	LOCK_I2C_BUS(dev->bus);
+
+	i2c_start(dev->bus);
+	i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+	i2c_sendbyte(dev->bus, subaddr, I2C_DELAY);
+	i2c_sendbyte(dev->bus, dev->addr + 1, I2C_DELAY);
+	data = i2c_readbyte(dev->bus, 1);
+	dev->reg[subaddr] = data;
+	i2c_stop(dev->bus);
+	UNLOCK_I2C_BUS(dev->bus);
+	return data;
+}
+
+static int adv7175_write_block(struct adv7175 *dev,
+			       unsigned const char *data, unsigned int len)
+{
+	int ack = 0;
+	unsigned subaddr;
+
+	while (len > 1) {
+		LOCK_I2C_BUS(dev->bus);
+		i2c_start(dev->bus);
+		i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+		ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY);
+		ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY);
+		len -= 2;
+		while (len > 1 && *data == ++subaddr) {
+			data++;
+			ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY);
+			len -= 2;
+		}
+		i2c_stop(dev->bus);
+		UNLOCK_I2C_BUS(dev->bus);
+	}
+	return ack;
+}
+
+/* ----------------------------------------------------------------------- */
+// Output filter:  S-Video  Composite
+
+#define MR050       0x11	//0x09
+#define MR060       0x14	//0x0c
+
+//---------------------------------------------------------------------------
+
+#define TR0MODE     0x46
+#define TR0RST	    0x80
+
+#define TR1CAPT	    0x80
+#define TR1PLAY	    0x00
+
+static const unsigned char init_common[] = {
+
+	0x00, MR050,		/* MR0, PAL enabled */
+	0x01, 0x00,		/* MR1 */
+	0x02, 0x0c,		/* subc. freq. */
+	0x03, 0x8c,		/* subc. freq. */
+	0x04, 0x79,		/* subc. freq. */
+	0x05, 0x26,		/* subc. freq. */
+	0x06, 0x40,		/* subc. phase */
+
+	0x07, TR0MODE,		/* TR0, 16bit */
+	0x08, 0x21,		/*  */
+	0x09, 0x00,		/*  */
+	0x0a, 0x00,		/*  */
+	0x0b, 0x00,		/*  */
+	0x0c, TR1CAPT,		/* TR1 */
+	0x0d, 0x4f,		/* MR2 */
+	0x0e, 0x00,		/*  */
+	0x0f, 0x00,		/*  */
+	0x10, 0x00,		/*  */
+	0x11, 0x00,		/*  */
+	0x12, 0x00,		/* MR3 */
+	0x24, 0x00,		/*  */
+};
+
+static const unsigned char init_pal[] = {
+	0x00, MR050,		/* MR0, PAL enabled */
+	0x01, 0x00,		/* MR1 */
+	0x02, 0x0c,		/* subc. freq. */
+	0x03, 0x8c,		/* subc. freq. */
+	0x04, 0x79,		/* subc. freq. */
+	0x05, 0x26,		/* subc. freq. */
+	0x06, 0x40,		/* subc. phase */
+};
+
+static const unsigned char init_ntsc[] = {
+	0x00, MR060,		/* MR0, NTSC enabled */
+	0x01, 0x00,		/* MR1 */
+	0x02, 0x55,		/* subc. freq. */
+	0x03, 0x55,		/* subc. freq. */
+	0x04, 0x55,		/* subc. freq. */
+	0x05, 0x25,		/* subc. freq. */
+	0x06, 0x1a,		/* subc. phase */
+};
+
+static int adv7175_attach(struct i2c_device *device)
+{
+	int i;
+	struct adv7175 *encoder;
+	char *dname;
+
+	MOD_INC_USE_COUNT;
+
+	device->data = encoder = kmalloc(sizeof(struct adv7175), GFP_KERNEL);
+	if (encoder == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+
+
+	memset(encoder, 0, sizeof(struct adv7175));
+	if ((device->addr == I2C_ADV7175) || (device->addr == (I2C_ADV7175 + 2))) {
+		dname = adv7175_name;
+	} else if ((device->addr == I2C_ADV7176) || (device->addr == (I2C_ADV7176 + 2))) {
+		dname = adv7176_name;
+	} else {
+		// We should never get here!!!
+		dname = unknown_name;
+	}
+	strcpy(device->name, dname);
+	encoder->bus = device->bus;
+	encoder->addr = device->addr;
+	encoder->norm = VIDEO_MODE_PAL;
+	encoder->input = 0;
+	encoder->enable = 1;
+
+	i = adv7175_write_block(encoder, init_common, sizeof(init_common));
+	if (i >= 0) {
+		i = adv7175_write(encoder, 0x07, TR0MODE | TR0RST);
+		i = adv7175_write(encoder, 0x07, TR0MODE);
+		i = adv7175_read(encoder, 0x12);
+		printk(KERN_INFO "%s_attach: %s rev. %d at 0x%02x\n",
+		       device->name, dname, i & 1, device->addr);
+	}
+	if (i < 0) {
+		printk(KERN_ERR "%s_attach: init error %d\n", device->name,
+		       i);
+	}
+
+	return 0;
+}
+
+
+static int adv7175_detach(struct i2c_device *device)
+{
+	kfree(device->data);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int adv7175_command(struct i2c_device *device, unsigned int cmd,
+			   void *arg)
+{
+	struct adv7175 *encoder = device->data;
+
+	switch (cmd) {
+
+	case ENCODER_GET_CAPABILITIES:
+		{
+			struct video_encoder_capability *cap = arg;
+
+			cap->flags = VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC
+			    // | VIDEO_ENCODER_SECAM
+			    // | VIDEO_ENCODER_CCIR
+			    ;
+			cap->inputs = 2;
+			cap->outputs = 1;
+		}
+		break;
+
+	case ENCODER_SET_NORM:
+		{
+			int iarg = *(int *) arg;
+
+			if (encoder->norm != iarg) {
+				switch (iarg) {
+
+				case VIDEO_MODE_NTSC:
+					adv7175_write_block(encoder,
+							    init_ntsc,
+							    sizeof
+							    (init_ntsc));
+					if (encoder->input == 0)
+						adv7175_write(encoder, 0x0d, 0x4f);	// Enable genlock
+					adv7175_write(encoder, 0x07,
+						      TR0MODE | TR0RST);
+					adv7175_write(encoder, 0x07,
+						      TR0MODE);
+					break;
+
+				case VIDEO_MODE_PAL:
+					adv7175_write_block(encoder,
+							    init_pal,
+							    sizeof
+							    (init_pal));
+					if (encoder->input == 0)
+						adv7175_write(encoder, 0x0d, 0x4f);	// Enable genlock
+					adv7175_write(encoder, 0x07,
+						      TR0MODE | TR0RST);
+					adv7175_write(encoder, 0x07,
+						      TR0MODE);
+					break;
+
+				case VIDEO_MODE_SECAM:	// WARNING! ADV7176 does not support SECAM.
+					// This is an attempt to convert SECAM->PAL (typically
+					// it does not work due to genlock: when decoder
+					// is in SECAM and encoder in in PAL the subcarrier
+					// can not be syncronized with horizontal frequency)
+					adv7175_write_block(encoder,
+							    init_pal,
+							    sizeof
+							    (init_pal));
+					if (encoder->input == 0)
+						adv7175_write(encoder, 0x0d, 0x49);	// Disable genlock
+					adv7175_write(encoder, 0x07,
+						      TR0MODE | TR0RST);
+					adv7175_write(encoder, 0x07,
+						      TR0MODE);
+					break;
+				default:
+					printk(KERN_ERR
+					       "%s: illegal norm: %d\n",
+					       device->name, iarg);
+					return -EINVAL;
+
+				}
+				DEBUG(printk
+				      (KERN_INFO "%s: switched to %s\n",
+				       device->name, norms[iarg]));
+				encoder->norm = iarg;
+			}
+		}
+		break;
+
+	case ENCODER_SET_INPUT:
+		{
+			int iarg = *(int *) arg;
+
+			/* RJ: *iarg = 0: input is from SAA7110
+			   *iarg = 1: input is from ZR36060
+			   *iarg = 2: color bar */
+
+			if (encoder->input != iarg) {
+				switch (iarg) {
+
+				case 0:
+					adv7175_write(encoder, 0x01, 0x00);
+					adv7175_write(encoder, 0x0c, TR1CAPT);	/* TR1 */
+					if (encoder->norm ==
+					    VIDEO_MODE_SECAM)
+						adv7175_write(encoder, 0x0d, 0x49);	// Disable genlock
+					else
+						adv7175_write(encoder, 0x0d, 0x4f);	// Enable genlock
+					adv7175_write(encoder, 0x07,
+						      TR0MODE | TR0RST);
+					adv7175_write(encoder, 0x07,
+						      TR0MODE);
+					//udelay(10);
+					break;
+
+				case 1:
+					adv7175_write(encoder, 0x01, 0x00);
+					adv7175_write(encoder, 0x0c, TR1PLAY);	/* TR1 */
+					adv7175_write(encoder, 0x0d, 0x49);
+					adv7175_write(encoder, 0x07,
+						      TR0MODE | TR0RST);
+					adv7175_write(encoder, 0x07,
+						      TR0MODE);
+					//udelay(10);
+					break;
+
+				case 2:
+					adv7175_write(encoder, 0x01, 0x80);
+					adv7175_write(encoder, 0x0d, 0x49);
+					adv7175_write(encoder, 0x07,
+						      TR0MODE | TR0RST);
+					adv7175_write(encoder, 0x07,
+						      TR0MODE);
+					//udelay(10);
+					break;
+
+				default:
+					printk(KERN_ERR
+					       "%s: illegal input: %d\n",
+					       device->name, iarg);
+					return -EINVAL;
+
+				}
+				DEBUG(printk
+				      (KERN_INFO "%s: switched to %s\n",
+				       device->name, inputs[iarg]));
+				encoder->input = iarg;
+			}
+		}
+		break;
+
+	case ENCODER_SET_OUTPUT:
+		{
+			int *iarg = arg;
+
+			/* not much choice of outputs */
+			if (*iarg != 0) {
+				return -EINVAL;
+			}
+		}
+		break;
+
+	case ENCODER_ENABLE_OUTPUT:
+		{
+			int *iarg = arg;
+
+			encoder->enable = !!*iarg;
+			adv7175_write(encoder, 0x61,
+				      (encoder->
+				       reg[0x61] & 0xbf) | (encoder->
+							    enable ? 0x00 :
+							    0x40));
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_adv7175 = {
+	"adv7175",		/* name */
+	I2C_DRIVERID_VIDEOENCODER,	/* ID */
+	I2C_ADV7175, I2C_ADV7175 + 3,
+
+	adv7175_attach,
+	adv7175_detach,
+	adv7175_command
+};
+
+static struct i2c_driver i2c_driver_adv7176 = {
+	"adv7175",		/* name */
+	I2C_DRIVERID_VIDEOENCODER,	/* ID */
+	I2C_ADV7176, I2C_ADV7176 + 3,
+
+	adv7175_attach,
+	adv7175_detach,
+	adv7175_command
+};
+
+EXPORT_NO_SYMBOLS;
+
+static int adv7175_init(void)
+{
+	int res_adv7175 = 0, res_adv7176 = 0;
+	res_adv7175 = i2c_register_driver(&i2c_driver_adv7175);
+	res_adv7176 = i2c_register_driver(&i2c_driver_adv7176);
+	return (res_adv7175 | res_adv7176);	// Any idea how to make it better?
+}
+
+static void adv7175_exit(void)
+{
+	i2c_unregister_driver(&i2c_driver_adv7176);
+	i2c_unregister_driver(&i2c_driver_adv7175);
+}
+
+module_init(adv7175_init);
+module_exit(adv7175_exit);
diff -urN linux-2.4.5-pre3/drivers/media/video/bt819.c linux/drivers/media/video/bt819.c
--- linux-2.4.5-pre3/drivers/media/video/bt819.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/video/bt819.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,496 @@
+/* 
+    bt819 - BT819A VideoStream Decoder (Rockwell Part)
+
+    Copyright (C) 1999 Mike Bernson <mike@mlb.org>
+    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+    Modifications for LML33/DC10plus unified driver
+    Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+    
+    This code was modify/ported from the saa7111 driver written
+    by Dave Perks.
+
+    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.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+
+#include <linux/videodev.h>
+
+#include <linux/i2c-old.h>
+#include <linux/video_decoder.h>
+
+#define DEBUG(x)       x	/* Debug driver */
+
+/* ----------------------------------------------------------------------- */
+
+struct bt819 {
+	struct i2c_bus *bus;
+	int addr;
+	unsigned char reg[32];
+
+	int initialized;
+	int norm;
+	int input;
+	int enable;
+	int bright;
+	int contrast;
+	int hue;
+	int sat;
+};
+
+struct timing {
+	int hactive;
+	int hdelay;
+	int vactive;
+	int vdelay;
+	int hscale;
+	int vscale;
+};
+
+struct timing timing_data[] = {
+	{864 - 24, 2, 623, 1, 0x0504, 0x0000},
+	{858 - 24, 2, 523, 1, 0x00f8, 0x0000},
+//      { 858-68, 64, 523, 1, 0x00f8, 0x0000 },
+};
+
+#define   I2C_BT819        0x8a
+
+#define   I2C_DELAY   10
+
+/* ----------------------------------------------------------------------- */
+
+static int bt819_write(struct bt819 *dev, unsigned char subaddr,
+		       unsigned char data)
+{
+	int ack;
+
+	LOCK_I2C_BUS(dev->bus);
+	i2c_start(dev->bus);
+	i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+	i2c_sendbyte(dev->bus, subaddr, I2C_DELAY);
+	ack = i2c_sendbyte(dev->bus, data, I2C_DELAY);
+	dev->reg[subaddr] = data;
+	i2c_stop(dev->bus);
+	UNLOCK_I2C_BUS(dev->bus);
+	return ack;
+}
+
+static int bt819_setbit(struct bt819 *dev, int subaddr, int bit, int data)
+{
+	return bt819_write(dev, subaddr, (dev->reg[subaddr] & ~(1 << bit)) | (data ? (1 << bit) : 0));
+}
+
+static int bt819_write_block(struct bt819 *dev, unsigned const char *data,
+			     unsigned int len)
+{
+	int ack;
+	unsigned subaddr;
+
+	ack = 0;
+	while (len > 1) {
+		LOCK_I2C_BUS(dev->bus);
+		i2c_start(dev->bus);
+		i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+		ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY);
+		ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++),
+				 I2C_DELAY);
+		len -= 2;
+		while (len > 1 && *data == ++subaddr) {
+			data++;
+			ack =
+			    i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY);
+			len -= 2;
+		}
+		i2c_stop(dev->bus);
+		UNLOCK_I2C_BUS(dev->bus);
+	}
+	return ack;
+}
+
+static int bt819_read(struct bt819 *dev, unsigned char subaddr)
+{
+	int data;
+
+	LOCK_I2C_BUS(dev->bus);
+	i2c_start(dev->bus);
+	i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+	i2c_sendbyte(dev->bus, subaddr, I2C_DELAY);
+	i2c_start(dev->bus);
+	i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY);
+	data = i2c_readbyte(dev->bus, 1);
+	i2c_stop(dev->bus);
+	UNLOCK_I2C_BUS(dev->bus);
+	return data;
+}
+
+static int bt819_init(struct i2c_device *device)
+{
+	struct bt819 *decoder;
+
+	static unsigned char init[] = {
+		//0x1f, 0x00,     /* Reset */
+		0x01, 0x59,	/* 0x01 input format */
+		0x02, 0x00,	/* 0x02 temporal decimation */
+		0x03, 0x12,	/* 0x03 Cropping msb */
+		0x04, 0x16,	/* 0x04 Vertical Delay, lsb */
+		0x05, 0xe0,	/* 0x05 Vertical Active lsb */
+		0x06, 0x80,	/* 0x06 Horizontal Delay lsb */
+		0x07, 0xd0,	/* 0x07 Horizontal Active lsb */
+		0x08, 0x00,	/* 0x08 Horizontal Scaling msb */
+		0x09, 0xf8,	/* 0x09 Horizontal Scaling lsb */
+		0x0a, 0x00,	/* 0x0a Brightness control */
+		0x0b, 0x30,	/* 0x0b Miscellaneous control */
+		0x0c, 0xd8,	/* 0x0c Luma Gain lsb */
+		0x0d, 0xfe,	/* 0x0d Chroma Gain (U) lsb */
+		0x0e, 0xb4,	/* 0x0e Chroma Gain (V) msb */
+		0x0f, 0x00,	/* 0x0f Hue control */
+		0x12, 0x04,	/* 0x12 Output Format */
+		0x13, 0x20,	/* 0x13 Vertial Scaling msb 0x60, */
+		0x14, 0x00,	/* 0x14 Vertial Scaling lsb */
+		0x16, 0x04,	/* 0x16 Video Timing Polarity 0x02, */
+		0x18, 0x68,	/* 0x18 AGC Delay */
+		0x19, 0x5d,	/* 0x19 Burst Gate Delay */
+		0x1a, 0x80,	/* 0x1a ADC Interface */
+	};
+
+	struct timing *timing;
+
+	decoder = device->data;
+	timing = &timing_data[decoder->norm];
+
+	init[3 * 2 - 1] = (((timing->vdelay >> 8) & 0x03) << 6) |
+	    (((timing->vactive >> 8) & 0x03) << 4) |
+	    (((timing->hdelay >> 8) & 0x03) << 2) |
+	    ((timing->hactive >> 8) & 0x03);
+	init[4 * 2 - 1] = timing->vdelay & 0xff;
+	init[5 * 2 - 1] = timing->vactive & 0xff;
+	init[6 * 2 - 1] = timing->hdelay & 0xff;
+	init[7 * 2 - 1] = timing->hactive & 0xff;
+	init[8 * 2 - 1] = timing->hscale >> 8;
+	init[9 * 2 - 1] = timing->hscale & 0xff;
+
+	bt819_write(decoder, 0x1f, 0x00);
+	mdelay(1);
+	return bt819_write_block(decoder, init, sizeof(init));
+
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int bt819_attach(struct i2c_device *device)
+{
+	int i;
+	struct bt819 *decoder;
+
+	MOD_INC_USE_COUNT;
+
+	device->data = decoder = kmalloc(sizeof(struct bt819), GFP_KERNEL);
+	if (decoder == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+
+	memset(decoder, 0, sizeof(struct bt819));
+	strcpy(device->name, "bt819");
+	decoder->bus = device->bus;
+	decoder->addr = device->addr;
+	decoder->norm = VIDEO_MODE_NTSC;
+	decoder->input = 0;
+	decoder->enable = 1;
+	decoder->bright = 32768;
+	decoder->contrast = 32768;
+	decoder->hue = 32768;
+	decoder->sat = 32768;
+	decoder->initialized = 0;
+
+	i = bt819_init(device);
+	if (i < 0) {
+		printk(KERN_ERR "%s: bt819_attach: init status %d\n",
+		       decoder->bus->name, i);
+	} else {
+		printk(KERN_INFO "%s: bt819_attach: chip version %x\n",
+		       decoder->bus->name, bt819_read(decoder,
+						      0x17) & 0x0f);
+	}
+	return 0;
+}
+
+static int bt819_detach(struct i2c_device *device)
+{
+	kfree(device->data);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int bt819_command(struct i2c_device *device, unsigned int cmd, void *arg)
+{
+	int temp;
+
+	struct bt819 *decoder = device->data;
+	//return 0;
+
+	if (!decoder->initialized) {	// First call to bt819_init could be
+		bt819_init(device);	// without #FRST = 0
+		decoder->initialized = 1;
+	}
+
+	switch (cmd) {
+
+	case DECODER_GET_CAPABILITIES:
+		{
+			struct video_decoder_capability *cap = arg;
+
+			cap->flags
+			    = VIDEO_DECODER_PAL
+			    | VIDEO_DECODER_NTSC | VIDEO_DECODER_CCIR;
+			cap->inputs = 8;
+			cap->outputs = 1;
+		}
+		break;
+
+	case DECODER_GET_STATUS:
+		{
+			int *iarg = arg;
+			int status;
+			int res;
+
+			status = bt819_read(decoder, 0x00);
+			res = 0;
+			if ((status & 0x80)) {
+				res |= DECODER_STATUS_GOOD;
+			}
+			switch (decoder->norm) {
+			case VIDEO_MODE_NTSC:
+				res |= DECODER_STATUS_NTSC;
+				break;
+			case VIDEO_MODE_PAL:
+				res |= DECODER_STATUS_PAL;
+				break;
+			default:
+			case VIDEO_MODE_AUTO:
+				if ((status & 0x10)) {
+					res |= DECODER_STATUS_PAL;
+				} else {
+					res |= DECODER_STATUS_NTSC;
+				}
+				break;
+			}
+			res |= DECODER_STATUS_COLOR;
+			*iarg = res;
+
+			DEBUG(printk(KERN_INFO "%s-bt819: get status %x\n",
+				     decoder->bus->name, *iarg));
+		}
+		break;
+
+	case DECODER_SET_NORM:
+		{
+			int *iarg = arg;
+			struct timing *timing;
+
+			DEBUG(printk(KERN_INFO "%s-bt819: set norm %x\n",
+				     decoder->bus->name, *iarg));
+
+			if (*iarg == VIDEO_MODE_NTSC) {
+				bt819_setbit(decoder, 0x01, 0, 1);
+				bt819_setbit(decoder, 0x01, 1, 0);
+				bt819_write(decoder, 0x18, 0x68);
+				bt819_write(decoder, 0x19, 0x5d);
+				//bt819_setbit(decoder, 0x1a,  5, 1);
+				timing = &timing_data[VIDEO_MODE_NTSC];
+			} else {
+				bt819_setbit(decoder, 0x01, 0, 1);
+				bt819_setbit(decoder, 0x01, 1, 1);
+				bt819_write(decoder, 0x18, 0x7f);
+				bt819_write(decoder, 0x19, 0x72);
+				//bt819_setbit(decoder, 0x1a,  5, 0);
+				timing = &timing_data[VIDEO_MODE_PAL];
+			}
+
+			bt819_write(decoder, 0x03,
+				    (((timing->vdelay >> 8) & 0x03) << 6) |
+				    (((timing->
+				       vactive >> 8) & 0x03) << 4) |
+				    (((timing->
+				       hdelay >> 8) & 0x03) << 2) |
+				    ((timing->hactive >> 8) & 0x03));
+			bt819_write(decoder, 0x04, timing->vdelay & 0xff);
+			bt819_write(decoder, 0x05, timing->vactive & 0xff);
+			bt819_write(decoder, 0x06, timing->hdelay & 0xff);
+			bt819_write(decoder, 0x07, timing->hactive & 0xff);
+			bt819_write(decoder, 0x08, timing->hscale >> 8);
+			bt819_write(decoder, 0x09, timing->hscale & 0xff);
+			decoder->norm = *iarg;
+		}
+		break;
+
+	case DECODER_SET_INPUT:
+		{
+			int *iarg = arg;
+
+			DEBUG(printk(KERN_INFO "%s-bt819: set input %x\n",
+				     decoder->bus->name, *iarg));
+
+			if (*iarg < 0 || *iarg > 7) {
+				return -EINVAL;
+			}
+
+			if (decoder->input != *iarg) {
+				decoder->input = *iarg;
+				/* select mode */
+				if (decoder->input == 0) {
+					bt819_setbit(decoder, 0x0b, 6, 0);
+					bt819_setbit(decoder, 0x1a, 1, 1);
+				} else {
+					bt819_setbit(decoder, 0x0b, 6, 1);
+					bt819_setbit(decoder, 0x1a, 1, 0);
+				}
+			}
+		}
+		break;
+
+	case DECODER_SET_OUTPUT:
+		{
+			int *iarg = arg;
+
+			DEBUG(printk(KERN_INFO "%s-bt819: set output %x\n",
+				     decoder->bus->name, *iarg));
+
+			/* not much choice of outputs */
+			if (*iarg != 0) {
+				return -EINVAL;
+			}
+		}
+		break;
+
+	case DECODER_ENABLE_OUTPUT:
+		{
+			int *iarg = arg;
+			int enable = (*iarg != 0);
+
+			DEBUG(printk
+			      (KERN_INFO "%s-bt819: enable output %x\n",
+			       decoder->bus->name, *iarg));
+
+			if (decoder->enable != enable) {
+				decoder->enable = enable;
+
+				if (decoder->enable) {
+					bt819_setbit(decoder, 0x16, 7, 0);
+				} else {
+					bt819_setbit(decoder, 0x16, 7, 1);
+				}
+			}
+		}
+		break;
+
+	case DECODER_SET_PICTURE:
+		{
+			struct video_picture *pic = arg;
+
+			DEBUG(printk
+			      (KERN_INFO
+			       "%s-bt819: set picture brightness %d contrast %d colour %d\n",
+			       decoder->bus->name, pic->brightness,
+			       pic->contrast, pic->colour));
+
+
+			if (decoder->bright != pic->brightness) {
+				/* We want -128 to 127 we get 0-65535 */
+				decoder->bright = pic->brightness;
+				bt819_write(decoder, 0x0a,
+					    (decoder->bright >> 8) - 128);
+			}
+
+			if (decoder->contrast != pic->contrast) {
+				/* We want 0 to 511 we get 0-65535 */
+				decoder->contrast = pic->contrast;
+				bt819_write(decoder, 0x0c,
+					    (decoder->
+					     contrast >> 7) & 0xff);
+				bt819_setbit(decoder, 0x0b, 2,
+					     ((decoder->
+					       contrast >> 15) & 0x01));
+			}
+
+			if (decoder->sat != pic->colour) {
+				/* We want 0 to 511 we get 0-65535 */
+				decoder->sat = pic->colour;
+				bt819_write(decoder, 0x0d,
+					    (decoder->sat >> 7) & 0xff);
+				bt819_setbit(decoder, 0x0b, 1,
+					     ((decoder->
+					       sat >> 15) & 0x01));
+
+				temp = (decoder->sat * 201) / 237;
+				bt819_write(decoder, 0x0e,
+					    (temp >> 7) & 0xff);
+				bt819_setbit(decoder, 0x0b, 0,
+					     (temp >> 15) & 0x01);
+			}
+
+			if (decoder->hue != pic->hue) {
+				/* We want -128 to 127 we get 0-65535 */
+				decoder->hue = pic->hue;
+				bt819_write(decoder, 0x0f,
+					    128 - (decoder->hue >> 8));
+			}
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_bt819 = {
+	"bt819",		/* name */
+	I2C_DRIVERID_VIDEODECODER,	/* ID */
+	I2C_BT819, I2C_BT819 + 1,
+
+	bt819_attach,
+	bt819_detach,
+	bt819_command
+};
+
+EXPORT_NO_SYMBOLS;
+
+static int bt819_setup(void)
+{
+	return i2c_register_driver(&i2c_driver_bt819);
+}
+
+static void bt819_exit(void)
+{
+	i2c_unregister_driver(&i2c_driver_bt819);
+}
+
+module_init(bt819_setup);
+module_exit(bt819_exit);
diff -urN linux-2.4.5-pre3/drivers/media/video/bt856.c linux/drivers/media/video/bt856.c
--- linux-2.4.5-pre3/drivers/media/video/bt856.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/video/bt856.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,303 @@
+/* 
+    bt856 - BT856A Digital Video Encoder (Rockwell Part)
+
+    Copyright (C) 1999 Mike Bernson <mike@mlb.org>
+    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+    Modifications for LML33/DC10plus unified driver
+    Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+    
+    This code was modify/ported from the saa7111 driver written
+    by Dave Perks.
+
+    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.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+
+#include <linux/videodev.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c-old.h>
+#include <linux/video_encoder.h>
+
+#define DEBUG(x)   x		/* Debug driver */
+
+/* ----------------------------------------------------------------------- */
+
+struct bt856 {
+	struct i2c_bus *bus;
+	int addr;
+	unsigned char reg[128];
+
+	int norm;
+	int enable;
+	int bright;
+	int contrast;
+	int hue;
+	int sat;
+};
+
+#define   I2C_BT856        0x88
+
+#define I2C_DELAY   10
+
+/* ----------------------------------------------------------------------- */
+
+static int bt856_write(struct bt856 *dev, unsigned char subaddr,
+		       unsigned char data)
+{
+	int ack;
+
+	LOCK_I2C_BUS(dev->bus);
+
+	i2c_start(dev->bus);
+	i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+	i2c_sendbyte(dev->bus, subaddr, I2C_DELAY);
+	ack = i2c_sendbyte(dev->bus, data, I2C_DELAY);
+	dev->reg[subaddr] = data;
+	i2c_stop(dev->bus);
+	UNLOCK_I2C_BUS(dev->bus);
+	return ack;
+}
+
+static int bt856_setbit(struct bt856 *dev, int subaddr, int bit, int data)
+{
+	return bt856_write(dev, subaddr,(dev->reg[subaddr] & ~(1 << bit)) | (data ? (1 << bit) : 0));
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int bt856_attach(struct i2c_device *device)
+{
+	struct bt856 *encoder;
+
+	/* This chip is not on the buz card but at the same address saa7185 */
+	//if (memcmp(device->bus->name, "buz", 3) == 0 || memcmp(device->bus->name, "zr36057", 6) == 0)
+	//   return 1;
+
+	MOD_INC_USE_COUNT;
+	device->data = encoder = kmalloc(sizeof(struct bt856), GFP_KERNEL);
+
+	if (encoder == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+
+
+	memset(encoder, 0, sizeof(struct bt856));
+	strcpy(device->name, "bt856");
+	encoder->bus = device->bus;
+	encoder->addr = device->addr;
+	encoder->norm = VIDEO_MODE_NTSC;
+	encoder->enable = 1;
+
+	DEBUG(printk(KERN_INFO "%s-bt856: attach\n", encoder->bus->name));
+
+	bt856_write(encoder, 0xdc, 0x18);
+	bt856_write(encoder, 0xda, 0);
+	bt856_write(encoder, 0xde, 0);
+
+	bt856_setbit(encoder, 0xdc, 3, 1);
+	//bt856_setbit(encoder, 0xdc, 6, 0);
+	bt856_setbit(encoder, 0xdc, 4, 1);
+
+	switch (encoder->norm) {
+
+	case VIDEO_MODE_NTSC:
+		bt856_setbit(encoder, 0xdc, 2, 0);
+		break;
+
+	case VIDEO_MODE_PAL:
+		bt856_setbit(encoder, 0xdc, 2, 1);
+		break;
+	}
+
+	bt856_setbit(encoder, 0xdc, 1, 1);
+	bt856_setbit(encoder, 0xde, 4, 0);
+	bt856_setbit(encoder, 0xde, 3, 1);
+	return 0;
+}
+
+
+static int bt856_detach(struct i2c_device *device)
+{
+	kfree(device->data);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int bt856_command(struct i2c_device *device, unsigned int cmd,
+			 void *arg)
+{
+	struct bt856 *encoder = device->data;
+
+	switch (cmd) {
+
+	case ENCODER_GET_CAPABILITIES:
+		{
+			struct video_encoder_capability *cap = arg;
+
+			DEBUG(printk
+			      (KERN_INFO "%s-bt856: get capabilities\n",
+			       encoder->bus->name));
+
+			cap->flags
+			    = VIDEO_ENCODER_PAL
+			    | VIDEO_ENCODER_NTSC | VIDEO_ENCODER_CCIR;
+			cap->inputs = 2;
+			cap->outputs = 1;
+		}
+		break;
+
+	case ENCODER_SET_NORM:
+		{
+			int *iarg = arg;
+
+			DEBUG(printk(KERN_INFO "%s-bt856: set norm %d\n",
+				     encoder->bus->name, *iarg));
+
+			switch (*iarg) {
+
+			case VIDEO_MODE_NTSC:
+				bt856_setbit(encoder, 0xdc, 2, 0);
+				break;
+
+			case VIDEO_MODE_PAL:
+				bt856_setbit(encoder, 0xdc, 2, 1);
+				bt856_setbit(encoder, 0xda, 0, 0);
+				//bt856_setbit(encoder, 0xda, 0, 1);
+				break;
+
+			default:
+				return -EINVAL;
+
+			}
+			encoder->norm = *iarg;
+		}
+		break;
+
+	case ENCODER_SET_INPUT:
+		{
+			int *iarg = arg;
+
+			DEBUG(printk(KERN_INFO "%s-bt856: set input %d\n",
+				     encoder->bus->name, *iarg));
+
+			/*     We only have video bus.
+			   *iarg = 0: input is from bt819
+			   *iarg = 1: input is from ZR36060 */
+
+			switch (*iarg) {
+
+			case 0:
+				bt856_setbit(encoder, 0xde, 4, 0);
+				bt856_setbit(encoder, 0xde, 3, 1);
+				bt856_setbit(encoder, 0xdc, 3, 1);
+				bt856_setbit(encoder, 0xdc, 6, 0);
+				break;
+			case 1:
+				bt856_setbit(encoder, 0xde, 4, 0);
+				bt856_setbit(encoder, 0xde, 3, 1);
+				bt856_setbit(encoder, 0xdc, 3, 1);
+				bt856_setbit(encoder, 0xdc, 6, 1);
+				break;
+			case 2:	// Color bar
+				bt856_setbit(encoder, 0xdc, 3, 0);
+				bt856_setbit(encoder, 0xde, 4, 1);
+				break;
+			default:
+				return -EINVAL;
+
+			}
+		}
+		break;
+
+	case ENCODER_SET_OUTPUT:
+		{
+			int *iarg = arg;
+
+			DEBUG(printk(KERN_INFO "%s-bt856: set output %d\n",
+				     encoder->bus->name, *iarg));
+
+			/* not much choice of outputs */
+			if (*iarg != 0) {
+				return -EINVAL;
+			}
+		}
+		break;
+
+	case ENCODER_ENABLE_OUTPUT:
+		{
+			int *iarg = arg;
+
+			encoder->enable = !!*iarg;
+
+			DEBUG(printk
+			      (KERN_INFO "%s-bt856: enable output %d\n",
+			       encoder->bus->name, encoder->enable));
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_bt856 = {
+	"bt856",		/* name */
+	I2C_DRIVERID_VIDEOENCODER,	/* ID */
+	I2C_BT856, I2C_BT856 + 1,
+	bt856_attach,
+	bt856_detach,
+	bt856_command
+};
+
+EXPORT_NO_SYMBOLS;
+
+static int bt856_init(void)
+{
+	return i2c_register_driver(&i2c_driver_bt856);
+}
+
+static void bt856_exit(void)
+{
+	i2c_unregister_driver(&i2c_driver_bt856);
+}
+
+module_init(bt856_init);
+module_exit(bt856_exit);
diff -urN linux-2.4.5-pre3/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- linux-2.4.5-pre3/drivers/media/video/bttv-driver.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/video/bttv-driver.c	Mon Dec  3 22:44:23 2001
@@ -69,6 +69,9 @@
 static unsigned int gbuffers = 2;
 static unsigned int gbufsize = BTTV_MAX_FBUF;
 static unsigned int combfilter = 0;
+static int video_nr = -1;
+static int radio_nr = -1;
+static int vbi_nr = -1;
 unsigned int bttv_debug = 0;
 unsigned int bttv_verbose = 1;
 unsigned int bttv_gpio = 0;
@@ -94,6 +97,10 @@
 MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
 MODULE_PARM(combfilter,"i");
 
+MODULE_PARM(video_nr,"i");
+MODULE_PARM(radio_nr,"i");
+MODULE_PARM(vbi_nr,"i");
+
 MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards");
 MODULE_AUTHOR("Ralph  Metzler & Marcus Metzler & Gerd Knorr");
 
@@ -2435,16 +2442,16 @@
 {
 	audio(btv, AUDIO_MUTE, 1);
         
-	if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
+	if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
 		return -1;
-	if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) 
+	if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) 
         {
 	        video_unregister_device(&btv->video_dev);
 		return -1;
 	}
 	if (btv->has_radio)
 	{
-		if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) 
+		if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) 
                 {
 		        video_unregister_device(&btv->vbi_dev);
 		        video_unregister_device(&btv->video_dev);
diff -urN linux-2.4.5-pre3/drivers/media/video/bw-qcam.c linux/drivers/media/video/bw-qcam.c
--- linux-2.4.5-pre3/drivers/media/video/bw-qcam.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/video/bw-qcam.c	Mon Dec  3 22:44:23 2001
@@ -83,10 +83,12 @@
 
 static unsigned int maxpoll=250;   /* Maximum busy-loop count for qcam I/O */
 static unsigned int yieldlines=4;  /* Yield after this many during capture */
+static int video_nr = -1;
 
 #if LINUX_VERSION_CODE >= 0x020117
 MODULE_PARM(maxpoll,"i");
 MODULE_PARM(yieldlines,"i");   
+MODULE_PARM(video_nr,"i");
 #endif
 
 extern __inline__ int read_lpstatus(struct qcam_device *q)
@@ -962,7 +964,7 @@
 	
 	printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name);
 	
-	if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1)
+	if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
 	{
 		parport_unregister_device(qcam->pdev);
 		kfree(qcam);
diff -urN linux-2.4.5-pre3/drivers/media/video/c-qcam.c linux/drivers/media/video/c-qcam.c
--- linux-2.4.5-pre3/drivers/media/video/c-qcam.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/video/c-qcam.c	Mon Dec  3 22:44:23 2001
@@ -69,6 +69,7 @@
 static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
 static int probe = 2;
 static int force_rgb = 0;
+static int video_nr = -1;
 
 static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
 {
@@ -815,7 +816,7 @@
 
 	parport_release(qcam->pdev);
 	
-	if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1)
+	if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
 	{
 		printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
 		       qcam->pport->name);
@@ -881,6 +882,7 @@
 MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "i");
 MODULE_PARM(probe, "i");
 MODULE_PARM(force_rgb, "i");
+MODULE_PARM(video_nr,"i");
 
 module_init(cqcam_init);
 module_exit(cqcam_cleanup);
diff -urN linux-2.4.5-pre3/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c
--- linux-2.4.5-pre3/drivers/media/video/cpia.c	Fri Apr  6 10:42:55 2001
+++ linux/drivers/media/video/cpia.c	Mon Dec  3 22:44:23 2001
@@ -52,7 +52,10 @@
 extern int cpia_usb_init(void);
 #endif
 
+static int video_nr = -1;
+
 #ifdef MODULE
+MODULE_PARM(video_nr,"i");
 MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <jerdfelt@valinux.com>");
 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
 MODULE_SUPPORTED_DEVICE("video");
@@ -540,6 +543,8 @@
 static int cpia_write_proc(struct file *file, const char *buffer,
                            unsigned long count, void *data)
 {
+	return -EINVAL;
+#if 0
 	struct cam_data *cam = data;
 	struct cam_params new_params;
 	int retval, find_colon;
@@ -1250,6 +1255,7 @@
 	up(&cam->param_lock);
 	
 	return retval;
+#endif
 }
 
 static void create_proc_cpia_cam(struct cam_data *cam)
@@ -3180,7 +3186,7 @@
 	camera->lowlevel_data = lowlevel;
 	
 	/* register v4l device */
-	if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER) == -1) {
+	if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
 		kfree(camera);
 		unlock_kernel();
 		printk(KERN_DEBUG "video_register_device failed\n");
diff -urN linux-2.4.5-pre3/drivers/media/video/planb.c linux/drivers/media/video/planb.c
--- linux-2.4.5-pre3/drivers/media/video/planb.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/video/planb.c	Mon Dec  3 22:44:23 2001
@@ -69,9 +69,11 @@
 static volatile struct planb_registers *planb_regs;
 
 static int def_norm = PLANB_DEF_NORM;	/* default norm */
+static int video_nr = -1;
 
 MODULE_PARM(def_norm, "i");
 MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)");
+MODULE_PARM(video_nr,"i");
 
 /* ------------------ PlanB Exported Functions ------------------ */
 static long planb_write(struct video_device *, const char *, unsigned long, int);
@@ -2168,7 +2170,7 @@
 	pb->intr_mask = PLANB_FRM_IRQ;
 	enable_irq(pb->irq);
 
-	if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER)<0)
+	if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER, video_nr)<0)
 		return -1;
 
 	return 0;
diff -urN linux-2.4.5-pre3/drivers/media/video/pms.c linux/drivers/media/video/pms.c
--- linux-2.4.5-pre3/drivers/media/video/pms.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/video/pms.c	Mon Dec  3 22:44:23 2001
@@ -64,6 +64,7 @@
 static int io_port		=	0x250;
 static int data_port		=	0x251;
 static int mem_base		=	0xC8000;
+static int video_nr             =       -1;
 
 	
 
@@ -1040,11 +1041,12 @@
 	pms_device.width=320;
 	pms_swsense(75);
 	pms_resolution(320,240);
-	return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER);
+	return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER, video_nr);
 }
 
 MODULE_PARM(io_port,"i");
 MODULE_PARM(mem_base,"i");
+MODULE_PARM(video_nr,"i");
 
 static void __exit shutdown_mediavision(void)
 {
diff -urN linux-2.4.5-pre3/drivers/media/video/saa5249.c linux/drivers/media/video/saa5249.c
--- linux-2.4.5-pre3/drivers/media/video/saa5249.c	Fri Nov 17 17:56:51 2000
+++ linux/drivers/media/video/saa5249.c	Mon Dec  3 22:44:23 2001
@@ -205,7 +205,7 @@
 	 *	Register it
 	 */
 
-	if((err=video_register_device(vd, VFL_TYPE_VTX))<0)
+	if((err=video_register_device(vd, VFL_TYPE_VTX,-1))<0)
 	{
 		kfree(t);
 		kfree(vd);
diff -urN linux-2.4.5-pre3/drivers/media/video/saa7110.c linux/drivers/media/video/saa7110.c
--- linux-2.4.5-pre3/drivers/media/video/saa7110.c	Wed Dec 29 17:08:55 1999
+++ linux/drivers/media/video/saa7110.c	Mon Dec  3 22:44:23 2001
@@ -19,6 +19,7 @@
 */
 
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -398,7 +399,7 @@
 
 /* ----------------------------------------------------------------------- */
 
-struct i2c_driver i2c_driver_saa7110 =
+static struct i2c_driver i2c_driver_saa7110 =
 {
 	"saa7110",			/* name */
 
@@ -412,18 +413,16 @@
 
 EXPORT_NO_SYMBOLS;
 
-#ifdef MODULE
-int init_module(void)
-#else
-int saa7110_init(void)
-#endif
+static int saa7110_init(void)
 {
 	return i2c_register_driver(&i2c_driver_saa7110);
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void saa7110_exit(void)
 {
 	i2c_unregister_driver(&i2c_driver_saa7110);
 }
-#endif
+
+
+module_init(saa7110_init);
+module_exit(saa7110_exit);
diff -urN linux-2.4.5-pre3/drivers/media/video/saa7111.c linux/drivers/media/video/saa7111.c
--- linux-2.4.5-pre3/drivers/media/video/saa7111.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/media/video/saa7111.c	Mon Dec  3 22:44:23 2001
@@ -1,46 +1,41 @@
 /* 
-   saa7111 - Philips SAA7111A video decoder driver version 0.0.3
+    saa7111 - Philips SAA7111A video decoder driver version 0.0.3
 
-   Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+    Copyright (C) 1998 Dave Perks <dperks@ibm.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 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.
- */
+    Slight changes for video timing and attachment output by
+    Wolfgang Scherr <scherr@net4you.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 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.
+*/
 
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/signal.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
-#include <linux/types.h>
-#include <linux/wrapper.h>
 
 #include <linux/videodev.h>
 #include <linux/version.h>
-#include <asm/uaccess.h>
-
 #include <linux/i2c-old.h>
+
 #include <linux/video_decoder.h>
 
 #define DEBUG(x)		/* Debug driver */
@@ -67,7 +62,8 @@
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned char data)
+static int saa7111_write(struct saa7111 *dev, unsigned char subaddr,
+			 unsigned char data)
 {
 	int ack;
 
@@ -82,9 +78,10 @@
 	return ack;
 }
 
-static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len)
+static int saa7111_write_block(struct saa7111 *dev,
+	       unsigned const char *data, unsigned int len)
 {
-	int ack = 0;
+	int ack = -1;
 	unsigned subaddr;
 
 	while (len > 1) {
@@ -96,7 +93,10 @@
 		len -= 2;
 		while (len > 1 && *data == ++subaddr) {
 			data++;
-			ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY);
+			ack =
+			    i2c_sendbyte(dev->bus,
+					 (dev->reg[subaddr] =
+					  *data++), I2C_DELAY);
 			len -= 2;
 		}
 		i2c_stop(dev->bus);
@@ -128,20 +128,19 @@
 	int i;
 	struct saa7111 *decoder;
 
-	static const unsigned char init[] =
-	{
+	static const unsigned char init[] = {
 		0x00, 0x00,	/* 00 - ID byte */
 		0x01, 0x00,	/* 01 - reserved */
 
-	/*front end */
+		/*front end */
 		0x02, 0xd0,	/* 02 - FUSE=3, GUDL=2, MODE=0 */
 		0x03, 0x23,	/* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
 		0x04, 0x00,	/* 04 - GAI1=256 */
 		0x05, 0x00,	/* 05 - GAI2=256 */
 
-	/* decoder */
-		0x06, 0xf6,	/* 06 - HSB at  13(50Hz) /  17(60Hz) pixels after end of last line */
-		0x07, 0xdd,	/* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */
+		/* decoder */
+		0x06, 0xf3,	/* 06 - HSB at  13(50Hz) /  17(60Hz) pixels after end of last line */
+		0x07, 0x13,	/* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */
 		0x08, 0xc8,	/* 08 - AUFD=1, FSEL=1, EXFIL=0, VTRC=1, HPLL=0, VNOI=0 */
 		0x09, 0x01,	/* 09 - BYPS=0, PREF=0, BPSS=0, VBLB=0, UPTCV=0, APER=1 */
 		0x0a, 0x80,	/* 0a - BRIG=128 */
@@ -160,11 +159,14 @@
 		0x17, 0x00,	/* 17 - VBI */
 	};
 
+	MOD_INC_USE_COUNT;
+
 	device->data = decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL);
-	if (decoder == NULL) {
+	if (decoder == NULL)
+	{
+		MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
-	MOD_INC_USE_COUNT;
 
 	memset(decoder, 0, sizeof(struct saa7111));
 	strcpy(device->name, "saa7111");
@@ -180,9 +182,11 @@
 
 	i = saa7111_write_block(decoder, init, sizeof(init));
 	if (i < 0) {
-		printk(KERN_ERR "%s_attach: init status %d\n", device->name, i);
+		printk(KERN_ERR "%s_attach: init status %d\n",
+		       device->name, i);
 	} else {
-		printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7111_read(decoder, 0x00));
+		printk(KERN_INFO "%s_attach: chip version %x\n",
+		       device->name, saa7111_read(decoder, 0x00) >> 4);
 	}
 	return 0;
 }
@@ -195,7 +199,8 @@
 	return 0;
 }
 
-static int saa7111_command(struct i2c_device *device, unsigned int cmd, void *arg)
+static int saa7111_command(struct i2c_device *device, unsigned int cmd,
+			   void *arg)
 {
 	struct saa7111 *decoder = device->data;
 
@@ -209,9 +214,12 @@
 			for (i = 0; i < 32; i += 16) {
 				int j;
 
-				printk("KERN_DEBUG %s: %03x", device->name, i);
+				printk("KERN_DEBUG %s: %03x", device->name,
+				       i);
 				for (j = 0; j < 16; ++j) {
-					printk(" %02x", saa7111_read(decoder, i + j));
+					printk(" %02x",
+					       saa7111_read(decoder,
+							    i + j));
 				}
 				printk("\n");
 			}
@@ -226,8 +234,7 @@
 			cap->flags
 			    = VIDEO_DECODER_PAL
 			    | VIDEO_DECODER_NTSC
-			    | VIDEO_DECODER_AUTO
-			    | VIDEO_DECODER_CCIR;
+			    | VIDEO_DECODER_AUTO | VIDEO_DECODER_CCIR;
 			cap->inputs = 8;
 			cap->outputs = 1;
 		}
@@ -274,15 +281,21 @@
 			switch (*iarg) {
 
 			case VIDEO_MODE_NTSC:
-				saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x40);
+				saa7111_write(decoder, 0x08,
+					      (decoder->
+					       reg[0x08] & 0x3f) | 0x40);
 				break;
 
 			case VIDEO_MODE_PAL:
-				saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x00);
+				saa7111_write(decoder, 0x08,
+					      (decoder->
+					       reg[0x08] & 0x3f) | 0x00);
 				break;
 
 			case VIDEO_MODE_AUTO:
-				saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x80);
+				saa7111_write(decoder, 0x08,
+					      (decoder->
+					       reg[0x08] & 0x3f) | 0x80);
 				break;
 
 			default:
@@ -300,12 +313,20 @@
 			if (*iarg < 0 || *iarg > 7) {
 				return -EINVAL;
 			}
+
 			if (decoder->input != *iarg) {
 				decoder->input = *iarg;
 				/* select mode */
-				saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input);
+				saa7111_write(decoder, 0x02,
+					      (decoder->
+					       reg[0x02] & 0xf8) |
+					      decoder->input);
 				/* bypass chrominance trap for modes 4..7 */
-				saa7111_write(decoder, 0x09, (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0));
+				saa7111_write(decoder, 0x09,
+					      (decoder->
+					       reg[0x09] & 0x7f) |
+					      ((decoder->input >
+						3) ? 0x80 : 0));
 			}
 		}
 		break;
@@ -330,19 +351,34 @@
 				decoder->enable = enable;
 
 // RJ: If output should be disabled (for playing videos), we also need a open PLL.
-				//     The input is set to 0 (where no input source is connected), although this
-				//     is not necessary.
-				//
-				//     If output should be enabled, we have to reverse the above.
+//     The input is set to 0 (where no input source is connected), although this
+//     is not necessary.
+//
+//     If output should be enabled, we have to reverse the above.
 
 				if (decoder->enable) {
-					saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input);
-					saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb));
-					saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3) | 0x0c);
+					saa7111_write(decoder, 0x02,
+						      (decoder->
+						       reg[0x02] & 0xf8) |
+						      decoder->input);
+					saa7111_write(decoder, 0x08,
+						      (decoder->
+						       reg[0x08] & 0xfb));
+					saa7111_write(decoder, 0x11,
+						      (decoder->
+						       reg[0x11] & 0xf3) |
+						      0x0c);
 				} else {
-					saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8));
-					saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb) | 0x04);
-					saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3));
+					saa7111_write(decoder, 0x02,
+						      (decoder->
+						       reg[0x02] & 0xf8));
+					saa7111_write(decoder, 0x08,
+						      (decoder->
+						       reg[0x08] & 0xfb) |
+						      0x04);
+					saa7111_write(decoder, 0x11,
+						      (decoder->
+						       reg[0x11] & 0xf3));
 				}
 			}
 		}
@@ -355,22 +391,26 @@
 			if (decoder->bright != pic->brightness) {
 				/* We want 0 to 255 we get 0-65535 */
 				decoder->bright = pic->brightness;
-				saa7111_write(decoder, 0x0a, decoder->bright >> 8);
+				saa7111_write(decoder, 0x0a,
+					      decoder->bright >> 8);
 			}
 			if (decoder->contrast != pic->contrast) {
 				/* We want 0 to 127 we get 0-65535 */
 				decoder->contrast = pic->contrast;
-				saa7111_write(decoder, 0x0b, decoder->contrast >> 9);
+				saa7111_write(decoder, 0x0b,
+					      decoder->contrast >> 9);
 			}
 			if (decoder->sat != pic->colour) {
 				/* We want 0 to 127 we get 0-65535 */
 				decoder->sat = pic->colour;
-				saa7111_write(decoder, 0x0c, decoder->sat >> 9);
+				saa7111_write(decoder, 0x0c,
+					      decoder->sat >> 9);
 			}
 			if (decoder->hue != pic->hue) {
 				/* We want -128 to 127 we get 0-65535 */
 				decoder->hue = pic->hue;
-				saa7111_write(decoder, 0x0d, (decoder->hue - 32768) >> 8);
+				saa7111_write(decoder, 0x0d,
+					      (decoder->hue - 32768) >> 8);
 			}
 		}
 		break;
@@ -384,8 +424,7 @@
 
 /* ----------------------------------------------------------------------- */
 
-struct i2c_driver i2c_driver_saa7111 =
-{
+static struct i2c_driver i2c_driver_saa7111 = {
 	"saa7111",		/* name */
 	I2C_DRIVERID_VIDEODECODER,	/* ID */
 	I2C_SAA7111, I2C_SAA7111 + 1,
@@ -397,22 +436,15 @@
 
 EXPORT_NO_SYMBOLS;
 
-#ifdef MODULE
-int init_module(void)
-#else
-int saa7111_init(void)
-#endif
+static int saa7111_init(void)
 {
 	return i2c_register_driver(&i2c_driver_saa7111);
 }
 
-
-
-#ifdef MODULE
-
-void cleanup_module(void)
+static void saa7111_exit(void)
 {
 	i2c_unregister_driver(&i2c_driver_saa7111);
 }
 
-#endif
+module_init(saa7111_init);
+module_exit(saa7111_exit);
diff -urN linux-2.4.5-pre3/drivers/media/video/saa7185.c linux/drivers/media/video/saa7185.c
--- linux-2.4.5-pre3/drivers/media/video/saa7185.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/media/video/saa7185.c	Mon Dec  3 22:44:23 2001
@@ -1,30 +1,34 @@
 /* 
-   saa7185 - Philips SAA7185B video encoder driver version 0.0.3
+    saa7185 - Philips SAA7185B video encoder driver version 0.0.3
 
-   Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+    Copyright (C) 1998 Dave Perks <dperks@ibm.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 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.
- */
+    Slight changes for video timing and attachment output by
+    Wolfgang Scherr <scherr@net4you.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 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.
+*/
 
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
@@ -41,9 +45,10 @@
 #include <asm/uaccess.h>
 
 #include <linux/i2c-old.h>
+
 #include <linux/video_encoder.h>
 
-#define DEBUG(x)   x		/* Debug driver */
+#define DEBUG(x)		/* Debug driver */
 
 /* ----------------------------------------------------------------------- */
 
@@ -66,13 +71,31 @@
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data)
+static int saa7185_read(struct saa7185 *dev)
 {
 	int ack;
 
 	LOCK_I2C_BUS(dev->bus);
 
 	i2c_start(dev->bus);
+	i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY);
+	ack = i2c_readbyte(dev->bus, 1);
+	i2c_stop(dev->bus);
+	UNLOCK_I2C_BUS(dev->bus);
+	return ack;
+}
+
+static int saa7185_write(struct saa7185 *dev, unsigned char subaddr,
+			 unsigned char data)
+{
+	int ack;
+
+	DEBUG(printk
+	      (KERN_DEBUG "SAA7185: %02x set to %02x\n", subaddr, data);
+	    )
+	    LOCK_I2C_BUS(dev->bus);
+
+	i2c_start(dev->bus);
 	i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
 	i2c_sendbyte(dev->bus, subaddr, I2C_DELAY);
 	ack = i2c_sendbyte(dev->bus, data, I2C_DELAY);
@@ -82,9 +105,10 @@
 	return ack;
 }
 
-static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len)
+static int saa7185_write_block(struct saa7185 *dev,
+			       unsigned const char *data, unsigned int len)
 {
-	int ack = 0;
+	int ack = -1;
 	unsigned subaddr;
 
 	while (len > 1) {
@@ -107,8 +131,7 @@
 
 /* ----------------------------------------------------------------------- */
 
-static const unsigned char init_common[] =
-{
+static const unsigned char init_common[] = {
 	0x3a, 0x0f,		/* CBENB=0, V656=0, VY2C=1, YUV2C=1, MY2C=1, MUV2C=1 */
 
 	0x42, 0x6b,		/* OVLY0=107 */
@@ -155,7 +178,7 @@
 	0x6c, 0x20,		/* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0, CBLF=0, ORCV2=0, PRCV2=0 */
 	0x6d, 0x00,		/* SRCM1=0, CCEN=0 */
 
-	0x6e, 0x0e,		/* HTRIG=0x00e, approx. centered, at least for PAL */
+	0x6e, 0x0e,		/* HTRIG=0x005, approx. centered, at least for PAL */
 	0x6f, 0x00,		/* HTRIG upper bits */
 	0x70, 0x20,		/* PHRES=0, SBLN=1, VTRIG=0 */
 
@@ -182,8 +205,7 @@
 	0x7d, 0x20,		/* LAL=244, FAL=22 */
 };
 
-static const unsigned char init_pal[] =
-{
+static const unsigned char init_pal[] = {
 	0x61, 0x1e,		/* FISE=0, PAL=1, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */
 	0x62, 0xc8,		/* DECTYP=1, BSTA=72 */
 	0x63, 0xcb,		/* FSC0 */
@@ -192,8 +214,7 @@
 	0x66, 0x2a,		/* FSC3 */
 };
 
-static const unsigned char init_ntsc[] =
-{
+static const unsigned char init_ntsc[] = {
 	0x61, 0x1d,		/* FISE=1, PAL=0, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */
 	0x62, 0xe6,		/* DECTYP=1, BSTA=102 */
 	0x63, 0x1f,		/* FSC0 */
@@ -207,11 +228,14 @@
 	int i;
 	struct saa7185 *encoder;
 
+	MOD_INC_USE_COUNT;
+	
 	device->data = encoder = kmalloc(sizeof(struct saa7185), GFP_KERNEL);
 	if (encoder == NULL) {
+		MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
-	MOD_INC_USE_COUNT;
+
 
 	memset(encoder, 0, sizeof(struct saa7185));
 	strcpy(device->name, "saa7185");
@@ -222,23 +246,33 @@
 
 	i = saa7185_write_block(encoder, init_common, sizeof(init_common));
 	if (i >= 0) {
-		i = saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc));
+		i = saa7185_write_block(encoder, init_ntsc,
+					sizeof(init_ntsc));
 	}
 	if (i < 0) {
-		printk(KERN_ERR "%s_attach: init error %d\n", device->name, i);
+		printk(KERN_ERR "%s_attach: init error %d\n", device->name,
+		       i);
+	} else {
+		printk(KERN_INFO "%s_attach: chip version %d\n",
+		       device->name, saa7185_read(encoder) >> 5);
 	}
+
 	return 0;
 }
 
 
 static int saa7185_detach(struct i2c_device *device)
 {
-	kfree(device->data);
+	struct saa7185 *encoder = device->data;
+	saa7185_write(encoder, 0x61, (encoder->reg[0x61]) | 0x40);	/* SW: output off is active */
+	//saa7185_write(encoder, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */
+	kfree(encoder);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
-static int saa7185_command(struct i2c_device *device, unsigned int cmd, void *arg)
+static int saa7185_command(struct i2c_device *device, unsigned int cmd,
+			   void *arg)
 {
 	struct saa7185 *encoder = device->data;
 
@@ -251,8 +285,7 @@
 			cap->flags
 			    = VIDEO_ENCODER_PAL
 			    | VIDEO_ENCODER_NTSC
-			    | VIDEO_ENCODER_SECAM
-			    | VIDEO_ENCODER_CCIR;
+			    | VIDEO_ENCODER_SECAM | VIDEO_ENCODER_CCIR;
 			cap->inputs = 1;
 			cap->outputs = 1;
 		}
@@ -265,11 +298,13 @@
 			switch (*iarg) {
 
 			case VIDEO_MODE_NTSC:
-				saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc));
+				saa7185_write_block(encoder, init_ntsc,
+						    sizeof(init_ntsc));
 				break;
 
 			case VIDEO_MODE_PAL:
-				saa7185_write_block(encoder, init_pal, sizeof(init_pal));
+				saa7185_write_block(encoder, init_pal,
+						    sizeof(init_pal));
 				break;
 
 			case VIDEO_MODE_SECAM:
@@ -285,12 +320,6 @@
 		{
 			int *iarg = arg;
 
-#if 0
-			/* not much choice of inputs */
-			if (*iarg != 0) {
-				return -EINVAL;
-			}
-#else
 			/* RJ: *iarg = 0: input is from SA7111
 			   *iarg = 1: input is from ZR36060 */
 
@@ -298,19 +327,25 @@
 
 			case 0:
 				/* Switch RTCE to 1 */
-				saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
+				saa7185_write(encoder, 0x61,
+					      (encoder->
+					       reg[0x61] & 0xf7) | 0x08);
+				saa7185_write(encoder, 0x6e, 0x01);
 				break;
 
 			case 1:
 				/* Switch RTCE to 0 */
-				saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00);
+				saa7185_write(encoder, 0x61,
+					      (encoder->
+					       reg[0x61] & 0xf7) | 0x00);
+				/* SW: a slight sync problem... */
+				saa7185_write(encoder, 0x6e, 0x00);
 				break;
 
 			default:
 				return -EINVAL;
 
 			}
-#endif
 		}
 		break;
 
@@ -330,7 +365,11 @@
 			int *iarg = arg;
 
 			encoder->enable = !!*iarg;
-			saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xbf) | (encoder->enable ? 0x00 : 0x40));
+			saa7185_write(encoder, 0x61,
+				      (encoder->
+				       reg[0x61] & 0xbf) | (encoder->
+							    enable ? 0x00 :
+							    0x40));
 		}
 		break;
 
@@ -343,8 +382,7 @@
 
 /* ----------------------------------------------------------------------- */
 
-struct i2c_driver i2c_driver_saa7185 =
-{
+static struct i2c_driver i2c_driver_saa7185 = {
 	"saa7185",		/* name */
 	I2C_DRIVERID_VIDEOENCODER,	/* ID */
 	I2C_SAA7185, I2C_SAA7185 + 1,
@@ -356,22 +394,15 @@
 
 EXPORT_NO_SYMBOLS;
 
-#ifdef MODULE
-int init_module(void)
-#else
-int saa7185_init(void)
-#endif
+static int saa7185_init(void)
 {
 	return i2c_register_driver(&i2c_driver_saa7185);
 }
 
-
-
-#ifdef MODULE
-
-void cleanup_module(void)
+static void saa7185_exit(void)
 {
 	i2c_unregister_driver(&i2c_driver_saa7185);
 }
 
-#endif
+module_init(saa7185_init);
+module_exit(saa7185_exit);
diff -urN linux-2.4.5-pre3/drivers/media/video/stradis.c linux/drivers/media/video/stradis.c
--- linux-2.4.5-pre3/drivers/media/video/stradis.c	Thu Apr 19 09:34:05 2001
+++ linux/drivers/media/video/stradis.c	Mon Dec  3 22:44:23 2001
@@ -63,6 +63,9 @@
 
 static int saa_num = 0;		/* number of SAA7146s in use */
 
+static int video_nr = -1;
+MODULE_PARM(video_nr,"i");
+
 #define nDebNormal	0x00480000
 #define nDebNoInc	0x00480000
 #define nDebVideo	0xd0480000
@@ -2073,7 +2076,7 @@
 		return result;
 	}
 	pci_set_master(dev);
-	if (video_register_device(&saa->video_dev, VFL_TYPE_GRABBER) < 0) {
+	if (video_register_device(&saa->video_dev, VFL_TYPE_GRABBER, video_nr) < 0) {
 		iounmap(saa->saa7146_mem);
 		return -1;
 	}
diff -urN linux-2.4.5-pre3/drivers/media/video/tda9875.c linux/drivers/media/video/tda9875.c
--- linux-2.4.5-pre3/drivers/media/video/tda9875.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/media/video/tda9875.c	Mon Dec  3 22:44:23 2001
@@ -80,8 +80,8 @@
 #define TDA9875_DACOS       0x13  /*DAC i/o select (ADC) 0b0000100*/
 #define TDA9875_LOSR        0x16  /*Line output select regirter 0b0100 0001*/
 
-#define TDA9875_CH1V        0x0c  /*Chanel 1 volume (mute)*/
-#define TDA9875_CH2V        0x0d  /*Chanel 2 volume (mute)*/
+#define TDA9875_CH1V        0x0c  /*Channel 1 volume (mute)*/
+#define TDA9875_CH2V        0x0d  /*Channel 2 volume (mute)*/
 #define TDA9875_SC1         0x14  /*SCART 1 in (mono)*/
 #define TDA9875_SC2         0x15  /*SCART 2 in (mono)*/
 
@@ -182,8 +182,8 @@
 	tda9875_write(client, TDA9875_SC1, 0x00 );    /* SCART 1 (SC1)*/
 	tda9875_write(client, TDA9875_SC2, 0x01 );    /* SCART 2 (sc2)*/
         
-	tda9875_write(client, TDA9875_CH1V, 0x10 );  /* Chanel volume 1 mute*/
-	tda9875_write(client, TDA9875_CH2V, 0x10 );  /* Chanel volume 2 mute */
+	tda9875_write(client, TDA9875_CH1V, 0x10 );  /* Channel volume 1 mute*/
+	tda9875_write(client, TDA9875_CH2V, 0x10 );  /* Channel volume 2 mute */
 	tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/
 	tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/
 	tda9875_write(client, TDA9875_LOSR, 0x00 );  /* line out (in:mono)*/
diff -urN linux-2.4.5-pre3/drivers/media/video/videodev.c linux/drivers/media/video/videodev.c
--- linux-2.4.5-pre3/drivers/media/video/videodev.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/video/videodev.c	Mon Dec  3 22:44:23 2001
@@ -30,6 +30,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/semaphore.h>
 
 #include <linux/kmod.h>
 
@@ -394,7 +395,7 @@
 		if (vfd == d->vdev) {
 			remove_proc_entry(d->name, video_dev_proc_entry);
 			list_del (&d->proc_list);
-			kfree (d);
+			kfree(d);
 			break;
 		}
 	}
@@ -406,9 +407,10 @@
 
 /**
  *	video_register_device - register video4linux devices
- *	@vfd: video device structure we want to register
+ *	@vfd:  video device structure we want to register
  *	@type: type of device to register
- *	FIXME: needs a semaphore on 2.3.x
+ *	@nr:   which device number (0 == /dev/video0, 1 == /dev/video1, ...
+ *             -1 == first free)
  *	
  *	The registration code assigns minor numbers based on the type
  *	requested. -ENFILE is returned in all the device slots for this
@@ -427,14 +429,17 @@
  *
  *	%VFL_TYPE_RADIO - A radio card	
  */
- 
-int video_register_device(struct video_device *vfd, int type)
+
+static DECLARE_MUTEX(videodev_register_lock);
+
+int video_register_device(struct video_device *vfd, int type, int nr)
 {
 	int i=0;
 	int base;
 	int err;
 	int end;
 	char *name_base;
+	char name[16];
 	
 	switch(type)
 	{
@@ -461,49 +466,58 @@
 		default:
 			return -1;
 	}
-	
-	for(i=base;i<end;i++)
-	{
-		if(video_device[i]==NULL)
-		{
-			char name[16];
 
-			video_device[i]=vfd;
-			vfd->minor=i;
-			/* The init call may sleep so we book the slot out
-			   then call */
-			MOD_INC_USE_COUNT;
-			if(vfd->initialize)
-			{
-				err=vfd->initialize(vfd);
-				if(err<0)
-				{
-					video_device[i]=NULL;
-					MOD_DEC_USE_COUNT;
-					return err;
-				}
-			}
-			sprintf (name, "v4l/%s%d", name_base, i - base);
-			/*
-			 *	Start the device root only. Anything else
-			 *	has serious privacy issues.
-			 */
-			vfd->devfs_handle =
-			    devfs_register (NULL, name, DEVFS_FL_DEFAULT,
-					    VIDEO_MAJOR, vfd->minor,
-					    S_IFCHR | S_IRUSR | S_IWUSR,
-					    &video_fops, NULL);
-
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-			sprintf (name, "%s%d", name_base, i - base);
-			videodev_proc_create_dev (vfd, name);
-#endif
-			
-
-			return 0;
+	/* pick a minor number */
+	down(&videodev_register_lock);
+	if (-1 == nr) {
+		/* use first free */
+		for(i=base;i<end;i++)
+			if (NULL == video_device[i])
+				break;
+		if (i == end) {
+			up(&videodev_register_lock);
+			return -ENFILE;
+		}
+	} else {
+		/* use the one the driver asked for */
+		i = base+nr;
+		if (NULL != video_device[i]) {
+			up(&videodev_register_lock);
+			return -ENFILE;
+		}
+	}
+	video_device[i]=vfd;
+	vfd->minor=i;
+	up(&videodev_register_lock);
+
+	/* The init call may sleep so we book the slot out
+	   then call */
+	MOD_INC_USE_COUNT;
+	if(vfd->initialize) {
+		err=vfd->initialize(vfd);
+		if(err<0) {
+			video_device[i]=NULL;
+			MOD_DEC_USE_COUNT;
+			return err;
 		}
 	}
-	return -ENFILE;
+	sprintf (name, "v4l/%s%d", name_base, i - base);
+	/*
+	 *	Start the device root only. Anything else
+	 *	has serious privacy issues.
+	 */
+	vfd->devfs_handle =
+		devfs_register (NULL, name, DEVFS_FL_DEFAULT,
+				VIDEO_MAJOR, vfd->minor,
+				S_IFCHR | S_IRUSR | S_IWUSR,
+				&video_fops,
+				NULL);
+	
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	sprintf (name, "%s%d", name_base, i - base);
+	videodev_proc_create_dev (vfd, name);
+#endif
+	return 0;
 }
 
 /**
@@ -546,7 +560,7 @@
  *	Initialise video for linux
  */
  
-int __init videodev_init(void)
+static int __init videodev_init(void)
 {
 	struct video_init *vfli = video_init_list;
 	
@@ -573,25 +587,28 @@
 	return 0;
 }
 
-#ifdef MODULE		
-int init_module(void)
-{
-	return videodev_init();
-}
-
-void cleanup_module(void)
+static void __exit videodev_exit(void)
 {
+#ifdef MODULE		
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 	videodev_proc_destroy ();
 #endif
+#endif
 	
 	devfs_unregister_chrdev(VIDEO_MAJOR, "video_capture");
 }
 
-#endif
+module_init(videodev_init)
+module_exit(videodev_exit)
 
 EXPORT_SYMBOL(video_register_device);
 EXPORT_SYMBOL(video_unregister_device);
 
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -urN linux-2.4.5-pre3/drivers/media/video/w9966.c linux/drivers/media/video/w9966.c
--- linux-2.4.5-pre3/drivers/media/video/w9966.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/video/w9966.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,996 @@
+/*
+	Winbond w9966cf Webcam parport driver.
+
+	Version 0.32
+
+	Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se>
+
+	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.
+*/
+/*
+	Supported devices:
+	*Lifeview FlyCam Supra (using the Philips saa7111a chip)
+
+	Does any other model using the w9966 interface chip exist ?
+
+	Todo:
+	
+	*Add a working EPP mode, since DMA ECP read isn't implemented
+	in the parport drivers. (That's why it's so sloow)
+
+	*Add support for other ccd-control chips than the saa7111
+	please send me feedback on what kind of chips you have.
+
+	*Add proper probing. I don't know what's wrong with the IEEE1284
+	parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID)
+	and nibble read seems to be broken for some peripherals.
+
+	*Add probing for onboard SRAM, port directions etc. (if possible)
+
+	*Add support for the hardware compressed modes (maybe using v4l2)
+
+	*Fix better support for the capture window (no skewed images, v4l
+	interface to capt. window)
+
+	*Probably some bugs that I don't know of
+
+	Please support me by sending feedback!
+	
+	Changes:
+	
+	Alan Cox:	Removed RGB mode for kernel merge, added THIS_MODULE
+			and owner support for newer module locks
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/videodev.h>
+#include <linux/parport.h>
+
+//#define DEBUG				// Undef me for production
+
+#ifdef DEBUG
+#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: "__FUNCTION__ "(): "x, ##a)
+#else
+#define DPRINTF(x...)
+#endif
+
+/*
+ *	Defines, simple typedefs etc.
+ */
+
+#define W9966_DRIVERNAME	"W9966CF Webcam"
+#define W9966_MAXCAMS		4	// Maximum number of cameras
+#define W9966_RBUFFER		2048	// Read buffer (must be an even number)
+#define W9966_SRAMSIZE		131072	// 128kb
+#define W9966_SRAMID		0x02	// check w9966cf.pdf
+
+// Empirically determined window limits
+#define W9966_WND_MIN_X		16
+#define W9966_WND_MIN_Y		14
+#define W9966_WND_MAX_X		705
+#define W9966_WND_MAX_Y		253
+#define W9966_WND_MAX_W		(W9966_WND_MAX_X - W9966_WND_MIN_X)
+#define W9966_WND_MAX_H		(W9966_WND_MAX_Y - W9966_WND_MIN_Y)
+
+// Keep track of our current state
+#define W9966_STATE_PDEV	0x01
+#define W9966_STATE_CLAIMED	0x02
+#define W9966_STATE_VDEV	0x04
+
+#define W9966_I2C_W_ID		0x48
+#define W9966_I2C_R_ID		0x49
+#define W9966_I2C_R_DATA	0x08
+#define W9966_I2C_R_CLOCK	0x04
+#define W9966_I2C_W_DATA	0x02
+#define W9966_I2C_W_CLOCK	0x01
+
+struct w9966_dev {
+	unsigned char dev_state;
+	unsigned char i2c_state;
+	unsigned short ppmode;
+	struct parport* pport;
+	struct pardevice* pdev;
+	struct video_device vdev;
+	unsigned short width;
+	unsigned short height;
+	unsigned char brightness;
+	signed char contrast;
+	signed char color;
+	signed char hue;
+};
+
+/*
+ *	Module specific properties
+ */
+
+MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
+MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
+
+#ifdef MODULE
+static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""};
+#else
+static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
+#endif
+MODULE_PARM(pardev, "1-" __MODULE_STRING(W9966_MAXCAMS) "s");
+MODULE_PARM_DESC(pardev, "pardev: where to search for\n\
+\teach camera. 'aggressive' means brute-force search.\n\
+\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign
+\tcam 1 to parport3 and search every parport for cam 2 etc...");
+
+static int parmode = 0;
+MODULE_PARM(parmode, "i");
+MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
+
+static int video_nr = -1;
+MODULE_PARM(video_nr, "i");
+
+/*
+ *	Private data
+ */
+
+static struct w9966_dev w9966_cams[W9966_MAXCAMS];
+
+/*
+ *	Private function declares
+ */
+
+static inline void w9966_setState(struct w9966_dev* cam, int mask, int val);
+static inline int  w9966_getState(struct w9966_dev* cam, int mask, int val);
+static inline void w9966_pdev_claim(struct w9966_dev *vdev);
+static inline void w9966_pdev_release(struct w9966_dev *vdev);
+
+static int w9966_rReg(struct w9966_dev* cam, int reg);
+static int w9966_wReg(struct w9966_dev* cam, int reg, int data);
+static int w9966_rReg_i2c(struct w9966_dev* cam, int reg);
+static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data);
+static int w9966_findlen(int near, int size, int maxlen);
+static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor);
+static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h);
+
+static int  w9966_init(struct w9966_dev* cam, struct parport* port);
+static void w9966_term(struct w9966_dev* cam);
+
+static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state);
+static inline int  w9966_i2c_setscl(struct w9966_dev* cam, int state);
+static inline int  w9966_i2c_getsda(struct w9966_dev* cam);
+static inline int  w9966_i2c_getscl(struct w9966_dev* cam);
+static int w9966_i2c_wbyte(struct w9966_dev* cam, int data);
+static int w9966_i2c_rbyte(struct w9966_dev* cam);
+
+static int  w9966_v4l_open(struct video_device *vdev, int mode);
+static void w9966_v4l_close(struct video_device *vdev);
+static int  w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg);
+static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count, int noblock);
+
+/*
+ *	Private function defines
+ */
+
+
+// Set camera phase flags, so we know what to uninit when terminating 
+static inline void w9966_setState(struct w9966_dev* cam, int mask, int val)
+{
+	cam->dev_state = (cam->dev_state & ~mask) ^ val;
+}
+
+// Get camera phase flags
+static inline int w9966_getState(struct w9966_dev* cam, int mask, int val)
+{
+	return ((cam->dev_state & mask) == val);
+}
+
+// Claim parport for ourself
+static inline void w9966_pdev_claim(struct w9966_dev* cam)
+{
+	if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
+		return;
+	parport_claim_or_block(cam->pdev);
+	w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
+}
+
+// Release parport for others to use
+static inline void w9966_pdev_release(struct w9966_dev* cam)
+{
+	if (w9966_getState(cam, W9966_STATE_CLAIMED, 0))
+		return;
+	parport_release(cam->pdev);
+	w9966_setState(cam, W9966_STATE_CLAIMED, 0);
+}
+ 
+// Read register from W9966 interface-chip
+// Expects a claimed pdev
+// -1 on error, else register data (byte)
+static int w9966_rReg(struct w9966_dev* cam, int reg)
+{
+	// ECP, read, regtransfer, REG, REG, REG, REG, REG
+	const unsigned char addr = 0x80 | (reg & 0x1f);
+	unsigned char val;
+	
+	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
+		return -1;
+	if (parport_write(cam->pport, &addr, 1) != 1)
+		return -1;
+	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
+		return -1;
+	if (parport_read(cam->pport, &val, 1) != 1)
+		return -1;
+
+	return val;
+}
+
+// Write register to W9966 interface-chip
+// Expects a claimed pdev
+// -1 on error
+static int w9966_wReg(struct w9966_dev* cam, int reg, int data)
+{
+	// ECP, write, regtransfer, REG, REG, REG, REG, REG
+	const unsigned char addr = 0xc0 | (reg & 0x1f);
+	const unsigned char val = data;
+	
+	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
+		return -1;
+	if (parport_write(cam->pport, &addr, 1) != 1)
+		return -1;
+	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
+		return -1;
+	if (parport_write(cam->pport, &val, 1) != 1)
+		return -1;
+
+	return 0;
+}
+
+// Initialize camera device. Setup all internal flags, set a
+// default video mode, setup ccd-chip, register v4l device etc..
+// Also used for 'probing' of hardware.
+// -1 on error
+static int w9966_init(struct w9966_dev* cam, struct parport* port)
+{
+	if (cam->dev_state != 0)
+		return -1;
+	
+	cam->pport = port;
+	cam->brightness = 128;
+	cam->contrast = 64;
+	cam->color = 64;
+	cam->hue = 0;
+
+// Select requested transfer mode
+	switch(parmode)
+	{
+	default:	// Auto-detect (priority: hw-ecp, hw-epp, sw-ecp)
+	case 0:
+		if (port->modes & PARPORT_MODE_ECP)
+			cam->ppmode = IEEE1284_MODE_ECP;
+		else if (port->modes & PARPORT_MODE_EPP)
+			cam->ppmode = IEEE1284_MODE_EPP;
+		else
+			cam->ppmode = IEEE1284_MODE_ECP;
+		break;	
+	case 1:		// hw- or sw-ecp
+		cam->ppmode = IEEE1284_MODE_ECP;
+		break;
+	case 2:		// hw- or sw-epp
+		cam->ppmode = IEEE1284_MODE_EPP;
+	break;
+	}
+	
+// Tell the parport driver that we exists
+	cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
+	if (cam->pdev == NULL) {
+		DPRINTF("parport_register_device() failed\n");
+		return -1;
+	}
+	w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
+
+	w9966_pdev_claim(cam);
+	
+// Setup a default capture mode
+	if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
+		DPRINTF("w9966_setup() failed.\n");
+		return -1;
+	}
+
+	w9966_pdev_release(cam);
+
+// Fill in the video_device struct and register us to v4l
+	memset(&cam->vdev, 0, sizeof(struct video_device));
+	strcpy(cam->vdev.name, W9966_DRIVERNAME);
+	cam->vdev.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+	cam->vdev.hardware = VID_HARDWARE_W9966;
+	cam->vdev.open = &w9966_v4l_open;
+	cam->vdev.close = &w9966_v4l_close;
+	cam->vdev.read = &w9966_v4l_read;
+	cam->vdev.ioctl = &w9966_v4l_ioctl;
+	cam->vdev.priv = (void*)cam;
+	cam->vdev.owner = THIS_MODULE;
+
+	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1)		 
+		return -1;
+	
+	w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
+	
+	// All ok
+	printk(
+		"w9966cf: Found and initialized a webcam on %s.\n",
+		cam->pport->name
+	);
+	return 0;
+}
+
+
+// Terminate everything gracefully
+static void w9966_term(struct w9966_dev* cam)
+{
+// Unregister from v4l
+	if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
+		video_unregister_device(&cam->vdev);
+		w9966_setState(cam, W9966_STATE_VDEV, 0);
+	}
+
+// Terminate from IEEE1284 mode and release pdev block
+	if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
+		w9966_pdev_claim(cam);
+		parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
+		w9966_pdev_release(cam);
+	}
+
+// Unregister from parport
+	if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
+		parport_unregister_device(cam->pdev);
+		w9966_setState(cam, W9966_STATE_PDEV, 0);
+	}
+}
+
+
+// Find a good length for capture window (used both for W and H)
+// A bit ugly but pretty functional. The capture length
+// have to match the downscale
+static int w9966_findlen(int near, int size, int maxlen)
+{
+	int bestlen = size;
+	int besterr = abs(near - bestlen);
+	int len;
+
+	for(len = size+1;len < maxlen;len++)
+	{
+		int err;
+		if ( ((64*size) %len) != 0)
+			continue;
+
+		err = abs(near - len);
+
+		// Only continue as long as we keep getting better values
+		if (err > besterr)
+			break;
+		
+		besterr = err;
+		bestlen = len;
+	}
+
+	return bestlen;
+}
+
+// Modify capture window (if necessary) 
+// and calculate downscaling
+// Return -1 on error
+static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor)
+{
+	int maxlen = max - min;
+	int len = *end - *beg + 1;
+	int newlen = w9966_findlen(len, size, maxlen);
+	int err = newlen - len; 
+
+	// Check for bad format
+	if (newlen > maxlen || newlen < size)
+		return -1;
+
+	// Set factor (6 bit fixed)
+	*factor = (64*size) / newlen;
+	if (*factor == 64)
+		*factor = 0x00;	// downscale is disabled
+	else
+		*factor |= 0x80; // set downscale-enable bit
+
+	// Modify old beginning and end
+	*beg -= err / 2;
+	*end += err - (err / 2);
+
+	// Move window if outside borders
+	if (*beg < min) {
+		*end += min - *beg;
+		*beg += min - *beg;
+	}
+	if (*end > max) {
+		*beg -= *end - max;
+		*end -= *end - max;
+	}
+
+	return 0;
+}
+
+// Setup the cameras capture window etc.
+// Expects a claimed pdev
+// return -1 on error
+static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h)
+{
+	unsigned int i;
+	unsigned int enh_s, enh_e;
+	unsigned char scale_x, scale_y;
+	unsigned char regs[0x1c];
+	unsigned char saa7111_regs[] = {
+		0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
+		0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
+		0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
+	};
+	
+	
+	if (w*h*2 > W9966_SRAMSIZE)
+	{
+		DPRINTF("capture window exceeds SRAM size!.\n");
+		w = 200; h = 160;	// Pick default values
+	}
+
+	w &= ~0x1;
+	if (w < 2) w = 2;
+	if (h < 1) h = 1;
+	if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W;
+	if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H;
+
+	cam->width = w;
+	cam->height = h;
+
+	enh_s = 0;	
+	enh_e = w*h*2;
+	
+// Modify capture window if necessary and calculate downscaling
+	if (
+		w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
+		w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0
+	) return -1;
+
+	DPRINTF(
+		"%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
+		w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80
+	);
+	
+// Setup registers
+	regs[0x00] = 0x00;			// Set normal operation
+	regs[0x01] = 0x18;			// Capture mode
+	regs[0x02] = scale_y;			// V-scaling
+	regs[0x03] = scale_x;			// H-scaling
+	
+	// Capture window	
+	regs[0x04] = (x1 & 0x0ff);		// X-start (8 low bits)
+	regs[0x05] = (x1 & 0x300)>>8;		// X-start (2 high bits)
+	regs[0x06] = (y1 & 0x0ff);		// Y-start (8 low bits)
+	regs[0x07] = (y1 & 0x300)>>8;		// Y-start (2 high bits)
+	regs[0x08] = (x2 & 0x0ff);		// X-end (8 low bits)
+	regs[0x09] = (x2 & 0x300)>>8;		// X-end (2 high bits)
+	regs[0x0a] = (y2 & 0x0ff);		// Y-end (8 low bits)
+
+	regs[0x0c] = W9966_SRAMID;		// SRAM-banks (1x 128kb)
+	
+	// Enhancement layer
+	regs[0x0d] = (enh_s& 0x000ff);		// Enh. start (0-7)
+	regs[0x0e] = (enh_s& 0x0ff00)>>8;	// Enh. start (8-15)
+	regs[0x0f] = (enh_s& 0x70000)>>16;	// Enh. start (16-17/18??)
+	regs[0x10] = (enh_e& 0x000ff);		// Enh. end (0-7)
+	regs[0x11] = (enh_e& 0x0ff00)>>8;	// Enh. end (8-15)
+	regs[0x12] = (enh_e& 0x70000)>>16;	// Enh. end (16-17/18??)
+
+	// Misc
+	regs[0x13] = 0x40;			// VEE control (raw 4:2:2)
+	regs[0x17] = 0x00;			// ???
+	regs[0x18] = cam->i2c_state = 0x00;	// Serial bus
+	regs[0x19] = 0xff;			// I/O port direction control
+	regs[0x1a] = 0xff;			// I/O port data register
+	regs[0x1b] = 0x10;			// ???
+	
+	// SAA7111 chip settings
+	saa7111_regs[0x0a] = cam->brightness;
+	saa7111_regs[0x0b] = cam->contrast;
+	saa7111_regs[0x0c] = cam->color;
+	saa7111_regs[0x0d] = cam->hue;
+
+// Reset (ECP-fifo & serial-bus)
+	if (w9966_wReg(cam, 0x00, 0x03) == -1)
+		return -1;
+
+// Write regs to w9966cf chip
+	for (i = 0; i < 0x1c; i++)
+		if (w9966_wReg(cam, i, regs[i]) == -1)
+			return -1;
+
+// Write regs to saa7111 chip
+	for (i = 0; i < 0x20; i++)
+		if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1)
+			return -1;
+
+	return 0;
+}
+
+/*
+ *	Ugly and primitive i2c protocol functions
+ */
+
+// Sets the data line on the i2c bus.
+// Expects a claimed pdev.
+static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state)
+{
+	if (state)
+		cam->i2c_state |= W9966_I2C_W_DATA;
+	else
+		cam->i2c_state &= ~W9966_I2C_W_DATA;
+	
+	w9966_wReg(cam, 0x18, cam->i2c_state);
+	udelay(5);
+}
+
+// Sets the clock line on the i2c bus.
+// Expects a claimed pdev. -1 on error
+static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state)
+{
+	int timeout;
+	if (state)
+		cam->i2c_state |= W9966_I2C_W_CLOCK;
+	else
+		cam->i2c_state &= ~W9966_I2C_W_CLOCK;
+
+	w9966_wReg(cam, 0x18, cam->i2c_state);
+	udelay(5);
+	
+	// we go to high, we also expect the peripheral to ack.
+	if (state) {
+		timeout = jiffies + 100;
+		while (!w9966_i2c_getscl(cam)) {
+			if (jiffies > timeout)
+				return -1;
+		}
+	}
+	return 0;
+}
+
+// Get peripheral data line
+// Expects a claimed pdev.
+static inline int w9966_i2c_getsda(struct w9966_dev* cam)
+{
+	const unsigned char state = w9966_rReg(cam, 0x18);
+	return ((state & W9966_I2C_R_DATA) > 0);
+}
+
+// Get peripheral clock line
+// Expects a claimed pdev.
+static inline int w9966_i2c_getscl(struct w9966_dev* cam)
+{
+	const unsigned char state = w9966_rReg(cam, 0x18);
+	return ((state & W9966_I2C_R_CLOCK) > 0);
+}
+
+// Write a byte with ack to the i2c bus.
+// Expects a claimed pdev. -1 on error
+static int w9966_i2c_wbyte(struct w9966_dev* cam, int data)
+{
+	int i;
+	for (i = 7; i >= 0; i--)
+	{
+		w9966_i2c_setsda(cam, (data >> i) & 0x01);
+
+		if (w9966_i2c_setscl(cam, 1) == -1)
+			return -1;			
+		w9966_i2c_setscl(cam, 0);
+	}
+
+	w9966_i2c_setsda(cam, 1);
+	
+	if (w9966_i2c_setscl(cam, 1) == -1)
+		return -1;
+	w9966_i2c_setscl(cam, 0);
+	
+	return 0;
+}
+
+// Read a data byte with ack from the i2c-bus
+// Expects a claimed pdev. -1 on error
+static int w9966_i2c_rbyte(struct w9966_dev* cam)
+{
+	unsigned char data = 0x00;
+	int i;	
+	
+	w9966_i2c_setsda(cam, 1);
+
+	for (i = 0; i < 8; i++)
+	{
+		if (w9966_i2c_setscl(cam, 1) == -1)
+			return -1;
+		data = data << 1;
+		if (w9966_i2c_getsda(cam))
+			data |= 0x01;
+		
+		w9966_i2c_setscl(cam, 0);
+	}
+	return data;
+}
+
+// Read a register from the i2c device.
+// Expects claimed pdev. -1 on error
+static int w9966_rReg_i2c(struct w9966_dev* cam, int reg)
+{
+	int data;
+
+	w9966_i2c_setsda(cam, 0);
+	w9966_i2c_setscl(cam, 0);
+
+	if (
+		w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
+		w9966_i2c_wbyte(cam, reg) == -1
+	)
+		return -1;
+
+	w9966_i2c_setsda(cam, 1);
+	if (w9966_i2c_setscl(cam, 1) == -1)
+		return -1;
+	w9966_i2c_setsda(cam, 0);
+	w9966_i2c_setscl(cam, 0);
+
+	if (
+		w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1 ||
+		(data = w9966_i2c_rbyte(cam)) == -1
+	)
+		return -1;
+
+	w9966_i2c_setsda(cam, 0);
+	
+	if (w9966_i2c_setscl(cam, 1) == -1)
+		return -1;
+	w9966_i2c_setsda(cam, 1);
+	
+	return data;
+}
+
+// Write a register to the i2c device.
+// Expects claimed pdev. -1 on error
+static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
+{
+	w9966_i2c_setsda(cam, 0);
+	w9966_i2c_setscl(cam, 0);
+
+	if (
+		w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
+		w9966_i2c_wbyte(cam, reg) == -1 ||
+		w9966_i2c_wbyte(cam, data) == -1
+	)
+		return -1;
+
+	w9966_i2c_setsda(cam, 0);
+	if (w9966_i2c_setscl(cam, 1) == -1)
+		return -1;
+		
+	w9966_i2c_setsda(cam, 1);
+
+	return 0;
+}
+
+/*
+ *	Video4linux interfacing
+ */
+
+static int w9966_v4l_open(struct video_device *vdev, int flags)
+{
+	return 0;
+}
+
+static void w9966_v4l_close(struct video_device *vdev)
+{
+}
+
+static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+{
+	struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
+	
+	switch(cmd)
+	{
+	case VIDIOCGCAP:
+	{
+		struct video_capability vcap = {
+			W9966_DRIVERNAME,	// name
+			VID_TYPE_CAPTURE | VID_TYPE_SCALES,	// type
+			1, 0,			// vid, aud channels
+			W9966_WND_MAX_W,	// max w
+			W9966_WND_MAX_H,	// max h
+			2, 1			// min w, min h
+		};
+
+		if(copy_to_user(arg, &vcap, sizeof(vcap)) != 0)
+			return -EFAULT;
+
+		return 0;
+	}
+	case VIDIOCGCHAN:
+	{
+		struct video_channel vch;
+		if(copy_from_user(&vch, arg, sizeof(vch)) != 0)
+			return -EFAULT;
+
+		if(vch.channel != 0)	// We only support one channel (#0)
+			return -EINVAL;
+
+		strcpy(vch.name, "CCD-input");
+		vch.flags = 0;		// We have no tuner or audio
+		vch.tuners = 0;
+		vch.type = VIDEO_TYPE_CAMERA;
+		vch.norm = 0;		// ???
+		
+		if(copy_to_user(arg, &vch, sizeof(vch)) != 0)
+			return -EFAULT;
+		
+		return 0;
+	}
+	case VIDIOCSCHAN:
+	{
+		struct video_channel vch;
+		if(copy_from_user(&vch, arg, sizeof(vch) ) != 0)
+			return -EFAULT;
+		
+		if(vch.channel != 0)
+			return -EINVAL;
+		
+		return 0;
+	}
+	case VIDIOCGTUNER:
+	{
+		struct video_tuner vtune;
+		if(copy_from_user(&vtune, arg, sizeof(vtune)) != 0)
+			return -EFAULT;
+		
+		if(vtune.tuner != 0);
+			return -EINVAL;
+		
+		strcpy(vtune.name, "Foo-tuner");
+		vtune.rangelow = 0;
+		vtune.rangehigh = 0;
+		vtune.flags = VIDEO_TUNER_NORM;
+		vtune.mode = VIDEO_MODE_AUTO;
+		vtune.signal = 0xffff;
+		
+		if(copy_to_user(arg, &vtune, sizeof(vtune)) != 0)
+			return -EFAULT;
+		
+		return 0;
+	}
+	case VIDIOCSTUNER:
+	{
+		struct video_tuner vtune;
+		if (copy_from_user(&vtune, arg, sizeof(vtune)) != 0)
+			return -EFAULT;
+		
+		if (vtune.tuner != 0)
+			return -EINVAL;
+		
+		if (vtune.mode != VIDEO_MODE_AUTO)
+			return -EINVAL;
+		
+		return 0;
+	}
+	case VIDIOCGPICT:
+	{
+		struct video_picture vpic = {
+			cam->brightness << 8,	// brightness
+			(cam->hue + 128) << 8,	// hue
+			cam->color << 9,	// color
+			cam->contrast << 9,	// contrast
+			0x8000,			// whiteness
+			16, VIDEO_PALETTE_YUV422// bpp, palette format
+		};
+
+		if(copy_to_user(arg, &vpic, sizeof(vpic)) != 0)
+			return -EFAULT;
+
+		return 0;
+	}
+	case VIDIOCSPICT:
+	{
+		struct video_picture vpic;
+		if(copy_from_user(&vpic, arg, sizeof(vpic)) != 0)
+			return -EFAULT;
+		
+		if (vpic.depth != 16 || vpic.palette != VIDEO_PALETTE_YUV422)
+			return -EINVAL;
+			
+		cam->brightness = vpic.brightness >> 8;
+		cam->hue = (vpic.hue >> 8) - 128;
+		cam->color = vpic.colour >> 9;
+		cam->contrast = vpic.contrast >> 9;
+
+		w9966_pdev_claim(cam);
+		
+		if (
+			w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 ||
+			w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 ||
+			w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 ||
+			w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1
+		) {
+			w9966_pdev_release(cam);
+			return -EFAULT;
+		}
+		
+		w9966_pdev_release(cam);
+		return 0;
+	}
+	case VIDIOCSWIN:
+	{
+		int ret;
+		struct video_window vwin;
+		
+		if (copy_from_user(&vwin, arg, sizeof(vwin)) != 0)
+			return -EFAULT;		
+		if (vwin.flags != 0)
+			return -EINVAL;
+		if (vwin.clipcount != 0)
+			return -EINVAL;
+		if (vwin.width < 2 || vwin.width > W9966_WND_MAX_W)
+			return -EINVAL;		
+		if (vwin.height < 1 || vwin.height > W9966_WND_MAX_H)
+			return -EINVAL;
+
+		// Update camera regs
+		w9966_pdev_claim(cam);
+		ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin.width, vwin.height);
+		w9966_pdev_release(cam);
+		
+		if (ret != 0) {
+			DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
+			return -EFAULT;
+		}
+		
+		return 0;
+	}
+	case VIDIOCGWIN:
+	{
+		struct video_window vwin;
+		memset(&vwin, 0, sizeof(vwin));
+		
+		vwin.width = cam->width;
+		vwin.height = cam->height;
+		
+		if(copy_to_user(arg, &vwin, sizeof(vwin)) != 0)
+			return -EFAULT;
+		
+		return 0;
+	}
+	// Unimplemented
+	case VIDIOCCAPTURE:	
+	case VIDIOCGFBUF:
+	case VIDIOCSFBUF:
+	case VIDIOCKEY:
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		return -EINVAL;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+// Capture data
+static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count,  int noblock)
+{
+	struct w9966_dev *cam = (struct w9966_dev *)vdev->priv;
+	unsigned char addr = 0xa0;	// ECP, read, CCD-transfer, 00000
+	unsigned char* dest = (unsigned char*)buf;
+	unsigned long dleft = count;
+	
+	// Why would anyone want more than this??
+	if (count > cam->width * cam->height * 2)
+		return -EINVAL;
+	
+	w9966_pdev_claim(cam);
+	w9966_wReg(cam, 0x00, 0x02);	// Reset ECP-FIFO buffer
+	w9966_wReg(cam, 0x00, 0x00);	// Return to normal operation
+	w9966_wReg(cam, 0x01, 0x98);	// Enable capture
+
+	// write special capture-addr and negotiate into data transfer	
+	if (
+		(parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0	)||
+		(parport_write(cam->pport, &addr, 1) != 1						)||
+		(parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0	)
+	) {
+		w9966_pdev_release(cam);
+		return -EFAULT;
+	}
+	
+	while(dleft > 0)
+	{
+		unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
+		unsigned char tbuf[W9966_RBUFFER];
+	
+		if (parport_read(cam->pport, tbuf, tsize) < tsize) {
+			w9966_pdev_release(cam);
+			return -EFAULT;
+		}
+		if (copy_to_user(dest, tbuf, tsize) != 0) {
+			w9966_pdev_release(cam);
+			return -EFAULT;
+		}
+		dest += tsize;
+		dleft -= tsize;
+	}
+	
+	w9966_wReg(cam, 0x01, 0x18);	// Disable capture
+	w9966_pdev_release(cam);
+
+	return count;
+}
+
+
+// Called once for every parport on init
+static void w9966_attach(struct parport *port)
+{
+	int i;
+	
+	for (i = 0; i < W9966_MAXCAMS; i++)
+	{
+		if (w9966_cams[i].dev_state != 0)	// Cam is already assigned
+			continue;
+		if (
+			strcmp(pardev[i], "aggressive") == 0 ||
+			strcmp(pardev[i], port->name) == 0
+		) {
+			if (w9966_init(&w9966_cams[i], port) != 0)
+			w9966_term(&w9966_cams[i]);
+			break;	// return
+		}
+	}
+}
+
+// Called once for every parport on termination
+static void w9966_detach(struct parport *port)
+{
+	int i;
+	for (i = 0; i < W9966_MAXCAMS; i++)
+	if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
+		w9966_term(&w9966_cams[i]);
+}
+
+
+static struct parport_driver w9966_ppd = {
+	W9966_DRIVERNAME,
+	w9966_attach,
+	w9966_detach,
+	NULL
+};
+
+// Module entry point
+static int __init w9966_mod_init(void)
+{
+	int i;
+	for (i = 0; i < W9966_MAXCAMS; i++)
+		w9966_cams[i].dev_state = 0;
+
+	return parport_register_driver(&w9966_ppd);
+}
+
+// Module cleanup
+static void __exit w9966_mod_term(void)
+{
+	parport_unregister_driver(&w9966_ppd);
+}
+
+module_init(w9966_mod_init);
+module_exit(w9966_mod_term);
diff -urN linux-2.4.5-pre3/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c
--- linux-2.4.5-pre3/drivers/media/video/zr36120.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/video/zr36120.c	Mon Dec  3 22:44:23 2001
@@ -57,11 +57,15 @@
 
 static unsigned int triton1=0;			/* triton1 chipset? */
 static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE };
+static int video_nr = -1;
+static int vbi_nr = -1;
 
 MODULE_AUTHOR("Pauline Middelink <middelin@polyware.nl>");
 MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber");
 MODULE_PARM(triton1,"i");
 MODULE_PARM(cardtype,"1-" __MODULE_STRING(ZORAN_MAX) "i");
+MODULE_PARM(video_nr,"i");
+MODULE_PARM(vbi_nr,"i");
 
 static int zoran_cards;
 static struct zoran zorans[ZORAN_MAX];
@@ -1990,13 +1994,13 @@
 	ztv->video_dev = zr36120_template;
 	strcpy(ztv->video_dev.name, ztv->i2c.name);
 	ztv->video_dev.priv = ztv;
-	if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER) < 0)
+	if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER, video_nr) < 0)
 		return -1;
 
 	ztv->vbi_dev = vbi_template;
 	strcpy(ztv->vbi_dev.name, ztv->i2c.name);
 	ztv->vbi_dev.priv = ztv;
-	if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI) < 0) {
+	if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI, vbi_nr) < 0) {
 		video_unregister_device(&ztv->video_dev);
 		return -1;
 	}
diff -urN linux-2.4.5-pre3/drivers/net/Config.in linux/drivers/net/Config.in
--- linux-2.4.5-pre3/drivers/net/Config.in	Mon Dec  3 22:43:49 2001
+++ linux/drivers/net/Config.in	Mon Dec  3 22:44:23 2001
@@ -146,7 +146,7 @@
          tristate '    Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
          tristate '    Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
       fi
-      dep_tristate '    DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102 $CONFIG_PCI $CONFIG_EXPERIMENTAL
+      dep_tristate '    Davicom DM910x/DM980x support' CONFIG_DM9102 $CONFIG_PCI
       dep_tristate '    EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI
       dep_mbool '      Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM $CONFIG_EEPRO100 $CONFIG_EXPERIMENTAL
       dep_tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
diff -urN linux-2.4.5-pre3/drivers/net/dmfe.c linux/drivers/net/dmfe.c
--- linux-2.4.5-pre3/drivers/net/dmfe.c	Mon Dec  3 22:43:49 2001
+++ linux/drivers/net/dmfe.c	Mon Dec  3 22:44:23 2001
@@ -1,82 +1,56 @@
 /*
-   dmfe.c: Version 1.30 06/11/2000
+    dmfe.c: Version 1.36p1 2001-05-12 for Linux kernel 2.4.x
 
-   A Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux. 
-   Copyright (C) 1997  Sten Wang
-   (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
+    A Davicom DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 NIC fast
+    ethernet driver for Linux.
+    Copyright (C) 1997  Sten Wang
 
-   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 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.
+    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.
 
+    DAVICOM Web-Site: www.davicom.com.tw
 
-   Compiler command:
-   "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall 
-   -Wstrict-prototypes -O6 -c dmfe.c"
-   OR
-   "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net -Wall 
-   -Wstrict-prototypes -O6 -c dmfe.c"
+    Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw
+    Maintainer: Tobias Ringstrom <tori@unhappy.mine.nu>
 
-   The following steps teach you how to active DM9102 board:
-   1. Used the upper compiler command to compile dmfe.c
-   2. insert dmfe module into kernel
-   "insmod dmfe"        ;;Auto Detection Mode
-   "insmod dmfe mode=0" ;;Force 10M Half Duplex
-   "insmod dmfe mode=1" ;;Force 100M Half Duplex
-   "insmod dmfe mode=4" ;;Force 10M Full Duplex
-   "insmod dmfe mode=5" ;;Force 100M Full Duplex
-   3. config a dm9102 network interface
-   "ifconfig eth0 172.22.3.18"
-   4. active the IP routing table
-   "route add -net 172.22.3.0 eth0"
-   5. Well done. Your DM9102 adapter actived now.
+    (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
 
-   Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw
+    Marcelo Tosatti <marcelo@conectiva.com.br> :
+    Made it compile in 2.3 (device to net_device)
 
-   Date:   10/28,1998
+    Alan Cox <alan@redhat.com> :
+    Cleaned up for kernel merge.
+    Removed the back compatibility support
+    Reformatted, fixing spelling etc as I went
+    Removed IRQ 0-15 assumption
 
-   (C)Copyright 1997-1998 DAVICOM Semiconductor, Inc. All Rights Reserved.
+    Jeff Garzik <jgarzik@mandrakesoft.com> :
+    Updated to use new PCI driver API.
+    Resource usage cleanups.
+    Report driver version to user.
 
-   Marcelo Tosatti <marcelo@conectiva.com.br> : 
-   Made it compile in 2.3 (device to net_device)
-   
-   Alan Cox <alan@redhat.com> :
-   Cleaned up for kernel merge.
-   Removed the back compatibility support
-   Reformatted, fixing spelling etc as I went
-   Removed IRQ 0-15 assumption
+    Tobias Ringstrom <tori@unhappy.mine.nu> :
+    Cleaned up and added SMP safety.  Thanks go to Jeff Garzik,
+	Andrew Morton and Frank Davis for the SMP safety fixes.
 
-   Jeff Garzik <jgarzik@mandrakesoft.com> :
-   Updated to use new PCI driver API.
-   Resource usage cleanups.
-   Report driver version to user.
+    TODO
 
-   Tobias Ringstr÷m <zajbot@goteborg.utfors.se> :
-   Added additional proper locking
-   Rewrote the transmit code to actually use the ring buffer,
-   and to generate a lot fewer interrupts.
+    Implement pci_driver::suspend() and pci_driver::resume()
+    power management methods.
 
-   Frank Davis <fdavis112@juno.com>
-   Added SMP-safe locking mechanisms in addition to Andrew Morton's work
+    Check and fix on 64bit and big endian boxes.
 
-   TODO
+    Test and make sure PCI latency is now correct for all cases.
+*/
 
-   Implement pci_driver::suspend() and pci_driver::resume()
-   power management methods.
-
-   Check and fix on 64bit and big endian boxes.
-
-   Test and make sure PCI latency is now correct for all cases.
-
- */
-
-#define DMFE_VERSION "1.30p3 (April 17, 2001)"
+#define DMFE_VERSION "1.36p1 (May 12, 2001)"
 
 #include <linux/module.h>
 
@@ -87,7 +61,7 @@
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -103,54 +77,58 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 
-static char version[] __initdata =
-KERN_INFO "Davicom DM91xx net driver, version " DMFE_VERSION "\n";
-
-
 
 /* Board/System/Debug information/definition ---------------- */
-#define PCI_DM9132_ID   0x91321282	/* Davicom DM9132 ID */
-#define PCI_DM9102_ID   0x91021282	/* Davicom DM9102 ID */
-#define PCI_DM9100_ID   0x91001282	/* Davicom DM9100 ID */
+#define PCI_DM9132_ID   0x91321282      /* Davicom DM9132 ID */
+#define PCI_DM9102_ID   0x91021282      /* Davicom DM9102 ID */
+#define PCI_DM9100_ID   0x91001282      /* Davicom DM9100 ID */
+#define PCI_DM9009_ID   0x90091282      /* Davicom DM9009 ID */
 
 #define DMFE_SUCC       0
 #define DM9102_IO_SIZE  0x80
 #define DM9102A_IO_SIZE 0x100
-#define TX_FREE_DESC_CNT 0xc	/* Tx packet count */
-#define TX_MAX_SEND_CNT 0x1	/* Maximum tx packet per time */
-#define TX_DESC_CNT     0x10	/* Allocated Tx descriptors */
-#define RX_DESC_CNT     0x10	/* Allocated Rx descriptors */
-#define TX_IRQ_THR      12
-#define DESC_ALL_CNT    TX_DESC_CNT+RX_DESC_CNT
+#define TX_MAX_SEND_CNT 0x1             /* Maximum tx packet per time */
+#define TX_DESC_CNT     0x10            /* Allocated Tx descriptors */
+#define RX_DESC_CNT     0x20            /* Allocated Rx descriptors */
+#define TX_FREE_DESC_CNT (TX_DESC_CNT - 2)	/* Max TX packet count */
+#define TX_WAKE_DESC_CNT (TX_DESC_CNT - 3)	/* TX wakeup count */
+#define DESC_ALL_CNT    (TX_DESC_CNT + RX_DESC_CNT)
 #define TX_BUF_ALLOC    0x600
 #define RX_ALLOC_SIZE   0x620
 #define DM910X_RESET    1
-#define CR6_DEFAULT     0x00280000	/* SF, HD */
-#define CR7_DEFAULT     0x1a2cd
-#define CR15_DEFAULT    0x06	/* TxJabber RxWatchdog */
-#define TDES0_ERR_MASK  0x4302	/* TXJT, LC, EC, FUE */
+#define CR0_DEFAULT     0x00E00000      /* TX & RX burst mode */
+#define CR6_DEFAULT     0x00080000      /* HD */
+#define CR7_DEFAULT     0x180c1
+#define CR15_DEFAULT    0x06            /* TxJabber RxWatchdog */
+#define TDES0_ERR_MASK  0x4302          /* TXJT, LC, EC, FUE */
 #define MAX_PACKET_SIZE 1514
 #define DMFE_MAX_MULTICAST 14
-#define RX_MAX_TRAFFIC  0x14000
+#define RX_COPY_SIZE	100
 #define MAX_CHECK_PACKET 0x8000
+#define DM9801_NOISE_FLOOR 8
+#define DM9802_NOISE_FLOOR 5
 
 #define DMFE_10MHF      0
 #define DMFE_100MHF     1
 #define DMFE_10MFD      4
 #define DMFE_100MFD     5
 #define DMFE_AUTO       8
+#define DMFE_1M_HPNA    0x10
+
+#define DMFE_TXTH_72	0x400000	/* TX TH 72 byte */
+#define DMFE_TXTH_96	0x404000	/* TX TH 96 byte */
+#define DMFE_TXTH_128	0x0000		/* TX TH 128 byte */
+#define DMFE_TXTH_256	0x4000		/* TX TH 256 byte */
+#define DMFE_TXTH_512	0x8000		/* TX TH 512 byte */
+#define DMFE_TXTH_1K	0xC000		/* TX TH 1K  byte */
+
+#define DMFE_TIMER_WUT  (jiffies + HZ * 1)/* timer wakeup time : 1 second */
+#define DMFE_TX_TIMEOUT (HZ * 1.5)	/* tx packet time-out time 1.5 s" */
+#define DMFE_TX_KICK 	(HZ * 0.5)	/* tx packet Kick-out time 0.5 s" */
 
-#define DMFE_TIMER_WUT  (HZ)	/* timer wakeup time : 1 second */
-#define DMFE_TX_TIMEOUT ((HZ*3)/2)	/* tx packet time-out time 1.5 s" */
+#define DMFE_DBUG(dbug_now, msg, vaule) if (dmfe_debug || dbug_now) printk(KERN_ERR "<DMFE>: %s %x\n", msg, vaule)
 
-#define DMFE_DBUG(dbug_now, msg, value)	\
-	if (dmfe_debug || dbug_now)	\
-		printk("DBUG: %s %x\n", msg, value)
-
-#define SHOW_MEDIA_TYPE(mode) \
- 	printk(KERN_WARNING "dmfe: Change Speed to %sMhz %s duplex\n",	\
-	       mode & 1 ? "100" : "10",					\
-	       mode & 4 ? "full":"half");
+#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR "<DMFE>: Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
 
 
 /* CR9 definition: SROM/MII */
@@ -164,20 +142,17 @@
 #define PHY_DATA_0      0x00000
 #define MDCLKH          0x10000
 
-#define SROM_CLK_WRITE(data, ioaddr) \
-	outl(data | CR9_SROM_READ | CR9_SRCS , ioaddr);			\
-	udelay(5);							\
-	outl(data | CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, ioaddr);	\
-	udelay(5);							\
-	outl(data | CR9_SROM_READ | CR9_SRCS , ioaddr);			\
-	udelay(5);
+#define PHY_POWER_DOWN	0x800
 
-#define __CHK_IO_SIZE(pci_id, dev_rev) \
-	( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? \
-		DM9102A_IO_SIZE : DM9102_IO_SIZE
-#define CHK_IO_SIZE(pci_dev, dev_rev) \
-	__CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev)
+#define SROM_V41_CODE   0x14
 
+#define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);
+
+#define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE
+#define CHK_IO_SIZE(pci_dev, dev_rev) __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev)
+
+/* Sten Check */
+#define DEVICE net_device
 
 /* Structure/enum declaration ------------------------------- */
 struct tx_desc {
@@ -197,19 +172,26 @@
 };
 
 struct dmfe_board_info {
-	u32 chip_id;		/* Chip vendor/Device ID */
-	u32 chip_revision;	/* Chip revision */
-	struct net_device *next_dev;	/* next device */
-	spinlock_t lock; /* Spinlock */
-	struct pci_dev *net_dev;	/* PCI device */
+	u32 chip_id;			/* Chip vendor/Device ID */
+	u32 chip_revision;		/* Chip revision */
+	struct DEVICE *next_dev;	/* next device */
+	struct pci_dev * net_dev;	/* PCI device */
+	spinlock_t lock;
 
-	unsigned long ioaddr;		/* I/O base address */
+	u32 ioaddr;			/* I/O base address */
 	u32 cr0_data;
 	u32 cr5_data;
 	u32 cr6_data;
 	u32 cr7_data;
 	u32 cr15_data;
-	
+
+	/* pointer for memory physical address */
+	dma_addr_t buf_pool_dma_ptr;	/* Tx buffer pool memory */
+	dma_addr_t buf_pool_dma_start;	/* Tx buffer pool align dword */
+	dma_addr_t desc_pool_dma_ptr;	/* descriptor pool memory */
+	dma_addr_t first_tx_desc_dma;
+	dma_addr_t first_rx_desc_dma;
+
 	/* descriptor pointer */
 	unsigned char *buf_pool_ptr;	/* Tx buffer pool memory */
 	unsigned char *buf_pool_start;	/* Tx buffer pool align dword */
@@ -220,52 +202,82 @@
 	struct rx_desc *first_rx_desc;
 	struct rx_desc *rx_insert_ptr;
 	struct rx_desc *rx_ready_ptr;	/* packet come pointer */
-	int tx_int_pkt_num;	/* number of packets to transmit until
-				 * a transmit interrupt is requested */
-	u32 tx_live_cnt;	/* number of used/live tx slots */
-	u32 rx_avail_cnt;	/* available rx descriptor count */
-	u32 interval_rx_cnt;	/* rx packet count a callback time */
-
-	u16 phy_id2;		/* Phyxcer ID2 */
-
-	u8 media_mode;		/* user specify media mode */
-	u8 op_mode;		/* real work media mode */
+	u32 tx_packet_cnt;		/* transmitted packet count */
+	u32 tx_queue_cnt;		/* wait to send packet count */
+	u32 rx_avail_cnt;		/* available rx descriptor count */
+	u32 interval_rx_cnt;		/* rx packet count a callback time */
+
+	u16 HPNA_command;		/* For HPNA register 16 */
+	u16 HPNA_timer;			/* For HPNA remote device check */
+	u16 dbug_cnt;
+	u16 NIC_capability;		/* NIC media capability */
+	u16 PHY_reg4;			/* Saved Phyxcer register 4 value */
+
+	u8 HPNA_present;		/* 0:none, 1:DM9801, 2:DM9802 */
+	u8 chip_type;			/* Keep DM9102A chip type */
+	u8 media_mode;			/* user specify media mode */
+	u8 op_mode;			/* real work media mode */
 	u8 phy_addr;
-	u8 link_failed;		/* Ever link failed */
-	u8 wait_reset;		/* Hardware failed, need to reset */
-	u8 in_reset_state;	/* Now driver in reset routine */
-	u8 rx_error_cnt;	/* recieved abnormal case count */
-	u8 dm910x_chk_mode;	/* Operating mode check */
+	u8 link_failed;			/* Ever link failed */
+	u8 wait_reset;			/* Hardware failed, need to reset */
+	u8 dm910x_chk_mode;		/* Operating mode check */
+	u8 first_in_callback;		/* Flag to record state */
 	struct timer_list timer;
-	struct net_device_stats stats;	/* statistic counter */
+
+	/* System defined statistic counter */
+	struct net_device_stats stats;
+
+	/* Driver defined statistic counter */
+	unsigned long tx_fifo_underrun;
+	unsigned long tx_loss_carrier;
+	unsigned long tx_no_carrier;
+	unsigned long tx_late_collision;
+	unsigned long tx_excessive_collision;
+	unsigned long tx_jabber_timeout;
+	unsigned long reset_count;
+	unsigned long reset_cr8;
+	unsigned long reset_fatal;
+	unsigned long reset_TXtimeout;
+
+	/* NIC SROM data */
 	unsigned char srom[128];
 };
 
 enum dmfe_offsets {
-	DCR0 = 0, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20, DCR5 = 0x28,
-	DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48, DCR10 = 0x50, DCR11 = 0x58,
-	DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70, DCR15 = 0x78
+	DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20,
+	DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48,
+	DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70,
+	DCR15 = 0x78
 };
 
 enum dmfe_CR6_bits {
-	CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80, CR6_FDM = 0x200,
-	CR6_TXSC = 0x2000, CR6_STI = 0x100000, CR6_SFT = 0x200000, CR6_RXA = 0x40000000,
-	CR6_NO_PURGE = 0x20000000
+	CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80,
+	CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000,
+	CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000
 };
 
 /* Global variable declaration ----------------------------- */
-static int dmfe_debug;
-static unsigned char dmfe_media_mode = 8;
-static u32 dmfe_cr6_user_set;
+static int __devinitdata printed_version;
+static char version[] __devinitdata =
+	KERN_INFO "Davicom DM9xxx net driver, version " DMFE_VERSION "\n";
+
+static int dmfe_debug = 0;
+static unsigned char dmfe_media_mode = DMFE_AUTO;
+static u32 dmfe_cr6_user_set = 0;
 
 /* For module input parameter */
-static int debug;
-static u32 cr6set;
+static int debug = 0;
+static u32 cr6set = 0;
 static unsigned char mode = 8;
 static u8 chkmode = 1;
+static u8 HPNA_mode = 0;	/* Default: Low Power/High Speed */
+static u8 HPNA_rx_cmd = 0;	/* Default: Disable Rx remote command */
+static u8 HPNA_tx_cmd = 0;	/* Default: Don't issue remote command */
+static u8 HPNA_NoiseFloor = 0;	/* Default: HPNA NoiseFloor */
+static u8 SF_mode = 0;		/* Special Function: 1:VLAN, 2:RX Flow Control
+				   4: TX pause packet */
 
-static unsigned long CrcTable[256] =
-{
+unsigned long CrcTable[256] = {
 	0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
 	0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
 	0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
@@ -333,83 +345,73 @@
 };
 
 /* function declaration ------------------------------------- */
-static int dmfe_open(struct net_device *);
-static int dmfe_start_xmit(struct sk_buff *, struct net_device *);
-static int dmfe_stop(struct net_device *);
-static struct net_device_stats *dmfe_get_stats(struct net_device *);
-static void dmfe_set_filter_mode(struct net_device *);
-static int dmfe_do_ioctl(struct net_device *, struct ifreq *, int);
-static u16 read_srom_word(long, int);
-static void dmfe_interrupt(int, void *, struct pt_regs *);
+static int dmfe_open(struct DEVICE *);
+static int dmfe_start_xmit(struct sk_buff *, struct DEVICE *);
+static int dmfe_stop(struct DEVICE *);
+static struct net_device_stats * dmfe_get_stats(struct DEVICE *);
+static void dmfe_set_filter_mode(struct DEVICE *);
+static int dmfe_do_ioctl(struct DEVICE *, struct ifreq *, int);
+static u16 read_srom_word(long ,int);
+static void dmfe_interrupt(int , void *, struct pt_regs *);
 static void dmfe_descriptor_init(struct dmfe_board_info *, u32);
 static void allocated_rx_buffer(struct dmfe_board_info *);
 static void update_cr6(u32, u32);
-static void send_filter_frame(struct net_device *, int);
-static void dm9132_id_table(struct net_device *, int);
+static void send_filter_frame(struct DEVICE * ,int);
+static void dm9132_id_table(struct DEVICE * ,int);
 static u16 phy_read(u32, u8, u8, u32);
 static void phy_write(u32, u8, u8, u16, u32);
 static void phy_write_1bit(u32, u32);
 static u16 phy_read_1bit(u32);
-static void dmfe_sense_speed(struct dmfe_board_info *);
+static u8 dmfe_sense_speed(struct dmfe_board_info *);
 static void dmfe_process_mode(struct dmfe_board_info *);
 static void dmfe_timer(unsigned long);
-static void dmfe_rx_packet(struct net_device *, struct dmfe_board_info *);
+static void dmfe_rx_packet(struct DEVICE *, struct dmfe_board_info *);
+static void dmfe_free_tx_pkt(struct DEVICE *, struct dmfe_board_info *);
 static void dmfe_reused_skb(struct dmfe_board_info *, struct sk_buff *);
-static void dmfe_dynamic_reset(struct net_device *);
+static void dmfe_dynamic_reset(struct DEVICE *);
 static void dmfe_free_rxbuffer(struct dmfe_board_info *);
-static void dmfe_init_dm910x(struct net_device *);
+static void dmfe_init_dm910x(struct DEVICE *);
 static unsigned long cal_CRC(unsigned char *, unsigned int, u8);
+static void dmfe_parse_srom(struct dmfe_board_info *);
+static void dmfe_program_DM9801(struct dmfe_board_info *, int);
+static void dmfe_program_DM9802(struct dmfe_board_info *);
+static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * );
+static void dmfe_set_phyxcer(struct dmfe_board_info *);
 
-/* DM910X network board routine ---------------------------- */
+/* DM910X network baord routine ---------------------------- */
 
 /*
- *	Search DM910X board, allocate space and register it
+ *	Search DM910X board ,allocate space and register it
  */
- 
 
-static int __init dmfe_init_one (struct pci_dev *pdev,
-				 const struct pci_device_id *ent)
+static int __devinit dmfe_init_one (struct pci_dev *pdev,
+				    const struct pci_device_id *ent)
 {
 	unsigned long pci_iobase;
 	u8 pci_irqline;
-	struct dmfe_board_info *db;	/* Point a board information structure */
+	struct dmfe_board_info *db;	/* board information structure */
 	int i;
 	struct net_device *dev;
-	u32 dev_rev;
-	u16 pci_command;
+	u32 dev_rev, pci_pmr;
 
-/* when built into the kernel, we only print version if device is found */
-#ifndef MODULE
-	static int printed_version;
 	if (!printed_version++)
 		printk(version);
-#endif
 
-	DMFE_DBUG(0, "dmfe_probe()", 0);
+	DMFE_DBUG(0, "dmfe_init_one()", 0);
 
 	/* Enable Master/IO access, Disable memory access */
 	i = pci_enable_device(pdev);
-	if (i) return i;
-
+	if (i)
+		return i;
 	pci_set_master(pdev);
-	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-	pci_command &= ~PCI_COMMAND_MEMORY;
-	pci_write_config_word(pdev, PCI_COMMAND, pci_command);
 
 	pci_iobase = pci_resource_start(pdev, 0);
 	pci_irqline = pdev->irq;
 
-	/* Interrupt check */
-	if (pci_irqline == 0) {
-		printk(KERN_ERR "dmfe(%s): Interrupt wrong : IRQ=%d\n",
-		       pdev->slot_name, pci_irqline);
-		goto err_out;
-	}
-
 	/* iobase check */
-	if (pci_iobase == 0 || pci_resource_len(pdev, 0) == 0) {
-		printk(KERN_ERR "dmfe(%s): I/O base is zero\n", pdev->slot_name);
-		goto err_out;
+	if (pci_iobase == 0) {
+		printk(KERN_ERR "<DMFE>: I/O base is zero\n");
+		return -ENODEV;
 	}
 
 #if 0	/* pci_{enable_device,set_master} sets minimum latency for us now */
@@ -427,15 +429,36 @@
 	/* Init network device */
 	dev = alloc_etherdev(sizeof(*db));
 	if (dev == NULL)
-		goto err_out;
+		return -ENOMEM;
 	SET_MODULE_OWNER(dev);
 
-	if (pci_request_regions(pdev, "dmfe"))
-		goto err_out_netdev;
+	/* IO range check */
+	if (pci_resource_len (pdev, 0) < (CHK_IO_SIZE(pdev, dev_rev)) ) {
+		printk(KERN_ERR "<DMFE>: Allocated I/O size too small\n");
+		goto err_out;
+	}
 
+	if (!request_region(pci_iobase,
+			    pci_resource_len (pdev, 0),
+			    dev->name)) {
+		printk(KERN_ERR "<DMFE>: I/O conflict : IO=%lx Range=%x\n",
+		       pci_iobase, CHK_IO_SIZE(pdev, dev_rev));
+		goto err_out;
+	}
+
+	/* Init system & device */
 	db = dev->priv;
-	pci_set_drvdata(pdev, dev);
-	spin_lock_init(&db->lock);
+
+	/* Allocated Tx/Rx descriptor memory */
+	db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr);
+	db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, &db->buf_pool_dma_ptr);
+
+	db->first_tx_desc = (struct tx_desc *)db->desc_pool_ptr;
+	db->first_tx_desc_dma = db->desc_pool_dma_ptr;
+	db->buf_pool_start = db->buf_pool_ptr;
+	db->buf_pool_dma_start = db->buf_pool_dma_ptr;
+
+	pdev->driver_data = dev;
 
 	db->chip_id = ent->driver_data;
 	db->ioaddr = pci_iobase;
@@ -445,12 +468,21 @@
 
 	dev->base_addr = pci_iobase;
 	dev->irq = pci_irqline;
+	pci_set_drvdata(pdev, dev);
 	dev->open = &dmfe_open;
 	dev->hard_start_xmit = &dmfe_start_xmit;
 	dev->stop = &dmfe_stop;
 	dev->get_stats = &dmfe_get_stats;
 	dev->set_multicast_list = &dmfe_set_filter_mode;
 	dev->do_ioctl = &dmfe_do_ioctl;
+	spin_lock_init(&db->lock);
+
+	pci_read_config_dword(pdev, 0x50, &pci_pmr);
+	pci_pmr &= 0x70000;
+	if ( (pci_pmr == 0x10000) && (dev_rev == 0x02000031) )
+		db->chip_type = 1;	/* DM9102A E3 */
+	else
+		db->chip_type = 0;
 
 	/* read 64 word srom data */
 	for (i = 0; i < 64; i++)
@@ -460,9 +492,8 @@
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = db->srom[20 + i];
 
-	i = register_netdev(dev);
-	if (i)
-		goto err_out_res;
+	i = register_netdev (dev);
+	if (i) goto err_out;
 
 	printk(KERN_INFO "%s: Davicom DM%04lx at 0x%lx,",
 	       dev->name,
@@ -474,11 +505,9 @@
 
 	return 0;
 
-err_out_res:
-	pci_release_regions(pdev);
-err_out_netdev:
-	kfree(dev);
 err_out:
+	pci_set_drvdata(pdev, NULL);
+	kfree(dev);
 	return -ENODEV;
 }
 
@@ -486,17 +515,22 @@
 static void __exit dmfe_remove_one (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct dmfe_board_info *db;
+	struct dmfe_board_info *db = dev->priv;
 
 	DMFE_DBUG(0, "dmfe_remove_one()", 0);
-	
-	db = dev->priv;
-
-	unregister_netdev(dev);
-	pci_release_regions(pdev);
-	kfree(dev);	/* free board information */
 
-	pci_set_drvdata(pdev, NULL);
+ 	if (dev) {
+		pci_free_consistent(db->net_dev, sizeof(struct tx_desc) *
+					DESC_ALL_CNT + 0x20, db->desc_pool_ptr,
+ 					db->desc_pool_dma_ptr);
+		pci_free_consistent(db->net_dev, TX_BUF_ALLOC * TX_DESC_CNT + 4,
+					db->buf_pool_ptr, db->buf_pool_dma_ptr);
+		unregister_netdev(dev);
+		release_region(dev->base_addr,
+				CHK_IO_SIZE(pdev, db->chip_revision));
+		kfree(dev);	/* free board information */
+		pci_set_drvdata(pdev, NULL);
+	}
 
 	DMFE_DBUG(0, "dmfe_remove_one() exit", 0);
 }
@@ -506,107 +540,103 @@
  *	Open the interface.
  *	The interface is opened whenever "ifconfig" actives it.
  */
- 
-static int dmfe_open(struct net_device *dev)
+
+static int dmfe_open(struct DEVICE *dev)
 {
 	int ret;
 	struct dmfe_board_info *db = dev->priv;
 
 	DMFE_DBUG(0, "dmfe_open", 0);
 
-	ret = request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev);
+	ret =  request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev);
 	if (ret)
 		return ret;
 
-	/* Allocated Tx/Rx descriptor memory */
-	db->desc_pool_ptr = kmalloc(sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, GFP_KERNEL | GFP_DMA);
-	if (db->desc_pool_ptr == NULL)
-		return -ENOMEM;
-	if ((u32) db->desc_pool_ptr & 0x1f)
-		db->first_tx_desc = (struct tx_desc *) (((u32) db->desc_pool_ptr & ~0x1f) + 0x20);
-	else
-		db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
-
-	/* Allocated Tx buffer memory */
-	db->buf_pool_ptr = kmalloc(TX_BUF_ALLOC * TX_DESC_CNT + 4, GFP_KERNEL | GFP_DMA);
-	if (db->buf_pool_ptr == NULL) {
-		kfree(db->desc_pool_ptr);
-		return -ENOMEM;
-	}
-	if ((u32) db->buf_pool_ptr & 0x3)
-		db->buf_pool_start = (char *) (((u32) db->buf_pool_ptr & ~0x3) + 0x4);
-	else
-		db->buf_pool_start = db->buf_pool_ptr;
-
 	/* system variable init */
 	db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set;
-	db->tx_int_pkt_num = TX_IRQ_THR;
-	db->tx_live_cnt = 0;
+	db->tx_packet_cnt = 0;
+	db->tx_queue_cnt = 0;
 	db->rx_avail_cnt = 0;
-	db->link_failed = 0;
+	db->link_failed = 1;
 	db->wait_reset = 0;
-	db->in_reset_state = 0;
-	db->rx_error_cnt = 0;
 
-	if (!chkmode || (db->chip_id == PCI_DM9132_ID) || (db->chip_revision >= 0x02000030)) {
-		//db->cr6_data &= ~CR6_SFT;         /* Used Tx threshold */
-		//db->cr6_data |= CR6_NO_PURGE;     /* No purge if rx unavailable */
-		db->cr0_data = 0xc00000;	/* TX/RX desc burst mode */
-		db->dm910x_chk_mode = 4;	/* Enter the normal mode */
-	} else {
+	db->first_in_callback = 0;
+	db->NIC_capability = 0xf;	/* All capability*/
+	db->PHY_reg4 = 0x1e0;
+
+	/* CR6 operation mode decision */
+	if ( !chkmode || (db->chip_id == PCI_DM9132_ID) ||
+		(db->chip_revision >= 0x02000030) ) {
+    		db->cr6_data |= DMFE_TXTH_256;
+		db->cr0_data = CR0_DEFAULT;
+		db->dm910x_chk_mode=4;		/* Enter the normal mode */
+ 	} else {
+		db->cr6_data |= CR6_SFT;	/* Store & Forward mode */
 		db->cr0_data = 0;
 		db->dm910x_chk_mode = 1;	/* Enter the check mode */
 	}
 
-	/* Initialize DM910X board */
+	/* Initilize DM910X board */
 	dmfe_init_dm910x(dev);
 
+	/* Active System Interface */
+	netif_wake_queue(dev);
+
 	/* set and active a timer process */
 	init_timer(&db->timer);
-	db->timer.expires = jiffies + DMFE_TIMER_WUT;
-	db->timer.data = (unsigned long) dev;
+	db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
+	db->timer.data = (unsigned long)dev;
 	db->timer.function = &dmfe_timer;
 	add_timer(&db->timer);
-	
-	netif_wake_queue(dev);
 
 	return 0;
 }
 
-/* Initialize DM910X board
-   Reset DM910X board
-   Initialize TX/Rx descriptor chain structure
-   Send the set-up frame
-   Enable Tx/Rx machine
+
+/*	Initilize DM910X board
+ *	Reset DM910X board
+ *	Initilize TX/Rx descriptor chain structure
+ *	Send the set-up frame
+ *	Enable Tx/Rx machine
  */
-static void dmfe_init_dm910x(struct net_device *dev)
+
+static void dmfe_init_dm910x(struct DEVICE *dev)
 {
 	struct dmfe_board_info *db = dev->priv;
 	u32 ioaddr = db->ioaddr;
-	
+
 	DMFE_DBUG(0, "dmfe_init_dm910x()", 0);
 
-	/* Reset DM910x board : need 32 PCI clock to complete */
+	/* Reset DM910x MAC controller */
 	outl(DM910X_RESET, ioaddr + DCR0);	/* RESET MAC */
-	udelay(5);
+	udelay(100);
 	outl(db->cr0_data, ioaddr + DCR0);
-
-	outl(0x180, ioaddr + DCR12);	/* Let bit 7 output port */
-	outl(0x80, ioaddr + DCR12);	/* RESET DM9102 phyxcer */
-	outl(0x0, ioaddr + DCR12);	/* Clear RESET signal */
+	udelay(5);
 
 	/* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
 	db->phy_addr = 1;
 
-	/* Media Mode Check */
+	/* Parser SROM and media mode */
+	dmfe_parse_srom(db);
 	db->media_mode = dmfe_media_mode;
-	if (db->media_mode & DMFE_AUTO)
-		dmfe_sense_speed(db);
-	else
-		db->op_mode = db->media_mode;
-	dmfe_process_mode(db);
 
-	/* Initialize Transmit/Receive decriptor and CR3/4 */
+	/* RESET Phyxcer Chip by GPR port bit 7 */
+	outl(0x180, ioaddr + DCR12);		/* Let bit 7 output port */
+	if (db->chip_id == PCI_DM9009_ID) {
+		outl(0x80, ioaddr + DCR12);	/* Issue RESET signal */
+		mdelay(300);			/* Delay 300 ms */
+	}
+	outl(0x0, ioaddr + DCR12);	/* Clear RESET signal */
+
+	/* Process Phyxcer Media Mode */
+	if ( !(db->media_mode & 0x10) )	/* Force 1M mode */
+		dmfe_set_phyxcer(db);
+
+	/* Media Mode Process */
+	if ( !(db->media_mode & DMFE_AUTO) )
+		db->op_mode = db->media_mode; 	/* Force Mode */
+
+	/* Initiliaze Transmit/Receive decriptor and CR3/4 */
 	dmfe_descriptor_init(db, ioaddr);
 
 	/* Init CR6 to program DM910x operation */
@@ -618,182 +648,184 @@
 	else
 		send_filter_frame(dev, dev->mc_count);	/* DM9102/DM9102A */
 
-	/* Init CR5/CR7, interrupt active bit */
-	outl(0xffffffff, ioaddr + DCR5);	/* clear all CR5 status */
+	/* Init CR7, interrupt active bit */
 	db->cr7_data = CR7_DEFAULT;
 	outl(db->cr7_data, ioaddr + DCR7);
 
 	/* Init CR15, Tx jabber and Rx watchdog timer */
-	db->cr15_data = CR15_DEFAULT;
 	outl(db->cr15_data, ioaddr + DCR15);
 
 	/* Enable DM910X Tx/Rx function */
-	db->cr6_data |= CR6_RXSC | CR6_TXSC;
+	db->cr6_data |= CR6_RXSC | CR6_TXSC | 0x40000;
 	update_cr6(db->cr6_data, ioaddr);
-
 }
 
 
 /*
-   Hardware start transmission.
-   Send a packet to media from the upper layer.
+ *	Hardware start transmission.
+ *	Send a packet to media from the upper layer.
  */
-static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev)
+
+static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
 {
 	struct dmfe_board_info *db = dev->priv;
 	struct tx_desc *txptr;
 	unsigned long flags;
 
 	DMFE_DBUG(0, "dmfe_start_xmit", 0);
+
+	/* Resource flag check */
+	netif_stop_queue(dev);
+
+	/* Too large packet check */
+	if (skb->len > MAX_PACKET_SIZE) {
+		printk(KERN_ERR "<DMFE>: big packet = %d\n", (u16)skb->len);
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
 	spin_lock_irqsave(&db->lock, flags);
-	
-	/* transmit this packet */
-	txptr = db->tx_insert_ptr;
-	memcpy((char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len);
-	if (--db->tx_int_pkt_num < 0)
-	{
-		txptr->tdes1 = 0xe1000000 | skb->len;
-		db->tx_int_pkt_num = TX_IRQ_THR;
+
+	/* No Tx resource check, it never happen nromally */
+	if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
+		spin_unlock_irqrestore(&db->lock, flags);
+		printk(KERN_ERR "<DMFE>: No Tx resource %d\n", db->tx_queue_cnt);
+		return 1;
 	}
-	else
-		txptr->tdes1 = 0x61000000 | skb->len;
 
-	/* Transmit Packet Process */
-	txptr->tdes0 = 0x80000000;	/* set owner bit to DM910X */
-	outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling command */
-	dev->trans_start = jiffies;     /* saved the time stamp */
+	/* Disable NIC interrupt */
+	outl(0, dev->base_addr + DCR7);
 
-	/* Point to next transmit free descriptor */
-	txptr = (struct tx_desc *)txptr->next_tx_desc;
+	/* transmit this packet */
+	txptr = db->tx_insert_ptr;
+	memcpy( (char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len);
+	txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len);
 
-	if (txptr->tdes0 & 0x80000000)
-		netif_stop_queue(dev);
+	/* Point to next transmit free descriptor */
+	db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;
 
-	db->tx_insert_ptr = txptr;
-	db->tx_live_cnt++;
+	/* Transmit Packet Process */
+	if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) ) {
+		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
+		db->tx_packet_cnt++;			/* Ready to send */
+		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */
+		dev->trans_start = jiffies;		/* saved time stamp */
+	} else {
+		db->tx_queue_cnt++;			/* queue TX packet */
+		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */
+	}
 
-	spin_unlock_irqrestore(&db->lock, flags);
+	/* Tx resource check */
+	if ( db->tx_queue_cnt < TX_FREE_DESC_CNT )
+		netif_wake_queue(dev);
 
 	/* free this SKB */
 	dev_kfree_skb(skb);
 
+	/* Restore CR7 to enable interrupt */
+	spin_unlock_irqrestore(&db->lock, flags);
+	outl(db->cr7_data, dev->base_addr + DCR7);
+
 	return 0;
 }
 
+
 /*
  *	Stop the interface.
  *	The interface is stopped when it is brought.
  */
 
-static int dmfe_stop(struct net_device *dev)
+static int dmfe_stop(struct DEVICE *dev)
 {
 	struct dmfe_board_info *db = dev->priv;
 	u32 ioaddr = dev->base_addr;
 
 	DMFE_DBUG(0, "dmfe_stop", 0);
 
+	/* disable system */
 	netif_stop_queue(dev);
 
+	/* deleted timer */
+	del_timer_sync(&db->timer);
+
 	/* Reset & stop DM910X board */
 	outl(DM910X_RESET, ioaddr + DCR0);
 	udelay(5);
+	phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
 
-	/* deleted timer */
-	del_timer_sync(&db->timer);
-	
 	/* free interrupt */
 	free_irq(dev->irq, dev);
 
 	/* free allocated rx buffer */
 	dmfe_free_rxbuffer(db);
 
-	/* free all descriptor memory and buffer memory */
-	kfree(db->desc_pool_ptr);
-	kfree(db->buf_pool_ptr);
+#if 0
+	/* show statistic counter */
+	printk("<DMFE>: FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
+		db->tx_fifo_underrun, db->tx_excessive_collision,
+		db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
+		db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
+		db->reset_fatal, db->reset_TXtimeout);
+#endif
 
 	return 0;
 }
 
+
 /*
-   DM9102 interrupt handler
-   receive the packet to upper layer, free the transmitted packet
+ *	DM9102 insterrupt handler
+ *	receive the packet to upper layer, free the transmitted packet
  */
 
 static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	struct net_device *dev = dev_id;
-	struct tx_desc *txptr;
-	struct dmfe_board_info *db;
-	u32 ioaddr;
+	struct DEVICE *dev = dev_id;
+	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
+	u32 ioaddr = dev->base_addr;
 	unsigned long flags;
 
+	DMFE_DBUG(0, "dmfe_interrupt()", 0);
+
 	if (!dev) {
-		DMFE_DBUG(1, "dmfe_interrupt() without device arg", 0);
+		DMFE_DBUG(1, "dmfe_interrupt() without DEVICE arg", 0);
 		return;
 	}
-	/* A real interrupt coming */
-	db = (struct dmfe_board_info *) dev->priv;
-	ioaddr = dev->base_addr;
-
-	DMFE_DBUG(0, "dmfe_interrupt()", 0);
 
 	spin_lock_irqsave(&db->lock, flags);
 
-	/* Disable all interrupt in CR7 to solve the interrupt edge problem */
-	outl(0, ioaddr + DCR7);
-
 	/* Got DM910X status */
 	db->cr5_data = inl(ioaddr + DCR5);
 	outl(db->cr5_data, ioaddr + DCR5);
-	/* printk("CR5=%x\n", db->cr5_data); */
+	if ( !(db->cr5_data & 0xc1) ) {
+		spin_unlock_irqrestore(&db->lock, flags);
+		return;
+	}
+
+	/* Disable all interrupt in CR7 to solve the interrupt edge problem */
+	outl(0, ioaddr + DCR7);
 
 	/* Check system status */
 	if (db->cr5_data & 0x2000) {
-		/* A system bus error occurred */
-		DMFE_DBUG(1, "A system bus error occurred. CR5=", db->cr5_data);
-		netif_stop_queue(dev);
-		db->wait_reset = 1;		/* Need to RESET */
-		outl(0, ioaddr + DCR7);		/* disable all interrupt */
+		/* system bus error happen */
+		DMFE_DBUG(1, "System bus error happen. CR5=", db->cr5_data);
+		db->reset_fatal++;
+		db->wait_reset = 1;	/* Need to RESET */
 		spin_unlock_irqrestore(&db->lock, flags);
 		return;
 	}
 
-	/* Free the transmitted descriptor */
-	txptr = db->tx_remove_ptr;
-	while (db->tx_live_cnt > 0 && (txptr->tdes0 & 0x80000000) == 0)
-	{
-		/* printk("tdes0=%x\n", txptr->tdes0); */
-		db->stats.tx_packets++;
-		
-		if ((txptr->tdes0 & TDES0_ERR_MASK) && (txptr->tdes0 != 0x7fffffff)) {
-			/* printk("tdes0=%x\n", txptr->tdes0); */
-			db->stats.tx_errors++;
-		}
-		/* Transmit statistic counter */
-		if (txptr->tdes0 != 0x7fffffff) {
- 			/* printk("tdes0=%x\n", txptr->tdes0); */
- 			db->stats.collisions += (txptr->tdes0 >> 3) & 0xf;
-			db->stats.tx_bytes += txptr->tdes1 & 0x7ff;
-			if (txptr->tdes0 & TDES0_ERR_MASK)
-				db->stats.tx_errors++;
-		}
-		txptr = (struct tx_desc *) txptr->next_tx_desc;
-		db->tx_live_cnt--;
-	}
-	/* Update TX remove pointer to next */
-	db->tx_remove_ptr = (struct tx_desc *) txptr;
-
-	if ((db->tx_insert_ptr->tdes0 & 0x80000000) == 0)
-		netif_wake_queue(dev);
-
-	/* Received the coming packet */
-	if (db->rx_avail_cnt)
+	 /* Received the coming packet */
+	if ( (db->cr5_data & 0x40) && db->rx_avail_cnt )
 		dmfe_rx_packet(dev, db);
 
 	/* reallocated rx descriptor buffer */
-	if (db->rx_avail_cnt < RX_DESC_CNT)
+	if (db->rx_avail_cnt<RX_DESC_CNT)
 		allocated_rx_buffer(db);
 
+	/* Free the transmitted descriptor */
+	if ( db->cr5_data & 0x01)
+		dmfe_free_tx_pkt(dev, db);
+
 	/* Mode Check */
 	if (db->dm910x_chk_mode & 0x2) {
 		db->dm910x_chk_mode = 0x4;
@@ -802,19 +834,85 @@
 	}
 
 	/* Restore CR7 to enable interrupt mask */
-	if (db->interval_rx_cnt > RX_MAX_TRAFFIC)
-		db->cr7_data = 0x1a28d;
-	else
-		db->cr7_data = 0x1a2cd;
 	outl(db->cr7_data, ioaddr + DCR7);
 
 	spin_unlock_irqrestore(&db->lock, flags);
 }
 
+
 /*
-   Receive the come packet and pass to upper layer
+ *	Free TX resource after TX complete
  */
-static void dmfe_rx_packet(struct net_device *dev, struct dmfe_board_info *db)
+
+static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
+{
+	struct tx_desc *txptr;
+	u32 ioaddr = dev->base_addr;
+
+	txptr = db->tx_remove_ptr;
+	while(db->tx_packet_cnt) {
+		/* printk("<DMFE>: tdes0=%x\n", txptr->tdes0); */
+		if (txptr->tdes0 & 0x80000000)
+			break;
+
+		/* A packet sent completed */
+		db->tx_packet_cnt--;
+		db->stats.tx_packets++;
+
+		/* Transmit statistic counter */
+		if ( txptr->tdes0 != 0x7fffffff ) {
+			/* printk("<DMFE>: tdes0=%x\n", txptr->tdes0); */
+			db->stats.collisions += (txptr->tdes0 >> 3) & 0xf;
+			db->stats.tx_bytes += txptr->tdes1 & 0x7ff;
+			if (txptr->tdes0 & TDES0_ERR_MASK) {
+				db->stats.tx_errors++;
+
+				if (txptr->tdes0 & 0x0002) {	/* UnderRun */
+					db->tx_fifo_underrun++;
+					if ( !(db->cr6_data & CR6_SFT) ) {
+						db->cr6_data = db->cr6_data | CR6_SFT;
+						update_cr6(db->cr6_data, db->ioaddr);
+					}
+				}
+				if (txptr->tdes0 & 0x0100)
+					db->tx_excessive_collision++;
+				if (txptr->tdes0 & 0x0200)
+					db->tx_late_collision++;
+				if (txptr->tdes0 & 0x0400)
+					db->tx_no_carrier++;
+				if (txptr->tdes0 & 0x0800)
+					db->tx_loss_carrier++;
+				if (txptr->tdes0 & 0x4000)
+					db->tx_jabber_timeout++;
+			}
+		}
+
+    		txptr = (struct tx_desc *) txptr->next_tx_desc;
+	}/* End of while */
+
+	/* Update TX remove pointer to next */
+	db->tx_remove_ptr = (struct tx_desc *) txptr;
+
+	/* Send the Tx packet in queue */
+	if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) {
+		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
+		db->tx_packet_cnt++;			/* Ready to send */
+		db->tx_queue_cnt--;
+		outl(0x1, ioaddr + DCR1);		/* Issue Tx polling */
+		dev->trans_start = jiffies;		/* saved time stamp */
+	}
+
+	/* Resource available check */
+	if ( db->tx_queue_cnt < TX_WAKE_DESC_CNT )
+		netif_wake_queue(dev);	/* Active upper layer, send again */
+}
+
+
+/*
+ *	Receive the come packet and pass to upper layer
+ */
+
+static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
 {
 	struct rx_desc *rxptr;
 	struct sk_buff *skb;
@@ -822,26 +920,26 @@
 
 	rxptr = db->rx_ready_ptr;
 
-	while (db->rx_avail_cnt) {
+	while(db->rx_avail_cnt) {
 		if (rxptr->rdes0 & 0x80000000)	/* packet owner check */
 			break;
 
 		db->rx_avail_cnt--;
 		db->interval_rx_cnt++;
 
-		if ((rxptr->rdes0 & 0x300) != 0x300) {
+		if ( (rxptr->rdes0 & 0x300) != 0x300) {
 			/* A packet without First/Last flag */
 			/* reused this SKB */
 			DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0);
 			dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);
-			/* db->rx_error_cnt++; */
 		} else {
 			/* A packet with First/Last flag */
-			rxlen = ((rxptr->rdes0 >> 16) & 0x3fff) - 4;	/* skip CRC */
+			rxlen = ( (rxptr->rdes0 >> 16) & 0x3fff) - 4;
 
-			if (rxptr->rdes0 & 0x8000) {	/* error summary bit check */
+			/* error summary bit check */
+			if (rxptr->rdes0 & 0x8000) {
 				/* This is a error packet */
-				/* printk("rdes0 error : %x \n", rxptr->rdes0); */
+				//printk("<DMFE>: rdes0: %lx\n", rxptr->rdes0);
 				db->stats.rx_errors++;
 				if (rxptr->rdes0 & 1)
 					db->stats.rx_fifo_errors++;
@@ -850,21 +948,36 @@
 				if (rxptr->rdes0 & 0x80)
 					db->stats.rx_length_errors++;
 			}
-			if (!(rxptr->rdes0 & 0x8000) ||
-			    ((db->cr6_data & CR6_PM) && (rxlen > 6))) {
+
+			if ( !(rxptr->rdes0 & 0x8000) ||
+				((db->cr6_data & CR6_PM) && (rxlen>6)) ) {
 				skb = (struct sk_buff *) rxptr->rx_skb_ptr;
 
 				/* Received Packet CRC check need or not */
-				if ((db->dm910x_chk_mode & 1) && (cal_CRC(skb->tail, rxlen, 1) != (*(unsigned long *) (skb->tail + rxlen)))) {
+				if ( (db->dm910x_chk_mode & 1) &&
+					(cal_CRC(skb->tail, rxlen, 1) !=
+					(*(unsigned long *) (skb->tail+rxlen) )
+					) ) {
 					/* Found a error received packet */
 					dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);
 					db->dm910x_chk_mode = 3;
 				} else {
-					/* A good packet coming, send to upper layer */
-					skb->dev = dev;
-					skb_put(skb, rxlen);
+					/* Good packet, send to upper layer */
+					/* Shorst packet used new SKB */
+					if ( (rxlen < RX_COPY_SIZE) &&
+						( (skb = dev_alloc_skb(rxlen + 2) )
+						!= NULL) ) {
+						/* size less than COPY_SIZE, allocated a rxlen SKB */
+						skb->dev = dev;
+						skb_reserve(skb, 2); /* 16byte align */
+						memcpy(skb_put(skb, rxlen), ((struct sk_buff *) rxptr->rx_skb_ptr)->tail, rxlen);
+						dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);
+					} else {
+						skb->dev = dev;
+						skb_put(skb, rxlen);
+					}
 					skb->protocol = eth_type_trans(skb, dev);
-					netif_rx(skb);	/* Send to upper layer */
+					netif_rx(skb);
 					dev->last_rx = jiffies;
 					db->stats.rx_packets++;
 					db->stats.rx_bytes += rxlen;
@@ -880,24 +993,27 @@
 	}
 
 	db->rx_ready_ptr = rxptr;
-
 }
 
+
 /*
-   Get statistics from driver.
+ *	Get statistics from driver.
  */
-static struct net_device_stats *dmfe_get_stats(struct net_device *dev)
+
+static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev)
 {
-	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
+	struct dmfe_board_info *db = (struct dmfe_board_info *)dev->priv;
 
 	DMFE_DBUG(0, "dmfe_get_stats", 0);
 	return &db->stats;
 }
 
+
 /*
-   Set DM910X multicast address
+ * Set DM910X multicast address
  */
-static void dmfe_set_filter_mode(struct net_device *dev)
+
+static void dmfe_set_filter_mode(struct DEVICE * dev)
 {
 	struct dmfe_board_info *db = dev->priv;
 	unsigned long flags;
@@ -912,6 +1028,7 @@
 		spin_unlock_irqrestore(&db->lock, flags);
 		return;
 	}
+
 	if (dev->flags & IFF_ALLMULTI || dev->mc_count > DMFE_MAX_MULTICAST) {
 		DMFE_DBUG(0, "Pass all multicast address", dev->mc_count);
 		db->cr6_data &= ~(CR6_PM | CR6_PBF);
@@ -919,83 +1036,97 @@
 		spin_unlock_irqrestore(&db->lock, flags);
 		return;
 	}
+
 	DMFE_DBUG(0, "Set multicast address", dev->mc_count);
 	if (db->chip_id == PCI_DM9132_ID)
 		dm9132_id_table(dev, dev->mc_count);	/* DM9132 */
 	else
-		send_filter_frame(dev, dev->mc_count);	/* DM9102/DM9102A */
+		send_filter_frame(dev, dev->mc_count); 	/* DM9102/DM9102A */
 	spin_unlock_irqrestore(&db->lock, flags);
 }
 
-/*
-   Process the upper socket ioctl command
- */
 
-/* 
- * The following function just returns 0. Shouldn't it do more? 
+/*
+ *	Process the upper socket ioctl command
  */
 
-static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+static int dmfe_do_ioctl(struct DEVICE *dev, struct ifreq *ifr, int cmd)
 {
 	DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
 	return 0;
 }
 
+
 /*
-   A periodic timer routine
-   Dynamic media sense, allocated Rx buffer...
+ *	A periodic timer routine
+ *	Dynamic media sense, allocated Rx buffer...
  */
+
 static void dmfe_timer(unsigned long data)
 {
 	u32 tmp_cr8;
 	unsigned char tmp_cr12;
-	struct net_device *dev = (struct net_device *) data;
+	struct DEVICE *dev = (struct DEVICE *) data;
 	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
-	unsigned long flags;
+ 	unsigned long flags;
 
 	DMFE_DBUG(0, "dmfe_timer()", 0);
 	spin_lock_irqsave(&db->lock, flags);
 
-	/* Do reset now */
-	if (db->in_reset_state) {
-		spin_unlock_irqrestore(&db->lock, flags);
-		return;
+	/* Media mode process when Link OK before enter this route */
+	if (db->first_in_callback == 0) {
+		db->first_in_callback = 1;
+		if (db->chip_type && (db->chip_id==PCI_DM9102_ID)) {
+			db->cr6_data &= ~0x40000;
+			update_cr6(db->cr6_data, db->ioaddr);
+			phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
+			db->cr6_data |= 0x40000;
+			update_cr6(db->cr6_data, db->ioaddr);
+			db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
+			add_timer(&db->timer);
+			spin_unlock_irqrestore(&db->lock, flags);
+			return;
+		}
 	}
 
+
 	/* Operating Mode Check */
-	if ((db->dm910x_chk_mode & 0x1) && (db->stats.rx_packets > MAX_CHECK_PACKET)) {
+	if ( (db->dm910x_chk_mode & 0x1) &&
+		(db->stats.rx_packets > MAX_CHECK_PACKET) )
 		db->dm910x_chk_mode = 0x4;
-	}
+
 	/* Dynamic reset DM910X : system error or transmit time-out */
 	tmp_cr8 = inl(db->ioaddr + DCR8);
-	if ((db->interval_rx_cnt == 0) && (tmp_cr8)) {
+	if ( (db->interval_rx_cnt==0) && (tmp_cr8) ) {
+		db->reset_cr8++;
 		db->wait_reset = 1;
-		/* printk("CR8 %x, Interval Rx %x\n", tmp_cr8, db->interval_rx_cnt); */
 	}
-	/* Receiving Traffic check */
-	if (db->interval_rx_cnt > RX_MAX_TRAFFIC)
-		db->cr7_data = 0x1a28d;
-	else
-		db->cr7_data = 0x1a2cd;
-	outl(db->cr7_data, db->ioaddr + DCR7);
-
 	db->interval_rx_cnt = 0;
 
-	if (db->wait_reset ||
-	    (db->tx_live_cnt > 0 &&
-	     ((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT)) ||
-	    (db->rx_error_cnt > 3)) {
-		/*
-		   printk("wait_reset %x, tx cnt %x, rx err %x, time %x\n", db->wait_reset, db->tx_packet_cnt, db->rx_error_cnt, jiffies-dev->trans_start);
-		 */
-		DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx monitor step1", 0);
+	/* TX polling kick monitor */
+	if ( db->tx_packet_cnt &&
+		((jiffies - dev->trans_start) > DMFE_TX_KICK) ) {
+		outl(0x1, dev->base_addr + DCR1);   /* Tx polling again */
+
+		/* TX Timeout */
+		if ( (jiffies - dev->trans_start) > DMFE_TX_TIMEOUT ) {
+			db->reset_TXtimeout++;
+			db->wait_reset = 1;
+			printk(KERN_WARNING "%s: Tx timeout - resetting\n",
+			       dev->name);
+		}
+	}
+
+	if (db->wait_reset) {
+		DMFE_DBUG(0, "Dynamic Reset device", db->tx_packet_cnt);
+		db->reset_count++;
 		dmfe_dynamic_reset(dev);
-		db->timer.expires = jiffies + DMFE_TIMER_WUT;
+		db->first_in_callback = 0;
+		db->timer.expires = DMFE_TIMER_WUT;
 		add_timer(&db->timer);
 		spin_unlock_irqrestore(&db->lock, flags);
 		return;
 	}
-	db->rx_error_cnt = 0;	/* Clear previos counter */
 
 	/* Link status check, Dynamic media type change */
 	if (db->chip_id == PCI_DM9132_ID)
@@ -1003,138 +1134,150 @@
 	else
 		tmp_cr12 = inb(db->ioaddr + DCR12);	/* DM9102/DM9102A */
 
-	if (((db->chip_id == PCI_DM9102_ID) && (db->chip_revision == 0x02000030)) ||
-	    ((db->chip_id == PCI_DM9132_ID) && (db->chip_revision == 0x02000010))) {
+	if ( ((db->chip_id == PCI_DM9102_ID) &&
+		(db->chip_revision == 0x02000030)) ||
+		((db->chip_id == PCI_DM9132_ID) &&
+		(db->chip_revision == 0x02000010)) ) {
 		/* DM9102A Chip */
 		if (tmp_cr12 & 2)
 			tmp_cr12 = 0x0;		/* Link failed */
 		else
-			tmp_cr12 = 0x3;		/* Link OK */
+			tmp_cr12 = 0x3;	/* Link OK */
 	}
-	if (!(tmp_cr12 & 0x3) && !db->link_failed) {
+
+	if ( !(tmp_cr12 & 0x3) && !db->link_failed ) {
 		/* Link Failed */
 		DMFE_DBUG(0, "Link Failed", tmp_cr12);
 		db->link_failed = 1;
-		phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);	/* reset Phy */
-
-		/* 10/100M link failed, used 1M Home-Net */
-		db->cr6_data |= 0x00040000;	/* CR6 bit18 = 1, select Home-Net */
-		db->cr6_data &= ~0x00000200;	/* CR6 bit9 =0, half duplex mode */
-		update_cr6(db->cr6_data, db->ioaddr);
-
-		/* For DM9801 : PHY ID1 0181h, PHY ID2 B900h */
-		db->phy_id2 = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
-		if (db->phy_id2 == 0xb900)
-			phy_write(db->ioaddr, db->phy_addr, 25, 0x7e08, db->chip_id);
-	} else if ((tmp_cr12 & 0x3) && db->link_failed) {
-		DMFE_DBUG(0, "Link link OK", tmp_cr12);
-		db->link_failed = 0;
 
-		/* CR6 bit18=0, select 10/100M */
-		db->cr6_data &= ~0x00040000;
-		update_cr6(db->cr6_data, db->ioaddr);
+		/* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
+		/* AUTO or force 1M Homerun/Longrun don't need */
+		if ( !(db->media_mode & 0x38) )
+			phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
+
+		/* AUTO mode, if INT phyxcer link failed, select EXT device */
+		if (db->media_mode & DMFE_AUTO) {
+			/* 10/100M link failed, used 1M Home-Net */
+			db->cr6_data|=0x00040000;	/* bit18=1, MII */
+			db->cr6_data&=~0x00000200;	/* bit9=0, HD mode */
+			update_cr6(db->cr6_data, db->ioaddr);
+		}
+	} else
+		if ((tmp_cr12 & 0x3) && db->link_failed) {
+			DMFE_DBUG(0, "Link link OK", tmp_cr12);
+			db->link_failed = 0;
+
+			/* Auto Sense Speed */
+			if ( (db->media_mode & DMFE_AUTO) &&
+				dmfe_sense_speed(db) )
+				db->link_failed = 1;
+			dmfe_process_mode(db);
+			/* SHOW_MEDIA_TYPE(db->op_mode); */
+		}
 
-		/* Auto Sense Speed */
-		if (db->media_mode & DMFE_AUTO)
-			dmfe_sense_speed(db);
-		dmfe_process_mode(db);
-		update_cr6(db->cr6_data, db->ioaddr);
-		/* SHOW_MEDIA_TYPE(db->op_mode); */
+	/* HPNA remote command check */
+	if (db->HPNA_command & 0xf00) {
+		db->HPNA_timer--;
+		if (!db->HPNA_timer)
+			dmfe_HPNA_remote_cmd_chk(db);
 	}
-	/* reallocated rx descriptor buffer */
-	if (db->rx_avail_cnt < RX_DESC_CNT)
-		allocated_rx_buffer(db);
 
 	/* Timer active again */
-	db->timer.expires = jiffies + DMFE_TIMER_WUT;
+	db->timer.expires = DMFE_TIMER_WUT;
 	add_timer(&db->timer);
 	spin_unlock_irqrestore(&db->lock, flags);
 }
 
+
 /*
-   Dynamic reset the DM910X board
-   Stop DM910X board
-   Free Tx/Rx allocated memory
-   Reset DM910X board
-   Re-initialize DM910X board
+ *	Dynamic reset the DM910X board
+ *	Stop DM910X board
+ *	Free Tx/Rx allocated memory
+ *	Reset DM910X board
+ *	Re-initilize DM910X board
  */
-static void dmfe_dynamic_reset(struct net_device *dev)
+
+static void dmfe_dynamic_reset(struct DEVICE *dev)
 {
 	struct dmfe_board_info *db = dev->priv;
 
 	DMFE_DBUG(0, "dmfe_dynamic_reset()", 0);
 
-	/* Enter dynamic reset route */
-	db->in_reset_state = 1;
+	/* Sopt MAC controller */
+	db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);	/* Disable Tx/Rx */
+	update_cr6(db->cr6_data, dev->base_addr);
+	outl(0, dev->base_addr + DCR7);		/* Disable Interrupt */
+	outl(inl(dev->base_addr + DCR5), dev->base_addr + DCR5);
 
 	/* Disable upper layer interface */
 	netif_stop_queue(dev);
-	
-	db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);		/* Disable Tx/Rx */
-	update_cr6(db->cr6_data, dev->base_addr);
 
 	/* Free Rx Allocate buffer */
 	dmfe_free_rxbuffer(db);
 
 	/* system variable init */
-	db->tx_int_pkt_num = TX_IRQ_THR;
-	db->tx_live_cnt = 0;
+	db->tx_packet_cnt = 0;
+	db->tx_queue_cnt = 0;
 	db->rx_avail_cnt = 0;
-	db->link_failed = 0;
+	db->link_failed = 1;
 	db->wait_reset = 0;
-	db->rx_error_cnt = 0;
 
-	/* Re-initialize DM910X board */
+	/* Re-initilize DM910X board */
 	dmfe_init_dm910x(dev);
 
-	/* Leave dynamic reser route */
-	db->in_reset_state = 0;
-
 	/* Restart upper layer interface */
 	netif_wake_queue(dev);
 }
 
+
 /*
-   free all allocated rx buffer 
+ *	free all allocated rx buffer
  */
-static void dmfe_free_rxbuffer(struct dmfe_board_info *db)
+
+static void dmfe_free_rxbuffer(struct dmfe_board_info * db)
 {
 	DMFE_DBUG(0, "dmfe_free_rxbuffer()", 0);
 
 	/* free allocated rx buffer */
 	while (db->rx_avail_cnt) {
-		dev_kfree_skb((void *) (db->rx_ready_ptr->rx_skb_ptr));
+		dev_kfree_skb( (void *) (db->rx_ready_ptr->rx_skb_ptr) );
 		db->rx_ready_ptr = (struct rx_desc *) db->rx_ready_ptr->next_rx_desc;
 		db->rx_avail_cnt--;
 	}
 }
 
+
 /*
-   Reused the SK buffer
+ *	Reused the SK buffer
  */
-static void dmfe_reused_skb(struct dmfe_board_info *db, struct sk_buff *skb)
+
+static void dmfe_reused_skb(struct dmfe_board_info *db, struct sk_buff * skb)
 {
 	struct rx_desc *rxptr = db->rx_insert_ptr;
 
 	if (!(rxptr->rdes0 & 0x80000000)) {
 		rxptr->rx_skb_ptr = (u32) skb;
-		rxptr->rdes2 = virt_to_bus(skb->tail);
-		rxptr->rdes0 = 0x80000000;
+		rxptr->rdes2 = cpu_to_le32( pci_map_single(db->net_dev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+		rxptr->rdes0 = cpu_to_le32(0x80000000);
 		db->rx_avail_cnt++;
 		db->rx_insert_ptr = (struct rx_desc *) rxptr->next_rx_desc;
 	} else
 		DMFE_DBUG(0, "SK Buffer reused method error", db->rx_avail_cnt);
 }
 
+
 /*
-   Initialize transmit/Receive descriptor 
-   Using Chain structure, and allocated Tx/Rx buffer
+ *	Initialize transmit/Receive descriptor
+ *	Using Chain structure, and allocated Tx/Rx buffer
  */
+
 static void dmfe_descriptor_init(struct dmfe_board_info *db, u32 ioaddr)
 {
 	struct tx_desc *tmp_tx;
 	struct rx_desc *tmp_rx;
 	unsigned char *tmp_buf;
+	dma_addr_t tmp_tx_dma, tmp_rx_dma;
+	dma_addr_t tmp_buf_dma;
 	int i;
 
 	DMFE_DBUG(0, "dmfe_descriptor_init()", 0);
@@ -1142,67 +1285,77 @@
 	/* tx descriptor start pointer */
 	db->tx_insert_ptr = db->first_tx_desc;
 	db->tx_remove_ptr = db->first_tx_desc;
-	outl(virt_to_bus(db->first_tx_desc), ioaddr + DCR4);	/* Init CR4 */
+	outl(db->first_tx_desc_dma, ioaddr + DCR4);     /* TX DESC address */
 
 	/* rx descriptor start pointer */
-	db->first_rx_desc = (struct rx_desc *)
-	    ((u32) db->first_tx_desc + sizeof(struct rx_desc) * TX_DESC_CNT);
+	db->first_rx_desc = (struct rx_desc *) ( (u32) db->first_tx_desc + sizeof(struct rx_desc) * TX_DESC_CNT );
+	db->first_rx_desc_dma = ( db->first_tx_desc_dma + sizeof(struct rx_desc) * TX_DESC_CNT);
 	db->rx_insert_ptr = db->first_rx_desc;
 	db->rx_ready_ptr = db->first_rx_desc;
-	outl(virt_to_bus(db->first_rx_desc), ioaddr + DCR3);	/* Init CR3 */
+	outl(db->first_rx_desc_dma, ioaddr + DCR3);	/* RX DESC address */
 
 	/* Init Transmit chain */
 	tmp_buf = db->buf_pool_start;
+	tmp_buf_dma = db->buf_pool_dma_start;
+	tmp_tx_dma = db->first_tx_desc_dma;
 	for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) {
 		tmp_tx->tx_buf_ptr = (u32) tmp_buf;
-		tmp_tx->tdes0 = 0;
-		tmp_tx->tdes1 = 0x81000000;	/* IC, chain */
-		tmp_tx->tdes2 = (u32) virt_to_bus(tmp_buf);
-		tmp_tx->tdes3 = (u32) virt_to_bus(tmp_tx) + sizeof(struct tx_desc);
+		tmp_tx->tdes0 = cpu_to_le32(0);
+		tmp_tx->tdes1 = cpu_to_le32(0x81000000);	/* IC, chain */
+		tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma);
+		tmp_tx_dma += sizeof(struct tx_desc);
+		tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma);
 		tmp_tx->next_tx_desc = (u32) ((u32) tmp_tx + sizeof(struct tx_desc));
 		tmp_buf = (unsigned char *) ((u32) tmp_buf + TX_BUF_ALLOC);
+		tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC;
 	}
-	(--tmp_tx)->tdes3 = (u32) virt_to_bus(db->first_tx_desc);
+	(--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma);
 	tmp_tx->next_tx_desc = (u32) db->first_tx_desc;
 
-	/* Init Receive descriptor chain */
+	 /* Init Receive descriptor chain */
+	tmp_rx_dma=db->first_rx_desc_dma;
 	for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT; i++, tmp_rx++) {
-		tmp_rx->rdes0 = 0;
-		tmp_rx->rdes1 = 0x01000600;
-		tmp_rx->rdes3 = (u32) virt_to_bus(tmp_rx) + sizeof(struct rx_desc);
+		tmp_rx->rdes0 = cpu_to_le32(0);
+		tmp_rx->rdes1 = cpu_to_le32(0x01000600);
+		tmp_rx_dma += sizeof(struct rx_desc);
+		tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma);
 		tmp_rx->next_rx_desc = (u32) ((u32) tmp_rx + sizeof(struct rx_desc));
 	}
-	(--tmp_rx)->rdes3 = (u32) virt_to_bus(db->first_rx_desc);
+	(--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma);
 	tmp_rx->next_rx_desc = (u32) db->first_rx_desc;
 
 	/* pre-allocated Rx buffer */
 	allocated_rx_buffer(db);
 }
 
+
 /*
-   Update CR6 value
-   Firstly stop DM910X , then written value and start
+ *	Update CR6 vaule
+ *	Firstly stop DM910X , then written value and start
  */
+
 static void update_cr6(u32 cr6_data, u32 ioaddr)
 {
 	u32 cr6_tmp;
 
-	cr6_tmp = cr6_data & ~0x2002;	/* stop Tx/Rx */
+	cr6_tmp = cr6_data & ~0x2002;           /* stop Tx/Rx */
 	outl(cr6_tmp, ioaddr + DCR6);
 	udelay(5);
 	outl(cr6_data, ioaddr + DCR6);
-	cr6_tmp = inl(ioaddr + DCR6);
-	/* printk("CR6 update %x ", cr6_tmp); */
+	udelay(5);
 }
 
-/* Send a setup frame for DM9132
-   This setup frame initialize DM910X address filter mode
- */
-static void dm9132_id_table(struct net_device *dev, int mc_cnt)
+
+/*
+ *	Send a setup frame for DM9132
+ *	This setup frame initilize DM910X addres filter mode
+*/
+
+static void dm9132_id_table(struct DEVICE *dev, int mc_cnt)
 {
 	struct dev_mc_list *mcptr;
-	u16 *addrptr;
-	u32 ioaddr = dev->base_addr + 0xc0;	/* ID Table */
+	u16 * addrptr;
+	u32 ioaddr = dev->base_addr+0xc0;		/* ID Table */
 	u32 hash_val;
 	u16 i, hash_table[4];
 
@@ -1226,26 +1379,28 @@
 
 	/* the multicast address in Hash Table : 64 bits */
 	for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
-		hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f;
+		hash_val = cal_CRC( (char *) mcptr->dmi_addr, 6, 0) & 0x3f;
 		hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
 	}
 
 	/* Write the hash table to MAC MD table */
-	for (i = 0; i < 4; i++, ioaddr += 4) {
+	for (i = 0; i < 4; i++, ioaddr += 4)
 		outw(hash_table[i], ioaddr);
-	}
 }
 
-/* Send a setup frame for DM9102/DM9102A
-   This setup frame initialize DM910X address filter mode
+
+/*
+ *	Send a setup frame for DM9102/DM9102A
+ *	This setup frame initilize DM910X addres filter mode
  */
-static void send_filter_frame(struct net_device *dev, int mc_cnt)
+
+static void send_filter_frame(struct DEVICE *dev, int mc_cnt)
 {
 	struct dmfe_board_info *db = dev->priv;
 	struct dev_mc_list *mcptr;
 	struct tx_desc *txptr;
-	u16 *addrptr;
-	u32 *suptr;
+	u16 * addrptr;
+	u32 * suptr;
 	int i;
 
 	DMFE_DBUG(0, "send_filter_frame()", 0);
@@ -1253,12 +1408,6 @@
 	txptr = db->tx_insert_ptr;
 	suptr = (u32 *) txptr->tx_buf_ptr;
 
-	if (txptr->tdes0 & 0x80000000) {
-		printk(KERN_WARNING "%s: Too busy to send filter frame\n",
-		       dev->name);
-		return;
-	}
-
 	/* Node address */
 	addrptr = (u16 *) dev->dev_addr;
 	*suptr++ = addrptr[0];
@@ -1278,26 +1427,35 @@
 		*suptr++ = addrptr[2];
 	}
 
-	for (i=0; i < 14; i++) 
+	for (; i<14; i++) {
 		*suptr++ = 0xffff;
 		*suptr++ = 0xffff;
 		*suptr++ = 0xffff;
-	
+	}
+
 	/* prepare the setup frame */
 	db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;
-	db->tx_live_cnt++;
-	txptr->tdes1 = 0x890000c0;
-	/* Send the setup packet */
-	txptr->tdes0 = 0x80000000;
-	update_cr6(db->cr6_data | 0x2000, dev->base_addr);
-	outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling command */
-	update_cr6(db->cr6_data, dev->base_addr);
+	txptr->tdes1 = cpu_to_le32(0x890000c0);
+
+	/* Resource Check and Send the setup packet */
+	if (!db->tx_packet_cnt) {
+		/* Resource Empty */
+		db->tx_packet_cnt++;
+		txptr->tdes0 = cpu_to_le32(0x80000000);
+		update_cr6(db->cr6_data | 0x2000, dev->base_addr);
+		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */
+		update_cr6(db->cr6_data, dev->base_addr);
+		dev->trans_start = jiffies;
+	} else
+		db->tx_queue_cnt++;	/* Put in TX queue */
 }
 
+
 /*
  *	Allocate rx buffer,
- *	Allocate as many Rx buffers as possible.
+ *	As possible as allocated maxiumn Rx buffer
  */
+
 static void allocated_rx_buffer(struct dmfe_board_info *db)
 {
 	struct rx_desc *rxptr;
@@ -1305,12 +1463,12 @@
 
 	rxptr = db->rx_insert_ptr;
 
-	while (db->rx_avail_cnt < RX_DESC_CNT) {
-		if ((skb = dev_alloc_skb(RX_ALLOC_SIZE)) == NULL)
+	while(db->rx_avail_cnt < RX_DESC_CNT) {
+		if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL )
 			break;
 		rxptr->rx_skb_ptr = (u32) skb;
-		rxptr->rdes2 = virt_to_bus(skb->tail);
-		rxptr->rdes0 = 0x80000000;
+		rxptr->rdes2 = cpu_to_le32( pci_map_single(db->net_dev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+		rxptr->rdes0 = cpu_to_le32(0x80000000);
 		rxptr = (struct rx_desc *) rxptr->next_rx_desc;
 		db->rx_avail_cnt++;
 	}
@@ -1318,9 +1476,11 @@
 	db->rx_insert_ptr = rxptr;
 }
 
+
 /*
-   Read one word data from the serial ROM
+ *	Read one word data from the serial ROM
  */
+
 static u16 read_srom_word(long ioaddr, int offset)
 {
 	int i;
@@ -1355,113 +1515,150 @@
 	return srom_data;
 }
 
+
 /*
  *	Auto sense the media mode
  */
- 
-static void dmfe_sense_speed(struct dmfe_board_info *db)
+
+static u8 dmfe_sense_speed(struct dmfe_board_info * db)
 {
-	int i;
-	u16 phy_mode = 0;
+	u8 ErrFlag = 0;
+	u16 phy_mode;
 
-	for (i = 1000; i; i--) {
-		udelay(5);
-		phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
-		if ((phy_mode & 0x24) == 0x24)
-			break;
-	}
+	/* CR6 bit18=0, select 10/100M */
+	update_cr6( (db->cr6_data & ~0x40000), db->ioaddr);
+
+	phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
+	phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
 
-	if (i) {
+	if ( (phy_mode & 0x24) == 0x24 ) {
 		if (db->chip_id == PCI_DM9132_ID)	/* DM9132 */
 			phy_mode = phy_read(db->ioaddr, db->phy_addr, 7, db->chip_id) & 0xf000;
-		else		/* DM9102/DM9102A */
+		else 				/* DM9102/DM9102A */
 			phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000;
-		/* printk("Phy_mode %x ",phy_mode); */
+		/* printk("<DMFE>: Phy_mode %x ",phy_mode); */
 		switch (phy_mode) {
-		case 0x1000:
-			db->op_mode = DMFE_10MHF;
-			break;
-		case 0x2000:
-			db->op_mode = DMFE_10MFD;
-			break;
-		case 0x4000:
-			db->op_mode = DMFE_100MHF;
-			break;
-		case 0x8000:
-			db->op_mode = DMFE_100MFD;
-			break;
-		default:
-			db->op_mode = DMFE_10MHF;
-			DMFE_DBUG(0, "Media Type error, phy reg17", phy_mode);
+		case 0x1000: db->op_mode = DMFE_10MHF; break;
+		case 0x2000: db->op_mode = DMFE_10MFD; break;
+		case 0x4000: db->op_mode = DMFE_100MHF; break;
+		case 0x8000: db->op_mode = DMFE_100MFD; break;
+		default: db->op_mode = DMFE_10MHF;
+			ErrFlag = 1;
 			break;
 		}
 	} else {
 		db->op_mode = DMFE_10MHF;
 		DMFE_DBUG(0, "Link Failed :", phy_mode);
+		ErrFlag = 1;
+	}
+
+	return ErrFlag;
+}
+
+
+/*
+ *	Set 10/100 phyxcer capability
+ *	AUTO mode : phyxcer register4 is NIC capability
+ *	Force mode: phyxcer register4 is the force media
+ */
+
+static void dmfe_set_phyxcer(struct dmfe_board_info *db)
+{
+	u16 phy_reg;
+
+	/* Select 10/100M phyxcer */
+	db->cr6_data &= ~0x40000;
+	update_cr6(db->cr6_data, db->ioaddr);
+
+	/* DM9009 Chip: Phyxcer reg18 bit12=0 */
+	if (db->chip_id == PCI_DM9009_ID) {
+		phy_reg = phy_read(db->ioaddr, db->phy_addr, 18, db->chip_id) & ~0x1000;
+		phy_write(db->ioaddr, db->phy_addr, 18, phy_reg, db->chip_id);
+	}
+
+	/* Phyxcer capability setting */
+	phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
+
+	if (db->media_mode & DMFE_AUTO) {
+		/* AUTO Mode */
+		phy_reg |= db->PHY_reg4;
+	} else {
+		/* Force Mode */
+		switch(db->media_mode) {
+		case DMFE_10MHF: phy_reg |= 0x20; break;
+		case DMFE_10MFD: phy_reg |= 0x40; break;
+		case DMFE_100MHF: phy_reg |= 0x80; break;
+		case DMFE_100MFD: phy_reg |= 0x100; break;
+		}
+		if (db->chip_id == PCI_DM9009_ID) phy_reg &= 0x61;
 	}
+
+  	/* Write new capability to Phyxcer Reg4 */
+	if ( !(phy_reg & 0x01e0)) {
+		phy_reg|=db->PHY_reg4;
+		db->media_mode|=DMFE_AUTO;
+	}
+	phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
+
+ 	/* Restart Auto-Negotiation */
+	if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
+		phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
+	if ( !db->chip_type )
+		phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
 }
 
+
 /*
-   Process op-mode
-   AUTO mode : PHY controller in Auto-negotiation Mode
-   Force mode: PHY controller in force mode with HUB
-   N-way force capability with SWITCH
+ *	Process op-mode
+ *	AUTO mode : PHY controller in Auto-negotiation Mode
+ *	Force mode: PHY controller in force mode with HUB
+ *			N-way force capability with SWITCH
  */
+
 static void dmfe_process_mode(struct dmfe_board_info *db)
 {
 	u16 phy_reg;
 
 	/* Full Duplex Mode Check */
-	db->cr6_data &= ~CR6_FDM;	/* Clear Full Duplex Bit */
 	if (db->op_mode & 0x4)
-		db->cr6_data |= CR6_FDM;
+		db->cr6_data |= CR6_FDM;	/* Set Full Duplex Bit */
+	else
+		db->cr6_data &= ~CR6_FDM;	/* Clear Full Duplex Bit */
 
-	if (!(db->media_mode & DMFE_AUTO)) {	/* Force Mode Check */
-		/* User force the media type */
-		phy_reg = phy_read(db->ioaddr, db->phy_addr, 5, db->chip_id);
-		/* printk("Nway phy_reg5 %x ",phy_reg); */
-		if (phy_reg & 0x1) {
-			/* parter own the N-Way capability */
-			phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x1e0;
-			switch (db->op_mode) {
-			case DMFE_10MHF:
-				phy_reg |= 0x20;
-				break;
-			case DMFE_10MFD:
-				phy_reg |= 0x40;
-				break;
-			case DMFE_100MHF:
-				phy_reg |= 0x80;
-				break;
-			case DMFE_100MFD:
-				phy_reg |= 0x100;
-				break;
-			}
-			phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
-		} else {
-			/* parter without the N-Way capability */
-			switch (db->op_mode) {
-			case DMFE_10MHF:
-				phy_reg = 0x0;
-				break;
-			case DMFE_10MFD:
-				phy_reg = 0x100;
-				break;
-			case DMFE_100MHF:
-				phy_reg = 0x2000;
-				break;
-			case DMFE_100MFD:
-				phy_reg = 0x2100;
-				break;
+	/* Transciver Selection */
+	if (db->op_mode & 0x10)		/* 1M HomePNA */
+		db->cr6_data |= 0x40000;/* External MII select */
+	else
+		db->cr6_data &= ~0x40000;/* Internal 10/100 transciver */
+
+	update_cr6(db->cr6_data, db->ioaddr);
+
+	/* 10/100M phyxcer force mode need */
+	if ( !(db->media_mode & 0x18)) {
+		/* Forece Mode */
+		phy_reg = phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
+		if ( !(phy_reg & 0x1) ) {
+			/* parter without N-Way capability */
+			phy_reg = 0x0;
+			switch(db->op_mode) {
+			case DMFE_10MHF: phy_reg = 0x0; break;
+			case DMFE_10MFD: phy_reg = 0x100; break;
+			case DMFE_100MHF: phy_reg = 0x2000; break;
+			case DMFE_100MFD: phy_reg = 0x2100; break;
 			}
 			phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
+       			if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
+				mdelay(20);
+			phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
 		}
 	}
 }
 
+
 /*
-   Write a word to Phy register
+ *	Write a word to Phy register
  */
+
 static void phy_write(u32 iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id)
 {
 	u16 i;
@@ -1486,11 +1683,11 @@
 		phy_write_1bit(ioaddr, PHY_DATA_0);
 		phy_write_1bit(ioaddr, PHY_DATA_1);
 
-		/* Send Phy address */
+		/* Send Phy addres */
 		for (i = 0x10; i > 0; i = i >> 1)
 			phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
 
-		/* Send register address */
+		/* Send register addres */
 		for (i = 0x10; i > 0; i = i >> 1)
 			phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
 
@@ -1499,14 +1696,16 @@
 		phy_write_1bit(ioaddr, PHY_DATA_0);
 
 		/* Write a word data to PHY controller */
-		for (i = 0x8000; i > 0; i >>= 1)
+		for ( i = 0x8000; i > 0; i >>= 1)
 			phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
 	}
 }
 
+
 /*
-   Read a word data from phy register
+ *	Read a word data from phy register
  */
+
 static u16 phy_read(u32 iobase, u8 phy_addr, u8 offset, u32 chip_id)
 {
 	int i;
@@ -1519,8 +1718,8 @@
 		phy_data = inw(ioaddr);
 	} else {
 		/* DM9102/DM9102A Chip */
-
 		ioaddr = iobase + DCR9;
+
 		/* Send 33 synchronization clock to Phy controller */
 		for (i = 0; i < 35; i++)
 			phy_write_1bit(ioaddr, PHY_DATA_1);
@@ -1533,11 +1732,11 @@
 		phy_write_1bit(ioaddr, PHY_DATA_1);
 		phy_write_1bit(ioaddr, PHY_DATA_0);
 
-		/* Send Phy address */
+		/* Send Phy addres */
 		for (i = 0x10; i > 0; i = i >> 1)
 			phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
 
-		/* Send register address */
+		/* Send register addres */
 		for (i = 0x10; i > 0; i = i >> 1)
 			phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
 
@@ -1554,41 +1753,47 @@
 	return phy_data;
 }
 
+
 /*
-   Write one bit data to Phy Controller
+ *	Write one bit data to Phy Controller
  */
+
 static void phy_write_1bit(u32 ioaddr, u32 phy_data)
 {
-	outl(phy_data, ioaddr);	/* MII Clock Low */
+	outl(phy_data, ioaddr);			/* MII Clock Low */
 	udelay(1);
 	outl(phy_data | MDCLKH, ioaddr);	/* MII Clock High */
 	udelay(1);
-	outl(phy_data, ioaddr);	/* MII Clock Low */
+	outl(phy_data, ioaddr);			/* MII Clock Low */
 	udelay(1);
 }
 
+
 /*
-   Read one bit phy data from PHY controller
+ *	Read one bit phy data from PHY controller
  */
+
 static u16 phy_read_1bit(u32 ioaddr)
 {
 	u16 phy_data;
 
 	outl(0x50000, ioaddr);
 	udelay(1);
-	phy_data = (inl(ioaddr) >> 19) & 0x1;
+	phy_data = ( inl(ioaddr) >> 19 ) & 0x1;
 	outl(0x40000, ioaddr);
 	udelay(1);
 
 	return phy_data;
 }
 
+
 /*
-   Calculate the CRC valude of the Rx packet
-   flag = 1 : return the reverse CRC (for the received packet CRC)
-   0 : return the normal CRC (for Hash Table index)
+ *	Calculate the CRC valude of the Rx packet
+ *	flag = 	1 : return the reverse CRC (for the received packet CRC)
+ *		0 : return the normal CRC (for Hash Table index)
  */
-unsigned long cal_CRC(unsigned char *Data, unsigned int Len, u8 flag)
+
+unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
 {
 	unsigned long Crc = 0xffffffff;
 
@@ -1603,10 +1808,190 @@
 }
 
 
-static struct pci_device_id dmfe_pci_tbl[] __initdata = {
+/*
+ *	Parser SROM and media mode
+ */
+
+static void dmfe_parse_srom(struct dmfe_board_info * db)
+{
+	char * srom = db->srom;
+	int dmfe_mode, tmp_reg;
+
+	DMFE_DBUG(0, "dmfe_parse_srom() ", 0);
+
+	/* Init CR15 */
+	db->cr15_data = CR15_DEFAULT;
+
+	/* Check SROM Version */
+	if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) {
+		/* SROM V4.01 */
+		/* Get NIC support media mode */
+		db->NIC_capability = *(u16 *) (&srom[34]);
+		db->PHY_reg4 = 0;
+		for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) {
+			switch( db->NIC_capability & tmp_reg ) {
+			case 0x1: db->PHY_reg4 |= 0x0020; break;
+			case 0x2: db->PHY_reg4 |= 0x0040; break;
+			case 0x4: db->PHY_reg4 |= 0x0080; break;
+			case 0x8: db->PHY_reg4 |= 0x0100; break;
+			}
+		}
+
+		/* Media Mode Force or not check */
+		dmfe_mode = *( (int *) &srom[34]) & *( (int *) &srom[36] );
+		switch(dmfe_mode) {
+		case 0x4: dmfe_media_mode = DMFE_100MHF; break;	/* 100MHF */
+		case 0x2: dmfe_media_mode = DMFE_10MFD; break;	/* 10MFD */
+		case 0x8: dmfe_media_mode = DMFE_100MFD; break;	/* 100MFD */
+		case 0x100:
+		case 0x200: dmfe_media_mode = DMFE_1M_HPNA; break;/* HomePNA */
+		}
+
+		/* Special Function setting */
+		/* VLAN function */
+		if ( (SF_mode & 0x1) || (srom[43] & 0x80) )
+			db->cr15_data |= 0x40;
+
+		/* Flow Control */
+		if ( (SF_mode & 0x2) || (srom[40] & 0x1) )
+			db->cr15_data |= 0x400;
+
+		/* TX pause packet */
+		if ( (SF_mode & 0x4) || (srom[40] & 0xe) )
+			db->cr15_data |= 0x9800;
+	}
+
+	/* Parse HPNA parameter */
+	db->HPNA_command = 1;
+
+	/* Accept remote command or not */
+	if (HPNA_rx_cmd == 0)
+		db->HPNA_command |= 0x8000;
+
+	 /* Issue remote command & operation mode */
+	if (HPNA_tx_cmd == 1)
+		switch(HPNA_mode) {	/* Issue Remote Command */
+		case 0: db->HPNA_command |= 0x0904; break;
+		case 1: db->HPNA_command |= 0x0a00; break;
+		case 2: db->HPNA_command |= 0x0506; break;
+		case 3: db->HPNA_command |= 0x0602; break;
+		}
+	else
+		switch(HPNA_mode) {	/* Don't Issue */
+		case 0: db->HPNA_command |= 0x0004; break;
+		case 1: db->HPNA_command |= 0x0000; break;
+		case 2: db->HPNA_command |= 0x0006; break;
+		case 3: db->HPNA_command |= 0x0002; break;
+		}
+
+	/* Check DM9801 or DM9802 present or not */
+	db->HPNA_present = 0;
+	update_cr6(db->cr6_data|0x40000, db->ioaddr);
+	tmp_reg = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
+	if ( ( tmp_reg & 0xfff0 ) == 0xb900 ) {
+		/* DM9801 or DM9802 present */
+		db->HPNA_timer = 8;
+		if ( phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id) == 0x4404) {
+			/* DM9801 HomeRun */
+			db->HPNA_present = 1;
+			dmfe_program_DM9801(db, tmp_reg);
+		} else {
+			/* DM9802 LongRun */
+			db->HPNA_present = 2;
+			dmfe_program_DM9802(db);
+		}
+	}
+
+}
+
+
+/*
+ *	Init HomeRun DM9801
+ */
+
+static void dmfe_program_DM9801(struct dmfe_board_info * db, int HPNA_rev)
+{
+	uint reg17, reg25;
+
+	if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9801_NOISE_FLOOR;
+	switch(HPNA_rev) {
+	case 0xb900: /* DM9801 E3 */
+		db->HPNA_command |= 0x1000;
+		reg25 = phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id);
+		reg25 = ( (reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000;
+		reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+		break;
+	case 0xb901: /* DM9801 E4 */
+		reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor;
+		reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3;
+		break;
+	case 0xb902: /* DM9801 E5 */
+	case 0xb903: /* DM9801 E6 */
+	default:
+		db->HPNA_command |= 0x1000;
+		reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5;
+		reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor;
+		break;
+	}
+	phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+	phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id);
+	phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);
+}
+
+
+/*
+ *	Init HomeRun DM9802
+ */
+
+static void dmfe_program_DM9802(struct dmfe_board_info * db)
+{
+	uint phy_reg;
+
+	if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9802_NOISE_FLOOR;
+	phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+	phy_reg = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+	phy_reg = ( phy_reg & 0xff00) + HPNA_NoiseFloor;
+	phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);
+}
+
+
+/*
+ *	Check remote HPNA power and speed status. If not correct,
+ *	issue command again.
+*/
+
+static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
+{
+	uint phy_reg;
+
+	/* Got remote device status */
+	phy_reg = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60;
+	switch(phy_reg) {
+	case 0x00: phy_reg = 0x0a00;break; /* LP/LS */
+	case 0x20: phy_reg = 0x0900;break; /* LP/HS */
+	case 0x40: phy_reg = 0x0600;break; /* HP/LS */
+	case 0x60: phy_reg = 0x0500;break; /* HP/HS */
+	}
+
+	/* Check remote device status match our setting ot not */
+	if ( phy_reg != (db->HPNA_command & 0x0f00) ) {
+		phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+		db->HPNA_timer=8;
+	} else
+		db->HPNA_timer=600;	/* Match, every 10 minutes, check */
+}
+
+
+
+static struct pci_device_id dmfe_pci_tbl[] __devinitdata = {
 	{ 0x1282, 0x9132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9132_ID },
 	{ 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID },
 	{ 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID },
+	{ 0x1282, 0x9009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9009_ID },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);
@@ -1624,20 +2009,23 @@
 MODULE_PARM(mode, "i");
 MODULE_PARM(cr6set, "i");
 MODULE_PARM(chkmode, "i");
+MODULE_PARM(HPNA_mode, "i");
+MODULE_PARM(HPNA_rx_cmd, "i");
+MODULE_PARM(HPNA_tx_cmd, "i");
+MODULE_PARM(HPNA_NoiseFloor, "i");
+MODULE_PARM(SF_mode, "i");
 
-/*	Description: 
+/*	Description:
  *	when user used insmod to add module, system invoked init_module()
- *	to initialize and register.
+ *	to initilize and register.
  */
- 
+
 static int __init dmfe_init_module(void)
 {
 	int rc;
-	
-/* when a module, this is printed whether or not devices are found in probe */
-#ifdef MODULE
+
 	printk(version);
-#endif
+	printed_version = 1;
 
 	DMFE_DBUG(0, "init_module() ", debug);
 
@@ -1646,18 +2034,27 @@
 	if (cr6set)
 		dmfe_cr6_user_set = cr6set;
 
-	switch (mode) {
-	case 0:
-	case 1:
-	case 4:
-	case 5:
+ 	switch(mode) {
+   	case DMFE_10MHF:
+	case DMFE_100MHF:
+	case DMFE_10MFD:
+	case DMFE_100MFD:
+	case DMFE_1M_HPNA:
 		dmfe_media_mode = mode;
 		break;
-	default:
-		dmfe_media_mode = 8;
+	default:dmfe_media_mode = DMFE_AUTO;
 		break;
 	}
 
+	if (HPNA_mode > 4)
+		HPNA_mode = 0;		/* Default: LP/HS */
+	if (HPNA_rx_cmd > 1)
+		HPNA_rx_cmd = 0;	/* Default: Ignored remote cmd */
+	if (HPNA_tx_cmd > 1)
+		HPNA_tx_cmd = 0;	/* Default: Don't issue remote cmd */
+	if (HPNA_NoiseFloor > 15)
+		HPNA_NoiseFloor = 0;
+
 	rc = pci_module_init(&dmfe_driver);
 	if (rc < 0)
 		return rc;
@@ -1665,14 +2062,16 @@
 	return 0;
 }
 
+
 /*
- *	Description: 
+ *	Description:
  *	when user used rmmod to delete module, system invoked clean_module()
  *	to un-register all registered services.
  */
- 
+
 static void __exit dmfe_cleanup_module(void)
 {
+	DMFE_DBUG(0, "dmfe_clean_module() ", debug);
 	pci_unregister_driver(&dmfe_driver);
 }
 
diff -urN linux-2.4.5-pre3/drivers/net/epic100.c linux/drivers/net/epic100.c
--- linux-2.4.5-pre3/drivers/net/epic100.c	Fri Apr 20 11:54:23 2001
+++ linux/drivers/net/epic100.c	Mon Dec  3 22:44:23 2001
@@ -41,8 +41,19 @@
 	* Merge becker version 1.11
 	* Move pci_enable_device before any PCI BAR len checks
 
+	LK1.1.7:
+	* { fill me in }
+
+	LK1.1.8:
+	* ethtool support (jgarzik)
+
 */
 
+#define DRV_NAME	"epic100"
+#define DRV_VERSION	"1.11+LK1.1.8"
+#define DRV_RELDATE	"May 18, 2001"
+
+
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -104,16 +115,18 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/ethtool.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/uaccess.h>
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-"epic100.c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
+DRV_NAME ".c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
 static char version2[] __devinitdata =
 "  http://www.scyld.com/network/epic100.html\n";
 static char version3[] __devinitdata =
-"  (unofficial 2.4.x kernel port, version 1.1.7, April 17, 2001)\n";
+"  (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver");
@@ -326,7 +339,7 @@
 static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static int epic_rx(struct net_device *dev);
 static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int epic_close(struct net_device *dev);
 static struct net_device_stats *epic_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
@@ -375,7 +388,7 @@
 	}
 	SET_MODULE_OWNER(dev);
 
-	if (pci_request_regions(pdev, "epic100"))
+	if (pci_request_regions(pdev, DRV_NAME))
 		goto err_out_free_netdev;
 
 #ifdef USE_IO_OPS
@@ -384,7 +397,7 @@
 	ioaddr = pci_resource_start (pdev, 1);
 	ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
 	if (!ioaddr) {
-		printk (KERN_ERR "epic100 %d: ioremap failed\n", card_idx);
+		printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx);
 		goto err_out_free_res;
 	}
 #endif
@@ -435,7 +448,7 @@
 		((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4));
 
 	if (debug > 2) {
-		printk(KERN_DEBUG "epic100(%s): EEPROM contents\n",
+		printk(KERN_DEBUG DRV_NAME "(%s): EEPROM contents\n",
 		       pdev->slot_name);
 		for (i = 0; i < 64; i++)
 			printk(" %4.4x%s", read_eeprom(ioaddr, i),
@@ -455,7 +468,7 @@
 			int mii_status = mdio_read(dev, phy, 1);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				ep->phys[phy_idx++] = phy;
-				printk(KERN_INFO "epic100(%s): MII transceiver #%d control "
+				printk(KERN_INFO DRV_NAME "(%s): MII transceiver #%d control "
 					   "%4.4x status %4.4x.\n",
 					   pdev->slot_name, phy, mdio_read(dev, phy, 0), mii_status);
 			}
@@ -464,11 +477,11 @@
 		if (phy_idx != 0) {
 			phy = ep->phys[0];
 			ep->advertising = mdio_read(dev, phy, 4);
-			printk(KERN_INFO "epic100(%s): Autonegotiation advertising %4.4x link "
+			printk(KERN_INFO DRV_NAME "(%s): Autonegotiation advertising %4.4x link "
 				   "partner %4.4x.\n",
 				   pdev->slot_name, ep->advertising, mdio_read(dev, phy, 5));
 		} else if ( ! (ep->chip_flags & NO_MII)) {
-			printk(KERN_WARNING "epic100(%s): ***WARNING***: No MII transceiver found!\n",
+			printk(KERN_WARNING DRV_NAME "(%s): ***WARNING***: No MII transceiver found!\n",
 			       pdev->slot_name);
 			/* Use the known PHY address of the EPII. */
 			ep->phys[0] = 3;
@@ -483,7 +496,7 @@
 	/* The lower four bits are the media type. */
 	if (duplex) {
 		ep->duplex_lock = ep->full_duplex = 1;
-		printk(KERN_INFO "epic100(%s):  Forced full duplex operation requested.\n",
+		printk(KERN_INFO DRV_NAME "(%s):  Forced full duplex operation requested.\n",
 		       pdev->slot_name);
 	}
 	dev->if_port = ep->default_port = option;
@@ -496,7 +509,7 @@
 	dev->stop = &epic_close;
 	dev->get_stats = &epic_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &mii_ioctl;
+	dev->do_ioctl = &netdev_ioctl;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->tx_timeout = &epic_tx_timeout;
 
@@ -1331,13 +1344,39 @@
 	return;
 }
 
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct epic_private *np = dev->priv;
+	u32 ethcmd;
+		
+	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, np->pci_dev->slot_name);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+        }
+	
+	return -EOPNOTSUPP;
+}
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct epic_private *ep = dev->priv;
 	long ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 
 	switch(cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = ep->phys[0] & 0x1f;
 		/* Fall Through */
@@ -1432,7 +1471,7 @@
 
 
 static struct pci_driver epic_driver = {
-	name:		"epic100",
+	name:		DRV_NAME,
 	id_table:	epic_pci_tbl,
 	probe:		epic_init_one,
 	remove:		epic_remove_one,
diff -urN linux-2.4.5-pre3/drivers/net/hamachi.c linux/drivers/net/hamachi.c
--- linux-2.4.5-pre3/drivers/net/hamachi.c	Fri Apr 20 11:54:23 2001
+++ linux/drivers/net/hamachi.c	Mon Dec  3 22:44:23 2001
@@ -23,10 +23,21 @@
 	or
 	http://www.parl.clemson.edu/~keithu/hamachi.html
 
-	For best viewing, set your tabs to 3.
+
+
+	Linux kernel changelog:
+
+	LK1.0.1:
+	- fix lack of pci_dev<->dev association
+	- ethtool support (jgarzik)
 
 */
 
+#define DRV_NAME	"hamachi"
+#define DRV_VERSION	"1.01+LK1.0.1"
+#define DRV_RELDATE	"5/18/2001"
+
+
 /* A few user-configurable values. */
 
 static int debug = 1;		/* 1 normal messages, 0 quiet .. 7 verbose.  */
@@ -116,7 +127,7 @@
 #define RX_RING_SIZE	512
 
 /*
- * Enable mii_ioctl.  Added interrupt coalescing parameter adjustment.
+ * Enable netdev_ioctl.  Added interrupt coalescing parameter adjustment.
  * 2/19/99 Pete Wyckoff <wyckoff@ca.sandia.gov>
  */
 
@@ -152,7 +163,9 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/ethtool.h>
 
+#include <asm/uaccess.h>
 #include <asm/processor.h>	/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -166,7 +179,7 @@
 #include <linux/delay.h>
 
 static char version[] __initdata =
-KERN_INFO "hamachi.c:v1.01 5/16/2000  Written by Donald Becker\n"
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Written by Donald Becker\n"
 KERN_INFO "   Some modifications by Eric kasten <kasten@nscl.msu.edu>\n"
 KERN_INFO "   Further modifications by Keith Underwood <keithu@parl.clemson.edu>\n";
 
@@ -502,7 +515,7 @@
 	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
 	u_int32_t rx_int_var, tx_int_var;	/* interrupt control variables */
 	u_int32_t option;							/* Hold on to a copy of the options */
-	u_int8_t pad[16];							/* Used for 32-byte alignment */
+	struct pci_dev *pci_dev;
 };
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>, Eric Kasten <kasten@nscl.msu.edu>, Keith Underwood <keithu@parl.clemson.edu>");
@@ -527,7 +540,7 @@
 static int mdio_read(long ioaddr, int phy_id, int location);
 static void mdio_write(long ioaddr, int phy_id, int location, int value);
 static int hamachi_open(struct net_device *dev);
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void hamachi_timer(unsigned long data);
 static void hamachi_tx_timeout(struct net_device *dev);
 static void hamachi_init_ring(struct net_device *dev);
@@ -569,7 +582,7 @@
 
 	pci_set_master(pdev);
 
-	i = pci_request_regions(pdev, "hamachi");
+	i = pci_request_regions(pdev, DRV_NAME);
 	if (i) return i;
 
 	irq = pdev->irq;
@@ -633,8 +646,10 @@
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
+	pci_set_drvdata(pdev, dev);
 
 	hmp->chip_id = chip_id;
+	hmp->pci_dev = pdev;
 
 	/* The lower four bits are the media type. */
 	if (option > 0) {
@@ -676,7 +691,7 @@
 	dev->stop = &hamachi_close;
 	dev->get_stats = &hamachi_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &mii_ioctl;
+	dev->do_ioctl = &netdev_ioctl;
 	dev->tx_timeout = &hamachi_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	if (mtu)
@@ -687,6 +702,7 @@
 		kfree(dev);
 		iounmap((char *)ioaddr);
 		pci_release_regions(pdev);
+		pci_set_drvdata(pdev, NULL);
 		return i;
 	}
 
@@ -1815,12 +1831,38 @@
 	}
 }
 
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct hamachi_private *np = dev->priv;
+	u32 ethcmd;
+		
+	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, np->pci_dev->slot_name);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+        }
+	
+	return -EOPNOTSUPP;
+}
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	long ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 
 	switch(cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = ((struct hamachi_private *)dev->priv)->phys[0] & 0x1f;
 		/* Fall Through */
@@ -1878,7 +1920,7 @@
 MODULE_DEVICE_TABLE(pci, hamachi_pci_tbl);
 
 static struct pci_driver hamachi_driver = {
-	name:		"hamachi",
+	name:		DRV_NAME,
 	id_table:	hamachi_pci_tbl,
 	probe:		hamachi_init_one,
 	remove:		hamachi_remove_one,
diff -urN linux-2.4.5-pre3/drivers/net/natsemi.c linux/drivers/net/natsemi.c
--- linux-2.4.5-pre3/drivers/net/natsemi.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/net/natsemi.c	Mon Dec  3 22:44:23 2001
@@ -34,9 +34,30 @@
 		- Clean up PCI enable (davej)
 	Version 1.0.4:
 		- Merge Donald Becker's natsemi.c version 1.07
+	Version 1.0.5:
+		- { fill me in }
+	Version 1.0.6:
+		* ethtool support (jgarzik)
+		* Proper initialization of the card (which sometimes
+		fails to occur and leaves the card in a non-functional
+		state). (uzi)
+
+		* Some documented register settings to optimize some
+		of the 100Mbit autodetection circuitry in rev C cards. (uzi)
+
+		* Polling of the PHY intr for stuff like link state
+		change and auto- negotiation to finally work properly. (uzi)
+
+		* One-liner removal of a duplicate declaration of
+		netdev_error(). (uzi)
 
 */
 
+#define DRV_NAME	"natsemi"
+#define DRV_VERSION	"1.07+LK1.0.6"
+#define DRV_RELDATE	"May 18, 2001"
+
+
 /* Updated to recommendations in pci-skeleton v2.03. */
 
 /* Automatically extracted configuration info:
@@ -92,16 +113,12 @@
 
 #define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
 
-#define final_version
-
 #if !defined(__OPTIMIZE__)
 #warning  You must compile this file with the correct options!
 #warning  See the last lines of the source file.
 #error You must compile this driver with "-O".
 #endif
 
-/* Include files, designed to support most kernel versions 2.0.0 and later. */
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -116,15 +133,17 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/ethtool.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.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 "natsemi.c:v1.07 1/9/2001  Written by Donald Becker <becker@scyld.com>\n"
+KERN_INFO DRV_NAME ".c:v1.07 1/9/2001  Written by Donald Becker <becker@scyld.com>\n"
 KERN_INFO "  http://www.scyld.com/network/natsemi.html\n"
-KERN_INFO "  (unofficial 2.4.x kernel port, version 1.0.5, April 17, 2001 Jeff Garzik, Tjeerd Mulder)\n";
+KERN_INFO "  (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE "  Jeff Garzik, Tjeerd Mulder)\n";
 
 /* Condensed operations for readability. */
 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
@@ -259,9 +278,12 @@
 	TxRingPtr=0x20, TxConfig=0x24,
 	RxRingPtr=0x30, RxConfig=0x34, ClkRun=0x3C,
 	WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C,
-	BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60,
-	RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64,
-	PCIPM = 0x44,
+	BootRomAddr=0x50, BootRomData=0x54, SiliconRev=0x58, StatsCtrl=0x5C,
+	StatsData=0x60, RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64,
+	PCIPM=0x44, PhyStatus=0xC0, MIntrCtrl=0xC4, MIntrStatus=0xC8,
+
+	/* These are from the spec, around page 78... on a separate table. */
+	PGSEL=0xCC, PMDCSR=0xE4, TSTDAT=0xFC, DSPCFG=0xF4, SDCFG=0x8C
 };
 
 /* Bit in ChipCmd. */
@@ -355,10 +377,9 @@
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
 static void netdev_error(struct net_device *dev, int intr_status);
 static int  netdev_rx(struct net_device *dev);
-static void netdev_error(struct net_device *dev, int intr_status);
 static void set_rx_mode(struct net_device *dev);
 static struct net_device_stats *get_stats(struct net_device *dev);
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  netdev_close(struct net_device *dev);
 
 
@@ -470,7 +491,7 @@
 	dev->stop = &netdev_close;
 	dev->get_stats = &get_stats;
 	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &mii_ioctl;
+	dev->do_ioctl = &netdev_ioctl;
 	dev->tx_timeout = &tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
@@ -584,7 +605,26 @@
 	long ioaddr = dev->base_addr;
 	int i;
 
-	/* Do we need to reset the chip??? */
+	/* Reset the chip, just in case. */
+	writel(ChipReset, ioaddr + ChipCmd);
+
+	/* On page 78 of the spec, they recommend some settings for "optimum
+	   performance" to be done in sequence.  These settings optimize some
+	   of the 100Mbit autodetection circuitry.  Also, we only want to do
+	   this for rev C of the chip.
+	*/
+	if (readl(ioaddr + SiliconRev) == 0x302) {
+		writew(0x0001, ioaddr + PGSEL);
+		writew(0x189C, ioaddr + PMDCSR);
+		writew(0x0000, ioaddr + TSTDAT);
+		writew(0x5040, ioaddr + DSPCFG);
+		writew(0x008C, ioaddr + SDCFG);
+	}
+
+	/* Enable PHY Specific event based interrupts.  Link state change
+	   and Auto-Negotiation Completion are among the affected.
+	*/
+	writew(0x0002, ioaddr + MIntrCtrl);
 
 	i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
 	if (i) return i;
@@ -820,14 +860,6 @@
 	long ioaddr;
 	int boguscnt = max_interrupt_work;
 
-#ifndef final_version			/* Can never occur. */
-	if (dev == NULL) {
-		printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown "
-				"device.\n", irq);
-		return;
-	}
-#endif
-
 	ioaddr = dev->base_addr;
 	np = dev->priv;
 
@@ -855,9 +887,7 @@
 				break;
 			if (np->tx_ring[entry].cmd_status & cpu_to_le32(0x08000000)) {
 				np->stats.tx_packets++;
-#if LINUX_VERSION_CODE > 0x20127
 				np->stats.tx_bytes += np->tx_skbuff[entry]->len;
-#endif
 			} else {			/* Various Tx errors */
 				int tx_status = le32_to_cpu(np->tx_ring[entry].cmd_status);
 				if (tx_status & 0x04010000) np->stats.tx_aborted_errors++;
@@ -893,18 +923,6 @@
 	if (debug > 3)
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, (int)readl(ioaddr + IntrStatus));
-
-#ifndef final_version
-	/* Code that should never be run!  Perhaps remove after testing.. */
-	{
-		static int stopit = 10;
-		if (!netif_running(dev)  &&  --stopit < 0) {
-			printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",
-				   dev->name);
-			free_irq(irq, dev);
-		}
-	}
-#endif
 }
 
 /* This routine is logically part of the interrupt handler, but separated
@@ -968,27 +986,12 @@
 						   skb->head, temp);
 #endif
 			}
-#ifndef final_version				/* Remove after testing. */
-			/* You will want this info for the initial debug. */
-			if (debug > 5)
-				printk(KERN_DEBUG "  Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
-					   "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
-					   "%d.%d.%d.%d.\n",
-					   skb->data[0], skb->data[1], skb->data[2], skb->data[3],
-					   skb->data[4], skb->data[5], skb->data[6], skb->data[7],
-					   skb->data[8], skb->data[9], skb->data[10],
-					   skb->data[11], skb->data[12], skb->data[13],
-					   skb->data[14], skb->data[15], skb->data[16],
-					   skb->data[17]);
-#endif
 			skb->protocol = eth_type_trans(skb, dev);
 			/* W/ hardware checksum: skb->ip_summed = CHECKSUM_UNNECESSARY; */
 			netif_rx(skb);
 			dev->last_rx = jiffies;
 			np->stats.rx_packets++;
-#if LINUX_VERSION_CODE > 0x20127
 			np->stats.rx_bytes += pkt_len;
-#endif
 		}
 		entry = (++np->cur_rx) % RX_RING_SIZE;
 		np->rx_head_desc = &np->rx_ring[entry];
@@ -1025,6 +1028,8 @@
 		printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"
 			   " %4.4x  partner %4.4x.\n", dev->name,
 			   (int)readl(ioaddr + 0x90), (int)readl(ioaddr + 0x94));
+		/* read MII int status to clear the flag */
+		readw(ioaddr + MIntrStatus);
 		check_duplex(dev);
 	}
 	if (intr_status & StatsMax) {
@@ -1126,12 +1131,38 @@
 	np->cur_rx_mode = rx_mode;
 }
 
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct netdev_private *np = dev->priv;
+	u32 ethcmd;
+		
+	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, np->pci_dev->slot_name);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+        }
+	
+	return -EOPNOTSUPP;
+}
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct netdev_private *np = dev->priv;
 	u16 *data = (u16 *)&rq->ifr_data;
 
 	switch(cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = 1;
 		/* Fall Through */
@@ -1211,9 +1242,6 @@
 		np->rx_ring[i].cmd_status = 0;
 		np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
 		if (np->rx_skbuff[i]) {
-#if LINUX_VERSION_CODE < 0x20100
-			np->rx_skbuff[i]->free = 1;
-#endif
 			dev_kfree_skb(np->rx_skbuff[i]);
 		}
 		np->rx_skbuff[i] = 0;
@@ -1245,7 +1273,7 @@
 }
 
 static struct pci_driver natsemi_driver = {
-	name:		"natsemi",
+	name:		DRV_NAME,
 	id_table:	natsemi_pci_tbl,
 	probe:		natsemi_probe1,
 	remove:		natsemi_remove1,
diff -urN linux-2.4.5-pre3/drivers/net/tulip/ChangeLog linux/drivers/net/tulip/ChangeLog
--- linux-2.4.5-pre3/drivers/net/tulip/ChangeLog	Mon Dec  3 22:43:50 2001
+++ linux/drivers/net/tulip/ChangeLog	Mon Dec  3 22:44:23 2001
@@ -1,3 +1,22 @@
+2001-05-18  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip_core.c: Added ethtool support.
+	  ETHTOOL_GDRVINFO ioctl only, for now.
+
+2001-05-14  Robert Olsson <Robert.Olsson@data.slu.se>
+
+	* Restored HW_FLOWCONTROL from Linux 2.1 series tulip (ANK)
+	  plus Jamal's NETIF_RX_* feedback control.
+
+2001-05-14  Robert Olsson <Robert.Olsson@data.slu.se>
+
+	* Added support for 21143's Interrupt Mitigation.
+	  Jamal original instigator.
+
+2001-05-14  Robert Olsson <Robert.Olsson@data.slu.se>
+
+	* tulip_refill_rx prototype added to tulip.h
+
 2001-05-13  Jeff Garzik  <jgarzik@mandrakesoft.com>
 
 	* tulip_core.c: Remove HAS_PCI_MWI flag from Comet, untested.
diff -urN linux-2.4.5-pre3/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c
--- linux-2.4.5-pre3/drivers/net/tulip/interrupt.c	Fri Apr 20 11:54:22 2001
+++ linux/drivers/net/tulip/interrupt.c	Mon Dec  3 22:44:23 2001
@@ -22,6 +22,42 @@
 int tulip_rx_copybreak;
 unsigned int tulip_max_interrupt_work;
 
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+
+#define MIT_SIZE 15
+unsigned int mit_table[MIT_SIZE+1] =
+{
+        /*  CRS11 21143 hardware Mitigation Control Interrupt 
+            We use only RX mitigation we other techniques for 
+            TX intr. mitigation.
+
+           31    Cycle Size (timer control)
+           30:27 TX timer in 16 * Cycle size
+           26:24 TX No pkts before Int.
+           23:20 RX timer in Cycle size
+           19:17 RX No pkts before Int.
+           16       Continues Mode (CM)
+        */
+                         
+        0x0,             /* IM disabled */
+        0x80150000,      /* RX time = 1, RX pkts = 2, CM = 1 */
+        0x80150000,
+        0x80270000,
+        0x80370000,
+        0x80490000,
+        0x80590000,
+        0x80690000,
+        0x807B0000,
+        0x808B0000,
+        0x809D0000,
+        0x80AD0000,
+        0x80BD0000,
+        0x80CF0000,
+        0x80DF0000,
+//       0x80FF0000      /* RX time = 16, RX pkts = 7, CM = 1 */
+        0x80F10000      /* RX time = 16, RX pkts = 0, CM = 1 */
+};
+#endif
 
 
 int tulip_refill_rx(struct net_device *dev)
@@ -70,6 +106,15 @@
 	int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
 	int received = 0;
 
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+        int drop = 0, mit_sel = 0;
+
+/* that one buffer is needed for mit activation; or might be a 
+   bug in the ring buffer code; check later -- JHS*/
+
+        if (rx_work_limit >=RX_RING_SIZE) rx_work_limit--;
+#endif
+
 	if (tulip_debug > 4)
 		printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
 			   tp->rx_ring[entry].status);
@@ -116,6 +161,12 @@
 				tp->stats.rx_length_errors++;
 			}
 #endif
+
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+                        drop = atomic_read(&netdev_dropping);
+                        if (drop)
+                                goto throttle;
+#endif
 			/* Check if the packet is long enough to accept without copying
 			   to a minimally-sized skbuff. */
 			if (pkt_len < tulip_rx_copybreak
@@ -157,7 +208,44 @@
 				tp->rx_buffers[entry].mapping = 0;
 			}
 			skb->protocol = eth_type_trans(skb, dev);
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+                        mit_sel = 
+#endif
 			netif_rx(skb);
+
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+                        switch (mit_sel) {
+                        case NET_RX_SUCCESS:
+                        case NET_RX_CN_LOW:
+                        case NET_RX_CN_MOD:
+                                break;
+
+                        case NET_RX_CN_HIGH:
+                                rx_work_limit -= NET_RX_CN_HIGH; /* additional*/
+                                break;
+                        case NET_RX_DROP:
+                                rx_work_limit = -1;
+                                break;
+                        default:
+                                printk("unknown feedback return code %d\n", mit_sel);
+                                break;
+                        }
+
+                        drop = atomic_read(&netdev_dropping);
+                        if (drop) {
+throttle:
+                                rx_work_limit = -1;
+                                mit_sel = NET_RX_DROP;
+
+                                if (tp->fc_bit) {
+                                        long ioaddr = dev->base_addr;
+
+                                        /* disable Rx & RxNoBuf ints. */
+                                        outl(tulip_tbl[tp->chip_id].valid_intrs&RX_A_NBF_STOP, ioaddr + CSR7);
+                                        set_bit(tp->fc_bit, &netdev_fc_xoff);
+                                }
+                        }
+#endif
 			dev->last_rx = jiffies;
 			tp->stats.rx_packets++;
 			tp->stats.rx_bytes += pkt_len;
@@ -165,8 +253,41 @@
 		received++;
 		entry = (++tp->cur_rx) % RX_RING_SIZE;
 	}
+#ifdef CONFIG_NET_HW_FLOWCONTROL
 
+        /* We use this simplistic scheme for IM. It's proven by
+           real life installations. We can have IM enabled
+           continuesly but this would cause unnecessary latency. 
+           Unfortunely we can't use all the NET_RX_* feedback here. 
+           This would turn on IM for devices that is not contributing 
+           to backlog congestion with unnecessary latency. 
+
+           We monitor the the device RX-ring and have:
+
+           HW Interrupt Mitigation either ON or OFF.
+
+           ON:  More then 1 pkt received (per intr.) OR we are dropping 
+           OFF: Only 1 pkt received
+           
+           Note. We only use min and max (0, 15) settings from mit_table */
+
+
+        if( tp->flags &  HAS_INTR_MITIGATION) {
+                if((received > 1 || mit_sel == NET_RX_DROP) 
+                   && tp->mit_sel != 15 ) { 
+                        tp->mit_sel = 15; 
+                        tp->mit_change = 1; /* Force IM change */
+                }
+                if((received <= 1 && mit_sel != NET_RX_DROP) && tp->mit_sel != 0 ) {
+                        tp->mit_sel = 0; 
+                        tp->mit_change = 1; /* Force IM change */
+                }
+        }
+
+        return RX_RING_SIZE+1; /* maxrx+1 */      
+#else
 	return received;
+#endif
 }
 
 
@@ -205,8 +326,22 @@
 				   dev->name, csr5, inl(dev->base_addr + CSR5));
 
 		if (csr5 & (RxIntr | RxNoBuf)) {
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+                        if (tp->fc_bit) {
+                                if (test_bit(tp->fc_bit, &netdev_fc_xoff)) {
+                                        tulip_refill_rx(dev);
+                                } else {
+                                        tulip_refill_rx(dev);
+                                        rx += tulip_rx(dev);
+                                }
+                        } else {        /* not in fc mode */
+                                rx += tulip_rx(dev);
+                                tulip_refill_rx(dev);
+                        }
+#else
 			rx += tulip_rx(dev);
 			tulip_refill_rx(dev);
+#endif
 		}
 
 		if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
@@ -308,9 +443,17 @@
 				}
 			}
 			if (csr5 & RxDied) {		/* Missed a Rx frame. */
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+                                if (tp->fc_bit && !test_bit(tp->fc_bit, &netdev_fc_xoff)) {
+                                        tp->stats.rx_errors++;
+                                        tulip_outl_csr(tp, tp->csr6 | csr6_st | csr6_sr, CSR6);
+                                }
+                                tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+#else
 				tp->stats.rx_errors++;
 				tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
 				tulip_outl_csr(tp, tp->csr6 | csr6_st | csr6_sr, CSR6);
+#endif
 			}
 			/*
 			 * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this
@@ -344,6 +487,10 @@
 			if (tulip_debug > 2)
 				printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
 					   dev->name, csr5);
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+                        if (tp->fc_bit && (test_bit(tp->fc_bit, &netdev_fc_xoff)))
+                          if (net_ratelimit()) printk("BUG!! enabling interupt when FC off (timerintr.) \n");
+#endif
 			outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
 			tp->ttimer = 0;
 			oi++;
@@ -356,9 +503,16 @@
                        /* Acknowledge all interrupt sources. */
                         outl(0x8001ffff, ioaddr + CSR5);
                         if (tp->flags & HAS_INTR_MITIGATION) {
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+                                if(tp->mit_change) {
+                                        outl(mit_table[tp->mit_sel], ioaddr + CSR11);
+                                        tp->mit_change = 0;
+                                }
+#else
                      /* Josip Loncaric at ICASE did extensive experimentation
 			to develop a good interrupt mitigation setting.*/
                                 outl(0x8b240000, ioaddr + CSR11);
+#endif
                         } else if (tp->chip_id == LC82C168) {
 				/* the LC82C168 doesn't have a hw timer.*/
 				outl(0x00, ioaddr + CSR7);
@@ -366,8 +520,10 @@
 			} else {
                           /* Mask all interrupting sources, set timer to
 				re-enable. */
+#ifndef CONFIG_NET_HW_FLOWCONTROL
                                 outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7);
                                 outl(0x0012, ioaddr + CSR11);
+#endif
                         }
 			break;
 		}
diff -urN linux-2.4.5-pre3/drivers/net/tulip/pnic.c linux/drivers/net/tulip/pnic.c
--- linux-2.4.5-pre3/drivers/net/tulip/pnic.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/net/tulip/pnic.c	Mon Dec  3 22:44:23 2001
@@ -86,8 +86,6 @@
 	}
 }
 
-int tulip_refill_rx(struct net_device *dev);
-
 void pnic_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
diff -urN linux-2.4.5-pre3/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h
--- linux-2.4.5-pre3/drivers/net/tulip/tulip.h	Mon Dec  3 22:43:50 2001
+++ linux/drivers/net/tulip/tulip.h	Mon Dec  3 22:44:23 2001
@@ -345,6 +345,13 @@
 	spinlock_t mii_lock;
 	unsigned int cur_rx, cur_tx;	/* The next free ring entry */
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+#define RX_A_NBF_STOP 0xffffff3f /* To disable RX and RX-NOBUF ints. */
+        int fc_bit;
+        int mit_sel;
+        int mit_change; /* Signal for Interrupt Mitigtion */
+#endif
 	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
 	unsigned int full_duplex_lock:1;
 	unsigned int fake_addr:1;	/* Multiport board faked address. */
@@ -397,6 +404,7 @@
 extern unsigned int tulip_max_interrupt_work;
 extern int tulip_rx_copybreak;
 void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+int tulip_refill_rx(struct net_device *dev);
 
 /* media.c */
 int tulip_mdio_read(struct net_device *dev, int phy_id, int location);
diff -urN linux-2.4.5-pre3/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c
--- linux-2.4.5-pre3/drivers/net/tulip/tulip_core.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/net/tulip/tulip_core.c	Mon Dec  3 22:44:23 2001
@@ -14,6 +14,10 @@
 
 */
 
+#define DRV_NAME	"tulip"
+#define DRV_VERSION	"0.9.15-pre2"
+#define DRV_RELDATE	"May 16, 2001"
+
 #include <linux/module.h>
 #include "tulip.h"
 #include <linux/pci.h>
@@ -21,10 +25,12 @@
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
 #include <linux/mii.h>
+#include <linux/ethtool.h>
 #include <asm/unaligned.h>
+#include <asm/uaccess.h>
 
 static char version[] __devinitdata =
-	"Linux Tulip driver version 0.9.15-pre1 (May 12, 2001)\n";
+	"Linux Tulip driver version " DRV_VERSION " (" DRV_RELDATE ")\n";
 
 
 /* A few user-configurable values. */
@@ -101,8 +107,7 @@
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 
-#define TULIP_MODULE_NAME "tulip"
-#define PFX TULIP_MODULE_NAME ": "
+#define PFX DRV_NAME ": "
 
 #ifdef TULIP_DEBUG
 int tulip_debug = TULIP_DEBUG;
@@ -472,10 +477,27 @@
 	add_timer(&tp->timer);
 }
 
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+/* Enable receiver */
+void tulip_xon(struct net_device *dev)
+{
+        struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+        clear_bit(tp->fc_bit, &netdev_fc_xoff);
+        if (netif_running(dev)){
+
+                tulip_refill_rx(dev);
+                outl(tulip_tbl[tp->chip_id].valid_intrs,  dev->base_addr+CSR7);
+        }
+}
+#endif
 
 static int
 tulip_open(struct net_device *dev)
 {
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+        struct tulip_private *tp = (struct tulip_private *)dev->priv;
+#endif
 	int retval;
 	MOD_INC_USE_COUNT;
 
@@ -488,6 +510,10 @@
 
 	tulip_up (dev);
 
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+        tp->fc_bit = netdev_register_fc(dev, tulip_xon);
+#endif
+
 	netif_start_queue (dev);
 
 	return 0;
@@ -595,6 +621,10 @@
 #endif
 
 	/* Stop and restart the chip's Tx processes . */
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+        if (tp->fc_bit && test_bit(tp->fc_bit,&netdev_fc_xoff))
+                printk("BUG tx_timeout restarting rx when fc on\n");
+#endif
 	tulip_restart_rxtx(tp, tp->csr6);
 	/* Trigger an immediate transmit demand. */
 	outl(0, ioaddr + CSR1);
@@ -751,6 +781,13 @@
 
 	netif_stop_queue (dev);
 
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+        if (tp->fc_bit) {
+                int bit = tp->fc_bit;
+                tp->fc_bit = 0;
+                netdev_unregister_fc(bit);
+        }
+#endif
 	tulip_down (dev);
 
 	if (tulip_debug > 1)
@@ -812,6 +849,30 @@
 }
 
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct tulip_private *np = dev->priv;
+	u32 ethcmd;
+		
+	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, np->pdev->slot_name);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+        }
+	
+	return -EOPNOTSUPP;
+}
+
 /* Provide ioctl() calls to examine the MII xcvr state. */
 static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -823,6 +884,8 @@
 	unsigned int regnum = data[1];
 
 	switch (cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
 		if (tp->mii_cnt)
 			data[0] = phy;
@@ -1685,7 +1748,7 @@
 
 
 static struct pci_driver tulip_driver = {
-	name:		TULIP_MODULE_NAME,
+	name:		DRV_NAME,
 	id_table:	tulip_pci_tbl,
 	probe:		tulip_init_one,
 	remove:		tulip_remove_one,
diff -urN linux-2.4.5-pre3/drivers/parport/BUGS-parport linux/drivers/parport/BUGS-parport
--- linux-2.4.5-pre3/drivers/parport/BUGS-parport	Mon Jun 19 13:42:38 2000
+++ linux/drivers/parport/BUGS-parport	Mon Dec  3 22:44:23 2001
@@ -3,4 +3,7 @@
 o lp doesn't allow you to read status while printing is in progress (is
   this still true?).
 
+o parport_pc_ecp_read_block_pio() is broken.  parport will revert to the
+  software-driven mode in ieee1284_ops.c
+
 See <URL:http://people.redhat.com/twaugh/parport/>.
diff -urN linux-2.4.5-pre3/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog
--- linux-2.4.5-pre3/drivers/parport/ChangeLog	Fri Apr 20 16:23:12 2001
+++ linux/drivers/parport/ChangeLog	Mon Dec  3 22:44:23 2001
@@ -1,3 +1,33 @@
+ 2001-05-10  Fred Barnes  <frmb2@ukc.ac.uk>
+
+       * parport_pc.c (parport_pc_epp_read_data): added support for
+       reading from a w91284pic peripheral, flag is PARPORT_W91284PIC.
+
+2001-05-07  Fred Barnes  <frmb2@ukc.ac.uk>
+ 
+ 	* parport_pc.c (parport_pc_epp_read_data,
+	parport_pc_epp_write_data, parport_pc_epp_read_addr,
+	parport_pc_epp_write_addr): support for fast reads/writes using
+	the PARPORT_EPP_FAST flag.
+ 
+ 	* ieee1284.c (parport_read, parport_write): added code to handle
+	software EPP mode (IEEE1284_MODE_EPPSWE).  Added code to allow
+	BYTE mode reverse transfers (previously always went for NIBBLE
+	mode).
+ 
+ 	* ieee1284_ops.c (parport_ieee1284_epp_read_data,
+	parport_ieee1284_epp_write_data): fixed various polarity problems.
+	Also (theoretically) fixed address versions (.._addr), but no
+	hardware to test this on.
+ 
+ 	* parport_pc.h: added parport_dump_state() function for debugging.
+ 	Needs to have DEBUG_PARPORT to be defined for it to be included.
+ 
+2001-05-03  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c: Fix the compile problem I introduce from the last
+	change.
+
 2001-04-20  Paul Gortmaker  <p_gortmaker@yahoo.com>
 
 	* parport_pc.c: Cut down the size quite a bit (more than 4k off
diff -urN linux-2.4.5-pre3/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c
--- linux-2.4.5-pre3/drivers/parport/ieee1284.c	Thu Jan  4 13:00:55 2001
+++ linux/drivers/parport/ieee1284.c	Mon Dec  3 22:44:23 2001
@@ -12,6 +12,8 @@
  * Any part of this program may be used in documents licensed under
  * the GNU Free Documentation License, Version 1.1 or any later version
  * published by the Free Software Foundation.
+ *
+ * Various hacks, Fred Barnes <frmb2@ukc.ac.uk>, 04/2000
  */
 
 #include <linux/config.h>
@@ -523,9 +525,10 @@
 		r = parport_wait_peripheral (port,
 					     PARPORT_STATUS_PAPEROUT,
 					     PARPORT_STATUS_PAPEROUT);
-		if (r)
+		if (r) {
 			DPRINTK (KERN_INFO "%s: Timeout at event 31\n",
-				 port->name);
+				port->name);
+		}
 
 		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
 		DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
@@ -614,6 +617,7 @@
 	/* Use the mode we're in. */
 	switch (mode) {
 	case IEEE1284_MODE_NIBBLE:
+	case IEEE1284_MODE_BYTE:
 		parport_negotiate (port, IEEE1284_MODE_COMPAT);
 	case IEEE1284_MODE_COMPAT:
 		DPRINTK (KERN_DEBUG "%s: Using compatibility mode\n",
@@ -623,19 +627,29 @@
 
 	case IEEE1284_MODE_EPP:
 		DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
-		if (addr)
+		if (addr) {
 			fn = port->ops->epp_write_addr;
-		else
+		} else {
 			fn = port->ops->epp_write_data;
+		}
+		break;
+	case IEEE1284_MODE_EPPSWE:
+		DPRINTK (KERN_DEBUG "%s: Using software-emulated EPP mode\n",
+			port->name);
+		if (addr) {
+			fn = parport_ieee1284_epp_write_addr;
+		} else {
+			fn = parport_ieee1284_epp_write_data;
+		}
 		break;
-
 	case IEEE1284_MODE_ECP:
 	case IEEE1284_MODE_ECPRLE:
 		DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
-		if (addr)
+		if (addr) {
 			fn = port->ops->ecp_write_addr;
-		else
+		} else {
 			fn = port->ops->ecp_write_data;
+		}
 		break;
 
 	case IEEE1284_MODE_ECPSWE:
@@ -643,10 +657,11 @@
 			 port->name);
 		/* The caller has specified that it must be emulated,
 		 * even if we have ECP hardware! */
-		if (addr)
+		if (addr) {
 			fn = parport_ieee1284_ecp_write_addr;
-		else
+		} else {
 			fn = parport_ieee1284_ecp_write_data;
+		}
 		break;
 
 	default:
@@ -656,8 +671,7 @@
 	}
 
 	retval = (*fn) (port, buffer, len, 0);
-	DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval,
-		 len);
+	DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval, len);
 	return retval;
 #endif /* IEEE1284 support */
 }
@@ -696,8 +710,22 @@
 	/* Use the mode we're in. */
 	switch (mode) {
 	case IEEE1284_MODE_COMPAT:
-		if (parport_negotiate (port, IEEE1284_MODE_NIBBLE))
+		/* if we can tri-state use BYTE mode instead of NIBBLE mode,
+		 * if that fails, revert to NIBBLE mode -- ought to store somewhere
+		 * the device's ability to do BYTE mode reverse transfers, so we don't
+		 * end up needlessly calling negotiate(BYTE) repeately..  (fb)
+		 */
+		if ((port->physport->modes & PARPORT_MODE_TRISTATE) &&
+		    !parport_negotiate (port, IEEE1284_MODE_BYTE)) {
+			/* got into BYTE mode OK */
+			DPRINTK (KERN_DEBUG "%s: Using byte mode\n", port->name);
+			fn = port->ops->byte_read_data;
+			break;
+		}
+		if (parport_negotiate (port, IEEE1284_MODE_NIBBLE)) {
 			return -EIO;
+		}
+		/* fall through to NIBBLE */
 	case IEEE1284_MODE_NIBBLE:
 		DPRINTK (KERN_DEBUG "%s: Using nibble mode\n", port->name);
 		fn = port->ops->nibble_read_data;
@@ -710,12 +738,21 @@
 
 	case IEEE1284_MODE_EPP:
 		DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
-		if (addr)
+		if (addr) {
 			fn = port->ops->epp_read_addr;
-		else
+		} else {
 			fn = port->ops->epp_read_data;
+		}
+		break;
+	case IEEE1284_MODE_EPPSWE:
+		DPRINTK (KERN_DEBUG "%s: Using software-emulated EPP mode\n",
+			port->name);
+		if (addr) {
+			fn = parport_ieee1284_epp_read_addr;
+		} else {
+			fn = parport_ieee1284_epp_read_data;
+		}
 		break;
-
 	case IEEE1284_MODE_ECP:
 	case IEEE1284_MODE_ECPRLE:
 		DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
diff -urN linux-2.4.5-pre3/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c
--- linux-2.4.5-pre3/drivers/parport/ieee1284_ops.c	Fri Mar  2 18:43:03 2001
+++ linux/drivers/parport/ieee1284_ops.c	Mon Dec  3 22:44:23 2001
@@ -10,6 +10,7 @@
  *
  * Author: Tim Waugh <tim@cyberelk.demon.co.uk>
  * Fixed AUTOFD polarity in ecp_forward_to_reverse().  Fred Barnes, 1999
+ * Software emulated EPP fixes, Fred Barnes, 04/2001.
  */
 
 
@@ -18,7 +19,7 @@
 #include <linux/delay.h>
 #include <asm/uaccess.h>
 
-#define DEBUG /* undef me for production */
+#undef DEBUG /* undef me for production */
 
 #ifdef CONFIG_LP_CONSOLE
 #undef DEBUG /* Don't want a garbled console */
@@ -725,31 +726,32 @@
 					const void *buffer, size_t len,
 					int flags)
 {
-	/* This is untested */
 	unsigned char *bp = (unsigned char *) buffer;
 	size_t ret = 0;
 
+	/* set EPP idle state (just to make sure) with strobe low */
 	parport_frob_control (port,
 			      PARPORT_CONTROL_STROBE |
 			      PARPORT_CONTROL_AUTOFD |
-			      PARPORT_CONTROL_SELECT,
+			      PARPORT_CONTROL_SELECT |
+			      PARPORT_CONTROL_INIT,
 			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_SELECT);
+			      PARPORT_CONTROL_INIT);
 	port->ops->data_forward (port);
 	for (; len > 0; len--, bp++) {
-		/* Event 62: Write data and strobe data */
+		/* Event 62: Write data and set autofd low */
 		parport_write_data (port, *bp);
 		parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
 				      PARPORT_CONTROL_AUTOFD);
 
-		/* Event 58 */
+		/* Event 58: wait for busy (nWait) to go high */
 		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10))
 			break;
 
-		/* Event 63 */
+		/* Event 63: set nAutoFd (nDStrb) high */
 		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
 
-		/* Event 60 */
+		/* Event 60: wait for busy (nWait) to go low */
 		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
 					     PARPORT_STATUS_BUSY, 5))
 			break;
@@ -757,7 +759,7 @@
 		ret++;
 	}
 
-	/* Event 61 */
+	/* Event 61: set strobe (nWrite) high */
 	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
 
 	return ret;
@@ -768,29 +770,37 @@
 				       void *buffer, size_t len,
 				       int flags)
 {
-	/* This is untested. */
 	unsigned char *bp = (unsigned char *) buffer;
 	unsigned ret = 0;
 
+	/* set EPP idle state (just to make sure) with strobe high */
 	parport_frob_control (port,
 			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_SELECT, 0);
+			      PARPORT_CONTROL_AUTOFD |
+			      PARPORT_CONTROL_SELECT |
+			      PARPORT_CONTROL_INIT,
+			      PARPORT_CONTROL_INIT);
 	port->ops->data_reverse (port);
 	for (; len > 0; len--, bp++) {
-		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-
-		/* Event 58 */
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY, 10))
+		/* Event 67: set nAutoFd (nDStrb) low */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+		/* Event 58: wait for Busy to go high */
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) {
 			break;
+		}
 
 		*bp = parport_read_data (port);
 
-		parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
-				      PARPORT_CONTROL_AUTOFD);
+		/* Event 63: set nAutoFd (nDStrb) high */
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
 
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5))
+		/* Event 60: wait for Busy to go low */
+		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY, 5)) {
 			break;
+		}
 
 		ret++;
 	}
@@ -873,3 +883,5 @@
 
 	return ret;
 }
+
+
diff -urN linux-2.4.5-pre3/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- linux-2.4.5-pre3/drivers/parport/parport_pc.c	Fri Apr 20 16:23:12 2001
+++ linux/drivers/parport/parport_pc.c	Mon Dec  3 22:44:23 2001
@@ -12,6 +12,7 @@
  * DMA support - Bert De Jonghe <bert@sophis.be>
  * Many ECP bugs fixed.  Fred Barnes & Jamie Lokier, 1999
  * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. 
+ * Various hacks, Fred Barnes, 04/2001
  */
 
 /* This driver should work with any hardware that is broadly compatible
@@ -211,6 +212,7 @@
 	/* Back to PS2 mode. */
 	frob_econtrol (p, 0xe0, ECR_PS2 << 5);
 
+	DPRINTK (KERN_DEBUG "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n", inb (ECONTROL (p)));
 	return residue;
 }
 #endif /* IEEE 1284 support */
@@ -367,9 +369,60 @@
 					size_t length, int flags)
 {
 	size_t got = 0;
+
+	if (flags & PARPORT_W91284PIC) {
+		unsigned char status;
+		size_t left = length;
+
+		/* use knowledge about data lines..:
+		 *  nFault is 0 if there is at least 1 byte in the Warp's FIFO
+		 *  pError is 1 if there are 16 bytes in the Warp's FIFO
+		 */
+		status = inb (STATUS (port));
+
+		while (!(status & 0x08) && (got < length)) {
+			if ((left >= 16) && (status & 0x20) && !(status & 0x08)) {
+				/* can grab 16 bytes from warp fifo */
+				if (!((long)buf & 0x03)) {
+					insl (EPPDATA (port), buf, 4);
+				} else {
+					insb (EPPDATA (port), buf, 16);
+				}
+				buf += 16;
+				got += 16;
+				left -= 16;
+			} else {
+				/* grab single byte from the warp fifo */
+				*((char *)buf)++ = inb (EPPDATA (port));
+				got++;
+				left--;
+			}
+			status = inb (STATUS (port));
+			if (status & 0x01) {
+				/* EPP timeout should never occur... */
+				printk (KERN_DEBUG "%s: EPP timeout occured while talking to "
+					"w91284pic (should not have done)\n", port->name);
+				clear_epp_timeout (port);
+			}
+		}
+		return got;
+	}
+	if ((flags & PARPORT_EPP_FAST) && (length > 1)) {
+		if (!(((long)buf | length) & 0x03)) {
+			insl (EPPDATA (port), buf, (length >> 2));
+		} else {
+			insb (EPPDATA (port), buf, length);
+		}
+		if (inb (STATUS (port)) & 0x01) {
+			clear_epp_timeout (port);
+			return -EIO;
+		}
+		return length;
+	}
 	for (; got < length; got++) {
 		*((char*)buf)++ = inb (EPPDATA(port));
-		if (inb (STATUS(port)) & 0x01) {
+		if (inb (STATUS (port)) & 0x01) {
+			/* EPP timeout */
 			clear_epp_timeout (port);
 			break;
 		}
@@ -382,6 +435,19 @@
 					 size_t length, int flags)
 {
 	size_t written = 0;
+
+	if ((flags & PARPORT_EPP_FAST) && (length > 1)) {
+		if (!(((long)buf | length) & 0x03)) {
+			outsl (EPPDATA (port), buf, (length >> 2));
+		} else {
+			outsb (EPPDATA (port), buf, length);
+		}
+		if (inb (STATUS (port)) & 0x01) {
+			clear_epp_timeout (port);
+			return -EIO;
+		}
+		return length;
+	}
 	for (; written < length; written++) {
 		outb (*((char*)buf)++, EPPDATA(port));
 		if (inb (STATUS(port)) & 0x01) {
@@ -397,6 +463,15 @@
 					size_t length, int flags)
 {
 	size_t got = 0;
+
+	if ((flags & PARPORT_EPP_FAST) && (length > 1)) {
+		insb (EPPADDR (port), buf, length);
+		if (inb (STATUS (port)) & 0x01) {
+			clear_epp_timeout (port);
+			return -EIO;
+		}
+		return length;
+	}
 	for (; got < length; got++) {
 		*((char*)buf)++ = inb (EPPADDR (port));
 		if (inb (STATUS (port)) & 0x01) {
@@ -413,6 +488,15 @@
 					 int flags)
 {
 	size_t written = 0;
+
+	if ((flags & PARPORT_EPP_FAST) && (length > 1)) {
+		outsb (EPPADDR (port), buf, length);
+		if (inb (STATUS (port)) & 0x01) {
+			clear_epp_timeout (port);
+			return -EIO;
+		}
+		return length;
+	}
 	for (; written < length; written++) {
 		outb (*((char*)buf)++, EPPADDR (port));
 		if (inb (STATUS (port)) & 0x01) {
@@ -500,7 +584,8 @@
 
 	/* We don't want to be interrupted every character. */
 	parport_pc_disable_irq (port);
-	frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
+	/* set nErrIntrEn and serviceIntr */
+	frob_econtrol (port, (1<<4) | (1<<2), (1<<4) | (1<<2));
 
 	/* Forward mode. */
 	parport_pc_data_forward (port); /* Must be in PS2 mode */
@@ -575,6 +660,7 @@
 		left--;
         }
 
+dump_parport_state ("leave fifo_write_block_dma", port);
 	return length - left;
 }
 
@@ -590,6 +676,7 @@
 	unsigned long start = (unsigned long) buf;
 	unsigned long end = (unsigned long) buf + length - 1;
 
+dump_parport_state ("enter fifo_write_block_dma", port);
 	if (end < MAX_DMA_ADDRESS) {
 		/* If it would cross a 64k boundary, cap it at the end. */
 		if ((start ^ end) & ~0xffffUL)
@@ -608,7 +695,8 @@
 
 	/* We don't want to be interrupted every character. */
 	parport_pc_disable_irq (port);
-	frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
+	/* set nErrIntrEn and serviceIntr */
+	frob_econtrol (port, (1<<4) | (1<<2), (1<<4) | (1<<2));
 
 	/* Forward mode. */
 	parport_pc_data_forward (port); /* Must be in PS2 mode */
@@ -698,6 +786,7 @@
 	if (dma_handle)
 		pci_unmap_single(priv->dev, dma_handle, length, PCI_DMA_TODEVICE);
 
+dump_parport_state ("leave fifo_write_block_dma", port);
 	return length - left;
 }
 
@@ -740,10 +829,10 @@
 
 		/* Adjust for the contents of the FIFO. */
 		for (written -= priv->fifo_depth; ; written++) {
-			if (inb (ECONTROL (port)) & 0x2)
+			if (inb (ECONTROL (port)) & 0x2) {
 				/* Full up. */
 				break;
-
+			}
 			outb (0, FIFO (port));
 		}
 
@@ -791,9 +880,10 @@
 		r = parport_wait_peripheral (port,
 					     PARPORT_STATUS_PAPEROUT,
 					     PARPORT_STATUS_PAPEROUT);
-		if (r)
+		if (r) {
 			printk (KERN_DEBUG "%s: PError timeout (%d) "
 				"in ecp_write_block_pio\n", port->name, r);
+		}
 	}
 
 	/* Set up ECP parallel port mode.*/
@@ -824,10 +914,10 @@
 
 		/* Adjust for the contents of the FIFO. */
 		for (written -= priv->fifo_depth; ; written++) {
-			if (inb (ECONTROL (port)) & 0x2)
+			if (inb (ECONTROL (port)) & 0x2) {
 				/* Full up. */
 				break;
-
+			}
 			outb (0, FIFO (port));
 		}
 
@@ -879,58 +969,99 @@
 	char *bufp = buf;
 
 	port = port->physport;
+DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n");
+dump_parport_state ("enter fcn", port);
 
 	/* Special case: a timeout of zero means we cannot call schedule(). */
 	if (!port->cad->timeout)
 		return parport_ieee1284_ecp_read_data (port, buf,
 						       length, flags);
 
-	fifofull = fifo_depth;
-	if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE)
+	if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) {
 		/* If the peripheral is allowed to send RLE compressed
 		 * data, it is possible for a byte to expand to 128
 		 * bytes in the FIFO. */
 		fifofull = 128;
+	} else {
+		fifofull = fifo_depth;
+	}
 
 	/* If the caller wants less than a full FIFO's worth of data,
-	 * go through software emulation.  Otherwise we may have to through
+	 * go through software emulation.  Otherwise we may have to throw
 	 * away data. */
 	if (length < fifofull)
 		return parport_ieee1284_ecp_read_data (port, buf,
 						       length, flags);
 
-	/* Switch to reverse mode if necessary. */
-	if ((port->ieee1284.phase != IEEE1284_PH_REV_IDLE) &&
-	    (port->ieee1284.phase != IEEE1284_PH_REV_DATA)) {
-		/* Event 38: Set nAutoFd low */
+	if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
+		/* change to reverse-idle phase (must be in forward-idle) */
+
+		/* Event 38: Set nAutoFd low (also make sure nStrobe is high) */
 		parport_frob_control (port,
-				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD
+				      | PARPORT_CONTROL_STROBE,
 				      PARPORT_CONTROL_AUTOFD);
 		parport_pc_data_reverse (port); /* Must be in PS2 mode */
 		udelay (5);
-
 		/* Event 39: Set nInit low to initiate bus reversal */
 		parport_frob_control (port,
 				      PARPORT_CONTROL_INIT,
 				      0);
-
-		/* Event 40: PError goes low */
+		/* Event 40: Wait for  nAckReverse (PError) to go low */
 		r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
-                if (r)
+                if (r) {
                         printk (KERN_DEBUG "%s: PE timeout Event 40 (%d) "
 				"in ecp_read_block_pio\n", port->name, r);
+			return 0;
+		}
 	}
 
 	/* Set up ECP FIFO mode.*/
-	parport_pc_data_reverse (port); /* Must be in PS2 mode */
-	parport_pc_frob_control (port,
+/*	parport_pc_frob_control (port,
 				 PARPORT_CONTROL_STROBE |
 				 PARPORT_CONTROL_AUTOFD,
-				 0);
+				 PARPORT_CONTROL_AUTOFD); */
 	r = change_mode (port, ECR_ECP); /* ECP FIFO */
 	if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name);
+
 	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
 
+	/* the first byte must be collected manually */
+dump_parport_state ("pre 43", port);
+	/* Event 43: Wait for nAck to go low */
+	r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0);
+	if (r) {
+		/* timed out while reading -- no data */
+		printk (KERN_DEBUG "PIO read timed out (initial byte)\n");
+		goto out_no_data;
+	}
+	/* read byte */
+	*bufp++ = inb (DATA (port));
+	left--;
+dump_parport_state ("43-44", port);
+	/* Event 44: nAutoFd (HostAck) goes high to acknowledge */
+	parport_pc_frob_control (port,
+				 PARPORT_CONTROL_AUTOFD,
+				 0);
+dump_parport_state ("pre 45", port);
+	/* Event 45: Wait for nAck to go high */
+/*	r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK); */
+dump_parport_state ("post 45", port);
+r = 0;
+	if (r) {
+		/* timed out while waiting for peripheral to respond to ack */
+		printk (KERN_DEBUG "ECP PIO read timed out (waiting for nAck)\n");
+
+		/* keep hold of the byte we've got already */
+		goto out_no_data;
+	}
+	/* Event 46: nAutoFd (HostAck) goes low to accept more data */
+	parport_pc_frob_control (port,
+				 PARPORT_CONTROL_AUTOFD,
+				 PARPORT_CONTROL_AUTOFD);
+
+
+dump_parport_state ("rev idle", port);
 	/* Do the transfer. */
 	while (left > fifofull) {
 		int ret;
@@ -949,31 +1080,35 @@
 
 		if (ecrval & 0x01) {
 			/* FIFO is empty. Wait for interrupt. */
+dump_parport_state ("FIFO empty", port);
 
 			/* Anyone else waiting for the port? */
 			if (port->waithead) {
-				printk (KERN_DEBUG
-					"Somebody wants the port\n");
+				printk (KERN_DEBUG "Somebody wants the port\n");
 				break;
 			}
 
 			/* Clear serviceIntr */
 			outb (ecrval & ~(1<<2), ECONTROL (port));
 		false_alarm:
+dump_parport_state ("waiting", port);
 			ret = parport_wait_event (port, HZ);
-			if (ret < 0) break;
+DPRINTK (KERN_DEBUG "parport_wait_event returned %d\n", ret);
+			if (ret < 0)
+				break;
 			ret = 0;
 			if (!time_before (jiffies, expire)) {
 				/* Timed out. */
+dump_parport_state ("timeout", port);
 				printk (KERN_DEBUG "PIO read timed out\n");
 				break;
 			}
 			ecrval = inb (ECONTROL (port));
 			if (!(ecrval & (1<<2))) {
 				if (current->need_resched &&
-				    time_before (jiffies, expire))
+				    time_before (jiffies, expire)) {
 					schedule ();
-
+				}
 				goto false_alarm;
 			}
 
@@ -986,12 +1121,15 @@
 
 		if (ecrval & 0x02) {
 			/* FIFO is full. */
+dump_parport_state ("FIFO full", port);
 			insb (fifo, bufp, fifo_depth);
 			bufp += fifo_depth;
 			left -= fifo_depth;
 			continue;
 		}
 
+DPRINTK (KERN_DEBUG "*** ecp_read_block_pio: reading one byte from the FIFO\n");
+
 		/* FIFO not filled.  We will cycle this loop for a while
                  * and either the peripheral will fill it faster,
                  * tripping a fast empty with insb, or we empty it. */
@@ -999,17 +1137,29 @@
 		left--;
 	}
 
+	/* scoop up anything left in the FIFO */
+	while (left && !(inb (ECONTROL (port) & 0x01))) {
+		*bufp++ = inb (fifo);
+		left--;
+	}
+
 	port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+dump_parport_state ("rev idle2", port);
+
+out_no_data:
+
+	/* Go to forward idle mode to shut the peripheral up (event 47). */
+	parport_frob_control (port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
 
-	/* Go to forward idle mode to shut the peripheral up. */
-	parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+	/* event 49: PError goes high */
 	r = parport_wait_peripheral (port,
 				     PARPORT_STATUS_PAPEROUT,
 				     PARPORT_STATUS_PAPEROUT);
-	if (r)
+	if (r) {
 		printk (KERN_DEBUG
 			"%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n",
 			port->name, r);
+	}
 
 	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
 
@@ -1022,13 +1172,21 @@
 				port->name, lost);
 	}
 
+dump_parport_state ("fwd idle", port);
 	return length - left;
 }
 
 #endif /* IEEE 1284 support */
-
 #endif /* Allowed to use FIFO/DMA */
 
+
+/*
+ *	******************************************
+ *	INITIALISATION AND MODULE STUFF BELOW HERE
+ *	******************************************
+ */
+
+
 void parport_pc_inc_use_count(void)
 {
 #ifdef MODULE
@@ -1756,17 +1914,19 @@
 	 */
 
 	/* If EPP timeout bit clear then EPP available */
-	if (!clear_epp_timeout(pb))
+	if (!clear_epp_timeout(pb)) {
 		return 0;  /* No way to clear timeout */
+	}
 
 	/* Check for Intel bug. */
 	if (priv->ecr) {
 		unsigned char i;
 		for (i = 0x00; i < 0x80; i += 0x20) {
 			outb (i, ECONTROL (pb));
-			if (clear_epp_timeout (pb))
+			if (clear_epp_timeout (pb)) {
 				/* Phony EPP in ECP. */
 				return 0;
+			}
 		}
 	}
 
@@ -1787,8 +1947,9 @@
 	int result;
 	unsigned char oecr;
 
-	if (!priv->ecr)
+	if (!priv->ecr) {
 		return 0;
+	}
 
 	oecr = inb (ECONTROL (pb));
 	/* Search for SMC style EPP+ECP mode */
@@ -1930,10 +2091,11 @@
 		pb->irq = programmable_irq_support(pb);
 	}
 
-	if (pb->modes & PARPORT_MODE_ECP)
+	if (pb->modes & PARPORT_MODE_ECP) {
 		pb->irq = irq_probe_ECP(pb);
+	}
 
-	if (pb->irq == PARPORT_IRQ_NONE && priv->ecr &&
+	if ((pb->irq == PARPORT_IRQ_NONE) && priv->ecr &&
 	    (pb->modes & PARPORT_MODE_EPP))
 		pb->irq = irq_probe_EPP(pb);
 
@@ -1978,11 +2140,12 @@
 	const struct parport_pc_private *priv = p->private_data;
 	if (priv->ecr)
 		p->dma = programmable_dma_support(p); /* ask ECP chipset first */
-	if (p->dma == PARPORT_DMA_NONE)
+	if (p->dma == PARPORT_DMA_NONE) {
 		/* ask known Super-IO chips proper, although these
 		   claim ECP compatible, some don't report their DMA
 		   conforming to ECP standards */
 		p->dma = get_superio_dma(p);
+	}
 
 	return p->dma;
 }
@@ -2092,6 +2255,8 @@
 		p->ops->compat_write_data = parport_pc_compat_write_block_pio;
 #ifdef CONFIG_PARPORT_1284
 		p->ops->ecp_write_data = parport_pc_ecp_write_block_pio;
+		/* currently broken, but working on it.. (FB) */
+		/* p->ops->ecp_read_data = parport_pc_ecp_read_block_pio; */
 #endif /* IEEE 1284 support */
 		if (p->dma != PARPORT_DMA_NONE) {
 			printk(", dma %d", p->dma);
@@ -2576,7 +2741,7 @@
 }
 #else
 static struct pci_driver parport_pc_pci_driver;
-static int __init parport_pc_init_superio(void) {return 0;}
+static int __init parport_pc_init_superio(int autoirq, int autodma) {return 0;}
 #endif /* CONFIG_PCI */
 
 /* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */
diff -urN linux-2.4.5-pre3/drivers/pci/Makefile linux/drivers/pci/Makefile
--- linux-2.4.5-pre3/drivers/pci/Makefile	Fri Apr 13 20:31:32 2001
+++ linux/drivers/pci/Makefile	Mon Dec  3 22:44:23 2001
@@ -22,6 +22,7 @@
 obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
 obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
 obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
+obj-$(CONFIG_ALL_PPC) += setup-bus.o
 
 ifndef CONFIG_X86
 obj-y += syscall.o
diff -urN linux-2.4.5-pre3/drivers/pci/pci.c linux/drivers/pci/pci.c
--- linux-2.4.5-pre3/drivers/pci/pci.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/pci/pci.c	Mon Dec  3 22:44:23 2001
@@ -1700,8 +1700,11 @@
 	set_bit (block, &page->bitmap [map]);
 	if (waitqueue_active (&pool->waitq))
 		wake_up (&pool->waitq);
-	else if (!is_page_busy (pool->blocks_per_page, page->bitmap))
-		pool_free_page (pool, page);
+	/*
+	 * Resist a temptation to do
+	 *    if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
+	 * it is not interrupt safe. Better have empty pages hang around.
+	 */
 	spin_unlock_irqrestore (&pool->lock, flags);
 }
 
diff -urN linux-2.4.5-pre3/drivers/pci/pci.ids linux/drivers/pci/pci.ids
--- linux-2.4.5-pre3/drivers/pci/pci.ids	Sun Mar 25 18:14:20 2001
+++ linux/drivers/pci/pci.ids	Mon Dec  3 22:44:23 2001
@@ -1069,6 +1069,13 @@
 	000e  Hydra Mac I/O
 	0010  Heathrow Mac I/O
 	0017  Paddington Mac I/O
+	0018  UniNorth FireWire
+	0019  KeyLargo USB
+	001e  UniNorth PCI
+	001f  UniNorth PCI
+	0020  UniNorth AGP
+	0021  UniNorth GMAC
+	0022  KeyLargo Mac I/O
 106c  Hyundai Electronics America
 	8801  Dual Pentium ISA/PCI Motherboard
 	8802  PowerPC ISA/PCI Motherboard
diff -urN linux-2.4.5-pre3/drivers/pci/proc.c linux/drivers/pci/proc.c
--- linux-2.4.5-pre3/drivers/pci/proc.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/pci/proc.c	Mon Dec  3 22:44:23 2001
@@ -245,6 +245,9 @@
 	struct pci_filp_private *fpriv = file->private_data;
 	int ret;
 
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
 	ret = pci_mmap_page_range(dev, vma,
 				  fpriv->mmap_state,
 				  fpriv->write_combine);
diff -urN linux-2.4.5-pre3/drivers/pci/quirks.c linux/drivers/pci/quirks.c
--- linux-2.4.5-pre3/drivers/pci/quirks.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/pci/quirks.c	Mon Dec  3 22:44:23 2001
@@ -32,7 +32,7 @@
 	while ((d = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) {
 		pci_read_config_byte(d, 0x82, &dlc);
 		if (!(dlc & 1<<1)) {
-			printk("PCI: PIIX3: Enabling Passive Release on %s\n", d->slot_name);
+			printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", d->slot_name);
 			dlc |= 1<<1;
 			pci_write_config_byte(d, 0x82, dlc);
 		}
@@ -89,23 +89,44 @@
  *	VIA Apollo KT133 needs PCI latency patch
  *	Made according to a windows driver based patch by George E. Breese
  *	see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm
+ *      Also see http://home.tiscalinet.de/au-ja/review-kt133a-1-en.html for
+ *      the info on which Mr Breese based his work.
  */
 static void __init quirk_vialatency(struct pci_dev *dev)
 {
 	u8 r70;
-
-	printk(KERN_INFO "Applying VIA PCI latency patch.\n");
-	/*
-	 *    In register 0x70, mask off bit 2 (PCI Master read caching)
-	 *    and 1 (Delay Transaction)
-	 */
-	pci_read_config_byte(dev, 0x70, &r70);
-	r70 &= 0xf9;
-	pci_write_config_byte(dev, 0x70, r70);
-	/*
-	 *    Turn off PCI Latency timeout (set to 0 clocks)
+	u8 rev;
+	struct pci_dev *vt82c686;
+   
+   
+	/* we want to look for a VT82C686 south bridge, and then apply the via latency
+	 * patch if we find that it's a 686B (by revision) <cpbotha@ieee.org>
 	 */
-	pci_write_config_byte(dev, 0x75, 0x80);
+	vt82c686 = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL);
+	if (vt82c686)   
+     	{
+		pci_read_config_byte(vt82c686, PCI_CLASS_REVISION, &rev);
+        	/* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */
+		if (rev >= 0x40 && rev <= 0x4f)
+		{
+        		printk(KERN_INFO "Applying VIA PCI latency patch (found VT82C686B).\n");
+			/*
+	 		 *    In register 0x70, mask off bit 2 (PCI Master read caching)
+	 		 *    and 1 (Delay Transaction)
+	 		 */
+			pci_read_config_byte(dev, 0x70, &r70);
+			r70 &= 0xf9;
+			pci_write_config_byte(dev, 0x70, r70);
+			/*
+	 	 	 *    Turn off PCI Latency timeout (set to 0 clocks)
+	 	 	 */
+			pci_write_config_byte(dev, 0x75, 0x80);
+		}
+		else
+		{
+			printk(KERN_INFO "Found VT82C686A, not applying VIA latency patch.\n");
+		}
+	} /* if (vt82c686) ... */
 }
 
 /*
@@ -363,7 +384,7 @@
  		    (f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
  		    (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
 #ifdef DEBUG
-			printk("PCI: Calling quirk %p for %s\n", f->hook, dev->slot_name);
+			printk(KERN_INFO "PCI: Calling quirk %p for %s\n", f->hook, dev->slot_name);
 #endif
 			f->hook(dev);
 		}
diff -urN linux-2.4.5-pre3/drivers/pci/setup-bus.c linux/drivers/pci/setup-bus.c
--- linux-2.4.5-pre3/drivers/pci/setup-bus.c	Mon Dec 11 13:46:26 2000
+++ linux/drivers/pci/setup-bus.c	Mon Dec  3 22:44:23 2001
@@ -136,9 +136,9 @@
 	ranges.mem_end = bus->resource[1]->end;
 	pcibios_fixup_pbus_ranges(bus, &ranges);
 
-	DBGC(("PCI: Bus %d, bridge: %s\n", bus->number, bridge->name));
-	DBGC(("  IO window: %04lx-%04lx\n", ranges.io_start, ranges.io_end));
-	DBGC(("  MEM window: %08lx-%08lx\n", ranges.mem_start, ranges.mem_end));
+	DBGC((KERN_ERR "PCI: Bus %d, bridge: %s\n", bus->number, bridge->name));
+	DBGC((KERN_ERR "  IO window: %04lx-%04lx\n", ranges.io_start, ranges.io_end));
+	DBGC((KERN_ERR "  MEM window: %08lx-%08lx\n", ranges.mem_start, ranges.mem_end));
 
 	/* Set up the top and bottom of the PCI I/O segment for this bus. */
 	pci_read_config_dword(bridge, PCI_IO_BASE, &l);
diff -urN linux-2.4.5-pre3/drivers/pci/setup-irq.c linux/drivers/pci/setup-irq.c
--- linux-2.4.5-pre3/drivers/pci/setup-irq.c	Tue Jan 11 14:22:31 2000
+++ linux/drivers/pci/setup-irq.c	Mon Dec  3 22:44:23 2001
@@ -53,7 +53,7 @@
 		irq = 0;
 	dev->irq = irq;
 
-	DBGC(("PCI fixup irq: (%s) got %d\n", dev->name, dev->irq));
+	DBGC((KERN_ERR "PCI fixup irq: (%s) got %d\n", dev->name, dev->irq));
 
 	/* Always tell the device, so the driver knows what is
 	   the real IRQ to use; the device does not use it. */
diff -urN linux-2.4.5-pre3/drivers/pci/setup-res.c linux/drivers/pci/setup-res.c
--- linux-2.4.5-pre3/drivers/pci/setup-res.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/pci/setup-res.c	Mon Dec  3 22:44:23 2001
@@ -121,7 +121,7 @@
 		}
 	}
 
-	DBGC(("  got res[%lx:%lx] for resource %d of %s\n", res->start,
+	DBGC((KERN_ERR "  got res[%lx:%lx] for resource %d of %s\n", res->start,
 						res->end, i, dev->name));
 
 	return 0;
@@ -165,7 +165,7 @@
 			if (r_size > size) {
 				tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
 				if (!tmp) {
-					printk("pdev_sort_resources(): kmalloc() failed!\n");
+					printk(KERN_ERR "pdev_sort_resources(): kmalloc() failed!\n");
 					continue;
 				}
 				tmp->next = ln;
@@ -185,7 +185,7 @@
 	u16 cmd;
 	int i;
 
-	DBGC(("PCI enable device: (%s)\n", dev->name));
+	DBGC((KERN_ERR "PCI enable device: (%s)\n", dev->name));
 
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 
@@ -230,5 +230,5 @@
 	/* Enable the appropriate bits in the PCI command register.  */
 	pci_write_config_word(dev, PCI_COMMAND, cmd);
 
-	DBGC(("  cmd reg 0x%x\n", cmd));
+	DBGC((KERN_ERR "  cmd reg 0x%x\n", cmd));
 }
diff -urN linux-2.4.5-pre3/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- linux-2.4.5-pre3/drivers/sbus/char/su.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/sbus/char/su.c	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.49 2001/05/11 05:35:02 davem Exp $
+/* $Id: su.c,v 1.50 2001/05/16 08:37:03 davem Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -1414,6 +1414,41 @@
  */
 
 /*
+ * get_serial_info - handle TIOCGSERIAL ioctl()
+ *
+ * Purpose: Return standard serial struct information about
+ *          a serial port handled by this driver.
+ *
+ * Added:   11-May-2001 Lars Kellogg-Stedman <lars@larsshack.org>
+ */
+static int get_serial_info(struct su_struct * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct	tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+
+	tmp.type		= info->type;
+	tmp.line		= info->line;
+	tmp.port		= info->port;
+	tmp.irq			= info->irq;
+	tmp.flags		= info->flags;
+	tmp.xmit_fifo_size	= info->xmit_fifo_size;
+	tmp.baud_base		= info->baud_base;
+	tmp.close_delay		= info->close_delay;
+	tmp.closing_wait	= info->closing_wait;
+	tmp.custom_divisor	= info->custom_divisor;
+	tmp.hub6		= 0;
+
+	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
  * get_lsr_info - get line status register info
  *
  * Purpose: Let user call ioctl() to get info when the UART physically
@@ -1571,6 +1606,9 @@
 		case TIOCMSET:
 			return set_modem_info(info, cmd, (unsigned int *) arg);
 
+		case TIOCGSERIAL:
+			return get_serial_info(info, (struct serial_struct *)arg);
+
 		case TIOCSERGETLSR: /* Get line status register */
 			return get_lsr_info(info, (unsigned int *) arg);
 
@@ -2223,7 +2261,7 @@
  */
 static __inline__ void __init show_su_version(void)
 {
-	char *revision = "$Revision: 1.49 $";
+	char *revision = "$Revision: 1.50 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -urN linux-2.4.5-pre3/drivers/scsi/ChangeLog.ips linux/drivers/scsi/ChangeLog.ips
--- linux-2.4.5-pre3/drivers/scsi/ChangeLog.ips	Tue Sep 19 08:01:34 2000
+++ linux/drivers/scsi/ChangeLog.ips	Mon Dec  3 22:44:23 2001
@@ -1,5 +1,25 @@
 IBM ServeRAID driver Change Log
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+        4.72.00  - Allow for a Scatter-Gather Element to exceed MAX_XFER Size     
+        
+        4.71.00  - Change all memory allocations to not use GFP_DMA flag 
+                   Code Clean-Up for 2.4.x kernel      
+        
+        4.70.15  - Fix Breakup for very large ( non-SG ) requests
+        
+        4.70.13  - Don't release HA Lock in ips_next() until SC taken off queue  
+                 - Unregister SCSI device in ips_release()                        
+                 - Don't Send CDB's if we already know the device is not present  
+                 
+        4.70.12  - Corrective actions for bad controller ( during initialization )
+        
+        4.70.09  - Use a Common ( Large Buffer ) for Flashing from the JCRM CD    
+                 - Add IPSSEND Flash Support                                      
+                 - Set Sense Data for Unknown SCSI Command                        
+                 - Use Slot Number from NVRAM Page 5 
+                 - Restore caller's DCDB Structure
+                                       
         4.20.14  - Update patch files for kernel 2.4.0-test5
 
         4.20.13  - Fix some failure cases / reset code
@@ -66,3 +86,4 @@
                 - Fixed read/write errors when the adapter is using an
                   8K stripe size.
 
+
\ No newline at end of file
diff -urN linux-2.4.5-pre3/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- linux-2.4.5-pre3/drivers/scsi/eata.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/scsi/eata.c	Mon Dec  3 22:44:23 2001
@@ -1,6 +1,10 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *       1 May 2001 Rev. 6.05 for linux 2.4.4
+ *        + Clean up all pci related routines.
+ *        + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d)
+ *
  *      30 Jan 2001 Rev. 6.04 for linux 2.4.1
  *        + Call pci_resource_start after pci_enable_device.
  *
@@ -828,77 +832,38 @@
    return FALSE;
 }
 
-static inline void tune_pci_port(unsigned long port_base) {
-
-#if defined(CONFIG_PCI)
-
-   unsigned int addr, k;
-   struct pci_dev *dev = NULL;
-
-   if (!pci_present()) return;
-
-   for (k = 0; k < MAX_PCI; k++) {
-
-      if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break;
-
-      if (pci_enable_device (dev)) continue;
-
-      addr = pci_resource_start (dev, 0);
-
-#if defined(DEBUG_PCI_DETECT)
-      printk("%s: tune_pci_port, bus %d, devfn 0x%x, addr 0x%x.\n",
-             driver_name, dev->bus->number, dev->devfn, addr);
-#endif
-
-      if ((addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0 == port_base) {
-         pci_set_master(dev);
-         return;
-         }
-
-      }
-
-#endif /* end CONFIG_PCI */
-
-   return;
-}
-
-static inline int
-            get_pci_irq(unsigned long port_base, unsigned char *apic_irq) {
+static inline struct pci_dev *get_pci_dev(unsigned long port_base) {
 
 #if defined(CONFIG_PCI)
 
    unsigned int addr;
    struct pci_dev *dev = NULL;
 
-   if (!pci_present()) return FALSE;
+   if (!pci_present()) return NULL;
 
    while((dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
-
-      if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
+      addr = pci_resource_start (dev, 0);
 
 #if defined(DEBUG_PCI_DETECT)
-      printk("%s: get_pci_irq, bus %d, devfn 0x%x, addr 0x%x, apic_irq %u.\n",
-             driver_name, dev->bus->number, dev->devfn, addr, dev->irq);
+      printk("%s: get_pci_dev, bus %d, devfn 0x%x, addr 0x%x.\n",
+             driver_name, dev->bus->number, dev->devfn, addr);
 #endif
 
-      if ((addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0 == port_base) {
-         *apic_irq = dev->irq;
-         return TRUE;
-         }
-
+      if (addr + PCI_BASE_ADDRESS_0 == port_base) return dev;
       }
 
 #endif /* end CONFIG_PCI */
 
-   return FALSE;
+   return NULL;
 }
 
 static inline int port_detect \
       (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) {
    unsigned char irq, dma_channel, subversion, i;
-   unsigned char protocol_rev, apic_irq;
+   unsigned char protocol_rev;
    struct eata_info info;
    char *bus_type, dma_name[16], tag_type;
+   struct pci_dev *pdev;
 
    /* Allowed DMA channels for ISA (0 indicates reserved) */
    unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
@@ -1002,9 +967,11 @@
       printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
              name, irq);
 
-   if (get_pci_irq(port_base, &apic_irq) && (irq != apic_irq)) {
-      printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, apic_irq);
-      irq = apic_irq;
+   pdev = get_pci_dev(port_base);
+
+   if (pdev && (irq != pdev->irq)) {
+      printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, pdev->irq);
+      irq = pdev->irq;
       }
 
    /* Board detected, allocate its IRQ */
@@ -1064,10 +1031,6 @@
    sh[j]->can_queue = (ushort) ntohs(info.queue_size);
    sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
    sh[j]->select_queue_depths = select_queue_depths;
-
-   /* Register the I/O space that we use */
-   request_region(sh[j]->io_port, sh[j]->n_io_port, driver_name);
-
    memset(HD(j), 0, sizeof(struct hostdata));
    HD(j)->subversion = subversion;
    HD(j)->protocol_rev = protocol_rev;
@@ -1185,7 +1148,8 @@
              info.pci, info.eisa, info.raidnum);
 #endif
 
-   tune_pci_port(sh[j]->io_port);
+   if (pdev) pci_set_master(pdev);
+
    return TRUE;
 }
 
@@ -1254,19 +1218,26 @@
 
       if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break;
 
-      if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
+      if (pci_enable_device (dev)) {
+
+#if defined(DEBUG_PCI_DETECT)
+         printk("%s: detect, bus %d, devfn 0x%x, pci_enable_device failed.\n",
+                driver_name, dev->bus->number, dev->devfn);
+#endif
+
+         continue;
+         }
+
+      addr = pci_resource_start (dev, 0);
 
 #if defined(DEBUG_PCI_DETECT)
       printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
              driver_name, k, dev->bus->number, dev->devfn, addr);
 #endif
 
-      if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
-             continue;
-
       /* Order addresses according to rev_scan value */
       io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] =
-             (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
+             addr + PCI_BASE_ADDRESS_0;
       }
 
 #endif /* end CONFIG_PCI */
@@ -1327,7 +1298,7 @@
    static const unsigned char data_out_cmds[] = {
       0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
       0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
-      0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b
+      0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d
       };
 
    static const unsigned char data_none_cmds[] = {
diff -urN linux-2.4.5-pre3/drivers/scsi/eata.h linux/drivers/scsi/eata.h
--- linux-2.4.5-pre3/drivers/scsi/eata.h	Fri Feb 16 16:02:36 2001
+++ linux/drivers/scsi/eata.h	Mon Dec  3 22:44:23 2001
@@ -13,7 +13,7 @@
 int eata2x_reset(Scsi_Cmnd *);
 int eata2x_biosparam(Disk *, kdev_t, int *);
 
-#define EATA_VERSION "6.04.00"
+#define EATA_VERSION "6.05.00"
 
 #define EATA {                                                               \
                 name:              "EATA/DMA 2.0x rev. " EATA_VERSION " ",   \
diff -urN linux-2.4.5-pre3/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c
--- linux-2.4.5-pre3/drivers/scsi/gdth.c	Fri Apr 27 13:59:18 2001
+++ linux/drivers/scsi/gdth.c	Mon Dec  3 22:44:23 2001
@@ -2,7 +2,7 @@
  * GDT ISA/EISA/PCI Disk Array Controller driver for Linux              *
  *                                                                      *
  * gdth.c                                                               *
- * Copyright (C) 1995-99 ICP vortex Computersysteme GmbH, Achim Leubner *
+ * Copyright (C) 1995-01 ICP vortex Computersysteme GmbH, Achim Leubner *
  *                                                                      *
  * <achim@vortex.de>                                                    *
  *                                                                      *
@@ -20,9 +20,92 @@
  * along with this kernel; if not, write to the Free Software           *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
  *                                                                      *
- * Tested with Linux 1.2.13, ..., 2.2.4                                 *
+ * Tested with Linux 1.2.13, ..., 2.2.18, ..., 2.4.2                    *
  *                                                                      *
  * $Log: gdth.c,v $
+ * Revision 1.49  2001/03/15 15:07:17  achim
+ * New __setup interface for boot command line options added
+ *
+ * Revision 1.48  2001/02/06 12:36:28  achim
+ * Bugfix Cluster protocol
+ *
+ * Revision 1.47  2001/01/10 14:42:06  achim
+ * New switch shared_access added
+ *
+ * Revision 1.46  2001/01/09 08:11:35  achim
+ * gdth_command() removed
+ * meaning of Scsi_Pointer members changed
+ *
+ * Revision 1.45  2000/11/16 12:02:24  achim
+ * Changes for kernel 2.4
+ *
+ * Revision 1.44  2000/10/11 08:44:10  achim
+ * Clustering changes: New flag media_changed added
+ *
+ * Revision 1.43  2000/09/20 12:59:01  achim
+ * DPMEM remap functions for all PCI controller types implemented
+ * Small changes for ia64 platform
+ *
+ * Revision 1.42  2000/07/20 09:04:50  achim
+ * Small changes for kernel 2.4
+ *
+ * Revision 1.41  2000/07/04 14:11:11  achim
+ * gdth_analyse_hdrive() added to rescan drives after online expansion
+ *
+ * Revision 1.40  2000/06/27 11:24:16  achim
+ * Changes Clustering, Screenservice
+ *
+ * Revision 1.39  2000/06/15 13:09:04  achim
+ * Changes for gdth_do_cmd()
+ *
+ * Revision 1.38  2000/06/15 12:08:43  achim
+ * Bugfix gdth_sync_event(), service SCREENSERVICE
+ * Data direction for command 0xc2 changed to DOU
+ *
+ * Revision 1.37  2000/05/25 13:50:10  achim
+ * New driver parameter virt_ctr added
+ *
+ * Revision 1.36  2000/05/04 08:50:46  achim
+ * Event buffer now in gdth_ha_str
+ *
+ * Revision 1.35  2000/03/03 10:44:08  achim
+ * New event_string only valid for the RP controller family
+ *
+ * Revision 1.34  2000/03/02 14:55:29  achim
+ * New mechanism for async. event handling implemented
+ *
+ * Revision 1.33  2000/02/21 15:37:37  achim
+ * Bugfix Alpha platform + DPMEM above 4GB
+ *
+ * Revision 1.32  2000/02/14 16:17:37  achim
+ * Bugfix sense_buffer[] + raw devices
+ *
+ * Revision 1.31  2000/02/10 10:29:00  achim
+ * Delete sense_buffer[0], if command OK
+ *
+ * Revision 1.30  1999/11/02 13:42:39  achim
+ * ARRAY_DRV_LIST2 implemented
+ * Now 255 log. and 100 host drives supported
+ *
+ * Revision 1.29  1999/10/05 13:28:47  achim
+ * GDT_CLUST_RESET added
+ *
+ * Revision 1.28  1999/08/12 13:44:54  achim
+ * MOUNTALL removed
+ * Cluster drives -> removeable drives
+ *
+ * Revision 1.27  1999/06/22 07:22:38  achim
+ * Small changes
+ *
+ * Revision 1.26  1999/06/10 16:09:12  achim
+ * Cluster Host Drive support: Bugfixes
+ *
+ * Revision 1.25  1999/06/01 16:03:56  achim
+ * gdth_init_pci(): Manipulate config. space to start RP controller
+ *
+ * Revision 1.24  1999/05/26 11:53:06  achim
+ * Cluster Host Drive support added
+ *
  * Revision 1.23  1999/03/26 09:12:31  achim
  * Default value for hdr_channel set to 0
  *
@@ -120,7 +203,7 @@
  * Initial revision
  *
  ************************************************************************/
-#ident "$Id: gdth.c,v 1.23 1999/03/26 09:12:31 achim Exp $" 
+#ident "$Id: gdth.c,v 1.49 2001/03/15 15:07:17 achim Exp $" 
 
 /* All GDT Disk Array Controllers are fully supported by this driver.
  * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the
@@ -147,10 +230,17 @@
  * max_ids:x                    x - target ID count per channel (1..MAXID)
  * rescan:Y                     rescan all channels/IDs 
  * rescan:N                     use all devices found until now
+ * virt_ctr:Y                   map every channel to a virtual controller 
+ * virt_ctr:N                   use multi channel support 
  * hdr_channel:x                x - number of virtual bus for host drives
+ * shared_access:Y              disable driver reserve/release protocol to 
+ *                              access a shared resource from several nodes, 
+ *                              appropiate controller firmware required
+ * shared_access:N              enable driver reserve/release protocol
  *
- * The default value is: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
- *                        max_ids:127,rescan:N,hdr_channel:0".
+ * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
+ *                          max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0,
+ *                          shared_access:N".
  * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y".
  * 
  * When loading the gdth driver as a module, the same options are available. 
@@ -160,10 +250,22 @@
  * '1' in place of 'Y' and '0' in place of 'N'.
  * 
  * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0
- *                         max_ids=127 rescan=0 hdr_channel=0"
+ *           max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0 shared_access=0"
  * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1".
  */
 
+/* The meaning of the Scsi_Pointer members in this driver is as follows:
+ * ptr:                         Chaining
+ * this_residual:               Command priority
+ * buffer:                      Unused
+ * buffers_residual:            Timeout value
+ * Status:                      Command status (gdth_do_cmd())
+ * Message:                     Additional info (gdth_do_cmd())
+ * have_data_in:                Flag for gdth_wait_completion()
+ * sent_command:                Opcode special command
+ * phase:                       Service/parameter/return code special command
+ */
+
 #ifdef MODULE
 #include <linux/module.h>
 #endif
@@ -181,13 +283,32 @@
 #include <linux/proc_fs.h>
 #include <linux/time.h>
 #include <linux/timer.h>
+#ifdef GDTH_RTC
+#include <linux/mc146818rtc.h>
+#endif
+#if LINUX_VERSION_CODE >= 0x020100
 #include <linux/reboot.h>
+#else
+#include <linux/bios32.h>
+#endif
+#if LINUX_VERSION_CODE >= 0x020126
+#include <linux/init.h>
+#endif
 
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#if LINUX_VERSION_CODE >= 0x020322
 #include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= 0x02015F
+#include <asm/spinlock.h>
+#endif
+
+#if LINUX_VERSION_CODE >= 0x010300
 #include <linux/blk.h>
+#else
+#include "../block/blk.h"
+#endif
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
@@ -196,9 +317,13 @@
 
 static void gdth_delay(int milliseconds);
 static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs);
+#if LINUX_VERSION_CODE >= 0x010346
 static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
+#else
+static void gdth_interrupt(int irq,struct pt_regs *regs);
+#endif
 static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
-static int gdth_async_event(int hanum,int service);
+static int gdth_async_event(int hanum);
 static void gdth_log_event(gdth_evt_data *dvr, char *buffer);
 
 static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority);
@@ -233,19 +358,25 @@
 static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
                              ulong32 p2,ulong32 p3);
 static int gdth_search_drives(int hanum);
+static int gdth_analyse_hdrive(int hanum, ushort hdrive);
 
 static void *gdth_mmap(ulong paddr, ulong size);
 static void gdth_munmap(void *addr);
 
 static const char *gdth_ctr_name(int hanum);
 
+#if LINUX_VERSION_CODE >= 0x010300
 static void gdth_flush(int hanum);
+#if LINUX_VERSION_CODE >= 0x020100
 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);
+#else
+static int halt_called = FALSE;
+void gdth_halt(void);
+#endif
+#endif
 
 #ifdef DEBUG_GDTH
 static unchar   DebugState = DEBUG_GDTH;
-extern long sys_syslog(int,char*,int);
-#define LOGEN sys_syslog(7,NULL,0)
 
 #ifdef __SERIAL__
 #define MAX_SERBUF 160
@@ -314,9 +445,9 @@
 #define TRACE3(a)   {if (DebugState!=0) {ser_printk a;}}
 
 #else /* !__SERIAL__ */
-#define TRACE(a)    {if (DebugState==1) {LOGEN;printk a;}}
-#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {LOGEN;printk a;}}
-#define TRACE3(a)   {if (DebugState!=0) {LOGEN;printk a;}}
+#define TRACE(a)    {if (DebugState==1) {printk a;}}
+#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {printk a;}}
+#define TRACE3(a)   {if (DebugState!=0) {printk a;}}
 #endif
 
 #else /* !DEBUG */
@@ -341,6 +472,64 @@
 
 #define BUS_L2P(a,b)    ((b)>(a)->virt_bus ? (b-1):(b))
 
+#if LINUX_VERSION_CODE < 0x010300
+static void *gdth_mmap(ulong paddr, ulong size) 
+{
+    if (paddr >= high_memory)
+        return NULL; 
+    else
+        return (void *)paddr;
+}
+static void gdth_munmap(void *addr) 
+{
+}
+inline ulong32 virt_to_phys(volatile void *addr)
+{
+    return (ulong32)addr;
+}
+inline void *phys_to_virt(ulong32 addr)
+{
+    return (void *)addr;
+}
+#define virt_to_bus             virt_to_phys
+#define bus_to_virt             phys_to_virt
+#define gdth_readb(addr)        (*(volatile unchar *)(addr))
+#define gdth_readw(addr)        (*(volatile ushort *)(addr))
+#define gdth_readl(addr)        (*(volatile ulong32 *)(addr))
+#define gdth_writeb(b,addr)     (*(volatile unchar *)(addr) = (b))
+#define gdth_writew(b,addr)     (*(volatile ushort *)(addr) = (b))
+#define gdth_writel(b,addr)     (*(volatile ulong32 *)(addr) = (b))
+#define memset_io(a,b,c)        memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c)    memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)      memcpy((void *)(a),(b),(c))
+
+#define PCI_SLOT(devfn)         ((devfn >> 3) & 0x1f)
+
+#elif LINUX_VERSION_CODE < 0x020100
+static int remapped = FALSE;
+static void *gdth_mmap(ulong paddr, ulong size) 
+{
+    if ( paddr >= high_memory) {
+        remapped = TRUE;
+        return vremap(paddr, size);
+    } else {
+        return (void *)paddr; 
+    }
+}
+static void gdth_munmap(void *addr) 
+{
+    if (remapped)
+        vfree(addr);
+    remapped = FALSE;
+}
+#define gdth_readb(addr)        readb((ulong)(addr))
+#define gdth_readw(addr)        readw((ulong)(addr))
+#define gdth_readl(addr)        (ulong32)readl((ulong)(addr))
+#define gdth_writeb(b,addr)     writeb((b),(ulong)(addr))
+#define gdth_writew(b,addr)     writew((b),(ulong)(addr))
+#define gdth_writel(b,addr)     writel((ulong32)(b),(ulong)(addr))
+
+#else
 static void *gdth_mmap(ulong paddr, ulong size) 
 { 
     return ioremap(paddr, size); 
@@ -354,7 +543,9 @@
 #define gdth_readl(addr)        (ulong32)readl((ulong)(addr))
 #define gdth_writeb(b,addr)     writeb((b),(ulong)(addr))
 #define gdth_writew(b,addr)     writew((b),(ulong)(addr))
-#define gdth_writel(b,addr)     writel((b),(ulong)(addr))
+#define gdth_writel(b,addr)     writel((ulong32)(b),(ulong)(addr))
+#endif
+
 
 static unchar   gdth_drq_tab[4] = {5,6,7,7};            /* DRQ table */
 static unchar   gdth_irq_tab[6] = {0,10,11,12,14,0};    /* IRQ table */
@@ -388,15 +579,24 @@
     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
     DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU,
     DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,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,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,DOU,DUN,DUN,DUN,DUN,DUN,
     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN
 };
 
 /* __initfunc, __initdata macros */
-#include <linux/init.h>
+#if LINUX_VERSION_CODE >= 0x020322
+#define GDTH_INITFUNC(type, func)       type __init func 
+#elif LINUX_VERSION_CODE >= 0x020126
+#define GDTH_INITFUNC(type, func)       __initfunc(type func)
+#else
+#define GDTH_INITFUNC(type, func)       type func
+#define __initdata
+#define __init
+#endif
 
+#if LINUX_VERSION_CODE >= 0x02015F
 #define GDTH_INIT_LOCK_HA(ha)           spin_lock_init(&(ha)->smp_lock)
 #define GDTH_LOCK_HA(ha,flags)          spin_lock_irqsave(&(ha)->smp_lock,flags)
 #define GDTH_UNLOCK_HA(ha,flags)        spin_unlock_irqrestore(&(ha)->smp_lock,flags)
@@ -405,6 +605,16 @@
 #define GDTH_UNLOCK_SCSI_DONE(flags)    spin_unlock_irqrestore(&io_request_lock,flags)
 #define GDTH_LOCK_SCSI_DOCMD()          spin_lock_irq(&io_request_lock)
 #define GDTH_UNLOCK_SCSI_DOCMD()        spin_unlock_irq(&io_request_lock)
+#else
+#define GDTH_INIT_LOCK_HA(ha)           do {} while (0)
+#define GDTH_LOCK_HA(ha,flags)          do {save_flags(flags); cli();} while (0)
+#define GDTH_UNLOCK_HA(ha,flags)        do {restore_flags(flags);} while (0)
+
+#define GDTH_LOCK_SCSI_DONE(flags)      do {} while (0)
+#define GDTH_UNLOCK_SCSI_DONE(flags)    do {} while (0)
+#define GDTH_LOCK_SCSI_DOCMD()          do {} while (0)
+#define GDTH_UNLOCK_SCSI_DOCMD()        do {} while (0)
+#endif
 
 /* LILO and modprobe/insmod parameters */
 /* IRQ list for GDT3000/3020 EISA controllers */
@@ -428,8 +638,13 @@
 static int max_ids = MAXID;
 /* rescan all IDs */
 static int rescan = 0;
+/* map channels to virtual controllers */
+static int virt_ctr = 0;
+/* shared access */
+static int shared_access = 0;
 
 #ifdef MODULE
+#if LINUX_VERSION_CODE >= 0x02011A
 /* parameters for modprobe/insmod */
 MODULE_PARM(irq, "i");
 MODULE_PARM(disable, "i");
@@ -439,25 +654,45 @@
 MODULE_PARM(hdr_channel, "i");
 MODULE_PARM(max_ids, "i");
 MODULE_PARM(rescan, "i");
+MODULE_PARM(virt_ctr, "i");
+MODULE_PARM(shared_access, "i");
 MODULE_AUTHOR("Achim Leubner");
 #endif
+#endif
 
 /* /proc support */
+#if LINUX_VERSION_CODE >= 0x010300
 #include <linux/stat.h> 
+#if LINUX_VERSION_CODE < 0x020322
+struct proc_dir_entry proc_scsi_gdth = {
+    PROC_SCSI_GDTH, 4, "gdth",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+#endif
 #include "gdth_proc.h"
 #include "gdth_proc.c"
+#endif
 
+#if LINUX_VERSION_CODE >= 0x020100
 /* notifier block to get a notify on system shutdown/halt/reboot */
 static struct notifier_block gdth_notifier = {
     gdth_halt, NULL, 0
 };
+#endif
+
 
 static void gdth_delay(int milliseconds)
 {
     if (milliseconds == 0) {
         udelay(1);
     } else {
+#if LINUX_VERSION_CODE >= 0x020168
         mdelay(milliseconds);
+#else
+        int i;
+        for (i = 0; i < milliseconds; ++i) 
+            udelay(1000);
+#endif
     }
 }
 
@@ -465,24 +700,24 @@
 {
     *cyls = size /HEADS/SECS;
     if (*cyls <= MAXCYLS) {
-	*heads = HEADS;
-	*secs = SECS;
-    } else {                            		/* too high for 64*32 */
-	*cyls = size /MEDHEADS/MEDSECS;
-	if (*cyls <= MAXCYLS) {
-	    *heads = MEDHEADS;
-	    *secs = MEDSECS;
-	} else {                        		/* too high for 127*63 */
-	    *cyls = size /BIGHEADS/BIGSECS;
-	    *heads = BIGHEADS;
-	    *secs = BIGSECS;
-	}
+        *heads = HEADS;
+        *secs = SECS;
+    } else {                                        /* too high for 64*32 */
+        *cyls = size /MEDHEADS/MEDSECS;
+        if (*cyls <= MAXCYLS) {
+            *heads = MEDHEADS;
+            *secs = MEDSECS;
+        } else {                                    /* too high for 127*63 */
+            *cyls = size /BIGHEADS/BIGSECS;
+            *heads = BIGHEADS;
+            *secs = BIGSECS;
+        }
     }
 }
 
 /* controller search and initialization functions */
 
-static int __init gdth_search_eisa(ushort eisa_adr)
+GDTH_INITFUNC(static int, gdth_search_eisa(ushort eisa_adr))
 {
     ulong32 id;
     
@@ -500,7 +735,7 @@
 }
 
 
-static int __init gdth_search_isa(ulong32 bios_adr)
+GDTH_INITFUNC(static int, gdth_search_isa(ulong32 bios_adr))
 {
     void *addr;
     ulong32 id;
@@ -516,11 +751,16 @@
 }
 
 
-static int __init gdth_search_pci(gdth_pci_str *pcistr)
+GDTH_INITFUNC(static int, gdth_search_pci(gdth_pci_str *pcistr))
 {
-    ulong32 base0, base1, base2;
+    ulong base0, base1, base2;
     ushort device_id, cnt;
+#if LINUX_VERSION_CODE >= 0x2015C
     struct pci_dev *pdev;
+#else
+    int error;
+    ushort idx;
+#endif
     
     TRACE(("gdth_search_pci()\n"));
 
@@ -530,11 +770,46 @@
         if (device_id > PCI_DEVICE_ID_VORTEX_GDT6555 &&
             device_id < PCI_DEVICE_ID_VORTEX_GDT6x17RP)
             continue;
+#if LINUX_VERSION_CODE >= 0x20363
+        pdev = NULL;
+        while ((pdev = pci_find_device(PCI_VENDOR_ID_VORTEX,device_id,pdev)) 
+               != NULL) {
+            if (pci_enable_device(pdev))
+                continue;
+            if (cnt >= MAXHA)
+                return cnt;
+            /* GDT PCI controller found, resources are already in pdev */
+            pcistr[cnt].pdev = pdev;
+            pcistr[cnt].device_id = device_id;
+            pcistr[cnt].bus = pdev->bus->number;
+            pcistr[cnt].device_fn = pdev->devfn;
+            pcistr[cnt].irq = pdev->irq;
+            base0 = pci_resource_flags(pdev, 0);
+            base1 = pci_resource_flags(pdev, 1);
+            base2 = pci_resource_flags(pdev, 2);
+            if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000/B */
+                device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) {  /* MPR */
+                if (!(base0 & IORESOURCE_MEM)) 
+                    continue;
+                pcistr[cnt].dpmem = pci_resource_start(pdev, 0);
+            } else {                                  /* GDT6110, GDT6120, .. */
+                if (!(base0 & IORESOURCE_MEM) ||
+                    !(base2 & IORESOURCE_MEM) ||
+                    !(base1 & IORESOURCE_IO)) 
+                    continue;
+                pcistr[cnt].dpmem = pci_resource_start(pdev, 2);
+                pcistr[cnt].io_mm = pci_resource_start(pdev, 0);
+                pcistr[cnt].io    = pci_resource_start(pdev, 1);
+            }
+            TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n",
+                    pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), 
+                    pcistr[cnt].irq, pcistr[cnt].dpmem));
+            cnt++;
+        }       
+#elif LINUX_VERSION_CODE >= 0x2015C
         pdev = NULL;
         while ((pdev = pci_find_device(PCI_VENDOR_ID_VORTEX,device_id,pdev)) 
                != NULL) {
-	    if (pci_enable_device(pdev))
-	    	continue;
             if (cnt >= MAXHA)
                 return cnt;
             /* GDT PCI controller found, resources are already in pdev */
@@ -543,16 +818,16 @@
             pcistr[cnt].bus = pdev->bus->number;
             pcistr[cnt].device_fn = pdev->devfn;
             pcistr[cnt].irq = pdev->irq;
-            base0 = pdev->resource[0].flags;
-            base1 = pdev->resource[1].flags;
-            base2 = pdev->resource[2].flags;
+            base0 = pdev->base_address[0];
+            base1 = pdev->base_address[1];
+            base2 = pdev->base_address[2];
             if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000/B */
                 device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) {  /* MPR */
                 if ((base0 & PCI_BASE_ADDRESS_SPACE) != 
                     PCI_BASE_ADDRESS_SPACE_MEMORY)
                     continue;
-                pcistr[cnt].dpmem = pdev->resource[0].start;
-            } else {                                    /* GDT6110, GDT6120, .. */
+                pcistr[cnt].dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK;
+            } else {                                  /* GDT6110, GDT6120, .. */
                 if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
                     PCI_BASE_ADDRESS_SPACE_MEMORY ||
                     (base2 & PCI_BASE_ADDRESS_SPACE) !=
@@ -560,21 +835,77 @@
                     (base1 & PCI_BASE_ADDRESS_SPACE) !=
                     PCI_BASE_ADDRESS_SPACE_IO)
                     continue;
-                pcistr[cnt].dpmem = pdev->resource[2].start;
-                pcistr[cnt].io_mm = pdev->resource[0].start;
-                pcistr[cnt].io    = pdev->resource[1].start;
+                pcistr[cnt].dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK;
+                pcistr[cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
+                pcistr[cnt].io    = base1 & PCI_BASE_ADDRESS_IO_MASK;
             }
-            TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%x\n",
+            TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n",
                     pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), 
                     pcistr[cnt].irq, pcistr[cnt].dpmem));
             cnt++;
         }       
+#else   
+        idx = 0;
+        while (!pcibios_find_device(PCI_VENDOR_ID_VORTEX,device_id,idx++,
+                                    &pcistr[cnt].bus,&pcistr[cnt].device_fn)) {
+            if (cnt >= MAXHA)
+                return cnt;
+            /* GDT PCI ctr. found, now read resources from config space */
+#if LINUX_VERSION_CODE >= 0x010300
+#define GDTH_BASEP      (int *)
+#else
+#define GDTH_BASEP
+#endif
+            if ((error = pcibios_read_config_dword(pcistr[cnt].bus,
+                                                   pcistr[cnt].device_fn,
+                                                   PCI_BASE_ADDRESS_0,
+                                                   GDTH_BASEP&base0)) ||
+                (error = pcibios_read_config_dword(pcistr[cnt].bus,
+                                                   pcistr[cnt].device_fn,
+                                                   PCI_BASE_ADDRESS_1,
+                                                   GDTH_BASEP&base1)) ||
+                (error = pcibios_read_config_dword(pcistr[cnt].bus,
+                                                   pcistr[cnt].device_fn,
+                                                   PCI_BASE_ADDRESS_2,
+                                                   GDTH_BASEP&base2)) ||
+                (error = pcibios_read_config_byte(pcistr[cnt].bus,
+                                                  pcistr[cnt].device_fn,
+                                                  PCI_INTERRUPT_LINE,
+                                                  &pcistr[cnt].irq))) {
+                printk("GDT-PCI: error %d reading configuration space", error);
+                continue;
+            }
+            pcistr[cnt].device_id = device_id;
+            if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000/B */
+                device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) {  /* MPR */
+                if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
+                    PCI_BASE_ADDRESS_SPACE_MEMORY)
+                    continue;
+                pcistr[cnt].dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK;
+            } else {                                    /* GDT6110, GDT6120, .. */
+                if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
+                    PCI_BASE_ADDRESS_SPACE_MEMORY ||
+                    (base2 & PCI_BASE_ADDRESS_SPACE) !=
+                    PCI_BASE_ADDRESS_SPACE_MEMORY ||
+                    (base1 & PCI_BASE_ADDRESS_SPACE) !=
+                    PCI_BASE_ADDRESS_SPACE_IO)
+                    continue;
+                pcistr[cnt].dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK;
+                pcistr[cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
+                pcistr[cnt].io    = base1 & PCI_BASE_ADDRESS_IO_MASK;
+            }
+            TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n",
+                    pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), 
+                    pcistr[cnt].irq, pcistr[cnt].dpmem));
+            cnt++;
+        }
+#endif
     }   
     return cnt;
 }
 
 
-static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt)
+GDTH_INITFUNC(static void, gdth_sort_pci(gdth_pci_str *pcistr, int cnt))
 {    
     gdth_pci_str temp;
     int i, changed;
@@ -612,7 +943,7 @@
 }
 
 
-static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
+GDTH_INITFUNC(static int, gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha))
 {
     ulong32 retries,id;
     unchar prot_ver,eisacf,i,irq_found;
@@ -701,7 +1032,7 @@
 }
 
        
-static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
+GDTH_INITFUNC(static int, gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha))
 {
     register gdt2_dpram_str *dp2_ptr;
     int i;
@@ -798,14 +1129,18 @@
 }
 
 
-static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
+GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha))
 {
     register gdt6_dpram_str *dp6_ptr;
     register gdt6c_dpram_str *dp6c_ptr;
     register gdt6m_dpram_str *dp6m_ptr;
     ulong32 retries;
     unchar prot_ver;
+    ushort command;
     int i, found = FALSE;
+#if LINUX_VERSION_CODE < 0x2015C
+    int rom_addr;
+#endif
 
     TRACE(("gdth_init_pci()\n"));
 
@@ -820,8 +1155,51 @@
             printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
             return 0;
         }
+        /* check and reset interface area */
         dp6_ptr = (gdt6_dpram_str *)ha->brd;
-        /* reset interface area */
+        gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
+        if (gdth_readl(&dp6_ptr->u) != DPMEM_MAGIC) {
+            printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
+                   pcistr->dpmem);
+            found = FALSE;
+            for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
+                gdth_munmap(ha->brd);
+                ha->brd = gdth_mmap(i, sizeof(ushort)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                if (gdth_readw(ha->brd) != 0xffff) {
+                    TRACE2(("init_pci_old() address 0x%x busy\n", i));
+                    continue;
+                }
+                gdth_munmap(ha->brd);
+#if LINUX_VERSION_CODE >= 0x2015C
+                pci_write_config_dword(pcistr->pdev, 
+                                       PCI_BASE_ADDRESS_0, i);
+#else
+                pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+                                           PCI_BASE_ADDRESS_0, i);
+#endif
+                ha->brd = gdth_mmap(i, sizeof(gdt6_dpram_str)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                dp6_ptr = (gdt6_dpram_str *)ha->brd;
+                gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
+                if (gdth_readl(&dp6_ptr->u) == DPMEM_MAGIC) {
+                    printk("GDT-PCI: Use free address at 0x%x\n", i);
+                    found = TRUE;
+                    break;
+                }
+            }   
+            if (!found) {
+                printk("GDT-PCI: No free address found!\n");
+                gdth_munmap(ha->brd);
+                return 0;
+            }
+        }
         memset_io((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u));
         if (gdth_readl(&dp6_ptr->u) != 0) {
             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
@@ -890,8 +1268,51 @@
             gdth_munmap(ha->brd);
             return 0;
         }
+        /* check and reset interface area */
         dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
-        /* reset interface area */
+        gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
+        if (gdth_readl(&dp6c_ptr->u) != DPMEM_MAGIC) {
+            printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
+                   pcistr->dpmem);
+            found = FALSE;
+            for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
+                gdth_munmap(ha->brd);
+                ha->brd = gdth_mmap(i, sizeof(ushort)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                if (gdth_readw(ha->brd) != 0xffff) {
+                    TRACE2(("init_pci_plx() address 0x%x busy\n", i));
+                    continue;
+                }
+                gdth_munmap(ha->brd);
+#if LINUX_VERSION_CODE >= 0x2015C
+                pci_write_config_dword(pcistr->pdev, 
+                                       PCI_BASE_ADDRESS_2, i);
+#else
+                pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+                                           PCI_BASE_ADDRESS_2, i);
+#endif
+                ha->brd = gdth_mmap(i, sizeof(gdt6c_dpram_str)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
+                gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
+                if (gdth_readl(&dp6c_ptr->u) == DPMEM_MAGIC) {
+                    printk("GDT-PCI: Use free address at 0x%x\n", i);
+                    found = TRUE;
+                    break;
+                }
+            }   
+            if (!found) {
+                printk("GDT-PCI: No free address found!\n");
+                gdth_munmap(ha->brd);
+                return 0;
+            }
+        }
         memset_io((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u));
         if (gdth_readl(&dp6c_ptr->u) != 0) {
             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
@@ -961,12 +1382,53 @@
             return 0;
         }
 
+        /* manipulate config. space to enable DPMEM, start RP controller */
+#if LINUX_VERSION_CODE >= 0x20363
+        pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command);
+        command |= 6;
+        pci_write_config_word(pcistr->pdev, PCI_COMMAND, command);
+        if (pci_resource_start(pcistr->pdev, 8) == 1UL)
+            pci_resource_start(pcistr->pdev, 8) = 0UL;
+        i = 0xFEFF0001UL;
+        pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, i);
+        gdth_delay(1);
+        pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS,
+                               pci_resource_start(pcistr->pdev, 8));
+#elif LINUX_VERSION_CODE >= 0x2015C
+        pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command);
+        command |= 6;
+        pci_write_config_word(pcistr->pdev, PCI_COMMAND, command);
+        if (pcistr->pdev->rom_address == 1UL)
+            pcistr->pdev->rom_address = 0UL;
+        i = 0xFEFF0001UL;
+        pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, i);
+        gdth_delay(1);
+        pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS,
+                               pcistr->pdev->rom_address);
+#else
+        pcibios_read_config_word(pcistr->bus, pcistr->device_fn,
+                                 PCI_COMMAND, &command);
+        command |= 6;
+        pcibios_write_config_word(pcistr->bus, pcistr->device_fn, 
+                                  PCI_COMMAND, command);
+        pcibios_read_config_dword(pcistr->bus, pcistr->device_fn,
+                                  PCI_ROM_ADDRESS, &rom_addr);
+        if (rom_addr == 1UL)
+            rom_addr = 0UL;
+        i = 0xFEFF0001UL;
+        pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+                                   PCI_ROM_ADDRESS, i);
+        gdth_delay(1);
+        pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+                                   PCI_ROM_ADDRESS, rom_addr);
+#endif
+        
         /* check and reset interface area */
         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
         gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
         if (gdth_readl(&dp6m_ptr->u) != DPMEM_MAGIC) {
-            printk("GDT-PCI: Cannot access DPMEM at 0x%x (shadowed?)\n", 
-                   (int)pcistr->dpmem);
+            printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
+                   pcistr->dpmem);
             found = FALSE;
             for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
                 gdth_munmap(ha->brd);
@@ -980,8 +1442,13 @@
                     continue;
                 }
                 gdth_munmap(ha->brd);
+#if LINUX_VERSION_CODE >= 0x2015C
                 pci_write_config_dword(pcistr->pdev, 
                                        PCI_BASE_ADDRESS_0, i);
+#else
+                pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+                                           PCI_BASE_ADDRESS_0, i);
+#endif
                 ha->brd = gdth_mmap(i, sizeof(gdt6m_dpram_str)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
@@ -1060,7 +1527,7 @@
 
 /* controller protocol functions */
 
-static void __init gdth_enable_int(int hanum)
+GDTH_INITFUNC(static void, gdth_enable_int(int hanum))
 {
     gdth_ha_str *ha;
     ulong flags;
@@ -1312,7 +1779,11 @@
 
     gdth_from_wait = TRUE;
     do {
+#if LINUX_VERSION_CODE >= 0x010346
         gdth_interrupt((int)ha->irq,ha,NULL);
+#else
+        gdth_interrupt((int)ha->irq,NULL);
+#endif
         if (wait_hanum==hanum && wait_index==index) {
             answer_found = TRUE;
             break;
@@ -1367,6 +1838,12 @@
             cmd_ptr->u.raw.bus        = (unchar)p2;
             cmd_ptr->u.raw.target     = (unchar)p3;
             cmd_ptr->u.raw.lun        = (unchar)(p3 >> 8);
+        } else if (service == SCREENSERVICE) {
+            if (opcode == GDT_REALTIME) {
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[0] = p1;
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = p2;
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = p3;
+            }
         }
         ha->cmd_len          = sizeof(gdth_cmd_str);
         ha->cmd_offs_dpmem   = 0;
@@ -1389,19 +1866,22 @@
 
 /* search for devices */
 
-static int __init gdth_search_drives(int hanum)
+GDTH_INITFUNC(static int, gdth_search_drives(int hanum))
 {
     register gdth_ha_str *ha;
     ushort cdev_cnt, i;
-    int drv_cyls, drv_hds, drv_secs;
-    ulong32 bus_no;
-    ulong32 drv_cnt, drv_no, j;
+    ulong32 bus_no, drv_cnt, drv_no, j;
     gdth_getch_str *chn;
     gdth_drlist_str *drl;
     gdth_iochan_str *ioc;
     gdth_raw_iochan_str *iocr;
-    gdth_arraylist_str *alst;
-        
+    gdth_arcdl_str *alst;
+    gdth_alist_str *alst2;
+#ifdef GDTH_RTC
+    unchar rtc[12];
+    ulong flags;
+#endif     
+   
     TRACE(("gdth_search_drives() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
 
@@ -1412,7 +1892,30 @@
         return 0;
     }
     TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n"));
-    
+
+#ifdef GDTH_RTC
+    /* read realtime clock info, send to controller */
+    /* 1. wait for the falling edge of update flag */
+    spin_lock_irqsave(&rtc_lock, flags);
+    for (j = 0; j < 1000000; ++j)
+        if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+            break;
+    for (j = 0; j < 1000000; ++j)
+        if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+            break;
+    /* 2. read info */
+    do {
+        for (j = 0; j < 12; ++j) 
+            rtc[j] = CMOS_READ(j);
+    } while (rtc[0] != CMOS_READ(0));
+    spin_lock_irqrestore(&rtc_lock, flags);
+    TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0],
+            *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]));
+    /* 3. send to controller firmware */
+    gdth_internal_cmd(hanum,SCREENSERVICE,GDT_REALTIME, *(ulong32 *)&rtc[0],
+                      *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]);
+#endif   
+ 
     /* initialize cache service */
     if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
         printk("GDT: Initialization error cache service (code %d)\n",
@@ -1421,19 +1924,7 @@
     }
     TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
     cdev_cnt = (ushort)ha->info;
-
-    /* mount all cache devices */
-    gdth_internal_cmd(hanum,CACHESERVICE,GDT_MOUNT,0xffff,1,0);
-    TRACE2(("gdth_search_drives(): mountall CACHESERVICE OK\n"));
-
-    /* initialize cache service after mountall */
-    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
-        printk("GDT: Initialization error cache service (code %d)\n",
-               ha->status);
-        return 0;
-    }
-    TRACE2(("gdth_search_drives() CACHES. init. after mountall\n"));
-    cdev_cnt = (ushort)ha->info;
+    ha->fw_vers = ha->service;
 
     /* detect number of buses - try new IOCTL */
     iocr = (gdth_raw_iochan_str *)ha->pscratch;
@@ -1493,7 +1984,8 @@
     ha->more_proc = FALSE;
     if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO,
                           INVALID_CHANNEL,sizeof(gdth_binfo_str))) {
-        memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch, sizeof(gdth_binfo_str));
+        memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch,
+               sizeof(gdth_binfo_str));
         if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_FEATURES,
                               INVALID_CHANNEL,sizeof(gdth_bfeat_str))) {
             TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n"));
@@ -1562,22 +2054,37 @@
                                   INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) {
                 for (j = 0; j < drv_cnt; ++j) {
                     drv_no = ((ulong32 *)ha->pscratch)[j];
-                    if (drv_no < MAX_HDRIVES) {
+                    if (drv_no < MAX_LDRIVES) {
                         ha->hdr[drv_no].is_logdrv = TRUE;
                         TRACE2(("Drive %d is log. drive\n",drv_no));
                     }
                 }
             }
+            alst = (gdth_arcdl_str *)ha->pscratch;
+            alst->entries_avail = MAX_LDRIVES;
+            alst->first_entry = 0;
+            alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]);
             if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
-                                  ARRAY_DRV_LIST | LA_CTRL_PATTERN,
-                                  0, 35 * sizeof(gdth_arraylist_str))) {
+                                  ARRAY_DRV_LIST2 | LA_CTRL_PATTERN, 
+                                  INVALID_CHANNEL, sizeof(gdth_arcdl_str) +
+                                  (alst->entries_avail-1) * sizeof(gdth_alist_str))) { 
+                for (j = 0; j < alst->entries_init; ++j) {
+                    ha->hdr[j].is_arraydrv = alst->list[j].is_arrayd;
+                    ha->hdr[j].is_master = alst->list[j].is_master;
+                    ha->hdr[j].is_parity = alst->list[j].is_parity;
+                    ha->hdr[j].is_hotfix = alst->list[j].is_hotfix;
+                    ha->hdr[j].master_no = alst->list[j].cd_handle;
+                }
+            } else if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                                         ARRAY_DRV_LIST | LA_CTRL_PATTERN,
+                                         0, 35 * sizeof(gdth_alist_str))) {
                 for (j = 0; j < 35; ++j) {
-                    alst = &((gdth_arraylist_str *)ha->pscratch)[j];
-                    ha->hdr[j].is_arraydrv = alst->is_arrayd;
-                    ha->hdr[j].is_master = alst->is_master;
-                    ha->hdr[j].is_parity = alst->is_parity;
-                    ha->hdr[j].is_hotfix = alst->is_hotfix;
-                    ha->hdr[j].master_no = alst->cd_handle;
+                    alst2 = &((gdth_alist_str *)ha->pscratch)[j];
+                    ha->hdr[j].is_arraydrv = alst2->is_arrayd;
+                    ha->hdr[j].is_master = alst2->is_master;
+                    ha->hdr[j].is_parity = alst2->is_parity;
+                    ha->hdr[j].is_hotfix = alst2->is_hotfix;
+                    ha->hdr[j].master_no = alst2->cd_handle;
                 }
             }
         }
@@ -1592,7 +2099,6 @@
     TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n"));
 
     /* set/get features raw service (scatter/gather) */
-    ha->raw_feat = 0;
     if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER,
                           0,0)) {
         TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n"));
@@ -1636,44 +2142,67 @@
         }
     }
 
-    /* scanning for cache devices */
-    for (i=0; i<cdev_cnt && i<MAX_HDRIVES; ++i) {
-        TRACE(("gdth_search_drives() cachedev. %d\n",i));
-        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,i,0,0)) {
-            /* static relation between host drive number and Bus/ID */
-            TRACE(("gdth_search_dr() drive %d mapped to bus/id %d/%d\n",
-                   i,ha->bus_cnt,i));
-
-            ha->hdr[i].present = TRUE;
-            ha->hdr[i].size = ha->info;
-
-            /* evaluate mapping (sectors per head, heads per cylinder) */
-            ha->hdr[i].size &= ~SECS32;
-            if (ha->info2 == 0) {
-		gdth_eval_mapping(ha->hdr[i].size,&drv_cyls,&drv_hds,&drv_secs);
-            } else {
-                drv_hds = ha->info2 & 0xff;
-                drv_secs = (ha->info2 >> 8) & 0xff;
-                drv_cyls = ha->hdr[i].size /drv_hds/drv_secs;
-            }
-            ha->hdr[i].heads = (unchar)drv_hds;
-            ha->hdr[i].secs  = (unchar)drv_secs;
-            /* round size */
-            ha->hdr[i].size  = drv_cyls * drv_hds * drv_secs;
-            TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n",
-                   i,ha->hdr[i].size,drv_hds,drv_secs));
+    /* scanning for host drives */
+    for (i = 0; i < cdev_cnt; ++i) 
+        gdth_analyse_hdrive(hanum,i);
+    
+    TRACE(("gdth_search_drives() OK\n"));
+    return 1;
+}
+
+static int gdth_analyse_hdrive(int hanum,ushort hdrive)
+{
+    register gdth_ha_str *ha;
+    int drv_cyls, drv_hds, drv_secs;
+
+    TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n",hanum,hdrive));
+    if (hdrive >= MAX_HDRIVES)
+        return 0;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,hdrive,0,0)) 
+        return 0;
+    ha->hdr[hdrive].present = TRUE;
+    ha->hdr[hdrive].size = ha->info;
+
+    /* evaluate mapping (sectors per head, heads per cylinder) */
+    ha->hdr[hdrive].size &= ~SECS32;
+    if (ha->info2 == 0) {
+        gdth_eval_mapping(ha->hdr[hdrive].size,&drv_cyls,&drv_hds,&drv_secs);
+    } else {
+        drv_hds = ha->info2 & 0xff;
+        drv_secs = (ha->info2 >> 8) & 0xff;
+        drv_cyls = ha->hdr[hdrive].size /drv_hds/drv_secs;
+    }
+    ha->hdr[hdrive].heads = (unchar)drv_hds;
+    ha->hdr[hdrive].secs  = (unchar)drv_secs;
+    /* round size */
+    ha->hdr[hdrive].size  = drv_cyls * drv_hds * drv_secs;
+    TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n",
+            hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs));
             
-            /* get informations about device */
-            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,i,
-                                  0,0)) {
-                TRACE(("gdth_search_dr() cache drive %d devtype %d\n",
-                       i,ha->info));
-                ha->hdr[i].devtype = (ushort)ha->info;
-            }
-        }
+    /* get informations about device */
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,hdrive,0,0)) {
+        TRACE2(("gdth_search_dr() cache drive %d devtype %d\n",
+                hdrive,ha->info));
+        ha->hdr[hdrive].devtype = (ushort)ha->info;
+    }
+
+    /* cluster info */
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_CLUST_INFO,hdrive,0,0)) {
+        TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n",
+                hdrive,ha->info));
+        if (!shared_access)
+            ha->hdr[hdrive].cluster_type = (unchar)ha->info;
+    }
+
+    /* R/W attributes */
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,hdrive,0,0)) {
+        TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n",
+                hdrive,ha->info));
+        ha->hdr[hdrive].rw_attribs = (unchar)ha->info;
     }
 
-    TRACE(("gdth_search_drives() OK\n"));
     return 1;
 }
 
@@ -1693,8 +2222,9 @@
     GDTH_LOCK_HA(ha, flags);
 
     scp->SCp.this_residual = (int)priority;
-    b = scp->channel;
+    b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
     t = scp->target;
+#if LINUX_VERSION_CODE >= 0x010300
     if (priority >= DEFAULT_PRI) {
         if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
             (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) {
@@ -1702,6 +2232,7 @@
             scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
         }
     }
+#endif
 
     if (ha->req_first==NULL) {
         ha->req_first = scp;                    /* queue was empty */
@@ -1752,7 +2283,7 @@
     for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) {
         if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr)
             pscp = (Scsi_Cmnd *)pscp->SCp.ptr;
-        b = nscp->channel;
+        b = virt_ctr ? NUMDATA(nscp->host)->busnum : nscp->channel;
         t = nscp->target;
         if (nscp->SCp.this_residual >= DEFAULT_PRI) {
             if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
@@ -1773,10 +2304,12 @@
             firsttime = FALSE;
         }
 
-        if (nscp->done != gdth_scsi_done) 
+#if LINUX_VERSION_CODE >= 0x010300
+        if (nscp->done != gdth_scsi_done || nscp->cmnd[0] != 0xff) 
+#endif
         {
         if (nscp->SCp.phase == -1) {
-            nscp->SCp.phase = SCSIRAWSERVICE;           /* default: raw svc. */ 
+            nscp->SCp.phase = CACHESERVICE;           /* default: cache svc. */ 
             if (nscp->cmnd[0] == TEST_UNIT_READY) {
                 TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", 
                         b, t, nscp->lun));
@@ -1789,8 +2322,9 @@
                 } else if ((ha->scan_mode & 0x0f) == 1) {
                     if (b == 0 && ((t == 0 && nscp->lun == 1) ||
                          (t == 1 && nscp->lun == 0))) {
-                        nscp->SCp.Status = GDT_SCAN_START;
-                        nscp->SCp.phase |= ((ha->scan_mode & 0x10 ? 1:0) << 8);
+                        nscp->SCp.sent_command = GDT_SCAN_START;
+                        nscp->SCp.phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) 
+                            | SCSIRAWSERVICE;
                         ha->scan_mode = 0x12;
                         TRACE2(("Scan mode: 0x%x (SCAN_START)\n", 
                                 ha->scan_mode));
@@ -1800,29 +2334,55 @@
                     }                   
                 } else if (ha->scan_mode == 0x12) {
                     if (b == ha->bus_cnt && t == ha->tid_cnt-1) {
-                        nscp->SCp.Status = GDT_SCAN_END;
+                        nscp->SCp.phase = SCSIRAWSERVICE;
+                        nscp->SCp.sent_command = GDT_SCAN_END;
                         ha->scan_mode &= 0x10;
                         TRACE2(("Scan mode: 0x%x (SCAN_END)\n", 
                                 ha->scan_mode));
                     }
                 }
             }
+            if (b == ha->virt_bus && nscp->cmnd[0] != INQUIRY &&
+                nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE &&
+                (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) {
+                /* always GDT_CLUST_INFO! */
+                nscp->SCp.sent_command = GDT_CLUST_INFO;
+            }
         }
         }
 
-        if (nscp->SCp.Status != -1) {
-            if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) {
+        if (nscp->SCp.sent_command != -1) {
+            if ((nscp->SCp.phase & 0xff) == CACHESERVICE) {
+                if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                    this_cmd = FALSE;
+                next_cmd = FALSE;
+            } else if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) {
                 if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b))))
                     this_cmd = FALSE;
                 next_cmd = FALSE;
+            } else {
+                memset((char*)nscp->sense_buffer,0,16);
+                nscp->sense_buffer[0] = 0x70;
+                nscp->sense_buffer[2] = NOT_READY;
+                nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                if (!nscp->SCp.have_data_in)
+                    nscp->SCp.have_data_in++;
+                else {
+                    GDTH_UNLOCK_HA(ha,flags);
+                    /* io_request_lock already active ! */
+                    nscp->scsi_done(nscp);
+                    GDTH_LOCK_HA(ha,flags);
+                }
             }
         } else
 
-        if (nscp->done == gdth_scsi_done) {
+#if LINUX_VERSION_CODE >= 0x010300
+        if (nscp->done == gdth_scsi_done && nscp->cmnd[0] == 0xff) {
             if (!(cmd_index=gdth_special_cmd(hanum,nscp)))
                 this_cmd = FALSE;
             next_cmd = FALSE;
         } else
+#endif
         if (b != ha->virt_bus) {
             if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW ||
                 !(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) 
@@ -1833,10 +2393,14 @@
             TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n",
                     nscp->cmnd[0], b, t, nscp->lun));
             nscp->result = DID_BAD_TARGET << 16;
-            GDTH_UNLOCK_HA(ha,flags);
-            /* io_request_lock already active ! */      
-            nscp->scsi_done(nscp);
-            GDTH_LOCK_HA(ha,flags);
+            if (!nscp->SCp.have_data_in)
+                nscp->SCp.have_data_in++;
+            else {
+                GDTH_UNLOCK_HA(ha,flags);
+                /* io_request_lock already active ! */      
+                nscp->scsi_done(nscp);
+                GDTH_LOCK_HA(ha,flags);
+            }
         } else {
             switch (nscp->cmnd[0]) {
               case TEST_UNIT_READY:
@@ -1849,7 +2413,24 @@
                 TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
                        nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
                        nscp->cmnd[4],nscp->cmnd[5]));
-                if (gdth_internal_cache_cmd(hanum,nscp)) {
+                if (ha->hdr[t].media_changed && nscp->cmnd[0] != INQUIRY) {
+                    /* return UNIT_ATTENTION */
+                    TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n",
+                             nscp->cmnd[0], t));
+                    ha->hdr[t].media_changed = FALSE;
+                    memset((char*)nscp->sense_buffer,0,16);
+                    nscp->sense_buffer[0] = 0x70;
+                    nscp->sense_buffer[2] = UNIT_ATTENTION;
+                    nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                    if (!nscp->SCp.have_data_in)
+                        nscp->SCp.have_data_in++;
+                    else {
+                        GDTH_UNLOCK_HA(ha,flags);
+                        /* io_request_lock already active ! */      
+                        nscp->scsi_done(nscp);
+                        GDTH_LOCK_HA(ha,flags);
+                    }
+                } else if (gdth_internal_cache_cmd(hanum,nscp)) {
                     GDTH_UNLOCK_HA(ha,flags);
                     /* io_request_lock already active ! */      
                     nscp->scsi_done(nscp);
@@ -1864,6 +2445,7 @@
                 if ( (nscp->cmnd[4]&1) && !(ha->hdr[t].devtype&1) ) {
                     TRACE(("Prevent r. nonremov. drive->do nothing\n"));
                     nscp->result = DID_OK << 16;
+                    nscp->sense_buffer[0] = 0;
                     if (!nscp->SCp.have_data_in)
                         nscp->SCp.have_data_in++;
                     else {
@@ -1881,11 +2463,36 @@
                 }
                 break;
                 
+              case RESERVE:
+              case RELEASE:
+                TRACE2(("cache cmd %s\n",nscp->cmnd[0] == RESERVE ?
+                        "RESERVE" : "RELEASE"));
+                if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                    this_cmd = FALSE;
+                break;
+                
               case READ_6:
               case WRITE_6:
               case READ_10:
               case WRITE_10:
-                if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                if (ha->hdr[t].media_changed) {
+                    /* return UNIT_ATTENTION */
+                    TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n",
+                             nscp->cmnd[0], t));
+                    ha->hdr[t].media_changed = FALSE;
+                    memset((char*)nscp->sense_buffer,0,16);
+                    nscp->sense_buffer[0] = 0x70;
+                    nscp->sense_buffer[2] = UNIT_ATTENTION;
+                    nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                    if (!nscp->SCp.have_data_in)
+                        nscp->SCp.have_data_in++;
+                    else {
+                        GDTH_UNLOCK_HA(ha,flags);
+                        /* io_request_lock already active ! */      
+                        nscp->scsi_done(nscp);
+                        GDTH_LOCK_HA(ha,flags);
+                    }
+                } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
                     this_cmd = FALSE;
                 break;
 
@@ -1985,7 +2592,10 @@
         inq.type_qual = (ha->hdr[t].devtype&4) ? TYPE_ROM:TYPE_DISK;
         /* you can here set all disks to removable, if you want to do
            a flush using the ALLOW_MEDIUM_REMOVAL command */
-        inq.modif_rmb = ha->hdr[t].devtype&1 ? 0x80:0x00;
+        inq.modif_rmb = 0x00;
+        if ((ha->hdr[t].devtype & 1) ||
+            (ha->hdr[t].cluster_type & CLUSTER_DRIVE))
+            inq.modif_rmb = 0x80;
         inq.version   = 2;
         inq.resp_aenc = 2;
         inq.add_length= 32;
@@ -2028,7 +2638,9 @@
         TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0]));
         break;
     }
+
     scp->result = DID_OK << 16;
+    scp->sense_buffer[0] = 0;
 
     if (!scp->SCp.have_data_in)
         scp->SCp.have_data_in++;
@@ -2043,8 +2655,9 @@
     register gdth_ha_str *ha;
     register gdth_cmd_str *cmdp;
     struct scatterlist *sl;
-    ushort i;
-    int cmd_index;
+    ushort i, cnt;
+    ulong32 no;
+    int cmd_index, read_write;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     cmdp = ha->pccb;
@@ -2066,37 +2679,46 @@
         gdth_set_sema0(hanum);
 
     /* fill command */
-    if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) {
+    read_write = FALSE;
+    if (scp->SCp.sent_command != -1) 
+        cmdp->OpCode = scp->SCp.sent_command;   /* special cache cmd. */
+    else if (scp->cmnd[0] == RESERVE) 
+        cmdp->OpCode = GDT_RESERVE_DRV;
+    else if (scp->cmnd[0] == RELEASE)
+        cmdp->OpCode = GDT_RELEASE_DRV;
+    else if (scp->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
         if (scp->cmnd[4] & 1)                   /* prevent ? */
-            cmdp->OpCode      = GDT_MOUNT;
+            cmdp->OpCode = GDT_MOUNT;
         else if (scp->cmnd[3] & 1)              /* removable drive ? */
-            cmdp->OpCode      = GDT_UNMOUNT;
+            cmdp->OpCode = GDT_UNMOUNT;
+        else
+            cmdp->OpCode = GDT_FLUSH;
+    } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10) {
+        read_write = TRUE;
+        if (gdth_write_through || ((ha->hdr[hdrive].rw_attribs & 1) && 
+                                   (ha->cache_feat & GDT_WR_THROUGH)))
+            cmdp->OpCode = GDT_WRITE_THR;
         else
-            cmdp->OpCode      = GDT_FLUSH;
+            cmdp->OpCode = GDT_WRITE;
     } else {
-        if (scp->cmnd[0]==WRITE_6 || scp->cmnd[0]==WRITE_10) {
-            if (gdth_write_through)
-                cmdp->OpCode  = GDT_WRITE_THR;
-            else
-                cmdp->OpCode  = GDT_WRITE;
-        } else {
-            cmdp->OpCode      = GDT_READ;
-        }
+        read_write = TRUE;
+        cmdp->OpCode = GDT_READ;
     }
+    
+    cmdp->BoardNode        = LOCALBOARD;
+    cmdp->u.cache.DeviceNo = hdrive;
+    cmdp->u.cache.BlockNo  = 1;
+    cmdp->u.cache.sg_canz  = 0;
 
-    cmdp->BoardNode           = LOCALBOARD;
-    cmdp->u.cache.DeviceNo    = hdrive;
-
-    if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) {
-        cmdp->u.cache.BlockNo = 1;
-        cmdp->u.cache.sg_canz = 0;
-    } else {
+    if (read_write) {
         if (scp->cmd_len != 6) {
-            cmdp->u.cache.BlockNo = ntohl(*(ulong32*)&scp->cmnd[2]);
-            cmdp->u.cache.BlockCnt= (ulong32)ntohs(*(ushort*)&scp->cmnd[7]);
+            memcpy(&no, &scp->cmnd[2], sizeof(ulong32));
+            cmdp->u.cache.BlockNo = ntohl(no);
+            memcpy(&cnt, &scp->cmnd[7], sizeof(ushort));
+            cmdp->u.cache.BlockCnt = (ulong32)ntohs(cnt);
         } else {
-            cmdp->u.cache.BlockNo = 
-                ntohl(*(ulong32*)&scp->cmnd[0]) & 0x001fffffUL;
+            memcpy(&no, &scp->cmnd[0], sizeof(ulong32));
+            cmdp->u.cache.BlockNo = ntohl(no) & 0x001fffffUL;
             cmdp->u.cache.BlockCnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4];
         }
 
@@ -2189,8 +2811,8 @@
         gdth_set_sema0(hanum);
 
     /* fill command */  
-    if (scp->SCp.Status != -1) {
-        cmdp->OpCode           = scp->SCp.Status;       /* special raw cmd. */
+    if (scp->SCp.sent_command != -1) {
+        cmdp->OpCode           = scp->SCp.sent_command; /* special raw cmd. */
         cmdp->BoardNode        = LOCALBOARD;
         cmdp->u.raw.direction  = (scp->SCp.phase >> 8);
         TRACE2(("special raw cmd 0x%x param 0x%x\n", 
@@ -2209,12 +2831,12 @@
         cmdp->u.raw.lun        = l;
         cmdp->u.raw.bus        = b;
         cmdp->u.raw.priority   = 0;
-        cmdp->u.raw.link_p     = NULL;
+        cmdp->u.raw.link_p     = 0;
         cmdp->u.raw.sdlen      = scp->request_bufflen;
         cmdp->u.raw.sense_len  = 16;
         cmdp->u.raw.sense_data = virt_to_bus(scp->sense_buffer);
         cmdp->u.raw.direction  = 
-            gdth_direction_tab[scp->cmnd[0]]==DOU ? DATA_OUT : DATA_IN;
+            gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN;
         memcpy(cmdp->u.raw.cmd,scp->cmnd,12);
 
         if (scp->use_sg) {
@@ -2346,8 +2968,12 @@
 
     if (ebuffer[elastidx].event_source == source &&
         ebuffer[elastidx].event_idx == idx &&
-        !memcmp((char *)&ebuffer[elastidx].event_data.eu,
-            (char *)&evt->eu, evt->size)) {
+        ((evt->size != 0 && ebuffer[elastidx].event_data.size != 0 &&
+            !memcmp((char *)&ebuffer[elastidx].event_data.eu,
+            (char *)&evt->eu, evt->size)) ||
+        (evt->size == 0 && ebuffer[elastidx].event_data.size == 0 &&
+            !strcmp((char *)&ebuffer[elastidx].event_data.event_string,
+            (char *)&evt->event_string)))) { 
         e = &ebuffer[elastidx];
         do_gettimeofday(&tv);
         e->last_stamp = tv.tv_sec;
@@ -2370,6 +2996,7 @@
         e->first_stamp = e->last_stamp = tv.tv_sec;
         e->same_count = 1;
         e->event_data = *evt;
+        e->application = 0;
     }
     return e;
 }
@@ -2449,18 +3076,20 @@
 
 /* SCSI interface functions */
 
+#if LINUX_VERSION_CODE >= 0x010346
 static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
+#else
+static void gdth_interrupt(int irq,struct pt_regs *regs)
+#endif
 {
     register gdth_ha_str *ha;
     gdt6m_dpram_str *dp6m_ptr;
     gdt6_dpram_str *dp6_ptr;
     gdt2_dpram_str *dp2_ptr;
     Scsi_Cmnd *scp;
-    int hanum, rval;
+    int hanum, rval, i;
     unchar IStatus;
-    ushort CmdStatus, Service = 0;
-    ulong32 InfoBytes, InfoBytes2 = 0;
-    gdth_evt_data dvr;
+    ushort Service;
     ulong flags = 0;
 
     TRACE(("gdth_interrupt() IRQ %d\n",irq));
@@ -2478,9 +3107,7 @@
 
     /* search controller */
     if ((hanum = gdth_get_status(&IStatus,irq)) == -1) {
-        /*
-        TRACE2(("gdth_interrupt(): Spurious interrupt received\n"));
-        */
+        /* spurious interrupt */
         if (!gdth_polling)
             GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
         return;
@@ -2494,34 +3121,28 @@
     if (ha->type == GDT_EISA) {
         if (IStatus & 0x80) {                       /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = inw(ha->bmic + MAILBOXREG+8);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
-            if (IStatus == ASYNCINDEX) {            /* async. event ? */
-                Service = inw(ha->bmic + MAILBOXREG+10);
-                InfoBytes2 = inl(ha->bmic + MAILBOXREG+4);
-            }
+            ha->status = inw(ha->bmic + MAILBOXREG+8);
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
         } else                                      /* no error */
-            CmdStatus = S_OK;
-        InfoBytes = inl(ha->bmic + MAILBOXREG+12);
-        if (gdth_polling)                           /* init. -> more info */
-            InfoBytes2 = inl(ha->bmic + MAILBOXREG+4);
+            ha->status = S_OK;
+        ha->info = inl(ha->bmic + MAILBOXREG+12);
+        ha->service = inw(ha->bmic + MAILBOXREG+10);
+        ha->info2 = inl(ha->bmic + MAILBOXREG+4);
+
         outb(0xff, ha->bmic + EDOORREG);            /* acknowledge interrupt */
         outb(0x00, ha->bmic + SEMA1REG);            /* reset status semaphore */
     } else if (ha->type == GDT_ISA) {
         dp2_ptr = (gdt2_dpram_str *)ha->brd;
         if (IStatus & 0x80) {                       /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = gdth_readw(&dp2_ptr->u.ic.Status);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
-            if (IStatus == ASYNCINDEX) {            /* async. event ? */
-                Service = gdth_readw(&dp2_ptr->u.ic.Service);
-                InfoBytes2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
-            }
+            ha->status = gdth_readw(&dp2_ptr->u.ic.Status);
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
         } else                                      /* no error */
-            CmdStatus = S_OK;
-        InfoBytes = gdth_readl(&dp2_ptr->u.ic.Info[0]);
-        if (gdth_polling)                           /* init. -> more info */
-            InfoBytes2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
+            ha->status = S_OK;
+        ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]);
+        ha->service = gdth_readw(&dp2_ptr->u.ic.Service);
+        ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
+
         gdth_writeb(0xff, &dp2_ptr->io.irqdel);     /* acknowledge interrupt */
         gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);   /* reset command index */
         gdth_writeb(0, &dp2_ptr->io.Sema1);         /* reset status semaphore */
@@ -2529,52 +3150,56 @@
         dp6_ptr = (gdt6_dpram_str *)ha->brd;
         if (IStatus & 0x80) {                       /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = gdth_readw(&dp6_ptr->u.ic.Status);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
-            if (IStatus == ASYNCINDEX) {        /* async. event ? */
-                Service = gdth_readw(&dp6_ptr->u.ic.Service);
-                InfoBytes2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
-            }
+            ha->status = gdth_readw(&dp6_ptr->u.ic.Status);
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
         } else                                      /* no error */
-            CmdStatus = S_OK;
-        InfoBytes = gdth_readl(&dp6_ptr->u.ic.Info[0]);
-        if (gdth_polling)                           /* init. -> more info */
-            InfoBytes2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
+            ha->status = S_OK;
+        ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]);
+        ha->service = gdth_readw(&dp6_ptr->u.ic.Service);
+        ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
+
         gdth_writeb(0xff, &dp6_ptr->io.irqdel);     /* acknowledge interrupt */
         gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);   /* reset command index */
         gdth_writeb(0, &dp6_ptr->io.Sema1);         /* reset status semaphore */
     } else if (ha->type == GDT_PCINEW) {
         if (IStatus & 0x80) {                       /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = inw(PTR2USHORT(&ha->plx->status));
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
-            if (IStatus == ASYNCINDEX) {            /* async. event ? */
-                Service = inw(PTR2USHORT(&ha->plx->service));
-                InfoBytes2 = inl(PTR2USHORT(&ha->plx->info[1]));
-            }
+            ha->status = inw(PTR2USHORT(&ha->plx->status));
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
         } else
-            CmdStatus = S_OK;
+            ha->status = S_OK;
+        ha->info = inl(PTR2USHORT(&ha->plx->info[0]));
+        ha->service = inw(PTR2USHORT(&ha->plx->service));
+        ha->info2 = inl(PTR2USHORT(&ha->plx->info[1]));
 
-        InfoBytes = inl(PTR2USHORT(&ha->plx->info[0]));
-        if (gdth_polling)                           /* init. -> more info */
-            InfoBytes2 = inl(PTR2USHORT(&ha->plx->info[1]));
         outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); 
         outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); 
     } else if (ha->type == GDT_PCIMPR) {
         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
         if (IStatus & 0x80) {                       /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = gdth_readw(&dp6m_ptr->i960r.status);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
-            if (IStatus == ASYNCINDEX) {            /* async. event ? */
-                Service = gdth_readw(&dp6m_ptr->i960r.service);
-                InfoBytes2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
-            }
+            ha->status = gdth_readw(&dp6m_ptr->i960r.status);
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
         } else                                      /* no error */
-            CmdStatus = S_OK;
-        InfoBytes = gdth_readl(&dp6m_ptr->i960r.info[0]);
-        if (gdth_polling)                           /* init. -> more info */
-            InfoBytes2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
+            ha->status = S_OK;
+        ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]);
+        ha->service = gdth_readw(&dp6m_ptr->i960r.service);
+        ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
+
+        /* event string */
+        if (IStatus == ASYNCINDEX) {
+            if (ha->service != SCREENSERVICE &&
+                (ha->fw_vers & 0xff) >= 0x1a) {
+                ha->dvr.severity =   
+                    gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.severity);
+                for (i = 0; i < 256; ++i) {
+                    ha->dvr.event_string[i] = gdth_readb
+                        (&((gdt6m_dpram_str *)ha->brd)->i960r.evt_str[i]);
+                    if (ha->dvr.event_string[i] == 0)
+                        break;
+                }
+            }
+        }
         gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
         gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
     } else {
@@ -2585,10 +3210,7 @@
     }
 
     TRACE(("gdth_interrupt() index %d stat %d info %d\n",
-           IStatus,CmdStatus,InfoBytes));
-    ha->status = CmdStatus;
-    ha->info   = InfoBytes;
-    ha->info2  = InfoBytes2;
+           IStatus,ha->status,ha->info));
 
     if (gdth_from_wait) {
         wait_hanum = hanum;
@@ -2597,7 +3219,7 @@
 
     if (IStatus == ASYNCINDEX) {
         TRACE2(("gdth_interrupt() async. event\n"));
-        gdth_async_event(hanum,Service);
+        gdth_async_event(hanum);
         if (!gdth_polling)
             GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
         gdth_next(hanum);
@@ -2606,9 +3228,9 @@
 
     if (IStatus == SPEZINDEX) {
         TRACE2(("Service unknown or not initialized !\n"));
-        dvr.size = sizeof(dvr.eu.driver);
-        dvr.eu.driver.ionode = hanum;
-        gdth_store_event(ha, ES_DRIVER, 4, &dvr);
+        ha->dvr.size = sizeof(ha->dvr.eu.driver);
+        ha->dvr.eu.driver.ionode = hanum;
+        gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr);
         if (!gdth_polling)
             GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
         return;
@@ -2618,10 +3240,10 @@
     ha->cmd_tab[IStatus-2].cmnd = UNUSED_CMND;
     if (scp == UNUSED_CMND) {
         TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
-        dvr.size = sizeof(dvr.eu.driver);
-        dvr.eu.driver.ionode = hanum;
-        dvr.eu.driver.index = IStatus;
-        gdth_store_event(ha, ES_DRIVER, 1, &dvr);
+        ha->dvr.size = sizeof(ha->dvr.eu.driver);
+        ha->dvr.eu.driver.ionode = hanum;
+        ha->dvr.eu.driver.index = IStatus;
+        gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr);
         if (!gdth_polling)
             GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
         return;
@@ -2652,9 +3274,7 @@
     register gdth_ha_str *ha;
     gdth_msg_str *msg;
     gdth_cmd_str *cmdp;
-    char c='\r';
-    ushort i;
-    gdth_evt_data dvr;
+    unchar b;
 
     ha   = HADATA(gdth_ctr_tab[hanum]);
     cmdp = ha->pccb;
@@ -2682,11 +3302,11 @@
             cmdp->OpCode        = GDT_READ;
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
-            cmdp->u.screen.msg_handle= msg->msg_handle;
-            cmdp->u.screen.msg_addr  = virt_to_bus(msg);
+            cmdp->u.screen.su.msg.msg_handle= msg->msg_handle;
+            cmdp->u.screen.su.msg.msg_addr  = virt_to_bus(msg);
             ha->scratch_busy = TRUE;
             ha->cmd_offs_dpmem = 0;
-            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) 
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
                 + sizeof(ulong32);
             ha->cmd_cnt = 0;
             gdth_copy_command(hanum);
@@ -2695,22 +3315,19 @@
         }
 
         if (msg->msg_answer && msg->msg_alen) {
-            for (i=0; i<msg->msg_alen && i<MSGLEN; ++i) {
-                /* getchar() ?? */           
-                /* .. */
-                if (c == '\r')
-                    break;
-                msg->msg_text[i] = c; 
-            }
-            msg->msg_alen -= i;
-            if (c!='\r' && msg->msg_alen!=0) {
-                msg->msg_answer = 1;
-                msg->msg_ext    = 1;
+            /* default answers (getchar() not possible) */
+            if (msg->msg_alen == 1) {
+                msg->msg_alen = 0;
+                msg->msg_len = 1;
+                msg->msg_text[0] = 0;
             } else {
-                msg->msg_ext    = 0;
-                msg->msg_answer = 0;
+                msg->msg_alen -= 2;
+                msg->msg_len = 2;
+                msg->msg_text[0] = 1;
+                msg->msg_text[1] = 0;
             }
-            msg->msg_len = i;
+            msg->msg_ext    = 0;
+            msg->msg_answer = 0;
             while (gdth_test_busy(hanum))
                 gdth_delay(0);
             cmdp->Service       = SCREENSERVICE;
@@ -2720,11 +3337,11 @@
             cmdp->OpCode        = GDT_WRITE;
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
-            cmdp->u.screen.msg_handle= msg->msg_handle;
-            cmdp->u.screen.msg_addr  = virt_to_bus(msg);
+            cmdp->u.screen.su.msg.msg_handle= msg->msg_handle;
+            cmdp->u.screen.su.msg.msg_addr  = virt_to_bus(msg);
             ha->scratch_busy = TRUE;
             ha->cmd_offs_dpmem = 0;
-            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) 
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
                 + sizeof(ulong32);
             ha->cmd_cnt = 0;
             gdth_copy_command(hanum);
@@ -2734,54 +3351,110 @@
         printk("\n");
 
     } else {
-        if (scp->SCp.Status == -1 && scp->channel != ha->virt_bus) {
-            ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[scp->target]--;
+        b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
+        if (scp->SCp.sent_command == -1 && b != ha->virt_bus) {
+            ha->raw[BUS_L2P(ha,b)].io_cnt[scp->target]--;
         }
         /* cache or raw service */
         if (ha->status == S_OK) {
-            scp->SCp.Message = S_OK;
-            if (scp->SCp.Status != -1) {
+            scp->SCp.Status = S_OK;
+            scp->SCp.Message = ha->info;
+            if (scp->SCp.sent_command != -1) {
                 TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n",
-                        scp->SCp.Status));
-                scp->SCp.Status = -1;
+                        scp->SCp.sent_command));
+                /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */
+                if (scp->SCp.sent_command == GDT_CLUST_INFO) {
+                    ha->hdr[scp->target].cluster_type = (unchar)ha->info;
+                    if (!(ha->hdr[scp->target].cluster_type & 
+                        CLUSTER_MOUNTED)) {
+                        /* NOT MOUNTED -> MOUNT */
+                        scp->SCp.sent_command = GDT_MOUNT;
+                        if (ha->hdr[scp->target].cluster_type & 
+                            CLUSTER_RESERVED) {
+                            /* cluster drive RESERVED (on the other node) */
+                            scp->SCp.phase = -2;      /* reservation conflict */
+                        }
+                    } else {
+                        scp->SCp.sent_command = -1;
+                    }
+                } else {
+                    if (scp->SCp.sent_command == GDT_MOUNT) {
+                        ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED;
+                        ha->hdr[scp->target].media_changed = TRUE;
+                    } else if (scp->SCp.sent_command == GDT_UNMOUNT) {
+                        ha->hdr[scp->target].cluster_type &= ~CLUSTER_MOUNTED;
+                        ha->hdr[scp->target].media_changed = TRUE;
+                    } 
+                    scp->SCp.sent_command = -1;
+                }
+                /* retry */
                 scp->SCp.this_residual = HIGH_PRI;
                 return 2;
+            } else {
+                /* RESERVE/RELEASE ? */
+                if (scp->cmnd[0] == RESERVE) {
+                    ha->hdr[scp->target].cluster_type |= CLUSTER_RESERVED;
+                } else if (scp->cmnd[0] == RELEASE) {
+                    ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
+                }           
+                scp->result = DID_OK << 16;
+                scp->sense_buffer[0] = 0;
             }
-            scp->result = DID_OK << 16;
         } else if (ha->status == S_BSY) {
             TRACE2(("Controller busy -> retry !\n"));
-            scp->SCp.Message = S_BSY;
+            scp->SCp.Status = S_BSY;
+            scp->SCp.Message = ha->info;
+            if (scp->SCp.sent_command == GDT_MOUNT)
+                scp->SCp.sent_command = GDT_CLUST_INFO;
+            /* retry */
             return 2;
         } else {
-            scp->SCp.Message = (int)((ha->info<<16)|ha->status);
-            if (scp->SCp.Status != -1) {
+            scp->SCp.Status = ha->status;
+            scp->SCp.Message = ha->info;
+
+            if (scp->SCp.sent_command != -1) {
                 TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n",
-                        scp->SCp.Status, ha->status));
-                scp->SCp.Status = -1;
-                scp->SCp.this_residual = HIGH_PRI;
-                return 2;
-            }
-            if (service == CACHESERVICE) {
+                        scp->SCp.sent_command, ha->status));
+                if (scp->SCp.sent_command == GDT_SCAN_START ||
+                    scp->SCp.sent_command == GDT_SCAN_END) {
+                    scp->SCp.sent_command = -1;
+                    /* retry */
+                    scp->SCp.this_residual = HIGH_PRI;
+                    return 2;
+                }
                 memset((char*)scp->sense_buffer,0,16);
                 scp->sense_buffer[0] = 0x70;
                 scp->sense_buffer[2] = NOT_READY;
                 scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-
+            } else if (service == CACHESERVICE) {
+                if (ha->status == S_CACHE_UNKNOWN &&
+                    (ha->hdr[scp->target].cluster_type & 
+                     CLUSTER_RESERVE_STATE) == CLUSTER_RESERVE_STATE) {
+                    /* bus reset -> force GDT_CLUST_INFO */
+                    ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
+                }
+                memset((char*)scp->sense_buffer,0,16);
+                scp->sense_buffer[0] = 0x70;
+                scp->sense_buffer[2] = NOT_READY;
+                scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+#if LINUX_VERSION_CODE >= 0x010300
                 if (scp->done != gdth_scsi_done)
+#endif  
                 {
-                    dvr.size = sizeof(dvr.eu.sync);
-                    dvr.eu.sync.ionode  = hanum;
-                    dvr.eu.sync.service = service;
-                    dvr.eu.sync.status  = ha->status;
-                    dvr.eu.sync.info    = ha->info;
-                    dvr.eu.sync.hostdrive = scp->target;
+                    ha->dvr.size = sizeof(ha->dvr.eu.sync);
+                    ha->dvr.eu.sync.ionode  = hanum;
+                    ha->dvr.eu.sync.service = service;
+                    ha->dvr.eu.sync.status  = ha->status;
+                    ha->dvr.eu.sync.info    = ha->info;
+                    ha->dvr.eu.sync.hostdrive = scp->target;
                     if (ha->status >= 0x8000)
-                        gdth_store_event(ha, ES_SYNC, 0, &dvr);
+                        gdth_store_event(ha, ES_SYNC, 0, &ha->dvr);
                     else
-                        gdth_store_event(ha, ES_SYNC, service, &dvr);
+                        gdth_store_event(ha, ES_SYNC, service, &ha->dvr);
                 }
             } else {
-                if (ha->status!=S_RAW_SCSI || ha->info>=0x100) {
+                /* sense buffer filled from controller firmware (DMA) */
+                if (ha->status != S_RAW_SCSI || ha->info >= 0x100) {
                     scp->result = DID_BAD_TARGET << 16;
                 } else {
                     scp->result = (DID_OK << 16) | ha->info;
@@ -2944,12 +3617,17 @@
         "GDT HA %u, Uncorrectable DRAM error detected with ECC",
 /*72*/  "\011\000\002\012\001\013\001\014\001"
         "GDT HA %u, SCSI bus %u, ID %u, LUN %u: reassigning block",
+/*73*/  "\005\000\002\006\002"
+        "GDT HA %u, Host drive %u resetted locally",
+/*74*/  "\005\000\002\006\002"
+        "GDT HA %u, Host drive %u resetted remotely",
+/*75*/  "\003\000\002"
+        "GDT HA %u, async. status 75 unknown",
 };
 
 
-static int gdth_async_event(int hanum,int service)
+static int gdth_async_event(int hanum)
 {
-    gdth_evt_data dvr;
     gdth_ha_str *ha;
     gdth_msg_str *msg;
     gdth_cmd_str *cmdp;
@@ -2959,9 +3637,9 @@
     cmdp= ha->pccb;
     msg = (gdth_msg_str *)ha->pscratch;
     TRACE2(("gdth_async_event() ha %d serv %d\n",
-            hanum,service));
+            hanum,ha->service));
 
-    if (service == SCREENSERVICE) {
+    if (ha->service == SCREENSERVICE) {
         if (ha->status == MSG_REQUEST) {
             while (gdth_test_busy(hanum))
                 gdth_delay(0);
@@ -2972,11 +3650,11 @@
             cmdp->OpCode        = GDT_READ;
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
-            cmdp->u.screen.msg_handle= MSG_INV_HANDLE;
-            cmdp->u.screen.msg_addr  = virt_to_bus(msg);
+            cmdp->u.screen.su.msg.msg_handle= MSG_INV_HANDLE;
+            cmdp->u.screen.su.msg.msg_addr  = virt_to_bus(msg);
             ha->scratch_busy = TRUE;
             ha->cmd_offs_dpmem = 0;
-            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) 
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
                 + sizeof(ulong32);
             ha->cmd_cnt = 0;
             gdth_copy_command(hanum);
@@ -2991,14 +3669,29 @@
         }
 
     } else {
-        dvr.size = sizeof(dvr.eu.async);
-        dvr.eu.async.ionode   = hanum;
-        dvr.eu.async.service = service;
-        dvr.eu.async.status  = ha->status;
-        dvr.eu.async.info    = ha->info;
-        *(ulong32 *)dvr.eu.async.scsi_coord  = ha->info2;
-        gdth_store_event(ha, ES_ASYNC, service, &dvr);
-        gdth_log_event( &dvr, NULL );
+        if (ha->type == GDT_PCIMPR && 
+            (ha->fw_vers & 0xff) >= 0x1a) {
+            ha->dvr.size = 0;
+            ha->dvr.eu.async.ionode = hanum;
+            ha->dvr.eu.async.status  = ha->status;
+            /* severity and event_string already set! */
+        } else {        
+            ha->dvr.size = sizeof(ha->dvr.eu.async);
+            ha->dvr.eu.async.ionode   = hanum;
+            ha->dvr.eu.async.service = ha->service;
+            ha->dvr.eu.async.status  = ha->status;
+            ha->dvr.eu.async.info    = ha->info;
+            *(ulong32 *)ha->dvr.eu.async.scsi_coord  = ha->info2;
+        }
+        gdth_store_event( ha, ES_ASYNC, ha->service, &ha->dvr );
+        gdth_log_event( &ha->dvr, NULL );
+    
+        /* new host drive from expand? */
+        if (ha->service == CACHESERVICE && ha->status == 56) {
+            TRACE2(("gdth_async_event(): new host drive %d created\n",
+                    (ushort)ha->info));
+            gdth_analyse_hdrive(hanum, (ushort)ha->info);
+        }   
     }
     return 1;
 }
@@ -3010,7 +3703,14 @@
     int i,j;
 
     TRACE2(("gdth_log_event()\n"));
-    if (dvr->eu.async.service == CACHESERVICE && 
+    if (dvr->size == 0) {
+        if (buffer == NULL) {
+            printk("Adapter %d: %s\n",dvr->eu.async.ionode,dvr->event_string); 
+        } else {
+            sprintf(buffer,"Adapter %d: %s\n",
+                dvr->eu.async.ionode,dvr->event_string); 
+        }
+    } else if (dvr->eu.async.service == CACHESERVICE && 
         INDEX_OK(dvr->eu.async.status, async_cache_tab)) {
         TRACE2(("GDT: Async. event cache service, event no.: %d\n",
                 dvr->eu.async.status));
@@ -3081,8 +3781,96 @@
 }
 #endif
 
+GDTH_INITFUNC(void, internal_setup(char *str,int *ints))
+{
+    int i, argc;
+    char *cur_str, *argv;
 
-int __init gdth_detect(Scsi_Host_Template *shtp)
+    TRACE2(("internal_setup() str %s ints[0] %d\n", 
+            str ? str:"NULL", ints ? ints[0]:0));
+
+    /* read irq[] from ints[] */
+    if (ints) {
+        argc = ints[0];
+        if (argc > 0) {
+            if (argc > MAXHA)
+                argc = MAXHA;
+            for (i = 0; i < argc; ++i)
+                irq[i] = ints[i+1];
+        }
+    }
+
+    /* analyse string */
+    argv = str;
+    while (argv && (cur_str = strchr(argv, ':'))) {
+        int val = 0, c = *++cur_str;
+        
+        if (c == 'n' || c == 'N')
+            val = 0;
+        else if (c == 'y' || c == 'Y')
+            val = 1;
+        else
+            val = (int)simple_strtoul(cur_str, NULL, 0);
+
+        if (!strncmp(argv, "disable:", 8))
+            disable = val;
+        else if (!strncmp(argv, "reserve_mode:", 13))
+            reserve_mode = val;
+        else if (!strncmp(argv, "reverse_scan:", 13))
+            reverse_scan = val;
+        else if (!strncmp(argv, "hdr_channel:", 12))
+            hdr_channel = val;
+        else if (!strncmp(argv, "max_ids:", 8))
+            max_ids = val;
+        else if (!strncmp(argv, "rescan:", 7))
+            rescan = val;
+        else if (!strncmp(argv, "virt_ctr:", 9))
+            virt_ctr = val;
+        else if (!strncmp(argv, "shared_access:", 14))
+            shared_access = val;
+        else if (!strncmp(argv, "reserve_list:", 13)) {
+            reserve_list[0] = val;
+            for (i = 1; i < MAX_RES_ARGS; i++) {
+                cur_str = strchr(cur_str, ',');
+                if (!cur_str)
+                    break;
+                if (!isdigit((int)*++cur_str)) {
+                    --cur_str;          
+                    break;
+                }
+                reserve_list[i] = 
+                    (int)simple_strtoul(cur_str, NULL, 0);
+            }
+            if (!cur_str)
+                break;
+            argv = ++cur_str;
+            continue;
+        }
+
+        if ((argv = strchr(argv, ',')))
+            ++argv;
+    }
+}
+
+GDTH_INITFUNC(int, option_setup(char *str))
+{
+    int ints[MAXHA];
+    char *cur = str;
+    int i = 1;
+
+    TRACE2(("option_setup() str %s\n", str ? str:"NULL")); 
+
+    while (cur && isdigit(*cur) && i <= MAXHA) {
+        ints[i++] = simple_strtoul(cur, NULL, 0);
+        if ((cur = strchr(cur, ',')) != NULL) cur++;
+    }
+
+    ints[0] = i - 1;
+    internal_setup(cur, ints);
+    return 1;
+}
+
+GDTH_INITFUNC(int, gdth_detect(Scsi_Host_Template *shtp))
 {
     struct Scsi_Host *shp;
     gdth_ha_str *ha;
@@ -3125,18 +3913,23 @@
             break;
         if (gdth_search_isa(isa_bios)) {        /* controller found */
             shp = scsi_register(shtp,sizeof(gdth_ext_str));
-            if(shp == NULL)
-            	continue;
             ha = HADATA(shp);
             if (!gdth_init_isa(isa_bios,ha)) {
                 scsi_unregister(shp);
                 continue;
             }
+#ifdef __ia64__
+            break;
+#else
             /* controller found and initialized */
             printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
                    isa_bios,ha->irq,ha->drq);
 
+#if LINUX_VERSION_CODE >= 0x010346 
             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha))
+#else
+            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
+#endif
             {
                 printk("GDT-ISA: Unable to allocate IRQ\n");
                 scsi_unregister(shp);
@@ -3144,7 +3937,11 @@
             }
             if (request_dma(ha->drq,"gdth")) {
                 printk("GDT-ISA: Unable to allocate DMA channel\n");
+#if LINUX_VERSION_CODE >= 0x010346 
                 free_irq(ha->irq,NULL);
+#else
+                free_irq(ha->irq);
+#endif
                 scsi_unregister(shp);
                 continue;
             }
@@ -3161,7 +3958,12 @@
             NUMDATA(shp)->busnum= 0;
 
             ha->pccb = CMDDATA(shp);
-            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, GDTH_SCRATCH_ORD);
+#if LINUX_VERSION_CODE >= 0x020322
+            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 
+                                                     GDTH_SCRATCH_ORD);
+#else
+            ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+#endif
             ha->scratch_busy = FALSE;
             ha->req_first = NULL;
             ha->tid_cnt = MAX_HDRIVES;
@@ -3176,8 +3978,16 @@
                 --gdth_ctr_count;
                 --gdth_ctr_vcount;
                 if (ha->pscratch != NULL)
+#if LINUX_VERSION_CODE >= 0x020322
                     free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
+#else
+                    scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+#endif
+#if LINUX_VERSION_CODE >= 0x010346 
                 free_irq(ha->irq,NULL);
+#else
+                free_irq(ha->irq);
+#endif
                 scsi_unregister(shp);
                 continue;
             }
@@ -3185,11 +3995,29 @@
                 hdr_channel = ha->bus_cnt;
             ha->virt_bus = hdr_channel;
 
+#if LINUX_VERSION_CODE >= 0x020000
             shp->max_id      = ha->tid_cnt;
             shp->max_lun     = MAXLUN;
-            shp->max_channel = ha->bus_cnt;
+            shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+            if (virt_ctr)  
+#endif
+            {
+                virt_ctr = 1;
+                /* register addit. SCSI channels as virtual controllers */
+                for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                    shp = scsi_register(shtp,sizeof(gdth_num_str));
+                    shp->unchecked_isa_dma = 1;
+                    shp->irq = ha->irq;
+                    shp->dma_channel = ha->drq;
+                    gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                    NUMDATA(shp)->hanum = (ushort)hanum;
+                    NUMDATA(shp)->busnum = b;
+                }
+            }  
+
             GDTH_INIT_LOCK_HA(ha);
             gdth_enable_int(hanum);
+#endif /* !__ia64__ */
         }
     }
 
@@ -3199,8 +4027,6 @@
             break;
         if (gdth_search_eisa(eisa_slot)) {      /* controller found */
             shp = scsi_register(shtp,sizeof(gdth_ext_str));
-            if(shp == NULL)
-            	continue;
             ha = HADATA(shp);
             if (!gdth_init_eisa(eisa_slot,ha)) {
                 scsi_unregister(shp);
@@ -3210,7 +4036,11 @@
             printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
                    eisa_slot>>12,ha->irq);
 
+#if LINUX_VERSION_CODE >= 0x010346 
             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha))
+#else
+            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
+#endif
             {
                 printk("GDT-EISA: Unable to allocate IRQ\n");
                 scsi_unregister(shp);
@@ -3229,7 +4059,12 @@
                     NUMDATA(shp)->hanum));
 
             ha->pccb = CMDDATA(shp);
-            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, GDTH_SCRATCH_ORD);
+#if LINUX_VERSION_CODE >= 0x020322
+            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 
+                                                     GDTH_SCRATCH_ORD);
+#else
+            ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+#endif
             ha->scratch_busy = FALSE;
             ha->req_first = NULL;
             ha->tid_cnt = MAX_HDRIVES;
@@ -3244,8 +4079,16 @@
                 --gdth_ctr_count;
                 --gdth_ctr_vcount;
                 if (ha->pscratch != NULL)
+#if LINUX_VERSION_CODE >= 0x020322
                     free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
+#else
+                    scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+#endif
+#if LINUX_VERSION_CODE >= 0x010346 
                 free_irq(ha->irq,NULL);
+#else
+                free_irq(ha->irq);
+#endif
                 scsi_unregister(shp);
                 continue;
             }
@@ -3253,16 +4096,37 @@
                 hdr_channel = ha->bus_cnt;
             ha->virt_bus = hdr_channel;
 
+#if LINUX_VERSION_CODE >= 0x020000
             shp->max_id      = ha->tid_cnt;
             shp->max_lun     = MAXLUN;
-            shp->max_channel = ha->bus_cnt;
+            shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+            if (virt_ctr)  
+#endif
+            {
+                virt_ctr = 1;
+                /* register addit. SCSI channels as virtual controllers */
+                for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                    shp = scsi_register(shtp,sizeof(gdth_num_str));
+                    shp->unchecked_isa_dma = 0;
+                    shp->irq = ha->irq;
+                    shp->dma_channel = 0xff;
+                    gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                    NUMDATA(shp)->hanum = (ushort)hanum;
+                    NUMDATA(shp)->busnum = b;
+                }
+            }  
+
             GDTH_INIT_LOCK_HA(ha);
             gdth_enable_int(hanum);
         }
     }
 
     /* scanning for PCI controllers */
+#if LINUX_VERSION_CODE >= 0x2015C
     if (pci_present())
+#else
+    if (pcibios_present())
+#endif
     {
         gdth_pci_str pcistr[MAXHA];
 
@@ -3272,8 +4136,6 @@
             if (gdth_ctr_count >= MAXHA)
                 break;
             shp = scsi_register(shtp,sizeof(gdth_ext_str));
-            if(shp == NULL)
-            	continue;
             ha = HADATA(shp);
             if (!gdth_init_pci(&pcistr[ctr],ha)) {
                 scsi_unregister(shp);
@@ -3283,14 +4145,18 @@
             printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
                    pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
 
+#if LINUX_VERSION_CODE >= 0x010346 
             if (request_irq(ha->irq, gdth_interrupt,
                             SA_INTERRUPT|SA_SHIRQ, "gdth", ha))
+#else
+            if (request_irq(ha->irq, gdth_interrupt,
+                            SA_INTERRUPT|SA_SHIRQ, "gdth")) 
+#endif
             {
                 printk("GDT-PCI: Unable to allocate IRQ\n");
                 scsi_unregister(shp);
                 continue;
             }
-	    scsi_set_pci_device(shp, pcistr[ctr].pdev);
             shp->unchecked_isa_dma = 0;
             shp->irq = ha->irq;
             shp->dma_channel = 0xff;
@@ -3302,7 +4168,12 @@
             NUMDATA(shp)->busnum= 0;
 
             ha->pccb = CMDDATA(shp);
-            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, GDTH_SCRATCH_ORD);
+#if LINUX_VERSION_CODE >= 0x020322
+            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 
+                                                     GDTH_SCRATCH_ORD);
+#else
+            ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+#endif
             ha->scratch_busy = FALSE;
             ha->req_first = NULL;
             ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES;
@@ -3317,8 +4188,16 @@
                 --gdth_ctr_count;
                 --gdth_ctr_vcount;
                 if (ha->pscratch != NULL)
+#if LINUX_VERSION_CODE >= 0x020322
                     free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
+#else
+                    scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+#endif
+#if LINUX_VERSION_CODE >= 0x010346 
                 free_irq(ha->irq,NULL);
+#else
+                free_irq(ha->irq);
+#endif
                 scsi_unregister(shp);
                 continue;
             }
@@ -3326,9 +4205,26 @@
                 hdr_channel = ha->bus_cnt;
             ha->virt_bus = hdr_channel;
 
+#if LINUX_VERSION_CODE >= 0x020000
             shp->max_id      = ha->tid_cnt;
             shp->max_lun     = MAXLUN;
-            shp->max_channel = ha->bus_cnt;
+            shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+            if (virt_ctr)  
+#endif
+            {
+                virt_ctr = 1;
+                /* register addit. SCSI channels as virtual controllers */
+                for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                    shp = scsi_register(shtp,sizeof(gdth_num_str));
+                    shp->unchecked_isa_dma = 0;
+                    shp->irq = ha->irq;
+                    shp->dma_channel = 0xff;
+                    gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                    NUMDATA(shp)->hanum = (ushort)hanum;
+                    NUMDATA(shp)->busnum = b;
+                }
+            }  
+
             GDTH_INIT_LOCK_HA(ha);
             gdth_enable_int(hanum);
         }
@@ -3344,7 +4240,9 @@
         gdth_timer.function = gdth_timeout;
         add_timer(&gdth_timer);
 #endif
+#if LINUX_VERSION_CODE >= 0x020100
         register_reboot_notifier(&gdth_notifier);
+#endif
     }
     gdth_polling = FALSE;
     return gdth_ctr_vcount;
@@ -3360,15 +4258,27 @@
     if (NUMDATA(shp)->busnum == 0) {
         hanum = NUMDATA(shp)->hanum;
         ha    = HADATA(gdth_ctr_tab[hanum]);
+#if LINUX_VERSION_CODE >= 0x010300
         gdth_flush(hanum);
+#endif
 
         if (shp->irq) {
+#if LINUX_VERSION_CODE >= 0x010346
             free_irq(shp->irq,NULL);
+#else
+            free_irq(shp->irq);
+#endif
         }
+#ifndef __ia64__
         if (shp->dma_channel != 0xff) {
             free_dma(shp->dma_channel);
         }
+#endif
+#if LINUX_VERSION_CODE >= 0x020322
         free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
+#else
+        scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+#endif
         gdth_ctr_released++;
         TRACE2(("gdth_release(): HA %d of %d\n", 
                 gdth_ctr_released, gdth_ctr_count));
@@ -3377,7 +4287,9 @@
 #ifdef GDTH_STATISTICS
             del_timer(&gdth_timer);
 #endif
+#if LINUX_VERSION_CODE >= 0x020100
             unregister_reboot_notifier(&gdth_notifier);
+#endif
         }
     }
 
@@ -3437,12 +4349,17 @@
     return SCSI_ABORT_SNOOZE;
 }
 
+#if LINUX_VERSION_CODE >= 0x010346
 int gdth_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
+#else
+int gdth_reset(Scsi_Cmnd *scp)
+#endif
 {
     TRACE2(("gdth_reset()\n"));
     return SCSI_RESET_PUNT;
 }
 
+#if LINUX_VERSION_CODE >= 0x02015F
 /* new error handling */
 int gdth_eh_abort(Scsi_Cmnd *scp)
 {
@@ -3462,28 +4379,50 @@
     gdth_ha_str *ha;
     ulong flags;
     Scsi_Cmnd *cmnd;
+    unchar b;
 
     TRACE2(("gdth_eh_bus_reset()\n"));
     hanum = NUMDATA(scp->host)->hanum;
+    b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
     ha    = HADATA(gdth_ctr_tab[hanum]);
-    if (scp->channel == ha->virt_bus)
-        return FAILED;
 
+    /* clear command tab */
     GDTH_LOCK_HA(ha, flags);
-    for (i = 0; i < MAXID; ++i)
-        ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[i] = 0;
     for (i = 0; i < GDTH_MAXCMDS; ++i) {
         cmnd = ha->cmd_tab[i].cmnd;
-        if (!SPECIAL_SCP(cmnd) && cmnd->channel == scp->channel)
+        if (!SPECIAL_SCP(cmnd) && cmnd->channel == b)
             ha->cmd_tab[i].cmnd = UNUSED_CMND;
     }
-    gdth_polling = TRUE;
-    while (gdth_test_busy(hanum))
-        gdth_delay(0);
-    gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS,
-                      BUS_L2P(ha,scp->channel), 0, 0);
-    gdth_polling = FALSE;
     GDTH_UNLOCK_HA(ha, flags);
+
+    if (b == ha->virt_bus) {
+        /* host drives */
+        for (i = 0; i < MAX_HDRIVES; ++i) {
+            if (ha->hdr[i].present) {
+                GDTH_LOCK_HA(ha, flags);
+                gdth_polling = TRUE;
+                while (gdth_test_busy(hanum))
+                    gdth_delay(0);
+                if (gdth_internal_cmd(hanum, CACHESERVICE, 
+                                      GDT_CLUST_RESET, i, 0, 0))
+                    ha->hdr[i].cluster_type &= ~CLUSTER_RESERVED;
+                gdth_polling = FALSE;
+                GDTH_UNLOCK_HA(ha, flags);
+            }
+        }
+    } else {
+        /* raw devices */
+        GDTH_LOCK_HA(ha, flags);
+        for (i = 0; i < MAXID; ++i)
+            ha->raw[BUS_L2P(ha,b)].io_cnt[i] = 0;
+        gdth_polling = TRUE;
+        while (gdth_test_busy(hanum))
+            gdth_delay(0);
+        gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS,
+                          BUS_L2P(ha,b), 0, 0);
+        gdth_polling = FALSE;
+        GDTH_UNLOCK_HA(ha, flags);
+    }
     return SUCCESS;
 }
 
@@ -3492,27 +4431,32 @@
     TRACE2(("gdth_eh_host_reset()\n"));
     return FAILED;
 }
+#endif
 
+#if LINUX_VERSION_CODE >= 0x010300
 int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
+#else
+int gdth_bios_param(Disk *disk,int dev,int *ip)
+#endif
 {
-    unchar t;
+    unchar b, t;
     int hanum;
     gdth_ha_str *ha;
 
     hanum = NUMDATA(disk->device->host)->hanum;
+    b = virt_ctr ? NUMDATA(disk->device->host)->busnum : disk->device->channel;
     t = disk->device->id;
-    TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", 
-            hanum, disk->device->channel, t));
+    TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", hanum, b, t)); 
     ha = HADATA(gdth_ctr_tab[hanum]);
 
-    if (disk->device->channel != ha->virt_bus || ha->hdr[t].heads == 0) {
+    if (b != ha->virt_bus || ha->hdr[t].heads == 0) {
         /* raw device or host drive without mapping information */
-	TRACE2(("Evaluate mapping\n"));
-	gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]);
+        TRACE2(("Evaluate mapping\n"));
+        gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]);
     } else {
-	ip[0] = ha->hdr[t].heads;
-	ip[1] = ha->hdr[t].secs;
-	ip[2] = disk->capacity / ip[0] / ip[1];
+        ip[0] = ha->hdr[t].heads;
+        ip[1] = ha->hdr[t].secs;
+        ip[2] = disk->capacity / ip[0] / ip[1];
     }
 
     TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n",
@@ -3521,24 +4465,6 @@
 }
 
 
-static void internal_done(Scsi_Cmnd *scp)
-{
-    scp->SCp.sent_command++;
-}
-
-int gdth_command(Scsi_Cmnd *scp)
-{
-    TRACE2(("gdth_command()\n"));
-
-    scp->SCp.sent_command = 0;
-    gdth_queuecommand(scp,internal_done);
-
-    while (!scp->SCp.sent_command)
-        barrier();
-    return scp->result;
-}
-
-
 int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
 {
     int hanum;
@@ -3550,171 +4476,173 @@
     scp->scsi_done = (void *)done;
     scp->SCp.have_data_in = 1;
     scp->SCp.phase = -1;
-    scp->SCp.Status = -1;
+    scp->SCp.sent_command = -1;
     hanum = NUMDATA(scp->host)->hanum;
 #ifdef GDTH_STATISTICS
     ++act_ios;
 #endif
 
     priority = DEFAULT_PRI;
+#if LINUX_VERSION_CODE >= 0x010300
     if (scp->done == gdth_scsi_done)
         priority = scp->SCp.this_residual;
+#endif
     gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
     gdth_putq( hanum, scp, priority );
     gdth_next( hanum );
     return 0;
 }
 
+#if LINUX_VERSION_CODE >= 0x010300
 /* flush routine */
 static void gdth_flush(int hanum)
 {
     int             i;
     gdth_ha_str     *ha;
-    Scsi_Cmnd     * scp;
-    Scsi_Device   * sdev;
     gdth_cmd_str    gdtcmd;
+#if LINUX_VERSION_CODE >= 0x020322
+    Scsi_Cmnd       *scp;
+    Scsi_Device     *sdev;
+#else
+    Scsi_Cmnd       scp;
+    Scsi_Device     sdev;
+#endif
+    char            cmnd[MAX_COMMAND_SIZE];   
+    memset(cmnd, 0xff, 12);
 
     TRACE2(("gdth_flush() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
 
+#if LINUX_VERSION_CODE >= 0x020322
     sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-    if (!sdev)
-	return;
-
     scp  = scsi_allocate_device(sdev, 1, FALSE);
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+#else
+    memset(&sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    sdev.host = scp.host = gdth_ctr_tab[hanum];
+    sdev.id = scp.target = sdev.host->this_id;
+    scp.device = &sdev;
+#endif
 
-    if (scp) {
-        scp->cmd_len = 12;
-        scp->use_sg = 0;
-
-        for (i = 0; i < MAX_HDRIVES; ++i) {
-            if (ha->hdr[i].present) {
-                gdtcmd.BoardNode = LOCALBOARD;
-                gdtcmd.Service = CACHESERVICE;
-                gdtcmd.OpCode = GDT_FLUSH;
-                gdtcmd.u.cache.DeviceNo = i;
-                gdtcmd.u.cache.BlockNo = 1;
-                gdtcmd.u.cache.sg_canz = 0;
-                TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
-                 gdth_do_cmd(scp, &gdtcmd, 30);
-            }
+    for (i = 0; i < MAX_HDRIVES; ++i) {
+        if (ha->hdr[i].present) {
+            gdtcmd.BoardNode = LOCALBOARD;
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_FLUSH;
+            gdtcmd.u.cache.DeviceNo = i;
+            gdtcmd.u.cache.BlockNo = 1;
+            gdtcmd.u.cache.sg_canz = 0;
+            TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
+#if LINUX_VERSION_CODE >= 0x020322
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+#else
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+#endif
         }
-    	scsi_release_command(scp);
     }
+#if LINUX_VERSION_CODE >= 0x020322
+    scsi_release_command(scp);
     scsi_free_host_dev(sdev);
+#endif
 }
 
 /* shutdown routine */
+#if LINUX_VERSION_CODE >= 0x020100
 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
+#else
+void gdth_halt(void)
+#endif
 {
     int             hanum;
 #ifndef __alpha__
-    Scsi_Cmnd     * scp;
-    Scsi_Device   * sdev;
     gdth_cmd_str    gdtcmd;
+#if LINUX_VERSION_CODE >= 0x020322
+    Scsi_Cmnd       *scp;
+    Scsi_Device     *sdev;
+#else
+    Scsi_Cmnd       scp;
+    Scsi_Device     sdev;
+#endif
+    char            cmnd[MAX_COMMAND_SIZE];   
 #endif
 
-    TRACE2(("gdth_halt() event %d\n",event));
+#if LINUX_VERSION_CODE >= 0x020100
+    TRACE2(("gdth_halt() event %d\n",(int)event));
     if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
         return NOTIFY_DONE;
+#else
+    TRACE2(("gdth_halt()\n"));
+    if (halt_called) {
+        TRACE2(("already called\n"));
+        return;
+    }
+    halt_called = TRUE;
+#endif
     printk("GDT: Flushing all host drives .. ");
     for (hanum = 0; hanum < gdth_ctr_count; ++hanum) {
         gdth_flush(hanum);
 
 #ifndef __alpha__
         /* controller reset */
-	sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-	scp  = scsi_allocate_device(sdev, 1, FALSE);
+        memset(cmnd, 0xff, 12);
+#if LINUX_VERSION_CODE >= 0x020322
+        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+        scp  = scsi_allocate_device(sdev, 1, FALSE);
         scp->cmd_len = 12;
         scp->use_sg = 0;
+#else
+        memset(&sdev,0,sizeof(Scsi_Device));
+        memset(&scp, 0,sizeof(Scsi_Cmnd));
+        sdev.host = scp.host = gdth_ctr_tab[hanum];
+        sdev.id = scp.target = sdev.host->this_id;
+        scp.device = &sdev;
+#endif
 
         gdtcmd.BoardNode = LOCALBOARD;
         gdtcmd.Service = CACHESERVICE;
         gdtcmd.OpCode = GDT_RESET;
         TRACE2(("gdth_halt(): reset controller %d\n", hanum));
-        gdth_do_cmd(scp, &gdtcmd, 10);
-	scsi_release_command(scp);
-	scsi_free_host_dev(sdev);
+#if LINUX_VERSION_CODE >= 0x020322
+        gdth_do_cmd(scp, &gdtcmd, cmnd, 10);
+        scsi_release_command(scp);
+        scsi_free_host_dev(sdev);
+#else
+        gdth_do_cmd(&scp, &gdtcmd, cmnd, 10);
+#endif
 #endif
     }
-
     printk("Done.\n");
 
 #ifdef GDTH_STATISTICS
     del_timer(&gdth_timer);
 #endif
+#if LINUX_VERSION_CODE >= 0x020100
+#if LINUX_VERSION_CODE < 0x020322
     unregister_reboot_notifier(&gdth_notifier);
+#endif
     return NOTIFY_OK;
+#endif
 }
+#endif
 
-/* called from init/main.c */
-void __init gdth_setup(char *str,int *ints)
-{
-    int i, argc;
-    char *cur_str, *argv;
 
+#if LINUX_VERSION_CODE < 0x020400 && !defined(MODULE)
+
+GDTH_INITFUNC(void, gdth_setup(char *str,int *ints)) 
+{    
     TRACE2(("gdth_setup() str %s ints[0] %d\n", 
             str ? str:"NULL", ints ? ints[0]:0));
-
-    /* read irq[] from ints[] */
-    if (ints) {
-        argc = ints[0];
-        if (argc > 0) {
-            if (argc > MAXHA)
-                argc = MAXHA;
-            for (i = 0; i < argc; ++i)
-                irq[i] = ints[i+1];
-        }
-    }
-
-    /* analyse string */
-    argv = str;
-    while (argv && (cur_str = strchr(argv, ':'))) {
-        int val = 0, c = *++cur_str;
-        
-        if (c == 'n' || c == 'N')
-            val = 0;
-        else if (c == 'y' || c == 'Y')
-            val = 1;
-        else
-            val = (int)simple_strtoul(cur_str, NULL, 0);
-
-        if (!strncmp(argv, "disable:", 8))
-            disable = val;
-        else if (!strncmp(argv, "reserve_mode:", 13))
-            reserve_mode = val;
-        else if (!strncmp(argv, "reverse_scan:", 13))
-            reverse_scan = val;
-        else if (!strncmp(argv, "hdr_channel:", 12))
-            hdr_channel = val;
-        else if (!strncmp(argv, "max_ids:", 8))
-            max_ids = val;
-        else if (!strncmp(argv, "rescan:", 7))
-            rescan = val;
-        else if (!strncmp(argv, "reserve_list:", 13)) {
-            reserve_list[0] = val;
-            for (i = 1; i < MAX_RES_ARGS; i++) {
-                cur_str = strchr(cur_str, ',');
-                if (!cur_str)
-                    break;
-                if (!isdigit((int)*++cur_str)) {
-                    --cur_str;          
-                    break;
-                }
-                reserve_list[i] = 
-                    (int)simple_strtoul(cur_str, NULL, 0);
-            }
-            if (!cur_str)
-                break;
-            argv = ++cur_str;
-            continue;
-        }
-
-        if ((argv = strchr(argv, ',')))
-            ++argv;
-    }
+    internal_setup(str, ints);
 }
 
+#else
 
-static Scsi_Host_Template driver_template = GDTH;
+Scsi_Host_Template driver_template = GDTH;
 #include "scsi_module.c"
+#ifndef MODULE
+__setup("gdth=", option_setup);
+#endif
+
+#endif
diff -urN linux-2.4.5-pre3/drivers/scsi/gdth.h linux/drivers/scsi/gdth.h
--- linux-2.4.5-pre3/drivers/scsi/gdth.h	Mon Dec 11 13:19:43 2000
+++ linux/drivers/scsi/gdth.h	Mon Dec  3 22:44:23 2001
@@ -4,13 +4,13 @@
 /*
  * Header file for the GDT ISA/EISA/PCI Disk Array Controller driver for Linux
  * 
- * gdth.h Copyright (C) 1995-99 ICP vortex Computersysteme GmbH, Achim Leubner
+ * gdth.h Copyright (C) 1995-01 ICP vortex Computersysteme GmbH, Achim Leubner
  * See gdth.c for further informations and 
  * below for supported controller types
  *
  * <achim@vortex.de>
  *
- * $Id: gdth.h,v 1.21 1999/03/26 09:12:24 achim Exp $
+ * $Id: gdth.h,v 1.38 2001/03/15 15:06:23 achim Exp $
  */
 
 #include <linux/version.h>
@@ -29,9 +29,9 @@
 /* defines, macros */
 
 /* driver version */
-#define GDTH_VERSION_STR        "1.14"
+#define GDTH_VERSION_STR        "1.28"
 #define GDTH_VERSION            1
-#define GDTH_SUBVERSION         14
+#define GDTH_SUBVERSION         28
 
 /* protocol version */
 #define PROTOCOL_VERSION        1
@@ -126,7 +126,7 @@
 #endif
 
 /* limits */
-#define GDTH_SCRATCH    PAGE_SIZE                    /* 4KB scratch buffer */
+#define GDTH_SCRATCH    PAGE_SIZE               /* 4KB scratch buffer */
 #define GDTH_SCRATCH_ORD 0                      /* order 0 means 1 page */
 #define GDTH_MAXCMDS    124
 #define GDTH_MAXC_P_L   16                      /* max. cmds per lun */
@@ -136,7 +136,8 @@
 #define MAXID           127
 #define MAXLUN          8
 #define MAXBUS          6
-#define MAX_HDRIVES     35                      /* max. host drive count */
+#define MAX_HDRIVES     100                     /* max. host drive count */
+#define MAX_LDRIVES     255                     /* max. log. drive count */
 #define MAX_EVENTS      100                     /* event buffer count */
 #define MAX_RES_ARGS    40                      /* device reservation, 
                                                    must be a multiple of 4 */
@@ -174,7 +175,13 @@
 #define IC_QUEUE_BYTES  4
 #define DPMEM_COMMAND_OFFSET    IC_HEADER_BYTES+IC_QUEUE_BYTES*MAXOFFSETS
 
-/* cache/raw service commands */
+/* cluster_type constants */
+#define CLUSTER_DRIVE         1
+#define CLUSTER_MOUNTED       2
+#define CLUSTER_RESERVED      4
+#define CLUSTER_RESERVE_STATE (CLUSTER_DRIVE|CLUSTER_MOUNTED|CLUSTER_RESERVED)
+
+/* commands for all services, cache service */
 #define GDT_INIT        0                       /* service initialization */
 #define GDT_READ        1                       /* read command */
 #define GDT_WRITE       2                       /* write command */
@@ -190,8 +197,13 @@
 #define GDT_READ_THR    17                      /* read through */
 #define GDT_EXT_INFO    18                      /* extended info */
 #define GDT_RESET       19                      /* controller reset */
+#define GDT_RESERVE_DRV 20                      /* reserve host drive */
+#define GDT_RELEASE_DRV 21                      /* release host drive */
+#define GDT_CLUST_INFO  22                      /* cluster info */
+#define GDT_RW_ATTRIBS  23                      /* R/W attribs (write thru,..)*/
+#define GDT_CLUST_RESET 24                      /* releases the cluster drives*/
 
-/* additional raw service commands */
+/* raw service commands */
 #define GDT_RESERVE     14                      /* reserve dev. to raw serv. */
 #define GDT_RELEASE     15                      /* release device */
 #define GDT_RESERVE_ALL 16                      /* reserve all devices */
@@ -200,6 +212,9 @@
 #define GDT_SCAN_START  19                      /* start device scan */
 #define GDT_SCAN_END    20                      /* stop device scan */  
 
+/* screen service commands */
+#define GDT_REALTIME    3                       /* realtime clock to screens. */
+
 /* IOCTL command defines */
 #define SCSI_DR_INFO    0x00                    /* SCSI drive info */                   
 #define SCSI_CHAN_CNT   0x05                    /* SCSI channel count */   
@@ -207,10 +222,11 @@
 #define SCSI_DEF_CNT    0x15                    /* grown/primary defects */
 #define DSK_STATISTICS  0x4b                    /* SCSI disk statistics */
 #define IOCHAN_DESC     0x5d                    /* description of IO channel */
-#define IOCHAN_RAW_DESC 0x5e                    /* description of raw IO channel */
+#define IOCHAN_RAW_DESC 0x5e                    /* description of raw IO chn. */
 #define L_CTRL_PATTERN  0x20000000L             /* SCSI IOCTL mask */
 #define ARRAY_INFO      0x12                    /* array drive info */
 #define ARRAY_DRV_LIST  0x0f                    /* array drive list */
+#define ARRAY_DRV_LIST2 0x34                    /* array drive list (new) */
 #define LA_CTRL_PATTERN 0x10000000L             /* array IOCTL mask */
 #define CACHE_DRV_CNT   0x01                    /* cache drive count */
 #define CACHE_DRV_LIST  0x02                    /* cache drive list */
@@ -223,19 +239,11 @@
 #define IO_CHANNEL      0x00020000L             /* default IO channel */
 #define INVALID_CHANNEL 0x0000ffffL             /* invalid channel */
 
-/* IOCTLs */
-#define GDTIOCTL_MASK       ('J'<<8)
-#define GDTIOCTL_GENERAL    (GDTIOCTL_MASK | 0) /* general IOCTL */
-#define GDTIOCTL_DRVERS     (GDTIOCTL_MASK | 1) /* get driver version */
-#define GDTIOCTL_CTRTYPE    (GDTIOCTL_MASK | 2) /* get controller type */
-#define GDTIOCTL_CTRCNT     (GDTIOCTL_MASK | 5) /* get controller count */
-#define GDTIOCTL_LOCKDRV    (GDTIOCTL_MASK | 6) /* lock host drive */
-#define GDTIOCTL_LOCKCHN    (GDTIOCTL_MASK | 7) /* lock channel */
-#define GDTIOCTL_EVENT      (GDTIOCTL_MASK | 8) /* read controller events */
-
 /* service errors */
 #define S_OK            1                       /* no error */
+#define S_GENERR        6                       /* general error */
 #define S_BSY           7                       /* controller busy */
+#define S_CACHE_UNKNOWN 12                      /* cache serv.: drive unknown */
 #define S_RAW_SCSI      12                      /* raw serv.: target error */
 #define S_RAW_ILL       0xff                    /* raw serv.: illegal */
 
@@ -250,8 +258,8 @@
 #define HIGH_PRI        0x08
 
 /* data directions */
-#define DATA_IN         0x01000000L             /* data from target */
-#define DATA_OUT        0x00000000L             /* data to target */
+#define GDTH_DATA_IN    0x01000000L             /* data from target */
+#define GDTH_DATA_OUT   0x00000000L             /* data to target */
 
 /* BMIC registers (EISA controllers) */
 #define ID0REG          0x0c80                  /* board ID */
@@ -299,7 +307,7 @@
     unchar      revision[4];                    /* revision */
     ulong32     sy_rate;                        /* current rate for sync. tr. */
     ulong32     sy_max_rate;                    /* max. rate for sync. tr. */
-    ulong32     no_ldrive;                      /* belongs to this logical drv.*/
+    ulong32     no_ldrive;                      /* belongs to this log. drv.*/
     ulong32     blkcnt;                         /* number of blocks */
     ushort      blksize;                        /* size of block in bytes */
     unchar      available;                      /* flag: access is available */
@@ -454,7 +462,15 @@
     unchar      is_parity;                      /* Flag: is parity drive? */
     unchar      is_hotfix;                      /* Flag: is hotfix drive? */
     unchar      res[3];
-} PACKED gdth_arraylist_str;
+} PACKED gdth_alist_str;
+
+typedef struct {
+    ulong32     entries_avail;                  /* allocated entries */
+    ulong32     entries_init;                   /* returned entries */
+    ulong32     first_entry;                    /* first entry number */
+    ulong32     list_offset;                    /* offset of following list */
+    gdth_alist_str list[1];                     /* list */
+} PACKED gdth_arcdl_str;
 
 /* cache info/config IOCTL */
 typedef struct {
@@ -586,8 +602,13 @@
         } PACKED ioctl;                         /* IOCTL command structure */
         struct {
             ushort      reserved;
-            ulong32     msg_handle;             /* message handle */
-            ulong32     msg_addr;               /* message buffer address */
+            union {
+                struct {
+                    ulong32  msg_handle;        /* message handle */
+                    ulong32  msg_addr;          /* message buffer address */
+                } PACKED msg;
+                unchar       data[12];          /* buffer for rtc data, ... */
+            } su;
         } PACKED screen;                        /* screen service cmd. str. */
         struct {
             ushort      reserved;
@@ -604,7 +625,7 @@
             unchar      priority;               /* only 0 used */
             ulong32     sense_len;              /* sense data length */
             ulong32     sense_data;             /* sense data addr. */
-            struct raw  *link_p;                /* linked cmds (not supp.) */
+            ulong32     link_p;                 /* linked cmds (not supp.) */
             ulong32     sg_ranz;                /* s/g element count */
             gdth_sg_str sg_lst[GDTH_MAXSG];     /* s/g list */
         } PACKED raw;                           /* raw service cmd. struct. */
@@ -650,6 +671,8 @@
             ulong32         l1, l2, l3, l4;
         } PACKED test;
     } eu;
+    ulong32                 severity;
+    unchar                  event_string[256];          
 } PACKED gdth_evt_data;
 
 typedef struct {
@@ -799,7 +822,9 @@
     unchar              unused5[7];
     unchar              edoor_en_reg;           /* board interrupts enable */
     unchar              unused6[27];
-    ulong32             unused7[1004];          /* size: 4 KB */
+    ulong32             unused7[939];         
+    ulong32             severity;       
+    char                evt_str[256];           /* event string */
 } PACKED gdt6m_i960_regs;
 
 /* DPRAM PCI MPR controllers */
@@ -815,7 +840,9 @@
 
 /* PCI resources */
 typedef struct {
+#if LINUX_VERSION_CODE >= 0x02015C
     struct pci_dev      *pdev;
+#endif
     ushort              device_id;              /* device ID (0,..,9) */
     unchar              bus;                    /* PCI bus */
     unchar              device_fn;              /* PCI device/function no. */
@@ -831,6 +858,7 @@
     ushort              type;                   /* controller class */
     ushort              raw_feat;               /* feat. raw service (s/g,..) */
     ulong32             stype;                  /* controller subtype */
+    ushort              fw_vers;                /* firmware version */
     ushort              cache_feat;             /* feat. cache serv. (s/g,..) */
     ushort              bmic;                   /* BMIC address (EISA) */
     void                *brd;                   /* DPRAM address */
@@ -843,12 +871,13 @@
     unchar              irq;                    /* IRQ */
     unchar              drq;                    /* DRQ (ISA controllers) */
     ushort              status;                 /* command status */
+    ushort              service;                /* service/firmware ver./.. */
     ulong32             info;
     ulong32             info2;                  /* additional info */
     Scsi_Cmnd           *req_first;             /* top of request queue */
     struct {
         unchar          present;                /* Flag: host drive present? */
-        unchar          is_logdrv;              /* Flag: logical drive (master)? */
+        unchar          is_logdrv;              /* Flag: log. drive (master)? */
         unchar          is_arraydrv;            /* Flag: array drive? */
         unchar          is_master;              /* Flag: array drive master? */
         unchar          is_parity;              /* Flag: parity drive? */
@@ -861,13 +890,15 @@
         ulong32         size;                   /* capacity */
         unchar          ldr_no;                 /* log. drive no. */
         unchar          rw_attribs;             /* r/w attributes */
+        unchar          cluster_type;           /* cluster properties */
+        unchar          media_changed;          /* Flag:MOUNT/UNMOUNT occured */
         ulong32         start_sec;              /* start sector */
-    } hdr[MAX_HDRIVES];                         /* host drives */
+    } hdr[MAX_LDRIVES];                         /* host drives */
     struct {
         unchar          lock;                   /* channel locked? (hot plug) */
         unchar          pdev_cnt;               /* physical device count */
         unchar          local_no;               /* local channel number */
-	unchar          io_cnt[MAXID];          /* current IO count */
+        unchar          io_cnt[MAXID];          /* current IO count */
         ulong32         address;                /* channel address */
         ulong32         id_list[MAXID];         /* IDs of the phys. devices */
     } raw[MAXBUS];                              /* SCSI channels */
@@ -887,7 +918,10 @@
     gdth_cpar_str       cpar;                   /* controller cache par. */
     gdth_bfeat_str      bfeat;                  /* controller features */
     gdth_binfo_str      binfo;                  /* controller info */
+    gdth_evt_data       dvr;                    /* event structure */
+#if LINUX_VERSION_CODE >= 0x02015F
     spinlock_t          smp_lock;
+#endif
 } gdth_ha_str;
 
 /* structure for scsi_register(), SCSI bus != 0 */
@@ -965,12 +999,16 @@
 
 int gdth_detect(Scsi_Host_Template *);
 int gdth_release(struct Scsi_Host *);
-int gdth_command(Scsi_Cmnd *);
 int gdth_queuecommand(Scsi_Cmnd *,void (*done)(Scsi_Cmnd *));
 int gdth_abort(Scsi_Cmnd *);
+#if LINUX_VERSION_CODE >= 0x010346
 int gdth_reset(Scsi_Cmnd *, unsigned int reset_flags);
+#else
+int gdth_reset(Scsi_Cmnd *);
+#endif
 const char *gdth_info(struct Scsi_Host *);
 
+#if LINUX_VERSION_CODE >= 0x020322
 int gdth_bios_param(Disk *,kdev_t,int *);
 int gdth_proc_info(char *,char **,off_t,int,int,int);
 int gdth_eh_abort(Scsi_Cmnd *scp);
@@ -983,7 +1021,7 @@
                detect:          gdth_detect,                     \
                release:         gdth_release,                    \
                info:            gdth_info,                       \
-               command:         gdth_command,                    \
+               command:         NULL,                            \
                queuecommand:    gdth_queuecommand,               \
                eh_abort_handler: gdth_eh_abort,                  \
                eh_device_reset_handler: gdth_eh_device_reset,    \
@@ -1000,5 +1038,85 @@
                unchecked_isa_dma: 1,                             \
                use_clustering:  ENABLE_CLUSTERING,               \
                use_new_eh_code: 1       /* use new error code */ }    
+
+#elif LINUX_VERSION_CODE >= 0x02015F
+int gdth_bios_param(Disk *,kdev_t,int *);
+extern struct proc_dir_entry proc_scsi_gdth;
+int gdth_proc_info(char *,char **,off_t,int,int,int);
+int gdth_eh_abort(Scsi_Cmnd *scp);
+int gdth_eh_device_reset(Scsi_Cmnd *scp);
+int gdth_eh_bus_reset(Scsi_Cmnd *scp);
+int gdth_eh_host_reset(Scsi_Cmnd *scp);
+#define GDTH { proc_dir:        &proc_scsi_gdth,                 \
+               proc_info:       gdth_proc_info,                  \
+               name:            "GDT SCSI Disk Array Controller",\
+               detect:          gdth_detect,                     \
+               release:         gdth_release,                    \
+               info:            gdth_info,                       \
+               command:         NULL,                            \
+               queuecommand:    gdth_queuecommand,               \
+               eh_abort_handler: gdth_eh_abort,                  \
+               eh_device_reset_handler: gdth_eh_device_reset,    \
+               eh_bus_reset_handler: gdth_eh_bus_reset,          \
+               eh_host_reset_handler: gdth_eh_host_reset,        \
+               abort:           gdth_abort,                      \
+               reset:           gdth_reset,                      \
+               bios_param:      gdth_bios_param,                 \
+               can_queue:       GDTH_MAXCMDS,                    \
+               this_id:         -1,                              \
+               sg_tablesize:    GDTH_MAXSG,                      \
+               cmd_per_lun:     GDTH_MAXC_P_L,                   \
+               present:         0,                               \
+               unchecked_isa_dma: 1,                             \
+               use_clustering:  ENABLE_CLUSTERING,               \
+               use_new_eh_code: 1       /* use new error code */ }    
+
+#elif LINUX_VERSION_CODE >= 0x010300
+int gdth_bios_param(Disk *,kdev_t,int *);
+extern struct proc_dir_entry proc_scsi_gdth;
+int gdth_proc_info(char *,char **,off_t,int,int,int);
+#define GDTH { NULL, NULL,                              \
+                   &proc_scsi_gdth,                     \
+                   gdth_proc_info,                      \
+                   "GDT SCSI Disk Array Controller",    \
+                   gdth_detect,                         \
+                   gdth_release,                        \
+                   gdth_info,                           \
+                   NULL,                                \
+                   gdth_queuecommand,                   \
+                   gdth_abort,                          \
+                   gdth_reset,                          \
+                   NULL,                                \
+                   gdth_bios_param,                     \
+                   GDTH_MAXCMDS,                        \
+                   -1,                                  \
+                   GDTH_MAXSG,                          \
+                   GDTH_MAXC_P_L,                       \
+                   0,                                   \
+                   1,                                   \
+                   ENABLE_CLUSTERING}
+
+#else
+int gdth_bios_param(Disk *,int,int *);
+#define GDTH { NULL, NULL,                              \
+                   "GDT SCSI Disk Array Controller",    \
+                   gdth_detect,                         \
+                   gdth_release,                        \
+                   gdth_info,                           \
+                   NULL,                                \
+                   gdth_queuecommand,                   \
+                   gdth_abort,                          \
+                   gdth_reset,                          \
+                   NULL,                                \
+                   gdth_bios_param,                     \
+                   GDTH_MAXCMDS,                        \
+                   -1,                                  \
+                   GDTH_MAXSG,                          \
+                   GDTH_MAXC_P_L,                       \
+                   0,                                   \
+                   1,                                   \
+                   ENABLE_CLUSTERING}
+#endif
+
 #endif
 
diff -urN linux-2.4.5-pre3/drivers/scsi/gdth_ioctl.h linux/drivers/scsi/gdth_ioctl.h
--- linux-2.4.5-pre3/drivers/scsi/gdth_ioctl.h	Mon Jan 11 10:17:20 1999
+++ linux/drivers/scsi/gdth_ioctl.h	Mon Dec  3 22:44:23 2001
@@ -2,7 +2,7 @@
 #define _GDTH_IOCTL_H
 
 /* gdth_ioctl.h
- * $Id: gdth_ioctl.h,v 1.2 1998/12/17 15:42:49 achim Exp $
+ * $Id: gdth_ioctl.h,v 1.9 2001/01/10 14:39:37 achim Exp $
  */
 
 /* IOCTLs */
@@ -11,13 +11,19 @@
 #define GDTIOCTL_DRVERS     (GDTIOCTL_MASK | 1) /* get driver version */
 #define GDTIOCTL_CTRTYPE    (GDTIOCTL_MASK | 2) /* get controller type */
 #define GDTIOCTL_OSVERS     (GDTIOCTL_MASK | 3) /* get OS version */
+#define GDTIOCTL_HDRLIST    (GDTIOCTL_MASK | 4) /* get host drive list */
 #define GDTIOCTL_CTRCNT     (GDTIOCTL_MASK | 5) /* get controller count */
 #define GDTIOCTL_LOCKDRV    (GDTIOCTL_MASK | 6) /* lock host drive */
 #define GDTIOCTL_LOCKCHN    (GDTIOCTL_MASK | 7) /* lock channel */
 #define GDTIOCTL_EVENT      (GDTIOCTL_MASK | 8) /* read controller events */
+#define GDTIOCTL_SCSI       (GDTIOCTL_MASK | 9) /* SCSI command */
+#define GDTIOCTL_RESET_BUS  (GDTIOCTL_MASK |10) /* reset SCSI bus */
+#define GDTIOCTL_RESCAN     (GDTIOCTL_MASK |11) /* rescan host drives */
+#define GDTIOCTL_RESET_DRV  (GDTIOCTL_MASK |12) /* reset (remote) drv. res. */
 
-#define GDTIOCTL_MAGIC      0xaffe0001UL
-
+#define GDTIOCTL_MAGIC      0xaffe0004
+#define EVENT_SIZE          294 
+#define MAX_HDRIVES         100                     
 
 /* IOCTL structure (write) */
 typedef struct {
@@ -34,7 +40,7 @@
         struct {
             unchar          lock;               /* lock/unlock */
             unchar          drive_cnt;          /* drive count */
-            ushort          drives[35];         /* drives */
+            ushort          drives[MAX_HDRIVES];/* drives */
         } lockdrv;
         struct {
             unchar          lock;               /* lock/unlock */
@@ -43,8 +49,19 @@
         struct {
             int             erase;              /* erase event ? */
             int             handle;
-            unchar          evt[34];            /* event structure */
+            unchar          evt[EVENT_SIZE];    /* event structure */
         } event;
+        struct {
+            unchar          bus;                /* SCSI bus */
+            unchar          target;             /* target ID */
+            unchar          lun;                /* LUN */
+            unchar          cmd_len;            /* command length */
+            unchar          cmd[12];            /* SCSI command */
+        } scsi;
+        struct {
+            ushort          hdr_no;             /* host drive number */
+            unchar          flag;               /* old meth./add/remove */
+        } rescan;
     } iu;
 } gdth_iowr_str;
 
@@ -77,8 +94,14 @@
         } ctrcnt;
         struct {
             int             handle;
-            unchar          evt[34];            /* event structure */
+            unchar          evt[EVENT_SIZE];    /* event structure */
         } event;
+        struct {
+            unchar          bus;                /* SCSI bus, 0xff: invalid */
+            unchar          target;             /* target ID */
+            unchar          lun;                /* LUN */
+            unchar          cluster_type;       /* cluster properties */
+        } hdr_list[MAX_HDRIVES];                /* index is host drive number */
     } iu;
 } gdth_iord_str;
 
diff -urN linux-2.4.5-pre3/drivers/scsi/gdth_proc.c linux/drivers/scsi/gdth_proc.c
--- linux-2.4.5-pre3/drivers/scsi/gdth_proc.c	Sat Nov 11 19:01:11 2000
+++ linux/drivers/scsi/gdth_proc.c	Mon Dec  3 22:44:23 2001
@@ -1,5 +1,5 @@
 /* gdth_proc.c 
- * $Id: gdth_proc.c,v 1.13 1999/03/22 16:12:53 achim Exp $
+ * $Id: gdth_proc.c,v 1.27 2001/03/14 10:47:00 achim Exp $
  */
 
 #include "gdth_ioctl.h"
@@ -31,27 +31,30 @@
 static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
 {
     int             ret_val;
-    Scsi_Cmnd     * scp;
-    Scsi_Device   * sdev;
+#if LINUX_VERSION_CODE >= 0x020322
+    Scsi_Cmnd       *scp;
+    Scsi_Device     *sdev;
+#else
+    Scsi_Cmnd       scp;
+    Scsi_Device     sdev;
+#endif
     gdth_iowr_str   *piowr;
 
     TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
     piowr = (gdth_iowr_str *)buffer;
 
+#if LINUX_VERSION_CODE >= 0x020322
     sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
-    
-    if(sdev==NULL)
-    	return -ENOMEM;
-
     scp  = scsi_allocate_device(sdev, 1, FALSE);
-    
-    if(scp==NULL)
-    {
-	scsi_free_host_dev(sdev);
-        return -ENOMEM;
-    }
     scp->cmd_len = 12;
     scp->use_sg = 0;
+#else
+    memset(&sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    sdev.host = scp.host = gdth_ctr_vtab[vh];
+    sdev.id = scp.target = sdev.host->this_id;
+    scp.device = &sdev;
+#endif
 
     if (length >= 4) {
         if (strncmp(buffer,"gdth",4) == 0) {
@@ -61,20 +64,29 @@
         } else if (piowr->magic == GDTIOCTL_MAGIC) {
             ret_val = gdth_set_bin_info( buffer, length, hanum, scp );
         } else {
-            printk("GDT: Wrong signature: %6s\n",buffer);
+            printk("GDT: Wrong signature %x (%x required)!\n",
+                   piowr->magic, GDTIOCTL_MAGIC);
+            if (piowr->magic > GDTIOCTL_MAGIC)
+                printk("GDT: Please update your driver.\n");
+            else
+                printk("GDT: Please update your tool.\n");
             ret_val = -EINVAL;
         }
     } else {
         ret_val = -EINVAL;
     }
-
+#if LINUX_VERSION_CODE >= 0x020322
     scsi_release_command(scp);
     scsi_free_host_dev(sdev);
-
+#endif
     return ret_val;
 }
          
-static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd * scp)
+#if LINUX_VERSION_CODE >= 0x020322
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
+#else
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
+#endif
 {
     int             orig_length, drive, wb_mode;
     int             i, found;
@@ -82,6 +94,10 @@
     gdth_cmd_str    gdtcmd;
     gdth_cpar_str   *pcpar;
 
+    char            cmnd[MAX_COMMAND_SIZE];
+    memset(cmnd, 0xff, 12);
+    memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
+
     TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
     orig_length = length + 5;
@@ -108,13 +124,15 @@
                 if (drive != -1 && i != drive)
                     continue;
                 found = TRUE;
-                gdtcmd.BoardNode = LOCALBOARD;
                 gdtcmd.Service = CACHESERVICE;
                 gdtcmd.OpCode = GDT_FLUSH;
                 gdtcmd.u.cache.DeviceNo = i;
                 gdtcmd.u.cache.BlockNo = 1;
-                gdtcmd.u.cache.sg_canz = 0;
-                gdth_do_cmd(scp, &gdtcmd, 30);
+#if LINUX_VERSION_CODE >= 0x020322
+                gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+#else
+                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+#endif
             }
         }
         if (!found)
@@ -159,7 +177,6 @@
             return(-EBUSY);
         pcpar = (gdth_cpar_str *)ha->pscratch;
         memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
-        gdtcmd.BoardNode = LOCALBOARD;
         gdtcmd.Service = CACHESERVICE;
         gdtcmd.OpCode = GDT_IOCTL;
         gdtcmd.u.ioctl.p_param = virt_to_bus(pcpar);
@@ -167,7 +184,11 @@
         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
         pcpar->write_back = wb_mode==1 ? 0:1;
-        gdth_do_cmd(scp, &gdtcmd, 30);
+#if LINUX_VERSION_CODE >= 0x020322
+        gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+#else
+        gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+#endif
         gdth_ioctl_free(hanum);
         printk("Done.\n");
         return(orig_length);
@@ -177,17 +198,27 @@
     return(-EINVAL);
 }
 
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd * scp)
+#if LINUX_VERSION_CODE >= 0x020322
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
+#else
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
+#endif
 {
     unchar          i, j;
+    ushort          k, hdr_cnt, status;
     gdth_ha_str     *ha;
     gdth_iowr_str   *piowr;
     gdth_iord_str   *piord;
     gdth_cmd_str    *pcmd;
     gdth_evt_str    *pevt;
-    ulong32         *ppadd, add_size;
-    ulong32         *ppadd2, add_size2;
+    ulong32         *ppadd, add_size, *ppadd2, add_size2, info;
     ulong           flags;
+    gdth_cmd_str    gdtcmd;
+    int             drv_cyls, drv_hds, drv_secs;
+ 
+    char            cmnd[MAX_COMMAND_SIZE];   
+    memset(cmnd, 0xff, 12);
+    memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
 
     TRACE2(("gdth_set_bin_info() ha %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
@@ -250,8 +281,13 @@
             *ppadd2 = virt_to_bus(piord->iu.general.data+add_size);
         }
         /* do IOCTL */
-        gdth_do_cmd(scp, pcmd, piowr->timeout);
-        piord->status = (ulong32)scp->SCp.Message;
+#if LINUX_VERSION_CODE >= 0x020322
+        gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout);
+        piord->status = (scp->SCp.Message<<16)|scp->SCp.Status;
+#else
+        gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
+        piord->status = (scp.SCp.Message<<16)|scp.SCp.Status;
+#endif
         break;
 
       case GDTIOCTL_DRVERS:
@@ -371,10 +407,10 @@
                 pevt->event_data.size = sizeof(pevt->event_data.eu.async);
                 gdth_log_event(&pevt->event_data, NULL);
             }
-	    GDTH_LOCK_HA(ha, flags);
+            GDTH_LOCK_HA(ha, flags);
             gdth_store_event(ha, pevt->event_source, pevt->event_idx,
                              &pevt->event_data);
-	    GDTH_UNLOCK_HA(ha, flags);
+            GDTH_UNLOCK_HA(ha, flags);
         } else if (piowr->iu.event.erase == 0xfe) {
             gdth_clear_events();
         } else if (piowr->iu.event.erase == 0) {
@@ -390,11 +426,236 @@
         piord->status = S_OK;
         break;
 
+      case GDTIOCTL_SCSI:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+        memcpy(cmnd, piowr->iu.scsi.cmd, 12);
+#if LINUX_VERSION_CODE >= 0x020322
+        scp->target = piowr->iu.scsi.target;
+        scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
+        scp->cmd_len = piowr->iu.scsi.cmd_len;
+        gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout);
+        piord->status = (scp->SCp.Message<<16)|scp->SCp.Status;
+#else
+        scp.target = piowr->iu.scsi.target;
+        scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
+        scp.cmd_len = piowr->iu.scsi.cmd_len;
+        gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
+        piord->status = (scp.SCp.Message<<16)|scp.SCp.Status;
+#endif
+        break;
+
+      case GDTIOCTL_RESET_BUS:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+#if LINUX_VERSION_CODE >= 0x020322
+        scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
+        piord->status = (ulong32)gdth_eh_bus_reset( scp );
+        if (piord->status == SUCCESS)
+            piord->status = S_OK;
+        else
+            piord->status = S_GENERR;
+#elif LINUX_VERSION_CODE >= 0x02015F
+        scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
+        piord->status = (ulong32)gdth_eh_bus_reset( &scp );
+        if (piord->status == SUCCESS)
+            piord->status = S_OK;
+        else
+            piord->status = S_GENERR;
+#else
+        piord->status = S_OK;
+#endif
+        break;
+
+      case GDTIOCTL_HDRLIST:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        for (i = 0; i < MAX_HDRIVES; ++i) {
+            if (ha->hdr[i].present) {
+                piord->iu.hdr_list[i].bus = ha->virt_bus;
+                piord->iu.hdr_list[i].target = i;
+                piord->iu.hdr_list[i].lun = 0;
+                piord->iu.hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
+                if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) {  
+                    gdtcmd.Service = CACHESERVICE;
+                    gdtcmd.OpCode = GDT_CLUST_INFO;
+                    gdtcmd.u.cache.DeviceNo = i;
+#if LINUX_VERSION_CODE >= 0x020322
+                    gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                    if (scp->SCp.Status == S_OK)
+                        piord->iu.hdr_list[i].cluster_type = 
+                            (unchar)scp->SCp.Message;
+#else
+                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                    if (scp.SCp.Status == S_OK)
+                        piord->iu.hdr_list[i].cluster_type = 
+                            (unchar)scp.SCp.Message;
+#endif
+                }
+            } else {
+                piord->iu.hdr_list[i].bus = 0xff;
+            }
+        }
+        break;
+
+      case GDTIOCTL_RESCAN:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        if (piowr->iu.rescan.flag == 0) {
+            /* old method: scan all host drives 
+               re-initialize cache service to get host drive count
+            */
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_INIT;
+            gdtcmd.u.cache.DeviceNo = LINUX_OS;
+#if LINUX_VERSION_CODE >= 0x020322
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            status = (ushort)scp->SCp.Status; 
+            info = (ulong32)scp->SCp.Message;
+#else
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            status = (ushort)scp.SCp.Status;
+            info = (ulong32)scp.SCp.Message;
+#endif
+            if (status != S_OK)
+                break;
+            k = 0;
+            hdr_cnt = (ushort)info;
+        } else {
+            k = piowr->iu.rescan.hdr_no;
+            hdr_cnt = k + 1;
+        }
+        if (hdr_cnt > MAX_HDRIVES)
+            hdr_cnt = MAX_HDRIVES;
+        /* scanning for host drives */
+        for (; k < hdr_cnt; ++k) {
+            /* info about host drive */
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_INFO;
+            gdtcmd.u.cache.DeviceNo = k;
+#if LINUX_VERSION_CODE >= 0x020322
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            status = (ushort)scp->SCp.Status; 
+            info = (ulong32)scp->SCp.Message;
+#else
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            status = (ushort)scp.SCp.Status;
+            info = (ulong32)scp.SCp.Message;
+#endif
+            GDTH_LOCK_HA(ha, flags);
+            piord->iu.hdr_list[k].bus = ha->virt_bus;
+            piord->iu.hdr_list[k].target = k;
+            piord->iu.hdr_list[k].lun = 0;
+            if (status != S_OK) {
+                ha->hdr[k].present = FALSE;
+            } else {
+                ha->hdr[k].present = TRUE;
+                ha->hdr[k].size = info;
+                /* evaluate mapping (sectors per head, heads per cylinder) */
+                ha->hdr[k].size &= ~SECS32;
+                gdth_eval_mapping(ha->hdr[k].size,&drv_cyls,&drv_hds,&drv_secs);
+                ha->hdr[k].heads = (unchar)drv_hds;
+                ha->hdr[k].secs = (unchar)drv_secs;
+                /* round size */
+                ha->hdr[k].size = drv_cyls * drv_hds * drv_secs;
+            }
+            GDTH_UNLOCK_HA(ha, flags);
+            if (status != S_OK)
+                continue;       /* next host drive */
+
+            /* devtype, cluster info, R/W attributes */
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_DEVTYPE;
+            gdtcmd.u.cache.DeviceNo = k;
+#if LINUX_VERSION_CODE >= 0x020322
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            status = (ushort)scp->SCp.Status; 
+            info = (ulong32)scp->SCp.Message;
+#else
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            status = (ushort)scp.SCp.Status;
+            info = (ulong32)scp.SCp.Message;
+#endif
+            GDTH_LOCK_HA(ha, flags);
+            ha->hdr[k].devtype = 0;
+            if (status == S_OK)
+                ha->hdr[k].devtype = (ushort)info;
+            GDTH_UNLOCK_HA(ha, flags);
+
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_CLUST_INFO;
+            gdtcmd.u.cache.DeviceNo = k;
+#if LINUX_VERSION_CODE >= 0x020322
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            status = (ushort)scp->SCp.Status; 
+            info = (ulong32)scp->SCp.Message;
+#else
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            status = (ushort)scp.SCp.Status;
+            info = (ulong32)scp.SCp.Message;
+#endif
+            GDTH_LOCK_HA(ha, flags);
+            ha->hdr[k].cluster_type = 0;
+            if (status == S_OK && !shared_access)
+                ha->hdr[k].cluster_type = (ushort)info;
+            GDTH_UNLOCK_HA(ha, flags);
+            piord->iu.hdr_list[k].cluster_type = ha->hdr[k].cluster_type;
+
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_RW_ATTRIBS;
+            gdtcmd.u.cache.DeviceNo = k;
+#if LINUX_VERSION_CODE >= 0x020322
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            status = (ushort)scp->SCp.Status; 
+            info = (ulong32)scp->SCp.Message;
+#else
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            status = (ushort)scp.SCp.Status;
+            info = (ulong32)scp.SCp.Message;
+#endif
+            GDTH_LOCK_HA(ha, flags);
+            ha->hdr[k].rw_attribs = 0;
+            if (status == S_OK)
+                ha->hdr[k].rw_attribs = (ushort)info;
+            GDTH_UNLOCK_HA(ha, flags);
+        }
+        break;
+
+      case GDTIOCTL_RESET_DRV:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        i = piowr->iu.scsi.target;
+        if (ha->hdr[i].present) {
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_CLUST_RESET;
+            gdtcmd.u.cache.DeviceNo = i;
+#if LINUX_VERSION_CODE >= 0x020322
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            piord->status = (scp->SCp.Message<<16)|scp->SCp.Status;
+#else
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            piord->status = (scp.SCp.Message<<16)|scp.SCp.Status;
+#endif
+        }
+        break;
+
       default:
         return(-EINVAL);
     }
-    /* we return a buffer ID to detect the right buffer during READ-IOCTL */
-    return 1;
+    return length;
 }
 
 static int gdth_get_info(char *buffer,char **start,off_t offset,
@@ -410,8 +671,13 @@
 
     gdth_cmd_str gdtcmd;
     gdth_evt_str estr;
-    Scsi_Cmnd  * scp;
+#if LINUX_VERSION_CODE >= 0x020322
+    Scsi_Cmnd *scp;
     Scsi_Device *sdev;
+#else
+    Scsi_Cmnd scp;
+    Scsi_Device sdev;
+#endif
     char hrec[161];
     struct timeval tv;
 
@@ -422,17 +688,28 @@
     gdth_cdrinfo_str *pcdi;
     gdth_hget_str *phg;
 
+    char cmnd[MAX_COMMAND_SIZE];
+    memset(cmnd, 0xff, 12);
+    memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
+
     TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
     ha = HADATA(gdth_ctr_tab[hanum]);
-    id = length;
 
+#if LINUX_VERSION_CODE >= 0x020322
     sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
     scp  = scsi_allocate_device(sdev, 1, FALSE);
     scp->cmd_len = 12;
     scp->use_sg = 0;
+#else
+    memset(&sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    sdev.host = scp.host = gdth_ctr_vtab[vh];
+    sdev.id = scp.target = sdev.host->this_id;
+    scp.device = &sdev;
+#endif
 
-    /* look for buffer ID in length */
-    if (id > 1) {
+    /* ioctl from tool? */
+    if (!gdth_ioctl_check_bin(hanum, (ushort)length)) {
         /* request is i.e. "cat /proc/scsi/gdth/0" */ 
         /* format: %-15s\t%-10s\t%-15s\t%s */
         /* driver parameters */
@@ -457,17 +734,13 @@
                        max_ids, hdr_channel);
         len += size;  pos = begin + len;
 
-        if (pos < offset) {
-            len = 0;
-            begin = pos;
-        }
-        if (pos > offset + length)
-            goto stop_output;
-
         /* controller information */
         size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
         len += size;  pos = begin + len;
-        strcpy(hrec, ha->binfo.type_string);
+        if (virt_ctr)
+            sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
+        else
+            strcpy(hrec, ha->binfo.type_string);
         size = sprintf(buffer+len,
                        " Number:       \t%d         \tName:          \t%s\n",
                        hanum, hrec);
@@ -503,17 +776,10 @@
                            ha->binfo.ser_no, ha->binfo.memsize / 1024);
             len += size;  pos = begin + len;
 
-            if (pos < offset) {
-                len = 0;
-                begin = pos;
-            }
-            if (pos > offset + length)
-                goto stop_output;
-
             /* 2. about physical devices */
             size = sprintf(buffer+len,"\nPhysical Devices:");
             len += size;  pos = begin + len;
-	    flag = FALSE;
+            flag = FALSE;
             
             if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
                 goto stop_output;
@@ -521,7 +787,6 @@
                 /* 2.a statistics (and retries/reassigns) */
                 TRACE2(("pdr_statistics() chn %d\n",i));                
                 pds = (gdth_dskstat_str *)(ha->pscratch + GDTH_SCRATCH/4);
-                gdtcmd.BoardNode = LOCALBOARD;
                 gdtcmd.Service = CACHESERVICE;
                 gdtcmd.OpCode = GDT_IOCTL;
                 gdtcmd.u.ioctl.p_param = virt_to_bus(pds);
@@ -535,11 +800,16 @@
                     sizeof(pds->list[0]);
                 if (pds->entries > cnt)
                     pds->entries = cnt;
-                gdth_do_cmd(scp, &gdtcmd, 30);
-                if (scp->SCp.Message != S_OK) 
+#if LINUX_VERSION_CODE >= 0x020322
+                gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                if (scp->SCp.Status != S_OK) 
+#else
+                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                if (scp.SCp.Status != S_OK) 
+#endif
+                { 
                     pds->count = 0;
-                TRACE2(("pdr_statistics() entries %d status %d\n",
-                        pds->count, scp->SCp.Message));
+                }
 
                 /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
                 for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
@@ -547,7 +817,6 @@
                     TRACE2(("scsi_drv_info() chn %d dev %d\n",
                         i, ha->raw[i].id_list[j]));             
                     pdi = (gdth_diskinfo_str *)ha->pscratch;
-                    gdtcmd.BoardNode = LOCALBOARD;
                     gdtcmd.Service = CACHESERVICE;
                     gdtcmd.OpCode = GDT_IOCTL;
                     gdtcmd.u.ioctl.p_param = virt_to_bus(pdi);
@@ -555,8 +824,14 @@
                     gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
                     gdtcmd.u.ioctl.channel = 
                         ha->raw[i].address | ha->raw[i].id_list[j];
-                    gdth_do_cmd(scp, &gdtcmd, 30);
-                    if (scp->SCp.Message == S_OK) {
+#if LINUX_VERSION_CODE >= 0x020322
+                    gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                    if (scp->SCp.Status == S_OK) 
+#else
+                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                    if (scp.SCp.Status == S_OK) 
+#endif
+                    {
                         strncpy(hrec,pdi->vendor,8);
                         strncpy(hrec+8,pdi->product,16);
                         strncpy(hrec+24,pdi->revision,4);
@@ -565,7 +840,7 @@
                                        "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
                                        'A'+i,pdi->target_id,pdi->lun,hrec);
                         len += size;  pos = begin + len;
-			flag = TRUE;
+                        flag = TRUE;
                         pdi->no_ldrive &= 0xffff;
                         if (pdi->no_ldrive == 0xffff)
                             strcpy(hrec,"--");
@@ -597,7 +872,6 @@
                         TRACE2(("scsi_drv_defcnt() chn %d dev %d\n",
                                 i, ha->raw[i].id_list[j]));             
                         pdef = (gdth_defcnt_str *)ha->pscratch;
-                        gdtcmd.BoardNode = LOCALBOARD;
                         gdtcmd.Service = CACHESERVICE;
                         gdtcmd.OpCode = GDT_IOCTL;
                         gdtcmd.u.ioctl.p_param = virt_to_bus(pdef);
@@ -606,37 +880,43 @@
                         gdtcmd.u.ioctl.channel = 
                             ha->raw[i].address | ha->raw[i].id_list[j];
                         pdef->sddc_type = 0x08;
-                        gdth_do_cmd(scp, &gdtcmd, 30);
-                        if (scp->SCp.Message == S_OK) {
+#if LINUX_VERSION_CODE >= 0x020322
+                        gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                        if (scp->SCp.Status == S_OK) 
+#else
+                        gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                        if (scp.SCp.Status == S_OK) 
+#endif
+                        {
                             size = sprintf(buffer+len,
                                            " Grown Defects:\t%d\n",
                                            pdef->sddc_cnt);
                             len += size;  pos = begin + len;
                         }
                     }
+                    if (pos < offset) {
+                        len = 0;
+                        begin = pos;
+                    }
+                    if (pos > offset + length)
+                        goto stop_output;
                 }
             }
             gdth_ioctl_free(hanum);
 
-	    if (!flag) {
-		size = sprintf(buffer+len, "\n --\n");
-		len += size;  pos = begin + len;
-	    }
-            if (pos < offset) {
-                len = 0;
-                begin = pos;
+            if (!flag) {
+                size = sprintf(buffer+len, "\n --\n");
+                len += size;  pos = begin + len;
             }
-            if (pos > offset + length)
-                goto stop_output;
 
             /* 3. about logical drives */
             size = sprintf(buffer+len,"\nLogical Drives:");
             len += size;  pos = begin + len;
-	    flag = FALSE;
+            flag = FALSE;
 
             if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
                 goto stop_output;
-            for (i = 0; i < MAX_HDRIVES; ++i) {
+            for (i = 0; i < MAX_LDRIVES; ++i) {
                 if (!ha->hdr[i].is_logdrv)
                     continue;
                 drv_no = i;
@@ -646,16 +926,22 @@
                     /* 3.a log. drive info */
                     TRACE2(("cache_drv_info() drive no %d\n",drv_no));
                     pcdi = (gdth_cdrinfo_str *)ha->pscratch;
-                    gdtcmd.BoardNode = LOCALBOARD;
                     gdtcmd.Service = CACHESERVICE;
                     gdtcmd.OpCode = GDT_IOCTL;
                     gdtcmd.u.ioctl.p_param = virt_to_bus(pcdi);
                     gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
                     gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
                     gdtcmd.u.ioctl.channel = drv_no;
-                    gdth_do_cmd(scp, &gdtcmd, 30);
-                    if (scp->SCp.Message != S_OK)
+#if LINUX_VERSION_CODE >= 0x020322
+                    gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                    if (scp->SCp.Status != S_OK)
+#else
+                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                    if (scp.SCp.Status != S_OK)
+#endif
+                    {
                         break;
+                    }
                     pcdi->ld_dtype >>= 16;
                     j++;
                     if (pcdi->ld_dtype > 2) {
@@ -674,7 +960,7 @@
                                        "\n Number:       \t%-2d        \tStatus:        \t%s\n",
                                        drv_no, hrec);
                         len += size;  pos = begin + len;
-			flag = TRUE;
+                        flag = TRUE;
                         no_mdrv = pcdi->cd_ldcnt;
                         if (no_mdrv > 1 || pcdi->ld_slave != -1) {
                             is_mirr = TRUE;
@@ -700,6 +986,12 @@
                         len += size;  pos = begin + len;
                     }
                     drv_no = pcdi->ld_slave;
+                    if (pos < offset) {
+                        len = 0;
+                        begin = pos;
+                    }
+                    if (pos > offset + length)
+                        goto stop_output;
                 } while (drv_no != -1);
                 
                 if (is_mirr) {
@@ -716,42 +1008,47 @@
                 size = sprintf(buffer+len,
                                " To Array Drv.:\t%s\n", hrec);
                 len += size;  pos = begin + len;
+                if (pos < offset) {
+                    len = 0;
+                    begin = pos;
+                }
+                if (pos > offset + length)
+                    goto stop_output;
             }       
             gdth_ioctl_free(hanum);
         
-	    if (!flag) {
-		size = sprintf(buffer+len, "\n --\n");
-		len += size;  pos = begin + len;
-	    }	
-            if (pos < offset) {
-                len = 0;
-                begin = pos;
-            }
-            if (pos > offset + length)
-                goto stop_output;
+            if (!flag) {
+                size = sprintf(buffer+len, "\n --\n");
+                len += size;  pos = begin + len;
+            }   
 
             /* 4. about array drives */
             size = sprintf(buffer+len,"\nArray Drives:");
             len += size;  pos = begin + len;
-	    flag = FALSE;
+            flag = FALSE;
 
             if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
                 goto stop_output;
-            for (i = 0; i < MAX_HDRIVES; ++i) {
+            for (i = 0; i < MAX_LDRIVES; ++i) {
                 if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
                     continue;
                 /* 4.a array drive info */
                 TRACE2(("array_info() drive no %d\n",i));
                 pai = (gdth_arrayinf_str *)ha->pscratch;
-                gdtcmd.BoardNode = LOCALBOARD;
                 gdtcmd.Service = CACHESERVICE;
                 gdtcmd.OpCode = GDT_IOCTL;
                 gdtcmd.u.ioctl.p_param = virt_to_bus(pai);
                 gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
                 gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
                 gdtcmd.u.ioctl.channel = i;
-                gdth_do_cmd(scp, &gdtcmd, 30);
-                if (scp->SCp.Message == S_OK) {
+#if LINUX_VERSION_CODE >= 0x020322
+                gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                if (scp->SCp.Status == S_OK) 
+#else
+                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                if (scp.SCp.Status == S_OK) 
+#endif
+                {
                     if (pai->ai_state == 0)
                         strcpy(hrec, "idle");
                     else if (pai->ai_state == 2)
@@ -787,36 +1084,35 @@
                                    pai->ai_size/(1024*1024/pai->ai_secsize),
                                    hrec);
                     len += size;  pos = begin + len;
+                    if (pos < offset) {
+                        len = 0;
+                        begin = pos;
+                    }
+                    if (pos > offset + length)
+                        goto stop_output;
                 }
             }
             gdth_ioctl_free(hanum);
         
-	    if (!flag) {
-		size = sprintf(buffer+len, "\n --\n");
-		len += size;  pos = begin + len;
-	    }
-            if (pos < offset) {
-                len = 0;
-                begin = pos;
+            if (!flag) {
+                size = sprintf(buffer+len, "\n --\n");
+                len += size;  pos = begin + len;
             }
-            if (pos > offset + length)
-                goto stop_output;
 
             /* 5. about host drives */
             size = sprintf(buffer+len,"\nHost Drives:");
             len += size;  pos = begin + len;
-	    flag = FALSE;
+            flag = FALSE;
 
             if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
                 goto stop_output;
-            for (i = 0; i < MAX_HDRIVES; ++i) {
+            for (i = 0; i < MAX_LDRIVES; ++i) {
                 if (!ha->hdr[i].is_logdrv || 
                     (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
                     continue;
                 /* 5.a get host drive list */
                 TRACE2(("host_get() drv_no %d\n",i));           
                 phg = (gdth_hget_str *)ha->pscratch;
-                gdtcmd.BoardNode = LOCALBOARD;
                 gdtcmd.Service = CACHESERVICE;
                 gdtcmd.OpCode = GDT_IOCTL;
                 gdtcmd.u.ioctl.p_param = virt_to_bus(phg);
@@ -825,23 +1121,27 @@
                 gdtcmd.u.ioctl.channel = i;
                 phg->entries = MAX_HDRIVES;
                 phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
-                gdth_do_cmd(scp, &gdtcmd, 30);
-                if (scp->SCp.Message != S_OK) {
+#if LINUX_VERSION_CODE >= 0x020322
+                gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                if (scp->SCp.Status != S_OK) 
+#else
+                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                if (scp.SCp.Status != S_OK) 
+#endif
+                {
                     ha->hdr[i].ldr_no = i;
                     ha->hdr[i].rw_attribs = 0;
                     ha->hdr[i].start_sec = 0;
                 } else {
                     for (j = 0; j < phg->entries; ++j) {
                         k = phg->entry[j].host_drive;
-                        if (k >= MAX_HDRIVES)
+                        if (k >= MAX_LDRIVES)
                             continue;
                         ha->hdr[k].ldr_no = phg->entry[j].log_drive;
                         ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
                         ha->hdr[k].start_sec = phg->entry[j].start_sec;
                     }
                 }
-                TRACE2(("host_get entries %d status %d\n",
-                        phg->entries, scp->SCp.Message));
             }
             gdth_ioctl_free(hanum);
 
@@ -853,24 +1153,24 @@
                                "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
                                i, ha->hdr[i].ldr_no);
                 len += size;  pos = begin + len;
-		flag = TRUE;
+                flag = TRUE;
 
                 size = sprintf(buffer+len,
                                " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
                                ha->hdr[i].size/2048, ha->hdr[i].start_sec);
                 len += size;  pos = begin + len;
+                if (pos < offset) {
+                    len = 0;
+                    begin = pos;
+                }
+                if (pos > offset + length)
+                    goto stop_output;
             }
         
-	    if (!flag) {
-		size = sprintf(buffer+len, "\n --\n");
-		len += size;  pos = begin + len;
-	    }
-            if (pos < offset) {
-                len = 0;
-                begin = pos;
+            if (!flag) {
+                size = sprintf(buffer+len, "\n --\n");
+                len += size;  pos = begin + len;
             }
-            if (pos > offset + length)
-                goto stop_output;
         }
 
         /* controller events */
@@ -886,7 +1186,7 @@
                 gdth_log_event(&estr.event_data, hrec);
                 do_gettimeofday(&tv);
                 sec = (int)(tv.tv_sec - estr.first_stamp);
-		if (sec < 0) sec = 0;
+                if (sec < 0) sec = 0;
                 size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
                                sec/3600, sec%3600/60, sec%60, hrec);
                 len += size;  pos = begin + len;
@@ -908,21 +1208,14 @@
         length = piord->size;
         memcpy(buffer+len, (char *)piord, length);
         gdth_ioctl_free(hanum);
-        len += length; pos = begin + len;
-
-        if (pos < offset) {
-            len = 0;
-            begin = pos;
-        }
-        if (pos > offset + length)
-            goto stop_output;
+        len = length; 
     }
 
 stop_output:
-
+#if LINUX_VERSION_CODE >= 0x020322
     scsi_release_command(scp);
     scsi_free_host_dev(sdev);
-
+#endif
     *start = buffer +(offset-begin);
     len -= (offset-begin);
     if (len > length)
@@ -932,18 +1225,33 @@
     return(len);
 }
 
-static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *gdtcmd,int timeout)
+static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd, 
+                        char *cmnd, int timeout)
 {
-    char cmnd[MAX_COMMAND_SIZE];
+    unsigned bufflen;
+#if LINUX_VERSION_CODE >= 0x020322
     DECLARE_MUTEX_LOCKED(sem);
+#else
+    struct semaphore sem = MUTEX_LOCKED;
+#endif
 
     TRACE2(("gdth_do_cmd()\n"));
-    memset(cmnd, 0, MAX_COMMAND_SIZE);
+    if (gdtcmd != NULL) { 
+        scp->SCp.this_residual = IOCTL_PRI;
+        bufflen = sizeof(gdth_cmd_str);
+    } else {
+        scp->SCp.this_residual = DEFAULT_PRI;
+        bufflen = 0;
+    }
     scp->request.rq_status = RQ_SCSI_BUSY;
     scp->request.sem = &sem;
-    scp->SCp.this_residual = IOCTL_PRI;
-    scsi_do_cmd(scp, cmnd, gdtcmd, sizeof(gdth_cmd_str), 
-                gdth_scsi_done, timeout*HZ, 1);
+#if LINUX_VERSION_CODE >= 0x020322
+    scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
+#else
+    GDTH_LOCK_SCSI_DOCMD();
+    scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
+    GDTH_UNLOCK_SCSI_DOCMD();
+#endif
     down(&sem);
 }
 
@@ -992,21 +1300,41 @@
     GDTH_UNLOCK_HA(ha, flags);
 }
 
+static int gdth_ioctl_check_bin(int hanum, ushort size)
+{
+    gdth_ha_str *ha;
+    ulong flags;
+    int ret_val;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    GDTH_LOCK_HA(ha, flags);
+
+    ret_val = FALSE;
+    if (ha->scratch_busy) {
+        if (((gdth_iord_str *)ha->pscratch)->size == (ulong32)size)
+            ret_val = TRUE;
+    }
+    GDTH_UNLOCK_HA(ha, flags);
+    return ret_val;
+}
+
+
 static void gdth_wait_completion(int hanum, int busnum, int id)
 {
     gdth_ha_str *ha;
     ulong flags;
     int i;
     Scsi_Cmnd *scp;
+    unchar b;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     GDTH_LOCK_HA(ha, flags);
 
     for (i = 0; i < GDTH_MAXCMDS; ++i) {
         scp = ha->cmd_tab[i].cmnd;
-        if (!SPECIAL_SCP(scp) && scp->target == (unchar)id &&
-            scp->channel == (unchar)busnum)
-        {
+        b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
+        if (!SPECIAL_SCP(scp) && scp->target == (unchar)id && 
+            b == (unchar)busnum) {
             scp->SCp.have_data_in = 0;
             GDTH_UNLOCK_HA(ha, flags);
             while (!scp->SCp.have_data_in)
@@ -1025,14 +1353,14 @@
     gdth_ha_str *ha;
     ulong flags;
     Scsi_Cmnd *scp;
+    unchar b;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     GDTH_LOCK_HA(ha, flags);
 
     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
-        if (scp->target == (unchar)id &&
-            scp->channel == (unchar)busnum)
-        {
+        b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
+        if (scp->target == (unchar)id && b == (unchar)busnum) {
             TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
             scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
         }
@@ -1045,14 +1373,14 @@
     gdth_ha_str *ha;
     ulong flags;
     Scsi_Cmnd *scp;
+    unchar b;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     GDTH_LOCK_HA(ha, flags);
 
     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
-        if (scp->target == (unchar)id &&
-            scp->channel == (unchar)busnum)
-        {
+        b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
+        if (scp->target == (unchar)id && b == (unchar)busnum) {
             TRACE2(("gdth_start_timeout(): update_timeout()\n"));
             gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual);
         }
@@ -1067,6 +1395,7 @@
     oldto = scp->timeout_per_command;
     scp->timeout_per_command = timeout;
 
+#if LINUX_VERSION_CODE >= 0x02014B
     if (timeout == 0) {
         del_timer(&scp->eh_timeout);
         scp->eh_timeout.data = (unsigned long) NULL;
@@ -1078,5 +1407,17 @@
         scp->eh_timeout.expires = jiffies + timeout;
         add_timer(&scp->eh_timeout);
     }
+#else
+    if (timeout > 0) {
+        if (timer_table[SCSI_TIMER].expires == 0) {
+            timer_table[SCSI_TIMER].expires = jiffies + timeout;
+            timer_active |= 1 << SCSI_TIMER;
+        } else {
+            if (jiffies + timeout < timer_table[SCSI_TIMER].expires)
+                timer_table[SCSI_TIMER].expires = jiffies + timeout;
+        }
+    }
+#endif
+
     return oldto;
 }
diff -urN linux-2.4.5-pre3/drivers/scsi/gdth_proc.h linux/drivers/scsi/gdth_proc.h
--- linux-2.4.5-pre3/drivers/scsi/gdth_proc.h	Fri Jan 21 09:48:11 2000
+++ linux/drivers/scsi/gdth_proc.h	Mon Dec  3 22:44:23 2001
@@ -2,23 +2,31 @@
 #define _GDTH_PROC_H
 
 /* gdth_proc.h 
- * $Id: gdth_proc.h,v 1.6 1999/03/05 14:32:36 achim Exp $
+ * $Id: gdth_proc.h,v 1.10 2000/07/24 09:30:01 achim Exp $
  */
 
 static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum);
-static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd * scp);
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd * scp);
 static int gdth_get_info(char *buffer,char **start,off_t offset,
                          int length,int vh,int hanum,int busnum);
 
+#if LINUX_VERSION_CODE >= 0x020322
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp);
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp);
+#else 
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
+#endif
+static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, 
+                        char *cmnd, int timeout);
+
 static int gdth_ioctl_alloc(int hanum, ushort size);
 static void gdth_ioctl_free(int hanum);
+static int gdth_ioctl_check_bin(int hanum, ushort size);
 static void gdth_wait_completion(int hanum, int busnum, int id);
 static void gdth_stop_timeout(int hanum, int busnum, int id);
 static void gdth_start_timeout(int hanum, int busnum, int id);
 static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout);
 
-static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *cmd,int timeout);
 void gdth_scsi_done(Scsi_Cmnd *scp);
 
 #endif
diff -urN linux-2.4.5-pre3/drivers/scsi/ips.c linux/drivers/scsi/ips.c
--- linux-2.4.5-pre3/drivers/scsi/ips.c	Fri Apr 27 13:59:18 2001
+++ linux/drivers/scsi/ips.c	Mon Dec  3 22:44:23 2001
@@ -86,6 +86,20 @@
 /*            Merge in changes through kernel 2.4.0test1ac21                 */
 /* 4.20.13  - Fix some failure cases / reset code                            */
 /*          - Hook into the reboot_notifier to flush the controller cache    */
+/* 4.50.01  - Fix problem when there is a hole in logical drive numbering   */
+/* 4.70.09  - Use a Common ( Large Buffer ) for Flashing from the JCRM CD    */
+/*          - Add IPSSEND Flash Support                                      */
+/*          - Set Sense Data for Unknown SCSI Command                        */
+/*          - Use Slot Number from NVRAM Page 5                              */
+/*          - Restore caller's DCDB Structure                                */
+/* 4.70.12  - Corrective actions for bad controller ( during initialization )*/
+/* 4.70.13  - Don't Send CDB's if we already know the device is not present  */
+/*          - Don't release HA Lock in ips_next() until SC taken off queue   */
+/*          - Unregister SCSI device in ips_release()                        */
+/* 4.70.15  - Fix Breakup for very large ( non-SG ) requests in ips_done()   */
+/* 4.71.00  - Change all memory allocations to not use GFP_DMA flag          */
+/*            Code Clean-Up for 2.4.x kernel                                 */
+/* 4.72.00  - Allow for a Scatter-Gather Element to exceed MAX_XFER Size     */
 /*                                                                           */
 /*****************************************************************************/
 
@@ -110,10 +124,8 @@
  * nocmdline            - Turn off passthru support
  * noi2o                - Don't use I2O Queues (ServeRAID 4 only)
  * nommap               - Don't use memory mapped I/O
+ * ioctlsize            - Initial size of the IOCTL buffer
  */
-  
-
-#include <linux/module.h>
 
 #include <asm/io.h>
 #include <asm/byteorder.h>
@@ -122,7 +134,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/ioport.h>
+#include <linux/ioport.h> 
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
@@ -130,6 +142,8 @@
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/reboot.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
 
 #include <linux/blk.h>
 #include <linux/types.h>
@@ -143,6 +157,8 @@
 #include "hosts.h"
 #include "ips.h"
 
+#include <linux/module.h>
+
 #include <linux/stat.h>
 #include <linux/config.h>
 
@@ -166,8 +182,9 @@
 /*
  * DRIVER_VER
  */
-#define IPS_VERSION_HIGH        "4.20"
-#define IPS_VERSION_LOW         ".20 "
+#define IPS_VERSION_HIGH        "4.72"
+#define IPS_VERSION_LOW         ".00 "
+
 
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
 struct proc_dir_entry proc_scsi_ips = {
@@ -214,6 +231,10 @@
 static int          ips_force_i2o = 1;               /* Always use I2O command delivery */
 static int          ips_resetcontroller = 1;         /* Reset the controller            */
 static int          ips_cmdline = 1;                 /* Support for passthru            */
+static int          ips_ioctlsize = IPS_IOCTL_SIZE;  /* Size of the ioctl buffer        */
+static int          ips_cd_boot = 0;                 /* Booting from ServeRAID Manager CD */
+static char        *ips_FlashData = NULL;            /* CD Boot - Flash Data Buffer      */
+static int          ips_FlashDataInUse = 0;          /* CD Boot - Flash Data In Use Flag */
 
 #ifdef IPS_DEBUG
 static int          ips_debug = 0;                   /* Debug mode                      */
@@ -224,7 +245,7 @@
  */
 static int ips_halt(struct notifier_block *nb, ulong event, void *buf);
 
-#define MAX_ADAPTER_NAME 9
+#define MAX_ADAPTER_NAME 11
 
 static char ips_adapter_name[][30] = {
    "ServeRAID",
@@ -235,7 +256,9 @@
    "ServeRAID 3L",
    "ServeRAID 4H",
    "ServeRAID 4M",
-   "ServeRAID 4L"
+   "ServeRAID 4L",
+   "ServeRAID 4Mx",
+   "ServeRAID 4Lx"
 };
 
 static struct notifier_block ips_notifier = {
@@ -347,6 +370,12 @@
 static u32 ips_statupd_copperhead(ips_ha_t *);
 static u32 ips_statupd_copperhead_memio(ips_ha_t *);
 static u32 ips_statupd_morpheus(ips_ha_t *);
+static void ips_flash_bios_section(void *);
+static void ips_flash_bios_segment(void *);
+static void ips_scheduled_flash_bios(void *);
+static void ips_create_nvrampage5(ips_ha_t *, IPS_NVRAM_P5 *);
+static void ips_get_bios_version(ips_ha_t *, int);
+static void ips_identify_controller(ips_ha_t *);
 static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
 static void ips_chkstatus(ips_ha_t *, IPS_STATUS *);
 static void ips_enable_int_copperhead(ips_ha_t *);
@@ -380,15 +409,15 @@
 static inline ips_copp_wait_item_t * ips_removeq_copp(ips_copp_queue_t *, ips_copp_wait_item_t *);
 static inline ips_copp_wait_item_t * ips_removeq_copp_head(ips_copp_queue_t *);
 static int ips_erase_bios(ips_ha_t *);
-static int ips_program_bios(ips_ha_t *, char *, int);
-static int ips_verify_bios(ips_ha_t *, char *, int);
+static int ips_program_bios(ips_ha_t *, char *, u32, u32);
+static int ips_verify_bios(ips_ha_t *, char *, u32, u32);
 static int ips_erase_bios_memio(ips_ha_t *);
-static int ips_program_bios_memio(ips_ha_t *, char *, int);
-static int ips_verify_bios_memio(ips_ha_t *, char *, int);
+static int ips_program_bios_memio(ips_ha_t *, char *, u32, u32);
+static int ips_verify_bios_memio(ips_ha_t *, char *, u32, u32);
 
 #ifndef NO_IPS_CMDLINE
 static int ips_is_passthru(Scsi_Cmnd *);
-static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *);
+static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int);
 static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static int ips_newusrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
@@ -432,6 +461,8 @@
       {"noi2o", &ips_force_i2o, 0},
       {"nommap", &ips_force_memio, 0},
       {"nocmdline", &ips_cmdline, 0},
+      {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE},
+      {"cdboot", &ips_cd_boot, 0},
    };
 
    METHOD_TRACE("ips_setup", 1);
@@ -498,8 +529,10 @@
    u8                func;
    u8                irq;
    u16               deviceID[2];
+   u16               subdevice_id;
    int               i;
    int               j;
+   u32               count;
    char             *ioremap_ptr;
    char             *mem_ptr;
    struct pci_dev   *dev[2];
@@ -522,6 +555,16 @@
 #endif
 #endif
 
+   /* If Booting from the ServeRAID Manager CD, Allocate a large Flash  */
+   /* Buffer ( so we won't need to allocate one for each adapter ).     */
+    if ( ips_cd_boot ) {                                                            
+      ips_FlashData = ( char * ) __get_free_pages( GFP_KERNEL, 7 ); 
+      if (ips_FlashData == NULL) {
+         /* The validity of this pointer is checked in ips_make_passthru() before it is used */
+         printk( KERN_WARNING "ERROR: Can't Allocate Large Buffer for Flashing\n" );
+      }
+   }                                                                               
+
    SHT->proc_info = ips_proc_info;
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
    SHT->proc_dir = &proc_scsi_ips;
@@ -530,53 +573,53 @@
 #endif
 
 #if defined(CONFIG_PCI)
- 
+
    /* initalize number of controllers */
    ips_num_controllers = 0;
    ips_next_controller = 0;
    ips_released_controllers = 0;
- 
+
    if (!pci_present())
       return (0);
 
-   morpheus = pci_find_device(IPS_VENDORID, IPS_MORPHEUS_DEVICEID, morpheus);
-   trombone = pci_find_device(IPS_VENDORID, IPS_COPPERHEAD_DEVICEID, trombone);
-  
+   morpheus = pci_find_device(IPS_VENDORID, IPS_DEVICEID_MORPHEUS, morpheus);
+   trombone = pci_find_device(IPS_VENDORID, IPS_DEVICEID_COPPERHEAD, trombone);
+
    /* determine which controller to probe first */
    if (!morpheus) {
       /* we only have trombone */
       dev[0] = trombone;
       dev[1] = NULL;
-      deviceID[0] = IPS_COPPERHEAD_DEVICEID;
+      deviceID[0] = IPS_DEVICEID_COPPERHEAD;
    } else if (!trombone) {
       /* we only have morpheus */
       dev[0] = morpheus;
       dev[1] = NULL;
-      deviceID[0] = IPS_MORPHEUS_DEVICEID;
+      deviceID[0] = IPS_DEVICEID_MORPHEUS;
    } else {
       /* we have both in the system */
       if (trombone->bus < morpheus->bus) {
          dev[0] = trombone;
          dev[1] = morpheus;
-         deviceID[0] = IPS_COPPERHEAD_DEVICEID;
-         deviceID[1] = IPS_MORPHEUS_DEVICEID;
+         deviceID[0] = IPS_DEVICEID_COPPERHEAD;
+         deviceID[1] = IPS_DEVICEID_MORPHEUS;
       } else if (trombone->bus > morpheus->bus) {
          dev[0] = morpheus;
          dev[1] = trombone;
-         deviceID[0] = IPS_MORPHEUS_DEVICEID;
-         deviceID[1] = IPS_COPPERHEAD_DEVICEID;
+         deviceID[0] = IPS_DEVICEID_MORPHEUS;
+         deviceID[1] = IPS_DEVICEID_COPPERHEAD;
       } else {
          /* further detection required */
          if (trombone->devfn < morpheus->devfn) {
             dev[0] = trombone;
             dev[1] = morpheus;
-            deviceID[0] = IPS_COPPERHEAD_DEVICEID;
-            deviceID[1] = IPS_MORPHEUS_DEVICEID;
+            deviceID[0] = IPS_DEVICEID_COPPERHEAD;
+            deviceID[1] = IPS_DEVICEID_MORPHEUS;
          } else {
             dev[0] = morpheus;
             dev[1] = trombone;
-            deviceID[0] = IPS_MORPHEUS_DEVICEID;
-            deviceID[1] = IPS_COPPERHEAD_DEVICEID;
+            deviceID[0] = IPS_DEVICEID_MORPHEUS;
+            deviceID[1] = IPS_DEVICEID_COPPERHEAD;
          }
       }
    }
@@ -711,14 +754,14 @@
 
          /* get planer status */
          if (pci_read_config_word(dev[i], 0x04, &planer)) {
-           printk(KERN_WARNING "(%s%d) can't get planer status.\n",
+            printk(KERN_WARNING "(%s%d) can't get planer status.\n",
                    ips_name, ips_next_controller);
 
             ips_next_controller++;
 
             continue;
          }
- 
+
          /* check to see if an onboard planer controller is disabled */
          if (!(planer & 0x000C)) {
 
@@ -743,6 +786,20 @@
             continue;
          }
 
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,15)
+         /* get the subdevice id */
+         if (pci_read_config_word(dev[i], 0x2e, &subdevice_id)) {
+            printk(KERN_WARNING "(%s%d) can't get subdevice id.\n",
+                   ips_name, ips_next_controller);
+
+            ips_next_controller++;
+
+            continue;
+         }
+#else
+         subdevice_id = dev[i]->subsystem_device;
+#endif
+
          /* found a controller */
          sh = scsi_register(SHT, sizeof(ips_ha_t));
 
@@ -771,7 +828,7 @@
          ips_num_controllers++;
          ha->active = 1;
 
-         ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_ATOMIC|GFP_DMA);
+         ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_ATOMIC);
 
          if (!ha->enq) {
             printk(KERN_WARNING "(%s%d) Unable to allocate host inquiry structure - skipping contoller\n",
@@ -779,26 +836,33 @@
 
             ha->active = 0;
             ips_free(ha);
+            scsi_unregister(sh);
+            ips_ha[ips_next_controller] = 0;
+            ips_sh[ips_next_controller] = 0;
             ips_next_controller++;
             ips_num_controllers--;
 
             continue;
          }
 
-         ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_ATOMIC|GFP_DMA);
+         ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_ATOMIC);
 
          if (!ha->adapt) {
             printk(KERN_WARNING "(%s%d) Unable to allocate host adapt structure - skipping controller\n",
                    ips_name, ips_next_controller);
+
             ha->active = 0;
             ips_free(ha);
+            scsi_unregister(sh);
+            ips_ha[ips_next_controller] = 0;
+            ips_sh[ips_next_controller] = 0;
             ips_next_controller++;
             ips_num_controllers--;
 
             continue;
          }
 
-         ha->conf = kmalloc(sizeof(IPS_CONF), GFP_ATOMIC|GFP_DMA);
+         ha->conf = kmalloc(sizeof(IPS_CONF), GFP_ATOMIC);
 
          if (!ha->conf) {
             printk(KERN_WARNING "(%s%d) Unable to allocate host conf structure - skipping controller\n",
@@ -806,13 +870,16 @@
 
             ha->active = 0;
             ips_free(ha);
+            scsi_unregister(sh);
+            ips_ha[ips_next_controller] = 0;
+            ips_sh[ips_next_controller] = 0;
             ips_next_controller++;
             ips_num_controllers--;
 
             continue;
          }
 
-         ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_ATOMIC|GFP_DMA);
+         ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_ATOMIC);
 
          if (!ha->nvram) {
             printk(KERN_WARNING "(%s%d) Unable to allocate host nvram structure - skipping controller\n",
@@ -820,13 +887,16 @@
 
             ha->active = 0;
             ips_free(ha);
+            scsi_unregister(sh);
+            ips_ha[ips_next_controller] = 0;
+            ips_sh[ips_next_controller] = 0;
             ips_next_controller++;
             ips_num_controllers--;
 
             continue;
          }
 
-         ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_ATOMIC|GFP_DMA);
+         ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_ATOMIC);
 
          if (!ha->subsys) {
             printk(KERN_WARNING "(%s%d) Unable to allocate host subsystem structure - skipping controller\n",
@@ -834,13 +904,16 @@
 
             ha->active = 0;
             ips_free(ha);
+            scsi_unregister(sh);
+            ips_ha[ips_next_controller] = 0;
+            ips_sh[ips_next_controller] = 0;
             ips_next_controller++;
             ips_num_controllers--;
 
             continue;
          }
 
-         ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_ATOMIC|GFP_DMA);
+         ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_ATOMIC);
 
          if (!ha->dummy) {
             printk(KERN_WARNING "(%s%d) Unable to allocate host dummy structure - skipping controller\n",
@@ -848,24 +921,29 @@
 
             ha->active = 0;
             ips_free(ha);
+            scsi_unregister(sh);
+            ips_ha[ips_next_controller] = 0;
+            ips_sh[ips_next_controller] = 0;
             ips_next_controller++;
             ips_num_controllers--;
 
             continue;
          }
 
-         ha->ioctl_data = kmalloc(IPS_IOCTL_SIZE, GFP_ATOMIC|GFP_DMA);
-         ha->ioctl_datasize = IPS_IOCTL_SIZE;
+         for (count = PAGE_SIZE, ha->ioctl_order = 0;
+              count < ips_ioctlsize;
+              ha->ioctl_order++, count <<= 1);
+
+         ha->ioctl_data = (char *) __get_free_pages(GFP_KERNEL, ha->ioctl_order);
+         ha->ioctl_datasize = count;
+
          if (!ha->ioctl_data) {
-            printk(KERN_WARNING "(%s%d) Unable to allocate ioctl data - skipping controller\n",
+            printk(KERN_WARNING "(%s%d) Unable to allocate ioctl data\n",
                    ips_name, ips_next_controller);
 
-            ha->active = 0;
-            ips_free(ha);
-            ips_next_controller++;
-            ips_num_controllers--;
-
-            continue;
+            ha->ioctl_data = NULL;
+            ha->ioctl_order = 0;
+            ha->ioctl_datasize = 0;
          }
 
          /* Store away needed values for later use */
@@ -879,7 +957,11 @@
          sh->cmd_per_lun = sh->hostt->cmd_per_lun;
          sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
          sh->use_clustering = sh->hostt->use_clustering;
-         scsi_set_pci_device(sh, dev[i]);
+/***** Implement the following if it gets into a future kernel
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,4)
+         sh->max_sectors = 128;
+#endif
+******/
 
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,32)
          sh->wish_block = FALSE;
@@ -895,7 +977,9 @@
          ha->ioremap_ptr = ioremap_ptr;
          ha->host_num = ips_next_controller;
          ha->revision_id = revision_id;
+         ha->slot_num = PCI_SLOT(dev[i]->devfn);
          ha->device_id = deviceID[i];
+         ha->subdevice_id = subdevice_id;
          ha->pcidev = dev[i];
 
          /*
@@ -962,6 +1046,9 @@
 
                ha->active = 0;
                ips_free(ha);
+               scsi_unregister(sh);
+               ips_ha[ips_next_controller] = 0;
+               ips_sh[ips_next_controller] = 0;
                ips_next_controller++;
                ips_num_controllers--;
 
@@ -976,6 +1063,9 @@
 
             ha->active = 0;
             ips_free(ha);
+            scsi_unregister(sh);
+            ips_ha[ips_next_controller] = 0;
+            ips_sh[ips_next_controller] = 0;
             ips_next_controller++;
             ips_num_controllers--;
 
@@ -985,7 +1075,7 @@
          /*
           * Allocate a temporary SCB for initialization
           */
-         ha->scbs = (ips_scb_t *) kmalloc(sizeof(ips_scb_t), GFP_ATOMIC|GFP_DMA);
+         ha->scbs = (ips_scb_t *) kmalloc(sizeof(ips_scb_t), GFP_ATOMIC);
          if (!ha->scbs) {
             /* couldn't allocate a temp SCB */
             printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
@@ -993,6 +1083,9 @@
 
             ha->active = 0;
             ips_free(ha);
+            scsi_unregister(sh);
+            ips_ha[ips_next_controller] = 0;
+            ips_sh[ips_next_controller] = 0;
             free_irq(ha->irq, ha);
             ips_next_controller++;
             ips_num_controllers--;
@@ -1001,7 +1094,7 @@
          }
 
          memset(ha->scbs, 0, sizeof(ips_scb_t));
-         ha->scbs->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC|GFP_DMA);
+         ha->scbs->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC);
          if (!ha->scbs->sg_list) {
             /* couldn't allocate a temp SCB S/G list */
             printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
@@ -1009,6 +1102,9 @@
 
             ha->active = 0;
             ips_free(ha);
+            scsi_unregister(sh);
+            ips_ha[ips_next_controller] = 0;
+            ips_sh[ips_next_controller] = 0;
             free_irq(ha->irq, ha);
             ips_next_controller++;
             ips_num_controllers--;
@@ -1027,6 +1123,13 @@
     * Controller init
     */
    for (i = 0; i < ips_next_controller; i++) {
+
+      if (ips_ha[i] == 0) {
+         printk(KERN_WARNING "(%s%d) ignoring bad controller\n",
+                ips_name, i);
+         continue;
+      }
+
       ha = ips_ha[i];
       sh = ips_sh[i];
 
@@ -1165,6 +1268,8 @@
    /* free IRQ */
    free_irq(ha->irq, ha);
 
+   scsi_unregister(sh);
+
    ips_released_controllers++;
 
    if (ips_num_controllers == ips_released_controllers)
@@ -1376,7 +1481,7 @@
    if (!ret) {
       Scsi_Cmnd *scsi_cmd;
 
-      printk(KERN_NOTICE 
+      printk(KERN_NOTICE
              "(%s%d) Controller reset failed - controller now offline.\n",
              ips_name, ha->host_num);
 
@@ -1408,7 +1513,7 @@
    if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
       Scsi_Cmnd *scsi_cmd;
 
-      printk(KERN_NOTICE 
+      printk(KERN_NOTICE
              "(%s%d) Controller reset failed - controller now offline.\n",
              ips_name, ha->host_num);
 
@@ -1622,17 +1727,29 @@
       kern_area = ha->ioctl_data;
       datasize = *((u32 *) &SC->cmnd[8]);
 
-      if (copy_to_user(user_area, kern_area, datasize) > 0) {
-         DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy out user data",
-                   ips_name, ha->host_num);
+      if (datasize) {
+         if (copy_to_user(user_area, kern_area, datasize) > 0) {
+            DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy out user data",
+                      ips_name, ha->host_num);
 
-         SC->result = DID_ERROR << 16;
-         SC->scsi_done(SC);
+            SC->result = DID_ERROR << 16;
+            SC->scsi_done(SC);
+         } else {
+            SC->scsi_done(SC);
+         }
       } else {
          SC->scsi_done(SC);
       }
    }
 
+   /* If We were using the CD Boot Flash Buffer, Restore the Old Values */
+   if ( ips_FlashData == ha->ioctl_data ) {                               
+      ha->ioctl_data = ha->save_ioctl_data;                           
+      ha->ioctl_order = ha->save_ioctl_order;                          
+      ha->ioctl_datasize = ha->save_ioctl_datasize;                       
+      ips_FlashDataInUse = 0;                                             
+   }
+
    return (0);
 }
 
@@ -1718,6 +1835,9 @@
             device->queue_depth = ha->max_cmds / count - 1;
          else
             device->queue_depth = 2;
+
+         if (device->queue_depth < 2)
+            device->queue_depth = 2;
       }
    }
 }
@@ -1979,10 +2099,11 @@
 
    /* Find our host structure */
    for (i = 0; i < ips_next_controller; i++) {
-      if (ips_sh[i] && ips_sh[i]->host_no == hostno) {
-         ha = (ips_ha_t *) ips_sh[i]->hostdata;
-
-         break;
+      if (ips_sh[i]) {
+         if (ips_sh[i]->host_no == hostno) {
+            ha = (ips_ha_t *) ips_sh[i]->hostdata;
+            break;
+         }
       }
    }
 
@@ -2051,7 +2172,8 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_make_passthru(ips_ha_t *ha, Scsi_Cmnd *SC, ips_scb_t *scb) {
+ips_make_passthru(ips_ha_t *ha, Scsi_Cmnd *SC, ips_scb_t *scb, int intr) {
+   IPS_NVRAM_P5    nvram;
    ips_passthru_t *pt;
 
    METHOD_TRACE("ips_make_passthru", 1);
@@ -2128,19 +2250,375 @@
             return (IPS_FAILURE);
          }
 
+         if ((pt->CoppCP.cmd.nvram.op_code == IPS_CMD_RW_NVRAM_PAGE) &&
+             (pt->CoppCP.cmd.nvram.page == 5) &&
+             (pt->CoppCP.cmd.nvram.write == 0)) {
+
+            if (pt->CmdBSize < sizeof(IPS_NVRAM_P5)) {
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            ips_get_bios_version(ha, IPS_INTR_IORL);
+            ips_create_nvrampage5(ha, &nvram);
+
+            /* Copy the result back */
+            memcpy(SC->request_buffer + sizeof(ips_passthru_t), &nvram, sizeof(IPS_NVRAM_P5));
+
+            SC->result = DID_OK << 16;
+            pt->BasicStatus = 0x00;
+            pt->ExtendedStatus = 0x00;
+
+            return (IPS_SUCCESS_IMM);
+         }
+
          if (ips_usrcmd(ha, pt, scb))
             return (IPS_SUCCESS);
          else
             return (IPS_FAILURE);
       } else if (SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
+         char           *user_area;
+         char           *kern_area;
+         u32             datasize;
+
          if (SC->request_bufflen < (sizeof(ips_passthru_t))) {
             /* wrong size */
             DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
                       ips_name, ha->host_num);
 
+            SC->result = DID_ERROR << 16;
+
             return (IPS_FAILURE);
          }
 
+
+         /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can     */
+         /* avoid allocating a huge buffer per adapter ( which can fail ). */
+         if ( (ips_FlashData) &&                                            
+              (pt->CmdBSize == IPS_IMAGE_SIZE) &&                                   
+              (ips_FlashDataInUse == 0) ) {                                 
+            ips_FlashDataInUse = 1;                                         
+            ha->save_ioctl_data  = ha->ioctl_data;                          
+            ha->save_ioctl_order = ha->ioctl_order;                         
+            ha->save_ioctl_datasize = ha->ioctl_datasize;                   
+            ha->ioctl_data  = ips_FlashData;                                
+            ha->ioctl_order = 7;                                            
+            ha->ioctl_datasize = IPS_IMAGE_SIZE;                                    
+         }                                                                  
+
+         if ((pt->CoppCP.cmd.nvram.op_code == IPS_CMD_RW_NVRAM_PAGE) &&
+             (pt->CoppCP.cmd.nvram.page == 5) &&
+             (pt->CoppCP.cmd.nvram.write == 0)) {
+
+            datasize = *((u32 *) &scb->scsi_cmd->cmnd[8]);
+
+            if (datasize < sizeof(IPS_NVRAM_P5)) {
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            ips_get_bios_version(ha, IPS_INTR_IORL);
+            ips_create_nvrampage5(ha, &nvram);
+
+            user_area = *((char **) &scb->scsi_cmd->cmnd[4]);
+            kern_area = (char *) &nvram;
+            datasize = *((u32 *) &scb->scsi_cmd->cmnd[8]);
+
+            if (datasize > sizeof(IPS_NVRAM_P5))
+               datasize = sizeof(IPS_NVRAM_P5);
+
+            /* Copy out the buffer */
+            if (copy_to_user((void *) user_area, (void *) kern_area, datasize) > 0) {
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            pt->BasicStatus = 0x00;
+            pt->ExtendedStatus = 0x00;
+            SC->result = DID_OK << 16;
+
+            return (IPS_SUCCESS_IMM);
+         }
+
+         /*
+          * IPSSEND flashing BIOS
+          */
+         if ((pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) &&
+             (pt->CoppCP.cmd.flashfw.type == 1) &&
+             (pt->CoppCP.cmd.flashfw.direction == 2) &&
+             (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
+            struct tq_struct  task;
+            IPS_FLASH_DATA    flash_data;
+            DECLARE_MUTEX_LOCKED(sem);
+
+            /* We only support one packet */
+            if (pt->CoppCP.cmd.flashfw.total_packets != 1) {
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            /* copy in the size/buffer ptr from the scsi command */
+            memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4);
+            memcpy(&pt->CmdBSize, &SC->cmnd[8], 4);
+
+            if (pt->CmdBSize > pt->CoppCP.cmd.flashfw.count) {
+               pt->CmdBSize = pt->CoppCP.cmd.flashfw.count;
+            } else {
+               /* ERROR: Command/Buffer mismatch */
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            if ((!ha->func.programbios) ||
+                (!ha->func.erasebios) ||
+                (!ha->func.verifybios)) {
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            /* must have a buffer */
+            if ((!pt->CmdBSize) || (!pt->CmdBuffer)) {
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            /* make sure buffer is big enough */
+            if (pt->CmdBSize > ha->ioctl_datasize) {
+               void *bigger_struct;
+               u32   count;
+               u32   order;
+
+               /* try to allocate a bigger struct */
+               for (count = PAGE_SIZE, order = 0;
+                    count < pt->CmdBSize;
+                    order++, count <<= 1);
+
+               bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
+               if (bigger_struct) {
+                  /* free the old memory */
+                  free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
+
+                  /* use the new memory */
+                  ha->ioctl_data = (char *) bigger_struct;
+                  ha->ioctl_order = order;
+                  ha->ioctl_datasize = count;
+               } else {
+                  pt->BasicStatus = 0x0B;
+                  pt->ExtendedStatus = 0x00;
+                  SC->result = DID_ERROR << 16;
+
+                  spin_unlock(&ha->ips_lock);
+
+                  return (IPS_FAILURE);
+               }
+            }
+
+            /* copy in the buffer */
+            if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) {
+               DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer",
+                         ips_name, ha->host_num);
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            flash_data.userbuffer = pt->CmdBuffer;
+            flash_data.usersize = pt->CmdBSize;
+            flash_data.kernbuffer = ha->ioctl_data;
+            flash_data.kernsize = ha->ioctl_datasize;
+            flash_data.offset = 0;
+            flash_data.SC = (void *) SC;
+            flash_data.pt = (void *) pt;
+            flash_data.ha = (void *) ha;
+            flash_data.sem = &sem;
+
+            task.sync = 0;
+            task.routine = ips_scheduled_flash_bios;
+            task.data = (void *) &flash_data;
+
+            /* Unlock the master lock */
+            spin_unlock_irq(&io_request_lock);
+
+            queue_task(&task, &tq_immediate);
+            mark_bh(IMMEDIATE_BH);
+
+            /* Wait for the flash to complete */
+            down(&sem);
+
+            /* Obtain the master lock */
+            spin_lock_irq(&io_request_lock);
+
+            return (flash_data.retcode);
+         }
+
+         /*
+          * IPSSEND flashing BIOS in sectioned mode
+          */
+         if ((pt->CoppCP.cmd.flashbios.op_code == IPS_CMD_RW_BIOSFW) &&
+             (pt->CoppCP.cmd.flashbios.type == 1) &&
+             (pt->CoppCP.cmd.flashbios.direction == 4) &&
+             (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
+            struct tq_struct  task;
+            IPS_FLASH_DATA    flash_data;
+            DECLARE_MUTEX_LOCKED(sem);
+
+            /* copy in the size/buffer ptr from the scsi command */
+            memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4);
+            memcpy(&pt->CmdBSize, &SC->cmnd[8], 4);
+
+            if (pt->CmdBSize > pt->CoppCP.cmd.flashbios.count) {
+               pt->CmdBSize = pt->CoppCP.cmd.flashbios.count;
+            } else {
+               /* ERROR: Command/Buffer mismatch */
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            /* Update the Card BIOS */
+            if ((!ha->func.programbios) ||
+                (!ha->func.erasebios) ||
+                (!ha->func.verifybios)) {
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            /* must have a buffer */
+            if ((!pt->CmdBSize) || (!pt->CmdBuffer)) {
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            /* make sure buffer is big enough */
+            if (pt->CmdBSize > ha->ioctl_datasize) {
+               void *bigger_struct;
+               u32   count;
+               u32   order;
+
+               /* try to allocate a bigger struct */
+               for (count = PAGE_SIZE, order = 0;
+                    count < pt->CmdBSize;
+                    order++, count <<= 1);
+
+               bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
+               if (bigger_struct) {
+                  /* free the old memory */
+                  free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
+
+                  /* use the new memory */
+                  ha->ioctl_data = (char *) bigger_struct;
+                  ha->ioctl_order = order;
+                  ha->ioctl_datasize = count;
+               } else {
+                  pt->BasicStatus = 0x0B;
+                  pt->ExtendedStatus = 0x00;
+                  SC->result = DID_ERROR << 16;
+
+                  spin_unlock(&ha->ips_lock);
+
+                  return (IPS_FAILURE);
+               }
+            }
+
+            /* copy in the buffer */
+            if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) {
+               DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer",
+                         ips_name, ha->host_num);
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            flash_data.userbuffer = pt->CmdBuffer;
+            flash_data.usersize = pt->CmdBSize;
+            flash_data.kernbuffer = ha->ioctl_data;
+            flash_data.kernsize = ha->ioctl_datasize;
+            flash_data.offset = pt->CoppCP.cmd.flashbios.offset;
+            flash_data.SC = (void *) SC;
+            flash_data.pt = (void *) pt;
+            flash_data.ha = (void *) ha;
+            flash_data.sem = &sem;
+
+            task.sync = 0;
+            task.routine = ips_flash_bios_section;
+            task.data = (void *) &flash_data;
+
+            /* Unlock the master lock */
+            spin_unlock_irq(&io_request_lock);
+
+            queue_task(&task, &tq_immediate);
+            mark_bh(IMMEDIATE_BH);
+           
+            /* Wait for the flash to complete */
+            down(&sem);
+
+            /* Obtain the master lock */
+            spin_lock_irq(&io_request_lock);
+
+            return (flash_data.retcode);
+         }
+
+         if ((pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) &&
+             (pt->CoppCP.cmd.flashfw.type == 1) &&
+             (pt->CoppCP.cmd.flashfw.direction == 3) &&
+             (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
+            /* Erase the Card BIOS */
+            if (!ha->func.erasebios) {
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            if ((*ha->func.erasebios)(ha)) {
+               DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
+                         ips_name, ha->host_num);
+               pt->BasicStatus = 0x0B;
+               pt->ExtendedStatus = 0x00;
+               SC->result = DID_ERROR << 16;
+
+               return (IPS_FAILURE);
+            }
+
+            SC->result = DID_OK << 16;
+            pt->BasicStatus = 0x00;
+            pt->ExtendedStatus = 0x00;
+
+            return (IPS_SUCCESS_IMM);
+         }
+
          if (ips_newusrcmd(ha, pt, scb))
             return (IPS_SUCCESS);
          else
@@ -2149,87 +2627,152 @@
 
       break;
 
-   case IPS_FLASHBIOS:
-      /* we must use the new interface */
-      if (SC->cmnd[0] != IPS_IOCTL_NEW_COMMAND)
-         return (IPS_FAILURE);
+   } /* end switch */
 
-      /* don't flash the BIOS on future cards */
-      if ((ha->device_id != IPS_COPPERHEAD_DEVICEID) ||
-          (ha->revision_id > IPS_REVID_TROMBONE64)) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unsupported controller",
-                   ips_name, ha->host_num);
+   return (IPS_FAILURE);
+}
 
-         return (IPS_FAILURE);
-      }
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_scheduled_flash_bios                                   */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Flash the BIOS on a Copperhead style controller                        */
+/*   To be called from a task queue                                         */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_scheduled_flash_bios(void *data) {
+   ips_ha_t       *ha;
+   Scsi_Cmnd      *SC;
+   ips_passthru_t *pt;
+   IPS_FLASH_DATA *fd;
 
-      /*
-       * Check to make sure we have functions
-       * to handle the request
-       */
-      if ((!ha->func.programbios) ||
-          (!ha->func.erasebios) ||
-          (!ha->func.verifybios))
-         return (IPS_FAILURE);
+   fd = (IPS_FLASH_DATA *) data;
+   ha = (ips_ha_t *) fd->ha;
+   pt = (ips_passthru_t *) fd->pt;
+   SC = (Scsi_Cmnd *) fd->SC;
 
-      /* copy in the size/buffer ptr from the scsi command */
-      memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4);
-      memcpy(&pt->CmdBSize, &SC->cmnd[8], 4);
+   /*
+    * Set initial return codes
+    */
+   SC->result = DID_OK << 16;
+   pt->BasicStatus = 0x00;
+   pt->ExtendedStatus = 0x00;
+   fd->retcode = IPS_SUCCESS_IMM;
 
-      /* must have a buffer */
-      if ((!pt->CmdBSize) || (!pt->CmdBuffer))
-         return (IPS_FAILURE);
+   /*
+    * Fix the size/ptr to account for the
+    * flash header
+    */
+   fd->kernbuffer += 0xC0;
+   fd->kernsize -= 0xC0;
+   fd->userbuffer += 0xC0;
+   fd->usersize -= 0xC0;
 
-      /* make sure buffer is big enough */
-      if (pt->CmdBSize > ha->ioctl_datasize) {
-         void *bigger_struct;
+   if ((*ha->func.erasebios)(ha)) {
+      DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
+                ips_name, ha->host_num);
+      pt->BasicStatus = 0x0B;
+      pt->ExtendedStatus = 0x00;
+      SC->result = DID_ERROR << 16;
+      fd->retcode = IPS_FAILURE;
+      up(fd->sem);
 
-         /* try to allocate a bigger struct */
-         bigger_struct = kmalloc(pt->CmdBSize, GFP_ATOMIC|GFP_DMA);
-         if (bigger_struct) {
-            /* free the old memory */
-            kfree(ha->ioctl_data);
+      return ;
+   }
 
-            /* use the new memory */
-            ha->ioctl_data = bigger_struct;
-            ha->ioctl_datasize = pt->CmdBSize;
-         } else
-            return (IPS_FAILURE);
-      }
+   ips_flash_bios_segment(data);
 
-      /* copy in the buffer */
-      if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer",
-                   ips_name, ha->host_num);
+   if (fd->retcode == IPS_FAILURE)
+      return ;
 
-         return (IPS_FAILURE);
-      }
+   if ((*ha->func.verifybios)(ha, fd->kernbuffer, fd->usersize, fd->offset)) {
+      DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash",
+                ips_name, ha->host_num);
+      pt->BasicStatus = 0x0B;
+      pt->ExtendedStatus = 0x00;
+      SC->result = DID_ERROR << 16;
+      fd->retcode = IPS_FAILURE;
+      up(fd->sem);
 
-      if ((*ha->func.erasebios)(ha)) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
-                   ips_name, ha->host_num);
+      return ;
+   }
 
-         return (IPS_FAILURE);
-      }
+   /* Tell them we are done */
+   if (fd->retcode != IPS_FAILURE)
+      up(fd->sem);
+}
 
-      if ((*ha->func.programbios)(ha, ha->ioctl_data, pt->CmdBSize)) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to program flash",
-                   ips_name, ha->host_num);
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_flash_bios_section                                     */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   wrapper for ips_flash_bios_segment that raises the semaphore           */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_flash_bios_section(void *data) {
+   ips_ha_t       *ha;
+   Scsi_Cmnd      *SC;
+   ips_passthru_t *pt;
+   IPS_FLASH_DATA *fd;
 
-         return (IPS_FAILURE);
-      }
+   fd = (IPS_FLASH_DATA *) data;
+   ha = (ips_ha_t *) fd->ha;
+   pt = (ips_passthru_t *) fd->pt;
+   SC = (Scsi_Cmnd *) fd->SC;
 
-      if ((*ha->func.verifybios)(ha, ha->ioctl_data, pt->CmdBSize)) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash",
-                   ips_name, ha->host_num);
+   /*
+    * Set initial return codes
+    */
+   SC->result = DID_OK << 16;
+   pt->BasicStatus = 0x00;
+   pt->ExtendedStatus = 0x00;
+   fd->retcode = IPS_SUCCESS_IMM;
 
-         return (IPS_FAILURE);
-      }
+   ips_flash_bios_segment(data);
 
-      return (IPS_SUCCESS_IMM);
-   } /* end switch */
+   if (fd->retcode != IPS_FAILURE)
+      up(fd->sem);
+}
 
-   return (IPS_FAILURE);
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_flash_bios_segment                                     */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Flash a portion of the BIOS on a Copperhead style controller           */
+/*   To be called from a task queue                                         */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_flash_bios_segment(void *data) {
+   ips_ha_t       *ha;
+   Scsi_Cmnd      *SC;
+   ips_passthru_t *pt;
+   IPS_FLASH_DATA *fd;
+
+   fd = (IPS_FLASH_DATA *) data;
+   ha = (ips_ha_t *) fd->ha;
+   pt = (ips_passthru_t *) fd->pt;
+   SC = (Scsi_Cmnd *) fd->SC;
+
+   if ((*ha->func.programbios)(ha, fd->kernbuffer, fd->usersize, fd->offset)) {
+      DEBUG_VAR(1, "(%s%d) flash bios failed - unable to program flash",
+                ips_name, ha->host_num);
+      pt->BasicStatus = 0x0B;
+      pt->ExtendedStatus = 0x00;
+      SC->result = DID_ERROR << 16;
+      fd->retcode = IPS_FAILURE;
+      up(fd->sem);
+
+      return ;
+   }
 }
 
 /****************************************************************************/
@@ -2363,16 +2906,23 @@
    if (pt->CmdBSize) {
       if (pt->CmdBSize > ha->ioctl_datasize) {
          void *bigger_struct;
+         u32   count;
+         u32   order;
 
          /* try to allocate a bigger struct */
-         bigger_struct = kmalloc(pt->CmdBSize, GFP_ATOMIC|GFP_DMA);
+         for (count = PAGE_SIZE, order = 0;
+              count < pt->CmdBSize;
+              order++, count <<= 1);
+
+         bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
          if (bigger_struct) {
             /* free the old memory */
-            kfree(ha->ioctl_data);
+            free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
 
             /* use the new memory */
-            ha->ioctl_data = bigger_struct;
-            ha->ioctl_datasize = pt->CmdBSize;
+            ha->ioctl_data = (char *) bigger_struct;
+            ha->ioctl_order = order;
+            ha->ioctl_datasize = count;
          } else
             return (0);
 
@@ -2450,6 +3000,10 @@
    pt = (ips_passthru_t *) scb->scsi_cmd->request_buffer;
 
    /* Copy data back to the user */
+   if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) {       /* Copy DCDB Back to Caller's Area */
+      memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof(IPS_DCDB_TABLE));
+   }
+
    if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_COMMAND) {
       /* Copy data back to the user */
       pt->BasicStatus = scb->basic_status;
@@ -2606,6 +3160,253 @@
 
 /****************************************************************************/
 /*                                                                          */
+/* Routine Name: ips_identify_controller                                    */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Identify this controller                                               */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_identify_controller(ips_ha_t *ha) {
+   METHOD_TRACE("ips_identify_controller", 1);
+
+   switch (ha->device_id) {
+   case IPS_DEVICEID_COPPERHEAD:
+      if (ha->revision_id <= IPS_REVID_SERVERAID) {
+         ha->ad_type = IPS_ADTYPE_SERVERAID;
+      } else if (ha->revision_id == IPS_REVID_SERVERAID2) {
+         ha->ad_type = IPS_ADTYPE_SERVERAID2;
+      } else if (ha->revision_id == IPS_REVID_NAVAJO) {
+         ha->ad_type = IPS_ADTYPE_NAVAJO;
+      } else if ((ha->revision_id == IPS_REVID_SERVERAID2) && (ha->slot_num == 0)) {
+         ha->ad_type = IPS_ADTYPE_KIOWA;
+      } else if ((ha->revision_id >= IPS_REVID_CLARINETP1) &&
+                 (ha->revision_id <= IPS_REVID_CLARINETP3)) {
+         if (ha->enq->ucMaxPhysicalDevices == 15)
+            ha->ad_type = IPS_ADTYPE_SERVERAID3L;
+         else
+            ha->ad_type = IPS_ADTYPE_SERVERAID3;
+      } else if ((ha->revision_id >= IPS_REVID_TROMBONE32) &&
+                 (ha->revision_id <= IPS_REVID_TROMBONE64)) {
+         ha->ad_type = IPS_ADTYPE_SERVERAID4H;
+      }
+      break;
+
+   case IPS_DEVICEID_MORPHEUS:
+      switch (ha->subdevice_id) {
+      case IPS_SUBDEVICEID_4L:
+         ha->ad_type = IPS_ADTYPE_SERVERAID4L;
+         break;
+
+      case IPS_SUBDEVICEID_4M:
+         ha->ad_type = IPS_ADTYPE_SERVERAID4M;
+         break;
+
+      case IPS_SUBDEVICEID_4MX:
+         ha->ad_type = IPS_ADTYPE_SERVERAID4MX;
+         break;
+
+      case IPS_SUBDEVICEID_4LX:
+         ha->ad_type = IPS_ADTYPE_SERVERAID4LX;
+         break;
+      }
+
+      break;
+   }
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_create_nvrampage5                                      */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Create a pseudo nvram page 5                                           */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_create_nvrampage5(ips_ha_t *ha, IPS_NVRAM_P5 *nvram) {
+   METHOD_TRACE("ips_create_nvrampage5", 1);
+
+   memset(nvram, 0, sizeof(IPS_NVRAM_P5));
+
+   nvram->signature = IPS_NVRAM_P5_SIG;
+   nvram->adapter_slot = ha->slot_num;
+   nvram->adapter_type = ha->ad_type;
+   nvram->operating_system = IPS_OS_LINUX;
+   strncpy((char *) nvram->driver_high, IPS_VERSION_HIGH, 4);
+   strncpy((char *) nvram->driver_low, IPS_VERSION_LOW, 4);
+   strncpy((char *) nvram->bios_high, ha->bios_version, 4);
+   strncpy((char *) nvram->bios_low, ha->bios_version + 4, 4);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_get_bios_version                                       */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Get the BIOS revision number                                           */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_get_bios_version(ips_ha_t *ha, int intr) {
+   ips_scb_t *scb;
+   int        ret;
+   u8         major;
+   u8         minor;
+   u8         subminor; 
+   u8        *buffer;
+   char       hexDigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+   METHOD_TRACE("ips_get_bios_version", 1);
+
+   major = 0;
+   minor = 0;
+
+   strncpy(ha->bios_version, "       ?", 8);
+
+   if (ha->device_id == IPS_DEVICEID_COPPERHEAD) {
+      if (IPS_USE_MEMIO(ha)) {
+         /* Memory Mapped I/O */
+
+         /* test 1st byte */
+         writel(0, ha->mem_ptr + IPS_REG_FLAP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            udelay(5); /* 5 us */
+
+         if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
+            return;
+
+         writel(1, ha->mem_ptr + IPS_REG_FLAP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            udelay(5); /* 5 us */
+
+         if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
+            return;
+
+         /* Get Major version */
+         writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            udelay(5); /* 5 us */
+
+         major = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+         /* Get Minor version */
+         writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            udelay(5); /* 5 us */
+
+         minor = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+         /* Get Sub Minor version */
+         writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            udelay(5);/* 5 us */
+
+         subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+
+      } else {
+         /* Programmed I/O */
+
+         /* test 1st byte */
+         outl(0, ha->io_addr + IPS_REG_FLAP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            udelay(5); /* 5 us */
+
+         if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
+            return ;
+
+         outl(1, ha->io_addr + IPS_REG_FLAP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            udelay(5); /* 5 us */
+
+         if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
+            return ;
+
+         /* Get Major version */
+         outl(0x1FF, ha->io_addr + IPS_REG_FLAP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            udelay(5); /* 5 us */
+
+         major = inb(ha->io_addr + IPS_REG_FLDP);
+
+         /* Get Minor version */
+         outl(0x1FE, ha->io_addr + IPS_REG_FLAP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            udelay(5); /* 5 us */
+
+         minor = inb(ha->io_addr + IPS_REG_FLDP);
+         
+         /* Get SubMinor version */
+         outl(0x1FD, ha->io_addr + IPS_REG_FLAP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            udelay(5); /* 5 us */
+
+         subminor = inb(ha->io_addr + IPS_REG_FLDP);
+
+      }
+   } else {
+      /* Morpheus Family - Send Command to the card */
+
+      buffer = kmalloc(0x1000, GFP_ATOMIC);
+      if (!buffer)
+         return;
+
+      memset(buffer, 0, 0x1000);
+
+      scb = &ha->scbs[ha->max_cmds-1];
+
+      ips_init_scb(ha, scb);
+
+      scb->timeout = ips_cmd_timeout;
+      scb->cdb[0] = IPS_CMD_RW_BIOSFW;
+
+      scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW;
+      scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
+      scb->cmd.flashfw.type = 1;
+      scb->cmd.flashfw.direction = 0;
+      scb->cmd.flashfw.count = 0x800;
+      scb->cmd.flashfw.buffer_addr = VIRT_TO_BUS(buffer);
+      scb->cmd.flashfw.total_packets = 1;
+      scb->cmd.flashfw.packet_num = 0;
+
+      /* issue the command */
+      if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
+          (ret == IPS_SUCCESS_IMM) ||
+          ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
+         /* Error occurred */
+         kfree(buffer);
+
+         return;
+      }
+
+      if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) {
+         major = buffer[0x1ff + 0xC0]; /* Offset 0x1ff after the header (0xc0) */
+         minor = buffer[0x1fe + 0xC0]; /* Offset 0x1fe after the header (0xc0) */
+         subminor = buffer[0x1fd + 0xC0]; /* Offset 0x1fe after the header (0xc0) */
+
+      } else {
+         return;
+      }
+
+      kfree(buffer);
+   }
+
+   ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4];
+   ha->bios_version[1] = '.';
+   ha->bios_version[2] = hexDigits[major & 0x0F];
+   ha->bios_version[3] = hexDigits[subminor];
+   ha->bios_version[4] = '.';
+   ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4];
+   ha->bios_version[6] = hexDigits[minor & 0x0F];
+   ha->bios_version[7] = 0;
+}
+
+/****************************************************************************/
+/*                                                                          */
 /* Routine Name: ips_hainit                                                 */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -2651,6 +3452,9 @@
       return (0);
    }
 
+   /* Identify this controller */
+   ips_identify_controller(ha);
+
    if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) {
       printk(KERN_WARNING "(%s%d) unable to read subsystem parameters.\n",
              ips_name, ha->host_num);
@@ -2799,30 +3603,47 @@
           (scb = ips_getscb(ha))) {
 
       IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
-      IPS_HA_UNLOCK(cpu_flags);
       item = ips_removeq_copp_head(&ha->copp_waitlist);
+      IPS_HA_UNLOCK(cpu_flags);
       scb->scsi_cmd = item->scsi_cmd;
       scb->sem = item->sem;
       kfree(item);
 
-      ret = ips_make_passthru(ha, scb->scsi_cmd, scb);
+      ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
 
       switch (ret) {
       case IPS_FAILURE:
          if (scb->scsi_cmd) {
+            scb->scsi_cmd->result = DID_ERROR << 16;
+
             /* raise the semaphore */
-            if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND)
-               up(scb->sem);
+            if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
+               u32 datasize;
 
-            scb->scsi_cmd->result = DID_ERROR << 16;
+               datasize = 0;
+               memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4);
+               up(scb->sem);
+            } else {
+               scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+            }
          }
+
          ips_freescb(ha, scb);
          break;
       case IPS_SUCCESS_IMM:
          if (scb->scsi_cmd) {
+            scb->scsi_cmd->result = DID_OK << 16;
+
             /* raise the semaphore */
-            if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND)
+            if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
+               u32 datasize;
+
+               datasize = 0;
+               memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4);
                up(scb->sem);
+            } else {
+               scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+            }
          }
 
          ips_freescb(ha, scb);
@@ -2891,10 +3712,12 @@
          continue;
       }
 
-      IPS_HA_UNLOCK(cpu_flags);
-
       q = p;
       SC = ips_removeq_wait(&ha->scb_waitlist, q);
+      if (SC == NULL)                    /* Should never happen, but good to check anyway */
+         continue;
+      
+      IPS_HA_UNLOCK(cpu_flags);          /* Unlock HA after command is taken off queue */
 
       SC->result = DID_OK;
       SC->host_scribble = NULL;
@@ -2932,27 +3755,37 @@
             scb->data_busaddr = VIRT_TO_BUS(sg[0].address);
             scb->sg_len = 0;
          } else {
+            /* Check for the first Element being bigger than MAX_XFER */
+            if (sg[0].length > ha->max_xfer) {
+               scb->sg_list[0].address = VIRT_TO_BUS(sg[0].address);
+               scb->sg_list[0].length = ha->max_xfer;
+               scb->data_len = ha->max_xfer;
+               scb->breakup = 0; 
+	            scb->sg_break=1;  
+               scb->sg_len = 1;
+	         }
+            else {
+               for (i = 0; i < SC->use_sg; i++) {
+                  scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
+                  scb->sg_list[i].length = sg[i].length;
+            
+                  if (scb->data_len + sg[i].length > ha->max_xfer) {
+                     /*
+                      * Data Breakup required
+                      */
+                     scb->breakup = i;
+                     break;
+                  }
 
-            for (i = 0; i < SC->use_sg; i++) {
-               scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
-               scb->sg_list[i].length = sg[i].length;
-
-               if (scb->data_len + sg[i].length > ha->max_xfer) {
-                  /*
-                   * Data Breakup required
-                   */
-                  scb->breakup = i;
-                  break;
+                  scb->data_len += sg[i].length;
                }
 
-               scb->data_len += sg[i].length;
+               if (!scb->breakup)
+                  scb->sg_len = SC->use_sg;
+               else
+                  scb->sg_len = scb->breakup;
             }
 
-            if (!scb->breakup)
-               scb->sg_len = SC->use_sg;
-            else
-               scb->sg_len = scb->breakup;
-
             scb->dcdb.transfer_length = scb->data_len;
             scb->data_busaddr = VIRT_TO_BUS(scb->sg_list);
          }
@@ -3590,9 +4423,9 @@
        * data and had to be broke up.  If so, queue
        * the rest of the data and continue.
        */
-      if (scb->breakup) {
-         /* we had a data breakup */
-         u16 bk_save;
+      if (scb->breakup || scb->sg_break) { 
+         /* We had a data breakup */
+         u8 bk_save;
 
          bk_save = scb->breakup;
          scb->breakup = 0;
@@ -3618,34 +4451,68 @@
                scb->dcdb.transfer_length = scb->data_len;
                scb->sg_len = 0;
             } else {
-               scb->data_len = 0;
-
-               for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) {
-                  scb->sg_list[i - bk_save].address = VIRT_TO_BUS(sg[i].address);
-                  scb->sg_list[i - bk_save].length = sg[i].length;
-
-                  if (scb->data_len + sg[i].length > ha->max_xfer) {
-                     /*
-                      * Data Breakup required
-                      */
-                     scb->breakup = i;
-                     break;
+               /* We're here because there was MORE than one s/g unit. */
+	            /* bk_save points to which sg unit to look at           */
+	            /* sg_break points to how far through this unit we are  */
+	            /* NOTE: We will not move from one sg to another here,  */
+               /*    just finish the one we are in.  Not the most      */
+               /*    efficient, but it keeps it from getting too hacky */
+
+		         /* IF sg_break is non-zero, then just work on this current sg piece, */
+               /* pointed to by bk_save                                             */
+               if (scb->sg_break) {
+                  scb->sg_len = 1;
+        			   scb->sg_list[0].address = VIRT_TO_BUS(sg[bk_save].address+ha->max_xfer*scb->sg_break);
+                  if (ha->max_xfer > sg[bk_save].length-ha->max_xfer * scb->sg_break) 
+                     scb->sg_list[0].length = sg[bk_save].length-ha->max_xfer * scb->sg_break;
+                  else 
+                     scb->sg_list[0].length = ha->max_xfer;
+                  scb->sg_break++;              /* MUST GO HERE for math below to work */
+			         scb->data_len = scb->sg_list[0].length;;
+
+		            if (sg[bk_save].length <= ha->max_xfer * scb->sg_break ) {
+                     scb->sg_break = 0;         /* No more work in this unit */
+                     if (( bk_save + 1 ) >= scb->scsi_cmd->use_sg) 
+                        scb->breakup = 0;
+                     else 
+                        scb->breakup = bk_save + 1;
                   }
+               } else {
+			         /* ( sg_break == 0 ), so this is our first look at a new sg piece */
+                  if (sg[bk_save].length > ha->max_xfer) {
+			            scb->sg_list[0].address = VIRT_TO_BUS(sg[bk_save].address);
+				         scb->sg_list[0].length = ha->max_xfer;
+				         scb->breakup = bk_save;
+				         scb->sg_break = 1;
+				         scb->data_len = ha->max_xfer;
+				         scb->sg_len = 1;
+ 	        		   } else {
+				         /* OK, the next sg is a short one, so loop until full */
+			            scb->data_len = 0;
+		     	         scb->sg_len = 0;
+      			      scb->sg_break = 0;
+                     /*   We're only doing full units here */
+				         for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) {
+					         scb->sg_list[i - bk_save].address = VIRT_TO_BUS(sg[i].address);
+				            scb->sg_list[i - bk_save].length = sg[i].length;
+                        if (scb->data_len + sg[i].length > ha->max_xfer) {
+					            scb->breakup = i;  /* sneaky, if not more work, than breakup is 0 */
+					            break;
+					         }
+					         scb->data_len += sg[i].length;
+					         scb->sg_len++;           /* only if we didn't get too big */
+		  		         }
+			         }
+		         }
 
-                  scb->data_len += sg[i].length;
-               }
-
-               if (!scb->breakup)
-                  scb->sg_len = scb->scsi_cmd->use_sg - bk_save;
-               else
-                  scb->sg_len = scb->breakup - bk_save;
-
+               /* Also, we need to be sure we don't queue work ( breakup != 0 )
+                  if no more sg units for next time */
                scb->dcdb.transfer_length = scb->data_len;
                scb->data_busaddr = VIRT_TO_BUS(scb->sg_list);
-           }
-        } else {
+            }
+         } else {
             /* Non S/G Request */
-            if (scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer)) {
+            if ((scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer)) > ha->max_xfer) {
                /* Further breakup required */
                scb->data_len = ha->max_xfer;
                scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + (bk_save * ha->max_xfer));
@@ -3882,7 +4749,9 @@
 static int
 ips_send_cmd(ips_ha_t *ha, ips_scb_t *scb) {
    int       ret;
-
+   char     *sp;
+   int       device_error;
+  
    METHOD_TRACE("ips_send_cmd", 1);
 
    ret = IPS_SUCCESS;
@@ -4068,7 +4937,20 @@
          break;
 
       default:
-         scb->scsi_cmd->result = DID_ERROR << 16;
+         /* Set the Return Info to appear like the Command was */
+         /* attempted, a Check Condition occurred, and Sense   */
+         /* Data indicating an Invalid CDB OpCode is returned. */
+         sp = (char *) scb->scsi_cmd->sense_buffer;
+         memset(sp, 0, sizeof(scb->scsi_cmd->sense_buffer));
+  
+         sp[0] = 0x70;             /* Error Code               */ 
+         sp[2] = ILLEGAL_REQUEST;  /* Sense Key 5 Illegal Req. */
+         sp[7] = 0x0A;             /* Additional Sense Length  */
+         sp[12] = 0x20;            /* ASC = Invalid OpCode     */
+         sp[13] = 0x00;            /* ASCQ                     */
+   
+         device_error = 2;         /* Indicate Check Condition */
+         scb->scsi_cmd->result = device_error | (DID_OK << 16);
          break;
       } /* end switch */
    } /* end if */
@@ -4083,6 +4965,13 @@
       else
          scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG;
 
+      /* If we already know the Device is Not there, no need to attempt a Command   */
+      /* This also protects an NT FailOver Controller from getting CDB's sent to it */
+      if ( ha->conf->dev[scb->bus-1][scb->target_id].ucState == 0 ) {
+         scb->scsi_cmd->result = DID_NO_CONNECT << 16;
+         return (IPS_SUCCESS_IMM); 
+      }
+
       ha->dcdb_active[scb->bus-1] |= (1 << scb->target_id);
       scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb);
       scb->cmd.dcdb.dcdb_address = VIRT_TO_BUS(&scb->dcdb);
@@ -4289,8 +5178,7 @@
       return (0);
    }
 
-   if (scb->target_id < ha->adapt->logical_drive_info.no_of_log_drive &&
-       ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_OFFLINE &&
+   if (ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_OFFLINE &&
        ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_FREE &&
        ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_CRS &&
        ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_SYS)
@@ -4510,9 +5398,10 @@
       }
 
       if (ha->ioctl_data) {
-         kfree(ha->ioctl_data);
+         free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
          ha->ioctl_data = NULL;
          ha->ioctl_datasize = 0;
+         ha->ioctl_order = 0;
       }
 
       if (ha->scbs) {
@@ -4552,9 +5441,10 @@
    METHOD_TRACE("ips_allocatescbs", 1);
 
    /* Allocate memory for the CCBs */
-   ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_ATOMIC|GFP_DMA);
-   if(ha->scbs == NULL)
-   	return 0;
+   ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_ATOMIC);
+   if (ha->scbs == NULL)
+    	return 0;
+
 
    memset(ha->scbs, 0, ha->max_cmds * sizeof(ips_scb_t));
 
@@ -4562,7 +5452,7 @@
       scb_p = &ha->scbs[i];
 
       /* allocate S/G list */
-      scb_p->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC|GFP_DMA);
+      scb_p->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC);
 
       if (! scb_p->sg_list)
          return (0);
@@ -4713,7 +5603,7 @@
 /****************************************************************************/
 static int
 ips_isinit_copperhead_memio(ips_ha_t *ha) {
-   u8 isr;
+   u8 isr=0;
    u8 scpr;
 
    METHOD_TRACE("ips_is_init_copperhead_memio", 1);
@@ -4903,7 +5793,7 @@
 /****************************************************************************/
 static int
 ips_init_copperhead_memio(ips_ha_t *ha) {
-   u8  Isr;
+   u8  Isr=0;
    u8  Cbsp;
    u8  PostByte[IPS_MAX_POST_BYTES];
    u8  ConfigByte[IPS_MAX_CONFIG_BYTES];
@@ -5372,7 +6262,7 @@
    TimeOut = 0;
 
    while ((val = inw(ha->io_addr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
-      UDELAY(1000);
+      udelay(1000);
 
       if (++TimeOut >= IPS_SEM_TIMEOUT) {
          if (!(val & IPS_BIT_START_STOP))
@@ -5435,7 +6325,7 @@
    TimeOut = 0;
 
    while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
-      UDELAY(1000);
+      udelay(1000);
 
       if (++TimeOut >= IPS_SEM_TIMEOUT) {
          if (!(val & IPS_BIT_START_STOP))
@@ -5674,7 +6564,7 @@
           */
 
          while (test_and_set_bit(IPS_IN_INTR, &ha->flags))
-            UDELAY(1000);
+            udelay(1000);
 
          (*ha->func.intr)(ha);
 
@@ -5700,7 +6590,7 @@
          spin_lock(&io_request_lock);
 
          while (test_and_set_bit(IPS_IN_INTR, &ha->flags))
-            UDELAY(1000);
+            udelay(1000);
 
          (*ha->func.intr)(ha);
 
@@ -5709,7 +6599,7 @@
          spin_unlock(&io_request_lock);
       }
 
-      UDELAY(1000); /* 1 milisecond */
+      udelay(1000); /* 1 milisecond */
       time--;
    }
 
@@ -5752,9 +6642,6 @@
              ha->nvram->bios_low[0], ha->nvram->bios_low[1],
              ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
 
-   /* save controller type */
-   ha->ad_type = ha->nvram->adapter_type;
-
    /* change values (as needed) */
    ha->nvram->operating_system = IPS_OS_LINUX;
    strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4);
@@ -5768,6 +6655,9 @@
       return (0);
    }
 
+   /* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */
+   ha->slot_num = ha->nvram->adapter_slot;
+
    return (1);
 }
 
@@ -6154,40 +7044,40 @@
 static int
 ips_erase_bios(ips_ha_t *ha) {
    int   timeout;
-   u8    status;
+   u8    status=0;
 
    METHOD_TRACE("ips_erase_bios", 1);
 
    /* Clear the status register */
    outl(0, ha->io_addr + IPS_REG_FLAP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    outb(0x50, ha->io_addr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    /* Erase Setup */
    outb(0x20, ha->io_addr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    /* Erase Confirm */
    outb(0xD0, ha->io_addr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    /* Erase Status */
    outb(0x70, ha->io_addr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    timeout = 80000; /* 80 seconds */
 
    while (timeout > 0) {
       if (ha->revision_id == IPS_REVID_TROMBONE64) {
          outl(0, ha->io_addr + IPS_REG_FLAP);
-         UDELAY(5); /* 5 us */
+         udelay(5); /* 5 us */
       }
 
       status = inb(ha->io_addr + IPS_REG_FLDP);
@@ -6206,14 +7096,14 @@
       /* try to suspend the erase */
       outb(0xB0, ha->io_addr + IPS_REG_FLDP);
       if (ha->revision_id == IPS_REVID_TROMBONE64)
-         UDELAY(5); /* 5 us */
+         udelay(5); /* 5 us */
 
       /* wait for 10 seconds */
       timeout = 10000;
       while (timeout > 0) {
          if (ha->revision_id == IPS_REVID_TROMBONE64) {
             outl(0, ha->io_addr + IPS_REG_FLAP);
-            UDELAY(5); /* 5 us */
+            udelay(5); /* 5 us */
          }
 
          status = inb(ha->io_addr + IPS_REG_FLDP);
@@ -6242,12 +7132,12 @@
    /* clear status */
    outb(0x50, ha->io_addr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    /* enable reads */
    outb(0xFF, ha->io_addr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    return (0);
 }
@@ -6270,33 +7160,33 @@
    /* Clear the status register */
    writel(0, ha->mem_ptr + IPS_REG_FLAP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    /* Erase Setup */
    writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    /* Erase Confirm */
    writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    /* Erase Status */
    writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    timeout = 80000; /* 80 seconds */
 
    while (timeout > 0) {
       if (ha->revision_id == IPS_REVID_TROMBONE64) {
          writel(0, ha->mem_ptr + IPS_REG_FLAP);
-         UDELAY(5); /* 5 us */
+         udelay(5); /* 5 us */
       }
 
       status = readb(ha->mem_ptr + IPS_REG_FLDP);
@@ -6315,14 +7205,14 @@
       /* try to suspend the erase */
       writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
       if (ha->revision_id == IPS_REVID_TROMBONE64)
-         UDELAY(5); /* 5 us */
+         udelay(5); /* 5 us */
 
       /* wait for 10 seconds */
       timeout = 10000;
       while (timeout > 0) {
          if (ha->revision_id == IPS_REVID_TROMBONE64) {
             writel(0, ha->mem_ptr + IPS_REG_FLAP);
-            UDELAY(5); /* 5 us */
+            udelay(5); /* 5 us */
          }
 
          status = readb(ha->mem_ptr + IPS_REG_FLDP);
@@ -6351,12 +7241,12 @@
    /* clear status */
    writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    /* enable reads */
    writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    return (0);
 }
@@ -6370,33 +7260,33 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_program_bios(ips_ha_t *ha, char *buffer, int buffersize) {
+ips_program_bios(ips_ha_t *ha, char *buffer, u32 buffersize, u32 offset) {
    int   i;
    int   timeout;
-   u8    status;
+   u8    status=0;
 
    METHOD_TRACE("ips_program_bios", 1);
 
    for (i = 0; i < buffersize; i++) {
       /* write a byte */
-      outl(i, ha->io_addr + IPS_REG_FLAP);
+      outl(i + offset, ha->io_addr + IPS_REG_FLAP);
       if (ha->revision_id == IPS_REVID_TROMBONE64)
-         UDELAY(5); /* 5 us */
+         udelay(5); /* 5 us */
 
       outb(0x40, ha->io_addr + IPS_REG_FLDP);
       if (ha->revision_id == IPS_REVID_TROMBONE64)
-         UDELAY(5); /* 5 us */
+         udelay(5); /* 5 us */
 
       outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
       if (ha->revision_id == IPS_REVID_TROMBONE64)
-         UDELAY(5); /* 5 us */
+         udelay(5); /* 5 us */
 
       /* wait up to one second */
       timeout = 1000;
       while (timeout > 0) {
          if (ha->revision_id == IPS_REVID_TROMBONE64) {
             outl(0, ha->io_addr + IPS_REG_FLAP);
-            UDELAY(5); /* 5 us */
+            udelay(5); /* 5 us */
          }
 
          status = inb(ha->io_addr + IPS_REG_FLDP);
@@ -6412,11 +7302,11 @@
          /* timeout error */
          outl(0, ha->io_addr + IPS_REG_FLAP);
          if (ha->revision_id == IPS_REVID_TROMBONE64)
-            UDELAY(5); /* 5 us */
+            udelay(5); /* 5 us */
 
          outb(0xFF, ha->io_addr + IPS_REG_FLDP);
          if (ha->revision_id == IPS_REVID_TROMBONE64)
-            UDELAY(5); /* 5 us */
+            udelay(5); /* 5 us */
 
          return (1);
       }
@@ -6426,11 +7316,11 @@
          /* programming error */
          outl(0, ha->io_addr + IPS_REG_FLAP);
          if (ha->revision_id == IPS_REVID_TROMBONE64)
-            UDELAY(5); /* 5 us */
+            udelay(5); /* 5 us */
 
          outb(0xFF, ha->io_addr + IPS_REG_FLDP);
          if (ha->revision_id == IPS_REVID_TROMBONE64)
-            UDELAY(5); /* 5 us */
+            udelay(5); /* 5 us */
 
          return (1);
       }
@@ -6439,11 +7329,11 @@
    /* Enable reading */
    outl(0, ha->io_addr + IPS_REG_FLAP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    outb(0xFF, ha->io_addr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    return (0);
 }
@@ -6457,33 +7347,33 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_program_bios_memio(ips_ha_t *ha, char *buffer, int buffersize) {
+ips_program_bios_memio(ips_ha_t *ha, char *buffer, u32 buffersize, u32 offset) {
    int   i;
    int   timeout;
-   u8    status;
+   u8    status=0;
 
    METHOD_TRACE("ips_program_bios_memio", 1);
 
    for (i = 0; i < buffersize; i++) {
       /* write a byte */
-      writel(i, ha->mem_ptr + IPS_REG_FLAP);
+      writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
       if (ha->revision_id == IPS_REVID_TROMBONE64)
-         UDELAY(5); /* 5 us */
+         udelay(5); /* 5 us */
 
       writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
       if (ha->revision_id == IPS_REVID_TROMBONE64)
-         UDELAY(5); /* 5 us */
+         udelay(5); /* 5 us */
 
       writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
       if (ha->revision_id == IPS_REVID_TROMBONE64)
-         UDELAY(5); /* 5 us */
+         udelay(5); /* 5 us */
 
       /* wait up to one second */
       timeout = 1000;
       while (timeout > 0) {
          if (ha->revision_id == IPS_REVID_TROMBONE64) {
             writel(0, ha->mem_ptr + IPS_REG_FLAP);
-            UDELAY(5); /* 5 us */
+            udelay(5); /* 5 us */
          }
 
          status = readb(ha->mem_ptr + IPS_REG_FLDP);
@@ -6499,11 +7389,11 @@
          /* timeout error */
          writel(0, ha->mem_ptr + IPS_REG_FLAP);
          if (ha->revision_id == IPS_REVID_TROMBONE64)
-            UDELAY(5); /* 5 us */
+            udelay(5); /* 5 us */
 
          writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
          if (ha->revision_id == IPS_REVID_TROMBONE64)
-            UDELAY(5); /* 5 us */
+            udelay(5); /* 5 us */
 
          return (1);
       }
@@ -6513,11 +7403,11 @@
          /* programming error */
          writel(0, ha->mem_ptr + IPS_REG_FLAP);
          if (ha->revision_id == IPS_REVID_TROMBONE64)
-            UDELAY(5); /* 5 us */
+            udelay(5); /* 5 us */
 
          writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
          if (ha->revision_id == IPS_REVID_TROMBONE64)
-            UDELAY(5); /* 5 us */
+            udelay(5); /* 5 us */
 
          return (1);
       }
@@ -6526,11 +7416,11 @@
    /* Enable reading */
    writel(0, ha->mem_ptr + IPS_REG_FLAP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    return (0);
 }
@@ -6544,7 +7434,7 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_verify_bios(ips_ha_t *ha, char *buffer, int buffersize) {
+ips_verify_bios(ips_ha_t *ha, char *buffer, u32 buffersize, u32 offset) {
    u8    checksum;
    int   i;
 
@@ -6553,23 +7443,23 @@
    /* test 1st byte */
    outl(0, ha->io_addr + IPS_REG_FLAP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
       return (1);
 
    outl(1, ha->io_addr + IPS_REG_FLAP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
    if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
       return (1);
 
    checksum = 0xff;
    for (i = 2; i < buffersize; i++) {
 
-      outl(i, ha->io_addr + IPS_REG_FLAP);
+      outl(i + offset, ha->io_addr + IPS_REG_FLAP);
       if (ha->revision_id == IPS_REVID_TROMBONE64)
-         UDELAY(5); /* 5 us */
+         udelay(5); /* 5 us */
 
       checksum = (u8) checksum + inb(ha->io_addr + IPS_REG_FLDP);
    }
@@ -6591,7 +7481,7 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_verify_bios_memio(ips_ha_t *ha, char *buffer, int buffersize) {
+ips_verify_bios_memio(ips_ha_t *ha, char *buffer, u32 buffersize, u32 offset) {
    u8    checksum;
    int   i;
 
@@ -6600,23 +7490,23 @@
    /* test 1st byte */
    writel(0, ha->mem_ptr + IPS_REG_FLAP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
 
    if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
       return (1);
 
    writel(1, ha->mem_ptr + IPS_REG_FLAP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
-      UDELAY(5); /* 5 us */
+      udelay(5); /* 5 us */
    if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
       return (1);
 
    checksum = 0xff;
    for (i = 2; i < buffersize; i++) {
 
-      writel(i, ha->mem_ptr + IPS_REG_FLAP);
+      writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
       if (ha->revision_id == IPS_REVID_TROMBONE64)
-         UDELAY(5); /* 5 us */
+         udelay(5); /* 5 us */
 
       checksum = (u8) checksum + readb(ha->mem_ptr + IPS_REG_FLDP);
    }
@@ -6631,7 +7521,6 @@
 
 static Scsi_Host_Template driver_template = IPS;
 #include "scsi_module.c"
-
 
 
 /*
diff -urN linux-2.4.5-pre3/drivers/scsi/ips.h linux/drivers/scsi/ips.h
--- linux-2.4.5-pre3/drivers/scsi/ips.h	Mon Dec 11 13:38:29 2000
+++ linux/drivers/scsi/ips.h	Mon Dec  3 22:44:23 2001
@@ -69,13 +69,13 @@
 
    #define IPS_HA(x)                   ((ips_ha_t *) x->hostdata)
    #define IPS_COMMAND_ID(ha, scb)     (int) (scb - ha->scbs)
-   #define IPS_IS_TROMBONE(ha)         (((ha->device_id == IPS_COPPERHEAD_DEVICEID) && \
+   #define IPS_IS_TROMBONE(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
                                          (ha->revision_id >= IPS_REVID_TROMBONE32) && \
                                          (ha->revision_id <= IPS_REVID_TROMBONE64)) ? 1 : 0)
-   #define IPS_IS_CLARINET(ha)         (((ha->device_id == IPS_COPPERHEAD_DEVICEID) && \
+   #define IPS_IS_CLARINET(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
                                          (ha->revision_id >= IPS_REVID_CLARINETP1) && \
                                          (ha->revision_id <= IPS_REVID_CLARINETP3)) ? 1 : 0)
-   #define IPS_IS_MORPHEUS(ha)         (ha->device_id == IPS_MORPHEUS_DEVICEID)
+   #define IPS_IS_MORPHEUS(ha)         (ha->device_id == IPS_DEVICEID_MORPHEUS)
    #define IPS_USE_I2O_DELIVER(ha)     ((IPS_IS_MORPHEUS(ha) || \
                                          (IPS_IS_TROMBONE(ha) && \
                                           (ips_force_i2o))) ? 1 : 0)
@@ -99,23 +99,11 @@
    #ifndef verify_area_20
       #define verify_area_20(t,a,sz)   (0) /* success */
    #endif
-
-   #ifndef PUT_USER
-      #define PUT_USER                 put_user
-   #endif
-
-   #ifndef __PUT_USER
-      #define __PUT_USER               __put_user
-   #endif
-
-   #ifndef GET_USER
-      #define GET_USER                 get_user
-   #endif
    
-   #ifndef __GET_USER
-      #define __GET_USER               __get_user
+   #ifndef DECLARE_MUTEX_LOCKED
+      #define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED;
    #endif
-   
+
    /*
     * Lock macros
     */
@@ -186,6 +174,7 @@
    #define IPS_CMD_DCDB_SG              0x84
    #define IPS_CMD_CONFIG_SYNC          0x58
    #define IPS_CMD_ERROR_TABLE          0x17
+   #define IPS_CMD_RW_BIOSFW            0x22
 
    /*
     * Adapter Equates
@@ -217,11 +206,16 @@
    #define IPS_INTR_HAL                 2
    #define IPS_ADAPTER_ID               0xF
    #define IPS_VENDORID                 0x1014
-   #define IPS_COPPERHEAD_DEVICEID      0x002E
-   #define IPS_MORPHEUS_DEVICEID        0x01BD
+   #define IPS_DEVICEID_COPPERHEAD      0x002E
+   #define IPS_DEVICEID_MORPHEUS        0x01BD
+   #define IPS_SUBDEVICEID_4M           0x01BE
+   #define IPS_SUBDEVICEID_4L           0x01BF
+   #define IPS_SUBDEVICEID_4MX          0x0208
+   #define IPS_SUBDEVICEID_4LX          0x020E
    #define IPS_IOCTL_SIZE               8192
    #define IPS_STATUS_SIZE              4
    #define IPS_STATUS_Q_SIZE            (IPS_MAX_CMDS+1) * IPS_STATUS_SIZE
+   #define IPS_IMAGE_SIZE               500 * 1024
    #define IPS_MEMMAP_SIZE              128
    #define IPS_ONE_MSEC                 1
    #define IPS_ONE_SEC                  1000
@@ -285,6 +279,21 @@
    #define IPS_REVID_TROMBONE64         0x10
 
    /*
+    * NVRAM Page 5 Adapter Defines
+    */
+   #define IPS_ADTYPE_SERVERAID         0x01
+   #define IPS_ADTYPE_SERVERAID2        0x02
+   #define IPS_ADTYPE_NAVAJO            0x03
+   #define IPS_ADTYPE_KIOWA             0x04
+   #define IPS_ADTYPE_SERVERAID3        0x05
+   #define IPS_ADTYPE_SERVERAID3L       0x06
+   #define IPS_ADTYPE_SERVERAID4H       0x07
+   #define IPS_ADTYPE_SERVERAID4M       0x08
+   #define IPS_ADTYPE_SERVERAID4L       0x09
+   #define IPS_ADTYPE_SERVERAID4MX      0x0A
+   #define IPS_ADTYPE_SERVERAID4LX      0x0B
+
+   /*
     * Adapter Command/Status Packet Definitions
     */
    #define IPS_SUCCESS                  0x01 /* Successfully completed       */
@@ -538,17 +547,41 @@
    u8     reserved2;
 } IPS_FFDC_CMD, *PIPS_FFDC_CMD;
 
+typedef struct {
+   u8     op_code;
+   u8     command_id;
+   u8     type;
+   u8     direction;
+   u32    count;
+   u32    buffer_addr;
+   u8     total_packets;
+   u8     packet_num;
+   u16    reserved;
+} IPS_FLASHFW_CMD, *PIPS_FLASHFW_CMD;
+
+typedef struct {
+   u8     op_code;
+   u8     command_id;
+   u8     type;
+   u8     direction;
+   u32    count;
+   u32    buffer_addr;
+   u32    offset;
+} IPS_FLASHBIOS_CMD, *PIPS_FLASHBIOS_CMD;
+
 typedef union {
-   IPS_IO_CMD        basic_io;
-   IPS_LD_CMD        logical_info;
-   IPS_IOCTL_CMD     ioctl_info;
-   IPS_DCDB_CMD      dcdb;
-   IPS_CS_CMD        config_sync;
-   IPS_US_CMD        unlock_stripe;
-   IPS_FC_CMD        flush_cache;
-   IPS_STATUS_CMD    status;
-   IPS_NVRAM_CMD     nvram;
-   IPS_FFDC_CMD      ffdc;
+   IPS_IO_CMD         basic_io;
+   IPS_LD_CMD         logical_info;
+   IPS_IOCTL_CMD      ioctl_info;
+   IPS_DCDB_CMD       dcdb;
+   IPS_CS_CMD         config_sync;
+   IPS_US_CMD         unlock_stripe;
+   IPS_FC_CMD         flush_cache;
+   IPS_STATUS_CMD     status;
+   IPS_NVRAM_CMD      nvram;
+   IPS_FFDC_CMD       ffdc;
+   IPS_FLASHFW_CMD    flashfw;
+   IPS_FLASHBIOS_CMD  flashbios;
 } IPS_HOST_COMMAND, *PIPS_HOST_COMMAND;
 
 typedef struct {
@@ -839,6 +872,19 @@
    int   option_value;
 } IPS_OPTION;
 
+typedef struct {
+   void             *userbuffer;
+   u32               usersize;
+   void             *kernbuffer;
+   u32               kernsize;
+   void             *ha;
+   void             *SC;
+   void             *pt;
+   struct semaphore *sem;
+   u32               offset;
+   u32               retcode;
+} IPS_FLASH_DATA;
+
 /*
  * Status Info
  */
@@ -893,8 +939,8 @@
    int  (*isintr)(struct ips_ha *);
    int  (*init)(struct ips_ha *);
    int  (*erasebios)(struct ips_ha *);
-   int  (*programbios)(struct ips_ha *, char *, int);
-   int  (*verifybios)(struct ips_ha *, char *, int);
+   int  (*programbios)(struct ips_ha *, char *, u32, u32);
+   int  (*verifybios)(struct ips_ha *, char *, u32, u32);
    u32  (*statupd)(struct ips_ha *);
    void (*statinit)(struct ips_ha *);
    void (*intr)(struct ips_ha *);
@@ -936,7 +982,11 @@
    u32                last_ffdc;          /* last time we sent ffdc info*/
    u8                 revision_id;        /* Revision level             */
    u16                device_id;          /* PCI device ID              */
-   u8                 reserved;
+   u8                 slot_num;           /* PCI Slot Number            */
+   u16                subdevice_id;       /* Subsystem device ID        */
+   u8                 ioctl_order;        /* Number of pages in ioctl   */
+   u8                 reserved2;          /* Empty                      */
+   u8                 bios_version[8];    /* BIOS Revision              */
    u32                mem_addr;           /* Memory mapped address      */
    u32                io_len;             /* Size of IO Address         */
    u32                mem_len;            /* Size of memory address     */
@@ -947,6 +997,9 @@
    spinlock_t         scb_lock;
    spinlock_t         copp_lock;
    spinlock_t         ips_lock;
+   char              *save_ioctl_data;    /* Save Area for ioctl_data   */
+   u8                 save_ioctl_order;   /* Save Area for ioctl_order  */
+   u32                save_ioctl_datasize;/* Save Area for ioctl_datasize */
 } ips_ha_t;
 
 typedef void (*ips_scb_callback) (ips_ha_t *, struct ips_scb *);
@@ -966,7 +1019,8 @@
    u32               timeout;
    u8                basic_status;
    u8                extended_status;
-   u16               breakup;
+   u8                breakup;
+   u8                sg_break;
    u32               data_len;
    u32               sg_len;
    u32               flags;
diff -urN linux-2.4.5-pre3/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c
--- linux-2.4.5-pre3/drivers/scsi/scsi_proc.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/scsi/scsi_proc.c	Mon Dec  3 22:44:23 2001
@@ -104,8 +104,11 @@
 
 	if (!(page = (char *) __get_free_page(GFP_KERNEL)))
 		return -ENOMEM;
-	copy_from_user(page, buf, count);
-	page[count] = '\0';
+	if(copy_from_user(page, buf, count))
+	{
+		free_page((ulong) page);
+		return -EFAULT;
+	}
 
 	if (hpnt->hostt->proc_info == NULL)
 		ret = -ENOSYS;
diff -urN linux-2.4.5-pre3/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- linux-2.4.5-pre3/drivers/scsi/u14-34f.c	Sun Feb  4 10:05:30 2001
+++ linux/drivers/scsi/u14-34f.c	Mon Dec  3 22:44:23 2001
@@ -1,6 +1,9 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *       1 May 2001 Rev. 6.05 for linux 2.4.4
+ *        + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d)
+ *
  *      25 Jan 2001 Rev. 6.03 for linux 2.4.0
  *        + "check_region" call replaced by "request_region".
  *
@@ -1005,7 +1008,7 @@
    static const unsigned char data_out_cmds[] = {
       0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
       0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
-      0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b
+      0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d
       };
 
    static const unsigned char data_none_cmds[] = {
diff -urN linux-2.4.5-pre3/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h
--- linux-2.4.5-pre3/drivers/scsi/u14-34f.h	Sun Feb  4 10:05:30 2001
+++ linux/drivers/scsi/u14-34f.h	Mon Dec  3 22:44:23 2001
@@ -13,7 +13,7 @@
 int u14_34f_reset(Scsi_Cmnd *);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "6.03.00"
+#define U14_34F_VERSION "6.05.00"
 
 #define ULTRASTOR_14_34F {                                                   \
                 name:         "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
diff -urN linux-2.4.5-pre3/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c
--- linux-2.4.5-pre3/drivers/sound/cs46xx.c	Thu Apr 12 12:16:36 2001
+++ linux/drivers/sound/cs46xx.c	Mon Dec  3 22:44:23 2001
@@ -47,6 +47,8 @@
  *	20010117-tw	2.4.0 pci cleanup, wrapper code for 2.2.16-2.4.0
  *	20010118-tw	basic PM support for 2.2.16+ and 2.4.0/2.4.2.
  *	20010228-dh	patch from David Huggins - cs_update_ptr recursion.
+ *	20010409-tw	add hercules game theatre XP amp code.
+ *	20010420-tw	cleanup powerdown/up code.
  *
  *	Status:
  *	Playback/Capture supported from 8k-48k.
@@ -56,9 +58,9 @@
  *	be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro
  *	definition.
  *
- *      Hercules Game Pro XP - the EGPIO2 pin controls the external Amp,
- *	but the static image can not modify the EGPIO pins, so we can not
- *	turn on the external amp.
+ *      Hercules Game Theatre XP - the EGPIO2 pin controls the external Amp,
+ *	so, use the drain/polarity to enable.  
+ *	hercules_egpio_disable set to 1, will force a 0 to EGPIODR.
  *
  *	VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control
  *	the external amplifier for the "back" speakers, since we do not
@@ -109,6 +111,11 @@
 #define CS_TRUE 	1
 #define CS_FALSE 	0
 
+#define CS_INC_USE_COUNT(m) (atomic_inc(m))
+#define CS_DEC_USE_COUNT(m) (atomic_dec(m))
+#define CS_DEC_AND_TEST(m) (atomic_dec_and_test(m))
+#define CS_IN_USE(m) (atomic_read(m) != 0)
+
 #define CS_DBGBREAKPOINT {__asm__("INT $3");}
 /*
  *	CS461x definitions
@@ -167,6 +174,8 @@
 static unsigned long cs_debugmask=CS_INIT | CS_ERROR;	/* use CS_DBGOUT with various mask values */
 MODULE_PARM(cs_debugmask, "i");
 #endif
+static unsigned long hercules_egpio_disable=0;  /* if non-zero set all EGPIO to 0 */
+MODULE_PARM(hercules_egpio_disable, "i");
 static unsigned long initdelay=700;  /* PM delay in millisecs */
 MODULE_PARM(initdelay, "i");
 static unsigned long powerdown=1;  /* turn on/off powerdown processing in driver */
@@ -189,7 +198,7 @@
 };
 
 #define CS46XX_MAJOR_VERSION "1"
-#define CS46XX_MINOR_VERSION "22"
+#define CS46XX_MINOR_VERSION "26"
 
 #ifdef __ia64__
 #define CS46XX_ARCH	     	"64"	//architecture key
@@ -287,6 +296,9 @@
 	   so we use a single per card lock */
 	spinlock_t lock;
 
+	/* mixer use count */
+	atomic_t mixer_use_cnt;
+
 	/* PCI device stuff */
 	struct pci_dev * pci_dev;
 	struct list_head list;
@@ -358,6 +370,7 @@
 static int cs_hardware_init(struct cs_card *card);
 static int cs46xx_powerup(struct cs_card *card, unsigned int type);
 static int cs461x_powerdown(struct cs_card *card, unsigned int type);
+static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type);
 
 static inline unsigned ld2(unsigned int x)
 {
@@ -667,6 +680,41 @@
 			dmabuf->divisor) );
 }
 
+/*
+* mute some of the more prevalent registers to avoid popping.
+*/
+static void cs_mute(struct cs_card *card, int state) 
+{
+	struct ac97_codec *dev=card->ac97_codec[0];
+
+	if(state == CS_TRUE)
+	{
+	/*
+	* fix pops when powering up on thinkpads
+	*/
+		card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev, 
+				(u8)BA0_AC97_MASTER_VOLUME); 
+		card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev, 
+				(u8)BA0_AC97_HEADPHONE_VOLUME); 
+		card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev, 
+				(u8)BA0_AC97_MASTER_VOLUME_MONO); 
+		card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev, 
+				(u8)BA0_AC97_PCM_OUT_VOLUME);
+			
+		cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
+		cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
+		cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
+		cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
+	}
+	else
+	{
+		cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, card->pm.u32AC97_master_volume);
+		cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, card->pm.u32AC97_headphone_volume);
+		cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, card->pm.u32AC97_master_volume_mono);
+		cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, card->pm.u32AC97_pcm_out_volume);
+	}
+}
+
 /* set playback sample rate */
 static unsigned int cs_set_dac_rate(struct cs_state * state, unsigned int rate)
 {	
@@ -1386,12 +1434,17 @@
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct dmabuf *dmabuf = &state->dmabuf;
+	struct cs_card *card=state->card;
 	unsigned long flags;
 	unsigned long tmo;
 	int count;
 
+	CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()+ \n"));
 	if (dmabuf->mapped || !dmabuf->ready)
+	{
+		CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- 0, not ready\n"));
 		return 0;
+	}
 
 	add_wait_queue(&dmabuf->wait, &wait);
 	for (;;) {
@@ -1427,8 +1480,18 @@
 	remove_wait_queue(&dmabuf->wait, &wait);
 	current->state = TASK_RUNNING;
 	if (signal_pending(current))
+	{
+		CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- -ERESTARTSYS\n"));
+		/*
+		* set to silence and let that clear the fifos.
+		*/
+		memset(dmabuf->rawbuf, (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
+		       dmabuf->dmasize);
+		cs461x_clear_serial_FIFOs(card, CS_TYPE_DAC);
 		return -ERESTARTSYS;
+	}
 
+	CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- 0\n"));
 	return 0;
 }
 
@@ -1524,7 +1587,7 @@
 				}
 
 				if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
-					CS_DBGOUT(CS_ERROR, 2, printk(
+					CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
 					  "cs46xx: ERROR DAC count<0 or count > dmasize (%d)\n",
 					  	dmabuf->count));
 					/* 
@@ -1584,7 +1647,7 @@
 	struct cs_state *playstate = card->channel[1].state;
 	u32 status;
 
-	CS_DBGOUT(CS_INTERRUPT, 4, printk("cs46xx: cs_interrupt()+ \n"));
+	CS_DBGOUT(CS_INTERRUPT, 9, printk("cs46xx: cs_interrupt()+ \n"));
 
 	spin_lock(&card->lock);
 
@@ -1614,7 +1677,7 @@
  	/* clear 'em */
 	cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV);
 	spin_unlock(&card->lock);
-	CS_DBGOUT(CS_INTERRUPT, 4, printk("cs46xx: cs_interrupt()- \n"));
+	CS_DBGOUT(CS_INTERRUPT, 9, printk("cs46xx: cs_interrupt()- \n"));
 }
 
 
@@ -2298,7 +2361,7 @@
 		if(state)
 		{
 			CS_DBGOUT(CS_OPEN, 2, printk(
-			  "cs46xx: cs_mmap() VM_WRITE - state CS_TRUE prog_dmabuf DAC\n") );
+			  "cs46xx: cs_mmap() VM_WRITE - state TRUE prog_dmabuf DAC\n") );
 			if ((ret = prog_dmabuf(state)) != 0)
 				return ret;
 		}
@@ -2307,7 +2370,7 @@
 		if(state)
 		{
 			CS_DBGOUT(CS_OPEN, 2, printk(
-			  "cs46xx: cs_mmap() VM_READ - state CS_TRUE prog_dmabuf ADC\n") );
+			  "cs46xx: cs_mmap() VM_READ - state TRUE prog_dmabuf ADC\n") );
 			if ((ret = prog_dmabuf(state)) != 0)
 				return ret;
 		}
@@ -2955,31 +3018,36 @@
 	}
 }
 
+		       
 /*
- *	For the VTB Santa Cruz card, the Secondary Codec must have the 
- *	GPIO pins 7 and 8 manipulated, not the Primary codec.
- *	Currently, only the primary codec is supported, so the following
- *	code will not function.  Additionally, slot 12 must be setup
- *	to allow proper output for 7 and 8 to occur (trw).
+ *	Game Theatre XP card - EGPIO[2] is used to enable the external amp.
  */
  
-static void amp_voyetra_4294(struct cs_card *card, int change)
+static void amp_hercules(struct cs_card *card, int change)
 {
-	struct ac97_codec *c=card->ac97_codec[0];
-	
+	int old=card->amplifier;
+	if(!card)
+	{
+		CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO 
+			"cs46xx: amp_hercules() called before initialized.\n"));
+		return;
+	}
 	card->amplifier+=change;
-
-	if(card->amplifier)
+	if( (card->amplifier && !old) && !(hercules_egpio_disable))
 	{
-		/* Switch the GPIO pins 7 and 8 to open drain */
-		cs_ac97_set(c, 0x4C, cs_ac97_get(c, 0x4C) & 0xFE7F);
-		cs_ac97_set(c, 0x4E, cs_ac97_get(c, 0x4E) | 0x0180);
-		/* Now wake the AMP (this might be backwards) */
-		cs_ac97_set(c, 0x54, cs_ac97_get(c, 0x54) & ~0x0180);
+		CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO 
+			"cs46xx: amp_hercules() external amp enabled\n"));
+		cs461x_pokeBA0(card, BA0_EGPIODR, 
+			EGPIODR_GPOE2);     /* enable EGPIO2 output */
+		cs461x_pokeBA0(card, BA0_EGPIOPTR, 
+			EGPIOPTR_GPPT2);   /* open-drain on output */
 	}
-	else
+	else if(old && !card->amplifier)
 	{
-		cs_ac97_set(c, 0x54, cs_ac97_get(c, 0x54) | 0x0180);
+		CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO 
+			"cs46xx: amp_hercules() external amp disabled\n"));
+		cs461x_pokeBA0(card, BA0_EGPIODR, 0); /* disable */
+		cs461x_pokeBA0(card, BA0_EGPIOPTR, 0); /* disable */
 	}
 }
 
@@ -3016,7 +3084,7 @@
 	/* Flip CLKRUN off while running */
 	if(!card->active && old)
 	{
-		CS_DBGOUT(CS_PARMS , 9, printk(
+		CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO
 			"cs46xx: clkrun() enable clkrun - change=%d active=%d\n",
 				change,card->active));
 		outw(control|0x2000, port+0x10);
@@ -3026,7 +3094,7 @@
 	/*
 	* sometimes on a resume the bit is set, so always reset the bit.
 	*/
-		CS_DBGOUT(CS_PARMS , 9, printk(
+		CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO
 			"cs46xx: clkrun() disable clkrun - change=%d active=%d\n",
 				change,card->active));
 		outw(control&~0x2000, port+0x10);
@@ -3404,7 +3472,7 @@
 			"cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp) );
 	}
 
-	CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_suspend()-\n"));
+	CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()-\n"));
 }
 
 /****************************************************************************
@@ -3417,7 +3485,7 @@
 	int Count,i;
 	struct ac97_codec *dev=card->ac97_codec[0];
 
-	CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_resume()+\n"));
+	CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()+\n"));
 
 /*
 * First, we restore the state of the general purpose register.  This
@@ -3458,7 +3526,7 @@
 	if(card->amp_init)
 		card->amp_init(card);
         
-	CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_resume()-\n"));
+	CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()-\n"));
 }
 
 
@@ -3521,7 +3589,7 @@
 {
 	unsigned int tmp;
 	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, 
-		printk("cs46xx: cs46xx_suspend()+ flags=%d s=0x%x\n",
+		printk("cs46xx: cs46xx_suspend()+ flags=0x%x s=0x%x\n",
 			(unsigned)card->pm.flags,(unsigned)card));
 /*
 * check the current state, only suspend if IDLE
@@ -3604,7 +3672,7 @@
 	printpm(card);
 
 	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, 
-		printk("cs46xx: cs46xx_suspend()- flags=%d\n",
+		printk("cs46xx: cs46xx_suspend()- flags=0x%x\n",
 			(unsigned)card->pm.flags));
 	return 0;
 }
@@ -3614,7 +3682,7 @@
 	int i;
 
 	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, 
-		printk( "cs46xx: cs46xx_resume()+ flags=%d\n",
+		printk( "cs46xx: cs46xx_resume()+ flags=0x%x\n",
 			(unsigned)card->pm.flags));
 	if(!(card->pm.flags & CS46XX_PM_SUSPENDED))
 	{
@@ -3654,7 +3722,7 @@
 
 	card->active_ctrl(card, -1);
 
-	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, printk("cs46xx: cs46xx_resume()- flags=%d\n",
+	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, printk("cs46xx: cs46xx_resume()- flags=0x%x\n",
 		(unsigned)card->pm.flags));
 	return 0;
 }
@@ -3919,12 +3987,17 @@
 	file->private_data = card->ac97_codec[i];
 
 	card->active_ctrl(card,1);
-	if( (tmp = cs46xx_powerup(card, CS_POWER_MIXVON )) )
+	if(!CS_IN_USE(&card->mixer_use_cnt))
 	{
-		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
-			"cs46xx: cs_open_mixdev() powerup failure (0x%x)\n",tmp) );
-		return -EIO;
+		if( (tmp = cs46xx_powerup(card, CS_POWER_MIXVON )) )
+		{
+			CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
+				"cs46xx: cs_open_mixdev() powerup failure (0x%x)\n",tmp) );
+			return -EIO;
+		}
 	}
+	card->amplifier_ctrl(card, 1);
+	CS_INC_USE_COUNT(&card->mixer_use_cnt);
 	MOD_INC_USE_COUNT;
 	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
 		  printk(KERN_INFO "cs46xx: cs_open_mixdev()- 0\n"));
@@ -3938,8 +4011,9 @@
 	struct list_head *entry;
 	int i;
 	unsigned int tmp;
-	
-	
+
+	CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
+		  printk(KERN_INFO "cs46xx: cs_release_mixdev()+\n"));
 	list_for_each(entry, &cs46xx_devs)
 	{
 		card = list_entry(entry, struct cs_card, list);
@@ -3955,14 +4029,26 @@
 		return -ENODEV;
 	}
 match:
+	card->active_ctrl(card, -1);
+	card->amplifier_ctrl(card, -1);
+	MOD_DEC_USE_COUNT;
+	if(!CS_DEC_AND_TEST(&card->mixer_use_cnt))
+	{
+		CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
+			  printk(KERN_INFO "cs46xx: cs_release_mixdev()- no powerdown, usecnt>0\n"));
+		return 0;
+	}
+/*
+* ok, no outstanding mixer opens, so powerdown.
+*/
 	if( (tmp = cs461x_powerdown(card, CS_POWER_MIXVON )) )
 	{
 		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
 			"cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n",tmp) );
 		return -EIO;
 	}
-	card->active_ctrl(card, -1);
-	MOD_DEC_USE_COUNT;
+	CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
+		  printk(KERN_INFO "cs46xx: cs_release_mixdev()- 0\n"));
 	return 0;
 }
 
@@ -4027,7 +4113,7 @@
 			else
 			{
 				CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
-				    "cs4281: mixer_ioctl(): invalid APM cmd (%d)\n",
+				    "cs46xx: mixer_ioctl(): invalid APM cmd (%d)\n",
 					val));
 			}
 			return 0;
@@ -4181,9 +4267,9 @@
 	cs461x_poke(card, BA1_FRMT, 0xadf);
 }
 
-static void cs461x_clear_serial_FIFOs(struct cs_card *card)
+static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type)
 {
-	int idx, loop, powerdown = 0;
+	int idx, loop, startfifo=0, endfifo=0, powerdown1 = 0;
 	unsigned int tmp;
 
 	/*
@@ -4192,7 +4278,7 @@
 	 */
 	if (!((tmp = cs461x_peekBA0(card, BA0_CLKCR1)) & CLKCR1_SWCE)) {
 		cs461x_pokeBA0(card, BA0_CLKCR1, tmp | CLKCR1_SWCE);
-		powerdown = 1;
+		powerdown1 = 1;
 	}
 
 	/*
@@ -4203,9 +4289,25 @@
 	cs461x_pokeBA0(card, BA0_SERBWP, 0);
 
 	/*
-	 *  Fill all 256 sample FIFO locations.
+	* Check for which FIFO locations to clear, if we are currently
+	* playing or capturing then we don't want to put in 128 bytes of
+	* "noise".
 	 */
-	for (idx = 0; idx < 256; idx++) {
+	if(type & CS_TYPE_DAC)
+	{
+		startfifo = 128;
+		endfifo = 256;
+	}
+	if(type & CS_TYPE_ADC)
+	{
+		startfifo = 0;
+		if(!endfifo)
+			endfifo = 128;
+	}
+	/*
+	 *  Fill sample FIFO locations (256 locations total).
+	 */
+	for (idx = startfifo; idx < endfifo; idx++) {
 		/*
 		 *  Make sure the previous FIFO write operation has completed.
 		 */
@@ -4215,7 +4317,7 @@
 				break;
 		}
 		if (cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY) {
-			if (powerdown)
+			if (powerdown1)
 				cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
 		}
 		/*
@@ -4231,7 +4333,7 @@
 	 *  Now, if we powered up the devices, then power them back down again.
 	 *  This is kinda ugly, but should never happen.
 	 */
-	if (powerdown)
+	if (powerdown1)
 		cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
 }
 
@@ -4268,6 +4370,9 @@
 			"cs46xx: cs461x_powerdown()- 0  unable to powerdown. tmp=0x%x\n",tmp));
 		return 0;
 	}
+
+	cs_mute(card, CS_TRUE);
+
 	/*
 	 *  Power down indicated areas.
 	 */
@@ -4443,6 +4548,7 @@
 		}
 	}
 	tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+	cs_mute(card, CS_FALSE);
 	CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO 
 		"cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp));
 	return 0;
@@ -4462,6 +4568,8 @@
 		type |= CS_POWER_MIXVOFF;
 	if(type & (CS_POWER_DAC | CS_POWER_ADC))
 		type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF;
+
+	cs_mute(card, CS_TRUE);
 	/*
 	 *  Power up indicated areas.
 	 */
@@ -4637,6 +4745,7 @@
 		}
 	}
 	tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+	cs_mute(card, CS_FALSE);
 	CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO 
 		"cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp));
 	return 0;
@@ -4741,7 +4850,6 @@
 	*/
 	if(!(card->pm.flags & CS46XX_PM_IDLE))
 		mdelay(initdelay);
-
 	/*
 	 *  Write the selected clock control setup to the hardware.  Do not turn on
 	 *  SWCE yet (if requested), so that the devices clocked by the output of
@@ -4770,7 +4878,7 @@
 	/*
 	 *  Fill the serial port FIFOs with silence.
 	 */
-	cs461x_clear_serial_FIFOs(card);
+	cs461x_clear_serial_FIFOs(card,CS_TYPE_DAC | CS_TYPE_ADC);
 
 	/*
 	 *  Set the serial port FIFO pointer to the first sample in the FIFO.
@@ -4951,12 +5059,25 @@
 	 */
 	if(card->pm.flags & CS46XX_PM_IDLE)
 	{
-		if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
-				CS_POWER_MIXVON )) )
+		if(!powerdown)
 		{
-			CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
-				"cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
-			return -EIO;
+			if( (tmp = cs46xx_powerup(card, CS_POWER_DAC | CS_POWER_ADC |
+					CS_POWER_MIXVON )) )
+			{
+				CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
+					"cs46xx: cs461x_powerup() failure (0x%x)\n",tmp) );
+				return -EIO;
+			}
+		}
+		else
+		{
+			if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
+					CS_POWER_MIXVON )) )
+			{
+				CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
+					"cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
+				return -EIO;
+			}
 		}
 	}
 	CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO 
@@ -4964,11 +5085,9 @@
 	return 0;
 }
 
-
 /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
    until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
    
-   
 /*
  *	Card subid table
  */
@@ -4987,8 +5106,12 @@
 	{0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL, NULL},
 	{0x5053, 0x3357, "Voyetra", amp_voyetra, NULL, NULL},
 	{0x1071, 0x6003, "Mitac MI6020/21", amp_voyetra, NULL, NULL},
-	{0x14AF, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL},
-	{0x1681, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL},
+	{0x14AF, 0x0050, "Hercules Game Theatre XP", amp_hercules, NULL, NULL},
+	{0x1681, 0x0050, "Hercules Game Theatre XP", amp_hercules, NULL, NULL},
+	{0x1681, 0x0051, "Hercules Game Theatre XP", amp_hercules, NULL, NULL},
+	{0x1681, 0x0052, "Hercules Game Theatre XP", amp_hercules, NULL, NULL},
+	{0x1681, 0x0053, "Hercules Game Theatre XP", amp_hercules, NULL, NULL},
+	{0x1681, 0x0054, "Hercules Game Theatre XP", amp_hercules, NULL, NULL},
 	/* Not sure if the 570 needs the clkrun hack */
 	{PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, NULL, clkrun_hack},
 	{PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, NULL, clkrun_hack},
@@ -5016,6 +5139,11 @@
 	CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
 		  printk(KERN_INFO "cs46xx: probe()+\n"));
 
+	if (pci_enable_device(pci_dev)) {
+		CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
+			 "cs46xx: pci_enable_device() failed\n"));
+		return -1;
+	}
 	if (!RSRCISMEMORYREGION(pci_dev, 0) ||
 	    !RSRCISMEMORYREGION(pci_dev, 1)) {
 		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
@@ -5042,12 +5170,6 @@
 		return -ENOMEM;
 	}
 	memset(card, 0, sizeof(*card));
-
-	if (pci_enable_device(pci_dev)) {
-		CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
-			 "cs46xx: pci_enable_device() failed\n"));
-		goto fail2;
-	}
 	card->ba0_addr = RSRCADDRESS(pci_dev, 0);
 	card->ba1_addr = RSRCADDRESS(pci_dev, 1);
 	card->pci_dev = pci_dev;
@@ -5096,7 +5218,7 @@
 		card->amplifier_ctrl = amp_none;
 		card->active_ctrl = clkrun_hack;
 	}		
-		       
+
 	if (external_amp == 1)
 	{
 		printk(KERN_INFO "cs46xx: Crystal EAPD support forced on.\n");
@@ -5120,7 +5242,7 @@
 	card->ba1.name.reg = ioremap_nocache(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
 	
 	CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO 
-		"cs46xx: card->ba0=0x%.08x\n",(unsigned)card->ba0) );
+		"cs46xx: card=0x%x card->ba0=0x%.08x\n",(unsigned)card,(unsigned)card->ba0) );
 	CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO 
 		"cs46xx: card->ba1=0x%.08x 0x%.08x 0x%.08x 0x%.08x\n",
 			(unsigned)card->ba1.name.data0,
@@ -5319,9 +5441,9 @@
 	unregister_sound_dsp(card->dev_audio);
         if(card->dev_midi)
                 unregister_sound_midi(card->dev_midi);
+	list_del(&card->list);
 	kfree(card);
 	PCI_SET_DRIVER_DATA(pci_dev,NULL);
-	list_del(&card->list);
 
 	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
 		 "cs46xx: cs46xx_remove()-: remove successful\n"));
@@ -5329,8 +5451,8 @@
 
 enum {
 	CS46XX_4610 = 0,
-	CS46XX_4612,  	/* same as 4624 */
-	CS46XX_4615,  	/* same as 4630 */
+	CS46XX_4612,  	/* same as 4630 */
+	CS46XX_4615,  	/* same as 4624 */
 };
 
 static struct pci_device_id cs46xx_pci_tbl[] __devinitdata = {
diff -urN linux-2.4.5-pre3/drivers/sound/emu10k1/cardwo.c linux/drivers/sound/emu10k1/cardwo.c
--- linux-2.4.5-pre3/drivers/sound/emu10k1/cardwo.c	Mon Aug 14 08:32:48 2000
+++ linux/drivers/sound/emu10k1/cardwo.c	Mon Dec  3 22:44:23 2001
@@ -87,7 +87,8 @@
 
 			pageindex = buffer->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
 
-			((u32 *) card->virtualpagetable.addr)[pageindex] = (busaddx * 2) | pageindex;
+			((u32 *) card->virtualpagetable.addr)[pageindex] =
+            cpu_to_le32((busaddx * 2) | pageindex);
 		}
 	}
 
diff -urN linux-2.4.5-pre3/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c
--- linux-2.4.5-pre3/drivers/sound/emu10k1/main.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/sound/emu10k1/main.c	Mon Dec  3 22:44:23 2001
@@ -475,7 +475,8 @@
 	}
 
 	for (pagecount = 0; pagecount < MAXPAGES; pagecount++)
-		((u32 *) card->virtualpagetable.addr)[pagecount] = (card->silentpage.dma_handle * 2) | pagecount;
+		((u32 *) card->virtualpagetable.addr)[pagecount] =
+         cpu_to_le32((card->silentpage.dma_handle * 2) | pagecount);
 
 	/* Init page table & tank memory base register */
 	sblive_writeptr_tag(card, 0,
@@ -612,6 +613,10 @@
 {
 	struct emu10k1_card *card;
 	u32 subsysvid;
+	int ret;
+
+	if ((ret=pci_enable_device(pci_dev)))
+		return ret;
 
 	if ((card = kmalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) {
 		printk(KERN_ERR "emu10k1: out of memory\n");
@@ -621,11 +626,6 @@
 
 	if (pci_set_dma_mask(pci_dev, EMU10K1_DMA_MASK)) {
 		printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n");
-		kfree(card);
-		return -ENODEV;
-	}
-
-	if (pci_enable_device(pci_dev)) {
 		kfree(card);
 		return -ENODEV;
 	}
diff -urN linux-2.4.5-pre3/drivers/sound/emu10k1/midi.c linux/drivers/sound/emu10k1/midi.c
--- linux-2.4.5-pre3/drivers/sound/emu10k1/midi.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/sound/emu10k1/midi.c	Mon Dec  3 22:44:23 2001
@@ -56,7 +56,7 @@
 {
 	struct midi_hdr *midihdr;
 
-	if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL) {
+	if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL) {
 		ERROR();
 		return -EINVAL;
 	}
@@ -328,7 +328,7 @@
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
 
-	if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL)
+	if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL)
 		return -EINVAL;
 
 	midihdr->bufferlength = count;
diff -urN linux-2.4.5-pre3/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- linux-2.4.5-pre3/drivers/sound/i810_audio.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/sound/i810_audio.c	Mon Dec  3 22:44:23 2001
@@ -96,6 +96,9 @@
 #ifndef PCI_DEVICE_ID_INTEL_ICH2
 #define PCI_DEVICE_ID_INTEL_ICH2	0x2445
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_ICH3
+#define PCI_DEVICE_ID_INTEL_ICH3	0x2485
+#endif
 #ifndef PCI_DEVICE_ID_INTEL_440MX
 #define PCI_DEVICE_ID_INTEL_440MX	0x7195
 #endif
@@ -210,13 +213,15 @@
 	ICH82901AB,
 	INTEL440MX,
 	INTELICH2,
+	INTELICH3
 };
 
 static char * card_names[] = {
 	"Intel ICH 82801AA",
 	"Intel ICH 82901AB",
 	"Intel 440MX",
-	"Intel ICH2"
+	"Intel ICH2",
+	"Intel ICH3"
 };
 
 static struct pci_device_id i810_pci_tbl [] __initdata = {
@@ -228,6 +233,8 @@
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTEL440MX},
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH2,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH2},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH3,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3},
 	{0,}
 };
 
diff -urN linux-2.4.5-pre3/drivers/sound/trident.c linux/drivers/sound/trident.c
--- linux-2.4.5-pre3/drivers/sound/trident.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/sound/trident.c	Mon Dec  3 22:44:23 2001
@@ -3170,7 +3170,7 @@
 		return -EINVAL;
 	if (count == 0)
 		return 0;
-	if (get_user(&c, buffer))
+	if (get_user(c, buffer))
 		return -EFAULT;
 	
 	spin_lock_irqsave(&card->lock, flags);
diff -urN linux-2.4.5-pre3/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- linux-2.4.5-pre3/drivers/sound/ymfpci.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/sound/ymfpci.c	Mon Dec  3 22:44:23 2001
@@ -2059,9 +2059,10 @@
 	}
 
 	if (mpuio >= 0 || oplio >= 0) {
-		v = 0x003e;
+		/* 0x0020: 1 - 10 bits of I/O address decoded, 0 - 16 bits. */
+		v = 0x001e;
 		pci_write_config_word(pcidev, PCIR_LEGCTRL, v);
-	
+
 		switch (pcidev->device) {
 		case PCI_DEVICE_ID_YAMAHA_724:
 		case PCI_DEVICE_ID_YAMAHA_740:
diff -urN linux-2.4.5-pre3/drivers/telephony/ixj.c linux/drivers/telephony/ixj.c
--- linux-2.4.5-pre3/drivers/telephony/ixj.c	Mon Dec  3 22:43:50 2001
+++ linux/drivers/telephony/ixj.c	Mon Dec  3 22:44:23 2001
@@ -4476,7 +4476,7 @@
 {
 	IXJ_FILTER_CADENCE *lcp;
 
-	lcp = kmalloc(sizeof(IXJ_CADENCE), GFP_KERNEL);
+	lcp = kmalloc(sizeof(IXJ_FILTER_CADENCE), GFP_KERNEL);
 	if (lcp == NULL)
 		return -ENOMEM;
 	if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_FILTER_CADENCE)))
diff -urN linux-2.4.5-pre3/drivers/usb/acm.c linux/drivers/usb/acm.c
--- linux-2.4.5-pre3/drivers/usb/acm.c	Fri Feb 16 16:06:17 2001
+++ linux/drivers/usb/acm.c	Mon Dec  3 22:44:23 2001
@@ -233,8 +233,14 @@
 		dbg("nonzero read bulk status received: %d", urb->status);
 
 	if (!urb->status & !acm->throttle)  {
-		for (i = 0; i < urb->actual_length && !acm->throttle; i++)
+		for (i = 0; i < urb->actual_length && !acm->throttle; i++) {
+			/* if we insert more than TTY_FLIPBUF_SIZE characters,
+			 * we drop them. */
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(tty);
+			}
 			tty_insert_flip_char(tty, data[i], 0);
+		}
 		tty_flip_buffer_push(tty);
 	}
 
@@ -303,6 +309,10 @@
 		dbg("usb_submit_urb(read bulk) failed");
 
 	acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
+
+	/* force low_latency on so that our tty_push actually forces the data through, 
+	   otherwise it is scheduled, and with high data rates data can get lost. */
+	tty->low_latency = 1;
 
 	return 0;
 }
diff -urN linux-2.4.5-pre3/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c
--- linux-2.4.5-pre3/drivers/usb/serial/keyspan.c	Thu Apr 12 12:16:36 2001
+++ linux/drivers/usb/serial/keyspan.c	Mon Dec  3 22:44:23 2001
@@ -1287,7 +1287,21 @@
 		msg.setPrescaler = 0xff;
 	}
 
-	msg.lcr = USA_DATABITS_8 | STOPBITS_5678_1;
+	msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
+	switch (p_priv->cflag & CSIZE) {
+	case CS5:
+		msg.lcr |= USA_DATABITS_5;
+		break;
+	case CS6:
+		msg.lcr |= USA_DATABITS_6;
+		break;
+	case CS7:
+		msg.lcr |= USA_DATABITS_7;
+		break;
+	case CS8:
+		msg.lcr |= USA_DATABITS_8;
+		break;
+	}
 	if (p_priv->cflag & PARENB) {
 		/* note USA_PARITY_NONE == 0 */
 		msg.lcr |= (p_priv->cflag & PARODD)?
@@ -1480,7 +1494,21 @@
 		//msg.setPrescaler = 0xff;
 	}
 
-	msg.lcr = USA_DATABITS_8 | STOPBITS_5678_1;
+	msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
+	switch (p_priv->cflag & CSIZE) {
+	case CS5:
+		msg.lcr |= USA_DATABITS_5;
+		break;
+	case CS6:
+		msg.lcr |= USA_DATABITS_6;
+		break;
+	case CS7:
+		msg.lcr |= USA_DATABITS_7;
+		break;
+	case CS8:
+		msg.lcr |= USA_DATABITS_8;
+		break;
+	}
 	if (p_priv->cflag & PARENB) {
 		/* note USA_PARITY_NONE == 0 */
 		msg.lcr |= (p_priv->cflag & PARODD)?
diff -urN linux-2.4.5-pre3/drivers/usb/serial/keyspan_pda_fw.h linux/drivers/usb/serial/keyspan_pda_fw.h
--- linux-2.4.5-pre3/drivers/usb/serial/keyspan_pda_fw.h	Fri Mar 10 13:19:34 2000
+++ linux/drivers/usb/serial/keyspan_pda_fw.h	Mon Dec  3 22:44:23 2001
@@ -1,9 +1,15 @@
 /*
- * keyspan_pda_fw.h
+ * USB Keyspan PDA Firmware
+ *
+ * Copyright (c) 1999, 2000 Brian Warner	<warner@lothar.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.
  *
  * Generated from keyspan_pda.s by ezusb_convert.pl
- * This file is presumed to be under the same copyright as the source file
- * from which it was derived.
+ *
  */
 
 static const struct ezusb_hex_record keyspan_pda_firmware[] = {
diff -urN linux-2.4.5-pre3/drivers/usb/serial/mct_u232.c linux/drivers/usb/serial/mct_u232.c
--- linux-2.4.5-pre3/drivers/usb/serial/mct_u232.c	Fri Apr  6 15:51:52 2001
+++ linux/drivers/usb/serial/mct_u232.c	Mon Dec  3 22:44:23 2001
@@ -218,11 +218,31 @@
 
 #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
 
+static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value) {
+	if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID) {
+		switch (value) {
+			case    300: return 0x01;
+			case    600: return 0x02; /* this one not tested */
+			case   1200: return 0x03;
+			case   2400: return 0x04;
+			case   4800: return 0x06;
+			case   9600: return 0x08;
+			case  19200: return 0x09;
+			case  38400: return 0x0a;
+			case  57600: return 0x0b;
+			case 115200: return 0x0c;
+			default:     return -1; /* normally not reached */
+		}
+	}
+	else
+		return MCT_U232_BAUD_RATE(value);
+}
+
 static int mct_u232_set_baud_rate(struct usb_serial *serial, int value)
 {
 	unsigned int divisor;
         int rc;
-	divisor = MCT_U232_BAUD_RATE(value);
+	divisor = mct_u232_calculate_baud_rate(serial, value);
         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                              MCT_U232_SET_BAUD_RATE_REQUEST,
 			     MCT_U232_SET_REQUEST_TYPE,
@@ -230,7 +250,7 @@
 			     WDR_TIMEOUT);
 	if (rc < 0)
 		err("Set BAUD RATE %d failed (error = %d)", value, rc);
-	dbg("set_baud_rate: 0x%x", divisor);
+	dbg("set_baud_rate: value: %d, divisor: 0x%x", value, divisor);
         return rc;
 } /* mct_u232_set_baud_rate */
 
@@ -366,6 +386,14 @@
 
 	if (!port->active) {
 		port->active = 1;
+
+		/* Compensate for a hardware bug: although the Sitecom U232-P25
+		 * device reports a maximum output packet size of 32 bytes,
+		 * it seems to be able to accept only 16 bytes (and that's what
+		 * SniffUSB says too...)
+		 */
+		if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID)
+			port->bulk_out_size = 16;
 
 		/* Do a defined restart: the normal serial device seems to 
 		 * always turn on DTR and RTS here, so do the same. I'm not
diff -urN linux-2.4.5-pre3/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c
--- linux-2.4.5-pre3/drivers/video/chipsfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/chipsfb.c	Mon Dec  3 22:44:23 2001
@@ -29,17 +29,19 @@
 #include <linux/selection.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <asm/io.h>
+
 #ifdef CONFIG_FB_COMPAT_XPMAC
 #include <asm/vc_ioctl.h>
-#endif
-#include <asm/io.h>
-#include <asm/prom.h>
 #include <asm/pci-bridge.h>
+#endif
 #ifdef CONFIG_PMAC_BACKLIGHT
 #include <asm/backlight.h>
 #endif
+#ifdef CONFIG_PMAC_PBOOK
 #include <linux/adb.h>
 #include <linux/pmu.h>
+#endif
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -56,14 +58,13 @@
 	struct {
 		__u8 red, green, blue;
 	} palette[256];
+	struct pci_dev *pdev;
 	unsigned long frame_buffer_phys;
 	__u8 *frame_buffer;
 	unsigned long blitter_regs_phys;
 	__u32 *blitter_regs;
 	unsigned long blitter_data_phys;
 	__u8 *blitter_data;
-	unsigned long io_base_phys;
-	__u8 *io_base;
 	struct fb_info_chips *next;
 #ifdef CONFIG_PMAC_PBOOK
 	unsigned char *save_framebuffer;
@@ -74,10 +75,10 @@
 };
 
 #define write_ind(num, val, ap, dp)	do { \
-	out_8(p->io_base + (ap), (num)); out_8(p->io_base + (dp), (val)); \
+	outb((num), (ap)); outb((val), (dp)); \
 } while (0)
 #define read_ind(num, var, ap, dp)	do { \
-	out_8(p->io_base + (ap), (num)); var = in_8(p->io_base + (dp)); \
+	outb((num), (ap)); var = inb((dp)); \
 } while (0);
 
 /* extension registers */
@@ -97,10 +98,10 @@
 #define read_sr(num, var)	read_ind(num, var, 0x3c4, 0x3c5)
 /* attribute registers - slightly strange */
 #define write_ar(num, val)	do { \
-	in_8(p->io_base + 0x3da); write_ind(num, val, 0x3c0, 0x3c0); \
+	inb(0x3da); write_ind(num, val, 0x3c0, 0x3c0); \
 } while (0)
 #define read_ar(num, var)	do { \
-	in_8(p->io_base + 0x3da); read_ind(num, var, 0x3c0, 0x3c1); \
+	inb(0x3da); read_ind(num, var, 0x3c0, 0x3c1); \
 } while (0)
 
 static struct fb_info_chips *all_chips;
@@ -117,7 +118,7 @@
  */
 int chips_init(void);
 
-static void chips_of_init(struct device_node *dp);
+static void chips_pci_init(struct pci_dev *dp);
 static int chips_get_fix(struct fb_fix_screeninfo *fix, int con,
 			 struct fb_info *info);
 static int chips_get_var(struct fb_var_screeninfo *var, int con,
@@ -253,29 +254,29 @@
 #endif /* CONFIG_PMAC_BACKLIGHT */
 		/* get the palette from the chip */
 		for (i = 0; i < 256; ++i) {
-			out_8(p->io_base + 0x3c7, i);
+			outb(i, 0x3c7);
 			udelay(1);
-			p->palette[i].red = in_8(p->io_base + 0x3c9);
-			p->palette[i].green = in_8(p->io_base + 0x3c9);
-			p->palette[i].blue = in_8(p->io_base + 0x3c9);
+			p->palette[i].red = inb(0x3c9);
+			p->palette[i].green = inb(0x3c9);
+			p->palette[i].blue = inb(0x3c9);
 		}
 		for (i = 0; i < 256; ++i) {
-			out_8(p->io_base + 0x3c8, i);
+			outb(i, 0x3c8);
 			udelay(1);
-			out_8(p->io_base + 0x3c9, 0);
-			out_8(p->io_base + 0x3c9, 0);
-			out_8(p->io_base + 0x3c9, 0);
+			outb(0, 0x3c9);
+			outb(0, 0x3c9);
+			outb(0, 0x3c9);
 		}
 	} else {
 #ifdef CONFIG_PMAC_BACKLIGHT
 		set_backlight_enable(1);
 #endif /* CONFIG_PMAC_BACKLIGHT */
 		for (i = 0; i < 256; ++i) {
-			out_8(p->io_base + 0x3c8, i);
+			outb(i, 0x3c8);
 			udelay(1);
-			out_8(p->io_base + 0x3c9, p->palette[i].red);
-			out_8(p->io_base + 0x3c9, p->palette[i].green);
-			out_8(p->io_base + 0x3c9, p->palette[i].blue);
+			outb(p->palette[i].red, 0x3c9);
+			outb(p->palette[i].green, 0x3c9);
+			outb(p->palette[i].blue, 0x3c9);
 		}
 	}
 }
@@ -307,11 +308,11 @@
 	p->palette[regno].red = red;
 	p->palette[regno].green = green;
 	p->palette[regno].blue = blue;
-	out_8(p->io_base + 0x3c8, regno);
+	outb(regno, 0x3c8);
 	udelay(1);
-	out_8(p->io_base + 0x3c9, red);
-	out_8(p->io_base + 0x3c9, green);
-	out_8(p->io_base + 0x3c9, blue);
+	outb(red, 0x3c9);
+	outb(green, 0x3c9);
+	outb(blue, 0x3c9);
 
 #ifdef FBCON_HAS_CFB16
 	if (regno < 16)
@@ -388,7 +389,7 @@
 	disp->visual = fix->visual;
 	disp->var = *var;
 
-#if (defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_FB_COMPAT_XPMAC))
+#ifdef CONFIG_FB_COMPAT_XPMAC
 	display_info.depth = bpp;
 	display_info.pitch = fix->line_length;
 #endif
@@ -517,7 +518,7 @@
 
 	for (i = 0; i < N_ELTS(chips_init_xr); ++i)
 		write_xr(chips_init_xr[i].addr, chips_init_xr[i].data);
-	out_8(p->io_base + 0x3c2, 0x29); /* set misc output reg */
+	outb(0x29, 0x3c2); /* set misc output reg */
 	for (i = 0; i < N_ELTS(chips_init_sr); ++i)
 		write_sr(chips_init_sr[i].addr, chips_init_sr[i].data);
 	for (i = 0; i < N_ELTS(chips_init_gr); ++i)
@@ -545,7 +546,6 @@
 // * 3400 has 1MB (I think).  Don't know if it's expandable.
 // -- Tim Seufert
 	p->fix.smem_len = 0x100000;	// 1MB
-	p->fix.mmio_start = p->io_base_phys;
 	p->fix.type = FB_TYPE_PACKED_PIXELS;
 	p->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 	p->fix.line_length = 800;
@@ -607,6 +607,8 @@
 
 #ifdef CONFIG_FB_COMPAT_XPMAC
 	if (!console_fb_info) {
+		unsigned long iobase;
+
 		display_info.height = p->var.yres;
 		display_info.width = p->var.xres;
 		display_info.depth = 8;
@@ -615,8 +617,9 @@
 		strncpy(display_info.name, "chips65550",
 			sizeof(display_info.name));
 		display_info.fb_address = p->frame_buffer_phys;
-		display_info.cmap_adr_address = p->io_base_phys + 0x3c8;
-		display_info.cmap_data_address = p->io_base_phys + 0x3c9;
+		iobase = pci_bus_io_base_phys(p->pdev->bus->number);
+		display_info.cmap_adr_address = iobase + 0x3c8;
+		display_info.cmap_data_address = iobase + 0x3c9;
 		display_info.disp_reg_address = p->blitter_regs_phys;
 		console_fb_info = &p->info;
 	}
@@ -632,35 +635,39 @@
 
 int __init chips_init(void)
 {
-	struct device_node *dp;
+	struct pci_dev *dp = NULL;
 
-	dp = find_devices("chips65550");
-	if (dp != 0)
-		chips_of_init(dp);
-	return 0;
+	while ((dp = pci_find_device(PCI_VENDOR_ID_CT,
+				     PCI_DEVICE_ID_CT_65550, dp)) != NULL)
+		if ((dp->class >> 16) == PCI_BASE_CLASS_DISPLAY)
+			chips_pci_init(dp);
+	return all_chips? 0: -ENODEV;
 }
 
-static void __init chips_of_init(struct device_node *dp)
+static void __init chips_pci_init(struct pci_dev *dp)
 {
 	struct fb_info_chips *p;
-	unsigned long addr;
-	unsigned char bus, devfn;
+	unsigned long addr, size;
 	unsigned short cmd;
 
-	if (dp->n_addrs == 0)
+	if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
+		return;
+	addr = dp->resource[0].start;
+	size = dp->resource[0].end + 1 - addr;
+	if (addr == 0)
 		return;
 	p = kmalloc(sizeof(*p), GFP_ATOMIC);
 	if (p == 0)
 		return;
 	memset(p, 0, sizeof(*p));
-	addr = dp->addrs[0].address;
-	if (!request_mem_region(addr, dp->addrs[0].size, "chipsfb")) {
+	if (!request_mem_region(addr, size, "chipsfb")) {
 		kfree(p);
 		return;
 	}
 #ifdef __BIG_ENDIAN
 	addr += 0x800000;	// Use big-endian aperture
 #endif
+	p->pdev = dp;
 	p->frame_buffer_phys = addr;
 	p->frame_buffer = __ioremap(addr, 0x200000, _PAGE_NO_CACHE);
 	p->blitter_regs_phys = addr + 0x400000;
@@ -668,14 +675,12 @@
 	p->blitter_data_phys = addr + 0x410000;
 	p->blitter_data = ioremap(addr + 0x410000, 0x10000);
 
-	if (pci_device_loc(dp, &bus, &devfn) == 0) {
-		pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
-		cmd |= 3;	/* enable memory and IO space */
-		pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
-		p->io_base = (__u8 *) pci_io_base(bus);
-		/* XXX really want the physical address here */
-		p->io_base_phys = (unsigned long) pci_io_base(bus);
-	}
+	/* we should use pci_enable_device here, but,
+	   the device doesn't declare its I/O ports in its BARs
+	   so pci_enable_device won't turn on I/O responses */
+	pci_read_config_word(dp, PCI_COMMAND, &cmd);
+	cmd |= 3;	/* enable memory and IO space */
+	pci_write_config_word(dp, PCI_COMMAND, cmd);
 
 	/* Clear the entire framebuffer */
 	memset(p->frame_buffer, 0, 0x100000);
diff -urN linux-2.4.5-pre3/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-2.4.5-pre3/fs/binfmt_elf.c	Thu Apr  5 17:13:23 2001
+++ linux/fs/binfmt_elf.c	Mon Dec  3 22:44:23 2001
@@ -135,12 +135,13 @@
 
 	/*
 	 * Force 16 byte _final_ alignment here for generality.
-	 * Leave an extra 16 bytes free so that on the PowerPC we
-	 * can move the aux table up to start on a 16-byte boundary.
 	 */
-	sp = (elf_addr_t *)((~15UL & (unsigned long)(u_platform)) - 16UL);
+	sp = (elf_addr_t *)(~15UL & (unsigned long)(u_platform));
 	csp = sp;
-	csp -= DLINFO_ITEMS*2 + (k_platform ? 2 : 0);
+	csp -= (1+DLINFO_ITEMS)*2 + (k_platform ? 2 : 0);
+#ifdef DLINFO_ARCH_ITEMS
+	csp -= DLINFO_ARCH_ITEMS*2;
+#endif
 	csp -= envc+1;
 	csp -= argc+1;
 	csp -= (!ibcs ? 3 : 1);	/* argc itself */
@@ -174,6 +175,13 @@
 	NEW_AUX_ENT(10, AT_EUID, (elf_addr_t) current->euid);
 	NEW_AUX_ENT(11, AT_GID, (elf_addr_t) current->gid);
 	NEW_AUX_ENT(12, AT_EGID, (elf_addr_t) current->egid);
+#ifdef ARCH_DLINFO
+	/* 
+	 * ARCH_DLINFO must come last so platform specific code can enforce
+	 * special alignment requirements on the AUXV if necessary (eg. PPC).
+	 */
+	ARCH_DLINFO;
+#endif
 #undef NEW_AUX_ENT
 
 	sp -= envc+1;
diff -urN linux-2.4.5-pre3/fs/dquot.c linux/fs/dquot.c
--- linux-2.4.5-pre3/fs/dquot.c	Fri Feb 16 16:06:17 2001
+++ linux/fs/dquot.c	Mon Dec  3 22:44:23 2001
@@ -1343,13 +1343,11 @@
 }
 
 
-void __init dquot_init_hash(void)
+static int __init dquot_init(void)
 {
 	printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\n", __DQUOT_VERSION__);
-
-	memset(dquot_hash, 0, sizeof(dquot_hash));
-	memset((caddr_t)&dqstats, 0, sizeof(dqstats));
 }
+__initcall(dquot_init);
 
 /*
  * Definitions of diskquota operations.
diff -urN linux-2.4.5-pre3/fs/freevxfs/Makefile linux/fs/freevxfs/Makefile
--- linux-2.4.5-pre3/fs/freevxfs/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/Makefile	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,11 @@
+#
+# VxFS Makefile
+#
+
+O_TARGET :=	freevxfs.o
+
+obj-y :=	vxfs_bmap.o vxfs_fshead.o vxfs_immed.o vxfs_inode.o \
+		vxfs_lookup.o vxfs_olt.o vxfs_subr.o vxfs_super.o
+obj-m :=	$(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs.h linux/fs/freevxfs/vxfs.h
--- linux-2.4.5-pre3/fs/freevxfs/vxfs.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs.h	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ */
+#ifndef _VXFS_SUPER_H_
+#define _VXFS_SUPER_H_
+
+#ident "$Id: vxfs.h 1.9 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - superblock structure.
+ *
+ * This file contains the definition of the disk and core
+ * superblocks of the Veritas Filesystem.
+ */
+#include <linux/types.h>
+
+
+/*
+ * Data types for use with the VxFS ondisk format.
+ */
+typedef	int32_t		vx_daddr_t;
+typedef int32_t		vx_ino_t;
+
+/*
+ * Superblock magic number (vxfs_super->vs_magic).
+ */
+#define VXFS_SUPER_MAGIC	0xa501FCF5
+
+/*
+ * The root inode.
+ */
+#define VXFS_ROOT_INO		2
+
+/*
+ * Num of entries in free extent array
+ */
+#define VXFS_NEFREE		32
+
+/*
+ * VxFS superblock (disk).
+ */
+struct vxfs_sb {
+	/*
+	 * Version 1
+	 */
+	u_int32_t	vs_magic;		/* Magic, VXFS_MAGIC */
+	int32_t		vs_version;		/* VxFS version, 1,2,3,4 */
+	u_int32_t	vs_ctime;		/* create time - secs */
+	u_int32_t	vs_cutime;		/* create time - usecs */
+	int32_t		__unused1;		/* ??? */
+	int32_t		__unused2;		/* ??? */
+	vx_daddr_t	vs_old_logstart;	/* OLD: addr of first log blk */
+	vx_daddr_t	vs_old_logend;		/* OLD: addr of last log blk */
+	int32_t		vs_bsize;		/* Block size */
+	int32_t		vs_size;		/* Number of blocks in FS */
+	int32_t		vs_dsize;		/* Number of data blocks */
+	u_int32_t	vs_old_ninode;		/* OLD: number of inodes */
+	int32_t		vs_old_nau;		/* Number of allocation units */
+	int32_t		__unused3;		/* ??? */
+	int32_t		vs_old_defiextsize;	/* OLD: dfault indirect ext size */
+	int32_t		vs_old_ilbsize;		/* OLD: Ilist block size in bytes */
+	int32_t		vs_immedlen;		/* Size of immediate data area */
+	int32_t		vs_ndaddr;		/* Number of direct extentes per inode */
+	vx_daddr_t	vs_firstau;		/* Address of first Allocation Unit */
+	vx_daddr_t	vs_emap;		/* Offset of extent map in AU */
+	vx_daddr_t	vs_imap;		/* Offset of inode map in AU (V1) */
+	vx_daddr_t	vs_iextop;		/* Offset of Ext. Op. map in AU */
+	vx_daddr_t	vs_istart;		/* Offset of inode list in AU */
+	vx_daddr_t	vs_bstart;		/* Offset of first data block in AU */
+	vx_daddr_t	vs_femap;		/* aufirst + emap */
+	vx_daddr_t	vs_fimap;		/* aufirst + imap */
+	vx_daddr_t	vs_fiextop;		/* aufirst + iextop */
+	vx_daddr_t	vs_fistart;		/* aufirst + istart */
+	vx_daddr_t	vs_fbstart;		/* aufirst + bstart */
+	int32_t		vs_nindir;		/* Number of entries in indirect */
+	int32_t		vs_aulen;		/* Length of AU in blocks */
+	int32_t		vs_auimlen;		/* Length of AU imap in blocks */
+	int32_t		vs_auemlen;		/* Length of AU emap in blocks */
+	int32_t		vs_auilen;		/* Length of AU ilist in blocks */
+	int32_t		vs_aupad;		/* Length of AU pad in blocks */
+	int32_t		vs_aublocks;		/* Number of data blocks in AU */
+	int32_t		vs_maxtier;		/* Log base 2 of aublocks */
+	int32_t		vs_inopb;		/* Number of inodes per blk */
+	int32_t		vs_old_inopau;		/* OLD: Number of inodes per AU */
+	int32_t		vs_old_inopilb;		/* OLD: Inodes per ilist blocks */
+	int32_t		vs_old_ndiripau;	/* OLD: Num of directory inodes per au */
+	int32_t		vs_iaddrlen;		/* Size of indirect addr ext. */
+	int32_t		vs_bshift;		/* Log base 2 of bsize */
+	int32_t		vs_inoshift;		/* Log base 2 of inobp */
+	int32_t		vs_bmask;		/* ~( bsize - 1 ) */
+	int32_t		vs_boffmask;		/* bsize - 1 */
+	int32_t		vs_old_inomask;		/* old_inopilb - 1 */
+	int32_t		vs_checksum;		/* Checksum of V1 data */
+	
+	/*
+	 * Version 1, writable
+	 */
+	int32_t		vs_free;		/* Number of free blocks */
+	int32_t		vs_ifree;		/* Number of free inodes */
+	int32_t		vs_efree[VXFS_NEFREE];	/* Number of free extents by size */
+	int32_t		vs_flags;		/* Flags ?!? */
+	u_int8_t	vs_mod;			/* Filesystem has been changed */
+	u_int8_t	vs_clean;		/* Clean FS */
+	u_int16_t	__unused4;		/* ??? */
+	u_int32_t	vs_firstlogid;		/* Mount time log ID */
+	u_int32_t	vs_wtime;		/* Last time written - sec */
+	u_int32_t	vs_wutime;		/* Last time written - usec */
+	u_int8_t	vs_fname[6];		/* FS name */
+	u_int8_t	vs_fpack[6];		/* FS pack name */
+	int32_t		vs_logversion;		/* Log format version */
+	int32_t		__unused5;		/* ??? */
+	
+	/*
+	 * Version 2, Read-only
+	 */
+	vx_daddr_t	vs_oltext[2];		/* OLT extent and replica */
+	int32_t		vs_oltsize;		/* OLT extent size */
+	int32_t		vs_iauimlen;		/* Size of inode map */
+	int32_t		vs_iausize;		/* Size of IAU in blocks */
+	int32_t		vs_dinosize;		/* Size of inode in bytes */
+	int32_t		vs_old_dniaddr;		/* OLD: Sum of indir levels per inode */
+	int32_t		vs_checksum2;		/* Checksum of V2 RO */
+
+	/*
+	 * Actually much more...
+	 */
+};
+
+
+/*
+ * In core superblock filesystem private data for VxFS.
+ */
+struct vxfs_sb_info {
+	struct vxfs_sb		*vsi_raw;	/* Raw (on disk) supeblock */
+	struct buffer_head	*vsi_bp;	/* Buffer for raw superblock*/
+	struct inode		*vsi_fship;	/* Fileset header inode */
+	struct inode		*vsi_ilist;	/* Inode list inode */
+	struct inode		*vsi_stilist;	/* Structual inode list inode */
+	u_long			vsi_iext;	/* Initial inode list */
+	ino_t			vsi_fshino;	/* Fileset header inode */
+	daddr_t			vsi_oltext;	/* OLT extent */
+	daddr_t			vsi_oltsize;	/* OLT size */
+};
+
+
+/*
+ * File modes.  File types above 0xf000 are vxfs internal only, they should
+ * not be passed back to higher levels of the system.  vxfs file types must
+ * never have one of the regular file type bits set.
+ */
+enum vxfs_mode {
+	VXFS_ISUID = 0x00000800,	/* setuid */
+	VXFS_ISGID = 0x00000400,	/* setgid */
+	VXFS_ISVTX = 0x00000200,	/* sticky bit */
+	VXFS_IREAD = 0x00000100,	/* read */
+	VXFS_IWRITE = 0x00000080,	/* write */
+	VXFS_IEXEC = 0x00000040,	/* exec */
+
+	VXFS_IFIFO = 0x00001000,	/* Named pipe */
+	VXFS_IFCHR = 0x00002000,	/* Character device */
+	VXFS_IFDIR = 0x00004000,	/* Directory */
+	VXFS_IFNAM = 0x00005000,	/* Xenix device ?? */
+	VXFS_IFBLK = 0x00006000,	/* Block device */
+	VXFS_IFREG = 0x00008000,	/* Regular file */
+	VXFS_IFCMP = 0x00009000,	/* Compressed file ?!? */
+	VXFS_IFLNK = 0x0000a000,	/* Symlink */
+	VXFS_IFSOC = 0x0000c000,	/* Socket */
+
+	/* VxFS internal */
+	VXFS_IFFSH = 0x10000000,	/* Fileset header */
+	VXFS_IFILT = 0x20000000,	/* Inode list */
+	VXFS_IFIAU = 0x30000000,	/* Inode allocation unit */
+	VXFS_IFCUT = 0x40000000,	/* Current usage table */
+	VXFS_IFATT = 0x50000000,	/* Attr. inode */
+	VXFS_IFLCT = 0x60000000,	/* Link count table */
+	VXFS_IFIAT = 0x70000000,	/* Indirect attribute file */
+	VXFS_IFEMR = 0x80000000,	/* Extent map reorg file */
+	VXFS_IFQUO = 0x90000000,	/* BSD quota file */
+	VXFS_IFPTI = 0xa0000000,	/* "Pass through" inode */
+	VXFS_IFLAB = 0x11000000,	/* Device label file */
+	VXFS_IFOLT = 0x12000000,	/* OLT file */
+	VXFS_IFLOG = 0x13000000,	/* Log file */
+	VXFS_IFEMP = 0x14000000,	/* Extent map file */
+	VXFS_IFEAU = 0x15000000,	/* Extent AU file */
+	VXFS_IFAUS = 0x16000000,	/* Extent AU summary file */
+	VXFS_IFDEV = 0x17000000,	/* Device config file */
+
+};
+
+#define	VXFS_TYPE_MASK		0xfffff000
+
+#define VXFS_IS_TYPE(ip,type)	(((ip)->vii_mode & VXFS_TYPE_MASK) == (type))
+#define VXFS_ISFIFO(x)		VXFS_IS_TYPE((x),VXFS_IFIFO)
+#define VXFS_ISCHR(x)		VXFS_IS_TYPE((x),VXFS_IFCHR)
+#define VXFS_ISDIR(x)		VXFS_IS_TYPE((x),VXFS_IFDIR)
+#define VXFS_ISNAM(x)		VXFS_IS_TYPE((x),VXFS_IFNAM)
+#define VXFS_ISBLK(x)		VXFS_IS_TYPE((x),VXFS_IFBLK)
+#define VXFS_ISLNK(x)		VXFS_IS_TYPE((x),VXFS_IFLNK)
+#define VXFS_ISREG(x)		VXFS_IS_TYPE((x),VXFS_IFREG)
+#define VXFS_ISCMP(x)		VXFS_IS_TYPE((x),VXFS_IFCMP)
+#define VXFS_ISSOC(x)		VXFS_IS_TYPE((x),VXFS_IFSOC)
+
+#define VXFS_ISFSH(x)		VXFS_IS_TYPE((x),VXFS_IFFSH)
+#define VXFS_ISILT(x)		VXFS_IS_TYPE((x),VXFS_IFILT)
+
+/*
+ * Inmode organisation types.
+ */
+enum {
+	VXFS_ORG_NONE	= 0,	/* Inode has *no* format ?!? */
+	VXFS_ORG_EXT4	= 1,	/* Ext4 */
+	VXFS_ORG_IMMED	= 2,	/* All data stored in inode */
+	VXFS_ORG_TYPED	= 3,	/* Typed extents */
+};
+
+#define VXFS_IS_ORG(ip,org)	((ip)->vii_orgtype == (org))
+#define VXFS_ISNONE(ip)		VXFS_IS_ORG((ip),VXFS_ORG_NONE)
+#define VXFS_ISEXT4(ip)		VXFS_IS_ORG((ip),VXFS_ORG_EXT4)
+#define VXFS_ISIMMED(ip)	VXFS_IS_ORG((ip),VXFS_ORG_IMMED)
+#define VXFS_ISTYPED(ip)	VXFS_IS_ORG((ip),VXFS_ORG_TYPED)
+
+
+/*
+ * Get filesystem private data from VFS inode.
+ */
+#define VXFS_INO(ip) \
+	((struct vxfs_inode_info *)(ip)->u.generic_ip)
+
+/*
+ * Get filesystem private data from VFS superblock.
+ */
+#define VXFS_SBI(sbp) \
+	((struct vxfs_sb_info *)(sbp)->u.generic_sbp)
+
+#endif /* _VXFS_SUPER_H_ */
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_bmap.c linux/fs/freevxfs/vxfs_bmap.c
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_bmap.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_bmap.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#ident "$Id: vxfs_bmap.c,v 1.19 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - filesystem to disk block mapping.
+ */
+#include <linux/fs.h>
+#include <linux/kernel.h>
+
+#include "vxfs.h"
+#include "vxfs_inode.h"
+
+
+#ifdef DIAGNOSTIC
+static void
+vxfs_typdump(struct vxfs_typed *typ)
+{
+	printk(KERN_DEBUG "type=%Lu ", typ->vt_hdr >> VXFS_TYPED_TYPESHIFT);
+	printk("offset=%Lx ", typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
+	printk("block=%x ", typ->vt_block);
+	printk("size=%x\n", typ->vt_size);
+}
+#endif
+
+/**
+ * vxfs_bmap_ext4 - do bmap for ext4 extents
+ * @ip:		pointer to the inode we do bmap for
+ * @iblock:	logical block.
+ *
+ * Description:
+ *   vxfs_bmap_ext4 performs the bmap operation for inodes with
+ *   ext4-style extents (which are much like the traditional UNIX
+ *   inode organisation).
+ *
+ * Returns:
+ *   The physical block number on success, else Zero.
+ */
+static daddr_t
+vxfs_bmap_ext4(struct inode *ip, long iblock)
+{
+	struct vxfs_inode_info		*vip = VXFS_INO(ip);
+	struct super_block		*sbp = ip->i_sb;
+	kdev_t				dev = ip->i_dev;
+	u_long				bsize = sbp->s_blocksize;
+	u_long				size = 0;
+	int				i;
+
+	for (i = 0; i < VXFS_NDADDR; i++) {
+		struct direct		*dp = vip->vii_ext4.ve4_direct + i;
+
+#ifdef DIAGNOSTIC
+		printk(KERN_DEBUG "iblock: %ld, %d (size: %lu)\n", iblock, i, size);
+		printk(KERN_DEBUG "dp->extent: %d, dp->size: %d\n", dp->extent, dp->size);
+#endif
+
+		if (iblock >= size && iblock < (size + dp->size))
+			return ((iblock - size) + dp->extent);
+		size += dp->size;
+	}
+
+	iblock -= size;
+
+	if (!(iblock / (vip->vii_ext4.ve4_indsize * vip->vii_ext4.ve4_indsize * bsize >> 2))) {
+		struct buffer_head	*bp;
+		daddr_t			pblock;
+
+		/*
+		 * XXX: is the second indir only used for
+		 *	double indirect extents?
+		 */
+		bp = bread(dev, vip->vii_ext4.ve4_indir[0],
+				bsize * ((vip->vii_ext4.ve4_indsize) / bsize) + 1);
+		pblock = *(bp->b_data + ((iblock / vip->vii_ext4.ve4_indsize) %
+					(vip->vii_ext4.ve4_indsize * bsize)));
+
+		brelse(bp);
+		return (pblock + (iblock % vip->vii_ext4.ve4_indsize));
+	} else
+		printk(KERN_WARNING "no matching indir?");
+
+	return 0;
+}
+
+/**
+ * vxfs_bmap_indir - recursion for vxfs_bmap_typed
+ * @ip:		pointer to the inode we do bmap for
+ * @indir:	indirect block we start reading at
+ * @size:	size of the typed area to search
+ * @block:	partially result from further searches
+ *
+ * Description:
+ *   vxfs_bmap_indir reads a &struct vxfs_typed at @indir
+ *   and performs the type-defined action.
+ *
+ * Return Value:
+ *   The physical block number on success, else Zero.
+ *
+ * Note:
+ *   Kernelstack is rare.  Unrecurse?
+ */
+static daddr_t
+vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
+{
+	struct buffer_head		*bp = NULL;
+	daddr_t				pblock = 0;
+	int				i;
+
+	for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
+		struct vxfs_typed	*typ;
+		u_int64_t		off;
+
+		bp = bread(ip->i_dev,
+				indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)),
+				ip->i_sb->s_blocksize);
+		if (!buffer_mapped(bp))
+			return 0;
+
+		typ = ((struct vxfs_typed *)bp->b_data) +
+			(i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
+		off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
+
+		if (block < off) {
+			brelse(bp);
+			continue;
+		}
+
+		switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
+		case VXFS_TYPED_INDIRECT:
+			pblock = vxfs_bmap_indir(ip, typ->vt_block,
+					typ->vt_size, block - off);
+			if (pblock == -2)
+				break;
+			goto out;
+		case VXFS_TYPED_DATA:
+			if ((block - off) >= typ->vt_size)
+				break;
+			pblock = (typ->vt_block + block - off);
+			goto out;
+		case VXFS_TYPED_INDIRECT_DEV4:
+		case VXFS_TYPED_DATA_DEV4: {
+			struct vxfs_typed_dev4	*typ4 = (struct vxfs_typed_dev4 *)typ;
+			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
+			printk(KERN_INFO "block: %Ld\tsize: %Ld\tdev: %d\n",
+					typ4->vd4_block, typ4->vd4_size, typ4->vd4_dev);
+			goto fail;
+		}
+		default:
+			BUG();
+		}
+		brelse(bp);
+	}
+
+fail:
+	pblock = 0;
+out:
+	brelse(bp);
+	return (pblock);
+}
+
+/**
+ * vxfs_bmap_typed - bmap for typed extents
+ * @ip:		pointer to the inode we do bmap for
+ * @iblock:	logical block
+ *
+ * Description:
+ *   Performs the bmap operation for typed extents.
+ *
+ * Return Value:
+ *   The physical block number on success, else Zero.
+ */
+static daddr_t
+vxfs_bmap_typed(struct inode *ip, long iblock)
+{
+	struct vxfs_inode_info		*vip = VXFS_INO(ip);
+	daddr_t				pblock = 0;
+	int				i;
+
+	for (i = 0; i < VXFS_NTYPED; i++) {
+		struct vxfs_typed	*typ = vip->vii_org.typed + i;
+		u_int64_t		off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
+
+#ifdef DIAGNOSTIC
+		vxfs_typdump(typ);
+#endif
+		if (iblock < off)
+			continue;
+		switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
+		case VXFS_TYPED_INDIRECT:
+			pblock = vxfs_bmap_indir(ip, typ->vt_block,
+					typ->vt_size, iblock - off);
+			if (pblock == -2)
+				break;
+			return (pblock);
+		case VXFS_TYPED_DATA:
+			if ((iblock - off) < typ->vt_size)
+				return (typ->vt_block + iblock - off);
+			break;
+		case VXFS_TYPED_INDIRECT_DEV4:
+		case VXFS_TYPED_DATA_DEV4: {
+			struct vxfs_typed_dev4	*typ4 = (struct vxfs_typed_dev4 *)typ;
+			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
+			printk(KERN_INFO "block: %Ld\tsize: %Ld\tdev: %d\n",
+					typ4->vd4_block, typ4->vd4_size, typ4->vd4_dev);
+			return 0;
+		}
+		default:
+			BUG();
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * vxfs_bmap1 - vxfs-internal bmap operation
+ * @ip:			pointer to the inode we do bmap for
+ * @iblock:		logical block
+ *
+ * Description:
+ *   vxfs_bmap1 perfoms a logical to physical block mapping
+ *   for vxfs-internal purposes.
+ *
+ * Return Value:
+ *   The physical block number on success, else Zero.
+ */
+daddr_t
+vxfs_bmap1(struct inode *ip, long iblock)
+{
+	struct vxfs_inode_info		*vip = VXFS_INO(ip);
+
+	if (VXFS_ISEXT4(vip))
+		return vxfs_bmap_ext4(ip, iblock);
+	if (VXFS_ISTYPED(vip))
+		return vxfs_bmap_typed(ip, iblock);
+	if (VXFS_ISNONE(vip))
+		goto unsupp;
+	if (VXFS_ISIMMED(vip))
+		goto unsupp;
+
+	printk(KERN_WARNING "vxfs: inode %ld has no valid orgtype (%x)\n",
+			ip->i_ino, vip->vii_orgtype);
+	BUG();
+
+unsupp:
+	printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n",
+			ip->i_ino, vip->vii_orgtype);
+	return 0;
+}
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_dir.h linux/fs/freevxfs/vxfs_dir.h
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_dir.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_dir.h	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ */
+#ifndef _VXFS_DIR_H_
+#define _VXFS_DIR_H_
+
+#ident "$Id: vxfs_dir.h,v 1.4 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - directory structure.
+ *
+ * This file contains the definition of the vxfs directory format.
+ */
+
+
+/*
+ * VxFS directory block header.
+ */
+struct vxfs_dirblk {
+	u_int16_t	d_free;
+	u_int16_t	d_nhash;
+	u_int16_t	d_hash[1];
+};
+
+/*
+ * Special dirblk for immed inodes:  no hash.
+ */
+struct vxfs_immed_dirblk {
+	u_int16_t	d_free;
+	u_int16_t	d_nhash;
+};
+
+/*
+ * VxFS directory entry.
+ */
+#define VXFS_NAME_LEN	256
+struct vxfs_direct {
+	vx_ino_t	d_ino;
+	u_int16_t	d_reclen;
+	u_int16_t	d_namelen;
+	u_int16_t	d_hashnext;
+	char		d_name[VXFS_NAME_LEN];
+};
+
+#endif /* _VXFS_DIR_H_ */
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_extern.h linux/fs/freevxfs/vxfs_extern.h
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_extern.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_extern.h	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ */
+#ifndef _VXFS_EXTERN_H_
+#define _VXFS_EXTERN_H_
+
+#ident "$Id: vxfs_extern.h,v 1.18 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - external prototypes.
+ *
+ * This file contains prototypes for all vxfs functions used
+ * outside their respective source files.
+ */
+
+
+struct kmem_cache_s;
+struct super_block;
+struct vxfs_inode_info;
+struct inode;
+
+
+/* vxfs_bmap.c */
+extern daddr_t			vxfs_bmap1(struct inode *, long);
+
+/* vxfs_fshead.c */
+extern int			vxfs_read_fshead(struct super_block *);
+
+/* vxfs_inode.c */
+extern struct kmem_cache_s	*vxfs_inode_cachep;
+extern void			vxfs_dumpi(struct vxfs_inode_info *, ino_t);
+extern struct inode *		vxfs_fake_inode(struct super_block *,
+					struct vxfs_inode_info *);
+extern struct vxfs_inode_info *	vxfs_blkiget(struct super_block *, u_long, ino_t);
+extern struct vxfs_inode_info *	vxfs_stiget(struct super_block *, ino_t);
+extern void			vxfs_read_inode(struct inode *);
+extern void			vxfs_put_inode(struct inode *);
+
+/* vxfs_lookup.c */
+extern struct inode_operations	vxfs_dir_inode_ops;
+extern struct file_operations	vxfs_dir_operations;
+
+/* vxfs_olt.c */
+extern int			vxfs_read_olt(struct super_block *, u_long);
+
+/* vxfs_subr.c */
+extern struct buffer_head *	vxfs_bread(struct inode *, int);
+
+#endif /* _VXFS_EXTERN_H_ */
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_fshead.c linux/fs/freevxfs/vxfs_fshead.c
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_fshead.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_fshead.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#ident "$Id: vxfs_fshead.c,v 1.17 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - fileset header routines.
+ */
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "vxfs.h"
+#include "vxfs_inode.h"
+#include "vxfs_extern.h"
+#include "vxfs_fshead.h"
+
+
+#ifdef DIAGNOSTIC
+static void
+vxfs_dumpfsh(struct vxfs_fsh *fhp)
+{
+	printk("\n\ndumping fileset header:\n");
+	printk("----------------------------\n");
+	printk("version: %u\n", fhp->fsh_version);
+	printk("fsindex: %u\n", fhp->fsh_fsindex);
+	printk("iauino: %u\tninodes:%u\n",
+			fhp->fsh_iauino, fhp->fsh_ninodes);
+	printk("maxinode: %u\tlctino: %u\n",
+			fhp->fsh_maxinode, fhp->fsh_lctino);
+	printk("nau: %u\n", fhp->fsh_nau);
+	printk("ilistino[0]: %u\tilistino[1]: %u\n",
+			fhp->fsh_ilistino[0], fhp->fsh_ilistino[1]);
+}
+#endif
+
+/**
+ * vxfs_getfsh - read fileset header into memory
+ * @ip:		the (fake) fileset header inode
+ * @which:	0 for the structural, 1 for the primary fsh.
+ *
+ * Description:
+ *   vxfs_getfsh reads either the structural or primary fileset header
+ *   described by @ip into memory.
+ *
+ * Returns:
+ *   The fileset header structure on success, else Zero.
+ */
+static struct vxfs_fsh *
+vxfs_getfsh(struct inode *ip, int which)
+{
+	struct buffer_head		*bp;
+
+	bp = vxfs_bread(ip, which);
+	if (buffer_mapped(bp)) {
+		struct vxfs_fsh		*fhp;
+
+		if (!(fhp = kmalloc(sizeof(struct vxfs_fsh), SLAB_KERNEL)))
+			return NULL;
+		memcpy(fhp, bp->b_data, sizeof(struct vxfs_fsh));
+
+		brelse(bp);
+		return (fhp);
+	}
+
+	return NULL;
+}
+
+/**
+ * vxfs_read_fshead - read the fileset headers
+ * @sbp:	superblock to which the fileset belongs
+ *
+ * Description:
+ *   vxfs_read_fshead will fill the inode and structural inode list in @sb.
+ *
+ * Returns:
+ *   Zero on success, else a negative error code (-EINVAL).
+ */
+int
+vxfs_read_fshead(struct super_block *sbp)
+{
+	struct vxfs_sb_info		*infp = VXFS_SBI(sbp);
+	struct vxfs_fsh			*pfp, *sfp;
+	struct vxfs_inode_info		*vip, *tip;
+
+	if (!(vip = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino))) {
+		printk(KERN_ERR "vxfs: unabled to read fsh inode\n");
+		return -EINVAL;
+	} else if (!VXFS_ISFSH(vip)) {
+		printk(KERN_ERR "vxfs: fsh list inode is of wrong type (%x)\n",
+				vip->vii_mode & VXFS_TYPE_MASK); 
+		return -EINVAL;
+	}
+
+
+#ifdef DIAGNOSTIC
+	printk("vxfs: fsh inode dump:\n");
+	vxfs_dumpi(vip, infp->vsi_fshino);
+#endif
+
+	if (!(infp->vsi_fship = vxfs_fake_inode(sbp, vip))) {
+		printk(KERN_ERR "vxfs: unabled to get fsh inode\n");
+		return -EINVAL;
+	}
+
+	if (!(sfp = vxfs_getfsh(infp->vsi_fship, 0))) {
+		printk(KERN_ERR "vxfs: unabled to get structural fsh\n");
+		return -EINVAL;
+	} 
+
+#ifdef DIAGNOSTIC
+	vxfs_dumpfsh(sfp);
+#endif
+
+	if (!(pfp = vxfs_getfsh(infp->vsi_fship, 1))) {
+		printk(KERN_ERR "vxfs: unabled to get primary fsh\n");
+		return -EINVAL;
+	}
+
+#ifdef DIAGNOSTIC
+	vxfs_dumpfsh(pfp);
+#endif
+
+	tip = vxfs_blkiget(sbp, infp->vsi_iext, sfp->fsh_ilistino[0]);
+	if (!tip || ((infp->vsi_stilist = vxfs_fake_inode(sbp, tip)) == NULL)) {
+		printk(KERN_ERR "vxfs: unabled to get structual list inode\n");
+		return -EINVAL;
+	} else if (!VXFS_ISILT(VXFS_INO(infp->vsi_stilist))) {
+		printk(KERN_ERR "vxfs: structual list inode is of wrong type (%x)\n",
+				VXFS_INO(infp->vsi_stilist)->vii_mode & VXFS_TYPE_MASK); 
+		return -EINVAL;
+	}
+
+	tip = vxfs_stiget(sbp, pfp->fsh_ilistino[0]);
+	if (!tip || ((infp->vsi_ilist = vxfs_fake_inode(sbp, tip)) == NULL)) {
+		printk(KERN_ERR "vxfs: unabled to get inode list inode\n");
+		return -EINVAL;
+	} else if (!VXFS_ISILT(VXFS_INO(infp->vsi_ilist))) {
+		printk(KERN_ERR "vxfs: inode list inode is of wrong type (%x)\n",
+				VXFS_INO(infp->vsi_ilist)->vii_mode & VXFS_TYPE_MASK);
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_fshead.h linux/fs/freevxfs/vxfs_fshead.h
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_fshead.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_fshead.h	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ */
+#ifndef _VXFS_FSHEAD_H_
+#define _VXFS_FSHEAD_H_
+
+#ident "$Id: vxfs_fshead.h,v 1.5 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - fileset header structures.
+ *
+ * This file contains the physical structure of the VxFS
+ * fileset header.
+ */
+
+
+/*
+ * Fileset header 
+ */
+struct vxfs_fsh {
+	u_int32_t	fsh_version;			/* Fileset header version */
+	u_int32_t	fsh_fsindex;
+	u_int32_t	fsh_time;
+	u_int32_t	fsh_utime;
+	u_int32_t	fsh_extop;
+	vx_ino_t	fsh_ninodes;
+	u_int32_t	fsh_nau;
+	u_int32_t	fsh_old_ilesize;
+	u_int32_t	fsh_dflags;
+	u_int32_t	fsh_quota;
+	vx_ino_t	fsh_maxinode;
+	vx_ino_t	fsh_iauino;
+	vx_ino_t	fsh_ilistino[2];
+	vx_ino_t	fsh_lctino;
+
+	/*
+	 * Slightly more fields follow, but they
+	 *  a) are not of any interested for us, and
+	 *  b) differ much in different vxfs versions/ports
+	 */
+};
+
+#endif /* _VXFS_FSHEAD_H_ */
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_immed.c linux/fs/freevxfs/vxfs_immed.c
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_immed.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_immed.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#ident "$Id: vxfs_immed.c,v 1.9 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - support for 'immed' inodes.
+ */
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+
+#include "vxfs.h"
+#include "vxfs_inode.h"
+
+
+static int	vxfs_immed_readlink(struct dentry *, char *, int);
+static int	vxfs_immed_follow_link(struct dentry *, struct nameidata *);
+
+static int	vxfs_immed_readpage(struct file *, struct page *);
+
+/*
+ * Inode operations for immed symlinks.
+ *
+ * Unliked all other operations we do not go through the pagecache,
+ * but do all work directly on the inode.
+ */
+struct inode_operations vxfs_immed_symlink_iops = {
+	.readlink =		vxfs_immed_readlink,
+	.follow_link =		vxfs_immed_follow_link,
+};
+
+/*
+ * Adress space operations for immed files and directories.
+ */
+struct address_space_operations vxfs_immed_aops = {
+	.readpage =		vxfs_immed_readpage,
+};
+
+
+/**
+ * vxfs_immed_readlink - read immed symlink
+ * @dp:		dentry for the link
+ * @bp:		output buffer
+ * @buflen:	length of @bp
+ *
+ * Description:
+ *   vxfs_immed_readlink calls vfs_readlink to read the link
+ *   described by @dp into userspace.
+ *
+ * Returns:
+ *   Number of bytes successfully copied to userspace.
+ */
+static int
+vxfs_immed_readlink(struct dentry *dp, char *bp, int buflen)
+{
+	struct vxfs_inode_info		*vip = VXFS_INO(dp->d_inode);
+
+	return (vfs_readlink(dp, bp, buflen, vip->vii_immed.vi_immed));
+}
+
+/**
+ * vxfs_immed_follow_link - follow immed symlink
+ * @dp:		dentry for the link
+ * @np:		pathname lookup data for the current path walk
+ *
+ * Description:
+ *   vxfs_immed_follow_link restarts the pathname lookup with
+ *   the data obtained from @dp.
+ *
+ * Returns:
+ *   Zero on success, else a negative error code.
+ */
+static int
+vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np)
+{
+	struct vxfs_inode_info		*vip = VXFS_INO(dp->d_inode);
+
+	return (vfs_follow_link(np, vip->vii_immed.vi_immed));
+}
+
+/**
+ * vxfs_immed_readpage - read part of an immed inode into pagecache
+ * @file:	file context (unused)
+ * @page:	page frame to fill in.
+ *
+ * Description:
+ *   vxfs_immed_readpage reads a part of the immed area of the
+ *   file that hosts @pp into the pagecache.
+ *
+ * Returns:
+ *   Zero on success, else a negative error code.
+ *
+ * Locking status:
+ *   @page is locked and will be unlocked.
+ */
+static int
+vxfs_immed_readpage(struct file *fp, struct page *pp)
+{
+	struct vxfs_inode_info	*vip = VXFS_INO(pp->mapping->host);
+	u_int64_t		offset = pp->index << PAGE_CACHE_SHIFT;
+	caddr_t			kaddr;
+
+	kaddr = kmap(pp);
+	memcpy(kaddr, vip->vii_immed.vi_immed + offset, PAGE_CACHE_SIZE);
+	kunmap(pp);
+	
+	flush_dcache_page(pp);
+	SetPageUptodate(pp);
+        UnlockPage(pp);
+
+	return 0;
+}
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_inode.c linux/fs/freevxfs/vxfs_inode.c
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_inode.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_inode.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#ident "$Id: vxfs_inode.c,v 1.29 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - inode routines.
+ */
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "vxfs.h"
+#include "vxfs_inode.h"
+#include "vxfs_extern.h"
+
+
+extern struct address_space_operations vxfs_aops;
+extern struct address_space_operations vxfs_immed_aops;
+
+extern struct inode_operations vxfs_immed_symlink_iops;
+
+static struct file_operations vxfs_file_operations = {
+	.read =			generic_file_read,
+	.mmap =			generic_file_mmap,
+};
+
+
+kmem_cache_t		*vxfs_inode_cachep;
+
+
+#ifdef DIAGNOSTIC
+/*
+ * Dump inode contents (partially).
+ */
+void
+vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
+{
+	printk(KERN_DEBUG "\n\n");
+	if (ino)
+		printk(KERN_DEBUG "dumping vxfs inode %ld\n", ino);
+	else
+		printk(KERN_DEBUG "dumping unknown vxfs inode\n");
+
+	printk(KERN_DEBUG "---------------------------\n");
+	printk(KERN_DEBUG "mode is %x\n", vip->vii_mode);
+	printk(KERN_DEBUG "nlink:%u    uid:%u   gid:%u\n",
+			vip->vii_nlink, vip->vii_uid, vip->vii_gid);
+	printk(KERN_DEBUG "size=%Lx  blocks=%u\n",
+			vip->vii_size, vip->vii_blocks);
+	printk(KERN_DEBUG "orgtype=%u\n", vip->vii_orgtype);
+}
+#endif
+
+
+/**
+ * vxfs_iget - find inode based on extent #
+ * @sbp:	superblock of the filesystem we search in
+ * @extent:	number of the extent to search
+ * @ino:	inode number to search
+ *
+ * Description:
+ *   vxfs_iget searches inode @ino in the filesystem described by
+ *   @sbp in the extent @extent.
+ *
+ * Returs:
+ *   The matching VxFS inode on success, else a NULL pointer.
+ */
+struct vxfs_inode_info *
+vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino)
+{
+	struct buffer_head		*bp;
+	u_long				block, offset;
+
+	block = extent + ((ino * VXFS_ISIZE) / sbp->s_blocksize);
+	offset = ((ino % (sbp->s_blocksize / VXFS_ISIZE)) * VXFS_ISIZE);
+	bp = bread(sbp->s_dev, block, sbp->s_blocksize);
+
+	if (buffer_mapped(bp)) {
+		struct vxfs_inode_info	*vip;
+		struct vxfs_dinode	*dip;
+
+		if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, SLAB_KERNEL)))
+			goto fail;
+		dip = (struct vxfs_dinode *)(bp->b_data + offset);
+		memcpy(vip, dip, sizeof(struct vxfs_inode_info));
+#ifdef DIAGNOSTIC
+		vxfs_dumpi(vip, ino);
+#endif
+		brelse(bp);
+		return (vip);
+	}
+
+fail:
+	printk(KERN_WARNING "vxfs: unable to read block %ld\n", block);
+	brelse(bp);
+	return NULL;
+}
+
+/**
+ * __vxfs_iget - generic find inode facility
+ * @sbp:		VFS superblock
+ * @ino:		inode number
+ * @ilistp:		inode list
+ *
+ * Description:
+ *   __vxfs_iget searches for @ino in the inode list @ilistp
+ *   of the filesystem described by @sbp.
+ *
+ * Returns:
+ *   The matching VxFS inode on success, else a NULL pointer.
+ */
+static struct vxfs_inode_info *
+__vxfs_iget(struct super_block *sbp, ino_t ino, struct inode *ilistp)
+{
+	struct buffer_head		*bp;
+	u_long				offset;
+
+	offset = (ino % (sbp->s_blocksize / VXFS_ISIZE)) * VXFS_ISIZE;
+	bp = vxfs_bread(ilistp, ino * VXFS_ISIZE / sbp->s_blocksize);
+
+	if (buffer_mapped(bp)) {
+		struct vxfs_inode_info	*vip;
+		struct vxfs_dinode	*dip;
+
+		if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, SLAB_KERNEL)))
+			goto fail;
+		dip = (struct vxfs_dinode *)(bp->b_data + offset);
+		memcpy(vip, dip, sizeof(struct vxfs_inode_info));
+#ifdef DIAGNOSTIC
+		vxfs_dumpi(vip, ino);
+#endif
+		brelse(bp);
+		return (vip);
+	}
+
+fail:
+	printk(KERN_WARNING "vxfs: unable to read inode %ld\n", ino);
+	brelse(bp);
+	return NULL;
+}
+
+/**
+ * vxfs_iget - find inode using the inode list
+ * @sbp:	VFS superblock
+ * @ino:	inode #
+ *
+ * Description:
+ *  Find inode @ino in the filesystem described by @sbp using
+ *  the inode list.
+ *
+ * Returns:
+ *   The matching VxFS inode on success, else a NULL pointer.
+ */
+static struct vxfs_inode_info *
+vxfs_iget(struct super_block *sbp, ino_t ino)
+{
+        return __vxfs_iget(sbp, ino, VXFS_SBI(sbp)->vsi_ilist);
+}
+
+/**
+ * vxfs_stiget - find inode using the structural inode list
+ * @sbp:	VFS superblock
+ * @ino:	inode #
+ *
+ * Description:
+ *  Find inode @ino in the filesystem described by @sbp using
+ *  the structural inode list.
+ *
+ * Returns:
+ *   The matching VxFS inode on success, else a NULL pointer.
+ */
+struct vxfs_inode_info *
+vxfs_stiget(struct super_block *sbp, ino_t ino)
+{
+        return __vxfs_iget(sbp, ino, VXFS_SBI(sbp)->vsi_stilist);
+}
+
+/**
+ * vxfs_transmod - mode for a VxFS inode
+ * @vip:	VxFS inode
+ *
+ * Description:
+ *   vxfs_transmod returns a Linux mode_t for a given
+ *   VxFS inode structure.
+ *
+ * Notes:
+ *   Use a table instead?
+ */
+static __inline__ mode_t
+vxfs_transmod(struct vxfs_inode_info *vip)
+{
+	mode_t			ret = vip->vii_mode & ~VXFS_TYPE_MASK;
+
+	if (VXFS_ISFIFO(vip))
+		ret |= S_IFIFO;
+	if (VXFS_ISCHR(vip))
+		ret |= S_IFCHR;
+	if (VXFS_ISDIR(vip))
+		ret |= S_IFDIR;
+	if (VXFS_ISBLK(vip))
+		ret |= S_IFBLK;
+	if (VXFS_ISLNK(vip))
+		ret |= S_IFLNK;
+	if (VXFS_ISREG(vip))
+		ret |= S_IFREG;
+	if (VXFS_ISSOC(vip))
+		ret |= S_IFSOCK;
+
+	return (ret);
+}
+
+/**
+ * vxfs_iinit- helper to fill inode fields
+ * @ip:		VFS inode
+ * @vip:	VxFS inode
+ *
+ * Description:
+ *   vxfs_instino is a helper function to fill in all relevant
+ *   fields in @ip from @vip.
+ */
+static void
+vxfs_iinit(struct inode *ip, struct vxfs_inode_info *vip)
+{
+
+	ip->i_mode = vxfs_transmod(vip);
+	ip->i_uid = (uid_t)vip->vii_uid;
+	ip->i_gid = (gid_t)vip->vii_gid;
+
+	ip->i_nlink = vip->vii_nlink;
+	ip->i_size = vip->vii_size;
+
+	ip->i_atime = vip->vii_atime;
+	ip->i_ctime = vip->vii_ctime;
+	ip->i_mtime = vip->vii_mtime;
+
+	ip->i_blksize = PAGE_SIZE;
+	ip->i_blocks = vip->vii_blocks;
+	ip->i_generation = vip->vii_gen;
+
+	ip->u.generic_ip = (void *)vip;
+	
+}
+
+/**
+ * vxfs_fake_inode - get fake inode structure
+ * @sbp:		filesystem superblock
+ * @vip:		fspriv inode
+ *
+ * Description:
+ *   vxfs_fake_inode gets a fake inode (not in the inode hash) for a
+ *   superblock, vxfs_inode pair.
+ *
+ * Returns:
+ *   VFS inode structure filled in.
+ */
+struct inode *
+vxfs_fake_inode(struct super_block *sbp, struct vxfs_inode_info *vip)
+{
+	struct inode			*ip;
+
+	if (!(ip = get_empty_inode()))
+		return NULL;
+
+	ip->i_sb = sbp;
+	ip->i_dev = sbp->s_dev;
+	vxfs_iinit(ip, vip);
+
+	return (ip);
+}
+
+/**
+ * vxfs_read_inode - fill in inode information
+ * @ip:		inode pointer to fill
+ *
+ * Description:
+ *   vxfs_read_inode reads the disk inode for @ip and fills
+ *   in all relevant fields in @ip.
+ *
+ * Locking:
+ *   We are under the bkl.
+ */
+void
+vxfs_read_inode(struct inode *ip)
+{
+	struct super_block		*sbp = ip->i_sb;
+	struct vxfs_inode_info		*vip;
+	struct address_space_operations	*aops;
+	ino_t				ino = ip->i_ino;
+
+	if (!(vip = vxfs_iget(sbp, ino)))
+		return;
+
+	vxfs_iinit(ip, vip);
+
+	if (VXFS_ISIMMED(vip))
+		aops = &vxfs_immed_aops;
+	else
+		aops = &vxfs_aops;
+
+	if (S_ISREG(ip->i_mode)) {
+		ip->i_fop = &vxfs_file_operations;
+		ip->i_mapping->a_ops = aops;
+	} else if (S_ISDIR(ip->i_mode)) {
+		ip->i_op = &vxfs_dir_inode_ops;
+		ip->i_fop = &vxfs_dir_operations;
+		ip->i_mapping->a_ops = aops;
+	} else if (S_ISLNK(ip->i_mode)) {
+		if (!VXFS_ISIMMED(vip)) {
+			ip->i_op = &page_symlink_inode_operations;
+			ip->i_mapping->a_ops = &vxfs_aops;
+		} else
+			ip->i_op = &vxfs_immed_symlink_iops;
+	} else
+		init_special_inode(ip, ip->i_mode, vip->vii_rdev);
+
+	return;
+}
+
+/**
+ * vxfs_put_inode - remove inode from main memory
+ * @ip:		inode to discard.
+ *
+ * Description:
+ *   vxfs_put_inode() is called on each iput.  If we are the last
+ *   link in memory, free the fspriv inode area.
+ *
+ * Locking:
+ *   No lock is held on entry.
+ */
+void
+vxfs_put_inode(struct inode *ip)
+{
+	if (atomic_read(&ip->i_count) == 1)
+		kmem_cache_free(vxfs_inode_cachep, ip->u.generic_ip);
+}
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_inode.h linux/fs/freevxfs/vxfs_inode.h
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_inode.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_inode.h	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ */
+#ifndef _VXFS_INODE_H_
+#define _VXFS_INODE_H_
+
+#ident "$Id: vxfs_inode.h,v 1.13 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - inode structure.
+ *
+ * This file contains the definition of the disk and core
+ * inodes of the Veritas Filesystem.
+ */
+
+
+#define VXFS_ISIZE		0x100		/* Inode size */
+
+#define VXFS_NDADDR		10		/* Number of direct addrs in inode */
+#define VXFS_NIADDR		2		/* Number of indirect addrs in inode */
+#define VXFS_NIMMED		96		/* Size of immediate data in inode */
+#define VXFS_NTYPED		6		/* Num of typed extents */
+
+#define VXFS_TYPED_OFFSETMASK	(0x00FFFFFFFFFFFFFFULL)
+#define VXFS_TYPED_TYPEMASK	(0xFF00000000000000ULL)
+#define VXFS_TYPED_TYPESHIFT	56
+
+#define VXFS_TYPED_PER_BLOCK(sbp) \
+	((sbp)->s_blocksize / sizeof(struct vxfs_typed))
+
+/*
+ * Possible extent descriptor types for %VXFS_ORG_TYPED extents.
+ */
+enum {
+	VXFS_TYPED_INDIRECT		= 1,
+	VXFS_TYPED_DATA			= 2,
+	VXFS_TYPED_INDIRECT_DEV4	= 3,
+	VXFS_TYPED_DATA_DEV4		= 4,
+};
+
+/*
+ * Data stored immediately in the inode.
+ */
+struct vxfs_immed {
+	u_int8_t	vi_immed[VXFS_NIMMED];
+};
+
+struct vxfs_ext4 {
+	u_int32_t		ve4_spare;		/* ?? */
+	u_int32_t		ve4_indsize;		/* Indirect extent size */
+	vx_daddr_t		ve4_indir[VXFS_NIADDR];	/* Indirect extents */
+	struct direct {					/* Direct extents */
+		vx_daddr_t	extent;			/* Extent number */
+		u_int32_t	size;			/* Size of extent */
+	} ve4_direct[VXFS_NDADDR];
+};
+
+struct vxfs_typed {
+	u_int64_t	vt_hdr;		/* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
+	vx_daddr_t	vt_block;	/* Extent block */
+	int32_t		vt_size;	/* Size in blocks */
+};
+
+struct vxfs_typed_dev4 {
+	u_int64_t	vd4_hdr;	/* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
+	u_int64_t	vd4_block;	/* Extent block */
+	u_int64_t	vd4_size;	/* Size in blocks */
+	int32_t		vd4_dev;	/* Device ID */
+	u_int32_t	__pad1;
+};
+
+/*
+ * The inode as contained on the physical device.
+ */
+struct vxfs_dinode {
+	int32_t		vdi_mode;
+	u_int32_t	vdi_nlink;	/* Link count */
+	u_int32_t	vdi_uid;	/* UID */
+	u_int32_t	vdi_gid;	/* GID */
+	u_int64_t	vdi_size;	/* Inode size in bytes */
+	u_int32_t	vdi_atime;	/* Last time accessed - sec */
+	u_int32_t	vdi_autime;	/* Last time accessed - usec */
+	u_int32_t	vdi_mtime;	/* Last modify time - sec */
+	u_int32_t	vdi_mutime;	/* Last modify time - usec */
+	u_int32_t	vdi_ctime;	/* Create time - sec */
+	u_int32_t	vdi_cutime;	/* Create time - usec */
+	u_int8_t	vdi_aflags;	/* Allocation flags */
+	u_int8_t	vdi_orgtype;	/* Organisation type */
+	u_int16_t	vdi_eopflags;
+	u_int32_t	vdi_eopdata;
+	union {
+		u_int32_t		rdev;
+		u_int32_t		dotdot;
+		struct {
+			u_int32_t	reserved;
+			u_int32_t	fixextsize;
+		} i_regular;
+		struct {
+			u_int32_t	matchino;
+			u_int32_t	fsetindex;
+		} i_vxspec;
+		u_int64_t		align;
+	} vdi_ftarea;
+	u_int32_t	vdi_blocks;	/* How much blocks does inode occupy */
+	u_int32_t	vdi_gen;	/* Inode generation */
+	u_int64_t	vdi_version;	/* Version */
+	union {
+		struct vxfs_immed	immed;
+		struct vxfs_ext4	ext4;
+		struct vxfs_typed	typed[VXFS_NTYPED];
+	} vdi_org;
+	u_int32_t	vdi_iattrino;
+};
+
+#define vdi_rdev	vdi_ftarea.rdev
+#define vdi_dotdot	vdi_ftarea.dotdot
+#define vdi_fixextsize	vdi_ftarea.regular.fixextsize
+#define vdi_matchino	vdi_ftarea.vxspec.matchino
+#define vdi_fsetindex	vdi_ftarea.vxspec.fsetindex
+
+#define vdi_immed	vdi_org.immed
+#define vdi_ext4	vdi_org.ext4
+#define vdi_typed	vdi_org.typed
+
+
+/*
+ * The inode as represented in the main memory.
+ *
+ * TBD: This should become a separate structure...
+ */
+#define vxfs_inode_info	vxfs_dinode
+
+#define vii_mode	vdi_mode
+#define vii_uid		vdi_uid
+#define vii_gid		vdi_gid
+#define vii_nlink	vdi_nlink
+#define vii_size	vdi_size
+#define vii_atime	vdi_atime
+#define vii_ctime	vdi_ctime
+#define vii_mtime	vdi_mtime
+#define vii_blocks	vdi_blocks
+#define vii_org		vdi_org
+#define vii_orgtype	vdi_orgtype
+#define vii_gen		vdi_gen
+
+#define vii_rdev	vdi_ftarea.rdev
+#define vii_dotdot	vdi_ftarea.dotdot
+#define vii_fixextsize	vdi_ftarea.regular.fixextsize
+#define vii_matchino	vdi_ftarea.vxspec.matchino
+#define vii_fsetindex	vdi_ftarea.vxspec.fsetindex
+
+#define vii_immed	vdi_org.immed
+#define vii_ext4	vdi_org.ext4
+#define vii_typed	vdi_org.typed
+
+#endif /* _VXFS_INODE_H_ */
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_lookup.c linux/fs/freevxfs/vxfs_lookup.c
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_lookup.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_lookup.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#ident "$Id: vxfs_lookup.c,v 1.11 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - lookup and other directory related code.
+ */
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/kernel.h>
+#include <linux/pagemap.h>
+
+#include "vxfs.h"
+#include "vxfs_dir.h"
+#include "vxfs_inode.h"
+
+/*
+ * Number of VxFS blocks per page.
+ */
+#define VXFS_BLOCK_PER_PAGE(sbp)  ((PAGE_CACHE_SIZE / (sbp)->s_blocksize))
+
+
+static struct dentry *	vxfs_lookup(struct inode *, struct dentry *);
+static int		vxfs_readdir(struct file *, void *, filldir_t);
+
+struct inode_operations vxfs_dir_inode_ops = {
+	.lookup =		vxfs_lookup,
+};
+
+struct file_operations vxfs_dir_operations = {
+	.readdir =		vxfs_readdir,
+};
+
+
+static __inline__ void
+vxfs_put_page(struct page *page)
+{
+	kunmap(page);
+	page_cache_release(page);
+}
+ 
+static __inline__ u_long
+dir_pages(struct inode *inode)
+{
+	return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+}
+ 
+static __inline__ u_long
+dir_blocks(struct inode *ip)
+{
+	u_long			bsize = ip->i_sb->s_blocksize;
+	return (ip->i_size + bsize - 1) & ~(bsize - 1);
+}
+
+/**
+ * vxfs_get_page - read a page into memory.
+ * @ip:		inode to read from
+ * @n:		page number
+ *
+ * Description:
+ *   vxfs_get_page reads the @n th page of @ip into the pagecache.
+ *
+ * Returns:
+ *   The wanted page on success, else a NULL pointer.
+ */
+static struct page *
+vxfs_get_page(struct inode *dir, u_long n)
+{
+	struct address_space *		mapping = dir->i_mapping;
+	struct page *			page;
+
+	page = read_cache_page(mapping, n,
+			(filler_t*)mapping->a_ops->readpage, NULL);
+
+	if (!IS_ERR(page)) {
+		wait_on_page(page);
+		kmap(page);
+		if (!Page_Uptodate(page))
+			goto fail;
+		/** if (!PageChecked(page)) **/
+			/** vxfs_check_page(page); **/
+		if (PageError(page))
+			goto fail;
+	}
+	
+	return (page);
+		 
+fail:
+	vxfs_put_page(page);
+	return ERR_PTR(-EIO);
+}
+
+/*
+ * NOTE! unlike strncmp, vxfs_match returns 1 for success, 0 for failure.
+ *
+ * len <= VXFS_NAME_LEN and de != NULL are guaranteed by caller.
+ */
+static __inline__ int
+vxfs_match(int len, const char * const name, struct vxfs_direct *de)
+{
+	if (len != de->d_namelen)
+		return 0;
+	if (!de->d_ino)
+		return 0;
+	return !memcmp(name, de->d_name, len);
+}
+
+static __inline__ struct vxfs_direct *
+vxfs_next_entry(struct vxfs_direct *de)
+{
+	return ((struct vxfs_direct *)((char*)de + de->d_reclen));
+}
+
+/**
+ * vxfs_find_entry - find a mathing directory entry for a dentry
+ * @ip:		directory inode
+ * @dp:		dentry for which we want to find a direct
+ * @ppp:	gets filled with the page the return value sits in
+ *
+ * Description:
+ *   vxfs_find_entry finds a &struct vxfs_direct for the VFS directory
+ *   cache entry @dp.  @ppp will be filled with the page the return
+ *   value resides in.
+ *
+ * Returns:
+ *   The wanted direct on success, else a NULL pointer.
+ */
+static struct vxfs_direct *
+vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
+{
+	const char			*name = dp->d_name.name;
+	u_long				npages = dir_pages(ip), n, i;
+	u_long				bsize = ip->i_sb->s_blocksize;
+	int				namelen = dp->d_name.len;
+	loff_t				pos = ip->i_size - 2;
+	struct vxfs_direct		*de;
+	struct page			*pp;
+	
+	
+	for (n = 0; n < npages; n++) {
+		char			*kaddr;
+		u_long			max;
+
+		pp = vxfs_get_page(ip, n);
+		if (IS_ERR(pp))
+			continue;
+
+		kaddr = (char *)page_address(pp);
+		max = (pos + bsize - 1) & ~(bsize - 1);
+
+		for (i = 0; i <= (PAGE_CACHE_SIZE / bsize) && i <= max; i++) {
+			struct vxfs_dirblk	*blp;
+			char			*lim;
+
+			blp = (struct vxfs_dirblk *)(kaddr + (i * bsize));
+			de = (struct vxfs_direct *)((char *)blp + (2 * blp->d_nhash) + 4);
+			
+			/*
+			 * The magic number 48 stands for the reclen offset
+			 * in the direct plus the size of reclen.
+			 */
+			lim = (char *)blp + bsize - 48;
+
+			do {
+				if ((char *)de > lim)
+					break;
+				if ((char *)de + de->d_reclen > lim)
+					break;
+				if (!de->d_reclen)
+					break;
+				if (vxfs_match(namelen, name, de))
+					goto found;
+			} while ((de = vxfs_next_entry(de)) != NULL);
+		}
+		vxfs_put_page(pp);
+	}
+
+	return NULL;
+
+found:
+	*ppp = pp;
+	return (de);
+}
+
+/**
+ * vxfs_inode_by_name - find inode number for dentry
+ * @dip:	directory to search in
+ * @dp:		dentry we seach for
+ *
+ * Description:
+ *   vxfs_inode_by_name finds out the inode number of
+ *   the path component described by @dp in @dip.
+ *
+ * Returns:
+ *   The wanted inode number on success, else Zero.
+ */
+static ino_t
+vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
+{
+	struct vxfs_direct		*de;
+	struct page			*pp;
+	ino_t				ino = 0;
+
+	de = vxfs_find_entry(dip, dp, &pp);
+	if (de) {
+		ino = de->d_ino;
+		kunmap(pp);
+		page_cache_release(pp);
+	}
+	
+	return (ino);
+}
+
+/**
+ * vxfs_lookup - lookup pathname component
+ * @dip:	dir in which we lookup
+ * @dp:		dentry we lookup
+ *
+ * Description:
+ *   vxfs_lookup tries to lookup the pathname component described
+ *   by @dp in @dip.
+ *
+ * Returns:
+ *   A NULL-pointer on success, else an negative error code encoded
+ *   in the return pointer.
+ */
+static struct dentry *
+vxfs_lookup(struct inode *dip, struct dentry *dp)
+{
+	struct inode		*ip = NULL;
+	ino_t			ino;
+			 
+	if (dp->d_name.len > VXFS_NAME_LEN)
+		return ERR_PTR(-ENAMETOOLONG);
+				 
+	ino = vxfs_inode_by_name(dip, dp);
+	if (ino == 0)
+		return NULL;
+
+	ip = iget(dip->i_sb, ino);
+	if (!ip)
+		return ERR_PTR(-EACCES);
+	d_add(dp, ip);
+	return NULL;
+}
+
+/**
+ * vxfs_readdir - read a directory
+ * @fp:		the directory to read
+ * @retp:	return buffer
+ * @filler:	filldir callback
+ *
+ * Description:
+ *   vxfs_readdir fills @retp with directory entries from @fp
+ *   using the VFS supplied callback @filler.
+ *
+ * Returns:
+ *   Zero.
+ */
+static int
+vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
+{
+	struct inode		*ip = fp->f_dentry->d_inode;
+	struct super_block	*sbp = ip->i_sb;
+	u_long			bsize = sbp->s_blocksize;
+	u_long			page, npages, block, nblocks, offset;
+	loff_t			pos;
+	int			pblocks;
+
+	switch ((long)fp->f_pos) {
+	case 0:
+		if (filler(retp, ".", 1, fp->f_pos, ip->i_ino, DT_DIR) < 0)
+			goto out;
+		fp->f_pos++;
+		/* fallthrough */
+	case 1:
+		if (filler(retp, "..", 2, fp->f_pos, VXFS_INO(ip)->vii_dotdot, DT_DIR) < 0)
+			goto out;
+		fp->f_pos++;
+		/* fallthrough */
+	}
+
+	if (fp->f_pos >= ip->i_size)
+		goto out;
+	
+	pos = fp->f_pos - 2;
+	offset = pos & ~PAGE_CACHE_MASK;
+	page = pos >> PAGE_CACHE_SHIFT;
+	block = pos & (sbp->s_blocksize - 1);
+
+	npages = dir_pages(ip);
+	nblocks = dir_blocks(ip);
+	pblocks = VXFS_BLOCK_PER_PAGE(sbp);
+
+	for (; page < npages; page++, offset = 0) {
+		char			*kaddr, *lim;
+		struct vxfs_dirblk	*dblkp;
+		struct vxfs_direct	*de;
+		struct page		*pp;
+
+		pp = vxfs_get_page(ip, page);
+		if (IS_ERR(pp))
+			continue;
+
+		kaddr = (char *)page_address(pp);
+
+		for (; block <= nblocks && block <= pblocks; block++) {
+			dblkp = (struct vxfs_dirblk *)
+				(kaddr + (block * bsize));
+			de = (struct vxfs_direct *)
+				((char *)dblkp + (2 * dblkp->d_nhash) + 4);
+			
+			/*
+			 * The magic number 48 stands for the reclen offset
+			 * in the direct plus the size of reclen.
+			 */
+			lim = (char *)dblkp + bsize - 48;
+
+			do {
+				int	over;
+
+				if ((char *)de > lim)
+					break;
+				if ((char *)de + de->d_reclen > lim)
+					break;
+				if (!de->d_reclen)
+					break;
+				if (!de->d_ino)
+					continue;
+
+				offset = (char *)de - kaddr;
+
+				over = filler(retp, de->d_name, de->d_namelen,
+						(page << PAGE_CACHE_SHIFT) | offset,
+						de->d_ino, DT_UNKNOWN);
+				if (over) {
+					vxfs_put_page(pp);
+					goto done;
+				}
+			} while ((de = vxfs_next_entry(de)) != NULL);
+		}
+
+		vxfs_put_page(pp);
+		block = 0;
+	}
+
+done:
+	fp->f_pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
+out:
+	fp->f_version = ip->i_version;
+	return 0;
+}
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_olt.c linux/fs/freevxfs/vxfs_olt.c
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_olt.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_olt.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#ident "$Id: vxfs_olt.c,v 1.7 2001/04/24 19:28:36 hch Exp hch $"
+
+/* 
+ * Veritas filesystem driver - object location table support.
+ */
+#include <linux/fs.h>
+#include <linux/kernel.h>
+
+#include "vxfs.h"
+#include "vxfs_olt.h"
+
+
+static __inline__ void
+vxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp)
+{
+	if (infp->vsi_fshino)
+		BUG();
+	infp->vsi_fshino = fshp->olt_fsino[0];
+}
+
+static __inline__ void
+vxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp)
+{
+	if (infp->vsi_iext)
+		BUG();
+	infp->vsi_iext = ilistp->olt_iext[0]; 
+}
+
+static __inline__ u_long
+vxfs_oblock(daddr_t oblock, u_long bsize)
+{
+	if ((oblock * BLOCK_SIZE) % bsize)
+		BUG();
+	return ((oblock * BLOCK_SIZE) / bsize);
+}
+
+
+/**
+ * vxfs_read_olt - read olt
+ * @sbp:	superblock of the filesystem
+ * @bsize:	blocksize of the filesystem
+ *
+ * Description:
+ *   vxfs_read_olt reads the olt of the filesystem described by @sbp
+ *   into main memory and does some basic setup.
+ *
+ * Returns:
+ *   Zero on success, else a negative error code.
+ */
+int
+vxfs_read_olt(struct super_block *sbp, u_long bsize)
+{
+	struct vxfs_sb_info	*infp = VXFS_SBI(sbp);
+	struct buffer_head	*bp;
+	struct vxfs_olt		*op;
+	char			*oaddr, *eaddr;
+
+
+	bp = bread(sbp->s_dev, vxfs_oblock(infp->vsi_oltext, bsize), bsize);
+	if (!bp || !bp->b_data)
+		goto fail;
+
+	op = (struct vxfs_olt *)bp->b_data;
+	if (op->olt_magic != VXFS_OLT_MAGIC) {
+		printk(KERN_NOTICE "vxfs: ivalid olt magic number\n");
+		goto fail;
+	}
+
+	oaddr = (char *)bp->b_data + op->olt_size;
+	eaddr = (char *)bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize);
+
+	while (oaddr < eaddr) {
+		struct vxfs_oltcommon	*ocp =
+			(struct vxfs_oltcommon *)oaddr;
+		
+		switch (ocp->olt_type) {
+		case VXFS_OLT_FSHEAD:
+			vxfs_get_fshead((struct vxfs_oltfshead *)oaddr, infp);
+			break;
+		case VXFS_OLT_ILIST:
+			vxfs_get_ilist((struct vxfs_oltilist *)oaddr, infp);
+			break;
+		}
+
+		oaddr += ocp->olt_size;
+	}
+
+	brelse(bp);
+	return 0;
+
+fail:
+	brelse(bp);
+	return -EINVAL;
+}
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_olt.h linux/fs/freevxfs/vxfs_olt.h
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_olt.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_olt.h	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ */
+#ifndef _VXFS_OLT_H_
+#define _VXFS_OLT_H_
+
+#ident "$Id: vxfs_olt.h,v 1.4 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - Object Location Table data structures.
+ *
+ * This file contains definitions for the Object Location Table used
+ * by the Veritas Filesystem version 2 and newer.
+ */
+
+
+/*
+ * OLT magic number (vxfs_olt->olt_magic).
+ */
+#define VXFS_OLT_MAGIC		0xa504FCF5
+
+/*
+ * VxFS OLT entry types.
+ */
+enum {
+	VXFS_OLT_FREE	= 1,
+	VXFS_OLT_FSHEAD	= 2,
+	VXFS_OLT_CUT	= 3,
+	VXFS_OLT_ILIST	= 4,
+	VXFS_OLT_DEV	= 5,
+	VXFS_OLT_SB	= 6
+};
+
+/*
+ * VxFS OLT header.
+ *
+ * The Object Location Table header is placed at the beginning of each
+ * OLT extent.  It is used to fing certain filesystem-wide metadata, e.g.
+ * the inital inode list, the fileset header or the device configuration.
+ */
+struct vxfs_olt {
+	u_int32_t	olt_magic;	/* magic number			*/
+	u_int32_t	olt_size;	/* size of this entry		*/
+	u_int32_t	olt_checksum;	/* checksum of extent		*/
+	u_int32_t	__unused1;	/* ???				*/
+	u_int32_t	olt_mtime;	/* time of last mod. (sec)	*/
+	u_int32_t	olt_mutime;	/* time of last mod. (usec)	*/
+	u_int32_t	olt_totfree;	/* free space in OLT extent	*/
+	vx_daddr_t	olt_extents[2];	/* addr of this extent, replica	*/
+	u_int32_t	olt_esize;	/* size of this extent		*/
+	vx_daddr_t	olt_next[2];    /* addr of next extent, replica	*/
+	u_int32_t	olt_nsize;	/* size of next extent		*/
+	u_int32_t	__unused2;	/* align to 8 byte boundary	*/
+};
+
+/*
+ * VxFS common OLT entry (on disk).
+ */
+struct vxfs_oltcommon {
+	u_int32_t	olt_type;	/* type of this record		*/
+	u_int32_t	olt_size;	/* size of this record		*/
+};
+
+/*
+ * VxFS free OLT entry (on disk).
+ */
+struct vxfs_oltfree {
+	u_int32_t	olt_type;	/* type of this record		*/
+	u_int32_t	olt_fsize;	/* size of this free record	*/
+};
+
+/*
+ * VxFS initial-inode list (on disk).
+ */
+struct vxfs_oltilist {
+	u_int32_t	olt_type;	/* type of this record		*/
+	u_int32_t	olt_size;	/* size of this record		*/
+	vx_ino_t	olt_iext[2];	/* initial inode list, replica	*/
+};
+
+/*
+ * Current Usage Table 
+ */
+struct vxfs_oltcut {
+	u_int32_t	olt_type;	/* type of this record		*/
+	u_int32_t	olt_size;	/* size of this record		*/
+	vx_ino_t	olt_cutino;	/* inode of current usage table	*/
+	u_int32_t	__pad;		/* unused, 8 byte align		*/
+};
+
+/*
+ * Inodes containing Superblock, Intent log and OLTs 
+ */
+struct vxfs_oltsb {
+	u_int32_t	olt_type;	/* type of this record		*/
+	u_int32_t	olt_size;	/* size of this record		*/
+	vx_ino_t	olt_sbino;	/* inode of superblock file	*/
+	u_int32_t	__unused1;	/* ???				*/
+	vx_ino_t	olt_logino[2];	/* inode of log file,replica	*/
+	vx_ino_t	olt_oltino[2];	/* inode of OLT, replica	*/
+};
+
+/*
+ * Inode containing device configuration + it's replica 
+ */
+struct vxfs_oltdev {
+	u_int32_t	olt_type;	/* type of this record		*/
+	u_int32_t	olt_size;	/* size of this record		*/
+	vx_ino_t	olt_devino[2];	/* inode of device config files	*/
+};
+
+/*
+ * Fileset header 
+ */
+struct vxfs_oltfshead {
+	u_int32_t	olt_type;	/* type number			*/
+	u_int32_t	olt_size;	/* size of this record		*/
+	vx_ino_t	olt_fsino[2];   /* inodes of fileset header	*/
+};
+
+#endif /* _VXFS_OLT_H_ */
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_subr.c linux/fs/freevxfs/vxfs_subr.c
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_subr.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_subr.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#ident "$Id: vxfs_subr.c,v 1.3 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - shared subroutines.
+ */
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "vxfs_extern.h"
+
+
+static int		vxfs_readpage(struct file *, struct page *);
+static int		vxfs_bmap(struct address_space *, long);
+
+struct address_space_operations vxfs_aops = {
+	.readpage =		vxfs_readpage,
+	.bmap =			vxfs_bmap
+};
+
+
+/**
+ * vxfs_bread - read buffer for a give inode,block tuple
+ * @ip:		inode
+ * @block:	logical block
+ *
+ * Description:
+ *   The vxfs_bread function performs a bmap operation for
+ *   the given inode and block and reads the result block
+ *   into main memory.
+ *
+ * Returns:
+ *   The resulting &struct buffer_head.
+ */
+struct buffer_head *
+vxfs_bread(struct inode *ip, int block)
+{
+	struct buffer_head	*bp;
+	daddr_t			pblock;
+
+	pblock = vxfs_bmap1(ip, block);
+	bp = bread(ip->i_dev, pblock, ip->i_sb->s_blocksize);
+
+	return (bp);
+}
+
+/**
+ * vxfs_get_block - locate buffer for given inode,block tuple 
+ * @ip:		inode
+ * @iblock:	logical block
+ * @bp:		buffer skeleton
+ * @create:	%TRUE if blocks may be newly allocated.
+ *
+ * Description:
+ *   The vxfs_get_block function fills @bp with the right physical
+ *   block and device number to perform a lowlevel read/write on
+ *   it.
+ *
+ * Returns:
+ *   Zero on success, else a negativ error code (-EIO).
+ */
+static int
+vxfs_getblk(struct inode *ip, long iblock,
+	    struct buffer_head *bp, int create)
+{
+	daddr_t			pblock;
+
+	pblock = vxfs_bmap1(ip, iblock);
+	if (pblock != 0) {
+		bp->b_dev = ip->i_dev;
+		bp->b_blocknr = pblock;
+		bp->b_state |= (1UL << BH_Mapped);
+
+		return 0;
+	}
+
+	return -EIO;
+}
+
+/**
+ * vxfs_readpage - read one page synchronously into the pagecache
+ * @file:	file context (unused)
+ * @page:	page frame to fill in.
+ *
+ * Description:
+ *   The vxfs_readpage routine reads @page synchronously into the
+ *   pagecache.
+ *
+ * Returns:
+ *   Zero on success, else a negative error code.
+ *
+ * Locking status:
+ *   @page is locked and will be unlocked.
+ */
+static int
+vxfs_readpage(struct file *file, struct page *page)
+{
+	return block_read_full_page(page, vxfs_getblk);
+}
+ 
+/**
+ * vxfs_bmap - perform logical to physical block mapping
+ * @mapping:	logical to physical mapping to use
+ * @block:	logical block (relative to @mapping).
+ *
+ * Description:
+ *   Vxfs_bmap find out the corresponding phsical block to the
+ *   @mapping, @block pair.
+ *
+ * Returns:
+ *   Physical block number on success, else Zero.
+ *
+ * Locking status:
+ *   We are under the bkl.
+ */
+static int
+vxfs_bmap(struct address_space *mapping, long block)
+{
+	return generic_block_bmap(mapping, block, vxfs_getblk);
+}
diff -urN linux-2.4.5-pre3/fs/freevxfs/vxfs_super.c linux/fs/freevxfs/vxfs_super.c
--- linux-2.4.5-pre3/fs/freevxfs/vxfs_super.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/freevxfs/vxfs_super.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2000-2001 Christoph Hellwig.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#ident "$Id: vxfs_super.c,v 1.22 2001/04/24 19:28:36 hch Exp hch $"
+
+/*
+ * Veritas filesystem driver - superblock related routines.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <linux/blkdev.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+
+#include "vxfs.h"
+#include "vxfs_extern.h"
+#include "vxfs_dir.h"
+#include "vxfs_inode.h"
+
+
+MODULE_AUTHOR("Christoph Hellwig");
+MODULE_DESCRIPTION("Veritas Filesystem (VxFS) driver");
+
+
+static void		vxfs_put_super(struct super_block *);
+static int		vxfs_statfs(struct super_block *, struct statfs *);
+
+
+static struct super_operations vxfs_super_ops = {
+	.read_inode =		vxfs_read_inode,
+	.put_inode =		vxfs_put_inode,
+	.put_super =		vxfs_put_super,
+	.statfs =		vxfs_statfs,
+};
+
+static __inline__ u_long
+vxfs_validate_bsize(kdev_t dev)
+{
+	u_long			bsize;
+	
+	bsize = get_hardsect_size(dev);
+	if (bsize < BLOCK_SIZE)
+		bsize = BLOCK_SIZE;
+
+	set_blocksize(dev, bsize);
+	return (bsize);
+}
+
+/**
+ * vxfs_put_super - free superblock resources
+ * @sbp:	VFS superblock.
+ *
+ * Description:
+ *   vxfs_put_super frees all resources allocated for @sbp
+ *   after the last instance of the filesystem is unmounted.
+ */
+static void
+vxfs_put_super(struct super_block *sbp)
+{
+	struct vxfs_sb_info	*infp = VXFS_SBI(sbp);
+
+	vxfs_put_inode(infp->vsi_fship);
+	vxfs_put_inode(infp->vsi_ilist);
+	vxfs_put_inode(infp->vsi_stilist);
+
+	brelse(infp->vsi_bp);
+	kfree(infp);
+}
+
+/**
+ * vxfs_statfs - get filesystem information
+ * @sbp:	VFS superblock
+ * @bufp:	output buffer
+ *
+ * Description:
+ *   vxfs_statfs fills the statfs buffer @bufp with information
+ *   about the filesystem described by @sbp.
+ *
+ * Returns:
+ *   Zero.
+ *
+ * Locking:
+ *   We are under bkl and @sbp->s_lock.
+ *
+ * Notes:
+ *   This is everything but complete...
+ */
+static int
+vxfs_statfs(struct super_block *sbp, struct statfs *bufp)
+{
+	struct vxfs_sb_info		*infp = VXFS_SBI(sbp);
+
+	bufp->f_type = VXFS_SUPER_MAGIC;
+	bufp->f_bsize = sbp->s_blocksize;
+	bufp->f_blocks = infp->vsi_raw->vs_dsize;
+	bufp->f_bfree = infp->vsi_raw->vs_free;
+	bufp->f_bavail = 0;
+	bufp->f_files = 0;
+	bufp->f_ffree = infp->vsi_raw->vs_ifree;
+	bufp->f_namelen = VXFS_NAME_LEN;
+
+	return 0;
+}
+
+/**
+ * vxfs_read_super - read superblock into memory and initalize filesystem
+ * @sbp:		VFS superblock (to fill)
+ * @dp:			fs private mount data
+ * @silent:		???
+ *
+ * Description:
+ *   We are called on the first mount of a filesystem to read the
+ *   superblock into memory and do some basic setup.
+ *
+ * Returns:
+ *   The superblock on success, else %NULL.
+ *
+ * Locking:
+ *   We are under the bkl and @sbp->s_lock.
+ */
+static struct super_block *
+vxfs_read_super(struct super_block *sbp, void *dp, int silent)
+{
+	struct vxfs_sb_info	*infp;
+	struct vxfs_sb		*rsbp;
+	struct buffer_head	*bp;
+	u_long			bsize;
+	kdev_t			dev = sbp->s_dev;
+
+	infp = kmalloc(sizeof(struct vxfs_sb_info), GFP_KERNEL);
+	if (!infp) {
+		printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n");
+		return NULL;
+	}
+	memset(infp, 0, sizeof(struct vxfs_sb_info));
+
+	bsize = vxfs_validate_bsize(dev);
+
+	bp = bread(dev, 1, bsize);
+	if (!bp) {
+		printk(KERN_WARNING "vxfs: unable to read disk superblock\n");
+		return NULL;
+	}
+
+	rsbp = (struct vxfs_sb *)bp->b_data;
+	if (rsbp->vs_magic != VXFS_SUPER_MAGIC) {
+		printk(KERN_NOTICE "vxfs: WRONG superblock magic\n");
+		return NULL;
+	}
+
+	if (rsbp->vs_version < 2 || rsbp->vs_version > 4) {
+		printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n", rsbp->vs_version);
+		return NULL;
+	}
+
+#ifdef DIAGNOSTIC
+	printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", rsbp->vs_version);
+	printk(KERN_DEBUG "vxfs: blocksize: %d\n", rsbp->vs_bsize);
+#endif
+
+	sbp->s_magic = rsbp->vs_magic;
+	sbp->u.generic_sbp = (void *)infp;
+
+	infp->vsi_raw = rsbp;
+	infp->vsi_bp = bp;
+	infp->vsi_oltext = rsbp->vs_oltext[0];
+	infp->vsi_oltsize = rsbp->vs_oltsize;
+	
+	sbp->s_blocksize = rsbp->vs_bsize;
+
+	switch (rsbp->vs_bsize) {
+	case 1024:
+		sbp->s_blocksize_bits = 10;
+		break;
+	case 2048:
+		sbp->s_blocksize_bits = 11;
+		break;
+	case 4096:
+		sbp->s_blocksize_bits = 12;
+		break;
+	default:
+		printk(KERN_WARNING "vxfs: unsupported blocksise: %d\n",
+				rsbp->vs_bsize);
+		return NULL;
+	}
+
+	if (vxfs_read_olt(sbp, bsize)) {
+		printk(KERN_WARNING "vxfs: unable to read olt\n");
+		return NULL;
+	}
+
+	if (vxfs_read_fshead(sbp)) {
+		printk(KERN_WARNING "vxfs: unable to read fshead\n");
+		return NULL;
+	}
+
+	sbp->s_op = &vxfs_super_ops;
+	if ((sbp->s_root = d_alloc_root(iget(sbp, VXFS_ROOT_INO))))
+		return (sbp);
+	
+	printk(KERN_WARNING "vxfs: unable to get root dentry.\n");
+	return NULL;
+}
+
+
+/*
+ * The usual module blurb.
+ */
+static DECLARE_FSTYPE_DEV(vxfs_fs_type, "vxfs", vxfs_read_super);
+
+static int __init
+vxfs_init(void)
+{
+	vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
+			sizeof(struct vxfs_inode_info), 0, 0, NULL, NULL);
+	if (vxfs_inode_cachep)
+		return (register_filesystem(&vxfs_fs_type));
+	return 0;
+}
+
+static void __exit
+vxfs_cleanup(void)
+{
+	unregister_filesystem(&vxfs_fs_type);
+	kmem_cache_destroy(vxfs_inode_cachep);
+}
+
+module_init(vxfs_init);
+module_exit(vxfs_cleanup);
diff -urN linux-2.4.5-pre3/fs/namei.c linux/fs/namei.c
--- linux-2.4.5-pre3/fs/namei.c	Fri Apr 20 16:04:32 2001
+++ linux/fs/namei.c	Mon Dec  3 22:44:23 2001
@@ -748,26 +748,24 @@
 }
 
 /* SMP-safe */
-struct dentry * lookup_one(const char * name, struct dentry * base)
+struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
 {
 	unsigned long hash;
 	struct qstr this;
 	unsigned int c;
 
 	this.name = name;
-	c = *(const unsigned char *)name;
-	if (!c)
+	this.len = len;
+	if (!len)
 		goto access;
 
 	hash = init_name_hash();
-	do {
-		name++;
-		if (c == '/')
+	while (len--) {
+		c = *(const unsigned char *)name++;
+		if (c == '/' || c == '\0')
 			goto access;
 		hash = partial_name_hash(c, hash);
-		c = *(const unsigned char *)name;
-	} while (c);
-	this.len = name - (const char *) this.name;
+	}
 	this.hash = end_name_hash(hash);
 
 	return lookup_hash(&this, base);
diff -urN linux-2.4.5-pre3/fs/nfs/dir.c linux/fs/nfs/dir.c
--- linux-2.4.5-pre3/fs/nfs/dir.c	Thu Mar 15 09:56:07 2001
+++ linux/fs/nfs/dir.c	Mon Dec  3 22:44:23 2001
@@ -802,7 +802,7 @@
 		dfprintk(VFS, "trying to rename %s to %s\n",
 			 dentry->d_name.name, silly);
 		
-		sdentry = lookup_one(silly, dentry->d_parent);
+		sdentry = lookup_one_len(silly, dentry->d_parent, slen);
 		/*
 		 * N.B. Better to return EBUSY here ... it could be
 		 * dangerous to delete the file while it's in use.
diff -urN linux-2.4.5-pre3/fs/nfs/file.c linux/fs/nfs/file.c
--- linux-2.4.5-pre3/fs/nfs/file.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/nfs/file.c	Mon Dec  3 22:44:23 2001
@@ -39,6 +39,7 @@
 static ssize_t nfs_file_write(struct file *, const char *, size_t, loff_t *);
 static int  nfs_file_flush(struct file *);
 static int  nfs_fsync(struct file *, struct dentry *dentry, int datasync);
+static int  nfs_file_release(struct inode *, struct file *);
 
 struct file_operations nfs_file_operations = {
 	read:		nfs_file_read,
@@ -46,7 +47,7 @@
 	mmap:		nfs_file_mmap,
 	open:		nfs_open,
 	flush:		nfs_file_flush,
-	release:	nfs_release,
+	release:	nfs_file_release,
 	fsync:		nfs_fsync,
 	lock:		nfs_lock,
 };
@@ -87,6 +88,13 @@
 	return status;
 }
 
+static int
+nfs_file_release(struct inode *inode, struct file *file)
+{
+	filemap_fdatasync(inode->i_mapping);
+	return nfs_release(inode,file);
+}
+
 static ssize_t
 nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
 {
@@ -283,9 +291,11 @@
 	 * Flush all pending writes before doing anything
 	 * with locks..
 	 */
-	down(&filp->f_dentry->d_inode->i_sem);
+	filemap_fdatasync(inode->i_mapping);
+	down(&inode->i_sem);
 	status = nfs_wb_all(inode);
-	up(&filp->f_dentry->d_inode->i_sem);
+	up(&inode->i_sem);
+	filemap_fdatawait(inode->i_mapping);
 	if (status < 0)
 		return status;
 
@@ -300,10 +310,12 @@
 	 */
  out_ok:
 	if ((cmd == F_SETLK || cmd == F_SETLKW) && fl->fl_type != F_UNLCK) {
-		down(&filp->f_dentry->d_inode->i_sem);
+		filemap_fdatasync(inode->i_mapping);
+		down(&inode->i_sem);
 		nfs_wb_all(inode);      /* we may have slept */
+		up(&inode->i_sem);
+		filemap_fdatawait(inode->i_mapping);
 		nfs_zap_caches(inode);
-		up(&filp->f_dentry->d_inode->i_sem);
 	}
 	return status;
 }
diff -urN linux-2.4.5-pre3/fs/nfs/flushd.c linux/fs/nfs/flushd.c
--- linux-2.4.5-pre3/fs/nfs/flushd.c	Tue Apr  3 13:45:37 2001
+++ linux/fs/nfs/flushd.c	Mon Dec  3 22:44:23 2001
@@ -174,7 +174,7 @@
 	 */
 	NFS_FLAGS(inode) |= NFS_INO_FLUSH;
 	atomic_inc(&inode->i_count);
- out:
+out:;
 }
 
 /* Protect me using the BKL */
diff -urN linux-2.4.5-pre3/fs/nfs/inode.c linux/fs/nfs/inode.c
--- linux-2.4.5-pre3/fs/nfs/inode.c	Wed Apr 25 14:58:17 2001
+++ linux/fs/nfs/inode.c	Mon Dec  3 22:44:23 2001
@@ -45,6 +45,7 @@
 static void nfs_invalidate_inode(struct inode *);
 
 static void nfs_read_inode(struct inode *);
+static void nfs_write_inode(struct inode *,int);
 static void nfs_delete_inode(struct inode *);
 static void nfs_put_super(struct super_block *);
 static void nfs_umount_begin(struct super_block *);
@@ -52,7 +53,7 @@
 
 static struct super_operations nfs_sops = { 
 	read_inode:	nfs_read_inode,
-	put_inode:	force_delete,
+	write_inode:	nfs_write_inode,
 	delete_inode:	nfs_delete_inode,
 	put_super:	nfs_put_super,
 	statfs:		nfs_statfs,
@@ -116,6 +117,14 @@
 }
 
 static void
+nfs_write_inode(struct inode *inode, int sync)
+{
+	int flags = sync ? FLUSH_WAIT : 0;
+
+	nfs_sync_file(inode, NULL, 0, 0, flags);
+}
+
+static void
 nfs_delete_inode(struct inode * inode)
 {
 	dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
@@ -887,40 +896,23 @@
  * A very similar scenario holds for the dir cache.
  */
 int
-nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+__nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
 	__u64		new_size, new_mtime;
 	loff_t		new_isize;
 	int		invalid = 0;
-	int		error = -EIO;
-
-	if (!inode || !fattr) {
-		printk(KERN_ERR "nfs_refresh_inode: inode or fattr is NULL\n");
-		goto out;
-	}
-	if (inode->i_mode == 0) {
-		printk(KERN_ERR "nfs_refresh_inode: empty inode\n");
-		goto out;
-	}
-
-	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
-		goto out;
-
-	if (is_bad_inode(inode))
-		goto out;
 
 	dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d info=0x%x)\n",
 			inode->i_dev, inode->i_ino,
 			atomic_read(&inode->i_count), fattr->valid);
 
-
 	if (NFS_FSID(inode) != fattr->fsid ||
 	    NFS_FILEID(inode) != fattr->fileid) {
 		printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n"
 		       "expected (0x%Lx/0x%Lx), got (0x%Lx/0x%Lx)\n",
 		       (long long)NFS_FSID(inode), (long long)NFS_FILEID(inode),
 		       (long long)fattr->fsid, (long long)fattr->fileid);
-		goto out;
+		goto out_err;
 	}
 
 	/*
@@ -933,8 +925,6 @@
 	new_size = fattr->size;
  	new_isize = nfs_size_to_loff_t(fattr->size);
 
-	error = 0;
-
 	/*
 	 * Update the read time so we don't revalidate too often.
 	 */
@@ -1024,11 +1014,9 @@
 
 	if (invalid)
 		nfs_zap_caches(inode);
+	return 0;
 
-out:
-	return error;
-
-out_changed:
+ out_changed:
 	/*
 	 * Big trouble! The inode has become a different object.
 	 */
@@ -1042,7 +1030,8 @@
 	 * (But we fall through to invalidate the caches.)
 	 */
 	nfs_invalidate_inode(inode);
-	goto out;
+ out_err:
+	return -EIO;
 }
 
 /*
diff -urN linux-2.4.5-pre3/fs/nfs/write.c linux/fs/nfs/write.c
--- linux-2.4.5-pre3/fs/nfs/write.c	Tue Apr  3 13:45:37 2001
+++ linux/fs/nfs/write.c	Mon Dec  3 22:44:23 2001
@@ -457,6 +457,7 @@
 	 *     spinlock since it can run flushd().
 	 */
 	inode_schedule_scan(inode, req->wb_timeout);
+	mark_inode_dirty(inode);
 }
 
 /*
@@ -489,6 +490,7 @@
 	 *     spinlock since it can run flushd().
 	 */
 	inode_schedule_scan(inode, req->wb_timeout);
+	mark_inode_dirty(inode);
 }
 #endif
 
@@ -1013,7 +1015,6 @@
 	struct dentry	*dentry = file->f_dentry;
 	struct inode	*inode = dentry->d_inode;
 	struct nfs_page	*req;
-	int		synchronous = file->f_flags & O_SYNC;
 	int		status = 0;
 
 	dprintk("NFS:      nfs_updatepage(%s/%s %d@%Ld)\n",
@@ -1044,24 +1045,14 @@
 	if (status < 0)
 		goto done;
 
-	if (req->wb_bytes == PAGE_CACHE_SIZE)
-		SetPageUptodate(page);
-
 	status = 0;
-	if (synchronous) {
-		int error;
-
-		error = nfs_sync_file(inode, file, page_index(page), 1, FLUSH_SYNC|FLUSH_STABLE);
-		if (error < 0 || (error = file->f_error) < 0)
-			status = error;
-		file->f_error = 0;
-	} else {
-		/* If we wrote past the end of the page.
-		 * Call the strategy routine so it can send out a bunch
-		 * of requests.
-		 */
-		if (req->wb_offset == 0 && req->wb_bytes == PAGE_CACHE_SIZE)
-			nfs_strategy(inode);
+	/* If we wrote past the end of the page.
+	 * Call the strategy routine so it can send out a bunch
+	 * of requests.
+	 */
+	if (req->wb_offset == 0 && req->wb_bytes == PAGE_CACHE_SIZE) {
+		SetPageUptodate(page);
+		nfs_strategy(inode);
 	}
 	nfs_release_request(req);
 done:
diff -urN linux-2.4.5-pre3/fs/nfsd/nfs3xdr.c linux/fs/nfsd/nfs3xdr.c
--- linux-2.4.5-pre3/fs/nfsd/nfs3xdr.c	Fri Dec 29 14:07:23 2000
+++ linux/fs/nfsd/nfs3xdr.c	Mon Dec  3 22:44:23 2001
@@ -707,15 +707,13 @@
 		exp  = cd->dirfh->fh_export;
 
 		fh_init(&fh, NFS3_FHSIZE);
-		if (fh_verify(cd->rqstp, cd->dirfh, S_IFDIR, MAY_EXEC) != 0)
-			goto noexec;
 		if (isdotent(name, namlen)) {
 			dchild = dparent;
 			if (namlen == 2)
 				dchild = dchild->d_parent;
 			dchild = dget(dchild);
 		} else
-			dchild = lookup_one(name, dparent);
+			dchild = lookup_one_len(name, dparent,namlen);
 		if (IS_ERR(dchild))
 			goto noexec;
 		if (fh_compose(&fh, exp, dchild) != 0 || !dchild->d_inode)
diff -urN linux-2.4.5-pre3/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- linux-2.4.5-pre3/fs/nfsd/nfsfh.c	Mon Dec  3 22:43:50 2001
+++ linux/fs/nfsd/nfsfh.c	Mon Dec  3 22:44:23 2001
@@ -413,7 +413,7 @@
 				d_drop(result);
 				dput(result);
 				result = tmp;
-				/* If !found, then this is really wierd, but it shouldn't hurt */
+				/* If !found, then this is really weird, but it shouldn't hurt */
 			}
 		}
 	} else {
diff -urN linux-2.4.5-pre3/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c
--- linux-2.4.5-pre3/fs/nfsd/nfsproc.c	Mon Mar 12 18:14:55 2001
+++ linux/fs/nfsd/nfsproc.c	Mon Dec  3 22:44:23 2001
@@ -216,7 +216,7 @@
 	if (isdotent(argp->name, argp->len))
 		goto done;
 	fh_lock(dirfhp);
-	dchild = lookup_one(argp->name, dirfhp->fh_dentry);
+	dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
 	if (IS_ERR(dchild)) {
 		nfserr = nfserrno(PTR_ERR(dchild));
 		goto out_unlock;
diff -urN linux-2.4.5-pre3/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c
--- linux-2.4.5-pre3/fs/nfsd/nfssvc.c	Thu Mar 15 09:56:07 2001
+++ linux/fs/nfsd/nfssvc.c	Mon Dec  3 22:44:23 2001
@@ -117,7 +117,7 @@
 	return error;
 }
 
-static void inline
+static inline void
 update_thread_usage(int busy_threads)
 {
 	unsigned long prev_call;
@@ -253,7 +253,7 @@
 		return 0;
 	case RC_REPLY:
 		return 1;
-	case RC_DOIT:
+	case RC_DOIT:;
 		/* do it */
 	}
 
diff -urN linux-2.4.5-pre3/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- linux-2.4.5-pre3/fs/nfsd/vfs.c	Mon Mar 12 18:13:28 2001
+++ linux/fs/nfsd/vfs.c	Mon Dec  3 22:44:23 2001
@@ -98,7 +98,7 @@
 	struct dentry		*dentry;
 	int			err;
 
-	dprintk("nfsd: nfsd_lookup(fh %s, %s)\n", SVCFH_fmt(fhp), name);
+	dprintk("nfsd: nfsd_lookup(fh %s, %*.*s)\n", SVCFH_fmt(fhp), len,len,name);
 
 	/* Obtain dentry and export. */
 	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC);
@@ -111,40 +111,42 @@
 	err = nfserr_acces;
 
 	/* Lookup the name, but don't follow links */
-	if (strcmp(name, ".")==0) {
-		dentry = dget(dparent);
-	} else if (strcmp(name, "..")==0) {
-		/* checking mountpoint crossing is very different when stepping up */
-		if (dparent == exp->ex_dentry) {
-			if (!EX_CROSSMNT(exp))
-				dentry = dget(dparent); /* .. == . just like at / */
-			else
-			{
-				struct svc_export *exp2 = NULL;
-				struct dentry *dp;
-				struct vfsmount *mnt = mntget(exp->ex_mnt);
-				dentry = dget(dparent);
-				while(follow_up(&mnt, &dentry))
-					;
-				dp = dget(dentry->d_parent);
-				dput(dentry);
-				dentry = dp;
-				for ( ; exp2 == NULL && dp->d_parent != dp;
-				     dp=dp->d_parent)
-					exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);
-				if (exp2==NULL) {
-					dput(dentry);
+	if (isdotent(name, len)) {
+		if (len==1)
+			dentry = dget(dparent);
+		else  { /* must be ".." */
+			/* checking mountpoint crossing is very different when stepping up */
+			if (dparent == exp->ex_dentry) {
+				if (!EX_CROSSMNT(exp))
+					dentry = dget(dparent); /* .. == . just like at / */
+				else
+				{
+					struct svc_export *exp2 = NULL;
+					struct dentry *dp;
+					struct vfsmount *mnt = mntget(exp->ex_mnt);
 					dentry = dget(dparent);
-				} else {
-					exp = exp2;
+					while(follow_up(&mnt, &dentry))
+						;
+					dp = dget(dentry->d_parent);
+					dput(dentry);
+					dentry = dp;
+					for ( ; exp2 == NULL && dp->d_parent != dp;
+					      dp=dp->d_parent)
+						exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);
+					if (exp2==NULL) {
+						dput(dentry);
+						dentry = dget(dparent);
+					} else {
+						exp = exp2;
+					}
+					mntput(mnt);
 				}
-				mntput(mnt);
-			}
-		} else
-			dentry = dget(dparent->d_parent);
+			} else
+				dentry = dget(dparent->d_parent);
+		}
 	} else {
 		fh_lock(fhp);
-		dentry = lookup_one(name, dparent);
+		dentry = lookup_one_len(name, dparent, len);
 		err = PTR_ERR(dentry);
 		if (IS_ERR(dentry))
 			goto out_nfserr;
@@ -843,7 +845,7 @@
 	if (!resfhp->fh_dentry) {
 		/* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
 		fh_lock(fhp);
-		dchild = lookup_one(fname, dentry);
+		dchild = lookup_one_len(fname, dentry, flen);
 		err = PTR_ERR(dchild);
 		if (IS_ERR(dchild))
 			goto out_nfserr;
@@ -968,7 +970,7 @@
 	/*
 	 * Compose the response file handle.
 	 */
-	dchild = lookup_one(fname, dentry);
+	dchild = lookup_one_len(fname, dentry, flen);
 	err = PTR_ERR(dchild);
 	if (IS_ERR(dchild))
 		goto out_nfserr;
@@ -1132,7 +1134,7 @@
 		goto out;
 	fh_lock(fhp);
 	dentry = fhp->fh_dentry;
-	dnew = lookup_one(fname, dentry);
+	dnew = lookup_one_len(fname, dentry, flen);
 	err = PTR_ERR(dnew);
 	if (IS_ERR(dnew))
 		goto out_nfserr;
@@ -1197,7 +1199,7 @@
 	ddir = ffhp->fh_dentry;
 	dirp = ddir->d_inode;
 
-	dnew = lookup_one(fname, ddir);
+	dnew = lookup_one_len(fname, ddir, len);
 	err = PTR_ERR(dnew);
 	if (IS_ERR(dnew))
 		goto out_nfserr;
@@ -1268,7 +1270,7 @@
 	fill_pre_wcc(ffhp);
 	fill_pre_wcc(tfhp);
 
-	odentry = lookup_one(fname, fdentry);
+	odentry = lookup_one_len(fname, fdentry, flen);
 	err = PTR_ERR(odentry);
 	if (IS_ERR(odentry))
 		goto out_nfserr;
@@ -1277,7 +1279,7 @@
 	if (!odentry->d_inode)
 		goto out_dput_old;
 
-	ndentry = lookup_one(tname, tdentry);
+	ndentry = lookup_one_len(tname, tdentry, tlen);
 	err = PTR_ERR(ndentry);
 	if (IS_ERR(ndentry))
 		goto out_dput_old;
@@ -1339,7 +1341,7 @@
 	dentry = fhp->fh_dentry;
 	dirp = dentry->d_inode;
 
-	rdentry = lookup_one(fname, dentry);
+	rdentry = lookup_one_len(fname, dentry, flen);
 	err = PTR_ERR(rdentry);
 	if (IS_ERR(rdentry))
 		goto out_nfserr;
diff -urN linux-2.4.5-pre3/fs/nls/Config.in linux/fs/nls/Config.in
--- linux-2.4.5-pre3/fs/nls/Config.in	Fri Apr  6 10:51:19 2001
+++ linux/fs/nls/Config.in	Mon Dec  3 22:44:23 2001
@@ -56,7 +56,7 @@
   tristate 'NLS ISO 8859-14 (Latin 8; Celtic)'      CONFIG_NLS_ISO8859_14
   tristate 'NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)' CONFIG_NLS_ISO8859_15
   tristate 'NLS KOI8-R (Russian)'                   CONFIG_NLS_KOI8_R
-  tristate 'NLS KOI8-U (Ukrainian)'                 CONFIG_NLS_KOI8_U
+  tristate 'NLS KOI8-U/RU (Ukrainian, Belarussian)' CONFIG_NLS_KOI8_U
   tristate 'NLS UTF8'                               CONFIG_NLS_UTF8
   endmenu
 fi
diff -urN linux-2.4.5-pre3/fs/nls/Makefile linux/fs/nls/Makefile
--- linux-2.4.5-pre3/fs/nls/Makefile	Fri Apr  6 10:51:19 2001
+++ linux/fs/nls/Makefile	Mon Dec  3 22:44:23 2001
@@ -49,7 +49,7 @@
 obj-$(CONFIG_NLS_ISO8859_14)	+= nls_iso8859-14.o
 obj-$(CONFIG_NLS_ISO8859_15)	+= nls_iso8859-15.o
 obj-$(CONFIG_NLS_KOI8_R)	+= nls_koi8-r.o
-obj-$(CONFIG_NLS_KOI8_U)	+= nls_koi8-u.o
+obj-$(CONFIG_NLS_KOI8_U)	+= nls_koi8-u.o nls_koi8-ru.o
 obj-$(CONFIG_NLS_ABC)		+= nls_abc.o
 obj-$(CONFIG_NLS_UTF8)		+= nls_utf8.o
 
diff -urN linux-2.4.5-pre3/fs/nls/nls_cp1255.c linux/fs/nls/nls_cp1255.c
--- linux-2.4.5-pre3/fs/nls/nls_cp1255.c	Fri Apr  6 10:51:19 2001
+++ linux/fs/nls/nls_cp1255.c	Mon Dec  3 22:44:23 2001
@@ -254,7 +254,7 @@
 };
 
 static unsigned char *page_uni2charset[256] = {
-	page00, NULL,   NULL,   NULL,   NULL,   page05, NULL,   NULL,   
+	page00, page01, page02, NULL,   NULL,   page05, 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,   
diff -urN linux-2.4.5-pre3/fs/nls/nls_iso8859-13.c linux/fs/nls/nls_iso8859-13.c
--- linux-2.4.5-pre3/fs/nls/nls_iso8859-13.c	Fri Apr  6 10:51:19 2001
+++ linux/fs/nls/nls_iso8859-13.c	Mon Dec  3 22:44:23 2001
@@ -149,35 +149,6 @@
 	0x00, 0xca, 0xea, 0xdd, 0xfd, 0xde, 0xfe, 0x00, /* 0x78-0x7f */
 };
 
-static unsigned char page02[256] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
-	0x00, 0xff, 0x00, 0x00, 0xb4, 0xa1, 0xa5, 0x00, /* 0x18-0x1f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
-	
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
-};
-
 static unsigned char page20[256] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
diff -urN linux-2.4.5-pre3/fs/nls/nls_koi8-ru.c linux/fs/nls/nls_koi8-ru.c
--- linux-2.4.5-pre3/fs/nls/nls_koi8-ru.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls/nls_koi8-ru.c	Mon Dec  3 22:44:23 2001
@@ -0,0 +1,99 @@
+/*
+ * linux/fs/nls_koi8-ru.c
+ *
+ * Charset koi8-ru translation based on charset koi8-u.
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+#include <linux/errno.h>
+
+static struct nls_table *p_nls;
+
+static int uni2char(const wchar_t uni,
+		    unsigned char *out, int boundlen)
+{
+	if (boundlen <= 0)
+		return -ENAMETOOLONG;
+
+	if ((uni & 0xffaf) == 0x040e || (uni & 0xffce) == 0x254c) {
+		/* koi8-ru and koi8-u differ only on two characters */
+		if (uni == 0x040e)
+			return 0xbe;
+		else if (uni == 0x045e)
+			return 0xae;
+		else if (uni == 0x255d || uni == 0x256c)
+			return 0;
+		else
+			return p_nls->uni2char(uni, out, boundlen);
+	}
+	else
+		/* fast path */
+		return p_nls->uni2char(uni, out, boundlen);
+}
+
+static int char2uni(const unsigned char *rawstring, int boundlen,
+		    wchar_t *uni)
+{
+	int n;
+
+	if ((*rawstring & 0xef) != 0xae) {
+		/* koi8-ru and koi8-u differ only on two characters */
+		*uni = (*rawstring & 0x10) ? 0x040e : 0x045e;
+		return 1;
+	}
+
+	n = p_nls->char2uni(rawstring, boundlen, uni);
+	return n;
+}
+
+static struct nls_table table = {
+	"koi8-ru",
+	uni2char,
+	char2uni,
+	NULL,
+	NULL,
+	THIS_MODULE,
+};
+
+static int __init init_nls_koi8_ru(void)
+{
+	p_nls = load_nls("koi8-u");
+
+	if (p_nls) {
+		table.charset2upper = p_nls->charset2upper;
+		table.charset2lower = p_nls->charset2lower;
+		return register_nls(&table);
+	}
+
+	return -EINVAL;
+}
+
+static void __exit exit_nls_koi8_ru(void)
+{
+	unregister_nls(&table);
+	unload_nls(p_nls);
+}
+
+module_init(init_nls_koi8_ru)
+module_exit(exit_nls_koi8_ru)
+
+/*
+ * 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 -urN linux-2.4.5-pre3/fs/nls/nls_koi8-u.c linux/fs/nls/nls_koi8-u.c
--- linux-2.4.5-pre3/fs/nls/nls_koi8-u.c	Mon Dec  3 22:43:50 2001
+++ linux/fs/nls/nls_koi8-u.c	Mon Dec  3 22:44:23 2001
@@ -141,6 +141,7 @@
 	0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde, /* 0x40-0x47 */
 	0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1, /* 0x48-0x4f */
 	0x00, 0xa3, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0xa7, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
diff -urN linux-2.4.5-pre3/fs/partitions/check.c linux/fs/partitions/check.c
--- linux-2.4.5-pre3/fs/partitions/check.c	Fri Feb 16 16:02:37 2001
+++ linux/fs/partitions/check.c	Mon Dec  3 22:44:23 2001
@@ -33,10 +33,7 @@
 #include "ibm.h"
 #include "ultrix.h"
 
-extern void device_init(void);
 extern int *blk_size[];
-extern void rd_load(void);
-extern void initrd_load(void);
 
 struct gendisk *gendisk_head;
 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
@@ -438,19 +435,3 @@
 		blk_size[dev->major] = dev->sizes;
 	}
 }
-
-int __init partition_setup(void)
-{
-	device_init();
-
-#ifdef CONFIG_BLK_DEV_RAM
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_start && mount_initrd) initrd_load();
-	else
-#endif
-	rd_load();
-#endif
-	return 0;
-}
-
-__initcall(partition_setup);
diff -urN linux-2.4.5-pre3/fs/proc/root.c linux/fs/proc/root.c
--- linux-2.4.5-pre3/fs/proc/root.c	Mon Dec  3 22:43:50 2001
+++ linux/fs/proc/root.c	Mon Dec  3 22:44:23 2001
@@ -54,6 +54,9 @@
 #ifdef CONFIG_PROC_DEVICETREE
 	proc_device_tree_init();
 #endif
+#ifdef CONFIG_PPC_RTAS
+	proc_rtas_init();
+#endif
 	proc_bus = proc_mkdir("bus", 0);
 }
 
diff -urN linux-2.4.5-pre3/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- linux-2.4.5-pre3/fs/umsdos/inode.c	Mon Oct 16 12:58:51 2000
+++ linux/fs/umsdos/inode.c	Mon Dec  3 22:44:23 2001
@@ -378,7 +378,7 @@
 	 * lookup_dentry needs a (so far non-existent) root. 
 	 */
 	printk(KERN_INFO "check_pseudo_root: mounted as root\n");
-	root = lookup_one(UMSDOS_PSDROOT_NAME, sb->s_root); 
+	root = lookup_one_len(UMSDOS_PSDROOT_NAME, sb->s_root,UMSDOS_PSDROOT_LEN); 
 	if (IS_ERR(root))
 		goto out_noroot;
 	if (!root->d_inode || !S_ISDIR(root->d_inode->i_mode))
@@ -387,12 +387,12 @@
 	printk(KERN_INFO "check_pseudo_root: found %s/%s\n", root->d_parent->d_name.name, root->d_name.name);
 
 	/* look for /sbin/init */
-	sbin = lookup_one("sbin", root);
+	sbin = lookup_one_len("sbin", root, 4);
 	if (IS_ERR(sbin))
 		goto out_dput;
 	if (!sbin->d_inode || !S_ISDIR(sbin->d_inode->i_mode))
 		goto out_dput_sbin;
-	init = lookup_one("init", sbin);
+	init = lookup_one_len("init", sbin, 4);
 	if (IS_ERR(init))
 		goto out_dput_sbin;
 	if (!init->d_inode)
diff -urN linux-2.4.5-pre3/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h
--- linux-2.4.5-pre3/include/asm-arm/arch-ebsa285/system.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-ebsa285/system.h	Mon Dec  3 22:44:23 2001
@@ -63,14 +63,24 @@
 			 */
 			outb(0xc4, 0x338);
 		} else {
-			/* To reboot, we set up the 21285 watchdog and
-			 * enable it.  We then wait for it to timeout.
+			/* 
+			 * Force the watchdog to do a CPU reset.
+			 *
+			 * After making sure that the watchdog is disabled
+			 * (so we can change the timer registers) we first
+			 * enable the timer to autoreload itself.  Next, the
+			 * timer interval is set really short and any
+			 * current interrupt request is cleared (so we can
+			 * see an edge transition).  Finally, TIMER4 is
+			 * enabled as the watchdog.
 			 */
-			*CSR_TIMER4_LOAD = 0x8000;
+			*CSR_SA110_CNTL &= ~(1 << 13);
 			*CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE |
 					   TIMER_CNTL_AUTORELOAD |
 					   TIMER_CNTL_DIV16;
-			*CSR_SA110_CNTL |= 1 << 13;
+			*CSR_TIMER4_LOAD = 0x2;
+			*CSR_TIMER4_CLR  = 0;
+			*CSR_SA110_CNTL |= (1 << 13);
 		}
 	}
 }
diff -urN linux-2.4.5-pre3/include/asm-arm/arch-l7200/keyboard.h linux/include/asm-arm/arch-l7200/keyboard.h
--- linux-2.4.5-pre3/include/asm-arm/arch-l7200/keyboard.h	Thu Apr 12 12:20:31 2001
+++ linux/include/asm-arm/arch-l7200/keyboard.h	Mon Dec  3 22:44:23 2001
@@ -42,7 +42,7 @@
 #define kbd_unexpected_up(kc)           (0200)
 #define kbd_leds(leds)                  do {} while (0)
 #define kbd_init_hw()                   l7200kbd_init_hw()
-#define kbd_sysrq_xlate                 do {} while (0)
+#define kbd_sysrq_xlate                 ((unsigned char *)NULL)
 #define kbd_disable_irq()               disable_irq(IRQ_GCTC2)
 #define kbd_enable_irq()                enable_irq(IRQ_GCTC2)
 
diff -urN linux-2.4.5-pre3/include/asm-arm/uaccess.h linux/include/asm-arm/uaccess.h
--- linux-2.4.5-pre3/include/asm-arm/uaccess.h	Tue Mar  6 19:44:35 2001
+++ linux/include/asm-arm/uaccess.h	Mon Dec  3 22:44:23 2001
@@ -75,6 +75,8 @@
 {
 	if (access_ok(VERIFY_READ, from, n))
 		__do_copy_from_user(to, from, n);
+	else /* security hole - plug it */
+		memzero(to, n);
 	return n;
 }
 
diff -urN linux-2.4.5-pre3/include/asm-i386/pci.h linux/include/asm-i386/pci.h
--- linux-2.4.5-pre3/include/asm-i386/pci.h	Mon Dec  3 22:43:50 2001
+++ linux/include/asm-i386/pci.h	Mon Dec  3 22:44:23 2001
@@ -179,6 +179,10 @@
 	return 0;
 }
 
+#define HAVE_PCI_MMAP
+extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			       enum pci_mmap_state mmap_state, int write_combine);
+
 #endif /* __KERNEL__ */
 
 #endif /* __i386_PCI_H */
diff -urN linux-2.4.5-pre3/include/asm-ppc/pci-bridge.h linux/include/asm-ppc/pci-bridge.h
--- linux-2.4.5-pre3/include/asm-ppc/pci-bridge.h	Mon Dec  3 22:43:50 2001
+++ linux/include/asm-ppc/pci-bridge.h	Mon Dec  3 22:44:23 2001
@@ -36,6 +36,7 @@
  * Structure of a PCI controller (host bridge)
  */
 struct pci_controller {
+	int index;			/* used for pci_controller_num */
 	struct pci_controller *next;
         struct pci_bus *bus;
 	void *arch_data;
diff -urN linux-2.4.5-pre3/include/asm-ppc/pci.h linux/include/asm-ppc/pci.h
--- linux-2.4.5-pre3/include/asm-ppc/pci.h	Mon Dec  3 22:43:50 2001
+++ linux/include/asm-ppc/pci.h	Mon Dec  3 22:44:23 2001
@@ -111,7 +111,14 @@
 }
 
 /* Return the index of the PCI controller for device PDEV. */
-#define pci_controller_num(PDEV)	(0)
+extern int pci_controller_num(struct pci_dev *pdev);
+
+/* Map a range of PCI memory or I/O space for a device into user space */
+int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state, int write_combine);
+
+/* 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)
diff -urN linux-2.4.5-pre3/include/linux/b1lli.h linux/include/linux/b1lli.h
--- linux-2.4.5-pre3/include/linux/b1lli.h	Mon Mar 26 15:38:19 2001
+++ linux/include/linux/b1lli.h	Mon Dec  3 22:44:23 2001
@@ -1,77 +1,9 @@
 /*
- * $Id: b1lli.h,v 1.8.8.1 2001/03/15 09:58:30 kai Exp $
+ * $Id: b1lli.h,v 1.8.8.2 2001/05/17 20:41:52 kai Exp $
  *
  * ISDN lowlevel-module for AVM B1-card.
  *
  * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
- *
- * $Log: b1lli.h,v $
- * Revision 1.8.8.1  2001/03/15 09:58:30  kai
- * spelling fix
- *
- * Revision 1.8  1999/07/01 15:26:54  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
- * Revision 1.7  1999/06/21 15:24:25  calle
- * extend information in /proc.
- *
- * Revision 1.6  1999/04/15 19:49:36  calle
- * fix fuer die B1-PCI. Jetzt geht z.B. auch IRQ 17 ...
- *
- * Revision 1.5  1998/10/25 14:50:28  fritz
- * Backported from MIPS (Cobalt).
- *
- * Revision 1.4  1998/03/29 16:05:02  calle
- * changes from 2.0 tree merged.
- *
- * Revision 1.1.2.9  1998/03/20 14:30:02  calle
- * added cardnr to detect if you try to add same T1 to different io address.
- * change number of nccis depending on number of channels.
- *
- * Revision 1.1.2.8  1998/03/04 17:32:33  calle
- * Changes for T1.
- *
- * Revision 1.1.2.7  1998/02/27 15:38:29  calle
- * T1 running with slow link.
- *
- * Revision 1.1.2.6  1998/02/24 17:57:36  calle
- * changes for T1.
- *
- * Revision 1.3  1998/01/31 10:54:37  calle
- * include changes for PCMCIA cards from 2.0 version
- *
- * Revision 1.2  1997/12/10 19:38:42  calle
- * get changes from 2.0 tree
- *
- * Revision 1.1.2.2  1997/11/26 16:57:26  calle
- * more changes for B1/M1/T1.
- *
- * Revision 1.1.2.1  1997/11/26 10:47:01  calle
- * prepared for M1 (Mobile) and T1 (PMX) cards.
- * prepared to set configuration after load to support other D-channel
- * protocols, point-to-point and leased lines.
- *
- * Revision 1.1  1997/03/04 21:27:32  calle
- * First version in isdn4linux
- *
- * Revision 2.2  1997/02/12 09:31:39  calle
- * new version
- *
- * Revision 1.1  1997/01/31 10:32:20  calle
- * Initial revision
  *
  */
 
diff -urN linux-2.4.5-pre3/include/linux/b1pcmcia.h linux/include/linux/b1pcmcia.h
--- linux-2.4.5-pre3/include/linux/b1pcmcia.h	Thu Aug 12 09:42:33 1999
+++ linux/include/linux/b1pcmcia.h	Mon Dec  3 22:44:23 2001
@@ -1,27 +1,10 @@
 /*
- * $Id: b1pcmcia.h,v 1.1 1999/07/01 15:26:56 calle Exp $
+ * $Id: b1pcmcia.h,v 1.1.8.1 2001/05/17 20:41:52 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)
- *
- * $Log: b1pcmcia.h,v $
- * Revision 1.1  1999/07/01 15:26:56  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
  *
  */
 
diff -urN linux-2.4.5-pre3/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.5-pre3/include/linux/fs.h	Mon Dec  3 22:43:50 2001
+++ linux/include/linux/fs.h	Mon Dec  3 22:44:23 2001
@@ -1204,7 +1204,7 @@
 extern void path_release(struct nameidata *);
 extern int follow_down(struct vfsmount **, struct dentry **);
 extern int follow_up(struct vfsmount **, struct dentry **);
-extern struct dentry * lookup_one(const char *, struct dentry *);
+extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
 extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
 #define user_path_walk(name,nd)	 __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
 #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
diff -urN linux-2.4.5-pre3/include/linux/hysdn_if.h linux/include/linux/hysdn_if.h
--- linux-2.4.5-pre3/include/linux/hysdn_if.h	Mon Mar 26 15:38:19 2001
+++ linux/include/linux/hysdn_if.h	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_if.h,v 1.1.8.1 2001/03/13 16:17:10 kai Exp $
+/* $Id: hysdn_if.h,v 1.1.8.2 2001/05/17 20:41:52 kai Exp $
 
  * Linux driver for HYSDN cards, ioctl definitions shared by hynetmgr and driver.
  * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -18,15 +18,6 @@
  * 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.
- *
- * $Log: hysdn_if.h,v $
- * Revision 1.1.8.1  2001/03/13 16:17:10  kai
- * spelling fixes from 2.4.3-pre
- *
- * Revision 1.1  2000/02/10 19:47:50  werner
- *
- * Initial release
- *
  *
  */
 
diff -urN linux-2.4.5-pre3/include/linux/init.h linux/include/linux/init.h
--- linux-2.4.5-pre3/include/linux/init.h	Fri Apr 27 15:48:19 2001
+++ linux/include/linux/init.h	Mon Dec  3 22:44:23 2001
@@ -34,6 +34,8 @@
  * Don't forget to initialize data not at file scope, i.e. within a function,
  * as gcc otherwise puts the data into the bss section and not into the init
  * section.
+ * 
+ * Also note, that this data cannot be "const".
  */
 
 #ifndef MODULE
diff -urN linux-2.4.5-pre3/include/linux/isdn.h linux/include/linux/isdn.h
--- linux-2.4.5-pre3/include/linux/isdn.h	Thu Apr 19 22:30:09 2001
+++ linux/include/linux/isdn.h	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.111.6.5 2001/04/20 02:40:48 keil Exp $
+/* $Id: isdn.h,v 1.111.6.6 2001/05/17 21:15:34 kai Exp $
 
  * Main header for the Linux ISDN subsystem (linklevel).
  *
@@ -22,55 +22,11 @@
  *
  */
 
-#ifndef isdn_h
-#define isdn_h
+#ifndef __ISDN_H__
+#define __ISDN_H__
 
-#ifdef __KERNEL__
-#include <linux/config.h>
-#endif
 #include <linux/ioctl.h>
 
-#define ISDN_TTY_MAJOR    43
-#define ISDN_TTYAUX_MAJOR 44
-#define ISDN_MAJOR        45
-
-/* The minor-devicenumbers for Channel 0 and 1 are used as arguments for
- * physical Channel-Mapping, so they MUST NOT be changed without changing
- * the correspondent code in isdn.c
- */
-
-#ifdef USE_MINIMUM_MEM
-/* Save memory */
-#define ISDN_MAX_DRIVERS    2
-#define ISDN_MAX_CHANNELS   8
-#else
-#define ISDN_MAX_DRIVERS    32
-#define ISDN_MAX_CHANNELS   64
-#endif
-#define ISDN_MINOR_B        0
-#define ISDN_MINOR_BMAX     (ISDN_MAX_CHANNELS-1)
-#define ISDN_MINOR_CTRL     64
-#define ISDN_MINOR_CTRLMAX  (64 + (ISDN_MAX_CHANNELS-1))
-#define ISDN_MINOR_PPP      128
-#define ISDN_MINOR_PPPMAX   (128 + (ISDN_MAX_CHANNELS-1))
-#define ISDN_MINOR_STATUS   255
-
-#undef CONFIG_ISDN_WITH_ABC_CALLB
-#undef CONFIG_ISDN_WITH_ABC_UDP_CHECK
-#undef CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP
-#undef CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL
-#undef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
-#undef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
-#undef CONFIG_ISDN_WITH_ABC_IPV4_TCP_KEEPALIVE
-#undef CONFIG_ISDN_WITH_ABC_IPV4_DYNADDR
-#undef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
-#undef CONFIG_ISDN_WITH_ABC_ICALL_BIND
-#undef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
-#undef CONFIG_ISDN_WITH_ABC_CONN_ERROR
-#undef CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
-#undef CONFIG_ISDN_WITH_ABC_IPTABLES_NETFILTER
-
-
 /* New ioctl-codes */
 #define IIOCNETAIF  _IO('I',1)
 #define IIOCNETDIF  _IO('I',2)
@@ -122,6 +78,7 @@
 #define ISDN_NET_ENCAP_CISCOHDLCK 6 /* With SLARP and keepalive    */
 #define ISDN_NET_ENCAP_X25IFACE   7 /* Documentation/networking/x25-iface.txt*/
 #define ISDN_NET_ENCAP_MAX_ENCAP  ISDN_NET_ENCAP_X25IFACE
+
 /* Facility which currently uses an ISDN-channel */
 #define ISDN_USAGE_NONE       0
 #define ISDN_USAGE_RAW        1
@@ -150,12 +107,6 @@
 } isdn_ioctl_struct;
 
 typedef struct {
-  unsigned long isdndev;
-  unsigned long atmodem[ISDN_MAX_CHANNELS];
-  unsigned long info[ISDN_MAX_CHANNELS];
-} debugvar_addr;
-
-typedef struct {
   char name[10];
   char phone[ISDN_MSNLEN];
   int  outgoing;
@@ -189,14 +140,15 @@
   int  dialmode;     /* Flag: off / on / auto                 */
 } isdn_net_ioctl_cfg;
 
-#define ISDN_NET_DIALMODE_MASK 0xC0  /* bits for status                   */
-#define  ISDN_NET_DM_OFF	0x00    /* this interface is stopped      */
-#define  ISDN_NET_DM_MANUAL	0x40    /* this interface is on (manual)  */
-#define  ISDN_NET_DM_AUTO	0x80    /* this interface is autodial     */
+#define ISDN_NET_DIALMODE_MASK  0xC0    /* bits for status                */
+#define ISDN_NET_DM_OFF	        0x00    /* this interface is stopped      */
+#define ISDN_NET_DM_MANUAL	0x40    /* this interface is on (manual)  */
+#define ISDN_NET_DM_AUTO	0x80    /* this interface is autodial     */
 #define ISDN_NET_DIALMODE(x) ((&(x))->flags & ISDN_NET_DIALMODE_MASK)
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
@@ -220,6 +172,31 @@
 #include <linux/skbuff.h>
 #include <linux/tcp.h>
 
+#define ISDN_TTY_MAJOR    43
+#define ISDN_TTYAUX_MAJOR 44
+#define ISDN_MAJOR        45
+
+/* The minor-devicenumbers for Channel 0 and 1 are used as arguments for
+ * physical Channel-Mapping, so they MUST NOT be changed without changing
+ * the correspondent code in isdn.c
+ */
+
+#ifdef CONFIG_COBALT_MICRO_SERVER
+/* Save memory */
+#define ISDN_MAX_DRIVERS    2
+#define ISDN_MAX_CHANNELS   8
+#else
+#define ISDN_MAX_DRIVERS    32
+#define ISDN_MAX_CHANNELS   64
+#endif
+#define ISDN_MINOR_B        0
+#define ISDN_MINOR_BMAX     (ISDN_MAX_CHANNELS-1)
+#define ISDN_MINOR_CTRL     64
+#define ISDN_MINOR_CTRLMAX  (64 + (ISDN_MAX_CHANNELS-1))
+#define ISDN_MINOR_PPP      128
+#define ISDN_MINOR_PPPMAX   (128 + (ISDN_MAX_CHANNELS-1))
+#define ISDN_MINOR_STATUS   255
+
 #ifdef CONFIG_ISDN_PPP
 
 #ifdef CONFIG_ISDN_PPP_VJ
@@ -682,4 +659,5 @@
 #define MIN(a,b) ((a<b)?a:b)
 #define MAX(a,b) ((a>b)?a:b)
 #endif /* __KERNEL__ */
-#endif /* isdn_h */
+
+#endif /* __ISDN_H__ */
diff -urN linux-2.4.5-pre3/include/linux/isdn_ppp.h linux/include/linux/isdn_ppp.h
--- linux-2.4.5-pre3/include/linux/isdn_ppp.h	Thu Apr 19 22:30:09 2001
+++ linux/include/linux/isdn_ppp.h	Mon Dec  3 22:44:23 2001
@@ -3,9 +3,6 @@
 #ifndef _LINUX_ISDN_PPP_H
 #define _LINUX_ISDN_PPP_H
 
-#ifdef __KERNEL__
-#include <linux/config.h>
-#endif
 
 #define CALLTYPE_INCOMING 0x1
 #define CALLTYPE_OUTGOING 0x2
@@ -46,13 +43,6 @@
 #define SC_LINK_DECOMP_DISCARD	0x40
 #define SC_LINK_COMP_DISCARD	0x80
 
-#define DECOMP_ERR_NOMEM	(-10)
-
-#define MP_END_FRAG    0x40
-#define MP_BEGIN_FRAG  0x80
-
-#define MP_MAX_QUEUE_LEN	16
-
 #define ISDN_PPP_COMP_MAX_OPTIONS 16
 
 #define IPPP_COMP_FLAG_XMIT 0x1
@@ -66,6 +56,17 @@
 };
 
 #ifdef __KERNEL__
+
+
+#include <linux/config.h>
+
+
+#define DECOMP_ERR_NOMEM	(-10)
+
+#define MP_END_FRAG    0x40
+#define MP_BEGIN_FRAG  0x80
+
+#define MP_MAX_QUEUE_LEN	16
 
 /*
  * We need a way for the decompressor to influence the generation of CCP
diff -urN linux-2.4.5-pre3/include/linux/isdnif.h linux/include/linux/isdnif.h
--- linux-2.4.5-pre3/include/linux/isdnif.h	Thu Apr 19 22:30:09 2001
+++ linux/include/linux/isdnif.h	Mon Dec  3 22:44:23 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.37 2000/11/19 17:01:54 kai Exp $
+/* $Id: isdnif.h,v 1.37.6.2 2001/05/17 21:15:34 kai Exp $
 
  * Linux ISDN subsystem
  *
@@ -23,12 +23,9 @@
  *
  */
 
-#ifndef isdnif_h
-#define isdnif_h
+#ifndef __ISDNIF_H__
+#define __ISDNIF_H__
 
-#ifdef __KERNEL__
-#include <linux/config.h>
-#endif
 
 /*
  * Values for general protocol-selection
@@ -69,6 +66,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <linux/skbuff.h>
 
 /***************************************************************************/
@@ -562,4 +560,5 @@
 #include <asm/uaccess.h>
 
 #endif /* __KERNEL__ */
-#endif /* isdnif_h */
+
+#endif /* __ISDNIF_H__ */
diff -urN linux-2.4.5-pre3/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- linux-2.4.5-pre3/include/linux/msdos_fs.h	Mon Dec 11 13:25:10 2000
+++ linux/include/linux/msdos_fs.h	Mon Dec  3 22:44:23 2001
@@ -54,8 +54,7 @@
 #define SCAN_NOTANY  3  /* test name, then use SCAN_HID or SCAN_NOTHID */
 
 #define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */
-#define IS_FREE(n) (!*(n) || *(const unsigned char *) (n) == DELETED_FLAG || \
-  *(const unsigned char *) (n) == FD_FILL_BYTE)
+#define IS_FREE(n) (!*(n) || *(const unsigned char *) (n) == DELETED_FLAG)
 
 #define MSDOS_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)
 	/* valid file mode bits */
diff -urN linux-2.4.5-pre3/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- linux-2.4.5-pre3/include/linux/nfs_fs.h	Fri Apr 27 15:49:37 2001
+++ linux/include/linux/nfs_fs.h	Mon Dec  3 22:44:23 2001
@@ -142,7 +142,7 @@
 				struct nfs_fattr *);
 extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *,
 				struct nfs_fattr *);
-extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
+extern int __nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_revalidate(struct dentry *);
 extern int nfs_permission(struct inode *, int);
 extern int nfs_open(struct inode *, struct file *);
@@ -271,6 +271,14 @@
 	if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
 		return NFS_STALE(inode) ? -ESTALE : 0;
 	return __nfs_revalidate_inode(server, inode);
+}
+
+static inline int
+nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+{
+	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+		return 0;
+	return __nfs_refresh_inode(inode,fattr);
 }
 
 static inline loff_t
diff -urN linux-2.4.5-pre3/include/linux/parport.h linux/include/linux/parport.h
--- linux-2.4.5-pre3/include/linux/parport.h	Thu Feb  8 10:40:25 2001
+++ linux/include/linux/parport.h	Mon Dec  3 22:44:23 2001
@@ -90,6 +90,7 @@
 
 /* Flags for block transfer operations. */
 #define PARPORT_EPP_FAST		(1<<0) /* Unreliable counts. */
+#define PARPORT_W91284PIC		(1<<1) /* have a Warp9 w91284pic in the device */
 
 /* The rest is for the kernel only */
 #ifdef __KERNEL__
diff -urN linux-2.4.5-pre3/include/linux/parport_pc.h linux/include/linux/parport_pc.h
--- linux-2.4.5-pre3/include/linux/parport_pc.h	Mon Dec 11 12:50:09 2000
+++ linux/include/linux/parport_pc.h	Mon Dec  3 22:44:23 2001
@@ -59,6 +59,51 @@
 	return val;
 }
 
+#ifdef DEBUG_PARPORT
+extern __inline__ void dump_parport_state (char *str, struct parport *p)
+{
+	/* here's hoping that reading these ports won't side-effect anything underneath */
+	unsigned char ecr = inb (ECONTROL (p));
+	unsigned char dcr = inb (CONTROL (p));
+	unsigned char dsr = inb (STATUS (p));
+	static char *ecr_modes[] = {"SPP", "PS2", "PPFIFO", "ECP", "xXx", "yYy", "TST", "CFG"};
+	const struct parport_pc_private *priv = (parport_pc_private *)p->physport->private_data;
+	int i;
+
+	printk (KERN_DEBUG "*** parport state (%s): ecr=[%s", str, ecr_modes[(ecr & 0xe0) >> 5]);
+	if (ecr & 0x10) printk (",nErrIntrEn");
+	if (ecr & 0x08) printk (",dmaEn");
+	if (ecr & 0x04) printk (",serviceIntr");
+	if (ecr & 0x02) printk (",f_full");
+	if (ecr & 0x01) printk (",f_empty");
+	for (i=0; i<2; i++) {
+		printk ("]  dcr(%s)=[", i ? "soft" : "hard");
+		dcr = i ? priv->ctr : inb (CONTROL (p));
+	
+		if (dcr & 0x20) {
+			printk ("rev");
+		} else {
+			printk ("fwd");
+		}
+		if (dcr & 0x10) printk (",ackIntEn");
+		if (!(dcr & 0x08)) printk (",N-SELECT-IN");
+		if (dcr & 0x04) printk (",N-INIT");
+		if (!(dcr & 0x02)) printk (",N-AUTOFD");
+		if (!(dcr & 0x01)) printk (",N-STROBE");
+	}
+	printk ("]  dsr=[");
+	if (!(dsr & 0x80)) printk ("BUSY");
+	if (dsr & 0x40) printk (",N-ACK");
+	if (dsr & 0x20) printk (",PERROR");
+	if (dsr & 0x10) printk (",SELECT");
+	if (dsr & 0x08) printk (",N-FAULT");
+	printk ("]\n");
+	return;
+}
+#else	/* !DEBUG_PARPORT */
+#define dump_parport_state(args...)
+#endif	/* !DEBUG_PARPORT */
+
 /* __parport_pc_frob_control differs from parport_pc_frob_control in that
  * it doesn't do any extra masking. */
 static __inline__ unsigned char __parport_pc_frob_control (struct parport *p,
diff -urN linux-2.4.5-pre3/include/linux/pci.h linux/include/linux/pci.h
--- linux-2.4.5-pre3/include/linux/pci.h	Mon Dec  3 22:43:50 2001
+++ linux/include/linux/pci.h	Mon Dec  3 22:44:23 2001
@@ -315,8 +315,6 @@
 
 #define pci_present pcibios_present
 
-#define pci_for_each_dev(dev) \
-	for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next))
 
 #define pci_for_each_dev_reverse(dev) \
 	for(dev = pci_dev_g(pci_devices.prev); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.prev))
@@ -473,6 +471,9 @@
 /* these external functions are only available when PCI support is enabled */
 #ifdef CONFIG_PCI
 
+#define pci_for_each_dev(dev) \
+	for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next))
+
 void pcibios_init(void);
 void pcibios_fixup_bus(struct pci_bus *);
 int pcibios_enable_device(struct pci_dev *);
@@ -624,6 +625,10 @@
 static inline void pci_unregister_driver(struct pci_driver *drv) { }
 static inline int scsi_to_pci_dma_dir(unsigned char scsi_dir) { return scsi_dir; }
 static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; }
+static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; }
+
+#define pci_for_each_dev(dev) \
+	for(dev = NULL; 0; )
 
 #else
 
diff -urN linux-2.4.5-pre3/include/linux/ppdev.h linux/include/linux/ppdev.h
--- linux-2.4.5-pre3/include/linux/ppdev.h	Mon Oct 11 10:04:02 1999
+++ linux/include/linux/ppdev.h	Mon Dec  3 22:44:23 2001
@@ -11,6 +11,7 @@
  * 2 of the License, or (at your option) any later version.
  *
  * Added PPGETTIME/PPSETTIME, Fred Barnes, 1999
+ * Added PPGETMODES/PPGETMODE/PPGETPHASE, Fred Barnes <frmb2@ukc.ac.uk>, 03/01/2001
  */
 
 #define PP_MAJOR	99
@@ -77,5 +78,24 @@
 /* Set and get port timeout (struct timeval's) */
 #define PPGETTIME	_IOR(PP_IOCTL, 0x95, struct timeval)
 #define PPSETTIME	_IOW(PP_IOCTL, 0x96, struct timeval)
+
+/* Get available modes (what the hardware can do) */
+#define PPGETMODES	_IOR(PP_IOCTL, 0x97, unsigned int)
+
+/* Get the current mode and phaze */
+#define PPGETMODE	_IOR(PP_IOCTL, 0x98, int)
+#define PPGETPHASE	_IOR(PP_IOCTL, 0x99, int)
+
+/* get/set flags */
+#define PPGETFLAGS	_IOR(PP_IOCTL, 0x9a, int)
+#define PPSETFLAGS	_IOW(PP_IOCTL, 0x9b, int)
+
+/* flags visible to the world */
+#define PP_FASTWRITE	(1<<2)
+#define PP_FASTREAD	(1<<3)
+#define PP_W91284PIC	(1<<4)
+
+/* only masks user-visible flags */
+#define PP_FLAGMASK	(PP_FASTWRITE | PP_FASTREAD | PP_W91284PIC)
 
 
diff -urN linux-2.4.5-pre3/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- linux-2.4.5-pre3/include/linux/proc_fs.h	Fri Apr 27 15:48:38 2001
+++ linux/include/linux/proc_fs.h	Mon Dec  3 22:44:23 2001
@@ -127,6 +127,11 @@
  */
 extern void proc_device_tree_init(void);
 
+/*
+ * proc_rtas.c
+ */
+extern void proc_rtas_init(void);
+
 extern struct proc_dir_entry *proc_symlink(const char *,
 		struct proc_dir_entry *, const char *);
 extern struct proc_dir_entry *proc_mknod(const char *,mode_t,
diff -urN linux-2.4.5-pre3/include/linux/videodev.h linux/include/linux/videodev.h
--- linux-2.4.5-pre3/include/linux/videodev.h	Mon Dec  3 22:43:50 2001
+++ linux/include/linux/videodev.h	Mon Dec  3 22:44:23 2001
@@ -33,9 +33,8 @@
 	devfs_handle_t devfs_handle;
 };
 
-extern int videodev_init(void);
 #define VIDEO_MAJOR	81
-extern int video_register_device(struct video_device *, int type);
+extern int video_register_device(struct video_device *, int type, int nr);
 
 #define VFL_TYPE_GRABBER	0
 #define VFL_TYPE_VBI		1
diff -urN linux-2.4.5-pre3/include/net/protocol.h linux/include/net/protocol.h
--- linux-2.4.5-pre3/include/net/protocol.h	Fri Apr 27 15:48:20 2001
+++ linux/include/net/protocol.h	Mon Dec  3 22:44:23 2001
@@ -67,7 +67,6 @@
 extern struct inet_protocol *inet_protos[MAX_INET_PROTOS];
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-extern struct inet6_protocol *inet6_protocol_base;
 extern struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
 #endif
 
diff -urN linux-2.4.5-pre3/init/main.c linux/init/main.c
--- linux-2.4.5-pre3/init/main.c	Mon Dec  3 22:43:50 2001
+++ linux/init/main.c	Mon Dec  3 22:44:23 2001
@@ -108,9 +108,6 @@
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
 #endif
-#if defined(CONFIG_QUOTA)
-extern void dquot_init_hash(void);
-#endif
 
 /*
  * Boot command-line arguments
@@ -580,9 +577,6 @@
 #if defined(CONFIG_SYSVIPC)
 	ipc_init();
 #endif
-#if defined(CONFIG_QUOTA)
-	dquot_init_hash();
-#endif
 	check_bugs();
 	printk("POSIX conformance testing by UNIFIX\n");
 
@@ -638,9 +632,6 @@
  */
 static void __init do_basic_setup(void)
 {
-#ifdef CONFIG_BLK_DEV_INITRD
-	int real_root_mountflags;
-#endif
 
 	/*
 	 * Tell the world that we're going to be the grim
@@ -707,13 +698,6 @@
 	/* Networking initialization needs a process context */ 
 	sock_init();
 
-#ifdef CONFIG_BLK_DEV_INITRD
-	real_root_dev = ROOT_DEV;
-	real_root_mountflags = root_mountflags;
-	if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY;
-	else mount_initrd =0;
-#endif
-
 	start_context_thread();
 	do_initcalls();
 
@@ -724,6 +708,33 @@
 #ifdef CONFIG_PCMCIA
 	init_pcmcia_ds();		/* Do this last */
 #endif
+}
+
+extern void rd_load(void);
+extern void initrd_load(void);
+
+/*
+ * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
+ */
+static void prepare_namespace(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+	int real_root_mountflags = root_mountflags;
+	if (!initrd_start)
+		mount_initrd = 0;
+	if (mount_initrd)
+		root_mountflags &= ~MS_RDONLY;
+	real_root_dev = ROOT_DEV;
+#endif
+
+#ifdef CONFIG_BLK_DEV_RAM
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (mount_initrd)
+		initrd_load();
+	else
+#endif
+	rd_load();
+#endif
 
 	/* Mount the root filesystem.. */
 	mount_root();
@@ -755,6 +766,8 @@
 {
 	lock_kernel();
 	do_basic_setup();
+
+	prepare_namespace();
 
 	/*
 	 * Ok, we have completed the initial bootup, and
diff -urN linux-2.4.5-pre3/ipc/shm.c linux/ipc/shm.c
--- linux-2.4.5-pre3/ipc/shm.c	Mon Mar 19 12:35:08 2001
+++ linux/ipc/shm.c	Mon Dec  3 22:44:23 2001
@@ -497,14 +497,21 @@
 		if (shp == NULL) 
 			goto out_up;
 		err = shm_checkid(shp, shmid);
-		if (err == 0) {
-			if (shp->shm_nattch){
-				shp->shm_flags |= SHM_DEST;
-				/* Do not find it any more */
-				shp->shm_perm.key = IPC_PRIVATE;
-			} else
-				shm_destroy (shp);
+		if(err)
+			goto out_unlock_up;
+		if (current->euid != shp->shm_perm.uid &&
+		    current->euid != shp->shm_perm.cuid && 
+		    !capable(CAP_SYS_ADMIN)) {
+			err=-EPERM;
+			goto out_unlock_up;
 		}
+		if (shp->shm_nattch){
+			shp->shm_flags |= SHM_DEST;
+			/* Do not find it any more */
+			shp->shm_perm.key = IPC_PRIVATE;
+		} else
+			shm_destroy (shp);
+
 		/* Unlock */
 		shm_unlock(shmid);
 		up(&shm_ids.sem);
diff -urN linux-2.4.5-pre3/kernel/context.c linux/kernel/context.c
--- linux-2.4.5-pre3/kernel/context.c	Fri Jan 12 09:52:41 2001
+++ linux/kernel/context.c	Mon Dec  3 22:44:23 2001
@@ -101,8 +101,10 @@
 		if (signal_pending(curtask)) {
 			while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0)
 				;
+			spin_lock_irq(&curtask->sigmask_lock);
 			flush_signals(curtask);
 			recalc_sigpending(curtask);
+			spin_unlock_irq(&curtask->sigmask_lock);
 		}
 	}
 }
diff -urN linux-2.4.5-pre3/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.4.5-pre3/kernel/ksyms.c	Mon Dec  3 22:43:50 2001
+++ linux/kernel/ksyms.c	Mon Dec  3 22:44:23 2001
@@ -146,7 +146,7 @@
 EXPORT_SYMBOL(path_walk);
 EXPORT_SYMBOL(path_release);
 EXPORT_SYMBOL(__user_walk);
-EXPORT_SYMBOL(lookup_one);
+EXPORT_SYMBOL(lookup_one_len);
 EXPORT_SYMBOL(lookup_hash);
 EXPORT_SYMBOL(sys_close);
 EXPORT_SYMBOL(dcache_lock);
@@ -264,6 +264,8 @@
 EXPORT_SYMBOL(dentry_open);
 EXPORT_SYMBOL(filemap_nopage);
 EXPORT_SYMBOL(filemap_sync);
+EXPORT_SYMBOL(filemap_fdatasync);
+EXPORT_SYMBOL(filemap_fdatawait);
 EXPORT_SYMBOL(lock_page);
 
 /* device registration */
diff -urN linux-2.4.5-pre3/mm/filemap.c linux/mm/filemap.c
--- linux-2.4.5-pre3/mm/filemap.c	Mon Dec  3 22:43:50 2001
+++ linux/mm/filemap.c	Mon Dec  3 22:44:23 2001
@@ -9,6 +9,7 @@
  * most "normal" filesystems (but you don't /have/ to use this:
  * the NFS filesystem used to do this differently, for example)
  */
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/shm.h>
 #include <linux/mman.h>
diff -urN linux-2.4.5-pre3/mm/swapfile.c linux/mm/swapfile.c
--- linux-2.4.5-pre3/mm/swapfile.c	Wed Apr 25 14:46:21 2001
+++ linux/mm/swapfile.c	Mon Dec  3 22:44:23 2001
@@ -134,7 +134,7 @@
 bad_count:
 	printk(KERN_ERR "get_swap_page: bad count %hd from %p\n",
 	       count, __builtin_return_address(0));
-	goto out;
+	return entry;
 }
 
 
diff -urN linux-2.4.5-pre3/mm/vmalloc.c linux/mm/vmalloc.c
--- linux-2.4.5-pre3/mm/vmalloc.c	Fri Mar 23 16:14:00 2001
+++ linux/mm/vmalloc.c	Mon Dec  3 22:44:23 2001
@@ -180,19 +180,13 @@
 	addr = VMALLOC_START;
 	write_lock(&vmlist_lock);
 	for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
-		if ((size + addr) < addr) {
-			write_unlock(&vmlist_lock);
-			kfree(area);
-			return NULL;
-		}
+		if ((size + addr) < addr)
+			goto out;
 		if (size + addr < (unsigned long) tmp->addr)
 			break;
 		addr = tmp->size + (unsigned long) tmp->addr;
-		if (addr > VMALLOC_END-size) {
-			write_unlock(&vmlist_lock);
-			kfree(area);
-			return NULL;
-		}
+		if (addr > VMALLOC_END-size)
+			goto out;
 	}
 	area->flags = flags;
 	area->addr = (void *)addr;
@@ -201,6 +195,11 @@
 	*p = area;
 	write_unlock(&vmlist_lock);
 	return area;
+
+out:
+	write_unlock(&vmlist_lock);
+	kfree(area);
+	return NULL;
 }
 
 void vfree(void * addr)
diff -urN linux-2.4.5-pre3/net/core/dev.c linux/net/core/dev.c
--- linux-2.4.5-pre3/net/core/dev.c	Mon Dec  3 22:43:50 2001
+++ linux/net/core/dev.c	Mon Dec  3 22:44:23 2001
@@ -1070,7 +1070,7 @@
 {
 	void (*stimul)(struct net_device *);
 	struct net_device *dev;
-} netdev_fc_slots[32];
+} netdev_fc_slots[BITS_PER_LONG];
 
 int netdev_register_fc(struct net_device *dev, void (*stimul)(struct net_device *dev))
 {
diff -urN linux-2.4.5-pre3/net/ipv4/protocol.c linux/net/ipv4/protocol.c
--- linux-2.4.5-pre3/net/ipv4/protocol.c	Mon Dec  3 22:43:50 2001
+++ linux/net/ipv4/protocol.c	Mon Dec  3 22:44:23 2001
@@ -5,7 +5,7 @@
  *
  *		INET protocol dispatch tables.
  *
- * Version:	$Id: protocol.c,v 1.13 2001/04/30 01:59:55 davem Exp $
+ * Version:	$Id: protocol.c,v 1.14 2001/05/18 02:25:49 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -16,6 +16,8 @@
  *		Alan Cox	: Added new fields for init and ready for
  *				  proper fragmentation (_NO_ 4K limits!)
  *		Richard Colella	: Hang on hash collision
+ *		Vince Laviano	: Modified inet_del_protocol() to correctly
+ *				  maintain copy bit.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -148,6 +150,10 @@
 	}
 
 	p = (struct inet_protocol *) inet_protos[hash];
+
+	if (p != NULL && p->protocol == prot->protocol)
+		lp = p;
+
 	while (p) {
 		/*
 		 * We have to worry if the protocol being deleted is
@@ -159,14 +165,14 @@
 			 * if we are the last one with this protocol and
 			 * there is a previous one, reset its copy bit.
 			 */
-			if (p->copy == 0 && lp != NULL) 
+			if (prot->copy == 0 && lp != NULL)
 				lp->copy = 0;
 			p->next = prot->next;
 			br_write_unlock_bh(BR_NETPROTO_LOCK);
 			return 0;
 		}
 		if (p->next != NULL && p->next->protocol == prot->protocol) 
-			lp = p;
+			lp = p->next;
 
 		p = (struct inet_protocol *) p->next;
 	}
diff -urN linux-2.4.5-pre3/net/ipv6/protocol.c linux/net/ipv6/protocol.c
--- linux-2.4.5-pre3/net/ipv6/protocol.c	Tue Oct 10 10:33:52 2000
+++ linux/net/ipv6/protocol.c	Mon Dec  3 22:44:24 2001
@@ -5,7 +5,7 @@
  *
  *		PF_INET6 protocol dispatch tables.
  *
- * Version:	$Id: protocol.c,v 1.9 2000/10/03 07:29:01 anton Exp $
+ * Version:	$Id: protocol.c,v 1.10 2001/05/18 02:25:49 davem Exp $
  *
  * Authors:	Pedro Roque	<roque@di.fc.ul.pt>
  *
@@ -15,6 +15,14 @@
  *		2 of the License, or (at your option) any later version.
  */
 
+/*
+ *      Changes:
+ *
+ *      Vince Laviano (vince@cs.stanford.edu)       16 May 2001
+ *      - Removed unused variable 'inet6_protocol_base'
+ *      - Modified inet6_del_protocol() to correctly maintain copy bit.
+ */
+
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -32,7 +40,6 @@
 #include <net/ipv6.h>
 #include <net/protocol.h>
 
-struct inet6_protocol *inet6_protocol_base;
 struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
 
 void inet6_add_protocol(struct inet6_protocol *prot)
@@ -80,6 +87,10 @@
 	}
 
 	p = (struct inet6_protocol *) inet6_protos[hash];
+
+        if (p != NULL && p->protocol == prot->protocol)
+                lp = p;
+
 	while(p != NULL) {
 		/*
 		 * We have to worry if the protocol being deleted is
@@ -91,14 +102,14 @@
 			 * if we are the last one with this protocol and
 			 * there is a previous one, reset its copy bit.
 			 */
-			if (p->copy == 0 && lp != NULL) 
+			if (prot->copy == 0 && lp != NULL)
 				lp->copy = 0;
 			p->next = prot->next;
 			br_write_unlock_bh(BR_NETPROTO_LOCK);
 			return(0);
 		}
 		if (p->next != NULL && p->next->protocol == prot->protocol) 
-			lp = p;
+			lp = p->next;
 
 		p = (struct inet6_protocol *) p->next;
 	}
diff -urN linux-2.4.5-pre3/net/irda/af_irda.c linux/net/irda/af_irda.c
--- linux-2.4.5-pre3/net/irda/af_irda.c	Mon Dec  3 22:43:50 2001
+++ linux/net/irda/af_irda.c	Mon Dec  3 22:44:24 2001
@@ -218,7 +218,8 @@
 		   self->max_data_size);
 
 	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
-	kfree_skb(skb);
+
+	skb_queue_tail(&sk->receive_queue, skb);
 
 	/* We are now connected! */
 	sk->state = TCP_ESTABLISHED;
@@ -438,7 +439,7 @@
  * We were waiting for a node to be discovered, but nothing has come up
  * so far. Wake up the user and tell him that we failed...
  */
-static void irda_discovery_timeout(u_long priv)
+static void irda_discovery_timeout(u_long	priv)
 {
 	struct irda_sock *self;
 	
@@ -775,6 +776,7 @@
 	struct sock *sk = sock->sk;
 	struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr;
 	struct irda_sock *self;
+	__u16 hints = 0;
 	int err;
 
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
@@ -819,6 +821,15 @@
 				 self->stsap_sel, IAS_KERNEL_ATTR);
 	irias_insert_object(self->ias_obj);
 	
+#if 1 /* Will be removed in near future */
+
+	/* Fill in some default hint bits values */
+	if (strncmp(addr->sir_name, "OBEX", 4) == 0)
+		hints = irlmp_service_to_hint(S_OBEX);
+	
+	if (hints)
+		self->skey = irlmp_register_service(hints);
+#endif
 	return 0;
 }
 
@@ -1622,54 +1633,34 @@
 {
 	struct sock *sk = sock->sk;
 	unsigned int mask;
-	struct irda_sock *self;
 
 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	self = sk->protinfo.irda;
 	poll_wait(file, sk->sleep, wait);
 	mask = 0;
 
-	/* Exceptional events? */
+	/* exceptional events? */
 	if (sk->err)
 		mask |= POLLERR;
 	if (sk->shutdown & RCV_SHUTDOWN)
 		mask |= POLLHUP;
 
-	/* Readable? */
+	/* readable? */
 	if (!skb_queue_empty(&sk->receive_queue)) {
 		IRDA_DEBUG(4, "Socket is readable\n");
 		mask |= POLLIN | POLLRDNORM;
 	}
-
 	/* Connection-based need to check for termination and startup */
-	switch (sk->type) {
-	case SOCK_STREAM:
-		if (sk->state == TCP_CLOSE)
-			mask |= POLLHUP;
+	if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE)
+		mask |= POLLHUP;
 
-		if (sk->state == TCP_ESTABLISHED) {
-			if ((self->tx_flow == FLOW_START) && 
-			    (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE))
-			{
-				mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
-			}
-		}
-		break;
-	case SOCK_SEQPACKET:
-		if ((self->tx_flow == FLOW_START) && 
-		    (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE))
-		{	
-			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
-		}
-		break;
-	case SOCK_DGRAM:
-		if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE)
+	/*
+	 * we set writable also when the other side has shut down the
+	 * connection. This prevents stuck sockets.
+	 */
+	if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE)
 			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
-		break;
-	default:
-		break;
-	}		
+
 	return mask;
 }
 
@@ -2337,9 +2328,6 @@
 SOCKOPS_WRAP(irda_stream, PF_IRDA);
 SOCKOPS_WRAP(irda_seqpacket, PF_IRDA);
 SOCKOPS_WRAP(irda_dgram, PF_IRDA);
-#ifdef CONFIG_IRDA_ULTRA
-SOCKOPS_WRAP(irda_ultra, PF_IRDA);
-#endif /* CONFIG_IRDA_ULTRA */
 
 /*
  * Function irda_device_event (this, event, ptr)
@@ -2428,9 +2416,7 @@
 #endif
 	return 0;
 }
-#ifdef MODULE
-module_init(irda_proto_init);	/* If non-module, called from init/main.c */
-#endif
+module_init(irda_proto_init);
 
 /*
  * Function irda_proto_cleanup (void)
@@ -2455,5 +2441,7 @@
  
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
 MODULE_DESCRIPTION("The Linux IrDA Protocol Subsystem"); 
+#ifdef CONFIG_IRDA_DEBUG
 MODULE_PARM(irda_debug, "1l");
+#endif
 #endif /* MODULE */
diff -urN linux-2.4.5-pre3/net/irda/irias_object.c linux/net/irda/irias_object.c
--- linux-2.4.5-pre3/net/irda/irias_object.c	Mon Dec  3 22:43:50 2001
+++ linux/net/irda/irias_object.c	Fri Mar  2 11:12:12 2001
@@ -34,7 +34,7 @@
 /*
  *  Used when a missing value needs to be returned
  */
-struct ias_value missing = { IAS_MISSING, 0, 0, 0, {0}};
+struct ias_value missing = { IAS_MISSING, 0, 0, 0};
 
 /*
  * Function strdup (str)
diff -urN linux-2.4.5-pre3/net/irda/irlap.c linux/net/irda/irlap.c
--- linux-2.4.5-pre3/net/irda/irlap.c	Mon Dec  3 22:43:50 2001
+++ linux/net/irda/irlap.c	Fri Mar  2 11:12:12 2001
@@ -860,6 +860,13 @@
 	/* Free sliding window buffered packets */
 	while ((skb = skb_dequeue(&self->wx_list)) != NULL)
 		dev_kfree_skb(skb);
+
+#ifdef CONFIG_IRDA_RECYCLE_RR
+	if (self->recycle_rr_skb) { 
+ 		dev_kfree_skb(self->recycle_rr_skb);
+ 		self->recycle_rr_skb = NULL;
+ 	}
+#endif
 }
 
 /*
@@ -1069,7 +1076,7 @@
 
 	/* Set the negociated xbofs value */
 	self->next_bofs   = self->qos_tx.additional_bofs.value;
-	if (now)
+	if(now)
 		self->bofs_count = self->next_bofs;
 
 	/* Set the negociated link speed (may need the new xbofs value) */
@@ -1100,13 +1107,13 @@
 		 */
 		self->N1 = -1; /* Disable */
 	else
-		self->N1 = 3000 / self->qos_rx.max_turn_time.value;
+		self->N1 = 3000 / self->qos_tx.max_turn_time.value;
 	
 	IRDA_DEBUG(4, "Setting N1 = %d\n", self->N1);
 	
 	
 	self->N2 = self->qos_tx.link_disc_time.value * 1000 / 
-		self->qos_rx.max_turn_time.value;
+		self->qos_tx.max_turn_time.value;
 	IRDA_DEBUG(4, "Setting N2 = %d\n", self->N2);
 
 	/* 
diff -urN linux-2.4.5-pre3/net/irda/irlap_frame.c linux/net/irda/irlap_frame.c
--- linux-2.4.5-pre3/net/irda/irlap_frame.c	Mon Dec  3 22:43:50 2001
+++ linux/net/irda/irlap_frame.c	Thu Feb  8 15:14:08 2001
@@ -742,6 +742,12 @@
 			return;
 		}
 		
+		/*
+		 *  make sure the skb->sk accounting of memory usage is sane
+		 */
+		if (skb->sk != NULL)
+			skb_set_owner_w(tx_skb, skb->sk);
+		
 		/* 
 		 *  Insert frame in store, in case of retransmissions 
 		 */
@@ -782,6 +788,12 @@
 			return;
 		}
 		
+		/*
+		 *  make sure the skb->sk accounting of memory usage is sane
+		 */
+		if (skb->sk != NULL)
+			skb_set_owner_w(tx_skb, skb->sk);
+		
 		/* 
 		 *  Insert frame in store, in case of retransmissions 
 		 */
@@ -851,6 +863,9 @@
 			return;
 		}		
 
+		if (skb->sk != NULL)
+			skb_set_owner_w(tx_skb, skb->sk);
+		
 		/* Insert frame in store */
 		skb_queue_tail(&self->wx_list, skb_get(skb));
 		
@@ -902,6 +917,9 @@
 			return;
 		}		
 		
+		if (skb->sk != NULL)
+			skb_set_owner_w(tx_skb, skb->sk);
+		
 		/* Insert frame in store */
 		skb_queue_tail(&self->wx_list, skb_get(skb));
 		
@@ -955,6 +973,12 @@
 		tx_skb->next = tx_skb->prev = NULL;
 		tx_skb->list = NULL;
 
+		/*
+		 *  make sure the skb->sk accounting of memory usage is sane
+		 */
+		if (skb->sk != NULL)
+			skb_set_owner_w(tx_skb, skb->sk);
+
 		/* Clear old Nr field + poll bit */
 		tx_skb->data[1] &= 0x0f;
 
@@ -1034,6 +1058,12 @@
 		/* Unlink tx_skb from list */
 		tx_skb->next = tx_skb->prev = NULL;
 		tx_skb->list = NULL;
+
+		/*
+		 *  make sure the skb->sk accounting of memory usage is sane
+		 */
+		if (skb->sk != NULL)
+			skb_set_owner_w(tx_skb, skb->sk);
 
 		/* Clear old Nr field + poll bit */
 		tx_skb->data[1] &= 0x0f;
diff -urN linux-2.4.5-pre3/net/irda/irlmp.c linux/net/irda/irlmp.c
--- linux-2.4.5-pre3/net/irda/irlmp.c	Mon Dec  3 22:43:50 2001
+++ linux/net/irda/irlmp.c	Fri Mar  2 11:12:12 2001
@@ -959,7 +959,6 @@
 {
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
-	ASSERT(skb->sk == NULL, /* Just a warning - NOP */;);
 	
 	/* Make room for MUX header */
 	ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;);
diff -urN linux-2.4.5-pre3/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c
--- linux-2.4.5-pre3/net/irda/irlmp_event.c	Mon Dec  3 22:43:50 2001
+++ linux/net/irda/irlmp_event.c	Sat Nov 11 18:11:22 2000
@@ -472,6 +472,8 @@
 		irlmp_start_watchdog_timer(self, 5*HZ);
 		break;
 	case LM_CONNECT_INDICATION:
+		irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
+
 		if (self->conn_skb) {
 			WARNING(__FUNCTION__ 
 				"(), busy with another request!\n");
@@ -479,8 +481,6 @@
 		}
 		self->conn_skb = skb;
 
-		irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
-
 		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
 		break;
 	default:
@@ -562,15 +562,6 @@
 	switch (event) {
 	case LM_CONNECT_REQUEST:
 		/* Keep state */
-		break;
-	case LM_CONNECT_INDICATION:
-		/* Will happen in some rare cases when the socket get stuck,
-		 * the other side retries the connect request.
-		 * We just unstuck the socket - Jean II */
-		IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_INDICATION, "
-			   "LSAP stuck in CONNECT_PEND state...\n");
-		/* Keep state */
-		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
 		break;
 	case LM_CONNECT_RESPONSE:
 		IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, "
diff -urN linux-2.4.5-pre3/net/irda/irnet/irnet_irda.c linux/net/irda/irnet/irnet_irda.c
--- linux-2.4.5-pre3/net/irda/irnet/irnet_irda.c	Mon Dec  3 22:43:50 2001
+++ linux/net/irda/irnet/irnet_irda.c	Mon Dec  3 22:44:24 2001
@@ -1081,6 +1081,7 @@
 			LOCK_STATUS lock)
 {
   irnet_socket *	self = (irnet_socket *) instance;
+  LOCAL_FLOW		oldflow = self->tx_flow;
 
   DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
   DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");
diff -urN linux-2.4.5-pre3/net/wanrouter/Makefile linux/net/wanrouter/Makefile
--- linux-2.4.5-pre3/net/wanrouter/Makefile	Thu Apr 12 12:11:39 2001
+++ linux/net/wanrouter/Makefile	Mon Dec  3 22:44:24 2001
@@ -12,9 +12,9 @@
 export-objs := wanmain.o
 
 obj-y :=  wanproc.o wanmain.o
-obj-m := $(O_TARGET) af_wanpipe.o
+obj-m := $(O_TARGET)
+ifneq ($(CONFIG_VENDOR_SANGOMA),n)
+	obj-m += $(O_TARGET)
+endif
 
 include $(TOPDIR)/Rules.make
-
-tar:
-	tar -cvf /dev/f1 .
diff -urN linux-2.4.5-pre3/scripts/Menuconfig linux/scripts/Menuconfig
--- linux-2.4.5-pre3/scripts/Menuconfig	Sun Oct  8 09:30:40 2000
+++ linux/scripts/Menuconfig	Mon Dec  3 22:44:24 2001
@@ -347,7 +347,7 @@
 
 	echo -e "
 	function $firstchoice () \
-		{ l_choice '$title' \"$choices\" $current ;}" >>MCradiolists
+		{ l_choice '$title' \"$choices\" \"$current\" ;}" >>MCradiolists
 }
 
 } # END load_functions()
diff -urN linux-2.4.5-pre3/scripts/checkconfig.pl linux/scripts/checkconfig.pl
--- linux-2.4.5-pre3/scripts/checkconfig.pl	Mon Jan 15 15:31:19 2001
+++ linux/scripts/checkconfig.pl	Mon Dec  3 22:44:24 2001
@@ -25,6 +25,13 @@
 	$fInComment && (s+^.*?\*/+ +o ? ($fInComment = 0) : next);
 	m+/\*+o && (s+/\*.*?\*/+ +go, (s+/\*.*$+ +o && ($fInComment = 1)));
 
+	# Pick up definitions.
+	if ( m/^\s*#/o )
+	{
+	    $iLinuxConfig      = $. if m/^\s*#\s*include\s*"linux\/config\.h"/o;
+	    $configList{uc $1} = 1  if m/^\s*#\s*include\s*"config\/(\S*)\.h"/o;
+	}
+
 	# Strip strings.
 	$fInString && (s+^.*?"+ +o ? ($fInString = 0) : next);
 	m+"+o && (s+".*?"+ +go, (s+".*$+ +o && ($fInString = 1)));
@@ -52,7 +59,7 @@
 
     # Report superfluous includes.
     if ( $iLinuxConfig && ! $fUseConfig )
-	{ print "$file: $iLinuxConfig: <linux/config.h> not needed.\n"; }
+	{ print "$file: $iLinuxConfig: linux/config.h not needed.\n"; }
 
     close(FILE);
 }
